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/gpu/GrTypes.h"
17#include "include/private/SkIDChangeListener.h"
18#include "include/private/SkImageInfoPriv.h"
19#include "include/private/SkTemplates.h"
20#include "src/core/SkAutoMalloc.h"
21#include "src/core/SkBlendModePriv.h"
22#include "src/core/SkColorFilterBase.h"
23#include "src/core/SkColorSpacePriv.h"
24#include "src/core/SkImagePriv.h"
25#include "src/core/SkMaskFilterBase.h"
26#include "src/core/SkMatrixPriv.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/SkTraceEvent.h"
32#include "src/gpu/GrBitmapTextureMaker.h"
33#include "src/gpu/GrCaps.h"
34#include "src/gpu/GrColorSpaceXform.h"
35#include "src/gpu/GrGpuResourcePriv.h"
36#include "src/gpu/GrPaint.h"
37#include "src/gpu/GrProxyProvider.h"
38#include "src/gpu/GrRecordingContextPriv.h"
39#include "src/gpu/GrTextureProxy.h"
40#include "src/gpu/GrXferProcessor.h"
41#include "src/gpu/SkGr.h"
42#include "src/gpu/effects/GrBicubicEffect.h"
43#include "src/gpu/effects/GrBlendFragmentProcessor.h"
44#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
45#include "src/gpu/effects/generated/GrClampFragmentProcessor.h"
46#include "src/gpu/effects/generated/GrConstColorProcessor.h"
47#include "src/gpu/effects/generated/GrDitherEffect.h"
48#include "src/image/SkImage_Base.h"
49#include "src/shaders/SkShaderBase.h"
50
51void 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
66sk_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 { SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); }
73
74 private:
75 GrUniqueKeyInvalidatedMessage fMsg;
76 };
77
78 auto listener = sk_make_sp<Listener>(*key, contextID);
79
80 // We stick a SkData on the key that calls invalidateListener in its destructor.
81 auto invalidateListener = [](const void* ptr, void* /*context*/) {
82 auto listener = reinterpret_cast<const sk_sp<Listener>*>(ptr);
83 (*listener)->markShouldDeregister();
84 delete listener;
85 };
86 auto data = SkData::MakeWithProc(new sk_sp<Listener>(listener),
87 sizeof(sk_sp<Listener>),
88 invalidateListener,
89 nullptr);
90 SkASSERT(!key->getCustomData());
91 key->setCustomData(std::move(data));
92 return std::move(listener);
93}
94
95sk_sp<GrSurfaceProxy> GrCopyBaseMipMapToTextureProxy(GrRecordingContext* ctx,
96 GrSurfaceProxy* baseProxy,
97 GrSurfaceOrigin origin,
98 SkBudgeted budgeted) {
99 SkASSERT(baseProxy);
100
101 if (!ctx->priv().caps()->isFormatCopyable(baseProxy->backendFormat())) {
102 return {};
103 }
104 auto copy = GrSurfaceProxy::Copy(ctx, baseProxy, origin, GrMipmapped::kYes,
105 SkBackingFit::kExact, budgeted);
106 if (!copy) {
107 return {};
108 }
109 SkASSERT(copy->asTextureProxy());
110 return copy;
111}
112
113GrSurfaceProxyView GrCopyBaseMipMapToView(GrRecordingContext* context,
114 GrSurfaceProxyView src,
115 SkBudgeted budgeted) {
116 auto origin = src.origin();
117 auto swizzle = src.swizzle();
118 auto* proxy = src.proxy();
119 return {GrCopyBaseMipMapToTextureProxy(context, proxy, origin, budgeted), origin, swizzle};
120}
121
122GrSurfaceProxyView GrRefCachedBitmapView(GrRecordingContext* ctx, const SkBitmap& bitmap,
123 GrMipmapped mipMapped) {
124 GrBitmapTextureMaker maker(ctx, bitmap, GrImageTexGenPolicy::kDraw);
125 return maker.view(mipMapped);
126}
127
128GrSurfaceProxyView GrMakeCachedBitmapProxyView(GrRecordingContext* context,
129 const SkBitmap& bitmap) {
130 if (!bitmap.peekPixels(nullptr)) {
131 return {};
132 }
133
134 GrBitmapTextureMaker maker(context, bitmap, GrImageTexGenPolicy::kDraw);
135 return maker.view(GrMipmapped::kNo);
136}
137
138///////////////////////////////////////////////////////////////////////////////
139
140SkPMColor4f SkColorToPMColor4f(SkColor c, const GrColorInfo& colorInfo) {
141 SkColor4f color = SkColor4f::FromColor(c);
142 if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) {
143 color = xform->apply(color);
144 }
145 return color.premul();
146}
147
148SkColor4f SkColor4fPrepForDst(SkColor4f color, const GrColorInfo& colorInfo) {
149 if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) {
150 color = xform->apply(color);
151 }
152 return color;
153}
154
155///////////////////////////////////////////////////////////////////////////////
156
157static inline bool blend_requires_shader(const SkBlendMode mode) {
158 return SkBlendMode::kDst != mode;
159}
160
161#ifndef SK_IGNORE_GPU_DITHER
162static inline float dither_range_for_config(GrColorType dstColorType) {
163 // We use 1 / (2^bitdepth-1) as the range since each channel can hold 2^bitdepth values
164 switch (dstColorType) {
165 // 4 bit
166 case GrColorType::kABGR_4444:
167 case GrColorType::kARGB_4444:
168 case GrColorType::kBGRA_4444:
169 return 1 / 15.f;
170 // 6 bit
171 case GrColorType::kBGR_565:
172 return 1 / 63.f;
173 // 8 bit
174 case GrColorType::kUnknown:
175 case GrColorType::kAlpha_8:
176 case GrColorType::kAlpha_8xxx:
177 case GrColorType::kGray_8:
178 case GrColorType::kGray_8xxx:
179 case GrColorType::kR_8:
180 case GrColorType::kRG_88:
181 case GrColorType::kRGB_888:
182 case GrColorType::kRGB_888x:
183 case GrColorType::kRGBA_8888:
184 case GrColorType::kRGBA_8888_SRGB:
185 case GrColorType::kBGRA_8888:
186 return 1 / 255.f;
187 // 10 bit
188 case GrColorType::kRGBA_1010102:
189 case GrColorType::kBGRA_1010102:
190 return 1 / 1023.f;
191 // 16 bit
192 case GrColorType::kAlpha_16:
193 case GrColorType::kR_16:
194 case GrColorType::kRG_1616:
195 case GrColorType::kRGBA_16161616:
196 return 1 / 32767.f;
197 // Half
198 case GrColorType::kAlpha_F16:
199 case GrColorType::kGray_F16:
200 case GrColorType::kR_F16:
201 case GrColorType::kRG_F16:
202 case GrColorType::kRGBA_F16:
203 case GrColorType::kRGBA_F16_Clamped:
204 // Float
205 case GrColorType::kAlpha_F32xxx:
206 case GrColorType::kRGBA_F32:
207 return 0.f; // no dithering
208 }
209 SkUNREACHABLE;
210}
211#endif
212
213static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context,
214 const GrColorInfo& dstColorInfo,
215 const SkPaint& skPaint,
216 const SkMatrixProvider& matrixProvider,
217 std::unique_ptr<GrFragmentProcessor>* shaderProcessor,
218 SkBlendMode* primColorMode,
219 GrPaint* grPaint) {
220 // Convert SkPaint color to 4f format in the destination color space
221 SkColor4f origColor = SkColor4fPrepForDst(skPaint.getColor4f(), dstColorInfo);
222
223 GrFPArgs fpArgs(context, matrixProvider, skPaint.getFilterQuality(), &dstColorInfo);
224
225 // Setup the initial color considering the shader, the SkPaint color, and the presence or not
226 // of per-vertex colors.
227 std::unique_ptr<GrFragmentProcessor> paintFP;
228 if (!primColorMode || blend_requires_shader(*primColorMode)) {
229 fpArgs.fInputColorIsOpaque = origColor.isOpaque();
230 if (shaderProcessor) {
231 paintFP = std::move(*shaderProcessor);
232 } else {
233 if (const SkShaderBase* shader = as_SB(skPaint.getShader())) {
234 paintFP = shader->asFragmentProcessor(fpArgs);
235 if (paintFP == nullptr) {
236 return false;
237 }
238 }
239 }
240 }
241
242 // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is
243 // a known constant value. In that case we can simply apply a color filter during this
244 // conversion without converting the color filter to a GrFragmentProcessor.
245 bool applyColorFilterToPaintColor = false;
246 if (paintFP) {
247 if (primColorMode) {
248 // There is a blend between the primitive color and the shader color. The shader sees
249 // the opaque paint color. The shader's output is blended using the provided mode by
250 // the primitive color. The blended color is then modulated by the paint's alpha.
251
252 // The geometry processor will insert the primitive color to start the color chain, so
253 // the GrPaint color will be ignored.
254
255 SkPMColor4f shaderInput = origColor.makeOpaque().premul();
256 paintFP = GrFragmentProcessor::OverrideInput(std::move(paintFP), shaderInput);
257 paintFP = GrBlendFragmentProcessor::Make(std::move(paintFP), /*dst=*/nullptr,
258 *primColorMode);
259
260 // We can ignore origColor here - alpha is unchanged by gamma
261 float paintAlpha = skPaint.getColor4f().fA;
262 if (1.0f != paintAlpha) {
263 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
264 // color channels. It's value should be treated as the same in ANY color space.
265 paintFP = GrFragmentProcessor::ModulateRGBA(
266 std::move(paintFP), {paintAlpha, paintAlpha, paintAlpha, paintAlpha});
267 }
268 } else {
269 grPaint->setColor4f(origColor.premul());
270 }
271 } else {
272 if (primColorMode) {
273 // There is a blend between the primitive color and the paint color. The blend considers
274 // the opaque paint color. The paint's alpha is applied to the post-blended color.
275 SkPMColor4f opaqueColor = origColor.makeOpaque().premul();
276 paintFP = GrConstColorProcessor::Make(opaqueColor);
277 paintFP = GrBlendFragmentProcessor::Make(std::move(paintFP), /*dst=*/nullptr,
278 *primColorMode);
279 grPaint->setColor4f(opaqueColor);
280
281 // We can ignore origColor here - alpha is unchanged by gamma
282 float paintAlpha = skPaint.getColor4f().fA;
283 if (1.0f != paintAlpha) {
284 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
285 // color channels. It's value should be treated as the same in ANY color space.
286 paintFP = GrFragmentProcessor::ModulateRGBA(
287 std::move(paintFP), {paintAlpha, paintAlpha, paintAlpha, paintAlpha});
288 }
289 } else {
290 // No shader, no primitive color.
291 grPaint->setColor4f(origColor.premul());
292 applyColorFilterToPaintColor = true;
293 }
294 }
295
296 SkColorFilter* colorFilter = skPaint.getColorFilter();
297 if (colorFilter) {
298 if (applyColorFilterToPaintColor) {
299 SkColorSpace* dstCS = dstColorInfo.colorSpace();
300 grPaint->setColor4f(colorFilter->filterColor4f(origColor, dstCS, dstCS).premul());
301 } else {
302 auto [success, fp] = as_CFB(colorFilter)->asFragmentProcessor(std::move(paintFP),
303 context, dstColorInfo);
304 if (!success) {
305 return false;
306 }
307 paintFP = std::move(fp);
308 }
309 }
310
311 SkMaskFilterBase* maskFilter = as_MFB(skPaint.getMaskFilter());
312 if (maskFilter) {
313 // We may have set this before passing to the SkShader.
314 fpArgs.fInputColorIsOpaque = false;
315 if (auto mfFP = maskFilter->asFragmentProcessor(fpArgs)) {
316 grPaint->setCoverageFragmentProcessor(std::move(mfFP));
317 }
318 }
319
320 // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on
321 // the GrPaint to also be null (also kSrcOver).
322 SkASSERT(!grPaint->getXPFactory());
323 if (!skPaint.isSrcOver()) {
324 grPaint->setXPFactory(SkBlendMode_AsXPFactory(skPaint.getBlendMode()));
325 }
326
327#ifndef SK_IGNORE_GPU_DITHER
328 GrColorType ct = dstColorInfo.colorType();
329 if (SkPaintPriv::ShouldDither(skPaint, GrColorTypeToSkColorType(ct)) && paintFP != nullptr) {
330 float ditherRange = dither_range_for_config(ct);
331 paintFP = GrDitherEffect::Make(std::move(paintFP), ditherRange);
332 }
333#endif
334
335 if (GrColorTypeClampType(dstColorInfo.colorType()) == GrClampType::kManual) {
336 if (paintFP != nullptr) {
337 paintFP = GrClampFragmentProcessor::Make(std::move(paintFP), /*clampToPremul=*/false);
338 } else {
339 auto color = grPaint->getColor4f();
340 grPaint->setColor4f({SkTPin(color.fR, 0.f, 1.f),
341 SkTPin(color.fG, 0.f, 1.f),
342 SkTPin(color.fB, 0.f, 1.f),
343 SkTPin(color.fA, 0.f, 1.f)});
344 }
345 }
346
347 if (paintFP) {
348 grPaint->setColorFragmentProcessor(std::move(paintFP));
349 }
350
351 return true;
352}
353
354bool SkPaintToGrPaint(GrRecordingContext* context,
355 const GrColorInfo& dstColorInfo,
356 const SkPaint& skPaint,
357 const SkMatrixProvider& matrixProvider,
358 GrPaint* grPaint) {
359 return skpaint_to_grpaint_impl(context, dstColorInfo, skPaint, matrixProvider,
360 /*shaderProcessor=*/nullptr, /*primColorMode=*/nullptr, grPaint);
361}
362
363/** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */
364bool SkPaintToGrPaintReplaceShader(GrRecordingContext* context,
365 const GrColorInfo& dstColorInfo,
366 const SkPaint& skPaint,
367 const SkMatrixProvider& matrixProvider,
368 std::unique_ptr<GrFragmentProcessor> shaderFP,
369 GrPaint* grPaint) {
370 if (!shaderFP) {
371 return false;
372 }
373 return skpaint_to_grpaint_impl(context, dstColorInfo, skPaint, matrixProvider, &shaderFP,
374 /*primColorMode=*/nullptr, grPaint);
375}
376
377/** Ignores the SkShader (if any) on skPaint. */
378bool SkPaintToGrPaintNoShader(GrRecordingContext* context,
379 const GrColorInfo& dstColorInfo,
380 const SkPaint& skPaint,
381 const SkMatrixProvider& matrixProvider,
382 GrPaint* grPaint) {
383 // Use a ptr to a nullptr to to indicate that the SkShader is ignored and not replaced.
384 std::unique_ptr<GrFragmentProcessor> nullShaderFP(nullptr);
385 return skpaint_to_grpaint_impl(context, dstColorInfo, skPaint, matrixProvider, &nullShaderFP,
386 /*primColorMode=*/nullptr, grPaint);
387}
388
389/** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must
390be setup as a vertex attribute using the specified SkBlendMode. */
391bool SkPaintToGrPaintWithBlend(GrRecordingContext* context,
392 const GrColorInfo& dstColorInfo,
393 const SkPaint& skPaint,
394 const SkMatrixProvider& matrixProvider,
395 SkBlendMode primColorMode,
396 GrPaint* grPaint) {
397 return skpaint_to_grpaint_impl(context, dstColorInfo, skPaint, matrixProvider,
398 /*shaderProcessor=*/nullptr, &primColorMode, grPaint);
399}
400
401bool SkPaintToGrPaintWithTexture(GrRecordingContext* context,
402 const GrColorInfo& dstColorInfo,
403 const SkPaint& paint,
404 const SkMatrixProvider& matrixProvider,
405 std::unique_ptr<GrFragmentProcessor> fp,
406 bool textureIsAlphaOnly,
407 GrPaint* grPaint) {
408 std::unique_ptr<GrFragmentProcessor> shaderFP;
409 if (textureIsAlphaOnly) {
410 if (const auto* shader = as_SB(paint.getShader())) {
411 shaderFP = shader->asFragmentProcessor(
412 GrFPArgs(context, matrixProvider, paint.getFilterQuality(), &dstColorInfo));
413 if (!shaderFP) {
414 return false;
415 }
416 shaderFP = GrFragmentProcessor::Compose(std::move(shaderFP), std::move(fp));
417 } else {
418 shaderFP = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
419 }
420 } else {
421 if (paint.getColor4f().isOpaque()) {
422 shaderFP = GrFragmentProcessor::OverrideInput(std::move(fp), SK_PMColor4fWHITE, false);
423 } else {
424 shaderFP = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
425 }
426 }
427
428 return SkPaintToGrPaintReplaceShader(context, dstColorInfo, paint, matrixProvider,
429 std::move(shaderFP), grPaint);
430}
431
432////////////////////////////////////////////////////////////////////////////////////////////////
433
434std::tuple<GrSamplerState::Filter,
435 GrSamplerState::MipmapMode,
436 bool /*bicubic*/>
437GrInterpretFilterQuality(SkISize imageDims,
438 SkFilterQuality paintFilterQuality,
439 const SkMatrix& viewM,
440 const SkMatrix& localM,
441 bool sharpenMipmappedTextures) {
442 using Filter = GrSamplerState::Filter;
443 using MipmapMode = GrSamplerState::MipmapMode;
444 switch (paintFilterQuality) {
445 case kNone_SkFilterQuality:
446 return {Filter::kNearest, MipmapMode::kNone, false};
447 case kLow_SkFilterQuality:
448 return {Filter::kLinear, MipmapMode::kNone, false};
449 case kMedium_SkFilterQuality: {
450 SkMatrix matrix;
451 matrix.setConcat(viewM, localM);
452 // With sharp mips, we bias lookups by -0.5. That means our final LOD is >= 0 until the
453 // computed LOD is >= 0.5. At what scale factor does a texture get an LOD of 0.5?
454 //
455 // Want: 0 = log2(1/s) - 0.5
456 // 0.5 = log2(1/s)
457 // 2^0.5 = 1/s
458 // 1/2^0.5 = s
459 // 2^0.5/2 = s
460 SkScalar mipScale = sharpenMipmappedTextures ? SK_ScalarRoot2Over2 : SK_Scalar1;
461 if (matrix.getMinScale() < mipScale) {
462 return {Filter::kLinear, MipmapMode::kLinear, false};
463 } else {
464 return {Filter::kLinear, MipmapMode::kNone, false};
465 }
466 }
467 case kHigh_SkFilterQuality: {
468 SkMatrix matrix;
469 matrix.setConcat(viewM, localM);
470 switch (SkMatrixPriv::AdjustHighQualityFilterLevel(matrix)) {
471 case kNone_SkFilterQuality: return {Filter::kNearest, MipmapMode::kNone , false};
472 case kLow_SkFilterQuality: return {Filter::kLinear , MipmapMode::kNone , false};
473 case kMedium_SkFilterQuality: return {Filter::kLinear , MipmapMode::kLinear, false};
474 case kHigh_SkFilterQuality: return {Filter::kNearest, MipmapMode::kNone , true };
475 }
476 SkUNREACHABLE;
477 }
478 }
479 SkUNREACHABLE;
480}
481