• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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