1 /*
2  * Copyright 2020 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 
17 #undef LOG_TAG
18 #define LOG_TAG "RenderEngine"
19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
20 
21 #include "SkiaRenderEngine.h"
22 
23 #include <GrBackendSemaphore.h>
24 #include <GrContextOptions.h>
25 #include <GrTypes.h>
26 #include <SkBlendMode.h>
27 #include <SkCanvas.h>
28 #include <SkColor.h>
29 #include <SkColorFilter.h>
30 #include <SkColorMatrix.h>
31 #include <SkColorSpace.h>
32 #include <SkData.h>
33 #include <SkGraphics.h>
34 #include <SkImage.h>
35 #include <SkImageFilters.h>
36 #include <SkImageInfo.h>
37 #include <SkM44.h>
38 #include <SkMatrix.h>
39 #include <SkPaint.h>
40 #include <SkPath.h>
41 #include <SkPoint.h>
42 #include <SkPoint3.h>
43 #include <SkRRect.h>
44 #include <SkRect.h>
45 #include <SkRefCnt.h>
46 #include <SkRegion.h>
47 #include <SkRuntimeEffect.h>
48 #include <SkSamplingOptions.h>
49 #include <SkScalar.h>
50 #include <SkShader.h>
51 #include <SkShadowUtils.h>
52 #include <SkString.h>
53 #include <SkSurface.h>
54 #include <SkTileMode.h>
55 #include <android-base/stringprintf.h>
56 #include <common/FlagManager.h>
57 #include <gui/FenceMonitor.h>
58 #include <gui/TraceUtils.h>
59 #include <include/gpu/ganesh/SkSurfaceGanesh.h>
60 #include <pthread.h>
61 #include <src/core/SkTraceEventCommon.h>
62 #include <sync/sync.h>
63 #include <ui/BlurRegion.h>
64 #include <ui/DebugUtils.h>
65 #include <ui/GraphicBuffer.h>
66 #include <ui/HdrRenderTypeUtils.h>
67 #include <utils/Trace.h>
68 
69 #include <cmath>
70 #include <cstdint>
71 #include <deque>
72 #include <memory>
73 #include <numeric>
74 
75 #include "Cache.h"
76 #include "ColorSpaces.h"
77 #include "compat/SkiaGpuContext.h"
78 #include "filters/BlurFilter.h"
79 #include "filters/GaussianBlurFilter.h"
80 #include "filters/KawaseBlurFilter.h"
81 #include "filters/LinearEffect.h"
82 #include "filters/MouriMap.h"
83 #include "log/log_main.h"
84 #include "skia/compat/SkiaBackendTexture.h"
85 #include "skia/debug/SkiaCapture.h"
86 #include "skia/debug/SkiaMemoryReporter.h"
87 #include "skia/filters/StretchShaderFactory.h"
88 #include "system/graphics-base-v1.0.h"
89 
90 namespace {
91 
92 // Debugging settings
93 static const bool kPrintLayerSettings = false;
94 static const bool kGaneshFlushAfterEveryLayer = kPrintLayerSettings;
95 
96 } // namespace
97 
98 // Utility functions related to SkRect
99 
100 namespace {
101 
getSkRect(const android::FloatRect & rect)102 static inline SkRect getSkRect(const android::FloatRect& rect) {
103     return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
104 }
105 
getSkRect(const android::Rect & rect)106 static inline SkRect getSkRect(const android::Rect& rect) {
107     return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
108 }
109 
110 /**
111  *  Verifies that common, simple bounds + clip combinations can be converted into
112  *  a single RRect draw call returning true if possible. If true the radii parameter
113  *  will be filled with the correct radii values that combined with bounds param will
114  *  produce the insected roundRect. If false, the returned state of the radii param is undefined.
115  */
intersectionIsRoundRect(const SkRect & bounds,const SkRect & crop,const SkRect & insetCrop,const android::vec2 & cornerRadius,SkVector radii[4])116 static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
117                                     const SkRect& insetCrop, const android::vec2& cornerRadius,
118                                     SkVector radii[4]) {
119     const bool leftEqual = bounds.fLeft == crop.fLeft;
120     const bool topEqual = bounds.fTop == crop.fTop;
121     const bool rightEqual = bounds.fRight == crop.fRight;
122     const bool bottomEqual = bounds.fBottom == crop.fBottom;
123 
124     // In the event that the corners of the bounds only partially align with the crop we
125     // need to ensure that the resulting shape can still be represented as a round rect.
126     // In particular the round rect implementation will scale the value of all corner radii
127     // if the sum of the radius along any edge is greater than the length of that edge.
128     // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
129     const bool requiredWidth = bounds.width() > (cornerRadius.x * 2);
130     const bool requiredHeight = bounds.height() > (cornerRadius.y * 2);
131     if (!requiredWidth || !requiredHeight) {
132         return false;
133     }
134 
135     // Check each cropped corner to ensure that it exactly matches the crop or its corner is
136     // contained within the cropped shape and does not need rounded.
137     // compute the UpperLeft corner radius
138     if (leftEqual && topEqual) {
139         radii[0].set(cornerRadius.x, cornerRadius.y);
140     } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
141                (topEqual && bounds.fLeft >= insetCrop.fLeft)) {
142         radii[0].set(0, 0);
143     } else {
144         return false;
145     }
146     // compute the UpperRight corner radius
147     if (rightEqual && topEqual) {
148         radii[1].set(cornerRadius.x, cornerRadius.y);
149     } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
150                (topEqual && bounds.fRight <= insetCrop.fRight)) {
151         radii[1].set(0, 0);
152     } else {
153         return false;
154     }
155     // compute the BottomRight corner radius
156     if (rightEqual && bottomEqual) {
157         radii[2].set(cornerRadius.x, cornerRadius.y);
158     } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
159                (bottomEqual && bounds.fRight <= insetCrop.fRight)) {
160         radii[2].set(0, 0);
161     } else {
162         return false;
163     }
164     // compute the BottomLeft corner radius
165     if (leftEqual && bottomEqual) {
166         radii[3].set(cornerRadius.x, cornerRadius.y);
167     } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
168                (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) {
169         radii[3].set(0, 0);
170     } else {
171         return false;
172     }
173 
174     return true;
175 }
176 
getBoundsAndClip(const android::FloatRect & boundsRect,const android::FloatRect & cropRect,const android::vec2 & cornerRadius)177 static inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const android::FloatRect& boundsRect,
178                                                            const android::FloatRect& cropRect,
179                                                            const android::vec2& cornerRadius) {
180     const SkRect bounds = getSkRect(boundsRect);
181     const SkRect crop = getSkRect(cropRect);
182 
183     SkRRect clip;
184     if (cornerRadius.x > 0 && cornerRadius.y > 0) {
185         // it the crop and the bounds are equivalent or there is no crop then we don't need a clip
186         if (bounds == crop || crop.isEmpty()) {
187             return {SkRRect::MakeRectXY(bounds, cornerRadius.x, cornerRadius.y), clip};
188         }
189 
190         // This makes an effort to speed up common, simple bounds + clip combinations by
191         // converting them to a single RRect draw. It is possible there are other cases
192         // that can be converted.
193         if (crop.contains(bounds)) {
194             const auto insetCrop = crop.makeInset(cornerRadius.x, cornerRadius.y);
195             if (insetCrop.contains(bounds)) {
196                 return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required
197             }
198 
199             SkVector radii[4];
200             if (intersectionIsRoundRect(bounds, crop, insetCrop, cornerRadius, radii)) {
201                 SkRRect intersectionBounds;
202                 intersectionBounds.setRectRadii(bounds, radii);
203                 return {intersectionBounds, clip};
204             }
205         }
206 
207         // we didn't hit any of our fast paths so set the clip to the cropRect
208         clip.setRectXY(crop, cornerRadius.x, cornerRadius.y);
209     }
210 
211     // if we hit this point then we either don't have rounded corners or we are going to rely
212     // on the clip to round the corners for us
213     return {SkRRect::MakeRect(bounds), clip};
214 }
215 
layerHasBlur(const android::renderengine::LayerSettings & layer,bool colorTransformModifiesAlpha)216 static inline bool layerHasBlur(const android::renderengine::LayerSettings& layer,
217                                 bool colorTransformModifiesAlpha) {
218     if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) {
219         // return false if the content is opaque and would therefore occlude the blur
220         const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque;
221         const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha;
222         return layer.skipContentDraw || !(opaqueContent && opaqueAlpha);
223     }
224     return false;
225 }
226 
getSkColor(const android::vec4 & color)227 static inline SkColor getSkColor(const android::vec4& color) {
228     return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
229 }
230 
getSkM44(const android::mat4 & matrix)231 static inline SkM44 getSkM44(const android::mat4& matrix) {
232     return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
233                  matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
234                  matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],
235                  matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
236 }
237 
getSkPoint3(const android::vec3 & vector)238 static inline SkPoint3 getSkPoint3(const android::vec3& vector) {
239     return SkPoint3::Make(vector.x, vector.y, vector.z);
240 }
241 } // namespace
242 
243 namespace android {
244 namespace renderengine {
245 namespace skia {
246 
247 using base::StringAppendF;
248 
primeCache(PrimeCacheConfig config)249 std::future<void> SkiaRenderEngine::primeCache(PrimeCacheConfig config) {
250     Cache::primeShaderCache(this, config);
251     return {};
252 }
253 
load(const SkData & key)254 sk_sp<SkData> SkiaRenderEngine::SkSLCacheMonitor::load(const SkData& key) {
255     // This "cache" does not actually cache anything. It just allows us to
256     // monitor Skia's internal cache. So this method always returns null.
257     return nullptr;
258 }
259 
store(const SkData & key,const SkData & data,const SkString & description)260 void SkiaRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data,
261                                                const SkString& description) {
262     mShadersCachedSinceLastCall++;
263     mTotalShadersCompiled++;
264     ATRACE_FORMAT("SF cache: %i shaders", mTotalShadersCompiled);
265 }
266 
reportShadersCompiled()267 int SkiaRenderEngine::reportShadersCompiled() {
268     return mSkSLCacheMonitor.totalShadersCompiled();
269 }
270 
setEnableTracing(bool tracingEnabled)271 void SkiaRenderEngine::setEnableTracing(bool tracingEnabled) {
272     SkAndroidFrameworkTraceUtil::setEnableTracing(tracingEnabled);
273 }
274 
SkiaRenderEngine(Threaded threaded,PixelFormat pixelFormat,BlurAlgorithm blurAlgorithm)275 SkiaRenderEngine::SkiaRenderEngine(Threaded threaded, PixelFormat pixelFormat,
276                                    BlurAlgorithm blurAlgorithm)
277       : RenderEngine(threaded), mDefaultPixelFormat(pixelFormat) {
278     switch (blurAlgorithm) {
279         case BlurAlgorithm::GAUSSIAN: {
280             ALOGD("Background Blurs Enabled (Gaussian algorithm)");
281             mBlurFilter = new GaussianBlurFilter();
282             break;
283         }
284         case BlurAlgorithm::KAWASE: {
285             ALOGD("Background Blurs Enabled (Kawase algorithm)");
286             mBlurFilter = new KawaseBlurFilter();
287             break;
288         }
289         default: {
290             mBlurFilter = nullptr;
291             break;
292         }
293     }
294 
295     mCapture = std::make_unique<SkiaCapture>();
296 }
297 
~SkiaRenderEngine()298 SkiaRenderEngine::~SkiaRenderEngine() { }
299 
300 // To be called from backend dtors. Used to clean up Skia objects before GPU API contexts are
301 // destroyed by subclasses.
finishRenderingAndAbandonContexts()302 void SkiaRenderEngine::finishRenderingAndAbandonContexts() {
303     std::lock_guard<std::mutex> lock(mRenderingMutex);
304 
305     if (mBlurFilter) {
306         delete mBlurFilter;
307     }
308 
309     // Leftover textures may hold refs to backend-specific Skia contexts, which must be released
310     // before ~SkiaGpuContext is called.
311     mTextureCleanupMgr.setDeferredStatus(false);
312     mTextureCleanupMgr.cleanup();
313 
314     // ~SkiaGpuContext must be called before GPU API contexts are torn down.
315     mContext.reset();
316     mProtectedContext.reset();
317 }
318 
useProtectedContext(bool useProtectedContext)319 void SkiaRenderEngine::useProtectedContext(bool useProtectedContext) {
320     if (useProtectedContext == mInProtectedContext ||
321         (useProtectedContext && !supportsProtectedContent())) {
322         return;
323     }
324 
325     // release any scratch resources before switching into a new mode
326     if (getActiveContext()) {
327         getActiveContext()->purgeUnlockedScratchResources();
328     }
329 
330     // Backend-specific way to switch to protected context
331     if (useProtectedContextImpl(
332             useProtectedContext ? GrProtected::kYes : GrProtected::kNo)) {
333         mInProtectedContext = useProtectedContext;
334         // given that we are sharing the same thread between two contexts we need to
335         // make sure that the thread state is reset when switching between the two.
336         if (getActiveContext()) {
337             getActiveContext()->resetContextIfApplicable();
338         }
339     }
340 }
341 
getActiveContext()342 SkiaGpuContext* SkiaRenderEngine::getActiveContext() {
343     return mInProtectedContext ? mProtectedContext.get() : mContext.get();
344 }
345 
toDegrees(uint32_t transform)346 static float toDegrees(uint32_t transform) {
347     switch (transform) {
348         case ui::Transform::ROT_90:
349             return 90.0;
350         case ui::Transform::ROT_180:
351             return 180.0;
352         case ui::Transform::ROT_270:
353             return 270.0;
354         default:
355             return 0.0;
356     }
357 }
358 
toSkColorMatrix(const android::mat4 & matrix)359 static SkColorMatrix toSkColorMatrix(const android::mat4& matrix) {
360     return SkColorMatrix(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], 0, matrix[0][1],
361                          matrix[1][1], matrix[2][1], matrix[3][1], 0, matrix[0][2], matrix[1][2],
362                          matrix[2][2], matrix[3][2], 0, matrix[0][3], matrix[1][3], matrix[2][3],
363                          matrix[3][3], 0);
364 }
365 
needsToneMapping(ui::Dataspace sourceDataspace,ui::Dataspace destinationDataspace)366 static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destinationDataspace) {
367     int64_t sourceTransfer = sourceDataspace & HAL_DATASPACE_TRANSFER_MASK;
368     int64_t destTransfer = destinationDataspace & HAL_DATASPACE_TRANSFER_MASK;
369 
370     // Treat unsupported dataspaces as srgb
371     if (destTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
372         destTransfer != HAL_DATASPACE_TRANSFER_HLG &&
373         destTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
374         destTransfer = HAL_DATASPACE_TRANSFER_SRGB;
375     }
376 
377     if (sourceTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
378         sourceTransfer != HAL_DATASPACE_TRANSFER_HLG &&
379         sourceTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
380         sourceTransfer = HAL_DATASPACE_TRANSFER_SRGB;
381     }
382 
383     const bool isSourceLinear = sourceTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
384     const bool isSourceSRGB = sourceTransfer == HAL_DATASPACE_TRANSFER_SRGB;
385     const bool isDestLinear = destTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
386     const bool isDestSRGB = destTransfer == HAL_DATASPACE_TRANSFER_SRGB;
387 
388     return !(isSourceLinear && isDestSRGB) && !(isSourceSRGB && isDestLinear) &&
389             sourceTransfer != destTransfer;
390 }
391 
ensureContextsCreated()392 void SkiaRenderEngine::ensureContextsCreated() {
393     if (mContext) {
394         return;
395     }
396 
397     std::tie(mContext, mProtectedContext) = createContexts();
398 }
399 
mapExternalTextureBuffer(const sp<GraphicBuffer> & buffer,bool isRenderable)400 void SkiaRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
401                                                   bool isRenderable) {
402     // Only run this if RE is running on its own thread. This
403     // way the access to GL/VK operations is guaranteed to be happening on the
404     // same thread.
405     if (!isThreaded()) {
406         return;
407     }
408     // We don't attempt to map a buffer if the buffer contains protected content. In GL this is
409     // important because GPU resources for protected buffers are much more limited. (In Vk we
410     // simply match the existing behavior for protected buffers.)  We also never cache any
411     // buffers while in a protected context.
412     const bool isProtectedBuffer = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
413     // Don't attempt to map buffers if we're not gpu sampleable. Callers shouldn't send a buffer
414     // over to RenderEngine.
415     const bool isGpuSampleable = buffer->getUsage() & GRALLOC_USAGE_HW_TEXTURE;
416     if (isProtectedBuffer || isProtected() || !isGpuSampleable) {
417         return;
418     }
419     ATRACE_CALL();
420 
421     // If we were to support caching protected buffers then we will need to switch the
422     // currently bound context if we are not already using the protected context (and subsequently
423     // switch back after the buffer is cached).
424     auto context = getActiveContext();
425     auto& cache = mTextureCache;
426 
427     std::lock_guard<std::mutex> lock(mRenderingMutex);
428     mGraphicBufferExternalRefs[buffer->getId()]++;
429 
430     if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) {
431         if (FlagManager::getInstance().renderable_buffer_usage()) {
432             isRenderable = buffer->getUsage() & GRALLOC_USAGE_HW_RENDER;
433         }
434         std::unique_ptr<SkiaBackendTexture> backendTexture =
435                 context->makeBackendTexture(buffer->toAHardwareBuffer(), isRenderable);
436         auto imageTextureRef =
437                 std::make_shared<AutoBackendTexture::LocalRef>(std::move(backendTexture),
438                                                                mTextureCleanupMgr);
439         cache.insert({buffer->getId(), imageTextureRef});
440     }
441 }
442 
unmapExternalTextureBuffer(sp<GraphicBuffer> && buffer)443 void SkiaRenderEngine::unmapExternalTextureBuffer(sp<GraphicBuffer>&& buffer) {
444     ATRACE_CALL();
445     std::lock_guard<std::mutex> lock(mRenderingMutex);
446     if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId());
447         iter != mGraphicBufferExternalRefs.end()) {
448         if (iter->second == 0) {
449             ALOGW("Attempted to unmap GraphicBuffer <id: %" PRId64
450                   "> from RenderEngine texture, but the "
451                   "ref count was already zero!",
452                   buffer->getId());
453             mGraphicBufferExternalRefs.erase(buffer->getId());
454             return;
455         }
456 
457         iter->second--;
458 
459         // Swap contexts if needed prior to deleting this buffer
460         // See Issue 1 of
461         // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_protected_content.txt: even
462         // when a protected context and an unprotected context are part of the same share group,
463         // protected surfaces may not be accessed by an unprotected context, implying that protected
464         // surfaces may only be freed when a protected context is active.
465         const bool inProtected = mInProtectedContext;
466         useProtectedContext(buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
467 
468         if (iter->second == 0) {
469             mTextureCache.erase(buffer->getId());
470             mGraphicBufferExternalRefs.erase(buffer->getId());
471         }
472 
473         // Swap back to the previous context so that cached values of isProtected in SurfaceFlinger
474         // are up-to-date.
475         if (inProtected != mInProtectedContext) {
476             useProtectedContext(inProtected);
477         }
478     }
479 }
480 
getOrCreateBackendTexture(const sp<GraphicBuffer> & buffer,bool isOutputBuffer)481 std::shared_ptr<AutoBackendTexture::LocalRef> SkiaRenderEngine::getOrCreateBackendTexture(
482         const sp<GraphicBuffer>& buffer, bool isOutputBuffer) {
483     // Do not lookup the buffer in the cache for protected contexts
484     if (!isProtected()) {
485         if (const auto& it = mTextureCache.find(buffer->getId()); it != mTextureCache.end()) {
486             return it->second;
487         }
488     }
489     std::unique_ptr<SkiaBackendTexture> backendTexture =
490             getActiveContext()->makeBackendTexture(buffer->toAHardwareBuffer(), isOutputBuffer);
491     return std::make_shared<AutoBackendTexture::LocalRef>(std::move(backendTexture),
492                                                           mTextureCleanupMgr);
493 }
494 
canSkipPostRenderCleanup() const495 bool SkiaRenderEngine::canSkipPostRenderCleanup() const {
496     std::lock_guard<std::mutex> lock(mRenderingMutex);
497     return mTextureCleanupMgr.isEmpty();
498 }
499 
cleanupPostRender()500 void SkiaRenderEngine::cleanupPostRender() {
501     ATRACE_CALL();
502     std::lock_guard<std::mutex> lock(mRenderingMutex);
503     mTextureCleanupMgr.cleanup();
504 }
505 
createRuntimeEffectShader(const RuntimeEffectShaderParameters & parameters)506 sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader(
507         const RuntimeEffectShaderParameters& parameters) {
508     // The given surface will be stretched by HWUI via matrix transformation
509     // which gets similar results for most surfaces
510     // Determine later on if we need to leverage the stertch shader within
511     // surface flinger
512     const auto& stretchEffect = parameters.layer.stretchEffect;
513     const auto& targetBuffer = parameters.layer.source.buffer.buffer;
514     auto shader = parameters.shader;
515     if (stretchEffect.hasEffect()) {
516         const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
517         if (graphicBuffer && parameters.shader) {
518             shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
519         }
520     }
521 
522     if (parameters.requiresLinearEffect) {
523         const auto format = targetBuffer != nullptr
524                 ? std::optional<ui::PixelFormat>(
525                           static_cast<ui::PixelFormat>(targetBuffer->getPixelFormat()))
526                 : std::nullopt;
527 
528         if (parameters.display.tonemapStrategy == DisplaySettings::TonemapStrategy::Local) {
529             // TODO: Handle color matrix transforms in linear space.
530             SkImage* image = parameters.shader->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr);
531             if (image) {
532                 static MouriMap kMapper;
533                 const float ratio = getHdrRenderType(parameters.layer.sourceDataspace, format) ==
534                                 HdrRenderType::GENERIC_HDR
535                         ? 1.0f
536                         : parameters.layerDimmingRatio;
537                 return kMapper.mouriMap(getActiveContext(), parameters.shader, ratio);
538             }
539         }
540 
541         auto effect =
542                 shaders::LinearEffect{.inputDataspace = parameters.layer.sourceDataspace,
543                                       .outputDataspace = parameters.outputDataSpace,
544                                       .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha,
545                                       .fakeOutputDataspace = parameters.fakeOutputDataspace};
546 
547         auto effectIter = mRuntimeEffects.find(effect);
548         sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
549         if (effectIter == mRuntimeEffects.end()) {
550             runtimeEffect = buildRuntimeEffect(effect);
551             mRuntimeEffects.insert({effect, runtimeEffect});
552         } else {
553             runtimeEffect = effectIter->second;
554         }
555 
556         mat4 colorTransform = parameters.layer.colorTransform;
557 
558         colorTransform *=
559                 mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
560                                  parameters.layerDimmingRatio, 1.f));
561 
562         const auto targetBuffer = parameters.layer.source.buffer.buffer;
563         const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
564         const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr;
565         return createLinearEffectShader(parameters.shader, effect, runtimeEffect,
566                                         std::move(colorTransform), parameters.display.maxLuminance,
567                                         parameters.display.currentLuminanceNits,
568                                         parameters.layer.source.buffer.maxLuminanceNits,
569                                         hardwareBuffer, parameters.display.renderIntent);
570     }
571     return parameters.shader;
572 }
573 
initCanvas(SkCanvas * canvas,const DisplaySettings & display)574 void SkiaRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
575     if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
576         // Record display settings when capture is running.
577         std::stringstream displaySettings;
578         PrintTo(display, &displaySettings);
579         // Store the DisplaySettings in additional information.
580         canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
581                                SkData::MakeWithCString(displaySettings.str().c_str()));
582     }
583 
584     // Before doing any drawing, let's make sure that we'll start at the origin of the display.
585     // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
586     // displays might have different scaling when compared to the physical screen.
587 
588     canvas->clipRect(getSkRect(display.physicalDisplay));
589     canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
590 
591     const auto clipWidth = display.clip.width();
592     const auto clipHeight = display.clip.height();
593     auto rotatedClipWidth = clipWidth;
594     auto rotatedClipHeight = clipHeight;
595     // Scale is contingent on the rotation result.
596     if (display.orientation & ui::Transform::ROT_90) {
597         std::swap(rotatedClipWidth, rotatedClipHeight);
598     }
599     const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
600             static_cast<SkScalar>(rotatedClipWidth);
601     const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
602             static_cast<SkScalar>(rotatedClipHeight);
603     canvas->scale(scaleX, scaleY);
604 
605     // Canvas rotation is done by centering the clip window at the origin, rotating, translating
606     // back so that the top left corner of the clip is at (0, 0).
607     canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
608     canvas->rotate(toDegrees(display.orientation));
609     canvas->translate(-clipWidth / 2, -clipHeight / 2);
610     canvas->translate(-display.clip.left, -display.clip.top);
611 }
612 
613 class AutoSaveRestore {
614 public:
AutoSaveRestore(SkCanvas * canvas)615     AutoSaveRestore(SkCanvas* canvas) : mCanvas(canvas) { mSaveCount = canvas->save(); }
~AutoSaveRestore()616     ~AutoSaveRestore() { restore(); }
replace(SkCanvas * canvas)617     void replace(SkCanvas* canvas) {
618         mCanvas = canvas;
619         mSaveCount = canvas->save();
620     }
restore()621     void restore() {
622         if (mCanvas) {
623             mCanvas->restoreToCount(mSaveCount);
624             mCanvas = nullptr;
625         }
626     }
627 
628 private:
629     SkCanvas* mCanvas;
630     int mSaveCount;
631 };
632 
getBlurRRect(const BlurRegion & region)633 static SkRRect getBlurRRect(const BlurRegion& region) {
634     const auto rect = SkRect::MakeLTRB(region.left, region.top, region.right, region.bottom);
635     const SkVector radii[4] = {SkVector::Make(region.cornerRadiusTL, region.cornerRadiusTL),
636                                SkVector::Make(region.cornerRadiusTR, region.cornerRadiusTR),
637                                SkVector::Make(region.cornerRadiusBR, region.cornerRadiusBR),
638                                SkVector::Make(region.cornerRadiusBL, region.cornerRadiusBL)};
639     SkRRect roundedRect;
640     roundedRect.setRectRadii(rect, radii);
641     return roundedRect;
642 }
643 
644 // Arbitrary default margin which should be close enough to zero.
645 constexpr float kDefaultMargin = 0.0001f;
equalsWithinMargin(float expected,float value,float margin=kDefaultMargin)646 static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) {
647     LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
648     return std::abs(expected - value) < margin;
649 }
650 
651 namespace {
652 template <typename T>
logSettings(const T & t)653 void logSettings(const T& t) {
654     std::stringstream stream;
655     PrintTo(t, &stream);
656     auto string = stream.str();
657     size_t pos = 0;
658     // Perfetto ignores \n, so split up manually into separate ALOGD statements.
659     const size_t size = string.size();
660     while (pos < size) {
661         const size_t end = std::min(string.find("\n", pos), size);
662         ALOGD("%s", string.substr(pos, end - pos).c_str());
663         pos = end + 1;
664     }
665 }
666 } // namespace
667 
668 // Helper class intended to be used on the stack to ensure that texture cleanup
669 // is deferred until after this class goes out of scope.
670 class DeferTextureCleanup final {
671 public:
DeferTextureCleanup(AutoBackendTexture::CleanupManager & mgr)672     DeferTextureCleanup(AutoBackendTexture::CleanupManager& mgr) : mMgr(mgr) {
673         mMgr.setDeferredStatus(true);
674     }
~DeferTextureCleanup()675     ~DeferTextureCleanup() { mMgr.setDeferredStatus(false); }
676 
677 private:
678     DISALLOW_COPY_AND_ASSIGN(DeferTextureCleanup);
679     AutoBackendTexture::CleanupManager& mMgr;
680 };
681 
drawLayersInternal(const std::shared_ptr<std::promise<FenceResult>> && resultPromise,const DisplaySettings & display,const std::vector<LayerSettings> & layers,const std::shared_ptr<ExternalTexture> & buffer,base::unique_fd && bufferFence)682 void SkiaRenderEngine::drawLayersInternal(
683         const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
684         const DisplaySettings& display, const std::vector<LayerSettings>& layers,
685         const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) {
686     ATRACE_FORMAT("%s for %s", __func__, display.namePlusId.c_str());
687 
688     std::lock_guard<std::mutex> lock(mRenderingMutex);
689 
690     if (buffer == nullptr) {
691         ALOGE("No output buffer provided. Aborting GPU composition.");
692         resultPromise->set_value(base::unexpected(BAD_VALUE));
693         return;
694     }
695 
696     validateOutputBufferUsage(buffer->getBuffer());
697 
698     auto context = getActiveContext();
699     LOG_ALWAYS_FATAL_IF(context->isAbandonedOrDeviceLost(),
700                         "Context is abandoned/device lost at start of %s", __func__);
701 
702     // any AutoBackendTexture deletions will now be deferred until cleanupPostRender is called
703     DeferTextureCleanup dtc(mTextureCleanupMgr);
704 
705     auto surfaceTextureRef = getOrCreateBackendTexture(buffer->getBuffer(), true);
706 
707     // wait on the buffer to be ready to use prior to using it
708     waitFence(context, bufferFence);
709 
710     sk_sp<SkSurface> dstSurface = surfaceTextureRef->getOrCreateSurface(display.outputDataspace);
711 
712     SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
713     if (dstCanvas == nullptr) {
714         ALOGE("Cannot acquire canvas from Skia.");
715         resultPromise->set_value(base::unexpected(BAD_VALUE));
716         return;
717     }
718 
719     // setup color filter if necessary
720     sk_sp<SkColorFilter> displayColorTransform;
721     if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
722         displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
723     }
724     const bool ctModifiesAlpha =
725             displayColorTransform && !displayColorTransform->isAlphaUnchanged();
726 
727     // Find the max layer white point to determine the max luminance of the scene...
728     const float maxLayerWhitePoint = std::transform_reduce(
729             layers.cbegin(), layers.cend(), 0.f,
730             [](float left, float right) { return std::max(left, right); },
731             [&](const auto& l) { return l.whitePointNits; });
732 
733     // ...and compute the dimming ratio if dimming is requested
734     const float displayDimmingRatio = display.targetLuminanceNits > 0.f && maxLayerWhitePoint > 0.f
735             ? maxLayerWhitePoint / display.targetLuminanceNits
736             : 1.f;
737 
738     // Find if any layers have requested blur, we'll use that info to decide when to render to an
739     // offscreen buffer and when to render to the native buffer.
740     sk_sp<SkSurface> activeSurface(dstSurface);
741     SkCanvas* canvas = dstCanvas;
742     SkiaCapture::OffscreenState offscreenCaptureState;
743     const LayerSettings* blurCompositionLayer = nullptr;
744     if (mBlurFilter) {
745         bool requiresCompositionLayer = false;
746         for (const auto& layer : layers) {
747             // if the layer doesn't have blur or it is not visible then continue
748             if (!layerHasBlur(layer, ctModifiesAlpha)) {
749                 continue;
750             }
751             if (layer.backgroundBlurRadius > 0 &&
752                 layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
753                 requiresCompositionLayer = true;
754             }
755             for (auto region : layer.blurRegions) {
756                 if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
757                     requiresCompositionLayer = true;
758                 }
759             }
760             if (requiresCompositionLayer) {
761                 activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
762                 canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
763                 blurCompositionLayer = &layer;
764                 break;
765             }
766         }
767     }
768 
769     AutoSaveRestore surfaceAutoSaveRestore(canvas);
770     // Clear the entire canvas with a transparent black to prevent ghost images.
771     canvas->clear(SK_ColorTRANSPARENT);
772     initCanvas(canvas, display);
773 
774     if (kPrintLayerSettings) {
775         logSettings(display);
776     }
777     for (const auto& layer : layers) {
778         ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str());
779 
780         if (kPrintLayerSettings) {
781             logSettings(layer);
782         }
783 
784         sk_sp<SkImage> blurInput;
785         if (blurCompositionLayer == &layer) {
786             LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
787             LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
788 
789             // save a snapshot of the activeSurface to use as input to the blur shaders
790             blurInput = activeSurface->makeImageSnapshot();
791 
792             // blit the offscreen framebuffer into the destination AHB. This ensures that
793             // even if the blurred image does not cover the screen (for example, during
794             // a rotation animation, or if blur regions are used), the entire screen is
795             // initialized.
796             if (layer.blurRegions.size() || FlagManager::getInstance().restore_blur_step()) {
797                 SkPaint paint;
798                 paint.setBlendMode(SkBlendMode::kSrc);
799                 if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
800                     uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
801                     dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
802                                               String8::format("SurfaceID|%" PRId64, id).c_str(),
803                                               nullptr);
804                     dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
805                 } else {
806                     activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
807                 }
808             }
809 
810             // assign dstCanvas to canvas and ensure that the canvas state is up to date
811             canvas = dstCanvas;
812             surfaceAutoSaveRestore.replace(canvas);
813             initCanvas(canvas, display);
814 
815             LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
816                                 dstSurface->getCanvas()->getSaveCount());
817             LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
818                                 dstSurface->getCanvas()->getTotalMatrix());
819 
820             // assign dstSurface to activeSurface
821             activeSurface = dstSurface;
822         }
823 
824         SkAutoCanvasRestore layerAutoSaveRestore(canvas, true);
825         if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
826             // Record the name of the layer if the capture is running.
827             std::stringstream layerSettings;
828             PrintTo(layer, &layerSettings);
829             // Store the LayerSettings in additional information.
830             canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(),
831                                    SkData::MakeWithCString(layerSettings.str().c_str()));
832         }
833         // Layers have a local transform that should be applied to them
834         canvas->concat(getSkM44(layer.geometry.positionTransform).asM33());
835 
836         const auto [bounds, roundRectClip] =
837                 getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop,
838                                  layer.geometry.roundedCornersRadius);
839         if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) {
840             std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
841 
842             // if multiple layers have blur, then we need to take a snapshot now because
843             // only the lowest layer will have blurImage populated earlier
844             if (!blurInput) {
845                 blurInput = activeSurface->makeImageSnapshot();
846             }
847 
848             // rect to be blurred in the coordinate space of blurInput
849             SkRect blurRect = canvas->getTotalMatrix().mapRect(bounds.rect());
850 
851             // Some layers may be much bigger than the screen. If we used
852             // `blurRect` directly, this would allocate a large buffer with no
853             // benefit. Apply the clip, which already takes the display size
854             // into account. The clipped size will then be used to calculate the
855             // size of the buffer we will create for blurring.
856             if (!blurRect.intersect(SkRect::Make(canvas->getDeviceClipBounds()))) {
857                 // This should not happen, but if it did, we would use the full
858                 // sized layer, which should still be fine.
859                 ALOGW("blur bounds does not intersect display clip!");
860             }
861 
862             // if the clip needs to be applied then apply it now and make sure
863             // it is restored before we attempt to draw any shadows.
864             SkAutoCanvasRestore acr(canvas, true);
865             if (!roundRectClip.isEmpty()) {
866                 canvas->clipRRect(roundRectClip, true);
867             }
868 
869             // TODO(b/182216890): Filter out empty layers earlier
870             if (blurRect.width() > 0 && blurRect.height() > 0) {
871                 if (layer.backgroundBlurRadius > 0) {
872                     ATRACE_NAME("BackgroundBlur");
873                     auto blurredImage = mBlurFilter->generate(context, layer.backgroundBlurRadius,
874                                                               blurInput, blurRect);
875 
876                     cachedBlurs[layer.backgroundBlurRadius] = blurredImage;
877 
878                     mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f,
879                                                 blurRect, blurredImage, blurInput);
880                 }
881 
882                 canvas->concat(getSkM44(layer.blurRegionTransform).asM33());
883                 for (auto region : layer.blurRegions) {
884                     if (cachedBlurs[region.blurRadius] == nullptr) {
885                         ATRACE_NAME("BlurRegion");
886                         cachedBlurs[region.blurRadius] =
887                                 mBlurFilter->generate(context, region.blurRadius, blurInput,
888                                                       blurRect);
889                     }
890 
891                     mBlurFilter->drawBlurRegion(canvas, getBlurRRect(region), region.blurRadius,
892                                                 region.alpha, blurRect,
893                                                 cachedBlurs[region.blurRadius], blurInput);
894                 }
895             }
896         }
897 
898         if (layer.shadow.length > 0) {
899             // This would require a new parameter/flag to SkShadowUtils::DrawShadow
900             LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow");
901 
902             SkRRect shadowBounds, shadowClip;
903             if (layer.geometry.boundaries == layer.shadow.boundaries) {
904                 shadowBounds = bounds;
905                 shadowClip = roundRectClip;
906             } else {
907                 std::tie(shadowBounds, shadowClip) =
908                         getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop,
909                                          layer.geometry.roundedCornersRadius);
910             }
911 
912             // Technically, if bounds is a rect and roundRectClip is not empty,
913             // it means that the bounds and roundedCornersCrop were different
914             // enough that we should intersect them to find the proper shadow.
915             // In practice, this often happens when the two rectangles appear to
916             // not match due to rounding errors. Draw the rounded version, which
917             // looks more like the intent.
918             const auto& rrect =
919                     shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds;
920             drawShadow(canvas, rrect, layer.shadow);
921         }
922 
923         const float layerDimmingRatio = layer.whitePointNits <= 0.f
924                 ? displayDimmingRatio
925                 : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
926 
927         const bool dimInLinearSpace = display.dimmingStage !=
928                 aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
929 
930         const bool isExtendedHdr = (layer.sourceDataspace & ui::Dataspace::RANGE_MASK) ==
931                         static_cast<int32_t>(ui::Dataspace::RANGE_EXTENDED) &&
932                 (display.outputDataspace & ui::Dataspace::TRANSFER_MASK) ==
933                         static_cast<int32_t>(ui::Dataspace::TRANSFER_SRGB);
934 
935         const bool useFakeOutputDataspaceForRuntimeEffect = !dimInLinearSpace && isExtendedHdr;
936 
937         const ui::Dataspace fakeDataspace = useFakeOutputDataspaceForRuntimeEffect
938                 ? static_cast<ui::Dataspace>(
939                           (display.outputDataspace & ui::Dataspace::STANDARD_MASK) |
940                           ui::Dataspace::TRANSFER_GAMMA2_2 |
941                           (display.outputDataspace & ui::Dataspace::RANGE_MASK))
942                 : ui::Dataspace::UNKNOWN;
943 
944         // If the input dataspace is range extended, the output dataspace transfer is sRGB
945         // and dimmingStage is GAMMA_OETF, dim in linear space instead, and
946         // set the output dataspace's transfer to be GAMMA2_2.
947         // This allows DPU side to use oetf_gamma_2p2 for extended HDR layer
948         // to avoid tone shift.
949         // The reason of tone shift here is because HDR layers manage white point
950         // luminance in linear space, which color pipelines request GAMMA_OETF break
951         // without a gamma 2.2 fixup.
952         const bool requiresLinearEffect = layer.colorTransform != mat4() ||
953                 (needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
954                 (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio)) ||
955                 (!dimInLinearSpace && isExtendedHdr);
956 
957         // quick abort from drawing the remaining portion of the layer
958         if (layer.skipContentDraw ||
959             (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending &&
960              (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) {
961             continue;
962         }
963 
964         const ui::Dataspace layerDataspace = layer.sourceDataspace;
965 
966         SkPaint paint;
967         if (layer.source.buffer.buffer) {
968             ATRACE_NAME("DrawImage");
969             validateInputBufferUsage(layer.source.buffer.buffer->getBuffer());
970             const auto& item = layer.source.buffer;
971             auto imageTextureRef = getOrCreateBackendTexture(item.buffer->getBuffer(), false);
972 
973             // if the layer's buffer has a fence, then we must must respect the fence prior to using
974             // the buffer.
975             if (layer.source.buffer.fence != nullptr) {
976                 waitFence(context, layer.source.buffer.fence->get());
977             }
978 
979             // isOpaque means we need to ignore the alpha in the image,
980             // replacing it with the alpha specified by the LayerSettings. See
981             // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean)
982             // The proper way to do this is to use an SkColorType that ignores
983             // alpha, like kRGB_888x_SkColorType, and that is used if the
984             // incoming image is kRGBA_8888_SkColorType. However, the incoming
985             // image may be kRGBA_F16_SkColorType, for which there is no RGBX
986             // SkColorType, or kRGBA_1010102_SkColorType, for which we have
987             // kRGB_101010x_SkColorType, but it is not yet supported as a source
988             // on the GPU. (Adding both is tracked in skbug.com/12048.) In the
989             // meantime, we'll use a workaround that works unless we need to do
990             // any color conversion. The workaround requires that we pretend the
991             // image is already premultiplied, so that we do not premultiply it
992             // before applying SkBlendMode::kPlus.
993             const bool useIsOpaqueWorkaround = item.isOpaque &&
994                     (imageTextureRef->colorType() == kRGBA_1010102_SkColorType ||
995                      imageTextureRef->colorType() == kRGBA_F16_SkColorType);
996             const auto alphaType = useIsOpaqueWorkaround ? kPremul_SkAlphaType
997                     : item.isOpaque                      ? kOpaque_SkAlphaType
998                     : item.usePremultipliedAlpha         ? kPremul_SkAlphaType
999                                                          : kUnpremul_SkAlphaType;
1000             sk_sp<SkImage> image = imageTextureRef->makeImage(layerDataspace, alphaType);
1001 
1002             auto texMatrix = getSkM44(item.textureTransform).asM33();
1003             // textureTansform was intended to be passed directly into a shader, so when
1004             // building the total matrix with the textureTransform we need to first
1005             // normalize it, then apply the textureTransform, then scale back up.
1006             texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height());
1007             texMatrix.postScale(image->width(), image->height());
1008 
1009             SkMatrix matrix;
1010             if (!texMatrix.invert(&matrix)) {
1011                 matrix = texMatrix;
1012             }
1013             // The shader does not respect the translation, so we add it to the texture
1014             // transform for the SkImage. This will make sure that the correct layer contents
1015             // are drawn in the correct part of the screen.
1016             matrix.postTranslate(bounds.rect().fLeft, bounds.rect().fTop);
1017 
1018             sk_sp<SkShader> shader;
1019 
1020             if (layer.source.buffer.useTextureFiltering) {
1021                 shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
1022                                            SkSamplingOptions(
1023                                                    {SkFilterMode::kLinear, SkMipmapMode::kNone}),
1024                                            &matrix);
1025             } else {
1026                 shader = image->makeShader(SkSamplingOptions(), matrix);
1027             }
1028 
1029             if (useIsOpaqueWorkaround) {
1030                 shader = SkShaders::Blend(SkBlendMode::kPlus, shader,
1031                                           SkShaders::Color(SkColors::kBlack,
1032                                                            toSkColorSpace(layerDataspace)));
1033             }
1034 
1035             paint.setShader(createRuntimeEffectShader(
1036                     RuntimeEffectShaderParameters{.shader = shader,
1037                                                   .layer = layer,
1038                                                   .display = display,
1039                                                   .undoPremultipliedAlpha = !item.isOpaque &&
1040                                                           item.usePremultipliedAlpha,
1041                                                   .requiresLinearEffect = requiresLinearEffect,
1042                                                   .layerDimmingRatio = dimInLinearSpace
1043                                                           ? layerDimmingRatio
1044                                                           : 1.f,
1045                                                   .outputDataSpace = display.outputDataspace,
1046                                                   .fakeOutputDataspace = fakeDataspace}));
1047 
1048             // Turn on dithering when dimming beyond this (arbitrary) threshold...
1049             static constexpr float kDimmingThreshold = 0.9f;
1050             // ...or we're rendering an HDR layer down to an 8-bit target
1051             // Most HDR standards require at least 10-bits of color depth for source content, so we
1052             // can just extract the transfer function rather than dig into precise gralloc layout.
1053             // Furthermore, we can assume that the only 8-bit target we support is RGBA8888.
1054             const bool requiresDownsample =
1055                     getHdrRenderType(layer.sourceDataspace,
1056                                      std::optional<ui::PixelFormat>(static_cast<ui::PixelFormat>(
1057                                              buffer->getPixelFormat()))) != HdrRenderType::SDR &&
1058                     buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888;
1059             if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) {
1060                 paint.setDither(true);
1061             }
1062             paint.setAlphaf(layer.alpha);
1063 
1064             if (imageTextureRef->colorType() == kAlpha_8_SkColorType) {
1065                 LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8");
1066 
1067                 // SysUI creates the alpha layer as a coverage layer, which is
1068                 // appropriate for the DPU. Use a color matrix to convert it to
1069                 // a mask.
1070                 // TODO (b/219525258): Handle input as a mask.
1071                 //
1072                 // The color matrix will convert A8 pixels with no alpha to
1073                 // black, as described by this vector. If the display handles
1074                 // the color transform, we need to invert it to find the color
1075                 // that will result in black after the DPU applies the transform.
1076                 SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a
1077                 if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) {
1078                     SkM44 colorSpaceMatrix = getSkM44(display.colorTransform);
1079                     if (colorSpaceMatrix.invert(&colorSpaceMatrix)) {
1080                         black = colorSpaceMatrix * black;
1081                     } else {
1082                         // We'll just have to use 0,0,0 as black, which should
1083                         // be close to correct.
1084                         ALOGI("Could not invert colorTransform!");
1085                     }
1086                 }
1087                 SkColorMatrix colorMatrix(0, 0, 0, 0, black[0],
1088                                           0, 0, 0, 0, black[1],
1089                                           0, 0, 0, 0, black[2],
1090                                           0, 0, 0, -1, 1);
1091                 if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
1092                     // On the other hand, if the device doesn't handle it, we
1093                     // have to apply it ourselves.
1094                     colorMatrix.postConcat(toSkColorMatrix(display.colorTransform));
1095                 }
1096                 paint.setColorFilter(SkColorFilters::Matrix(colorMatrix));
1097             }
1098         } else {
1099             ATRACE_NAME("DrawColor");
1100             const auto color = layer.source.solidColor;
1101             sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
1102                                                                 .fG = color.g,
1103                                                                 .fB = color.b,
1104                                                                 .fA = layer.alpha},
1105                                                       toSkColorSpace(layerDataspace));
1106             paint.setShader(createRuntimeEffectShader(
1107                     RuntimeEffectShaderParameters{.shader = shader,
1108                                                   .layer = layer,
1109                                                   .display = display,
1110                                                   .undoPremultipliedAlpha = false,
1111                                                   .requiresLinearEffect = requiresLinearEffect,
1112                                                   .layerDimmingRatio = layerDimmingRatio,
1113                                                   .outputDataSpace = display.outputDataspace,
1114                                                   .fakeOutputDataspace = fakeDataspace}));
1115         }
1116 
1117         if (layer.disableBlending) {
1118             paint.setBlendMode(SkBlendMode::kSrc);
1119         }
1120 
1121         // An A8 buffer will already have the proper color filter attached to
1122         // its paint, including the displayColorTransform as needed.
1123         if (!paint.getColorFilter()) {
1124             if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) {
1125                 // If we don't dim in linear space, then when we gamma correct the dimming ratio we
1126                 // can assume a gamma 2.2 transfer function.
1127                 static constexpr float kInverseGamma22 = 1.f / 2.2f;
1128                 const auto gammaCorrectedDimmingRatio =
1129                         std::pow(layerDimmingRatio, kInverseGamma22);
1130                 auto dimmingMatrix =
1131                         mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio,
1132                                          gammaCorrectedDimmingRatio, 1.f));
1133 
1134                 const auto colorFilter =
1135                         SkColorFilters::Matrix(toSkColorMatrix(std::move(dimmingMatrix)));
1136                 paint.setColorFilter(displayColorTransform
1137                                              ? displayColorTransform->makeComposed(colorFilter)
1138                                              : colorFilter);
1139             } else {
1140                 paint.setColorFilter(displayColorTransform);
1141             }
1142         }
1143 
1144         if (!roundRectClip.isEmpty()) {
1145             canvas->clipRRect(roundRectClip, true);
1146         }
1147 
1148         if (!bounds.isRect()) {
1149             paint.setAntiAlias(true);
1150             canvas->drawRRect(bounds, paint);
1151         } else {
1152             canvas->drawRect(bounds.rect(), paint);
1153         }
1154         if (kGaneshFlushAfterEveryLayer) {
1155             ATRACE_NAME("flush surface");
1156             // No-op in Graphite. If "flushing" Skia's drawing commands after each layer is desired
1157             // in Graphite, then a graphite::Recording would need to be snapped and tracked for each
1158             // layer, which is likely possible but adds non-trivial complexity (in both bookkeeping
1159             // and refactoring).
1160             skgpu::ganesh::Flush(activeSurface);
1161         }
1162     }
1163 
1164     surfaceAutoSaveRestore.restore();
1165     mCapture->endCapture();
1166 
1167     LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
1168     auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface));
1169 
1170     if (ATRACE_ENABLED()) {
1171         static gui::FenceMonitor sMonitor("RE Completion");
1172         sMonitor.queueFence(drawFence);
1173     }
1174     resultPromise->set_value(std::move(drawFence));
1175 }
1176 
getMaxTextureSize() const1177 size_t SkiaRenderEngine::getMaxTextureSize() const {
1178     return mContext->getMaxTextureSize();
1179 }
1180 
getMaxViewportDims() const1181 size_t SkiaRenderEngine::getMaxViewportDims() const {
1182     return mContext->getMaxRenderTargetSize();
1183 }
1184 
drawShadow(SkCanvas * canvas,const SkRRect & casterRRect,const ShadowSettings & settings)1185 void SkiaRenderEngine::drawShadow(SkCanvas* canvas,
1186                                   const SkRRect& casterRRect,
1187                                   const ShadowSettings& settings) {
1188     ATRACE_CALL();
1189     const float casterZ = settings.length / 2.0f;
1190     const auto flags =
1191             settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;
1192 
1193     SkShadowUtils::DrawShadow(canvas, SkPath::RRect(casterRRect), SkPoint3::Make(0, 0, casterZ),
1194                               getSkPoint3(settings.lightPos), settings.lightRadius,
1195                               getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
1196                               flags);
1197 }
1198 
onActiveDisplaySizeChanged(ui::Size size)1199 void SkiaRenderEngine::onActiveDisplaySizeChanged(ui::Size size) {
1200     // This cache multiplier was selected based on review of cache sizes relative
1201     // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x),
1202     // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a
1203     // conservative default based on that analysis.
1204     const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat);
1205     const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER;
1206 
1207     // start by resizing the current context
1208     getActiveContext()->setResourceCacheLimit(maxResourceBytes);
1209 
1210     // if it is possible to switch contexts then we will resize the other context
1211     const bool originalProtectedState = mInProtectedContext;
1212     useProtectedContext(!mInProtectedContext);
1213     if (mInProtectedContext != originalProtectedState) {
1214         getActiveContext()->setResourceCacheLimit(maxResourceBytes);
1215         // reset back to the initial context that was active when this method was called
1216         useProtectedContext(originalProtectedState);
1217     }
1218 }
1219 
dump(std::string & result)1220 void SkiaRenderEngine::dump(std::string& result) {
1221     // Dump for the specific backend (GLES or Vk)
1222     appendBackendSpecificInfoToDump(result);
1223 
1224     // Info about protected content
1225     StringAppendF(&result, "RenderEngine supports protected context: %d\n",
1226                   supportsProtectedContent());
1227     StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
1228     StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n",
1229                   mSkSLCacheMonitor.shadersCachedSinceLastCall());
1230 
1231     std::vector<ResourcePair> cpuResourceMap = {
1232             {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
1233             {"skia/sk_resource_cache/rrect-blur_", "Masks"},
1234             {"skia/sk_resource_cache/rects-blur_", "Masks"},
1235             {"skia/sk_resource_cache/tessellated", "Shadows"},
1236             {"skia", "Other"},
1237     };
1238     SkiaMemoryReporter cpuReporter(cpuResourceMap, false);
1239     SkGraphics::DumpMemoryStatistics(&cpuReporter);
1240     StringAppendF(&result, "Skia CPU Caches: ");
1241     cpuReporter.logTotals(result);
1242     cpuReporter.logOutput(result);
1243 
1244     {
1245         std::lock_guard<std::mutex> lock(mRenderingMutex);
1246 
1247         std::vector<ResourcePair> gpuResourceMap = {
1248                 {"texture_renderbuffer", "Texture/RenderBuffer"},
1249                 {"texture", "Texture"},
1250                 {"gr_text_blob_cache", "Text"},
1251                 {"skia", "Other"},
1252         };
1253         SkiaMemoryReporter gpuReporter(gpuResourceMap, true);
1254         mContext->dumpMemoryStatistics(&gpuReporter);
1255         StringAppendF(&result, "Skia's GPU Caches: ");
1256         gpuReporter.logTotals(result);
1257         gpuReporter.logOutput(result);
1258         StringAppendF(&result, "Skia's Wrapped Objects:\n");
1259         gpuReporter.logOutput(result, true);
1260 
1261         StringAppendF(&result, "RenderEngine tracked buffers: %zu\n",
1262                       mGraphicBufferExternalRefs.size());
1263         StringAppendF(&result, "Dumping buffer ids...\n");
1264         for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) {
1265             StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts);
1266         }
1267         StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n",
1268                       mTextureCache.size());
1269         StringAppendF(&result, "Dumping buffer ids...\n");
1270         // TODO(178539829): It would be nice to know which layer these are coming from and what
1271         // the texture sizes are.
1272         for (const auto& [id, unused] : mTextureCache) {
1273             StringAppendF(&result, "- 0x%" PRIx64 "\n", id);
1274         }
1275         StringAppendF(&result, "\n");
1276 
1277         SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true);
1278         if (mProtectedContext) {
1279             mProtectedContext->dumpMemoryStatistics(&gpuProtectedReporter);
1280         }
1281         StringAppendF(&result, "Skia's GPU Protected Caches: ");
1282         gpuProtectedReporter.logTotals(result);
1283         gpuProtectedReporter.logOutput(result);
1284         StringAppendF(&result, "Skia's Protected Wrapped Objects:\n");
1285         gpuProtectedReporter.logOutput(result, true);
1286 
1287         StringAppendF(&result, "\n");
1288         StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size());
1289         for (const auto& [linearEffect, unused] : mRuntimeEffects) {
1290             StringAppendF(&result, "- inputDataspace: %s\n",
1291                           dataspaceDetails(
1292                                   static_cast<android_dataspace>(linearEffect.inputDataspace))
1293                                   .c_str());
1294             StringAppendF(&result, "- outputDataspace: %s\n",
1295                           dataspaceDetails(
1296                                   static_cast<android_dataspace>(linearEffect.outputDataspace))
1297                                   .c_str());
1298             StringAppendF(&result, "undoPremultipliedAlpha: %s\n",
1299                           linearEffect.undoPremultipliedAlpha ? "true" : "false");
1300         }
1301     }
1302     StringAppendF(&result, "\n");
1303 }
1304 
1305 } // namespace skia
1306 } // namespace renderengine
1307 } // namespace android
1308