| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 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 | */ | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 16 | #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 |  | 
|  | 28 | namespace android::renderengine::skia { | 
|  | 29 |  | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 30 | namespace { | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 31 | // Warming shader cache, not framebuffer cache. | 
|  | 32 | constexpr bool kUseFrameBufferCache = false; | 
|  | 33 |  | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 34 | // clang-format off | 
|  | 35 | // Any non-identity matrix will do. | 
|  | 36 | const 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); | 
|  | 40 | // clang-format on | 
|  | 41 | // When choosing dataspaces below, whether the match the destination or not determined whether | 
|  | 42 | // a color correction effect is added to the shader. There may be other additional shader details | 
|  | 43 | // for particular color spaces. | 
|  | 44 | // TODO(b/184842383) figure out which color related shaders are necessary | 
|  | 45 | constexpr auto kDestDataSpace = ui::Dataspace::SRGB; | 
|  | 46 | } // namespace | 
|  | 47 |  | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 48 | static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 49 | const std::shared_ptr<ExternalTexture>& dstTexture) { | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 50 | // Somewhat arbitrary dimensions, but on screen and slightly shorter, based | 
|  | 51 | // on actual use. | 
|  | 52 | FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30); | 
|  | 53 | LayerSettings layer{ | 
|  | 54 | .geometry = | 
|  | 55 | Geometry{ | 
|  | 56 | .boundaries = rect, | 
|  | 57 | .roundedCornersCrop = rect, | 
|  | 58 | }, | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 59 | // drawShadow ignores alpha | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 60 | .shadow = | 
|  | 61 | ShadowSettings{ | 
|  | 62 | .ambientColor = vec4(0, 0, 0, 0.00935997f), | 
|  | 63 | .spotColor = vec4(0, 0, 0, 0.0455841f), | 
|  | 64 | .lightPos = vec3(370.508f, -1527.03f, 1650.f), | 
|  | 65 | .lightRadius = 2200.0f, | 
|  | 66 | .length = 0.955342f, | 
|  | 67 | }, | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 68 | // important that this matches dest so the general shadow fragment shader doesn't | 
|  | 69 | // have color correction added, and important that it be srgb, so the *vertex* shader | 
|  | 70 | // doesn't have color correction added. | 
|  | 71 | .sourceDataspace = kDestDataSpace, | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 72 | }; | 
|  | 73 |  | 
|  | 74 | auto layers = std::vector<const LayerSettings*>{&layer}; | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 75 | // The identity matrix will generate the fast shader | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 76 | renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 77 | nullptr); | 
|  | 78 | // This matrix, which has different scales for x and y, will | 
|  | 79 | // generate the slower (more general case) version, which has variants for translucent | 
|  | 80 | // casters and rounded rects. | 
|  | 81 | // clang-format off | 
|  | 82 | layer.geometry.positionTransform = mat4(0.7f, 0.f,  0.f, 0.f, | 
|  | 83 | 0.f, 0.8f, 0.f, 0.f, | 
|  | 84 | 0.f, 0.f,  1.f, 0.f, | 
|  | 85 | 0.f, 0.f,  0.f, 1.f); | 
|  | 86 | // clang-format on | 
|  | 87 | for (auto translucent : {false, true}) { | 
|  | 88 | layer.shadow.casterIsTranslucent = translucent; | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 89 | renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 90 | base::unique_fd(), nullptr); | 
|  | 91 | } | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 95 | const std::shared_ptr<ExternalTexture>& dstTexture, | 
|  | 96 | const std::shared_ptr<ExternalTexture>& srcTexture) { | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 97 | 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 III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 103 | .roundedCornersCrop = rect, | 
|  | 104 | }, | 
|  | 105 | .source = PixelSource{.buffer = | 
|  | 106 | Buffer{ | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 107 | .buffer = srcTexture, | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 108 | .maxMasteringLuminance = 1000.f, | 
|  | 109 | .maxContentLuminance = 1000.f, | 
|  | 110 | }}, | 
|  | 111 | }; | 
|  | 112 |  | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 113 | auto threeCornerRadii = {0.0f, 0.05f, 50.f}; | 
|  | 114 | auto oneCornerRadius = {50.f}; | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 115 |  | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 116 | // Test both drawRect and drawRRect | 
|  | 117 | auto layers = std::vector<const LayerSettings*>{&layer}; | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 118 | for (bool identity : {true, false}) { | 
|  | 119 | layer.geometry.positionTransform = identity ? mat4() : kScaleAndTranslate; | 
|  | 120 | // Corner radii less than 0.5 creates a special shader. This likely occurs in real usage | 
|  | 121 | // due to animating corner radius. | 
|  | 122 | // For the non-idenity matrix, only the large corner radius will create a new shader. | 
|  | 123 | for (float roundedCornersRadius : identity ? threeCornerRadii : oneCornerRadius) { | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 124 | // roundedCornersCrop is always set, but it is this radius that triggers the behavior | 
|  | 125 | layer.geometry.roundedCornersRadius = roundedCornersRadius; | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 126 | for (bool isOpaque : {true, false}) { | 
|  | 127 | layer.source.buffer.isOpaque = isOpaque; | 
|  | 128 | for (auto alpha : {half(.23999f), half(1.0f)}) { | 
|  | 129 | layer.alpha = alpha; | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 130 | renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 131 | base::unique_fd(), nullptr); | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 132 | } | 
|  | 133 | } | 
|  | 134 | } | 
|  | 135 | } | 
|  | 136 | } | 
|  | 137 |  | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 138 | static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 139 | const std::shared_ptr<ExternalTexture>& dstTexture) { | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 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 | }, | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 147 | .source = | 
|  | 148 | PixelSource{ | 
|  | 149 | .solidColor = half3(0.1f, 0.2f, 0.3f), | 
|  | 150 | }, | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 151 | .alpha = 1, | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 152 | }; | 
|  | 153 |  | 
|  | 154 | auto layers = std::vector<const LayerSettings*>{&layer}; | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 155 | for (auto transform : {mat4(), kScaleAndTranslate}) { | 
|  | 156 | layer.geometry.positionTransform = transform; | 
|  | 157 | for (float roundedCornersRadius : {0.0f, 0.05f, 50.f}) { | 
|  | 158 | layer.geometry.roundedCornersRadius = roundedCornersRadius; | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 159 | renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 160 | base::unique_fd(), nullptr); | 
|  | 161 | } | 
|  | 162 | } | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 163 | } | 
|  | 164 |  | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 165 | static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 166 | const std::shared_ptr<ExternalTexture>& dstTexture) { | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 167 | const Rect& displayRect = display.physicalDisplay; | 
|  | 168 | FloatRect rect(0, 0, displayRect.width(), displayRect.height()); | 
|  | 169 | LayerSettings layer{ | 
|  | 170 | .geometry = | 
|  | 171 | Geometry{ | 
|  | 172 | .boundaries = rect, | 
|  | 173 | }, | 
|  | 174 | .alpha = 1, | 
|  | 175 | }; | 
|  | 176 |  | 
|  | 177 | auto layers = std::vector<const LayerSettings*>{&layer}; | 
|  | 178 | for (int radius : {9, 60}) { | 
|  | 179 | layer.backgroundBlurRadius = radius; | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 180 | renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 181 | base::unique_fd(), nullptr); | 
|  | 182 | } | 
|  | 183 | } | 
|  | 184 |  | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 185 | // | 
|  | 186 | // The collection of shaders cached here were found by using perfetto to record shader compiles | 
|  | 187 | // during actions that involve RenderEngine, logging the layer settings, and the shader code | 
|  | 188 | // and reproducing those settings here. | 
|  | 189 | // | 
|  | 190 | // It is helpful when debugging this to turn on | 
|  | 191 | // in SkGLRenderEngine.cpp: | 
|  | 192 | //    kPrintLayerSettings = true | 
|  | 193 | //    kFlushAfterEveryLayer = true | 
|  | 194 | // in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp | 
|  | 195 | //    gPrintSKSL = true | 
|  | 196 | // | 
|  | 197 | // TODO(b/184631553) cache the shader involved in youtube pip return. | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 198 | void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 199 | const int previousCount = renderengine->reportShadersCompiled(); | 
|  | 200 | if (previousCount) { | 
|  | 201 | ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount); | 
|  | 202 | } | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 203 | const nsecs_t timeBefore = systemTime(); | 
|  | 204 | // The dimensions should not matter, so long as we draw inside them. | 
|  | 205 | const Rect displayRect(0, 0, 1080, 2340); | 
|  | 206 | DisplaySettings display{ | 
|  | 207 | .physicalDisplay = displayRect, | 
|  | 208 | .clip = displayRect, | 
|  | 209 | .maxLuminance = 500, | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 210 | .outputDataspace = kDestDataSpace, | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 211 | }; | 
|  | 212 |  | 
|  | 213 | const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; | 
|  | 214 |  | 
|  | 215 | sp<GraphicBuffer> dstBuffer = | 
|  | 216 | new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, | 
|  | 217 | usage, "primeShaderCache_dst"); | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 218 |  | 
|  | 219 | const auto dstTexture = std::make_shared<ExternalTexture>(dstBuffer, *renderengine, | 
|  | 220 | ExternalTexture::Usage::WRITEABLE); | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 221 | // This buffer will be the source for the call to drawImageLayers. Draw | 
|  | 222 | // something to it as a placeholder for what an app draws. We should draw | 
| Nathaniel Nifong | 4fc750d | 2021-03-19 11:37:36 -0400 | [diff] [blame] | 223 | // something, but the details are not important. Make use of the shadow layer drawing step | 
|  | 224 | // to populate it. | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 225 | sp<GraphicBuffer> srcBuffer = | 
|  | 226 | new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, | 
|  | 227 | usage, "drawImageLayer_src"); | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 228 |  | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 229 | const auto srcTexture = | 
|  | 230 | std::make_shared<ExternalTexture>(srcBuffer, *renderengine, | 
|  | 231 | ExternalTexture::Usage::READABLE | | 
|  | 232 | ExternalTexture::Usage::WRITEABLE); | 
|  | 233 |  | 
|  | 234 | drawSolidLayers(renderengine, display, dstTexture); | 
|  | 235 | drawShadowLayers(renderengine, display, srcTexture); | 
|  | 236 | drawBlurLayers(renderengine, display, dstTexture); | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 237 | // The majority of shaders are related to sampling images. | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 238 | drawImageLayers(renderengine, display, dstTexture, srcTexture); | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 239 |  | 
| Nathaniel Nifong | f436240 | 2021-04-12 11:41:05 -0400 | [diff] [blame] | 240 | // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; | 
|  | 241 | const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; | 
|  | 242 |  | 
|  | 243 | sp<GraphicBuffer> externalBuffer = | 
|  | 244 | new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, | 
|  | 245 | usageExternal, "primeShaderCache_external"); | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 246 | const auto externalTexture = | 
|  | 247 | std::make_shared<ExternalTexture>(externalBuffer, *renderengine, | 
|  | 248 | ExternalTexture::Usage::READABLE); | 
| Nathaniel Nifong | f436240 | 2021-04-12 11:41:05 -0400 | [diff] [blame] | 249 | // TODO(b/184665179) doubles number of image shader compilations, but only somewhere | 
|  | 250 | // between 6 and 8 will occur in real uses. | 
| Alec Mouri | a90a570 | 2021-04-16 16:36:21 +0000 | [diff] [blame] | 251 | drawImageLayers(renderengine, display, dstTexture, externalTexture); | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 252 |  | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 253 | const nsecs_t timeAfter = systemTime(); | 
|  | 254 | const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6; | 
| Nathaniel Nifong | b9f27ef | 2021-04-01 16:44:12 -0400 | [diff] [blame] | 255 | const int shadersCompiled = renderengine->reportShadersCompiled(); | 
|  | 256 | ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs); | 
| Leon Scroggins III | b9216dc | 2021-03-08 17:19:01 -0500 | [diff] [blame] | 257 | } | 
|  | 258 |  | 
|  | 259 | } // namespace android::renderengine::skia |