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