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