blob: 725f57b797237029824a2beb487a2c2a5fc53a63 [file] [log] [blame]
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -05001/*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050016#include "Cache.h"
17#include "AutoBackendTexture.h"
18#include "SkiaRenderEngine.h"
19#include "android-base/unique_fd.h"
20#include "renderengine/DisplaySettings.h"
21#include "renderengine/LayerSettings.h"
22#include "ui/GraphicBuffer.h"
23#include "ui/GraphicTypes.h"
24#include "ui/PixelFormat.h"
25#include "ui/Rect.h"
26#include "utils/Timers.h"
27
28namespace android::renderengine::skia {
29
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040030namespace {
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -040031// Warming shader cache, not framebuffer cache.
32constexpr bool kUseFrameBufferCache = false;
33
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040034// clang-format off
35// Any non-identity matrix will do.
36const auto kScaleAndTranslate = mat4(0.7f, 0.f, 0.f, 0.f,
37 0.f, 0.7f, 0.f, 0.f,
38 0.f, 0.f, 1.f, 0.f,
39 67.3f, 52.2f, 0.f, 1.f);
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -040040const auto kScaleAsymmetric = mat4(0.8f, 0.f, 0.f, 0.f,
41 0.f, 1.1f, 0.f, 0.f,
42 0.f, 0.f, 1.f, 0.f,
43 0.f, 0.f, 0.f, 1.f);
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040044// clang-format on
Nathaniel Nifongbf6f7542021-04-27 12:05:16 -040045// When setting layer.sourceDataspace, whether it matches the destination or not determines whether
46// a color correction effect is added to the shader.
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040047constexpr auto kDestDataSpace = ui::Dataspace::SRGB;
Nathaniel Nifong21e021f2021-04-21 13:15:46 -040048constexpr auto kOtherDataSpace = ui::Dataspace::DISPLAY_P3;
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040049} // namespace
50
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -040051static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
Alec Mouria90a5702021-04-16 16:36:21 +000052 const std::shared_ptr<ExternalTexture>& dstTexture) {
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050053 // Somewhat arbitrary dimensions, but on screen and slightly shorter, based
54 // on actual use.
55 FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30);
56 LayerSettings layer{
57 .geometry =
58 Geometry{
59 .boundaries = rect,
60 .roundedCornersCrop = rect,
61 },
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -040062 // drawShadow ignores alpha
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050063 .shadow =
64 ShadowSettings{
65 .ambientColor = vec4(0, 0, 0, 0.00935997f),
66 .spotColor = vec4(0, 0, 0, 0.0455841f),
67 .lightPos = vec3(370.508f, -1527.03f, 1650.f),
68 .lightRadius = 2200.0f,
69 .length = 0.955342f,
70 },
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040071 // important that this matches dest so the general shadow fragment shader doesn't
72 // have color correction added, and important that it be srgb, so the *vertex* shader
73 // doesn't have color correction added.
74 .sourceDataspace = kDestDataSpace,
Nathaniel Nifong490a9472021-06-23 16:44:19 -040075 // setting this is mandatory for shadows and blurs
76 .skipContentDraw = true,
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050077 };
78
79 auto layers = std::vector<const LayerSettings*>{&layer};
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040080 // The identity matrix will generate the fast shader
Alec Mouria90a5702021-04-16 16:36:21 +000081 renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(),
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040082 nullptr);
83 // This matrix, which has different scales for x and y, will
84 // generate the slower (more general case) version, which has variants for translucent
85 // casters and rounded rects.
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -040086 layer.geometry.positionTransform = kScaleAsymmetric;
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -040087 for (auto translucent : {false, true}) {
88 layer.shadow.casterIsTranslucent = translucent;
Alec Mouria90a5702021-04-16 16:36:21 +000089 renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050090 base::unique_fd(), nullptr);
91 }
92}
93
94static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
Alec Mouria90a5702021-04-16 16:36:21 +000095 const std::shared_ptr<ExternalTexture>& dstTexture,
96 const std::shared_ptr<ExternalTexture>& srcTexture) {
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -050097 const Rect& displayRect = display.physicalDisplay;
98 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
99 LayerSettings layer{
100 .geometry =
101 Geometry{
102 .boundaries = rect,
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500103 .roundedCornersCrop = rect,
104 },
105 .source = PixelSource{.buffer =
106 Buffer{
Alec Mouria90a5702021-04-16 16:36:21 +0000107 .buffer = srcTexture,
John Reckac09e452021-04-07 16:35:37 -0400108 .maxLuminanceNits = 1000.f,
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500109 }},
110 };
111
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400112 auto threeCornerRadii = {0.0f, 0.05f, 50.f};
113 auto oneCornerRadius = {50.f};
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400114
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500115 // Test both drawRect and drawRRect
116 auto layers = std::vector<const LayerSettings*>{&layer};
Nathaniel Nifongbf6f7542021-04-27 12:05:16 -0400117 for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
118 layer.sourceDataspace = dataspace;
119 for (bool identity : {true, false}) {
120 layer.geometry.positionTransform = identity ? mat4() : kScaleAndTranslate;
121 // Corner radii less than 0.5 creates a special shader. This likely occurs in real usage
122 // due to animating corner radius.
123 // For the non-idenity matrix, only the large corner radius will create a new shader.
124 for (float roundedCornersRadius : identity ? threeCornerRadii : oneCornerRadius) {
125 // roundedCornersCrop is always set, but it is this radius that triggers the
126 // behavior
127 layer.geometry.roundedCornersRadius = roundedCornersRadius;
128 for (bool isOpaque : {true, false}) {
129 layer.source.buffer.isOpaque = isOpaque;
130 for (auto alpha : {half(.23999f), half(1.0f)}) {
131 layer.alpha = alpha;
132 renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
133 base::unique_fd(), nullptr);
134 }
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500135 }
136 }
137 }
138 }
139}
140
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400141static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
Alec Mouria90a5702021-04-16 16:36:21 +0000142 const std::shared_ptr<ExternalTexture>& dstTexture) {
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400143 const Rect& displayRect = display.physicalDisplay;
144 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
145 LayerSettings layer{
146 .geometry =
147 Geometry{
148 .boundaries = rect,
149 },
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400150 .source =
151 PixelSource{
152 .solidColor = half3(0.1f, 0.2f, 0.3f),
153 },
Nathaniel Nifong768693f2021-06-08 14:33:47 -0400154 .alpha = 0.5,
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400155 };
156
157 auto layers = std::vector<const LayerSettings*>{&layer};
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400158 for (auto transform : {mat4(), kScaleAndTranslate}) {
159 layer.geometry.positionTransform = transform;
160 for (float roundedCornersRadius : {0.0f, 0.05f, 50.f}) {
161 layer.geometry.roundedCornersRadius = roundedCornersRadius;
Alec Mouria90a5702021-04-16 16:36:21 +0000162 renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400163 base::unique_fd(), nullptr);
164 }
165 }
Nathaniel Nifong4fc750d2021-03-19 11:37:36 -0400166}
167
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400168static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
Alec Mouria90a5702021-04-16 16:36:21 +0000169 const std::shared_ptr<ExternalTexture>& dstTexture) {
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400170 const Rect& displayRect = display.physicalDisplay;
171 FloatRect rect(0, 0, displayRect.width(), displayRect.height());
172 LayerSettings layer{
173 .geometry =
174 Geometry{
175 .boundaries = rect,
176 },
177 .alpha = 1,
Nathaniel Nifong490a9472021-06-23 16:44:19 -0400178 // setting this is mandatory for shadows and blurs
179 .skipContentDraw = true,
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400180 };
181
182 auto layers = std::vector<const LayerSettings*>{&layer};
Nathaniel Nifong490a9472021-06-23 16:44:19 -0400183 // Different blur code is invoked for radii less and greater than 30 pixels
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400184 for (int radius : {9, 60}) {
185 layer.backgroundBlurRadius = radius;
Alec Mouria90a5702021-04-16 16:36:21 +0000186 renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400187 base::unique_fd(), nullptr);
188 }
189}
190
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400191// The unique feature of these layers is that the boundary is slightly smaller than the rounded
192// rect crop, so the rounded edges intersect that boundary and require a different clipping method.
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -0400193// For buffers, this is done with a stage that computes coverage and it will differ for round and
194// elliptical corners.
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400195static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
196 const std::shared_ptr<ExternalTexture>& dstTexture,
197 const std::shared_ptr<ExternalTexture>& srcTexture) {
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400198 const Rect& displayRect = display.physicalDisplay;
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400199 FloatRect rect(0, 0, displayRect.width(), displayRect.height() - 20); // boundary is smaller
200
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -0400201 PixelSource bufferSource{.buffer = Buffer{
202 .buffer = srcTexture,
203 .isOpaque = 0,
204 .maxLuminanceNits = 1000.f,
205 }};
206 PixelSource bufferOpaque{.buffer = Buffer{
207 .buffer = srcTexture,
208 .isOpaque = 1,
209 .maxLuminanceNits = 1000.f,
210 }};
211 PixelSource colorSource{.solidColor = half3(0.1f, 0.2f, 0.3f)};
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400212
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400213 LayerSettings layer{
214 .geometry =
215 Geometry{
216 .boundaries = rect,
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400217 .roundedCornersRadius = 27, // larger than the 20 above.
218 .roundedCornersCrop =
219 FloatRect(0, 0, displayRect.width(), displayRect.height()),
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400220 },
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400221 };
222
223 auto layers = std::vector<const LayerSettings*>{&layer};
Nathaniel Nifongafeac5b2021-05-27 10:52:30 -0400224 for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
225 layer.source = pixelSource;
226 for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
227 layer.sourceDataspace = dataspace;
228 // Produce a CircularRRect clip and an EllipticalRRect clip
229 for (auto transform : {kScaleAndTranslate, kScaleAsymmetric}) {
230 layer.geometry.positionTransform = transform;
231 // In real use, I saw alpha of 1.0 and 0.999, probably a mistake, but cache both
232 // shaders.
233 for (float alpha : {0.5f, 1.f}) {
234 layer.alpha = alpha,
235 renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
236 base::unique_fd(), nullptr);
237 }
238 }
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400239 }
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400240 }
241}
242
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400243//
244// The collection of shaders cached here were found by using perfetto to record shader compiles
245// during actions that involve RenderEngine, logging the layer settings, and the shader code
246// and reproducing those settings here.
247//
248// It is helpful when debugging this to turn on
249// in SkGLRenderEngine.cpp:
250// kPrintLayerSettings = true
251// kFlushAfterEveryLayer = true
252// in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
253// gPrintSKSL = true
254//
255// TODO(b/184631553) cache the shader involved in youtube pip return.
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500256void Cache::primeShaderCache(SkiaRenderEngine* renderengine) {
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400257 const int previousCount = renderengine->reportShadersCompiled();
258 if (previousCount) {
259 ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount);
260 }
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500261
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400262 // The loop is beneficial for debugging and should otherwise be optimized out by the compiler.
263 // Adding additional bounds to the loop is useful for verifying that the size of the dst buffer
264 // does not impact the shader compilation counts by triggering different behaviors in RE/Skia.
265 for (SkSize bounds : {SkSize::Make(128, 128), /*SkSize::Make(1080, 2340)*/}) {
266 const nsecs_t timeBefore = systemTime();
267 // The dimensions should not matter, so long as we draw inside them.
268 const Rect displayRect(0, 0, bounds.fWidth, bounds.fHeight);
269 DisplaySettings display{
270 .physicalDisplay = displayRect,
271 .clip = displayRect,
272 .maxLuminance = 500,
273 .outputDataspace = kDestDataSpace,
274 };
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500275
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400276 const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
Alec Mouria90a5702021-04-16 16:36:21 +0000277
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400278 sp<GraphicBuffer> dstBuffer =
279 new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
280 1, usage, "primeShaderCache_dst");
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400281
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400282 const auto dstTexture =
283 std::make_shared<ExternalTexture>(dstBuffer, *renderengine,
284 ExternalTexture::Usage::WRITEABLE);
285 // This buffer will be the source for the call to drawImageLayers. Draw
286 // something to it as a placeholder for what an app draws. We should draw
287 // something, but the details are not important. Make use of the shadow layer drawing step
288 // to populate it.
289 sp<GraphicBuffer> srcBuffer =
290 new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
291 1, usage, "drawImageLayer_src");
Alec Mouria90a5702021-04-16 16:36:21 +0000292
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400293 const auto srcTexture =
294 std::make_shared<ExternalTexture>(srcBuffer, *renderengine,
295 ExternalTexture::Usage::READABLE |
296 ExternalTexture::Usage::WRITEABLE);
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400297
Nathaniel Nifong490a9472021-06-23 16:44:19 -0400298 // 6 shaders
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400299 drawSolidLayers(renderengine, display, dstTexture);
Nathaniel Nifong490a9472021-06-23 16:44:19 -0400300 // 8 shaders
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400301 drawShadowLayers(renderengine, display, srcTexture);
Nathaniel Nifongcda45e92021-06-10 15:01:42 -0400302
303 if (renderengine->supportsBackgroundBlur()) {
Nathaniel Nifong490a9472021-06-23 16:44:19 -0400304 // 2 shaders
Nathaniel Nifongcda45e92021-06-10 15:01:42 -0400305 drawBlurLayers(renderengine, display, dstTexture);
306 }
307
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400308 // The majority of shaders are related to sampling images.
309 drawImageLayers(renderengine, display, dstTexture, srcTexture);
Nathaniel Nifongf4362402021-04-12 11:41:05 -0400310
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400311 // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
312 const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
Nathaniel Nifongb9f27ef2021-04-01 16:44:12 -0400313
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400314 sp<GraphicBuffer> externalBuffer =
315 new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
316 1, usageExternal, "primeShaderCache_external");
317 const auto externalTexture =
318 std::make_shared<ExternalTexture>(externalBuffer, *renderengine,
319 ExternalTexture::Usage::READABLE);
320 // TODO(b/184665179) doubles number of image shader compilations, but only somewhere
321 // between 6 and 8 will occur in real uses.
322 drawImageLayers(renderengine, display, dstTexture, externalTexture);
Nathaniel Nifong21e021f2021-04-21 13:15:46 -0400323
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400324 // Draw layers for b/185569240.
Nathaniel Nifong2d91c5e2021-05-13 17:14:00 -0400325 drawClippedLayers(renderengine, display, dstTexture, externalTexture);
Derek Sollenbergere9a51082021-05-06 14:01:38 -0400326
327 const nsecs_t timeAfter = systemTime();
328 const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
329 const int shadersCompiled = renderengine->reportShadersCompiled();
330 ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs);
331 }
Leon Scroggins IIIb9216dc2021-03-08 17:19:01 -0500332}
333
334} // namespace android::renderengine::skia