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