1 /*
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 */
16 #include "Cache.h"
17
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19
20 #include "AutoBackendTexture.h"
21 #include "SkiaRenderEngine.h"
22 #include "android-base/unique_fd.h"
23 #include "cutils/properties.h"
24 #include "renderengine/DisplaySettings.h"
25 #include "renderengine/LayerSettings.h"
26 #include "renderengine/impl/ExternalTexture.h"
27 #include "ui/GraphicBuffer.h"
28 #include "ui/GraphicTypes.h"
29 #include "ui/PixelFormat.h"
30 #include "ui/Rect.h"
31 #include "utils/Timers.h"
32
33 #include <com_android_graphics_libgui_flags.h>
34 #include <common/trace.h>
35
36 namespace android::renderengine::skia {
37
38 namespace {
39
40 // clang-format off
41 // Any non-identity matrix will do.
42 const auto kScaleAndTranslate = mat4(0.7f, 0.f, 0.f, 0.f,
43 0.f, 0.7f, 0.f, 0.f,
44 0.f, 0.f, 1.f, 0.f,
45 67.3f, 52.2f, 0.f, 1.f);
46 const auto kScaleAsymmetric = mat4(0.8f, 0.f, 0.f, 0.f,
47 0.f, 1.1f, 0.f, 0.f,
48 0.f, 0.f, 1.f, 0.f,
49 0.f, 0.f, 0.f, 1.f);
50 const auto kFlip = mat4(1.1f, -0.1f, 0.f, 0.f,
51 0.1f, 1.1f, 0.f, 0.f,
52 0.f, 0.f, 1.f, 0.f,
53 2.f, 2.f, 0.f, 1.f);
54 // clang-format on
55 // When setting layer.sourceDataspace, whether it matches the destination or not determines whether
56 // a color correction effect is added to the shader.
57 constexpr auto kDestDataSpace = ui::Dataspace::SRGB;
58 constexpr auto kOtherDataSpace = ui::Dataspace::DISPLAY_P3;
59 constexpr auto kBT2020DataSpace = ui::Dataspace::BT2020_ITU_PQ;
60 constexpr auto kExtendedHdrDataSpce =
61 static_cast<ui::Dataspace>(ui::Dataspace::RANGE_EXTENDED | ui::Dataspace::TRANSFER_SRGB |
62 ui::Dataspace::STANDARD_DCI_P3);
63 // Dimming is needed to trigger linear effects for some dataspace pairs
64 const std::array<float, 3> kLayerWhitePoints = {
65 1000.0f, 500.0f,
66 100.0f, // trigger dithering by dimming below 20%
67 };
68 } // namespace
69
drawShadowLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture)70 static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
71 const std::shared_ptr<ExternalTexture>& dstTexture) {
72 // Somewhat arbitrary dimensions, but on screen and slightly shorter, based
73 // on actual use.
74 const Rect& displayRect = display.physicalDisplay;
75 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
76 FloatRect smallerRect(20, 20, displayRect.width()-20, displayRect.height()-20);
77
78 LayerSettings layer{
79 .geometry =
80 Geometry{
81 .boundaries = rect,
82 .roundedCornersRadius = {50.f, 50.f},
83 .roundedCornersCrop = rect,
84 },
85 .alpha = 1,
86 // setting this is mandatory for shadows and blurs
87 .skipContentDraw = true,
88 // drawShadow ignores alpha
89 .shadow =
90 ShadowSettings{
91 .boundaries = rect,
92 .ambientColor = vec4(0, 0, 0, 0.00935997f),
93 .spotColor = vec4(0, 0, 0, 0.0455841f),
94 .lightPos = vec3(500.f, -1500.f, 1500.f),
95 .lightRadius = 2500.0f,
96 .length = 15.f,
97 },
98 };
99 LayerSettings caster{
100 .geometry =
101 Geometry{
102 .boundaries = smallerRect,
103 .roundedCornersRadius = {50.f, 50.f},
104 .roundedCornersCrop = rect,
105 },
106 .source =
107 PixelSource{
108 .solidColor = half3(0.f, 0.f, 0.f),
109 },
110 .alpha = 1,
111 };
112
113 // Four combinations of settings are used (two transforms here, and drawShadowLayers is
114 // called with two different destination data spaces) They're all rounded rect.
115 // Three of these are cache misses that generate new shaders.
116 // The first combination generates a short and simple shadow shader.
117 // The second combination, flip transform, generates two shaders. The first appears to involve
118 // gaussian_fp. The second is a long and general purpose shadow shader with a device space
119 // transformation stage.
120 // The third combination is a cache hit, nothing new.
121 // The fourth combination, flip transform with a non-SRGB destination dataspace, is new.
122 // It is unique in that nearly everything is done in the vertex shader, and that vertex shader
123 // requires color correction. This is triggered differently from every other instance of color
124 // correction. All other instances are triggered when src and dst dataspaces differ, while
125 // this one is triggered by the destination being non-srgb. Apparently since the third
126 // combination is a cache hit, this color correction is only added when the vertex shader is
127 // doing something non-trivial.
128 for (auto transform : {mat4(), kFlip}) {
129 layer.geometry.positionTransform = transform;
130 caster.geometry.positionTransform = transform;
131
132 auto layers = std::vector<LayerSettings>{layer, caster};
133 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
134 }
135 }
136
drawImageLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)137 static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
138 const std::shared_ptr<ExternalTexture>& dstTexture,
139 const std::shared_ptr<ExternalTexture>& srcTexture) {
140 const Rect& displayRect = display.physicalDisplay;
141 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
142 LayerSettings layer{
143 .geometry =
144 Geometry{
145 .boundaries = rect,
146 // The position transform doesn't matter when the reduced shader mode
147 // in in effect. A matrix transform stage is always included.
148 .positionTransform = mat4(),
149 .roundedCornersCrop = rect,
150 },
151 .source = PixelSource{.buffer =
152 Buffer{
153 .buffer = srcTexture,
154 .maxLuminanceNits = 1000.f,
155 }},
156 };
157
158 for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
159 layer.sourceDataspace = dataspace;
160 // Cache shaders for both rects and round rects.
161 // In reduced shader mode, all non-zero round rect radii get the same code path.
162 for (float roundedCornersRadius : {0.0f, 50.0f}) {
163 // roundedCornersCrop is always set, but the radius triggers the behavior
164 layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius};
165 for (bool isOpaque : {true, false}) {
166 layer.source.buffer.isOpaque = isOpaque;
167 for (auto alpha : {half(.2f), half(1.0f)}) {
168 layer.alpha = alpha;
169 auto layers = std::vector<LayerSettings>{layer};
170 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
171 }
172 }
173 }
174 }
175 }
176
drawSolidLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture)177 static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
178 const std::shared_ptr<ExternalTexture>& dstTexture) {
179 const Rect& displayRect = display.physicalDisplay;
180 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
181 LayerSettings layer{
182 .geometry =
183 Geometry{
184 .boundaries = rect,
185 },
186 .source =
187 PixelSource{
188 .solidColor = half3(0.1f, 0.2f, 0.3f),
189 },
190 .alpha = 0.5,
191 };
192
193 for (auto transform : {mat4(), kScaleAndTranslate}) {
194 layer.geometry.positionTransform = transform;
195 for (float roundedCornersRadius : {0.0f, 50.f}) {
196 layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius};
197 auto layers = std::vector<LayerSettings>{layer};
198 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
199 }
200 }
201 }
202
drawBlurLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture)203 static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
204 const std::shared_ptr<ExternalTexture>& dstTexture) {
205 const Rect& displayRect = display.physicalDisplay;
206 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
207 LayerSettings layer{
208 .geometry =
209 Geometry{
210 .boundaries = rect,
211 },
212 .alpha = 1,
213 // setting this is mandatory for shadows and blurs
214 .skipContentDraw = true,
215 };
216
217 // Different blur code is invoked for radii less and greater than 30 pixels
218 for (int radius : {9, 60}) {
219 layer.backgroundBlurRadius = radius;
220 auto layers = std::vector<LayerSettings>{layer};
221 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
222 }
223 }
224
225 // The unique feature of these layers is that the boundary is slightly smaller than the rounded
226 // rect crop, so the rounded edges intersect that boundary and require a different clipping method.
227 // For buffers, this is done with a stage that computes coverage and it will differ for round and
228 // elliptical corners.
drawClippedLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)229 static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
230 const std::shared_ptr<ExternalTexture>& dstTexture,
231 const std::shared_ptr<ExternalTexture>& srcTexture) {
232 const Rect& displayRect = display.physicalDisplay;
233 FloatRect rect(0, 0, displayRect.width(), displayRect.height() - 20); // boundary is smaller
234
235 PixelSource bufferSource{.buffer = Buffer{
236 .buffer = srcTexture,
237 .isOpaque = 0,
238 .maxLuminanceNits = 1000.f,
239 }};
240 PixelSource bufferOpaque{.buffer = Buffer{
241 .buffer = srcTexture,
242 .isOpaque = 1,
243 .maxLuminanceNits = 1000.f,
244 }};
245 PixelSource colorSource{.solidColor = half3(0.1f, 0.2f, 0.3f)};
246
247 LayerSettings layer{
248 .geometry =
249 Geometry{
250 .boundaries = rect,
251 .roundedCornersRadius = {27.f, 27.f},
252 .roundedCornersCrop =
253 FloatRect(0, 0, displayRect.width(), displayRect.height()),
254 },
255 };
256
257 for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
258 layer.source = pixelSource;
259 for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
260 layer.sourceDataspace = dataspace;
261 // Produce a CircularRRect clip and an EllipticalRRect clip.
262 for (auto transform : {kScaleAndTranslate, kScaleAsymmetric}) {
263 layer.geometry.positionTransform = transform;
264 for (float alpha : {0.5f, 1.f}) {
265 layer.alpha = alpha;
266 auto layers = std::vector<LayerSettings>{layer};
267 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
268 }
269 }
270 }
271 }
272 }
273
drawPIPImageLayer(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)274 static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
275 const std::shared_ptr<ExternalTexture>& dstTexture,
276 const std::shared_ptr<ExternalTexture>& srcTexture) {
277 const Rect& displayRect = display.physicalDisplay;
278 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
279 LayerSettings layer{
280 .geometry =
281 Geometry{
282 .boundaries = rect,
283 // Note that this flip matrix only makes a difference when clipping,
284 // which happens in this layer because the roundrect crop is just a bit
285 // larger than the layer bounds.
286 .positionTransform = kFlip,
287 .roundedCornersRadius = {94.2551f, 94.2551f},
288 .roundedCornersCrop = FloatRect(-93.75, 0, displayRect.width() + 93.75,
289 displayRect.height()),
290 },
291 .source = PixelSource{.buffer =
292 Buffer{
293 .buffer = srcTexture,
294 .usePremultipliedAlpha = 1,
295 .isOpaque = 0,
296 .maxLuminanceNits = 1000.f,
297 }},
298 .alpha = 1,
299 .sourceDataspace = kOtherDataSpace,
300
301 };
302
303 auto layers = std::vector<LayerSettings>{layer};
304 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
305 }
306
drawHolePunchLayer(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture)307 static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
308 const std::shared_ptr<ExternalTexture>& dstTexture) {
309 const Rect& displayRect = display.physicalDisplay;
310 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
311 FloatRect small(0, 0, displayRect.width()-20, displayRect.height()+20);
312 LayerSettings layer{
313 .geometry =
314 Geometry{
315 // the boundaries have to be smaller than the rounded crop so that
316 // clipRRect is used instead of drawRRect
317 .boundaries = small,
318 .positionTransform = kScaleAndTranslate,
319 .roundedCornersRadius = {50.f, 50.f},
320 .roundedCornersCrop = rect,
321 },
322 .source =
323 PixelSource{
324 .solidColor = half3(0.f, 0.f, 0.f),
325 },
326 .alpha = 0,
327 .sourceDataspace = kDestDataSpace,
328 .disableBlending = true,
329
330 };
331
332 auto layers = std::vector<LayerSettings>{layer};
333 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
334 }
335
drawImageDimmedLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)336 static void drawImageDimmedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
337 const std::shared_ptr<ExternalTexture>& dstTexture,
338 const std::shared_ptr<ExternalTexture>& srcTexture) {
339 const Rect& displayRect = display.physicalDisplay;
340 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
341 LayerSettings layer{
342 .geometry =
343 Geometry{
344 .boundaries = rect,
345 // The position transform doesn't matter when the reduced shader mode
346 // in in effect. A matrix transform stage is always included.
347 .positionTransform = mat4(),
348 .roundedCornersRadius = {0.f, 0.f},
349 .roundedCornersCrop = rect,
350 },
351 .source = PixelSource{.buffer = Buffer{.buffer = srcTexture,
352 .usePremultipliedAlpha = true,
353 .isOpaque = true,
354 .maxLuminanceNits = 1000.f}},
355 .alpha = 1.f,
356 .sourceDataspace = kDestDataSpace,
357 };
358
359 std::vector<LayerSettings> layers;
360
361 for (auto layerWhitePoint : kLayerWhitePoints) {
362 layer.whitePointNits = layerWhitePoint;
363 layers.push_back(layer);
364 }
365 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
366 }
367
drawTransparentImageDimmedLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)368 static void drawTransparentImageDimmedLayers(SkiaRenderEngine* renderengine,
369 const DisplaySettings& display,
370 const std::shared_ptr<ExternalTexture>& dstTexture,
371 const std::shared_ptr<ExternalTexture>& srcTexture) {
372 const Rect& displayRect = display.physicalDisplay;
373 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
374 LayerSettings layer{
375 .geometry =
376 Geometry{
377 .boundaries = rect,
378 .positionTransform = mat4(),
379 .roundedCornersCrop = rect,
380 },
381 .source = PixelSource{.buffer =
382 Buffer{
383 .buffer = srcTexture,
384 .usePremultipliedAlpha = true,
385 .isOpaque = false,
386 .maxLuminanceNits = 1000.f,
387 }},
388 .sourceDataspace = kDestDataSpace,
389 };
390
391 for (auto roundedCornerRadius : {0.f, 50.f}) {
392 layer.geometry.roundedCornersRadius = {roundedCornerRadius, roundedCornerRadius};
393 for (auto alpha : {0.5f, 1.0f}) {
394 layer.alpha = alpha;
395 for (auto isOpaque : {true, false}) {
396 if (roundedCornerRadius == 0.f && isOpaque) {
397 // already covered in drawImageDimmedLayers
398 continue;
399 }
400
401 layer.source.buffer.isOpaque = isOpaque;
402 std::vector<LayerSettings> layers;
403
404 for (auto layerWhitePoint : kLayerWhitePoints) {
405 layer.whitePointNits = layerWhitePoint;
406 layers.push_back(layer);
407 }
408 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
409 }
410 }
411 }
412 }
413
drawClippedDimmedImageLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)414 static void drawClippedDimmedImageLayers(SkiaRenderEngine* renderengine,
415 const DisplaySettings& display,
416 const std::shared_ptr<ExternalTexture>& dstTexture,
417 const std::shared_ptr<ExternalTexture>& srcTexture) {
418 const Rect& displayRect = display.physicalDisplay;
419
420 // If rect and boundary is too small compared to roundedCornersRadius, Skia will switch to
421 // blending instead of EllipticalRRect, so enlarge them a bit.
422 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
423 FloatRect boundary(0, 0, displayRect.width(),
424 displayRect.height() - 20); // boundary is smaller
425 LayerSettings layer{
426 .geometry =
427 Geometry{
428 .boundaries = boundary,
429 .positionTransform = mat4(),
430 .roundedCornersRadius = {27.f, 27.f},
431 .roundedCornersCrop = rect,
432 },
433 .source = PixelSource{.buffer =
434 Buffer{
435 .buffer = srcTexture,
436 .usePremultipliedAlpha = true,
437 .isOpaque = false,
438 .maxLuminanceNits = 1000.f,
439 }},
440 .alpha = 1.f,
441 .sourceDataspace = kDestDataSpace,
442 };
443
444 std::array<mat4, 2> transforms = {kScaleAndTranslate, kScaleAsymmetric};
445
446 constexpr float radius = 27.f;
447
448 for (size_t i = 0; i < transforms.size(); i++) {
449 layer.geometry.positionTransform = transforms[i];
450 layer.geometry.roundedCornersRadius = {radius, radius};
451
452 std::vector<LayerSettings> layers;
453
454 for (auto layerWhitePoint : kLayerWhitePoints) {
455 layer.whitePointNits = layerWhitePoint;
456 layers.push_back(layer);
457 }
458 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
459 }
460 }
461
drawSolidDimmedLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture)462 static void drawSolidDimmedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
463 const std::shared_ptr<ExternalTexture>& dstTexture) {
464 const Rect& displayRect = display.physicalDisplay;
465 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
466 LayerSettings layer{
467 .geometry =
468 Geometry{
469 .boundaries = rect,
470 .roundedCornersCrop = rect,
471 },
472 .source =
473 PixelSource{
474 .solidColor = half3(0.1f, 0.2f, 0.3f),
475 },
476 .alpha = 1.f,
477 };
478
479 std::vector<LayerSettings> layers;
480
481 for (auto layerWhitePoint : kLayerWhitePoints) {
482 layer.whitePointNits = layerWhitePoint;
483 layers.push_back(layer);
484 }
485 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
486 }
487
drawBT2020ImageLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)488 static void drawBT2020ImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
489 const std::shared_ptr<ExternalTexture>& dstTexture,
490 const std::shared_ptr<ExternalTexture>& srcTexture) {
491 const Rect& displayRect = display.physicalDisplay;
492 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
493 LayerSettings layer{
494 .geometry =
495 Geometry{
496 .boundaries = rect,
497 // The position transform doesn't matter when the reduced shader mode
498 // in in effect. A matrix transform stage is always included.
499 .positionTransform = mat4(),
500 .roundedCornersRadius = {0.f, 0.f},
501 .roundedCornersCrop = rect,
502 },
503 .source = PixelSource{.buffer = Buffer{.buffer = srcTexture,
504 .usePremultipliedAlpha = true,
505 .isOpaque = true,
506 .maxLuminanceNits = 1000.f}},
507 .alpha = 1.f,
508 .sourceDataspace = kBT2020DataSpace,
509 };
510
511 for (auto alpha : {0.5f, 1.f}) {
512 layer.alpha = alpha;
513 std::vector<LayerSettings> layers;
514 layer.whitePointNits = -1.f;
515 layers.push_back(layer);
516
517 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
518 }
519 }
drawBT2020ClippedImageLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)520 static void drawBT2020ClippedImageLayers(SkiaRenderEngine* renderengine,
521 const DisplaySettings& display,
522 const std::shared_ptr<ExternalTexture>& dstTexture,
523 const std::shared_ptr<ExternalTexture>& srcTexture) {
524 const Rect& displayRect = display.physicalDisplay;
525
526 // If rect and boundary is too small compared to roundedCornersRadius, Skia will switch to
527 // blending instead of EllipticalRRect, so enlarge them a bit.
528 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
529 FloatRect boundary(0, 0, displayRect.width(),
530 displayRect.height() - 10); // boundary is smaller
531 LayerSettings layer{
532 .geometry =
533 Geometry{
534 .boundaries = boundary,
535 .positionTransform = kScaleAsymmetric,
536 .roundedCornersRadius = {64.1f, 64.1f},
537 .roundedCornersCrop = rect,
538 },
539 .source = PixelSource{.buffer =
540 Buffer{
541 .buffer = srcTexture,
542 .usePremultipliedAlpha = true,
543 .isOpaque = true,
544 .maxLuminanceNits = 1000.f,
545 }},
546 .alpha = 0.5f,
547 .sourceDataspace = kBT2020DataSpace,
548 };
549
550 std::vector<LayerSettings> layers = {layer};
551 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
552 }
553
drawExtendedHDRImageLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)554 static void drawExtendedHDRImageLayers(SkiaRenderEngine* renderengine,
555 const DisplaySettings& display,
556 const std::shared_ptr<ExternalTexture>& dstTexture,
557 const std::shared_ptr<ExternalTexture>& srcTexture) {
558 const Rect& displayRect = display.physicalDisplay;
559 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
560 LayerSettings layer{
561 .geometry =
562 Geometry{
563 .boundaries = rect,
564 // The position transform doesn't matter when the reduced shader mode
565 // in in effect. A matrix transform stage is always included.
566 .positionTransform = mat4(),
567 .roundedCornersRadius = {50.f, 50.f},
568 .roundedCornersCrop = rect,
569 },
570 .source = PixelSource{.buffer = Buffer{.buffer = srcTexture,
571 .usePremultipliedAlpha = true,
572 .isOpaque = true,
573 .maxLuminanceNits = 1000.f}},
574 .alpha = 0.5f,
575 .sourceDataspace = kExtendedHdrDataSpce,
576 };
577
578 for (auto roundedCornerRadius : {0.f, 50.f}) {
579 layer.geometry.roundedCornersRadius = {roundedCornerRadius, roundedCornerRadius};
580 for (auto alpha : {0.5f, 1.f}) {
581 layer.alpha = alpha;
582 std::vector<LayerSettings> layers;
583
584 for (auto layerWhitePoint : kLayerWhitePoints) {
585 layer.whitePointNits = layerWhitePoint;
586 layers.push_back(layer);
587 }
588 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
589 }
590 }
591 }
592
drawP3ImageLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)593 static void drawP3ImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
594 const std::shared_ptr<ExternalTexture>& dstTexture,
595 const std::shared_ptr<ExternalTexture>& srcTexture) {
596 const Rect& displayRect = display.physicalDisplay;
597 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
598 LayerSettings layer{
599 .geometry =
600 Geometry{
601 .boundaries = rect,
602 // The position transform doesn't matter when the reduced shader mode
603 // in in effect. A matrix transform stage is always included.
604 .positionTransform = mat4(),
605 .roundedCornersRadius = {50.f, 50.f},
606 .roundedCornersCrop = rect,
607 },
608 .source = PixelSource{.buffer = Buffer{.buffer = srcTexture,
609 .usePremultipliedAlpha = true,
610 .isOpaque = false,
611 .maxLuminanceNits = 1000.f}},
612 .alpha = 0.5f,
613 .sourceDataspace = kOtherDataSpace,
614 };
615
616 for (auto alpha : {0.5f, 1.f}) {
617 layer.alpha = alpha;
618 std::vector<LayerSettings> layers;
619
620 for (auto layerWhitePoint : kLayerWhitePoints) {
621 layer.whitePointNits = layerWhitePoint;
622 layers.push_back(layer);
623 }
624 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
625 }
626 }
627
drawEdgeExtensionLayers(SkiaRenderEngine * renderengine,const DisplaySettings & display,const std::shared_ptr<ExternalTexture> & dstTexture,const std::shared_ptr<ExternalTexture> & srcTexture)628 static void drawEdgeExtensionLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
629 const std::shared_ptr<ExternalTexture>& dstTexture,
630 const std::shared_ptr<ExternalTexture>& srcTexture) {
631 const Rect& displayRect = display.physicalDisplay;
632 // Make the layer
633 LayerSettings layer{
634 // Make the layer bigger than the texture
635 .geometry = Geometry{.boundaries = FloatRect(0, 0, displayRect.width(),
636 displayRect.height())},
637 .source = PixelSource{.buffer =
638 Buffer{
639 .buffer = srcTexture,
640 .isOpaque = 1,
641 }},
642 // The type of effect does not affect the shader's uniforms, but the layer must have a
643 // valid EdgeExtensionEffect to apply the shader
644 .edgeExtensionEffect =
645 EdgeExtensionEffect(true /* left */, false, false, true /* bottom */),
646 };
647 for (float alpha : {0.5, 0.0, 1.0}) {
648 layer.alpha = alpha;
649 auto layers = std::vector<LayerSettings>{layer};
650 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd());
651 }
652 }
653
654 //
655 // The collection of shaders cached here were found by using perfetto to record shader compiles
656 // during actions that involve RenderEngine, logging the layer settings, and the shader code
657 // and reproducing those settings here.
658 //
659 // It is helpful when debugging this to turn on
660 // in SkGLRenderEngine.cpp:
661 // kPrintLayerSettings = true
662 // kFlushAfterEveryLayer = true
663 // in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
664 // gPrintSKSL = true
primeShaderCache(SkiaRenderEngine * renderengine,PrimeCacheConfig config)665 void Cache::primeShaderCache(SkiaRenderEngine* renderengine, PrimeCacheConfig config) {
666 SFTRACE_CALL();
667 const int previousCount = renderengine->reportShadersCompiled();
668 if (previousCount) {
669 ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount);
670 }
671
672 // The loop is beneficial for debugging and should otherwise be optimized out by the compiler.
673 // Adding additional bounds to the loop is useful for verifying that the size of the dst buffer
674 // does not impact the shader compilation counts by triggering different behaviors in RE/Skia.
675 for (SkSize bounds : {SkSize::Make(128, 128), /*SkSize::Make(1080, 2340)*/}) {
676 const nsecs_t timeBefore = systemTime();
677 // The dimensions should not matter, so long as we draw inside them.
678 const Rect displayRect(0, 0, bounds.fWidth, bounds.fHeight);
679 DisplaySettings display{
680 .physicalDisplay = displayRect,
681 .clip = displayRect,
682 .maxLuminance = 500,
683 .outputDataspace = kDestDataSpace,
684 };
685 DisplaySettings p3Display{
686 .physicalDisplay = displayRect,
687 .clip = displayRect,
688 .maxLuminance = 500,
689 .outputDataspace = kOtherDataSpace,
690 };
691 DisplaySettings p3DisplayEnhance{.physicalDisplay = displayRect,
692 .clip = displayRect,
693 .maxLuminance = 500,
694 .outputDataspace = kOtherDataSpace,
695 .dimmingStage = aidl::android::hardware::graphics::
696 composer3::DimmingStage::GAMMA_OETF,
697 .renderIntent = aidl::android::hardware::graphics::
698 composer3::RenderIntent::ENHANCE};
699 DisplaySettings bt2020Display{.physicalDisplay = displayRect,
700 .clip = displayRect,
701 .maxLuminance = 500,
702 .outputDataspace = ui::Dataspace::BT2020,
703 .deviceHandlesColorTransform = true,
704 .dimmingStage = aidl::android::hardware::graphics::composer3::
705 DimmingStage::GAMMA_OETF,
706 .renderIntent = aidl::android::hardware::graphics::composer3::
707 RenderIntent::TONE_MAP_ENHANCE};
708
709 const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
710
711 sp<GraphicBuffer> dstBuffer =
712 sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
713 PIXEL_FORMAT_RGBA_8888, 1, usage, "primeShaderCache_dst");
714
715 const auto dstTexture =
716 std::make_shared<impl::ExternalTexture>(dstBuffer, *renderengine,
717 impl::ExternalTexture::Usage::WRITEABLE);
718 // This buffer will be the source for the call to drawImageLayers. Draw
719 // something to it as a placeholder for what an app draws. We should draw
720 // something, but the details are not important. Make use of the shadow layer drawing step
721 // to populate it.
722 sp<GraphicBuffer> srcBuffer =
723 sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
724 PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src");
725
726 const auto srcTexture = std::make_shared<
727 impl::ExternalTexture>(srcBuffer, *renderengine,
728 impl::ExternalTexture::Usage::READABLE |
729 impl::ExternalTexture::Usage::WRITEABLE);
730
731 if (config.cacheHolePunchLayer) {
732 SFTRACE_NAME("cacheHolePunchLayer");
733 drawHolePunchLayer(renderengine, display, dstTexture);
734 }
735
736 if (config.cacheSolidLayers) {
737 SFTRACE_NAME("cacheSolidLayers");
738 drawSolidLayers(renderengine, display, dstTexture);
739 drawSolidLayers(renderengine, p3Display, dstTexture);
740 }
741
742 if (config.cacheSolidDimmedLayers) {
743 SFTRACE_NAME("cacheSolidDimmedLayers");
744 drawSolidDimmedLayers(renderengine, display, dstTexture);
745 }
746
747 if (config.cacheShadowLayers) {
748 SFTRACE_NAME("cacheShadowLayers");
749 drawShadowLayers(renderengine, display, srcTexture);
750 drawShadowLayers(renderengine, p3Display, srcTexture);
751 }
752
753 if (renderengine->supportsBackgroundBlur()) {
754 SFTRACE_NAME("supportsBackgroundBlur");
755 drawBlurLayers(renderengine, display, dstTexture);
756 }
757
758 // The majority of skia shaders needed by RenderEngine are related to sampling images.
759 // These need to be generated with various source textures.
760 // Make a list of applicable sources.
761 // GRALLOC_USAGE_HW_TEXTURE should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.
762 const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
763 sp<GraphicBuffer> externalBuffer =
764 sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
765 PIXEL_FORMAT_RGBA_8888, 1, usageExternal,
766 "primeShaderCache_external");
767 const auto externalTexture =
768 std::make_shared<impl::ExternalTexture>(externalBuffer, *renderengine,
769 impl::ExternalTexture::Usage::READABLE);
770 std::vector<std::shared_ptr<ExternalTexture>> textures = {srcTexture, externalTexture};
771
772 // Another external texture with a different pixel format triggers useIsOpaqueWorkaround.
773 // It doesn't have to be f16, but it can't be the usual 8888.
774 sp<GraphicBuffer> f16ExternalBuffer =
775 sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
776 PIXEL_FORMAT_RGBA_FP16, 1, usageExternal,
777 "primeShaderCache_external_f16");
778 // The F16 texture may not be usable on all devices, so check first that it was created.
779 status_t error = f16ExternalBuffer->initCheck();
780 if (!error) {
781 const auto f16ExternalTexture =
782 std::make_shared<impl::ExternalTexture>(f16ExternalBuffer, *renderengine,
783 impl::ExternalTexture::Usage::READABLE);
784 textures.push_back(f16ExternalTexture);
785 }
786
787 for (auto texture : textures) {
788 if (config.cacheImageLayers) {
789 SFTRACE_NAME("cacheImageLayers");
790 drawImageLayers(renderengine, display, dstTexture, texture);
791 }
792
793 if (config.cacheImageDimmedLayers) {
794 SFTRACE_NAME("cacheImageDimmedLayers");
795 drawImageDimmedLayers(renderengine, display, dstTexture, texture);
796 drawImageDimmedLayers(renderengine, p3Display, dstTexture, texture);
797 drawImageDimmedLayers(renderengine, bt2020Display, dstTexture, texture);
798 }
799
800 if (config.cacheClippedLayers) {
801 SFTRACE_NAME("cacheClippedLayers");
802 // Draw layers for b/185569240.
803 drawClippedLayers(renderengine, display, dstTexture, texture);
804 }
805
806 if (config.cacheEdgeExtension) {
807 SFTRACE_NAME("cacheEdgeExtension");
808 drawEdgeExtensionLayers(renderengine, display, dstTexture, texture);
809 drawEdgeExtensionLayers(renderengine, p3Display, dstTexture, texture);
810 }
811 }
812
813 if (config.cachePIPImageLayers) {
814 SFTRACE_NAME("cachePIPImageLayers");
815 drawPIPImageLayer(renderengine, display, dstTexture, externalTexture);
816 }
817
818 if (config.cacheTransparentImageDimmedLayers) {
819 SFTRACE_NAME("cacheTransparentImageDimmedLayers");
820 drawTransparentImageDimmedLayers(renderengine, bt2020Display, dstTexture,
821 externalTexture);
822 drawTransparentImageDimmedLayers(renderengine, display, dstTexture, externalTexture);
823 drawTransparentImageDimmedLayers(renderengine, p3Display, dstTexture, externalTexture);
824 drawTransparentImageDimmedLayers(renderengine, p3DisplayEnhance, dstTexture,
825 externalTexture);
826 }
827
828 if (config.cacheClippedDimmedImageLayers) {
829 SFTRACE_NAME("cacheClippedDimmedImageLayers");
830 drawClippedDimmedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture);
831 }
832
833 if (config.cacheUltraHDR) {
834 SFTRACE_NAME("cacheUltraHDR");
835 drawBT2020ClippedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture);
836
837 drawBT2020ImageLayers(renderengine, bt2020Display, dstTexture, externalTexture);
838 drawBT2020ImageLayers(renderengine, p3Display, dstTexture, externalTexture);
839
840 drawExtendedHDRImageLayers(renderengine, display, dstTexture, externalTexture);
841 drawExtendedHDRImageLayers(renderengine, p3Display, dstTexture, externalTexture);
842 drawExtendedHDRImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture);
843
844 drawP3ImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture);
845 }
846
847 // draw one final layer synchronously to force GL submit
848 LayerSettings layer{
849 .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)},
850 };
851 auto layers = std::vector<LayerSettings>{layer};
852 // call get() to make it synchronous
853 {
854 SFTRACE_NAME("finalLayer");
855 renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()).get();
856 }
857
858 const nsecs_t timeAfter = systemTime();
859 const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
860 const int shadersCompiled = renderengine->reportShadersCompiled() - previousCount;
861 ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs);
862 }
863 }
864
865 } // namespace android::renderengine::skia
866