1 /*
2 * Copyright 2022 Google LLC
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/graphite/KeyHelpers.h"
9
10 #include "include/core/SkData.h"
11 #include "include/effects/SkRuntimeEffect.h"
12 #include "src/core/SkColorSpacePriv.h"
13 #include "src/core/SkDebugUtils.h"
14 #include "src/core/SkRuntimeEffectPriv.h"
15 #include "src/gpu/Blend.h"
16 #include "src/gpu/graphite/KeyContext.h"
17 #include "src/gpu/graphite/PaintParamsKey.h"
18 #include "src/gpu/graphite/PipelineData.h"
19 #include "src/gpu/graphite/ReadWriteSwizzle.h"
20 #include "src/gpu/graphite/RecorderPriv.h"
21 #include "src/gpu/graphite/ResourceProvider.h"
22 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
23 #include "src/gpu/graphite/ShaderCodeDictionary.h"
24 #include "src/gpu/graphite/Texture.h"
25 #include "src/gpu/graphite/TextureProxy.h"
26 #include "src/gpu/graphite/Uniform.h"
27 #include "src/gpu/graphite/UniformManager.h"
28 #include "src/shaders/SkImageShader.h"
29
30 constexpr SkPMColor4f kErrorColor = { 1, 0, 0, 1 };
31
32 #define VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID) \
33 SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, dict->getUniforms(codeSnippetID));)
34
35 namespace skgpu::graphite {
36
37 //--------------------------------------------------------------------------------------------------
38
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer)39 void PassthroughShaderBlock::BeginBlock(const KeyContext& keyContext,
40 PaintParamsKeyBuilder* builder,
41 PipelineDataGatherer* gatherer) {
42 builder->beginBlock(BuiltInCodeSnippetID::kPassthroughShader);
43 }
44
45 //--------------------------------------------------------------------------------------------------
46
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer)47 void PassthroughBlenderBlock::BeginBlock(const KeyContext& keyContext,
48 PaintParamsKeyBuilder* builder,
49 PipelineDataGatherer* gatherer) {
50 builder->beginBlock(BuiltInCodeSnippetID::kPassthroughBlender);
51 }
52
53 //--------------------------------------------------------------------------------------------------
54
55 namespace {
56
add_solid_uniform_data(const ShaderCodeDictionary * dict,const SkPMColor4f & premulColor,PipelineDataGatherer * gatherer)57 void add_solid_uniform_data(const ShaderCodeDictionary* dict,
58 const SkPMColor4f& premulColor,
59 PipelineDataGatherer* gatherer) {
60 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kSolidColorShader)
61 gatherer->write(premulColor);
62
63 gatherer->addFlags(dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kSolidColorShader));
64 }
65
66 } // anonymous namespace
67
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const SkPMColor4f & premulColor)68 void SolidColorShaderBlock::BeginBlock(const KeyContext& keyContext,
69 PaintParamsKeyBuilder* builder,
70 PipelineDataGatherer* gatherer,
71 const SkPMColor4f& premulColor) {
72 if (gatherer) {
73 auto dict = keyContext.dict();
74
75 add_solid_uniform_data(dict, premulColor, gatherer);
76 }
77
78 builder->beginBlock(BuiltInCodeSnippetID::kSolidColorShader);
79 }
80
81 //--------------------------------------------------------------------------------------------------
82
83 namespace {
84 // All the gradients share a common postamble of:
85 // tilemode
86 // colorSpace
87 // doUnPremul
add_gradient_postamble(const GradientShaderBlocks::GradientData & gradData,PipelineDataGatherer * gatherer)88 void add_gradient_postamble(const GradientShaderBlocks::GradientData& gradData,
89 PipelineDataGatherer* gatherer) {
90 using ColorSpace = SkGradientShader::Interpolation::ColorSpace;
91
92 static_assert(static_cast<int>(ColorSpace::kLab) == 2);
93 static_assert(static_cast<int>(ColorSpace::kOKLab) == 3);
94 static_assert(static_cast<int>(ColorSpace::kLCH) == 4);
95 static_assert(static_cast<int>(ColorSpace::kOKLCH) == 5);
96 static_assert(static_cast<int>(ColorSpace::kHSL) == 7);
97 static_assert(static_cast<int>(ColorSpace::kHWB) == 8);
98
99 bool inputPremul = static_cast<bool>(gradData.fInterpolation.fInPremul);
100
101 gatherer->write(static_cast<int>(gradData.fTM));
102 gatherer->write(static_cast<int>(gradData.fInterpolation.fColorSpace));
103 gatherer->write(static_cast<int>(inputPremul));
104 }
105
add_linear_gradient_uniform_data(const ShaderCodeDictionary * dict,BuiltInCodeSnippetID codeSnippetID,const GradientShaderBlocks::GradientData & gradData,PipelineDataGatherer * gatherer)106 void add_linear_gradient_uniform_data(const ShaderCodeDictionary* dict,
107 BuiltInCodeSnippetID codeSnippetID,
108 const GradientShaderBlocks::GradientData& gradData,
109 PipelineDataGatherer* gatherer) {
110 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
111 size_t stops = codeSnippetID == BuiltInCodeSnippetID::kLinearGradientShader4 ? 4 : 8;
112
113 gatherer->writeArray({gradData.fColors, stops});
114 gatherer->writeArray({gradData.fOffsets, stops});
115 gatherer->write(gradData.fPoints[0]);
116 gatherer->write(gradData.fPoints[1]);
117 add_gradient_postamble(gradData, gatherer);
118
119 gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
120 };
121
add_radial_gradient_uniform_data(const ShaderCodeDictionary * dict,BuiltInCodeSnippetID codeSnippetID,const GradientShaderBlocks::GradientData & gradData,PipelineDataGatherer * gatherer)122 void add_radial_gradient_uniform_data(const ShaderCodeDictionary* dict,
123 BuiltInCodeSnippetID codeSnippetID,
124 const GradientShaderBlocks::GradientData& gradData,
125 PipelineDataGatherer* gatherer) {
126 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
127 size_t stops = codeSnippetID == BuiltInCodeSnippetID::kRadialGradientShader4 ? 4 : 8;
128
129 gatherer->writeArray({gradData.fColors, stops});
130 gatherer->writeArray({gradData.fOffsets, stops});
131 gatherer->write(gradData.fPoints[0]);
132 gatherer->write(gradData.fRadii[0]);
133 add_gradient_postamble(gradData, gatherer);
134
135 gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
136 };
137
add_sweep_gradient_uniform_data(const ShaderCodeDictionary * dict,BuiltInCodeSnippetID codeSnippetID,const GradientShaderBlocks::GradientData & gradData,PipelineDataGatherer * gatherer)138 void add_sweep_gradient_uniform_data(const ShaderCodeDictionary* dict,
139 BuiltInCodeSnippetID codeSnippetID,
140 const GradientShaderBlocks::GradientData& gradData,
141 PipelineDataGatherer* gatherer) {
142 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
143 size_t stops = codeSnippetID == BuiltInCodeSnippetID::kSweepGradientShader4 ? 4 : 8;
144
145 gatherer->writeArray({gradData.fColors, stops});
146 gatherer->writeArray({gradData.fOffsets, stops});
147 gatherer->write(gradData.fPoints[0]);
148 gatherer->write(gradData.fBias);
149 gatherer->write(gradData.fScale);
150 add_gradient_postamble(gradData, gatherer);
151
152 gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
153 };
154
add_conical_gradient_uniform_data(const ShaderCodeDictionary * dict,BuiltInCodeSnippetID codeSnippetID,const GradientShaderBlocks::GradientData & gradData,PipelineDataGatherer * gatherer)155 void add_conical_gradient_uniform_data(const ShaderCodeDictionary* dict,
156 BuiltInCodeSnippetID codeSnippetID,
157 const GradientShaderBlocks::GradientData& gradData,
158 PipelineDataGatherer* gatherer) {
159 VALIDATE_UNIFORMS(gatherer, dict, codeSnippetID)
160 size_t stops = codeSnippetID == BuiltInCodeSnippetID::kConicalGradientShader4 ? 4 : 8;
161
162 gatherer->writeArray({gradData.fColors, stops});
163 gatherer->writeArray({gradData.fOffsets, stops});
164 gatherer->write(gradData.fPoints[0]);
165 gatherer->write(gradData.fPoints[1]);
166 gatherer->write(gradData.fRadii[0]);
167 gatherer->write(gradData.fRadii[1]);
168 add_gradient_postamble(gradData, gatherer);
169
170 gatherer->addFlags(dict->getSnippetRequirementFlags(codeSnippetID));
171 };
172
173 } // anonymous namespace
174
GradientData(SkShaderBase::GradientType type,int numStops)175 GradientShaderBlocks::GradientData::GradientData(SkShaderBase::GradientType type, int numStops)
176 : fType(type)
177 , fPoints{{0.0f, 0.0f}, {0.0f, 0.0f}}
178 , fRadii{0.0f, 0.0f}
179 , fBias(0.0f)
180 , fScale(0.0f)
181 , fTM(SkTileMode::kClamp)
182 , fNumStops(numStops) {
183 sk_bzero(fColors, sizeof(fColors));
184 sk_bzero(fOffsets, sizeof(fOffsets));
185 }
186
GradientData(SkShaderBase::GradientType type,SkPoint point0,SkPoint point1,float radius0,float radius1,float bias,float scale,SkTileMode tm,int numStops,const SkPMColor4f * colors,float * offsets,const SkGradientShader::Interpolation & interp)187 GradientShaderBlocks::GradientData::GradientData(SkShaderBase::GradientType type,
188 SkPoint point0, SkPoint point1,
189 float radius0, float radius1,
190 float bias, float scale,
191 SkTileMode tm,
192 int numStops,
193 const SkPMColor4f* colors,
194 float* offsets,
195 const SkGradientShader::Interpolation& interp)
196 : fType(type)
197 , fBias(bias)
198 , fScale(scale)
199 , fTM(tm)
200 , fNumStops(std::min(numStops, kMaxStops))
201 , fInterpolation(interp) {
202 SkASSERT(fNumStops >= 1);
203
204 fPoints[0] = point0;
205 fPoints[1] = point1;
206 fRadii[0] = radius0;
207 fRadii[1] = radius1;
208 memcpy(fColors, colors, fNumStops * sizeof(SkColor4f));
209 if (offsets) {
210 memcpy(fOffsets, offsets, fNumStops * sizeof(float));
211 } else {
212 for (int i = 0; i < fNumStops; ++i) {
213 fOffsets[i] = SkIntToFloat(i) / (fNumStops-1);
214 }
215 }
216
217 // Extend the colors and offset, if necessary, to fill out the arrays
218 // TODO: this should be done later when the actual code snippet has been selected!!
219 for (int i = fNumStops ; i < kMaxStops; ++i) {
220 fColors[i] = fColors[fNumStops-1];
221 fOffsets[i] = fOffsets[fNumStops-1];
222 }
223 }
224
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const GradientData & gradData)225 void GradientShaderBlocks::BeginBlock(const KeyContext& keyContext,
226 PaintParamsKeyBuilder *builder,
227 PipelineDataGatherer* gatherer,
228 const GradientData& gradData) {
229 auto dict = keyContext.dict();
230 BuiltInCodeSnippetID codeSnippetID = BuiltInCodeSnippetID::kSolidColorShader;
231 switch (gradData.fType) {
232 case SkShaderBase::GradientType::kLinear:
233 codeSnippetID = gradData.fNumStops <= 4
234 ? BuiltInCodeSnippetID::kLinearGradientShader4
235 : BuiltInCodeSnippetID::kLinearGradientShader8;
236 if (gatherer) {
237 add_linear_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
238 }
239 break;
240 case SkShaderBase::GradientType::kRadial:
241 codeSnippetID = gradData.fNumStops <= 4
242 ? BuiltInCodeSnippetID::kRadialGradientShader4
243 : BuiltInCodeSnippetID::kRadialGradientShader8;
244 if (gatherer) {
245 add_radial_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
246 }
247 break;
248 case SkShaderBase::GradientType::kSweep:
249 codeSnippetID = gradData.fNumStops <= 4
250 ? BuiltInCodeSnippetID::kSweepGradientShader4
251 : BuiltInCodeSnippetID::kSweepGradientShader8;
252 if (gatherer) {
253 add_sweep_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
254 }
255 break;
256 case SkShaderBase::GradientType::kConical:
257 codeSnippetID = gradData.fNumStops <= 4
258 ? BuiltInCodeSnippetID::kConicalGradientShader4
259 : BuiltInCodeSnippetID::kConicalGradientShader8;
260 if (gatherer) {
261 add_conical_gradient_uniform_data(dict, codeSnippetID, gradData, gatherer);
262 }
263 break;
264 case SkShaderBase::GradientType::kColor:
265 case SkShaderBase::GradientType::kNone:
266 default:
267 SkASSERT(0);
268 break;
269 }
270
271 builder->beginBlock(codeSnippetID);
272 }
273
274 //--------------------------------------------------------------------------------------------------
275
276 namespace {
277
add_localmatrixshader_uniform_data(const ShaderCodeDictionary * dict,const SkM44 & localMatrix,PipelineDataGatherer * gatherer)278 void add_localmatrixshader_uniform_data(const ShaderCodeDictionary* dict,
279 const SkM44& localMatrix,
280 PipelineDataGatherer* gatherer) {
281 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kLocalMatrixShader)
282
283 SkM44 lmInverse;
284 bool wasInverted = localMatrix.invert(&lmInverse); // TODO: handle failure up stack
285 if (!wasInverted) {
286 lmInverse.setIdentity();
287 }
288
289 gatherer->write(lmInverse);
290
291 gatherer->addFlags(
292 dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kLocalMatrixShader));
293 }
294
295 } // anonymous namespace
296
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const LMShaderData * lmShaderData)297 void LocalMatrixShaderBlock::BeginBlock(const KeyContext& keyContext,
298 PaintParamsKeyBuilder* builder,
299 PipelineDataGatherer* gatherer,
300 const LMShaderData* lmShaderData) {
301 SkASSERT(!gatherer == !lmShaderData);
302
303 auto dict = keyContext.dict();
304 // When extracted into ShaderInfo::SnippetEntries the children will appear after their
305 // parent. Thus, the parent's uniform data must appear in the uniform block before the
306 // uniform data of the children.
307 if (gatherer) {
308 add_localmatrixshader_uniform_data(dict, lmShaderData->fLocalMatrix, gatherer);
309 }
310
311 builder->beginBlock(BuiltInCodeSnippetID::kLocalMatrixShader);
312 }
313
314 //--------------------------------------------------------------------------------------------------
315
316 namespace {
317
add_color_space_uniforms(const SkColorSpaceXformSteps & steps,PipelineDataGatherer * gatherer)318 void add_color_space_uniforms(const SkColorSpaceXformSteps& steps, PipelineDataGatherer* gatherer) {
319 static constexpr int kNumXferFnCoeffs = 7;
320
321 gatherer->write(SkTo<int>(steps.flags.mask()));
322 gatherer->write(SkTo<int>(skcms_TransferFunction_getType(&steps.srcTF)));
323 gatherer->write(SkTo<int>(skcms_TransferFunction_getType(&steps.dstTFInv)));
324 gatherer->writeHalfArray({&steps.srcTF.g, kNumXferFnCoeffs});
325 gatherer->writeHalfArray({&steps.dstTFInv.g, kNumXferFnCoeffs});
326
327 SkMatrix gamutTransform;
328 gamutTransform.set9(steps.src_to_dst_matrix);
329 gatherer->writeHalf(gamutTransform);
330 }
331
add_image_uniform_data(const ShaderCodeDictionary * dict,const ImageShaderBlock::ImageData & imgData,PipelineDataGatherer * gatherer)332 void add_image_uniform_data(const ShaderCodeDictionary* dict,
333 const ImageShaderBlock::ImageData& imgData,
334 PipelineDataGatherer* gatherer) {
335 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kImageShader)
336
337 gatherer->write(SkPoint::Make(imgData.fTextureProxy->dimensions().fWidth,
338 imgData.fTextureProxy->dimensions().fHeight));
339 gatherer->write(imgData.fSubset);
340 gatherer->write(SkTo<int>(imgData.fTileModes[0]));
341 gatherer->write(SkTo<int>(imgData.fTileModes[1]));
342 gatherer->write(SkTo<int>(imgData.fSampling.filter));
343 gatherer->write(imgData.fSampling.useCubic);
344 if (imgData.fSampling.useCubic) {
345 const SkCubicResampler& cubic = imgData.fSampling.cubic;
346 gatherer->write(SkImageShader::CubicResamplerMatrix(cubic.B, cubic.C));
347 } else {
348 gatherer->write(SkM44());
349 }
350 gatherer->write(SkTo<int>(imgData.fReadSwizzle));
351
352 add_color_space_uniforms(imgData.fSteps, gatherer);
353
354 gatherer->addFlags(dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kImageShader));
355 }
356
357 } // anonymous namespace
358
ImageData(const SkSamplingOptions & sampling,SkTileMode tileModeX,SkTileMode tileModeY,SkRect subset,ReadSwizzle readSwizzle)359 ImageShaderBlock::ImageData::ImageData(const SkSamplingOptions& sampling,
360 SkTileMode tileModeX,
361 SkTileMode tileModeY,
362 SkRect subset,
363 ReadSwizzle readSwizzle)
364 : fSampling(sampling)
365 , fTileModes{tileModeX, tileModeY}
366 , fSubset(subset)
367 , fReadSwizzle(readSwizzle) {
368 SkASSERT(fSteps.flags.mask() == 0); // By default, the colorspace should have no effect
369 }
370
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const ImageData * imgData)371 void ImageShaderBlock::BeginBlock(const KeyContext& keyContext,
372 PaintParamsKeyBuilder* builder,
373 PipelineDataGatherer* gatherer,
374 const ImageData* imgData) {
375 SkASSERT(!gatherer == !imgData);
376
377 // TODO: allow through lazy proxies
378 if (gatherer && !imgData->fTextureProxy) {
379 // TODO: At some point the pre-compile path should also be creating a texture
380 // proxy (i.e., we can remove the 'pipelineData' in the above test).
381 SolidColorShaderBlock::BeginBlock(keyContext, builder, gatherer, kErrorColor);
382 return;
383 }
384
385 auto dict = keyContext.dict();
386 if (gatherer) {
387 gatherer->add(imgData->fSampling,
388 imgData->fTileModes,
389 imgData->fTextureProxy);
390
391 add_image_uniform_data(dict, *imgData, gatherer);
392 }
393
394 builder->beginBlock(BuiltInCodeSnippetID::kImageShader);
395 }
396
397 //--------------------------------------------------------------------------------------------------
398
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const PorterDuffBlendShaderData & blendData)399 void PorterDuffBlendShaderBlock::BeginBlock(const KeyContext& keyContext,
400 PaintParamsKeyBuilder* builder,
401 PipelineDataGatherer* gatherer,
402 const PorterDuffBlendShaderData& blendData) {
403 auto dict = keyContext.dict();
404 // When extracted into ShaderInfo::SnippetEntries the children will appear after their
405 // parent. Thus, the parent's uniform data must appear in the uniform block before the
406 // uniform data of the children.
407 if (gatherer) {
408 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kPorterDuffBlendShader)
409 SkASSERT(blendData.fPorterDuffConstants.size() == 4);
410 gatherer->write(SkSLType::kHalf4, blendData.fPorterDuffConstants.data());
411 gatherer->addFlags(
412 dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kPorterDuffBlendShader));
413 }
414
415 builder->beginBlock(BuiltInCodeSnippetID::kPorterDuffBlendShader);
416 }
417
418 //--------------------------------------------------------------------------------------------------
419
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const BlendShaderData & blendData)420 void BlendShaderBlock::BeginBlock(const KeyContext& keyContext,
421 PaintParamsKeyBuilder* builder,
422 PipelineDataGatherer* gatherer,
423 const BlendShaderData& blendData) {
424 auto dict = keyContext.dict();
425 // When extracted into ShaderInfo::SnippetEntries the children will appear after their
426 // parent. Thus, the parent's uniform data must appear in the uniform block before the
427 // uniform data of the children.
428 if (gatherer) {
429 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kBlendShader)
430 gatherer->write(SkTo<int>(blendData.fBM));
431
432 gatherer->addFlags(dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kBlendShader));
433 }
434
435 builder->beginBlock(BuiltInCodeSnippetID::kBlendShader);
436 }
437
438 //--------------------------------------------------------------------------------------------------
439
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer)440 void ColorFilterShaderBlock::BeginBlock(const KeyContext& keyContext,
441 PaintParamsKeyBuilder* builder,
442 PipelineDataGatherer* gatherer) {
443 auto dict = keyContext.dict();
444
445 if (gatherer) {
446 gatherer->addFlags(
447 dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kColorFilterShader));
448 }
449
450 builder->beginBlock(BuiltInCodeSnippetID::kColorFilterShader);
451 }
452
453 //--------------------------------------------------------------------------------------------------
454
455 namespace {
456
add_matrix_colorfilter_uniform_data(const ShaderCodeDictionary * dict,const MatrixColorFilterBlock::MatrixColorFilterData & data,PipelineDataGatherer * gatherer)457 void add_matrix_colorfilter_uniform_data(const ShaderCodeDictionary* dict,
458 const MatrixColorFilterBlock::MatrixColorFilterData& data,
459 PipelineDataGatherer* gatherer) {
460 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kMatrixColorFilter)
461 gatherer->write(data.fMatrix);
462 gatherer->write(data.fTranslate);
463 gatherer->write(static_cast<int>(data.fInHSLA));
464
465 gatherer->addFlags(
466 dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kMatrixColorFilter));
467 }
468
469 } // anonymous namespace
470
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const MatrixColorFilterData * matrixCFData)471 void MatrixColorFilterBlock::BeginBlock(const KeyContext& keyContext,
472 PaintParamsKeyBuilder* builder,
473 PipelineDataGatherer* gatherer,
474 const MatrixColorFilterData* matrixCFData) {
475 SkASSERT(!gatherer == !matrixCFData);
476
477 auto dict = keyContext.dict();
478
479 if (gatherer) {
480 add_matrix_colorfilter_uniform_data(dict, *matrixCFData, gatherer);
481 }
482
483 builder->beginBlock(BuiltInCodeSnippetID::kMatrixColorFilter);
484 }
485
486 //--------------------------------------------------------------------------------------------------
487
488 namespace {
489
add_blend_colorfilter_uniform_data(const ShaderCodeDictionary * dict,const BlendColorFilterBlock::BlendColorFilterData & data,PipelineDataGatherer * gatherer)490 void add_blend_colorfilter_uniform_data(const ShaderCodeDictionary* dict,
491 const BlendColorFilterBlock::BlendColorFilterData& data,
492 PipelineDataGatherer* gatherer) {
493 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kBlendColorFilter)
494 gatherer->write(SkTo<int>(data.fBlendMode));
495 gatherer->write(data.fSrcColor);
496
497 gatherer->addFlags(dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kBlendColorFilter));
498 }
499
500 } // anonymous namespace
501
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const BlendColorFilterData * data)502 void BlendColorFilterBlock::BeginBlock(const KeyContext& keyContext,
503 PaintParamsKeyBuilder* builder,
504 PipelineDataGatherer* gatherer,
505 const BlendColorFilterData* data) {
506 auto dict = keyContext.dict();
507
508 if (gatherer) {
509 add_blend_colorfilter_uniform_data(dict, *data, gatherer);
510 }
511
512 builder->beginBlock(BuiltInCodeSnippetID::kBlendColorFilter);
513 }
514
515 //--------------------------------------------------------------------------------------------------
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer)516 void ComposeColorFilterBlock::BeginBlock(const KeyContext& keyContext,
517 PaintParamsKeyBuilder* builder,
518 PipelineDataGatherer* gatherer) {
519 builder->beginBlock(BuiltInCodeSnippetID::kComposeColorFilter);
520 }
521
522 //--------------------------------------------------------------------------------------------------
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer)523 void GaussianColorFilterBlock::BeginBlock(const KeyContext& keyContext,
524 PaintParamsKeyBuilder* builder,
525 PipelineDataGatherer* gatherer) {
526 builder->beginBlock(BuiltInCodeSnippetID::kGaussianColorFilter);
527 }
528
529 //--------------------------------------------------------------------------------------------------
530
531 namespace {
532
add_table_colorfilter_uniform_data(const ShaderCodeDictionary * dict,const TableColorFilterBlock::TableColorFilterData & data,PipelineDataGatherer * gatherer)533 void add_table_colorfilter_uniform_data(const ShaderCodeDictionary* dict,
534 const TableColorFilterBlock::TableColorFilterData& data,
535 PipelineDataGatherer* gatherer) {
536 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kTableColorFilter)
537
538 gatherer->addFlags(dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kTableColorFilter));
539 }
540
541 } // anonymous namespace
542
TableColorFilterData()543 TableColorFilterBlock::TableColorFilterData::TableColorFilterData() {}
544
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const TableColorFilterData & data)545 void TableColorFilterBlock::BeginBlock(const KeyContext& keyContext,
546 PaintParamsKeyBuilder* builder,
547 PipelineDataGatherer* gatherer,
548 const TableColorFilterData& data) {
549 auto dict = keyContext.dict();
550
551 if (gatherer) {
552 if (!data.fTextureProxy) {
553 // We're dropping the color filter here!
554 PassthroughShaderBlock::BeginBlock(keyContext, builder, gatherer);
555 return;
556 }
557
558 static const SkTileMode kTileModes[2] = { SkTileMode::kClamp, SkTileMode::kClamp };
559 gatherer->add(SkSamplingOptions(), kTileModes, data.fTextureProxy);
560
561 add_table_colorfilter_uniform_data(dict, data, gatherer);
562 }
563
564 builder->beginBlock(BuiltInCodeSnippetID::kTableColorFilter);
565 }
566
567 //--------------------------------------------------------------------------------------------------
568 namespace {
569
add_color_space_xform_uniform_data(const ShaderCodeDictionary * dict,const ColorSpaceTransformBlock::ColorSpaceTransformData * data,PipelineDataGatherer * gatherer)570 void add_color_space_xform_uniform_data(
571 const ShaderCodeDictionary* dict,
572 const ColorSpaceTransformBlock::ColorSpaceTransformData* data,
573 PipelineDataGatherer* gatherer) {
574
575 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kColorSpaceXformColorFilter)
576 add_color_space_uniforms(data->fSteps, gatherer);
577
578 gatherer->addFlags(
579 dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kColorSpaceXformColorFilter));
580 }
581
582 } // anonymous namespace
583
ColorSpaceTransformData(const SkColorSpace * src,SkAlphaType srcAT,const SkColorSpace * dst,SkAlphaType dstAT)584 ColorSpaceTransformBlock::ColorSpaceTransformData::ColorSpaceTransformData(const SkColorSpace* src,
585 SkAlphaType srcAT,
586 const SkColorSpace* dst,
587 SkAlphaType dstAT)
588 : fSteps(src, srcAT, dst, dstAT) {}
589
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const ColorSpaceTransformData * data)590 void ColorSpaceTransformBlock::BeginBlock(const KeyContext& keyContext,
591 PaintParamsKeyBuilder* builder,
592 PipelineDataGatherer* gatherer,
593 const ColorSpaceTransformData* data) {
594 if (gatherer) {
595 add_color_space_xform_uniform_data(keyContext.dict(), data, gatherer);
596 }
597 builder->beginBlock(BuiltInCodeSnippetID::kColorSpaceXformColorFilter);
598 }
599
600 //--------------------------------------------------------------------------------------------------
601 namespace {
602
make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,skgpu::BlendCoeff dstCoeff)603 constexpr skgpu::BlendInfo make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,
604 skgpu::BlendCoeff dstCoeff) {
605 return { skgpu::BlendEquation::kAdd,
606 srcCoeff,
607 dstCoeff,
608 SK_PMColor4fTRANSPARENT,
609 skgpu::BlendModifiesDst(skgpu::BlendEquation::kAdd, srcCoeff, dstCoeff) };
610 }
611
612 static constexpr int kNumCoeffModes = (int)SkBlendMode::kLastCoeffMode + 1;
613 /*>> No coverage, input color unknown <<*/
614 static constexpr skgpu::BlendInfo gBlendTable[kNumCoeffModes] = {
615 /* clear */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kZero),
616 /* src */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kZero),
617 /* dst */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
618 /* src-over */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISA),
619 /* dst-over */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kOne),
620 /* src-in */ make_simple_blendInfo(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kZero),
621 /* dst-in */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSA),
622 /* src-out */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kZero),
623 /* dst-out */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kISA),
624 /* src-atop */ make_simple_blendInfo(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kISA),
625 /* dst-atop */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kSA),
626 /* xor */ make_simple_blendInfo(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kISA),
627 /* plus */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kOne),
628 /* modulate */ make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSC),
629 /* screen */ make_simple_blendInfo(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISC)
630 };
631
get_blend_info(SkBlendMode bm)632 const skgpu::BlendInfo& get_blend_info(SkBlendMode bm) {
633 if (bm <= SkBlendMode::kLastCoeffMode) {
634 return gBlendTable[(int) bm];
635 }
636
637 return gBlendTable[(int) SkBlendMode::kSrc];
638 }
639
add_shaderbasedblender_uniform_data(const ShaderCodeDictionary * dict,SkBlendMode bm,PipelineDataGatherer * gatherer)640 void add_shaderbasedblender_uniform_data(const ShaderCodeDictionary* dict,
641 SkBlendMode bm,
642 PipelineDataGatherer* gatherer) {
643 VALIDATE_UNIFORMS(gatherer, dict, BuiltInCodeSnippetID::kShaderBasedBlender)
644 gatherer->write(SkTo<int>(bm));
645
646 gatherer->addFlags(
647 dict->getSnippetRequirementFlags(BuiltInCodeSnippetID::kShaderBasedBlender));
648 }
649
650 } // anonymous namespace
651
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,SkBlendMode bm)652 void BlendModeBlock::BeginBlock(const KeyContext& keyContext,
653 PaintParamsKeyBuilder *builder,
654 PipelineDataGatherer* gatherer,
655 SkBlendMode bm) {
656
657 auto dict = keyContext.dict();
658
659 if (bm <= SkBlendMode::kLastCoeffMode) {
660 builder->setBlendInfo(get_blend_info(bm));
661
662 builder->beginBlock(BuiltInCodeSnippetID::kFixedFunctionBlender);
663 static_assert(SkTFitsIn<uint8_t>(SkBlendMode::kLastMode));
664 builder->addByte(static_cast<uint8_t>(bm));
665 } else {
666 // TODO: set up the correct blend info
667 builder->setBlendInfo({});
668
669 if (gatherer) {
670 add_shaderbasedblender_uniform_data(dict, bm, gatherer);
671 }
672
673 builder->beginBlock(BuiltInCodeSnippetID::kShaderBasedBlender);
674 }
675 }
676
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,SkBlendMode bm)677 void PrimitiveBlendModeBlock::BeginBlock(const KeyContext& keyContext,
678 PaintParamsKeyBuilder *builder,
679 PipelineDataGatherer* gatherer,
680 SkBlendMode bm) {
681 auto dict = keyContext.dict();
682 // Unlike in the usual blendmode case, the primitive blend mode will always be implemented
683 // via shader-based blending.
684 if (gatherer) {
685 add_shaderbasedblender_uniform_data(dict, bm, gatherer);
686 }
687 builder->beginBlock(BuiltInCodeSnippetID::kPrimitiveColorShaderBasedBlender);
688 }
689
ShaderData(sk_sp<const SkRuntimeEffect> effect)690 RuntimeEffectBlock::ShaderData::ShaderData(sk_sp<const SkRuntimeEffect> effect)
691 : fEffect(std::move(effect)) {}
692
ShaderData(sk_sp<const SkRuntimeEffect> effect,sk_sp<const SkData> uniforms)693 RuntimeEffectBlock::ShaderData::ShaderData(sk_sp<const SkRuntimeEffect> effect,
694 sk_sp<const SkData> uniforms)
695 : fEffect(std::move(effect))
696 , fUniforms(std::move(uniforms)) {}
697
skdata_matches(const SkData * a,const SkData * b)698 static bool skdata_matches(const SkData* a, const SkData* b) {
699 // Returns true if both SkData objects hold the same contents, or if they are both null.
700 // (SkData::equals supports passing null, and returns false.)
701 return a ? a->equals(b) : (a == b);
702 }
703
operator ==(const ShaderData & rhs) const704 bool RuntimeEffectBlock::ShaderData::operator==(const ShaderData& rhs) const {
705 return fEffect == rhs.fEffect && skdata_matches(fUniforms.get(), rhs.fUniforms.get());
706 }
707
gather_runtime_effect_uniforms(SkSpan<const SkRuntimeEffect::Uniform> rtsUniforms,SkSpan<const Uniform> graphiteUniforms,const SkData * uniformData,PipelineDataGatherer * gatherer)708 static void gather_runtime_effect_uniforms(SkSpan<const SkRuntimeEffect::Uniform> rtsUniforms,
709 SkSpan<const Uniform> graphiteUniforms,
710 const SkData* uniformData,
711 PipelineDataGatherer* gatherer) {
712 // Collect all the other uniforms from the provided SkData.
713 const uint8_t* uniformBase = uniformData->bytes();
714 for (size_t index = 0; index < rtsUniforms.size(); ++index) {
715 const Uniform& uniform = graphiteUniforms[index];
716 // Get a pointer to the offset in our data for this uniform.
717 const uint8_t* uniformPtr = uniformBase + rtsUniforms[index].offset;
718 // Pass the uniform data to the gatherer.
719 gatherer->write(uniform, uniformPtr);
720 }
721 }
722
BeginBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,const ShaderData & shaderData)723 void RuntimeEffectBlock::BeginBlock(const KeyContext& keyContext,
724 PaintParamsKeyBuilder* builder,
725 PipelineDataGatherer* gatherer,
726 const ShaderData& shaderData) {
727 ShaderCodeDictionary* dict = keyContext.dict();
728 int codeSnippetID = dict->findOrCreateRuntimeEffectSnippet(shaderData.fEffect.get());
729
730 keyContext.rtEffectDict()->set(codeSnippetID, shaderData.fEffect);
731
732 if (gatherer) {
733 const ShaderSnippet* entry = dict->getEntry(codeSnippetID);
734 SkASSERT(entry);
735
736 SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, entry->fUniforms);)
737 gatherer->addFlags(entry->fSnippetRequirementFlags);
738
739 gather_runtime_effect_uniforms(shaderData.fEffect->uniforms(),
740 entry->fUniforms,
741 shaderData.fUniforms.get(),
742 gatherer);
743 }
744
745 builder->beginBlock(codeSnippetID);
746 }
747
748 } // namespace skgpu::graphite
749