• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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