blob: 59b06568a091312a3a4df6d3d00426626c73c07d [file] [log] [blame]
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -05001/*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050016#include "Cache.h"
17#include "AutoBackendTexture.h"
18#include "SkiaRenderEngine.h"
19#include "android-base/unique_fd.h"
Bruno BELANYIb9b5b702023-10-13 13:25:11 +000020#include "cutils/properties.h"
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050021#include "renderengine/DisplaySettings.h"
22#include "renderengine/LayerSettings.h"
Vishnu Nairdbbe3852022-01-12 20:22:11 -080023#include "renderengine/impl/ExternalTexture.h"
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050024#include "ui/GraphicBuffer.h"
25#include "ui/GraphicTypes.h"
26#include "ui/PixelFormat.h"
27#include "ui/Rect.h"
28#include "utils/Timers.h"
29
30namespace android::renderengine::skia {
31
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040032namespace {
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -040033
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040034// clang-format off
35// Any non-identity matrix will do.
36const auto kScaleAndTranslate = mat4(0.7f, 0.f, 0.f, 0.f,
37 0.f, 0.7f, 0.f, 0.f,
38 0.f, 0.f, 1.f, 0.f,
39 67.3f, 52.2f, 0.f, 1.f);
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -040040const auto kScaleAsymmetric = mat4(0.8f, 0.f, 0.f, 0.f,
41 0.f, 1.1f, 0.f, 0.f,
42 0.f, 0.f, 1.f, 0.f,
43 0.f, 0.f, 0.f, 1.f);
Nathaniel Nifong13491502021-06-30 17:28:29 -040044const auto kFlip = mat4(1.1f, -0.1f, 0.f, 0.f,
45 0.1f, 1.1f, 0.f, 0.f,
46 0.f, 0.f, 1.f, 0.f,
47 2.f, 2.f, 0.f, 1.f);
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040048// clang-format on
Nathaniel Nifongbf6f7542021-04-27 12:05:16 -040049// When setting layer.sourceDataspace, whether it matches the destination or not determines whether
50// a color correction effect is added to the shader.
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040051constexpr auto kDestDataSpace = ui::Dataspace::SRGB;
Nathaniel Nifong21e021f2021-04-21 13:15:46 -040052constexpr auto kOtherDataSpace = ui::Dataspace::DISPLAY_P3;
Mattias Simonsson458adf12023-08-16 10:49:30 +000053constexpr auto kBT2020DataSpace = ui::Dataspace::BT2020_ITU_PQ;
Mattias Simonsson5860d922023-08-16 13:47:41 +000054constexpr auto kExtendedHdrDataSpce =
55 static_cast<ui::Dataspace>(ui::Dataspace::RANGE_EXTENDED | ui::Dataspace::TRANSFER_SRGB |
56 ui::Dataspace::STANDARD_DCI_P3);
Mattias Simonsson65746132023-08-15 13:26:16 +000057// Dimming is needed to trigger linear effects for some dataspace pairs
58const std::array<float, 3> kLayerWhitePoints = {
59 1000.0f, 500.0f,
60 100.0f, // trigger dithering by dimming below 20%
61};
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040062} // namespace
63
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -040064static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
Alec Mouria90a5702021-04-16 16:36:21 +000065 const std::shared_ptr<ExternalTexture>& dstTexture) {
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050066 // Somewhat arbitrary dimensions, but on screen and slightly shorter, based
67 // on actual use.
Nathaniel Nifonga6b54232021-07-02 13:24:32 -040068 const Rect& displayRect = display.physicalDisplay;
69 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
70 FloatRect smallerRect(20, 20, displayRect.width()-20, displayRect.height()-20);
71
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050072 LayerSettings layer{
73 .geometry =
74 Geometry{
75 .boundaries = rect,
Vishnu Nair50c0afe2022-07-11 15:04:07 -070076 .roundedCornersRadius = {50.f, 50.f},
Leon Scroggins III894c5f82023-08-25 14:43:54 -040077 .roundedCornersCrop = rect,
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050078 },
Leon Scroggins III894c5f82023-08-25 14:43:54 -040079 .alpha = 1,
80 // setting this is mandatory for shadows and blurs
81 .skipContentDraw = true,
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -040082 // drawShadow ignores alpha
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050083 .shadow =
84 ShadowSettings{
Nathaniel Nifonga6b54232021-07-02 13:24:32 -040085 .boundaries = rect,
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050086 .ambientColor = vec4(0, 0, 0, 0.00935997f),
87 .spotColor = vec4(0, 0, 0, 0.0455841f),
Nathaniel Nifonga6b54232021-07-02 13:24:32 -040088 .lightPos = vec3(500.f, -1500.f, 1500.f),
89 .lightRadius = 2500.0f,
90 .length = 15.f,
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050091 },
Nathaniel Nifonga6b54232021-07-02 13:24:32 -040092 };
93 LayerSettings caster{
94 .geometry =
95 Geometry{
96 .boundaries = smallerRect,
Vishnu Nair50c0afe2022-07-11 15:04:07 -070097 .roundedCornersRadius = {50.f, 50.f},
Leon Scroggins III894c5f82023-08-25 14:43:54 -040098 .roundedCornersCrop = rect,
Nathaniel Nifonga6b54232021-07-02 13:24:32 -040099 },
100 .source =
101 PixelSource{
102 .solidColor = half3(0.f, 0.f, 0.f),
103 },
104 .alpha = 1,
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500105 };
106
Nathaniel Nifong49a59582021-07-26 19:49:47 -0400107 // Four combinations of settings are used (two transforms here, and drawShadowLayers is
108 // called with two different destination data spaces) They're all rounded rect.
109 // Three of these are cache misses that generate new shaders.
110 // The first combination generates a short and simple shadow shader.
111 // The second combination, flip transform, generates two shaders. The first appears to involve
112 // gaussian_fp. The second is a long and general purpose shadow shader with a device space
113 // transformation stage.
114 // The third combination is a cache hit, nothing new.
115 // The fourth combination, flip transform with a non-SRGB destination dataspace, is new.
116 // It is unique in that nearly everything is done in the vertex shader, and that vertex shader
117 // requires color correction. This is triggered differently from every other instance of color
118 // correction. All other instances are triggered when src and dst dataspaces differ, while
119 // this one is triggered by the destination being non-srgb. Apparently since the third
120 // combination is a cache hit, this color correction is only added when the vertex shader is
121 // doing something non-trivial.
122 for (auto transform : {mat4(), kFlip}) {
123 layer.geometry.positionTransform = transform;
124 caster.geometry.positionTransform = transform;
Leon Scroggins IIIae07fe52022-04-26 15:23:55 -0400125
126 auto layers = std::vector<LayerSettings>{layer, caster};
Alec Mourif29700f2023-08-17 21:53:31 +0000127 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500128 }
129}
130
131static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
Alec Mouria90a5702021-04-16 16:36:21 +0000132 const std::shared_ptr<ExternalTexture>& dstTexture,
133 const std::shared_ptr<ExternalTexture>& srcTexture) {
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500134 const Rect& displayRect = display.physicalDisplay;
135 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
136 LayerSettings layer{
137 .geometry =
138 Geometry{
Leon Scroggins III894c5f82023-08-25 14:43:54 -0400139 .boundaries = rect,
Nathaniel Nifongf06a45b2021-06-25 17:24:26 -0400140 // The position transform doesn't matter when the reduced shader mode
141 // in in effect. A matrix transform stage is always included.
142 .positionTransform = mat4(),
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500143 .roundedCornersCrop = rect,
144 },
145 .source = PixelSource{.buffer =
146 Buffer{
Alec Mouria90a5702021-04-16 16:36:21 +0000147 .buffer = srcTexture,
John Reckac09e452021-04-07 16:35:37 -0400148 .maxLuminanceNits = 1000.f,
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500149 }},
150 };
151
Nathaniel Nifongbf6f7542021-04-27 12:05:16 -0400152 for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
153 layer.sourceDataspace = dataspace;
Nathaniel Nifong13491502021-06-30 17:28:29 -0400154 // Cache shaders for both rects and round rects.
155 // In reduced shader mode, all non-zero round rect radii get the same code path.
Nathaniel Nifongf06a45b2021-06-25 17:24:26 -0400156 for (float roundedCornersRadius : {0.0f, 50.0f}) {
157 // roundedCornersCrop is always set, but the radius triggers the behavior
Vishnu Nair50c0afe2022-07-11 15:04:07 -0700158 layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius};
Nathaniel Nifongf06a45b2021-06-25 17:24:26 -0400159 for (bool isOpaque : {true, false}) {
160 layer.source.buffer.isOpaque = isOpaque;
161 for (auto alpha : {half(.2f), half(1.0f)}) {
162 layer.alpha = alpha;
Leon Scroggins IIIae07fe52022-04-26 15:23:55 -0400163 auto layers = std::vector<LayerSettings>{layer};
Alec Mourif29700f2023-08-17 21:53:31 +0000164 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500165 }
166 }
167 }
168 }
169}
170
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400171static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
Alec Mouria90a5702021-04-16 16:36:21 +0000172 const std::shared_ptr<ExternalTexture>& dstTexture) {
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400173 const Rect& displayRect = display.physicalDisplay;
174 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
175 LayerSettings layer{
176 .geometry =
177 Geometry{
178 .boundaries = rect,
179 },
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400180 .source =
181 PixelSource{
182 .solidColor = half3(0.1f, 0.2f, 0.3f),
183 },
Nathaniel Nifong768693f2021-06-08 14:33:47 -0400184 .alpha = 0.5,
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400185 };
186
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400187 for (auto transform : {mat4(), kScaleAndTranslate}) {
188 layer.geometry.positionTransform = transform;
Nathaniel Nifongf06a45b2021-06-25 17:24:26 -0400189 for (float roundedCornersRadius : {0.0f, 50.f}) {
Vishnu Nair50c0afe2022-07-11 15:04:07 -0700190 layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius};
Leon Scroggins IIIae07fe52022-04-26 15:23:55 -0400191 auto layers = std::vector<LayerSettings>{layer};
Alec Mourif29700f2023-08-17 21:53:31 +0000192 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400193 }
194 }
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400195}
196
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400197static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
Alec Mouria90a5702021-04-16 16:36:21 +0000198 const std::shared_ptr<ExternalTexture>& dstTexture) {
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400199 const Rect& displayRect = display.physicalDisplay;
200 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
201 LayerSettings layer{
202 .geometry =
203 Geometry{
204 .boundaries = rect,
205 },
206 .alpha = 1,
Nathaniel Nifong490a9472021-06-23 16:44:19 -0400207 // setting this is mandatory for shadows and blurs
208 .skipContentDraw = true,
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400209 };
210
Nathaniel Nifong490a9472021-06-23 16:44:19 -0400211 // Different blur code is invoked for radii less and greater than 30 pixels
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400212 for (int radius : {9, 60}) {
213 layer.backgroundBlurRadius = radius;
Leon Scroggins IIIae07fe52022-04-26 15:23:55 -0400214 auto layers = std::vector<LayerSettings>{layer};
Alec Mourif29700f2023-08-17 21:53:31 +0000215 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400216 }
217}
218
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400219// The unique feature of these layers is that the boundary is slightly smaller than the rounded
220// rect crop, so the rounded edges intersect that boundary and require a different clipping method.
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -0400221// For buffers, this is done with a stage that computes coverage and it will differ for round and
222// elliptical corners.
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400223static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
224 const std::shared_ptr<ExternalTexture>& dstTexture,
225 const std::shared_ptr<ExternalTexture>& srcTexture) {
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400226 const Rect& displayRect = display.physicalDisplay;
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400227 FloatRect rect(0, 0, displayRect.width(), displayRect.height() - 20); // boundary is smaller
228
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -0400229 PixelSource bufferSource{.buffer = Buffer{
230 .buffer = srcTexture,
231 .isOpaque = 0,
232 .maxLuminanceNits = 1000.f,
233 }};
234 PixelSource bufferOpaque{.buffer = Buffer{
235 .buffer = srcTexture,
236 .isOpaque = 1,
237 .maxLuminanceNits = 1000.f,
238 }};
239 PixelSource colorSource{.solidColor = half3(0.1f, 0.2f, 0.3f)};
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400240
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400241 LayerSettings layer{
242 .geometry =
243 Geometry{
244 .boundaries = rect,
Vishnu Nair50c0afe2022-07-11 15:04:07 -0700245 .roundedCornersRadius = {27.f, 27.f},
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400246 .roundedCornersCrop =
247 FloatRect(0, 0, displayRect.width(), displayRect.height()),
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400248 },
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400249 };
250
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -0400251 for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
252 layer.source = pixelSource;
253 for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
254 layer.sourceDataspace = dataspace;
Nathaniel Nifong13491502021-06-30 17:28:29 -0400255 // Produce a CircularRRect clip and an EllipticalRRect clip.
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -0400256 for (auto transform : {kScaleAndTranslate, kScaleAsymmetric}) {
257 layer.geometry.positionTransform = transform;
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -0400258 for (float alpha : {0.5f, 1.f}) {
Leon Scroggins IIIae07fe52022-04-26 15:23:55 -0400259 layer.alpha = alpha;
260 auto layers = std::vector<LayerSettings>{layer};
Alec Mourif29700f2023-08-17 21:53:31 +0000261 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -0400262 }
263 }
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400264 }
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400265 }
266}
267
Nathaniel Nifong13491502021-06-30 17:28:29 -0400268static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
269 const std::shared_ptr<ExternalTexture>& dstTexture,
270 const std::shared_ptr<ExternalTexture>& srcTexture) {
271 const Rect& displayRect = display.physicalDisplay;
272 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
273 LayerSettings layer{
274 .geometry =
275 Geometry{
Leon Scroggins III894c5f82023-08-25 14:43:54 -0400276 .boundaries = rect,
Nathaniel Nifong13491502021-06-30 17:28:29 -0400277 // Note that this flip matrix only makes a difference when clipping,
278 // which happens in this layer because the roundrect crop is just a bit
279 // larger than the layer bounds.
280 .positionTransform = kFlip,
Vishnu Nair50c0afe2022-07-11 15:04:07 -0700281 .roundedCornersRadius = {94.2551f, 94.2551f},
282 .roundedCornersCrop = FloatRect(-93.75, 0, displayRect.width() + 93.75,
283 displayRect.height()),
Nathaniel Nifong13491502021-06-30 17:28:29 -0400284 },
285 .source = PixelSource{.buffer =
286 Buffer{
287 .buffer = srcTexture,
Nathaniel Nifong13491502021-06-30 17:28:29 -0400288 .usePremultipliedAlpha = 1,
Leon Scroggins III894c5f82023-08-25 14:43:54 -0400289 .isOpaque = 0,
290 .maxLuminanceNits = 1000.f,
Nathaniel Nifong13491502021-06-30 17:28:29 -0400291 }},
Nathaniel Nifong13491502021-06-30 17:28:29 -0400292 .alpha = 1,
Leon Scroggins III894c5f82023-08-25 14:43:54 -0400293 .sourceDataspace = kOtherDataSpace,
Nathaniel Nifong13491502021-06-30 17:28:29 -0400294
295 };
296
Sally Qi59a9f502021-10-12 18:53:23 +0000297 auto layers = std::vector<LayerSettings>{layer};
Alec Mourif29700f2023-08-17 21:53:31 +0000298 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
Nathaniel Nifong13491502021-06-30 17:28:29 -0400299}
300
301static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
302 const std::shared_ptr<ExternalTexture>& dstTexture) {
303 const Rect& displayRect = display.physicalDisplay;
304 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
305 FloatRect small(0, 0, displayRect.width()-20, displayRect.height()+20);
306 LayerSettings layer{
307 .geometry =
308 Geometry{
Nathaniel Nifong13491502021-06-30 17:28:29 -0400309 // the boundaries have to be smaller than the rounded crop so that
310 // clipRRect is used instead of drawRRect
311 .boundaries = small,
Leon Scroggins III894c5f82023-08-25 14:43:54 -0400312 .positionTransform = kScaleAndTranslate,
Vishnu Nair50c0afe2022-07-11 15:04:07 -0700313 .roundedCornersRadius = {50.f, 50.f},
Nathaniel Nifong13491502021-06-30 17:28:29 -0400314 .roundedCornersCrop = rect,
315 },
Vishnu Nair50c0afe2022-07-11 15:04:07 -0700316 .source =
317 PixelSource{
Nathaniel Nifong13491502021-06-30 17:28:29 -0400318 .solidColor = half3(0.f, 0.f, 0.f),
319 },
Nathaniel Nifong13491502021-06-30 17:28:29 -0400320 .alpha = 0,
Leon Scroggins III894c5f82023-08-25 14:43:54 -0400321 .sourceDataspace = kDestDataSpace,
Nathaniel Nifong13491502021-06-30 17:28:29 -0400322 .disableBlending = true,
323
324 };
325
Sally Qi59a9f502021-10-12 18:53:23 +0000326 auto layers = std::vector<LayerSettings>{layer};
Alec Mourif29700f2023-08-17 21:53:31 +0000327 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
Nathaniel Nifong13491502021-06-30 17:28:29 -0400328}
329
Mattias Simonsson65746132023-08-15 13:26:16 +0000330static void drawImageDimmedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
331 const std::shared_ptr<ExternalTexture>& dstTexture,
332 const std::shared_ptr<ExternalTexture>& srcTexture) {
333 const Rect& displayRect = display.physicalDisplay;
334 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
335 LayerSettings layer{
336 .geometry =
337 Geometry{
338 // The position transform doesn't matter when the reduced shader mode
339 // in in effect. A matrix transform stage is always included.
340 .positionTransform = mat4(),
341 .boundaries = rect,
342 .roundedCornersCrop = rect,
343 .roundedCornersRadius = {0.f, 0.f},
344 },
345 .source = PixelSource{.buffer = Buffer{.buffer = srcTexture,
346 .maxLuminanceNits = 1000.f,
347 .usePremultipliedAlpha = true,
348 .isOpaque = true}},
349 .alpha = 1.f,
350 .sourceDataspace = kDestDataSpace,
351 };
352
353 std::vector<LayerSettings> layers;
354
355 for (auto layerWhitePoint : kLayerWhitePoints) {
356 layer.whitePointNits = layerWhitePoint;
357 layers.push_back(layer);
358 }
359 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
360}
361
362static void drawTransparentImageDimmedLayers(SkiaRenderEngine* renderengine,
363 const DisplaySettings& display,
364 const std::shared_ptr<ExternalTexture>& dstTexture,
365 const std::shared_ptr<ExternalTexture>& srcTexture) {
366 const Rect& displayRect = display.physicalDisplay;
367 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
368 LayerSettings layer{
369 .geometry =
370 Geometry{
371 .positionTransform = mat4(),
372 .boundaries = rect,
373 .roundedCornersCrop = rect,
374 },
375 .source = PixelSource{.buffer =
376 Buffer{
377 .buffer = srcTexture,
378 .maxLuminanceNits = 1000.f,
379 .usePremultipliedAlpha = true,
380 .isOpaque = false,
381 }},
382 .sourceDataspace = kDestDataSpace,
383 };
384
385 for (auto roundedCornerRadius : {0.f, 50.f}) {
386 layer.geometry.roundedCornersRadius = {roundedCornerRadius, roundedCornerRadius};
387 for (auto alpha : {0.5f, 1.0f}) {
388 layer.alpha = alpha;
Mattias Simonsson5860d922023-08-16 13:47:41 +0000389 for (auto isOpaque : {true, false}) {
390 if (roundedCornerRadius == 0.f && isOpaque) {
391 // already covered in drawImageDimmedLayers
392 continue;
393 }
Mattias Simonsson65746132023-08-15 13:26:16 +0000394
Mattias Simonsson5860d922023-08-16 13:47:41 +0000395 layer.source.buffer.isOpaque = isOpaque;
396 std::vector<LayerSettings> layers;
397
398 for (auto layerWhitePoint : kLayerWhitePoints) {
399 layer.whitePointNits = layerWhitePoint;
400 layers.push_back(layer);
401 }
402 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
Mattias Simonsson65746132023-08-15 13:26:16 +0000403 }
Mattias Simonsson65746132023-08-15 13:26:16 +0000404 }
405 }
406}
407
408static void drawClippedDimmedImageLayers(SkiaRenderEngine* renderengine,
409 const DisplaySettings& display,
410 const std::shared_ptr<ExternalTexture>& dstTexture,
411 const std::shared_ptr<ExternalTexture>& srcTexture) {
412 const Rect& displayRect = display.physicalDisplay;
413
414 // If rect and boundary is too small compared to roundedCornersRadius, Skia will switch to
415 // blending instead of EllipticalRRect, so enlarge them a bit.
416 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
417 FloatRect boundary(0, 0, displayRect.width(),
418 displayRect.height() - 20); // boundary is smaller
419 LayerSettings layer{
420 .geometry =
421 Geometry{
422 .positionTransform = mat4(),
423 .boundaries = boundary,
424 .roundedCornersCrop = rect,
425 .roundedCornersRadius = {27.f, 27.f},
426 },
427 .source = PixelSource{.buffer =
428 Buffer{
429 .buffer = srcTexture,
430 .maxLuminanceNits = 1000.f,
431 .usePremultipliedAlpha = true,
432 .isOpaque = false,
433 }},
434 .alpha = 1.f,
435 .sourceDataspace = kDestDataSpace,
436 };
437
438 std::array<mat4, 2> transforms = {kScaleAndTranslate, kScaleAsymmetric};
439
440 constexpr float radius = 27.f;
441
442 for (size_t i = 0; i < transforms.size(); i++) {
443 layer.geometry.positionTransform = transforms[i];
444 layer.geometry.roundedCornersRadius = {radius, radius};
445
446 std::vector<LayerSettings> layers;
447
448 for (auto layerWhitePoint : kLayerWhitePoints) {
449 layer.whitePointNits = layerWhitePoint;
450 layers.push_back(layer);
451 }
452 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
453 }
454}
455
456static void drawSolidDimmedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
457 const std::shared_ptr<ExternalTexture>& dstTexture) {
458 const Rect& displayRect = display.physicalDisplay;
459 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
460 LayerSettings layer{
461 .geometry =
462 Geometry{
463 .boundaries = rect,
464 .roundedCornersCrop = rect,
465 },
466 .source =
467 PixelSource{
468 .solidColor = half3(0.1f, 0.2f, 0.3f),
469 },
470 .alpha = 1.f,
471 };
472
473 std::vector<LayerSettings> layers;
474
475 for (auto layerWhitePoint : kLayerWhitePoints) {
476 layer.whitePointNits = layerWhitePoint;
477 layers.push_back(layer);
478 }
479 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
480}
481
Mattias Simonsson458adf12023-08-16 10:49:30 +0000482static void drawBT2020ImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
483 const std::shared_ptr<ExternalTexture>& dstTexture,
484 const std::shared_ptr<ExternalTexture>& srcTexture) {
485 const Rect& displayRect = display.physicalDisplay;
486 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
487 LayerSettings layer{
488 .geometry =
489 Geometry{
490 // The position transform doesn't matter when the reduced shader mode
491 // in in effect. A matrix transform stage is always included.
492 .positionTransform = mat4(),
493 .boundaries = rect,
494 .roundedCornersCrop = rect,
495 .roundedCornersRadius = {0.f, 0.f},
496 },
497 .source = PixelSource{.buffer = Buffer{.buffer = srcTexture,
498 .maxLuminanceNits = 1000.f,
499 .usePremultipliedAlpha = true,
500 .isOpaque = true}},
501 .alpha = 1.f,
502 .sourceDataspace = kBT2020DataSpace,
503 };
504
505 for (auto alpha : {0.5f, 1.f}) {
506 layer.alpha = alpha;
507 std::vector<LayerSettings> layers;
508 layer.whitePointNits = -1.f;
509 layers.push_back(layer);
510
511 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
512 }
513}
514static void drawBT2020ClippedImageLayers(SkiaRenderEngine* renderengine,
515 const DisplaySettings& display,
516 const std::shared_ptr<ExternalTexture>& dstTexture,
517 const std::shared_ptr<ExternalTexture>& srcTexture) {
518 const Rect& displayRect = display.physicalDisplay;
519
520 // If rect and boundary is too small compared to roundedCornersRadius, Skia will switch to
521 // blending instead of EllipticalRRect, so enlarge them a bit.
522 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
523 FloatRect boundary(0, 0, displayRect.width(),
524 displayRect.height() - 10); // boundary is smaller
525 LayerSettings layer{
526 .geometry =
527 Geometry{
528 .positionTransform = kScaleAsymmetric,
529 .boundaries = boundary,
530 .roundedCornersCrop = rect,
531 .roundedCornersRadius = {64.1f, 64.1f},
532 },
533 .source = PixelSource{.buffer =
534 Buffer{
535 .buffer = srcTexture,
536 .maxLuminanceNits = 1000.f,
537 .usePremultipliedAlpha = true,
538 .isOpaque = true,
539 }},
540 .alpha = 0.5f,
541 .sourceDataspace = kBT2020DataSpace,
542 };
543
544 std::vector<LayerSettings> layers = {layer};
545 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
546}
547
Mattias Simonsson5860d922023-08-16 13:47:41 +0000548static void drawExtendedHDRImageLayers(SkiaRenderEngine* renderengine,
549 const DisplaySettings& display,
550 const std::shared_ptr<ExternalTexture>& dstTexture,
551 const std::shared_ptr<ExternalTexture>& srcTexture) {
552 const Rect& displayRect = display.physicalDisplay;
553 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
554 LayerSettings layer{
555 .geometry =
556 Geometry{
557 // The position transform doesn't matter when the reduced shader mode
558 // in in effect. A matrix transform stage is always included.
559 .positionTransform = mat4(),
560 .boundaries = rect,
561 .roundedCornersCrop = rect,
562 .roundedCornersRadius = {50.f, 50.f},
563 },
564 .source = PixelSource{.buffer = Buffer{.buffer = srcTexture,
565 .maxLuminanceNits = 1000.f,
566 .usePremultipliedAlpha = true,
567 .isOpaque = true}},
568 .alpha = 0.5f,
569 .sourceDataspace = kExtendedHdrDataSpce,
570 };
571
572 for (auto roundedCornerRadius : {0.f, 50.f}) {
573 layer.geometry.roundedCornersRadius = {roundedCornerRadius, roundedCornerRadius};
574 for (auto alpha : {0.5f, 1.f}) {
575 layer.alpha = alpha;
576 std::vector<LayerSettings> layers;
577
578 for (auto layerWhitePoint : kLayerWhitePoints) {
579 layer.whitePointNits = layerWhitePoint;
580 layers.push_back(layer);
581 }
582 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
583 }
584 }
585}
586
587static void drawP3ImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
588 const std::shared_ptr<ExternalTexture>& dstTexture,
589 const std::shared_ptr<ExternalTexture>& srcTexture) {
590 const Rect& displayRect = display.physicalDisplay;
591 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
592 LayerSettings layer{
593 .geometry =
594 Geometry{
595 // The position transform doesn't matter when the reduced shader mode
596 // in in effect. A matrix transform stage is always included.
597 .positionTransform = mat4(),
598 .boundaries = rect,
599 .roundedCornersCrop = rect,
600 .roundedCornersRadius = {50.f, 50.f},
601 },
602 .source = PixelSource{.buffer = Buffer{.buffer = srcTexture,
603 .maxLuminanceNits = 1000.f,
604 .usePremultipliedAlpha = true,
605 .isOpaque = false}},
606 .alpha = 0.5f,
607 .sourceDataspace = kOtherDataSpace,
608 };
609
610 for (auto alpha : {0.5f, 1.f}) {
611 layer.alpha = alpha;
612 std::vector<LayerSettings> layers;
613
614 for (auto layerWhitePoint : kLayerWhitePoints) {
615 layer.whitePointNits = layerWhitePoint;
616 layers.push_back(layer);
617 }
618 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
619 }
620}
621
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400622//
623// The collection of shaders cached here were found by using perfetto to record shader compiles
624// during actions that involve RenderEngine, logging the layer settings, and the shader code
625// and reproducing those settings here.
626//
627// It is helpful when debugging this to turn on
628// in SkGLRenderEngine.cpp:
629// kPrintLayerSettings = true
630// kFlushAfterEveryLayer = true
631// in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
632// gPrintSKSL = true
Russell Myers3348c742024-04-29 20:22:42 +0000633void Cache::primeShaderCache(SkiaRenderEngine* renderengine, PrimeCacheConfig config) {
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400634 const int previousCount = renderengine->reportShadersCompiled();
635 if (previousCount) {
636 ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount);
637 }
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500638
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400639 // The loop is beneficial for debugging and should otherwise be optimized out by the compiler.
640 // Adding additional bounds to the loop is useful for verifying that the size of the dst buffer
641 // does not impact the shader compilation counts by triggering different behaviors in RE/Skia.
642 for (SkSize bounds : {SkSize::Make(128, 128), /*SkSize::Make(1080, 2340)*/}) {
643 const nsecs_t timeBefore = systemTime();
644 // The dimensions should not matter, so long as we draw inside them.
645 const Rect displayRect(0, 0, bounds.fWidth, bounds.fHeight);
646 DisplaySettings display{
647 .physicalDisplay = displayRect,
648 .clip = displayRect,
649 .maxLuminance = 500,
650 .outputDataspace = kDestDataSpace,
651 };
Nathaniel Nifonga6b54232021-07-02 13:24:32 -0400652 DisplaySettings p3Display{
653 .physicalDisplay = displayRect,
654 .clip = displayRect,
655 .maxLuminance = 500,
656 .outputDataspace = kOtherDataSpace,
657 };
Mattias Simonsson5860d922023-08-16 13:47:41 +0000658 DisplaySettings p3DisplayEnhance{.physicalDisplay = displayRect,
659 .clip = displayRect,
660 .maxLuminance = 500,
661 .outputDataspace = kOtherDataSpace,
662 .dimmingStage = aidl::android::hardware::graphics::
663 composer3::DimmingStage::GAMMA_OETF,
664 .renderIntent = aidl::android::hardware::graphics::
665 composer3::RenderIntent::ENHANCE};
Mattias Simonsson65746132023-08-15 13:26:16 +0000666 DisplaySettings bt2020Display{.physicalDisplay = displayRect,
667 .clip = displayRect,
668 .maxLuminance = 500,
669 .outputDataspace = ui::Dataspace::BT2020,
670 .deviceHandlesColorTransform = true,
671 .dimmingStage = aidl::android::hardware::graphics::composer3::
672 DimmingStage::GAMMA_OETF,
673 .renderIntent = aidl::android::hardware::graphics::composer3::
674 RenderIntent::TONE_MAP_ENHANCE};
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500675
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400676 const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
Alec Mouria90a5702021-04-16 16:36:21 +0000677
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400678 sp<GraphicBuffer> dstBuffer =
Ady Abrahamd11bade2022-08-01 16:18:03 -0700679 sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
680 PIXEL_FORMAT_RGBA_8888, 1, usage, "primeShaderCache_dst");
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400681
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400682 const auto dstTexture =
Vishnu Nairdbbe3852022-01-12 20:22:11 -0800683 std::make_shared<impl::ExternalTexture>(dstBuffer, *renderengine,
684 impl::ExternalTexture::Usage::WRITEABLE);
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400685 // This buffer will be the source for the call to drawImageLayers. Draw
686 // something to it as a placeholder for what an app draws. We should draw
687 // something, but the details are not important. Make use of the shadow layer drawing step
688 // to populate it.
689 sp<GraphicBuffer> srcBuffer =
Ady Abrahamd11bade2022-08-01 16:18:03 -0700690 sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
691 PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src");
Alec Mouria90a5702021-04-16 16:36:21 +0000692
Vishnu Nairdbbe3852022-01-12 20:22:11 -0800693 const auto srcTexture = std::make_shared<
694 impl::ExternalTexture>(srcBuffer, *renderengine,
695 impl::ExternalTexture::Usage::READABLE |
696 impl::ExternalTexture::Usage::WRITEABLE);
Nathaniel Nifong49a59582021-07-26 19:49:47 -0400697
Russell Myers3348c742024-04-29 20:22:42 +0000698 if (config.cacheHolePunchLayer) {
699 drawHolePunchLayer(renderengine, display, dstTexture);
700 }
701
702 if (config.cacheSolidLayers) {
703 drawSolidLayers(renderengine, display, dstTexture);
704 drawSolidLayers(renderengine, p3Display, dstTexture);
705 }
706
707 if (config.cacheSolidDimmedLayers) {
708 drawSolidDimmedLayers(renderengine, display, dstTexture);
709 }
710
711 if (config.cacheShadowLayers) {
712 drawShadowLayers(renderengine, display, srcTexture);
713 drawShadowLayers(renderengine, p3Display, srcTexture);
714 }
Nathaniel Nifongcda45e92021-06-10 15:01:42 -0400715
716 if (renderengine->supportsBackgroundBlur()) {
717 drawBlurLayers(renderengine, display, dstTexture);
718 }
719
Nathaniel Nifong73537a32021-08-06 15:07:26 -0400720 // The majority of skia shaders needed by RenderEngine are related to sampling images.
721 // These need to be generated with various source textures.
722 // Make a list of applicable sources.
723 // GRALLOC_USAGE_HW_TEXTURE should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400724 const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400725 sp<GraphicBuffer> externalBuffer =
Ady Abrahamd11bade2022-08-01 16:18:03 -0700726 sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
727 PIXEL_FORMAT_RGBA_8888, 1, usageExternal,
728 "primeShaderCache_external");
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400729 const auto externalTexture =
Vishnu Nairdbbe3852022-01-12 20:22:11 -0800730 std::make_shared<impl::ExternalTexture>(externalBuffer, *renderengine,
731 impl::ExternalTexture::Usage::READABLE);
Ryan Prichard40800e12024-06-27 23:03:32 -0700732 std::vector<std::shared_ptr<ExternalTexture>> textures = {srcTexture, externalTexture};
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400733
Nathaniel Nifong73537a32021-08-06 15:07:26 -0400734 // Another external texture with a different pixel format triggers useIsOpaqueWorkaround.
735 // It doesn't have to be f16, but it can't be the usual 8888.
Nathaniel Nifongf06a45b2021-06-25 17:24:26 -0400736 sp<GraphicBuffer> f16ExternalBuffer =
Ady Abrahamd11bade2022-08-01 16:18:03 -0700737 sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
738 PIXEL_FORMAT_RGBA_FP16, 1, usageExternal,
739 "primeShaderCache_external_f16");
Nathaniel Nifong73537a32021-08-06 15:07:26 -0400740 // The F16 texture may not be usable on all devices, so check first that it was created.
741 status_t error = f16ExternalBuffer->initCheck();
742 if (!error) {
743 const auto f16ExternalTexture =
Vishnu Nairdbbe3852022-01-12 20:22:11 -0800744 std::make_shared<impl::ExternalTexture>(f16ExternalBuffer, *renderengine,
745 impl::ExternalTexture::Usage::READABLE);
Nathaniel Nifong73537a32021-08-06 15:07:26 -0400746 textures.push_back(f16ExternalTexture);
747 }
Nathaniel Nifongf06a45b2021-06-25 17:24:26 -0400748
Nathaniel Nifong73537a32021-08-06 15:07:26 -0400749 for (auto texture : textures) {
Russell Myers3348c742024-04-29 20:22:42 +0000750 if (config.cacheImageLayers) {
751 drawImageLayers(renderengine, display, dstTexture, texture);
752 }
Mattias Simonsson5860d922023-08-16 13:47:41 +0000753
Russell Myers3348c742024-04-29 20:22:42 +0000754 if (config.cacheImageDimmedLayers) {
755 drawImageDimmedLayers(renderengine, display, dstTexture, texture);
756 drawImageDimmedLayers(renderengine, p3Display, dstTexture, texture);
757 drawImageDimmedLayers(renderengine, bt2020Display, dstTexture, texture);
758 }
Mattias Simonsson5860d922023-08-16 13:47:41 +0000759
Russell Myers3348c742024-04-29 20:22:42 +0000760 if (config.cacheClippedLayers) {
761 // Draw layers for b/185569240.
762 drawClippedLayers(renderengine, display, dstTexture, texture);
763 }
Nathaniel Nifongf06a45b2021-06-25 17:24:26 -0400764 }
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400765
Russell Myers3348c742024-04-29 20:22:42 +0000766 if (config.cachePIPImageLayers) {
767 drawPIPImageLayer(renderengine, display, dstTexture, externalTexture);
768 }
Nathaniel Nifong13491502021-06-30 17:28:29 -0400769
Russell Myers3348c742024-04-29 20:22:42 +0000770 if (config.cacheTransparentImageDimmedLayers) {
771 drawTransparentImageDimmedLayers(renderengine, bt2020Display, dstTexture,
772 externalTexture);
773 drawTransparentImageDimmedLayers(renderengine, display, dstTexture, externalTexture);
774 drawTransparentImageDimmedLayers(renderengine, p3Display, dstTexture, externalTexture);
775 drawTransparentImageDimmedLayers(renderengine, p3DisplayEnhance, dstTexture,
776 externalTexture);
777 }
Mattias Simonsson65746132023-08-15 13:26:16 +0000778
Russell Myers3348c742024-04-29 20:22:42 +0000779 if (config.cacheClippedDimmedImageLayers) {
780 drawClippedDimmedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture);
781 }
Mattias Simonsson458adf12023-08-16 10:49:30 +0000782
Russell Myers3348c742024-04-29 20:22:42 +0000783 if (config.cacheUltraHDR) {
Bruno BELANYIb9b5b702023-10-13 13:25:11 +0000784 drawBT2020ClippedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture);
Mattias Simonsson65746132023-08-15 13:26:16 +0000785
Bruno BELANYIb9b5b702023-10-13 13:25:11 +0000786 drawBT2020ImageLayers(renderengine, bt2020Display, dstTexture, externalTexture);
787 drawBT2020ImageLayers(renderengine, p3Display, dstTexture, externalTexture);
Mattias Simonsson5860d922023-08-16 13:47:41 +0000788
Bruno BELANYIb9b5b702023-10-13 13:25:11 +0000789 drawExtendedHDRImageLayers(renderengine, display, dstTexture, externalTexture);
790 drawExtendedHDRImageLayers(renderengine, p3Display, dstTexture, externalTexture);
791 drawExtendedHDRImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture);
792
793 drawP3ImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture);
794 }
Mattias Simonsson5860d922023-08-16 13:47:41 +0000795
Nathaniel Nifong2d2f4322021-07-22 15:17:36 -0400796 // draw one final layer synchronously to force GL submit
797 LayerSettings layer{
798 .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)},
799 };
Sally Qi59a9f502021-10-12 18:53:23 +0000800 auto layers = std::vector<LayerSettings>{layer};
Sally Qi4cabdd02021-08-05 16:45:57 -0700801 // call get() to make it synchronous
Alec Mourif29700f2023-08-17 21:53:31 +0000802 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()).get();
Nathaniel Nifong2d2f4322021-07-22 15:17:36 -0400803
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400804 const nsecs_t timeAfter = systemTime();
805 const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
Leon Scroggins III45be9182022-04-27 10:37:11 -0400806 const int shadersCompiled = renderengine->reportShadersCompiled() - previousCount;
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400807 ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs);
808 }
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500809}
810
811} // namespace android::renderengine::skia