xref: /aosp_15_r20/external/skia/src/gpu/ganesh/SkGr.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2010 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SkGr.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorFilter.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPixelRef.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurfaceProps.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrBackendSurface.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrTypes.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkIDChangeListener.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkBlenderBase.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMessageBus.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPaintPriv.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRuntimeEffectPriv.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/DitherUtils.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/Swizzle.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorInfo.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorSpaceXform.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFPArgs.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessor.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessors.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProxyProvider.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxy.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTextureProxy.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrXferProcessor.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrSkSLFP.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrTextureEffect.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkShaderBase.h"
52*c8dee2aaSAndroid Build Coastguard Worker 
53*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
54*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker class SkBlender;
57*c8dee2aaSAndroid Build Coastguard Worker class SkColorSpace;
58*c8dee2aaSAndroid Build Coastguard Worker enum SkColorType : int;
59*c8dee2aaSAndroid Build Coastguard Worker 
GrMakeKeyFromImageID(skgpu::UniqueKey * key,uint32_t imageID,const SkIRect & imageBounds)60*c8dee2aaSAndroid Build Coastguard Worker void GrMakeKeyFromImageID(skgpu::UniqueKey* key, uint32_t imageID, const SkIRect& imageBounds) {
61*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(key);
62*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(imageID);
63*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!imageBounds.isEmpty());
64*c8dee2aaSAndroid Build Coastguard Worker     static const skgpu::UniqueKey::Domain kImageIDDomain = skgpu::UniqueKey::GenerateDomain();
65*c8dee2aaSAndroid Build Coastguard Worker     skgpu::UniqueKey::Builder builder(key, kImageIDDomain, 5, "Image");
66*c8dee2aaSAndroid Build Coastguard Worker     builder[0] = imageID;
67*c8dee2aaSAndroid Build Coastguard Worker     builder[1] = imageBounds.fLeft;
68*c8dee2aaSAndroid Build Coastguard Worker     builder[2] = imageBounds.fTop;
69*c8dee2aaSAndroid Build Coastguard Worker     builder[3] = imageBounds.fRight;
70*c8dee2aaSAndroid Build Coastguard Worker     builder[4] = imageBounds.fBottom;
71*c8dee2aaSAndroid Build Coastguard Worker }
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
74*c8dee2aaSAndroid Build Coastguard Worker 
GrMakeUniqueKeyInvalidationListener(skgpu::UniqueKey * key,uint32_t contextID)75*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkIDChangeListener> GrMakeUniqueKeyInvalidationListener(skgpu::UniqueKey* key,
76*c8dee2aaSAndroid Build Coastguard Worker                                                               uint32_t contextID) {
77*c8dee2aaSAndroid Build Coastguard Worker     class Listener : public SkIDChangeListener {
78*c8dee2aaSAndroid Build Coastguard Worker     public:
79*c8dee2aaSAndroid Build Coastguard Worker         Listener(const skgpu::UniqueKey& key, uint32_t contextUniqueID)
80*c8dee2aaSAndroid Build Coastguard Worker                 : fMsg(key, contextUniqueID) {}
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker         void changed() override {
83*c8dee2aaSAndroid Build Coastguard Worker             SkMessageBus<skgpu::UniqueKeyInvalidatedMessage, uint32_t>::Post(fMsg);
84*c8dee2aaSAndroid Build Coastguard Worker         }
85*c8dee2aaSAndroid Build Coastguard Worker 
86*c8dee2aaSAndroid Build Coastguard Worker     private:
87*c8dee2aaSAndroid Build Coastguard Worker         skgpu::UniqueKeyInvalidatedMessage fMsg;
88*c8dee2aaSAndroid Build Coastguard Worker     };
89*c8dee2aaSAndroid Build Coastguard Worker 
90*c8dee2aaSAndroid Build Coastguard Worker     auto listener = sk_make_sp<Listener>(*key, contextID);
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker     // We stick a SkData on the key that calls invalidateListener in its destructor.
93*c8dee2aaSAndroid Build Coastguard Worker     auto invalidateListener = [](const void* ptr, void* /*context*/) {
94*c8dee2aaSAndroid Build Coastguard Worker         auto listener = reinterpret_cast<const sk_sp<Listener>*>(ptr);
95*c8dee2aaSAndroid Build Coastguard Worker         (*listener)->markShouldDeregister();
96*c8dee2aaSAndroid Build Coastguard Worker         delete listener;
97*c8dee2aaSAndroid Build Coastguard Worker     };
98*c8dee2aaSAndroid Build Coastguard Worker     auto data = SkData::MakeWithProc(new sk_sp<Listener>(listener),
99*c8dee2aaSAndroid Build Coastguard Worker                                      sizeof(sk_sp<Listener>),
100*c8dee2aaSAndroid Build Coastguard Worker                                      invalidateListener,
101*c8dee2aaSAndroid Build Coastguard Worker                                      nullptr);
102*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!key->getCustomData());
103*c8dee2aaSAndroid Build Coastguard Worker     key->setCustomData(std::move(data));
104*c8dee2aaSAndroid Build Coastguard Worker     return listener;
105*c8dee2aaSAndroid Build Coastguard Worker }
106*c8dee2aaSAndroid Build Coastguard Worker 
GrCopyBaseMipMapToTextureProxy(GrRecordingContext * ctx,sk_sp<GrSurfaceProxy> baseProxy,GrSurfaceOrigin origin,std::string_view label,skgpu::Budgeted budgeted)107*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrSurfaceProxy> GrCopyBaseMipMapToTextureProxy(GrRecordingContext* ctx,
108*c8dee2aaSAndroid Build Coastguard Worker                                                      sk_sp<GrSurfaceProxy> baseProxy,
109*c8dee2aaSAndroid Build Coastguard Worker                                                      GrSurfaceOrigin origin,
110*c8dee2aaSAndroid Build Coastguard Worker                                                      std::string_view label,
111*c8dee2aaSAndroid Build Coastguard Worker                                                      skgpu::Budgeted budgeted) {
112*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(baseProxy);
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     // We don't allow this for promise proxies i.e. if they need mips they need to give them
115*c8dee2aaSAndroid Build Coastguard Worker     // to us upfront.
116*c8dee2aaSAndroid Build Coastguard Worker     if (baseProxy->isPromiseProxy()) {
117*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
118*c8dee2aaSAndroid Build Coastguard Worker     }
119*c8dee2aaSAndroid Build Coastguard Worker     if (!ctx->priv().caps()->isFormatCopyable(baseProxy->backendFormat())) {
120*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
121*c8dee2aaSAndroid Build Coastguard Worker     }
122*c8dee2aaSAndroid Build Coastguard Worker     auto copy = GrSurfaceProxy::Copy(ctx,
123*c8dee2aaSAndroid Build Coastguard Worker                                      std::move(baseProxy),
124*c8dee2aaSAndroid Build Coastguard Worker                                      origin,
125*c8dee2aaSAndroid Build Coastguard Worker                                      skgpu::Mipmapped::kYes,
126*c8dee2aaSAndroid Build Coastguard Worker                                      SkBackingFit::kExact,
127*c8dee2aaSAndroid Build Coastguard Worker                                      budgeted,
128*c8dee2aaSAndroid Build Coastguard Worker                                      label);
129*c8dee2aaSAndroid Build Coastguard Worker     if (!copy) {
130*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
131*c8dee2aaSAndroid Build Coastguard Worker     }
132*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(copy->asTextureProxy());
133*c8dee2aaSAndroid Build Coastguard Worker     return copy;
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker 
GrCopyBaseMipMapToView(GrRecordingContext * context,GrSurfaceProxyView src,skgpu::Budgeted budgeted)136*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxyView GrCopyBaseMipMapToView(GrRecordingContext* context,
137*c8dee2aaSAndroid Build Coastguard Worker                                           GrSurfaceProxyView src,
138*c8dee2aaSAndroid Build Coastguard Worker                                           skgpu::Budgeted budgeted) {
139*c8dee2aaSAndroid Build Coastguard Worker     auto origin = src.origin();
140*c8dee2aaSAndroid Build Coastguard Worker     auto swizzle = src.swizzle();
141*c8dee2aaSAndroid Build Coastguard Worker     auto proxy = src.refProxy();
142*c8dee2aaSAndroid Build Coastguard Worker     return {GrCopyBaseMipMapToTextureProxy(
143*c8dee2aaSAndroid Build Coastguard Worker                     context, proxy, origin, /*label=*/"CopyBaseMipMapToView", budgeted),
144*c8dee2aaSAndroid Build Coastguard Worker             origin,
145*c8dee2aaSAndroid Build Coastguard Worker             swizzle};
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker 
adjust_mipmapped(skgpu::Mipmapped mipmapped,const SkBitmap & bitmap,const GrCaps * caps)148*c8dee2aaSAndroid Build Coastguard Worker static skgpu::Mipmapped adjust_mipmapped(skgpu::Mipmapped mipmapped,
149*c8dee2aaSAndroid Build Coastguard Worker                                          const SkBitmap& bitmap,
150*c8dee2aaSAndroid Build Coastguard Worker                                          const GrCaps* caps) {
151*c8dee2aaSAndroid Build Coastguard Worker     if (!caps->mipmapSupport() || bitmap.dimensions().area() <= 1) {
152*c8dee2aaSAndroid Build Coastguard Worker         return skgpu::Mipmapped::kNo;
153*c8dee2aaSAndroid Build Coastguard Worker     }
154*c8dee2aaSAndroid Build Coastguard Worker     return mipmapped;
155*c8dee2aaSAndroid Build Coastguard Worker }
156*c8dee2aaSAndroid Build Coastguard Worker 
choose_bmp_texture_colortype(const GrCaps * caps,const SkBitmap & bitmap)157*c8dee2aaSAndroid Build Coastguard Worker static GrColorType choose_bmp_texture_colortype(const GrCaps* caps, const SkBitmap& bitmap) {
158*c8dee2aaSAndroid Build Coastguard Worker     GrColorType ct = SkColorTypeToGrColorType(bitmap.info().colorType());
159*c8dee2aaSAndroid Build Coastguard Worker     if (caps->getDefaultBackendFormat(ct, GrRenderable::kNo).isValid()) {
160*c8dee2aaSAndroid Build Coastguard Worker         return ct;
161*c8dee2aaSAndroid Build Coastguard Worker     }
162*c8dee2aaSAndroid Build Coastguard Worker     return GrColorType::kRGBA_8888;
163*c8dee2aaSAndroid Build Coastguard Worker }
164*c8dee2aaSAndroid Build Coastguard Worker 
make_bmp_proxy(GrProxyProvider * proxyProvider,const SkBitmap & bitmap,GrColorType ct,skgpu::Mipmapped mipmapped,SkBackingFit fit,skgpu::Budgeted budgeted)165*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<GrTextureProxy> make_bmp_proxy(GrProxyProvider* proxyProvider,
166*c8dee2aaSAndroid Build Coastguard Worker                                             const SkBitmap& bitmap,
167*c8dee2aaSAndroid Build Coastguard Worker                                             GrColorType ct,
168*c8dee2aaSAndroid Build Coastguard Worker                                             skgpu::Mipmapped mipmapped,
169*c8dee2aaSAndroid Build Coastguard Worker                                             SkBackingFit fit,
170*c8dee2aaSAndroid Build Coastguard Worker                                             skgpu::Budgeted budgeted) {
171*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap bmpToUpload;
172*c8dee2aaSAndroid Build Coastguard Worker     if (ct != SkColorTypeToGrColorType(bitmap.info().colorType())) {
173*c8dee2aaSAndroid Build Coastguard Worker         SkColorType skCT = GrColorTypeToSkColorType(ct);
174*c8dee2aaSAndroid Build Coastguard Worker         if (!bmpToUpload.tryAllocPixels(bitmap.info().makeColorType(skCT)) ||
175*c8dee2aaSAndroid Build Coastguard Worker             !bitmap.readPixels(bmpToUpload.pixmap())) {
176*c8dee2aaSAndroid Build Coastguard Worker             return {};
177*c8dee2aaSAndroid Build Coastguard Worker         }
178*c8dee2aaSAndroid Build Coastguard Worker         bmpToUpload.setImmutable();
179*c8dee2aaSAndroid Build Coastguard Worker     } else {
180*c8dee2aaSAndroid Build Coastguard Worker         bmpToUpload = bitmap;
181*c8dee2aaSAndroid Build Coastguard Worker     }
182*c8dee2aaSAndroid Build Coastguard Worker     auto proxy = proxyProvider->createProxyFromBitmap(bmpToUpload, mipmapped, fit, budgeted);
183*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!proxy || mipmapped == skgpu::Mipmapped::kNo ||
184*c8dee2aaSAndroid Build Coastguard Worker              proxy->mipmapped() == skgpu::Mipmapped::kYes);
185*c8dee2aaSAndroid Build Coastguard Worker     return proxy;
186*c8dee2aaSAndroid Build Coastguard Worker }
187*c8dee2aaSAndroid Build Coastguard Worker 
GrMakeCachedBitmapProxyView(GrRecordingContext * rContext,const SkBitmap & bitmap,std::string_view label,skgpu::Mipmapped mipmapped)188*c8dee2aaSAndroid Build Coastguard Worker std::tuple<GrSurfaceProxyView, GrColorType> GrMakeCachedBitmapProxyView(
189*c8dee2aaSAndroid Build Coastguard Worker         GrRecordingContext* rContext,
190*c8dee2aaSAndroid Build Coastguard Worker         const SkBitmap& bitmap,
191*c8dee2aaSAndroid Build Coastguard Worker         std::string_view label,
192*c8dee2aaSAndroid Build Coastguard Worker         skgpu::Mipmapped mipmapped) {
193*c8dee2aaSAndroid Build Coastguard Worker     if (!bitmap.peekPixels(nullptr)) {
194*c8dee2aaSAndroid Build Coastguard Worker         return {};
195*c8dee2aaSAndroid Build Coastguard Worker     }
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker     GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
198*c8dee2aaSAndroid Build Coastguard Worker     const GrCaps* caps = rContext->priv().caps();
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker     skgpu::UniqueKey key;
201*c8dee2aaSAndroid Build Coastguard Worker     SkIPoint origin = bitmap.pixelRefOrigin();
202*c8dee2aaSAndroid Build Coastguard Worker     SkIRect subset = SkIRect::MakePtSize(origin, bitmap.dimensions());
203*c8dee2aaSAndroid Build Coastguard Worker     GrMakeKeyFromImageID(&key, bitmap.pixelRef()->getGenerationID(), subset);
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker     mipmapped = adjust_mipmapped(mipmapped, bitmap, caps);
206*c8dee2aaSAndroid Build Coastguard Worker     GrColorType ct = choose_bmp_texture_colortype(caps, bitmap);
207*c8dee2aaSAndroid Build Coastguard Worker 
208*c8dee2aaSAndroid Build Coastguard Worker     auto installKey = [&](GrTextureProxy* proxy) {
209*c8dee2aaSAndroid Build Coastguard Worker         auto listener = GrMakeUniqueKeyInvalidationListener(&key, proxyProvider->contextID());
210*c8dee2aaSAndroid Build Coastguard Worker         bitmap.pixelRef()->addGenIDChangeListener(std::move(listener));
211*c8dee2aaSAndroid Build Coastguard Worker         proxyProvider->assignUniqueKeyToProxy(key, proxy);
212*c8dee2aaSAndroid Build Coastguard Worker     };
213*c8dee2aaSAndroid Build Coastguard Worker 
214*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrTextureProxy> proxy = proxyProvider->findOrCreateProxyByUniqueKey(key);
215*c8dee2aaSAndroid Build Coastguard Worker     if (!proxy) {
216*c8dee2aaSAndroid Build Coastguard Worker         proxy = make_bmp_proxy(
217*c8dee2aaSAndroid Build Coastguard Worker                 proxyProvider, bitmap, ct, mipmapped, SkBackingFit::kExact, skgpu::Budgeted::kYes);
218*c8dee2aaSAndroid Build Coastguard Worker         if (!proxy) {
219*c8dee2aaSAndroid Build Coastguard Worker             return {};
220*c8dee2aaSAndroid Build Coastguard Worker         }
221*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
222*c8dee2aaSAndroid Build Coastguard Worker                  proxy->mipmapped() == skgpu::Mipmapped::kYes);
223*c8dee2aaSAndroid Build Coastguard Worker         installKey(proxy.get());
224*c8dee2aaSAndroid Build Coastguard Worker     }
225*c8dee2aaSAndroid Build Coastguard Worker 
226*c8dee2aaSAndroid Build Coastguard Worker     skgpu::Swizzle swizzle = caps->getReadSwizzle(proxy->backendFormat(), ct);
227*c8dee2aaSAndroid Build Coastguard Worker     if (mipmapped == skgpu::Mipmapped::kNo || proxy->mipmapped() == skgpu::Mipmapped::kYes) {
228*c8dee2aaSAndroid Build Coastguard Worker         return {{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}, ct};
229*c8dee2aaSAndroid Build Coastguard Worker     }
230*c8dee2aaSAndroid Build Coastguard Worker 
231*c8dee2aaSAndroid Build Coastguard Worker     // We need a mipped proxy, but we found a proxy earlier that wasn't mipped. Thus we generate
232*c8dee2aaSAndroid Build Coastguard Worker     // a new mipped surface and copy the original proxy into the base layer. We will then let
233*c8dee2aaSAndroid Build Coastguard Worker     // the gpu generate the rest of the mips.
234*c8dee2aaSAndroid Build Coastguard Worker     auto mippedProxy = GrCopyBaseMipMapToTextureProxy(
235*c8dee2aaSAndroid Build Coastguard Worker             rContext, proxy, kTopLeft_GrSurfaceOrigin, /*label=*/"MakeCachedBitmapProxyView");
236*c8dee2aaSAndroid Build Coastguard Worker     if (!mippedProxy) {
237*c8dee2aaSAndroid Build Coastguard Worker         // We failed to make a mipped proxy with the base copied into it. This could have
238*c8dee2aaSAndroid Build Coastguard Worker         // been from failure to make the proxy or failure to do the copy. Thus we will fall
239*c8dee2aaSAndroid Build Coastguard Worker         // back to just using the non mipped proxy; See skbug.com/7094.
240*c8dee2aaSAndroid Build Coastguard Worker         return {{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}, ct};
241*c8dee2aaSAndroid Build Coastguard Worker     }
242*c8dee2aaSAndroid Build Coastguard Worker     // In this case we are stealing the key from the original proxy which should only happen
243*c8dee2aaSAndroid Build Coastguard Worker     // when we have just generated mipmaps for an originally unmipped proxy/texture. This
244*c8dee2aaSAndroid Build Coastguard Worker     // means that all future uses of the key will access the mipmapped version. The texture
245*c8dee2aaSAndroid Build Coastguard Worker     // backing the unmipped version will remain in the resource cache until the last texture
246*c8dee2aaSAndroid Build Coastguard Worker     // proxy referencing it is deleted at which time it too will be deleted or recycled.
247*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(proxy->getUniqueKey() == key);
248*c8dee2aaSAndroid Build Coastguard Worker     proxyProvider->removeUniqueKeyFromProxy(proxy.get());
249*c8dee2aaSAndroid Build Coastguard Worker     installKey(mippedProxy->asTextureProxy());
250*c8dee2aaSAndroid Build Coastguard Worker     return {{std::move(mippedProxy), kTopLeft_GrSurfaceOrigin, swizzle}, ct};
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker 
GrMakeUncachedBitmapProxyView(GrRecordingContext * rContext,const SkBitmap & bitmap,skgpu::Mipmapped mipmapped,SkBackingFit fit,skgpu::Budgeted budgeted)253*c8dee2aaSAndroid Build Coastguard Worker std::tuple<GrSurfaceProxyView, GrColorType> GrMakeUncachedBitmapProxyView(
254*c8dee2aaSAndroid Build Coastguard Worker         GrRecordingContext* rContext,
255*c8dee2aaSAndroid Build Coastguard Worker         const SkBitmap& bitmap,
256*c8dee2aaSAndroid Build Coastguard Worker         skgpu::Mipmapped mipmapped,
257*c8dee2aaSAndroid Build Coastguard Worker         SkBackingFit fit,
258*c8dee2aaSAndroid Build Coastguard Worker         skgpu::Budgeted budgeted) {
259*c8dee2aaSAndroid Build Coastguard Worker     GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
260*c8dee2aaSAndroid Build Coastguard Worker     const GrCaps* caps = rContext->priv().caps();
261*c8dee2aaSAndroid Build Coastguard Worker 
262*c8dee2aaSAndroid Build Coastguard Worker     mipmapped = adjust_mipmapped(mipmapped, bitmap, caps);
263*c8dee2aaSAndroid Build Coastguard Worker     GrColorType ct = choose_bmp_texture_colortype(caps, bitmap);
264*c8dee2aaSAndroid Build Coastguard Worker 
265*c8dee2aaSAndroid Build Coastguard Worker     if (auto proxy = make_bmp_proxy(proxyProvider, bitmap, ct, mipmapped, fit, budgeted)) {
266*c8dee2aaSAndroid Build Coastguard Worker         skgpu::Swizzle swizzle = caps->getReadSwizzle(proxy->backendFormat(), ct);
267*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
268*c8dee2aaSAndroid Build Coastguard Worker                  proxy->mipmapped() == skgpu::Mipmapped::kYes);
269*c8dee2aaSAndroid Build Coastguard Worker         return {{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}, ct};
270*c8dee2aaSAndroid Build Coastguard Worker     }
271*c8dee2aaSAndroid Build Coastguard Worker     return {};
272*c8dee2aaSAndroid Build Coastguard Worker }
273*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
274*c8dee2aaSAndroid Build Coastguard Worker 
SkColorToPMColor4f(SkColor c,const GrColorInfo & colorInfo)275*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f SkColorToPMColor4f(SkColor c, const GrColorInfo& colorInfo) {
276*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f color = SkColor4f::FromColor(c);
277*c8dee2aaSAndroid Build Coastguard Worker     if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) {
278*c8dee2aaSAndroid Build Coastguard Worker         color = xform->apply(color);
279*c8dee2aaSAndroid Build Coastguard Worker     }
280*c8dee2aaSAndroid Build Coastguard Worker     return color.premul();
281*c8dee2aaSAndroid Build Coastguard Worker }
282*c8dee2aaSAndroid Build Coastguard Worker 
SkColor4fPrepForDst(SkColor4f color,const GrColorInfo & colorInfo)283*c8dee2aaSAndroid Build Coastguard Worker SkColor4f SkColor4fPrepForDst(SkColor4f color, const GrColorInfo& colorInfo) {
284*c8dee2aaSAndroid Build Coastguard Worker     if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) {
285*c8dee2aaSAndroid Build Coastguard Worker         color = xform->apply(color);
286*c8dee2aaSAndroid Build Coastguard Worker     }
287*c8dee2aaSAndroid Build Coastguard Worker     return color;
288*c8dee2aaSAndroid Build Coastguard Worker }
289*c8dee2aaSAndroid Build Coastguard Worker 
290*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
291*c8dee2aaSAndroid Build Coastguard Worker 
blender_requires_shader(const SkBlender * blender)292*c8dee2aaSAndroid Build Coastguard Worker static inline bool blender_requires_shader(const SkBlender* blender) {
293*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(blender);
294*c8dee2aaSAndroid Build Coastguard Worker     std::optional<SkBlendMode> mode = as_BB(blender)->asBlendMode();
295*c8dee2aaSAndroid Build Coastguard Worker     return !mode.has_value() || *mode != SkBlendMode::kDst;
296*c8dee2aaSAndroid Build Coastguard Worker }
297*c8dee2aaSAndroid Build Coastguard Worker 
298*c8dee2aaSAndroid Build Coastguard Worker 
299*c8dee2aaSAndroid Build Coastguard Worker #ifndef SK_IGNORE_GPU_DITHER
make_dither_effect(GrRecordingContext * rContext,std::unique_ptr<GrFragmentProcessor> inputFP,float range,const GrCaps * caps)300*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrFragmentProcessor> make_dither_effect(
301*c8dee2aaSAndroid Build Coastguard Worker         GrRecordingContext* rContext,
302*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<GrFragmentProcessor> inputFP,
303*c8dee2aaSAndroid Build Coastguard Worker         float range,
304*c8dee2aaSAndroid Build Coastguard Worker         const GrCaps* caps) {
305*c8dee2aaSAndroid Build Coastguard Worker     if (range == 0 || inputFP == nullptr) {
306*c8dee2aaSAndroid Build Coastguard Worker         return inputFP;
307*c8dee2aaSAndroid Build Coastguard Worker     }
308*c8dee2aaSAndroid Build Coastguard Worker 
309*c8dee2aaSAndroid Build Coastguard Worker     if (caps->avoidDithering()) {
310*c8dee2aaSAndroid Build Coastguard Worker         return inputFP;
311*c8dee2aaSAndroid Build Coastguard Worker     }
312*c8dee2aaSAndroid Build Coastguard Worker 
313*c8dee2aaSAndroid Build Coastguard Worker     // We used to use integer math on sk_FragCoord, when supported, and a fallback using floating
314*c8dee2aaSAndroid Build Coastguard Worker     // point (on a 4x4 rather than 8x8 grid). Now we precompute a 8x8 table in a texture because
315*c8dee2aaSAndroid Build Coastguard Worker     // it was shown to be significantly faster on several devices. Test was done with the following
316*c8dee2aaSAndroid Build Coastguard Worker     // running in viewer with the stats layer enabled and looking at total frame time:
317*c8dee2aaSAndroid Build Coastguard Worker     //      SkRandom r;
318*c8dee2aaSAndroid Build Coastguard Worker     //      for (int i = 0; i < N; ++i) {
319*c8dee2aaSAndroid Build Coastguard Worker     //          SkColor c[2] = {r.nextU(), r.nextU()};
320*c8dee2aaSAndroid Build Coastguard Worker     //          SkPoint pts[2] = {{r.nextRangeScalar(0, 500), r.nextRangeScalar(0, 500)},
321*c8dee2aaSAndroid Build Coastguard Worker     //                            {r.nextRangeScalar(0, 500), r.nextRangeScalar(0, 500)}};
322*c8dee2aaSAndroid Build Coastguard Worker     //          SkPaint p;
323*c8dee2aaSAndroid Build Coastguard Worker     //          p.setDither(true);
324*c8dee2aaSAndroid Build Coastguard Worker     //          p.setShader(SkGradientShader::MakeLinear(pts, c, nullptr, 2, SkTileMode::kRepeat));
325*c8dee2aaSAndroid Build Coastguard Worker     //          canvas->drawPaint(p);
326*c8dee2aaSAndroid Build Coastguard Worker     //      }
327*c8dee2aaSAndroid Build Coastguard Worker     // Device            GPU             N      no dither    int math dither   table dither
328*c8dee2aaSAndroid Build Coastguard Worker     // Linux desktop     QuadroP1000     5000   304ms        400ms (1.31x)     383ms (1.26x)
329*c8dee2aaSAndroid Build Coastguard Worker     // TecnoSpark3Pro    PowerVRGE8320   200    299ms        820ms (2.74x)     592ms (1.98x)
330*c8dee2aaSAndroid Build Coastguard Worker     // Pixel 4           Adreno640       500    110ms        221ms (2.01x)     214ms (1.95x)
331*c8dee2aaSAndroid Build Coastguard Worker     // Galaxy S20 FE     Mali-G77 MP11   600    165ms        360ms (2.18x)     260ms (1.58x)
332*c8dee2aaSAndroid Build Coastguard Worker     static const SkBitmap gLUT = skgpu::MakeDitherLUT();
333*c8dee2aaSAndroid Build Coastguard Worker     auto [tex, ct] = GrMakeCachedBitmapProxyView(
334*c8dee2aaSAndroid Build Coastguard Worker             rContext, gLUT, /*label=*/"MakeDitherEffect", skgpu::Mipmapped::kNo);
335*c8dee2aaSAndroid Build Coastguard Worker     if (!tex) {
336*c8dee2aaSAndroid Build Coastguard Worker         return inputFP;
337*c8dee2aaSAndroid Build Coastguard Worker     }
338*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(ct == GrColorType::kAlpha_8);
339*c8dee2aaSAndroid Build Coastguard Worker     GrSamplerState sampler(GrSamplerState::WrapMode::kRepeat, SkFilterMode::kNearest);
340*c8dee2aaSAndroid Build Coastguard Worker     auto te = GrTextureEffect::Make(
341*c8dee2aaSAndroid Build Coastguard Worker             std::move(tex), kPremul_SkAlphaType, SkMatrix::I(), sampler, *caps);
342*c8dee2aaSAndroid Build Coastguard Worker     static const SkRuntimeEffect* effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
343*c8dee2aaSAndroid Build Coastguard Worker         "uniform half range;"
344*c8dee2aaSAndroid Build Coastguard Worker         "uniform shader inputFP;"
345*c8dee2aaSAndroid Build Coastguard Worker         "uniform shader table;"
346*c8dee2aaSAndroid Build Coastguard Worker         "half4 main(float2 xy) {"
347*c8dee2aaSAndroid Build Coastguard Worker             "half4 color = inputFP.eval(xy);"
348*c8dee2aaSAndroid Build Coastguard Worker             "half value = table.eval(sk_FragCoord.xy).a - 0.5;" // undo the bias in the table
349*c8dee2aaSAndroid Build Coastguard Worker             // For each color channel, add the random offset to the channel value and then clamp
350*c8dee2aaSAndroid Build Coastguard Worker             // between 0 and alpha to keep the color premultiplied.
351*c8dee2aaSAndroid Build Coastguard Worker             "return half4(clamp(color.rgb + value * range, 0.0, color.a), color.a);"
352*c8dee2aaSAndroid Build Coastguard Worker         "}"
353*c8dee2aaSAndroid Build Coastguard Worker     );
354*c8dee2aaSAndroid Build Coastguard Worker     return GrSkSLFP::Make(effect, "Dither", /*inputFP=*/nullptr,
355*c8dee2aaSAndroid Build Coastguard Worker                           GrSkSLFP::OptFlags::kPreservesOpaqueInput,
356*c8dee2aaSAndroid Build Coastguard Worker                           "range", range,
357*c8dee2aaSAndroid Build Coastguard Worker                           "inputFP", std::move(inputFP),
358*c8dee2aaSAndroid Build Coastguard Worker                           "table", GrSkSLFP::IgnoreOptFlags(std::move(te)));
359*c8dee2aaSAndroid Build Coastguard Worker }
360*c8dee2aaSAndroid Build Coastguard Worker #endif
361*c8dee2aaSAndroid Build Coastguard Worker 
skpaint_to_grpaint_impl(GrRecordingContext * context,const GrColorInfo & dstColorInfo,const SkPaint & skPaint,const SkMatrix & ctm,std::optional<std::unique_ptr<GrFragmentProcessor>> shaderFP,SkBlender * primColorBlender,const SkSurfaceProps & surfaceProps,GrPaint * grPaint)362*c8dee2aaSAndroid Build Coastguard Worker static inline bool skpaint_to_grpaint_impl(
363*c8dee2aaSAndroid Build Coastguard Worker         GrRecordingContext* context,
364*c8dee2aaSAndroid Build Coastguard Worker         const GrColorInfo& dstColorInfo,
365*c8dee2aaSAndroid Build Coastguard Worker         const SkPaint& skPaint,
366*c8dee2aaSAndroid Build Coastguard Worker         const SkMatrix& ctm,
367*c8dee2aaSAndroid Build Coastguard Worker         std::optional<std::unique_ptr<GrFragmentProcessor>> shaderFP,
368*c8dee2aaSAndroid Build Coastguard Worker         SkBlender* primColorBlender,
369*c8dee2aaSAndroid Build Coastguard Worker         const SkSurfaceProps& surfaceProps,
370*c8dee2aaSAndroid Build Coastguard Worker         GrPaint* grPaint) {
371*c8dee2aaSAndroid Build Coastguard Worker     // Convert SkPaint color to 4f format in the destination color space
372*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f origColor = SkColor4fPrepForDst(skPaint.getColor4f(), dstColorInfo);
373*c8dee2aaSAndroid Build Coastguard Worker 
374*c8dee2aaSAndroid Build Coastguard Worker     GrFPArgs fpArgs(context, &dstColorInfo, surfaceProps, GrFPArgs::Scope::kDefault);
375*c8dee2aaSAndroid Build Coastguard Worker 
376*c8dee2aaSAndroid Build Coastguard Worker     // Setup the initial color considering the shader, the SkPaint color, and the presence or not
377*c8dee2aaSAndroid Build Coastguard Worker     // of per-vertex colors.
378*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<GrFragmentProcessor> paintFP;
379*c8dee2aaSAndroid Build Coastguard Worker     const bool gpProvidesShader = shaderFP.has_value() && !*shaderFP;
380*c8dee2aaSAndroid Build Coastguard Worker     if (!primColorBlender || blender_requires_shader(primColorBlender)) {
381*c8dee2aaSAndroid Build Coastguard Worker         if (shaderFP.has_value()) {
382*c8dee2aaSAndroid Build Coastguard Worker             paintFP = std::move(*shaderFP);
383*c8dee2aaSAndroid Build Coastguard Worker         } else {
384*c8dee2aaSAndroid Build Coastguard Worker             if (const SkShaderBase* shader = as_SB(skPaint.getShader())) {
385*c8dee2aaSAndroid Build Coastguard Worker                 paintFP = GrFragmentProcessors::Make(shader, fpArgs, ctm);
386*c8dee2aaSAndroid Build Coastguard Worker                 if (paintFP == nullptr) {
387*c8dee2aaSAndroid Build Coastguard Worker                     return false;
388*c8dee2aaSAndroid Build Coastguard Worker                 }
389*c8dee2aaSAndroid Build Coastguard Worker             }
390*c8dee2aaSAndroid Build Coastguard Worker         }
391*c8dee2aaSAndroid Build Coastguard Worker     }
392*c8dee2aaSAndroid Build Coastguard Worker 
393*c8dee2aaSAndroid Build Coastguard Worker     // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is
394*c8dee2aaSAndroid Build Coastguard Worker     // a known constant value. In that case we can simply apply a color filter during this
395*c8dee2aaSAndroid Build Coastguard Worker     // conversion without converting the color filter to a GrFragmentProcessor.
396*c8dee2aaSAndroid Build Coastguard Worker     bool applyColorFilterToPaintColor = false;
397*c8dee2aaSAndroid Build Coastguard Worker     if (paintFP) {
398*c8dee2aaSAndroid Build Coastguard Worker         if (primColorBlender) {
399*c8dee2aaSAndroid Build Coastguard Worker             // There is a blend between the primitive color and the shader color. The shader sees
400*c8dee2aaSAndroid Build Coastguard Worker             // the opaque paint color. The shader's output is blended using the provided mode by
401*c8dee2aaSAndroid Build Coastguard Worker             // the primitive color. The blended color is then modulated by the paint's alpha.
402*c8dee2aaSAndroid Build Coastguard Worker 
403*c8dee2aaSAndroid Build Coastguard Worker             // The geometry processor will insert the primitive color to start the color chain, so
404*c8dee2aaSAndroid Build Coastguard Worker             // the GrPaint color will be ignored.
405*c8dee2aaSAndroid Build Coastguard Worker 
406*c8dee2aaSAndroid Build Coastguard Worker             SkPMColor4f shaderInput = origColor.makeOpaque().premul();
407*c8dee2aaSAndroid Build Coastguard Worker             paintFP = GrFragmentProcessor::OverrideInput(std::move(paintFP), shaderInput);
408*c8dee2aaSAndroid Build Coastguard Worker             paintFP = GrFragmentProcessors::Make(as_BB(primColorBlender),
409*c8dee2aaSAndroid Build Coastguard Worker                                                  /*srcFP=*/std::move(paintFP),
410*c8dee2aaSAndroid Build Coastguard Worker                                                  /*dstFP=*/nullptr,
411*c8dee2aaSAndroid Build Coastguard Worker                                                  fpArgs);
412*c8dee2aaSAndroid Build Coastguard Worker             if (!paintFP) {
413*c8dee2aaSAndroid Build Coastguard Worker                 return false;
414*c8dee2aaSAndroid Build Coastguard Worker             }
415*c8dee2aaSAndroid Build Coastguard Worker 
416*c8dee2aaSAndroid Build Coastguard Worker             // We can ignore origColor here - alpha is unchanged by gamma
417*c8dee2aaSAndroid Build Coastguard Worker             float paintAlpha = skPaint.getColor4f().fA;
418*c8dee2aaSAndroid Build Coastguard Worker             if (1.0f != paintAlpha) {
419*c8dee2aaSAndroid Build Coastguard Worker                 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
420*c8dee2aaSAndroid Build Coastguard Worker                 // color channels. It's value should be treated as the same in ANY color space.
421*c8dee2aaSAndroid Build Coastguard Worker                 paintFP = GrFragmentProcessor::ModulateRGBA(
422*c8dee2aaSAndroid Build Coastguard Worker                         std::move(paintFP), {paintAlpha, paintAlpha, paintAlpha, paintAlpha});
423*c8dee2aaSAndroid Build Coastguard Worker             }
424*c8dee2aaSAndroid Build Coastguard Worker         } else {
425*c8dee2aaSAndroid Build Coastguard Worker             float paintAlpha = skPaint.getColor4f().fA;
426*c8dee2aaSAndroid Build Coastguard Worker             if (paintAlpha != 1.0f) {
427*c8dee2aaSAndroid Build Coastguard Worker                 // This invokes the shader's FP tree with an opaque version of the paint color,
428*c8dee2aaSAndroid Build Coastguard Worker                 // then multiplies the final result by the incoming (paint) alpha.
429*c8dee2aaSAndroid Build Coastguard Worker                 // We're actually putting the *unpremul* paint color on the GrPaint. This is okay,
430*c8dee2aaSAndroid Build Coastguard Worker                 // because the shader is supposed to see the original (opaque) RGB from the paint.
431*c8dee2aaSAndroid Build Coastguard Worker                 // ApplyPaintAlpha then creates a valid premul color by applying the paint alpha.
432*c8dee2aaSAndroid Build Coastguard Worker                 // Think of this as equivalent to (but faster than) putting origColor.premul() on
433*c8dee2aaSAndroid Build Coastguard Worker                 // the GrPaint, and ApplyPaintAlpha unpremuling it before passing it to the child.
434*c8dee2aaSAndroid Build Coastguard Worker                 paintFP = GrFragmentProcessor::ApplyPaintAlpha(std::move(paintFP));
435*c8dee2aaSAndroid Build Coastguard Worker                 grPaint->setColor4f({origColor.fR, origColor.fG, origColor.fB, origColor.fA});
436*c8dee2aaSAndroid Build Coastguard Worker             } else {
437*c8dee2aaSAndroid Build Coastguard Worker                 // paintFP will ignore its input color, so we must disable coverage-as-alpha.
438*c8dee2aaSAndroid Build Coastguard Worker                 // TODO(skbug:11942): The alternative would be to always use ApplyPaintAlpha, but
439*c8dee2aaSAndroid Build Coastguard Worker                 // we'd need to measure the cost of that shader math against the CAA benefit.
440*c8dee2aaSAndroid Build Coastguard Worker                 paintFP = GrFragmentProcessor::DisableCoverageAsAlpha(std::move(paintFP));
441*c8dee2aaSAndroid Build Coastguard Worker                 grPaint->setColor4f(origColor.premul());
442*c8dee2aaSAndroid Build Coastguard Worker             }
443*c8dee2aaSAndroid Build Coastguard Worker         }
444*c8dee2aaSAndroid Build Coastguard Worker     } else {
445*c8dee2aaSAndroid Build Coastguard Worker         if (primColorBlender) {
446*c8dee2aaSAndroid Build Coastguard Worker             // The primitive itself has color (e.g. interpolated vertex color) and this is what
447*c8dee2aaSAndroid Build Coastguard Worker             // the GP will output. Thus, we must get the paint color in separately below as a color
448*c8dee2aaSAndroid Build Coastguard Worker             // FP. This could be made more efficient if the relevant GPs used GrPaint color and
449*c8dee2aaSAndroid Build Coastguard Worker             // took the SkBlender to apply with primitive color. As it stands changing the SkPaint
450*c8dee2aaSAndroid Build Coastguard Worker             // color will break batches.
451*c8dee2aaSAndroid Build Coastguard Worker             grPaint->setColor4f(SK_PMColor4fWHITE);  // won't be used.
452*c8dee2aaSAndroid Build Coastguard Worker             if (blender_requires_shader(primColorBlender)) {
453*c8dee2aaSAndroid Build Coastguard Worker                 paintFP = GrFragmentProcessor::MakeColor(origColor.makeOpaque().premul());
454*c8dee2aaSAndroid Build Coastguard Worker                 paintFP = GrFragmentProcessors::Make(as_BB(primColorBlender),
455*c8dee2aaSAndroid Build Coastguard Worker                                                      /*srcFP=*/std::move(paintFP),
456*c8dee2aaSAndroid Build Coastguard Worker                                                      /*dstFP=*/nullptr,
457*c8dee2aaSAndroid Build Coastguard Worker                                                      fpArgs);
458*c8dee2aaSAndroid Build Coastguard Worker                 if (!paintFP) {
459*c8dee2aaSAndroid Build Coastguard Worker                     return false;
460*c8dee2aaSAndroid Build Coastguard Worker                 }
461*c8dee2aaSAndroid Build Coastguard Worker             }
462*c8dee2aaSAndroid Build Coastguard Worker 
463*c8dee2aaSAndroid Build Coastguard Worker             // The paint's *alpha* is applied after the paint/primitive color blend:
464*c8dee2aaSAndroid Build Coastguard Worker             // We can ignore origColor here - alpha is unchanged by gamma
465*c8dee2aaSAndroid Build Coastguard Worker             float paintAlpha = skPaint.getColor4f().fA;
466*c8dee2aaSAndroid Build Coastguard Worker             if (paintAlpha != 1.0f) {
467*c8dee2aaSAndroid Build Coastguard Worker                 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
468*c8dee2aaSAndroid Build Coastguard Worker                 // color channels. It's value should be treated as the same in ANY color space.
469*c8dee2aaSAndroid Build Coastguard Worker                 paintFP = GrFragmentProcessor::ModulateRGBA(
470*c8dee2aaSAndroid Build Coastguard Worker                         std::move(paintFP), {paintAlpha, paintAlpha, paintAlpha, paintAlpha});
471*c8dee2aaSAndroid Build Coastguard Worker             }
472*c8dee2aaSAndroid Build Coastguard Worker         } else {
473*c8dee2aaSAndroid Build Coastguard Worker             // No shader, no primitive color.
474*c8dee2aaSAndroid Build Coastguard Worker             grPaint->setColor4f(origColor.premul());
475*c8dee2aaSAndroid Build Coastguard Worker             // We can do this if there isn't a GP that is acting as the shader.
476*c8dee2aaSAndroid Build Coastguard Worker             applyColorFilterToPaintColor = !gpProvidesShader;
477*c8dee2aaSAndroid Build Coastguard Worker         }
478*c8dee2aaSAndroid Build Coastguard Worker     }
479*c8dee2aaSAndroid Build Coastguard Worker 
480*c8dee2aaSAndroid Build Coastguard Worker     SkColorFilter* colorFilter = skPaint.getColorFilter();
481*c8dee2aaSAndroid Build Coastguard Worker     if (colorFilter) {
482*c8dee2aaSAndroid Build Coastguard Worker         if (applyColorFilterToPaintColor) {
483*c8dee2aaSAndroid Build Coastguard Worker             SkColorSpace* dstCS = dstColorInfo.colorSpace();
484*c8dee2aaSAndroid Build Coastguard Worker             grPaint->setColor4f(colorFilter->filterColor4f(origColor, dstCS, dstCS).premul());
485*c8dee2aaSAndroid Build Coastguard Worker         } else {
486*c8dee2aaSAndroid Build Coastguard Worker             auto [success, fp] = GrFragmentProcessors::Make(
487*c8dee2aaSAndroid Build Coastguard Worker                     context, colorFilter, std::move(paintFP), dstColorInfo, surfaceProps);
488*c8dee2aaSAndroid Build Coastguard Worker             if (!success) {
489*c8dee2aaSAndroid Build Coastguard Worker                 return false;
490*c8dee2aaSAndroid Build Coastguard Worker             }
491*c8dee2aaSAndroid Build Coastguard Worker             paintFP = std::move(fp);
492*c8dee2aaSAndroid Build Coastguard Worker         }
493*c8dee2aaSAndroid Build Coastguard Worker     }
494*c8dee2aaSAndroid Build Coastguard Worker 
495*c8dee2aaSAndroid Build Coastguard Worker     if (auto maskFilter = skPaint.getMaskFilter()) {
496*c8dee2aaSAndroid Build Coastguard Worker         if (auto mfFP = GrFragmentProcessors::Make(maskFilter, fpArgs, ctm)) {
497*c8dee2aaSAndroid Build Coastguard Worker             grPaint->setCoverageFragmentProcessor(std::move(mfFP));
498*c8dee2aaSAndroid Build Coastguard Worker         }
499*c8dee2aaSAndroid Build Coastguard Worker     }
500*c8dee2aaSAndroid Build Coastguard Worker 
501*c8dee2aaSAndroid Build Coastguard Worker #ifndef SK_IGNORE_GPU_DITHER
502*c8dee2aaSAndroid Build Coastguard Worker     SkColorType ct = GrColorTypeToSkColorType(dstColorInfo.colorType());
503*c8dee2aaSAndroid Build Coastguard Worker     if (paintFP != nullptr && (
504*c8dee2aaSAndroid Build Coastguard Worker             surfaceProps.isAlwaysDither() || SkPaintPriv::ShouldDither(skPaint, ct))) {
505*c8dee2aaSAndroid Build Coastguard Worker         float ditherRange = skgpu::DitherRangeForConfig(ct);
506*c8dee2aaSAndroid Build Coastguard Worker         paintFP = make_dither_effect(
507*c8dee2aaSAndroid Build Coastguard Worker                 context, std::move(paintFP), ditherRange, context->priv().caps());
508*c8dee2aaSAndroid Build Coastguard Worker     }
509*c8dee2aaSAndroid Build Coastguard Worker #endif
510*c8dee2aaSAndroid Build Coastguard Worker 
511*c8dee2aaSAndroid Build Coastguard Worker     // Note that for the final blend onto the canvas, we should prefer to use the GrXferProcessor
512*c8dee2aaSAndroid Build Coastguard Worker     // instead of a SkBlendModeBlender to perform the blend. The Xfer processor is able to perform
513*c8dee2aaSAndroid Build Coastguard Worker     // coefficient-based blends directly, without readback. This will be much more efficient.
514*c8dee2aaSAndroid Build Coastguard Worker     if (auto bm = skPaint.asBlendMode()) {
515*c8dee2aaSAndroid Build Coastguard Worker         // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field
516*c8dee2aaSAndroid Build Coastguard Worker         // on the GrPaint to also be null (also kSrcOver).
517*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!grPaint->getXPFactory());
518*c8dee2aaSAndroid Build Coastguard Worker         if (bm.value() != SkBlendMode::kSrcOver) {
519*c8dee2aaSAndroid Build Coastguard Worker             grPaint->setXPFactory(GrXPFactory::FromBlendMode(bm.value()));
520*c8dee2aaSAndroid Build Coastguard Worker         }
521*c8dee2aaSAndroid Build Coastguard Worker     } else {
522*c8dee2aaSAndroid Build Coastguard Worker         // Apply a custom blend against the surface color, and force the XP to kSrc so that the
523*c8dee2aaSAndroid Build Coastguard Worker         // computed result is applied directly to the canvas while still honoring the alpha.
524*c8dee2aaSAndroid Build Coastguard Worker         paintFP = GrFragmentProcessors::Make(as_BB(skPaint.getBlender()),
525*c8dee2aaSAndroid Build Coastguard Worker                                              std::move(paintFP),
526*c8dee2aaSAndroid Build Coastguard Worker                                              GrFragmentProcessor::SurfaceColor(),
527*c8dee2aaSAndroid Build Coastguard Worker                                              fpArgs);
528*c8dee2aaSAndroid Build Coastguard Worker         if (!paintFP) {
529*c8dee2aaSAndroid Build Coastguard Worker             return false;
530*c8dee2aaSAndroid Build Coastguard Worker         }
531*c8dee2aaSAndroid Build Coastguard Worker         grPaint->setXPFactory(GrXPFactory::FromBlendMode(SkBlendMode::kSrc));
532*c8dee2aaSAndroid Build Coastguard Worker     }
533*c8dee2aaSAndroid Build Coastguard Worker 
534*c8dee2aaSAndroid Build Coastguard Worker     if (GrColorTypeClampType(dstColorInfo.colorType()) == GrClampType::kManual) {
535*c8dee2aaSAndroid Build Coastguard Worker         if (paintFP != nullptr) {
536*c8dee2aaSAndroid Build Coastguard Worker             paintFP = GrFragmentProcessor::ClampOutput(std::move(paintFP));
537*c8dee2aaSAndroid Build Coastguard Worker         } else {
538*c8dee2aaSAndroid Build Coastguard Worker             auto color = grPaint->getColor4f();
539*c8dee2aaSAndroid Build Coastguard Worker             grPaint->setColor4f({SkTPin(color.fR, 0.f, 1.f),
540*c8dee2aaSAndroid Build Coastguard Worker                                  SkTPin(color.fG, 0.f, 1.f),
541*c8dee2aaSAndroid Build Coastguard Worker                                  SkTPin(color.fB, 0.f, 1.f),
542*c8dee2aaSAndroid Build Coastguard Worker                                  SkTPin(color.fA, 0.f, 1.f)});
543*c8dee2aaSAndroid Build Coastguard Worker         }
544*c8dee2aaSAndroid Build Coastguard Worker     }
545*c8dee2aaSAndroid Build Coastguard Worker 
546*c8dee2aaSAndroid Build Coastguard Worker     if (paintFP) {
547*c8dee2aaSAndroid Build Coastguard Worker         grPaint->setColorFragmentProcessor(std::move(paintFP));
548*c8dee2aaSAndroid Build Coastguard Worker     }
549*c8dee2aaSAndroid Build Coastguard Worker 
550*c8dee2aaSAndroid Build Coastguard Worker     return true;
551*c8dee2aaSAndroid Build Coastguard Worker }
552*c8dee2aaSAndroid Build Coastguard Worker 
SkPaintToGrPaint(GrRecordingContext * context,const GrColorInfo & dstColorInfo,const SkPaint & skPaint,const SkMatrix & ctm,const SkSurfaceProps & surfaceProps,GrPaint * grPaint)553*c8dee2aaSAndroid Build Coastguard Worker bool SkPaintToGrPaint(GrRecordingContext* context,
554*c8dee2aaSAndroid Build Coastguard Worker                       const GrColorInfo& dstColorInfo,
555*c8dee2aaSAndroid Build Coastguard Worker                       const SkPaint& skPaint,
556*c8dee2aaSAndroid Build Coastguard Worker                       const SkMatrix& ctm,
557*c8dee2aaSAndroid Build Coastguard Worker                       const SkSurfaceProps& surfaceProps,
558*c8dee2aaSAndroid Build Coastguard Worker                       GrPaint* grPaint) {
559*c8dee2aaSAndroid Build Coastguard Worker     return skpaint_to_grpaint_impl(context,
560*c8dee2aaSAndroid Build Coastguard Worker                                    dstColorInfo,
561*c8dee2aaSAndroid Build Coastguard Worker                                    skPaint,
562*c8dee2aaSAndroid Build Coastguard Worker                                    ctm,
563*c8dee2aaSAndroid Build Coastguard Worker                                    /*shaderFP=*/std::nullopt,
564*c8dee2aaSAndroid Build Coastguard Worker                                    /*primColorBlender=*/nullptr,
565*c8dee2aaSAndroid Build Coastguard Worker                                    surfaceProps,
566*c8dee2aaSAndroid Build Coastguard Worker                                    grPaint);
567*c8dee2aaSAndroid Build Coastguard Worker }
568*c8dee2aaSAndroid Build Coastguard Worker 
569*c8dee2aaSAndroid Build Coastguard Worker /** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */
SkPaintToGrPaintReplaceShader(GrRecordingContext * context,const GrColorInfo & dstColorInfo,const SkPaint & skPaint,const SkMatrix & ctm,std::unique_ptr<GrFragmentProcessor> shaderFP,const SkSurfaceProps & surfaceProps,GrPaint * grPaint)570*c8dee2aaSAndroid Build Coastguard Worker bool SkPaintToGrPaintReplaceShader(GrRecordingContext* context,
571*c8dee2aaSAndroid Build Coastguard Worker                                    const GrColorInfo& dstColorInfo,
572*c8dee2aaSAndroid Build Coastguard Worker                                    const SkPaint& skPaint,
573*c8dee2aaSAndroid Build Coastguard Worker                                    const SkMatrix& ctm,
574*c8dee2aaSAndroid Build Coastguard Worker                                    std::unique_ptr<GrFragmentProcessor> shaderFP,
575*c8dee2aaSAndroid Build Coastguard Worker                                    const SkSurfaceProps& surfaceProps,
576*c8dee2aaSAndroid Build Coastguard Worker                                    GrPaint* grPaint) {
577*c8dee2aaSAndroid Build Coastguard Worker     return skpaint_to_grpaint_impl(context,
578*c8dee2aaSAndroid Build Coastguard Worker                                    dstColorInfo,
579*c8dee2aaSAndroid Build Coastguard Worker                                    skPaint,
580*c8dee2aaSAndroid Build Coastguard Worker                                    ctm,
581*c8dee2aaSAndroid Build Coastguard Worker                                    std::move(shaderFP),
582*c8dee2aaSAndroid Build Coastguard Worker                                    /*primColorBlender=*/nullptr,
583*c8dee2aaSAndroid Build Coastguard Worker                                    surfaceProps,
584*c8dee2aaSAndroid Build Coastguard Worker                                    grPaint);
585*c8dee2aaSAndroid Build Coastguard Worker }
586*c8dee2aaSAndroid Build Coastguard Worker 
587*c8dee2aaSAndroid Build Coastguard Worker /** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must
588*c8dee2aaSAndroid Build Coastguard Worker     be setup as a vertex attribute using the specified SkBlender. */
SkPaintToGrPaintWithBlend(GrRecordingContext * context,const GrColorInfo & dstColorInfo,const SkPaint & skPaint,const SkMatrix & ctm,SkBlender * primColorBlender,const SkSurfaceProps & surfaceProps,GrPaint * grPaint)589*c8dee2aaSAndroid Build Coastguard Worker bool SkPaintToGrPaintWithBlend(GrRecordingContext* context,
590*c8dee2aaSAndroid Build Coastguard Worker                                const GrColorInfo& dstColorInfo,
591*c8dee2aaSAndroid Build Coastguard Worker                                const SkPaint& skPaint,
592*c8dee2aaSAndroid Build Coastguard Worker                                const SkMatrix& ctm,
593*c8dee2aaSAndroid Build Coastguard Worker                                SkBlender* primColorBlender,
594*c8dee2aaSAndroid Build Coastguard Worker                                const SkSurfaceProps& surfaceProps,
595*c8dee2aaSAndroid Build Coastguard Worker                                GrPaint* grPaint) {
596*c8dee2aaSAndroid Build Coastguard Worker     return skpaint_to_grpaint_impl(context,
597*c8dee2aaSAndroid Build Coastguard Worker                                    dstColorInfo,
598*c8dee2aaSAndroid Build Coastguard Worker                                    skPaint,
599*c8dee2aaSAndroid Build Coastguard Worker                                    ctm,
600*c8dee2aaSAndroid Build Coastguard Worker                                    /*shaderFP=*/std::nullopt,
601*c8dee2aaSAndroid Build Coastguard Worker                                    primColorBlender,
602*c8dee2aaSAndroid Build Coastguard Worker                                    surfaceProps,
603*c8dee2aaSAndroid Build Coastguard Worker                                    grPaint);
604*c8dee2aaSAndroid Build Coastguard Worker }
605