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 "SkGr.h"
9 #include "GrBitmapTextureMaker.h"
10 #include "GrCaps.h"
11 #include "GrColorSpaceXform.h"
12 #include "GrContext.h"
13 #include "GrContextPriv.h"
14 #include "GrGpuResourcePriv.h"
15 #include "GrPaint.h"
16 #include "GrProxyProvider.h"
17 #include "GrTextureProxy.h"
18 #include "GrTypes.h"
19 #include "GrXferProcessor.h"
20 #include "SkAutoMalloc.h"
21 #include "SkBlendModePriv.h"
22 #include "SkCanvas.h"
23 #include "SkColorFilter.h"
24 #include "SkConvertPixels.h"
25 #include "SkData.h"
26 #include "SkImage_Base.h"
27 #include "SkImageInfoPriv.h"
28 #include "SkImagePriv.h"
29 #include "SkMaskFilterBase.h"
30 #include "SkMessageBus.h"
31 #include "SkMipMap.h"
32 #include "SkPM4fPriv.h"
33 #include "SkPaintPriv.h"
34 #include "SkPixelRef.h"
35 #include "SkResourceCache.h"
36 #include "SkShaderBase.h"
37 #include "SkTemplates.h"
38 #include "SkTraceEvent.h"
39 #include "effects/GrBicubicEffect.h"
40 #include "effects/GrConstColorProcessor.h"
41 #include "effects/GrDitherEffect.h"
42 #include "effects/GrPorterDuffXferProcessor.h"
43 #include "effects/GrXfermodeFragmentProcessor.h"
44
GrImageInfoToSurfaceDesc(const SkImageInfo & info,const GrCaps & caps)45 GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info, const GrCaps& caps) {
46 GrSurfaceDesc desc;
47 desc.fFlags = kNone_GrSurfaceFlags;
48 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
49 desc.fWidth = info.width();
50 desc.fHeight = info.height();
51 desc.fConfig = SkImageInfo2GrPixelConfig(info, caps);
52 desc.fSampleCnt = 1;
53 return desc;
54 }
55
GrMakeKeyFromImageID(GrUniqueKey * key,uint32_t imageID,const SkIRect & imageBounds)56 void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds) {
57 SkASSERT(key);
58 SkASSERT(imageID);
59 SkASSERT(!imageBounds.isEmpty());
60 static const GrUniqueKey::Domain kImageIDDomain = GrUniqueKey::GenerateDomain();
61 GrUniqueKey::Builder builder(key, kImageIDDomain, 5, "Image");
62 builder[0] = imageID;
63 builder[1] = imageBounds.fLeft;
64 builder[2] = imageBounds.fTop;
65 builder[3] = imageBounds.fRight;
66 builder[4] = imageBounds.fBottom;
67 }
68
69 //////////////////////////////////////////////////////////////////////////////
GrUploadBitmapToTextureProxy(GrProxyProvider * proxyProvider,const SkBitmap & bitmap,SkColorSpace * dstColorSpace)70 sk_sp<GrTextureProxy> GrUploadBitmapToTextureProxy(GrProxyProvider* proxyProvider,
71 const SkBitmap& bitmap,
72 SkColorSpace* dstColorSpace) {
73 if (!bitmap.peekPixels(nullptr)) {
74 return nullptr;
75 }
76
77 SkDestinationSurfaceColorMode colorMode = dstColorSpace
78 ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
79 : SkDestinationSurfaceColorMode::kLegacy;
80
81 if (!SkImageInfoIsValid(bitmap.info(), colorMode)) {
82 return nullptr;
83 }
84
85 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap
86 // even if it's mutable. In ddl, if the bitmap is mutable then we must make a copy since the
87 // upload of the data to the gpu can happen at anytime and the bitmap may change by then.
88 SkCopyPixelsMode cpyMode = proxyProvider->mutableBitmapsNeedCopy() ? kIfMutable_SkCopyPixelsMode
89 : kNever_SkCopyPixelsMode;
90 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, cpyMode);
91
92 return proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags,
93 kTopLeft_GrSurfaceOrigin, 1, SkBudgeted::kYes,
94 SkBackingFit::kExact);
95 }
96
97 ////////////////////////////////////////////////////////////////////////////////
98
GrInstallBitmapUniqueKeyInvalidator(const GrUniqueKey & key,SkPixelRef * pixelRef)99 void GrInstallBitmapUniqueKeyInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
100 class Invalidator : public SkPixelRef::GenIDChangeListener {
101 public:
102 explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
103 private:
104 GrUniqueKeyInvalidatedMessage fMsg;
105
106 void onChange() override { SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); }
107 };
108
109 pixelRef->addGenIDChangeListener(new Invalidator(key));
110 }
111
GrCopyBaseMipMapToTextureProxy(GrContext * ctx,GrTextureProxy * baseProxy)112 sk_sp<GrTextureProxy> GrCopyBaseMipMapToTextureProxy(GrContext* ctx, GrTextureProxy* baseProxy) {
113 SkASSERT(baseProxy);
114
115 if (!ctx->caps()->isConfigCopyable(baseProxy->config())) {
116 return nullptr;
117 }
118
119 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
120 GrSurfaceDesc desc;
121 desc.fFlags = kNone_GrSurfaceFlags;
122 desc.fOrigin = baseProxy->origin();
123 desc.fWidth = baseProxy->width();
124 desc.fHeight = baseProxy->height();
125 desc.fConfig = baseProxy->config();
126 desc.fSampleCnt = 1;
127
128 sk_sp<GrTextureProxy> proxy = proxyProvider->createMipMapProxy(desc, SkBudgeted::kYes);
129 if (!proxy) {
130 return nullptr;
131 }
132
133 // Copy the base layer to our proxy
134 sk_sp<SkColorSpace> colorSpace;
135 if (GrPixelConfigIsSRGB(proxy->config())) {
136 colorSpace = SkColorSpace::MakeSRGB();
137 }
138 sk_sp<GrSurfaceContext> sContext =
139 ctx->contextPriv().makeWrappedSurfaceContext(proxy, std::move(colorSpace));
140 SkASSERT(sContext);
141 SkAssertResult(sContext->copy(baseProxy));
142
143 return proxy;
144 }
145
GrRefCachedBitmapTextureProxy(GrContext * ctx,const SkBitmap & bitmap,const GrSamplerState & params,SkScalar scaleAdjust[2])146 sk_sp<GrTextureProxy> GrRefCachedBitmapTextureProxy(GrContext* ctx,
147 const SkBitmap& bitmap,
148 const GrSamplerState& params,
149 SkScalar scaleAdjust[2]) {
150 // Caller doesn't care about the texture's color space (they can always get it from the bitmap)
151 return GrBitmapTextureMaker(ctx, bitmap).refTextureProxyForParams(params, nullptr,
152 nullptr, scaleAdjust);
153 }
154
GrMakeCachedBitmapProxy(GrProxyProvider * proxyProvider,const SkBitmap & bitmap,SkBackingFit fit)155 sk_sp<GrTextureProxy> GrMakeCachedBitmapProxy(GrProxyProvider* proxyProvider,
156 const SkBitmap& bitmap,
157 SkBackingFit fit) {
158 if (!bitmap.peekPixels(nullptr)) {
159 return nullptr;
160 }
161
162 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap
163 // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the
164 // upload of the data to the gpu can happen at anytime and the bitmap may change by then.
165 SkCopyPixelsMode cpyMode = proxyProvider->mutableBitmapsNeedCopy() ? kIfMutable_SkCopyPixelsMode
166 : kNever_SkCopyPixelsMode;
167 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, cpyMode);
168
169 if (!image) {
170 return nullptr;
171 }
172
173 return GrMakeCachedImageProxy(proxyProvider, std::move(image), fit);
174 }
175
create_unique_key_for_image(const SkImage * image,GrUniqueKey * result)176 static void create_unique_key_for_image(const SkImage* image, GrUniqueKey* result) {
177 if (!image) {
178 result->reset(); // will be invalid
179 return;
180 }
181
182 if (const SkBitmap* bm = as_IB(image)->onPeekBitmap()) {
183 SkIPoint origin = bm->pixelRefOrigin();
184 SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bm->width(), bm->height());
185 GrMakeKeyFromImageID(result, bm->getGenerationID(), subset);
186 return;
187 }
188
189 GrMakeKeyFromImageID(result, image->uniqueID(), image->bounds());
190 }
191
GrMakeCachedImageProxy(GrProxyProvider * proxyProvider,sk_sp<SkImage> srcImage,SkBackingFit fit)192 sk_sp<GrTextureProxy> GrMakeCachedImageProxy(GrProxyProvider* proxyProvider,
193 sk_sp<SkImage> srcImage,
194 SkBackingFit fit) {
195 sk_sp<GrTextureProxy> proxy;
196 GrUniqueKey originalKey;
197
198 create_unique_key_for_image(srcImage.get(), &originalKey);
199
200 if (originalKey.isValid()) {
201 proxy = proxyProvider->findOrCreateProxyByUniqueKey(originalKey, kTopLeft_GrSurfaceOrigin);
202 }
203 if (!proxy) {
204 proxy = proxyProvider->createTextureProxy(std::move(srcImage), kNone_GrSurfaceFlags,
205 kTopLeft_GrSurfaceOrigin, 1, SkBudgeted::kYes,
206 fit);
207 if (proxy && originalKey.isValid()) {
208 proxyProvider->assignUniqueKeyToProxy(originalKey, proxy.get());
209 }
210 }
211
212 return proxy;
213 }
214
215 ///////////////////////////////////////////////////////////////////////////////
216
SkColorToPremulGrColor4f(SkColor c,const GrColorSpaceInfo & colorSpaceInfo)217 GrColor4f SkColorToPremulGrColor4f(SkColor c, const GrColorSpaceInfo& colorSpaceInfo) {
218 // We want to premultiply after linearizing, so this is easy:
219 return SkColorToUnpremulGrColor4f(c, colorSpaceInfo).premul();
220 }
221
SkColorToPremulGrColor4fLegacy(SkColor c)222 GrColor4f SkColorToPremulGrColor4fLegacy(SkColor c) {
223 return GrColor4f::FromGrColor(SkColorToUnpremulGrColor(c)).premul();
224 }
225
SkColorToUnpremulGrColor4f(SkColor c,const GrColorSpaceInfo & colorSpaceInfo)226 GrColor4f SkColorToUnpremulGrColor4f(SkColor c, const GrColorSpaceInfo& colorSpaceInfo) {
227 GrColor4f color;
228 if (colorSpaceInfo.colorSpace()) {
229 // SkColor4f::FromColor does sRGB -> Linear
230 color = GrColor4f::FromSkColor4f(SkColor4f::FromColor(c));
231 } else {
232 // GrColor4f::FromGrColor just multiplies by 1/255
233 color = GrColor4f::FromGrColor(SkColorToUnpremulGrColor(c));
234 }
235
236 if (auto* xform = colorSpaceInfo.colorSpaceXformFromSRGB()) {
237 color = xform->clampedXform(color);
238 }
239
240 return color;
241 }
242
243 ///////////////////////////////////////////////////////////////////////////////
244
SkImageInfo2GrPixelConfig(const SkColorType type,SkColorSpace * cs,const GrCaps & caps)245 GrPixelConfig SkImageInfo2GrPixelConfig(const SkColorType type, SkColorSpace* cs,
246 const GrCaps& caps) {
247 switch (type) {
248 case kUnknown_SkColorType:
249 return kUnknown_GrPixelConfig;
250 case kAlpha_8_SkColorType:
251 return kAlpha_8_GrPixelConfig;
252 case kRGB_565_SkColorType:
253 return kRGB_565_GrPixelConfig;
254 case kARGB_4444_SkColorType:
255 return kRGBA_4444_GrPixelConfig;
256 case kRGBA_8888_SkColorType:
257 return (caps.srgbSupport() && cs && cs->gammaCloseToSRGB())
258 ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
259 // TODO: We're checking for srgbSupport, but we can then end up picking sBGRA as our pixel
260 // config (which may not be supported). We need a better test here.
261 case kRGB_888x_SkColorType:
262 return kUnknown_GrPixelConfig;
263 case kBGRA_8888_SkColorType:
264 return (caps.srgbSupport() && cs && cs->gammaCloseToSRGB())
265 ? kSBGRA_8888_GrPixelConfig : kBGRA_8888_GrPixelConfig;
266 case kRGBA_1010102_SkColorType:
267 return kRGBA_1010102_GrPixelConfig;
268 case kRGB_101010x_SkColorType:
269 return kUnknown_GrPixelConfig;
270 case kGray_8_SkColorType:
271 return kGray_8_GrPixelConfig;
272 case kRGBA_F16_SkColorType:
273 return kRGBA_half_GrPixelConfig;
274 }
275 SkASSERT(0); // shouldn't get here
276 return kUnknown_GrPixelConfig;
277 }
278
SkImageInfo2GrPixelConfig(const SkImageInfo & info,const GrCaps & caps)279 GrPixelConfig SkImageInfo2GrPixelConfig(const SkImageInfo& info, const GrCaps& caps) {
280 return SkImageInfo2GrPixelConfig(info.colorType(), info.colorSpace(), caps);
281 }
282
GrPixelConfigToColorType(GrPixelConfig config,SkColorType * ctOut)283 bool GrPixelConfigToColorType(GrPixelConfig config, SkColorType* ctOut) {
284 SkColorType ct;
285 switch (config) {
286 case kAlpha_8_GrPixelConfig: // fall through
287 case kAlpha_8_as_Alpha_GrPixelConfig: // fall through
288 case kAlpha_8_as_Red_GrPixelConfig:
289 ct = kAlpha_8_SkColorType;
290 break;
291 case kGray_8_GrPixelConfig: // fall through
292 case kGray_8_as_Lum_GrPixelConfig: // fall through
293 case kGray_8_as_Red_GrPixelConfig:
294 ct = kGray_8_SkColorType;
295 break;
296 case kRGB_565_GrPixelConfig:
297 ct = kRGB_565_SkColorType;
298 break;
299 case kRGBA_4444_GrPixelConfig:
300 ct = kARGB_4444_SkColorType;
301 break;
302 case kRGBA_8888_GrPixelConfig:
303 ct = kRGBA_8888_SkColorType;
304 break;
305 case kBGRA_8888_GrPixelConfig:
306 ct = kBGRA_8888_SkColorType;
307 break;
308 case kSRGBA_8888_GrPixelConfig:
309 ct = kRGBA_8888_SkColorType;
310 break;
311 case kSBGRA_8888_GrPixelConfig:
312 ct = kBGRA_8888_SkColorType;
313 break;
314 case kRGBA_1010102_GrPixelConfig:
315 ct = kRGBA_1010102_SkColorType;
316 break;
317 case kRGBA_half_GrPixelConfig:
318 ct = kRGBA_F16_SkColorType;
319 break;
320 default:
321 return false;
322 }
323 if (ctOut) {
324 *ctOut = ct;
325 }
326 return true;
327 }
328
GrRenderableConfigForColorSpace(const SkColorSpace * colorSpace)329 GrPixelConfig GrRenderableConfigForColorSpace(const SkColorSpace* colorSpace) {
330 if (!colorSpace) {
331 return kRGBA_8888_GrPixelConfig;
332 } else if (colorSpace->gammaIsLinear()) {
333 return kRGBA_half_GrPixelConfig;
334 } else if (colorSpace->gammaCloseToSRGB()) {
335 return kSRGBA_8888_GrPixelConfig;
336 } else {
337 SkDEBUGFAIL("No renderable config exists for color space with strange gamma");
338 return kUnknown_GrPixelConfig;
339 }
340 }
341
342 ////////////////////////////////////////////////////////////////////////////////////////////////
343
blend_requires_shader(const SkBlendMode mode)344 static inline bool blend_requires_shader(const SkBlendMode mode) {
345 return SkBlendMode::kDst != mode;
346 }
347
skpaint_to_grpaint_impl(GrContext * context,const GrColorSpaceInfo & colorSpaceInfo,const SkPaint & skPaint,const SkMatrix & viewM,std::unique_ptr<GrFragmentProcessor> * shaderProcessor,SkBlendMode * primColorMode,GrPaint * grPaint)348 static inline bool skpaint_to_grpaint_impl(GrContext* context,
349 const GrColorSpaceInfo& colorSpaceInfo,
350 const SkPaint& skPaint,
351 const SkMatrix& viewM,
352 std::unique_ptr<GrFragmentProcessor>* shaderProcessor,
353 SkBlendMode* primColorMode,
354 GrPaint* grPaint) {
355 grPaint->setAllowSRGBInputs(colorSpaceInfo.isGammaCorrect());
356
357 // Convert SkPaint color to 4f format, including optional linearizing and gamut conversion.
358 GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), colorSpaceInfo);
359
360 const GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo);
361
362 // Setup the initial color considering the shader, the SkPaint color, and the presence or not
363 // of per-vertex colors.
364 std::unique_ptr<GrFragmentProcessor> shaderFP;
365 if (!primColorMode || blend_requires_shader(*primColorMode)) {
366 if (shaderProcessor) {
367 shaderFP = std::move(*shaderProcessor);
368 } else if (const auto* shader = as_SB(skPaint.getShader())) {
369 shaderFP = shader->asFragmentProcessor(fpArgs);
370 if (!shaderFP) {
371 return false;
372 }
373 }
374 }
375
376 // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is
377 // a known constant value. In that case we can simply apply a color filter during this
378 // conversion without converting the color filter to a GrFragmentProcessor.
379 bool applyColorFilterToPaintColor = false;
380 if (shaderFP) {
381 if (primColorMode) {
382 // There is a blend between the primitive color and the shader color. The shader sees
383 // the opaque paint color. The shader's output is blended using the provided mode by
384 // the primitive color. The blended color is then modulated by the paint's alpha.
385
386 // The geometry processor will insert the primitive color to start the color chain, so
387 // the GrPaint color will be ignored.
388
389 GrColor4f shaderInput = origColor.opaque();
390 shaderFP = GrFragmentProcessor::OverrideInput(std::move(shaderFP), shaderInput);
391 shaderFP = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(shaderFP),
392 *primColorMode);
393
394 // The above may return null if compose results in a pass through of the prim color.
395 if (shaderFP) {
396 grPaint->addColorFragmentProcessor(std::move(shaderFP));
397 }
398
399 // We can ignore origColor here - alpha is unchanged by gamma
400 GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
401 if (GrColor_WHITE != paintAlpha) {
402 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
403 // color channels. It's value should be treated as the same in ANY color space.
404 grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make(
405 GrColor4f::FromGrColor(paintAlpha),
406 GrConstColorProcessor::InputMode::kModulateRGBA));
407 }
408 } else {
409 // The shader's FP sees the paint unpremul color
410 grPaint->setColor4f(origColor);
411 grPaint->addColorFragmentProcessor(std::move(shaderFP));
412 }
413 } else {
414 if (primColorMode) {
415 // There is a blend between the primitive color and the paint color. The blend considers
416 // the opaque paint color. The paint's alpha is applied to the post-blended color.
417 auto processor = GrConstColorProcessor::Make(origColor.opaque(),
418 GrConstColorProcessor::InputMode::kIgnore);
419 processor = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(processor),
420 *primColorMode);
421 if (processor) {
422 grPaint->addColorFragmentProcessor(std::move(processor));
423 }
424
425 grPaint->setColor4f(origColor.opaque());
426
427 // We can ignore origColor here - alpha is unchanged by gamma
428 GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
429 if (GrColor_WHITE != paintAlpha) {
430 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
431 // color channels. It's value should be treated as the same in ANY color space.
432 grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make(
433 GrColor4f::FromGrColor(paintAlpha),
434 GrConstColorProcessor::InputMode::kModulateRGBA));
435 }
436 } else {
437 // No shader, no primitive color.
438 grPaint->setColor4f(origColor.premul());
439 applyColorFilterToPaintColor = true;
440 }
441 }
442
443 SkColorFilter* colorFilter = skPaint.getColorFilter();
444 if (colorFilter) {
445 if (applyColorFilterToPaintColor) {
446 // If we're in legacy mode, we *must* avoid using the 4f version of the color filter,
447 // because that will combine with the linearized version of the stored color.
448 if (colorSpaceInfo.isGammaCorrect()) {
449 grPaint->setColor4f(GrColor4f::FromSkColor4f(
450 colorFilter->filterColor4f(origColor.toSkColor4f())).premul());
451 } else {
452 grPaint->setColor4f(SkColorToPremulGrColor4fLegacy(
453 colorFilter->filterColor(skPaint.getColor())));
454 }
455 } else {
456 auto cfFP = colorFilter->asFragmentProcessor(context, colorSpaceInfo);
457 if (cfFP) {
458 grPaint->addColorFragmentProcessor(std::move(cfFP));
459 } else {
460 return false;
461 }
462 }
463 }
464
465 SkMaskFilterBase* maskFilter = as_MFB(skPaint.getMaskFilter());
466 if (maskFilter) {
467 if (auto mfFP = maskFilter->asFragmentProcessor(fpArgs)) {
468 grPaint->addCoverageFragmentProcessor(std::move(mfFP));
469 }
470 }
471
472 // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on
473 // the GrPaint to also be null (also kSrcOver).
474 SkASSERT(!grPaint->getXPFactory());
475 if (!skPaint.isSrcOver()) {
476 grPaint->setXPFactory(SkBlendMode_AsXPFactory(skPaint.getBlendMode()));
477 }
478
479 #ifndef SK_IGNORE_GPU_DITHER
480 // Conservative default, in case GrPixelConfigToColorType() fails.
481 SkColorType ct = SkColorType::kRGB_565_SkColorType;
482 GrPixelConfigToColorType(colorSpaceInfo.config(), &ct);
483 if (SkPaintPriv::ShouldDither(skPaint, ct) && grPaint->numColorFragmentProcessors() > 0 &&
484 !colorSpaceInfo.isGammaCorrect()) {
485 auto ditherFP = GrDitherEffect::Make(colorSpaceInfo.config());
486 if (ditherFP) {
487 grPaint->addColorFragmentProcessor(std::move(ditherFP));
488 }
489 }
490 #endif
491 return true;
492 }
493
SkPaintToGrPaint(GrContext * context,const GrColorSpaceInfo & colorSpaceInfo,const SkPaint & skPaint,const SkMatrix & viewM,GrPaint * grPaint)494 bool SkPaintToGrPaint(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo,
495 const SkPaint& skPaint, const SkMatrix& viewM, GrPaint* grPaint) {
496 return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, viewM, nullptr, nullptr,
497 grPaint);
498 }
499
500 /** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */
SkPaintToGrPaintReplaceShader(GrContext * context,const GrColorSpaceInfo & colorSpaceInfo,const SkPaint & skPaint,std::unique_ptr<GrFragmentProcessor> shaderFP,GrPaint * grPaint)501 bool SkPaintToGrPaintReplaceShader(GrContext* context,
502 const GrColorSpaceInfo& colorSpaceInfo,
503 const SkPaint& skPaint,
504 std::unique_ptr<GrFragmentProcessor> shaderFP,
505 GrPaint* grPaint) {
506 if (!shaderFP) {
507 return false;
508 }
509 return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, SkMatrix::I(), &shaderFP,
510 nullptr, grPaint);
511 }
512
513 /** Ignores the SkShader (if any) on skPaint. */
SkPaintToGrPaintNoShader(GrContext * context,const GrColorSpaceInfo & colorSpaceInfo,const SkPaint & skPaint,GrPaint * grPaint)514 bool SkPaintToGrPaintNoShader(GrContext* context,
515 const GrColorSpaceInfo& colorSpaceInfo,
516 const SkPaint& skPaint,
517 GrPaint* grPaint) {
518 // Use a ptr to a nullptr to to indicate that the SkShader is ignored and not replaced.
519 static std::unique_ptr<GrFragmentProcessor> kNullShaderFP(nullptr);
520 static std::unique_ptr<GrFragmentProcessor>* kIgnoreShader = &kNullShaderFP;
521 return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, SkMatrix::I(), kIgnoreShader,
522 nullptr, grPaint);
523 }
524
525 /** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must
526 be setup as a vertex attribute using the specified SkBlendMode. */
SkPaintToGrPaintWithXfermode(GrContext * context,const GrColorSpaceInfo & colorSpaceInfo,const SkPaint & skPaint,const SkMatrix & viewM,SkBlendMode primColorMode,GrPaint * grPaint)527 bool SkPaintToGrPaintWithXfermode(GrContext* context,
528 const GrColorSpaceInfo& colorSpaceInfo,
529 const SkPaint& skPaint,
530 const SkMatrix& viewM,
531 SkBlendMode primColorMode,
532 GrPaint* grPaint) {
533 return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, viewM, nullptr, &primColorMode,
534 grPaint);
535 }
536
SkPaintToGrPaintWithTexture(GrContext * context,const GrColorSpaceInfo & colorSpaceInfo,const SkPaint & paint,const SkMatrix & viewM,std::unique_ptr<GrFragmentProcessor> fp,bool textureIsAlphaOnly,GrPaint * grPaint)537 bool SkPaintToGrPaintWithTexture(GrContext* context,
538 const GrColorSpaceInfo& colorSpaceInfo,
539 const SkPaint& paint,
540 const SkMatrix& viewM,
541 std::unique_ptr<GrFragmentProcessor> fp,
542 bool textureIsAlphaOnly,
543 GrPaint* grPaint) {
544 std::unique_ptr<GrFragmentProcessor> shaderFP;
545 if (textureIsAlphaOnly) {
546 if (const auto* shader = as_SB(paint.getShader())) {
547 shaderFP = shader->asFragmentProcessor(GrFPArgs(
548 context, &viewM, nullptr, paint.getFilterQuality(), &colorSpaceInfo));
549 if (!shaderFP) {
550 return false;
551 }
552 std::unique_ptr<GrFragmentProcessor> fpSeries[] = { std::move(shaderFP), std::move(fp) };
553 shaderFP = GrFragmentProcessor::RunInSeries(fpSeries, 2);
554 } else {
555 shaderFP = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
556 }
557 } else {
558 shaderFP = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
559 }
560
561 return SkPaintToGrPaintReplaceShader(context, colorSpaceInfo, paint, std::move(shaderFP),
562 grPaint);
563 }
564
565
566 ////////////////////////////////////////////////////////////////////////////////////////////////
567
GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality,const SkMatrix & viewM,const SkMatrix & localM,bool sharpenMipmappedTextures,bool * doBicubic)568 GrSamplerState::Filter GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality,
569 const SkMatrix& viewM,
570 const SkMatrix& localM,
571 bool sharpenMipmappedTextures,
572 bool* doBicubic) {
573 *doBicubic = false;
574 GrSamplerState::Filter textureFilterMode;
575 switch (paintFilterQuality) {
576 case kNone_SkFilterQuality:
577 textureFilterMode = GrSamplerState::Filter::kNearest;
578 break;
579 case kLow_SkFilterQuality:
580 textureFilterMode = GrSamplerState::Filter::kBilerp;
581 break;
582 case kMedium_SkFilterQuality: {
583 SkMatrix matrix;
584 matrix.setConcat(viewM, localM);
585 // With sharp mips, we bias lookups by -0.5. That means our final LOD is >= 0 until the
586 // computed LOD is >= 0.5. At what scale factor does a texture get an LOD of 0.5?
587 //
588 // Want: 0 = log2(1/s) - 0.5
589 // 0.5 = log2(1/s)
590 // 2^0.5 = 1/s
591 // 1/2^0.5 = s
592 // 2^0.5/2 = s
593 SkScalar mipScale = sharpenMipmappedTextures ? SK_ScalarRoot2Over2 : SK_Scalar1;
594 if (matrix.getMinScale() < mipScale) {
595 textureFilterMode = GrSamplerState::Filter::kMipMap;
596 } else {
597 // Don't trigger MIP level generation unnecessarily.
598 textureFilterMode = GrSamplerState::Filter::kBilerp;
599 }
600 break;
601 }
602 case kHigh_SkFilterQuality: {
603 SkMatrix matrix;
604 matrix.setConcat(viewM, localM);
605 *doBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode);
606 break;
607 }
608 default:
609 // Should be unreachable. If not, fall back to mipmaps.
610 textureFilterMode = GrSamplerState::Filter::kMipMap;
611 break;
612
613 }
614 return textureFilterMode;
615 }
616