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