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