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