• 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/ShaderCodeDictionary.h"
9 
10 #include "include/core/SkSamplingOptions.h"
11 #include "include/core/SkTileMode.h"
12 #include "include/effects/SkRuntimeEffect.h"
13 #include "include/gpu/graphite/Context.h"
14 #include "src/core/SkColorSpacePriv.h"
15 #include "src/core/SkColorSpaceXformSteps.h"
16 #include "src/core/SkRuntimeEffectPriv.h"
17 #include "src/core/SkSLTypeShared.h"
18 #include "src/gpu/BlendFormula.h"
19 #include "src/gpu/Swizzle.h"
20 #include "src/gpu/graphite/Caps.h"
21 #include "src/gpu/graphite/ContextUtils.h"
22 #include "src/gpu/graphite/ReadSwizzle.h"
23 #include "src/gpu/graphite/Renderer.h"
24 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
25 #include "src/sksl/SkSLString.h"
26 #include "src/sksl/SkSLUtil.h"
27 #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
28 #include "src/sksl/ir/SkSLVarDeclarations.h"
29 
30 #include <new>
31 
32 using namespace skia_private;
33 using namespace SkKnownRuntimeEffects;
34 
35 namespace skgpu::graphite {
36 
37 static constexpr int kNoChildren = 0;
38 static constexpr char kRuntimeShaderName[] = "RuntimeEffect";
39 
40 static_assert(static_cast<int>(BuiltInCodeSnippetID::kLast) < kSkiaBuiltInReservedCnt);
41 
42 // The toLinearSrgb and fromLinearSrgb RuntimeEffect intrinsics need to be able to map to and
43 // from the dst color space and linearSRGB. These are the 10 uniforms needed to allow that.
44 // These boil down to two copies of the kColorSpaceTransformUniforms uniforms. The first set
45 // for mapping to LinearSRGB and the second set for mapping from LinearSRGB.
46 static constexpr Uniform kRuntimeEffectColorSpaceTransformUniforms[] = {
47         // to LinearSRGB
48         { "flags_toLinear",          SkSLType::kInt },
49         { "srcKind_toLinear",        SkSLType::kInt },
50         { "gamutTransform_toLinear", SkSLType::kHalf3x3 },
51         { "dstKind_toLinear",        SkSLType::kInt },
52         { "csXformCoeffs_toLinear",  SkSLType::kHalf4x4 },
53         // from LinearSRGB
54         { "flags_fromLinear",          SkSLType::kInt },
55         { "srcKind_fromLinear",        SkSLType::kInt },
56         { "gamutTransform_fromLinear", SkSLType::kHalf3x3 },
57         { "dstKind_fromLinear",        SkSLType::kInt },
58         { "csXformCoeffs_fromLinear",  SkSLType::kHalf4x4 },
59 };
60 
61 namespace {
62 
get_known_rte_name(StableKey key)63 const char* get_known_rte_name(StableKey key) {
64     switch (key) {
65 #define M(type) case StableKey::k##type : return "KnownRuntimeEffect_" #type;
66 #define M1(type)
67 #define M2(type, initializer) case StableKey::k##type : return "KnownRuntimeEffect_" #type;
68         SK_ALL_STABLEKEYS(M, M1, M2)
69 #undef M2
70 #undef M1
71 #undef M
72     }
73 
74     SkUNREACHABLE;
75 }
76 
get_mangled_name(const std::string & baseName,int manglingSuffix)77 std::string get_mangled_name(const std::string& baseName, int manglingSuffix) {
78     return baseName + "_" + std::to_string(manglingSuffix);
79 }
80 
get_mangled_uniform_name(const ShaderInfo & shaderInfo,const Uniform & uniform,int manglingSuffix)81 std::string get_mangled_uniform_name(const ShaderInfo& shaderInfo,
82                                      const Uniform& uniform,
83                                      int manglingSuffix) {
84     std::string result;
85 
86     if (uniform.isPaintColor()) {
87         // Due to deduplication there will only ever be one of these
88         result = uniform.name();
89     } else {
90         result = uniform.name() + std::string("_") + std::to_string(manglingSuffix);
91     }
92     if (shaderInfo.ssboIndex()) {
93         result = EmitStorageBufferAccess("fs", shaderInfo.ssboIndex(), result.c_str());
94     }
95     return result;
96 }
97 
get_mangled_sampler_name(const TextureAndSampler & tex,int manglingSuffix)98 std::string get_mangled_sampler_name(const TextureAndSampler& tex, int manglingSuffix) {
99     return tex.name() + std::string("_") + std::to_string(manglingSuffix);
100 }
101 
102 // Returns an expression to invoke this entry.
emit_expression_for_entry(const ShaderInfo & shaderInfo,const ShaderNode * node,ShaderSnippet::Args args)103 std::string emit_expression_for_entry(const ShaderInfo& shaderInfo,
104                                       const ShaderNode* node,
105                                       ShaderSnippet::Args args) {
106     return node->entry()->fExpressionGenerator(shaderInfo, node, args);
107 }
108 
109 // Emit the glue code needed to invoke a single static helper isolated within its own scope.
110 // Glue code will assign the resulting color into a variable `half4 outColor%d`, where the %d is
111 // filled in with 'node->keyIndex()'.
emit_glue_code_for_entry(const ShaderInfo & shaderInfo,const ShaderNode * node,const ShaderSnippet::Args & args,std::string * funcBody)112 std::string emit_glue_code_for_entry(const ShaderInfo& shaderInfo,
113                                      const ShaderNode* node,
114                                      const ShaderSnippet::Args& args,
115                                      std::string* funcBody) {
116     std::string expr = emit_expression_for_entry(shaderInfo, node, args);
117     std::string outputVar = get_mangled_name("outColor", node->keyIndex());
118     SkSL::String::appendf(funcBody,
119                           "// [%d] %s\n"
120                           "half4 %s = %s;",
121                           node->keyIndex(),
122                           node->entry()->fName,
123                           outputVar.c_str(),
124                           expr.c_str());
125     return outputVar;
126 }
127 
128 // Walk the node tree and generate all preambles, accumulating into 'preamble'.
emit_preambles(const ShaderInfo & shaderInfo,SkSpan<const ShaderNode * > nodes,std::string treeLabel,std::string * preamble)129 void emit_preambles(const ShaderInfo& shaderInfo,
130                     SkSpan<const ShaderNode*> nodes,
131                     std::string treeLabel,
132                     std::string* preamble) {
133     for (int i = 0; i < SkTo<int>(nodes.size()); ++i) {
134         const ShaderNode* node = nodes[i];
135         std::string nodeLabel = std::to_string(i);
136         std::string nextLabel = treeLabel.empty() ? nodeLabel
137                                                   : (treeLabel + "<-" + nodeLabel);
138 
139         if (node->numChildren() > 0) {
140             emit_preambles(shaderInfo, node->children(), nextLabel, preamble);
141         }
142 
143         std::string nodePreamble = node->entry()->fPreambleGenerator(shaderInfo, node);
144         if (!nodePreamble.empty()) {
145             SkSL::String::appendf(preamble,
146                                 "// [%d]   %s: %s\n"
147                                 "%s\n",
148                                 node->keyIndex(), nextLabel.c_str(), node->entry()->fName,
149                                 nodePreamble.c_str());
150         }
151     }
152 }
153 
make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,skgpu::BlendCoeff dstCoeff)154 constexpr skgpu::BlendInfo make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,
155                                                  skgpu::BlendCoeff dstCoeff) {
156     return { skgpu::BlendEquation::kAdd,
157              srcCoeff,
158              dstCoeff,
159              SK_PMColor4fTRANSPARENT,
160              skgpu::BlendModifiesDst(skgpu::BlendEquation::kAdd, srcCoeff, dstCoeff) };
161 }
162 
163 static constexpr int kNumCoeffModes = (int)SkBlendMode::kLastCoeffMode + 1;
164 static constexpr skgpu::BlendInfo gBlendTable[kNumCoeffModes] = {
165         /* clear */      make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kZero),
166         /* src */        make_simple_blendInfo(skgpu::BlendCoeff::kOne,  skgpu::BlendCoeff::kZero),
167         /* dst */        make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
168         /* src-over */   make_simple_blendInfo(skgpu::BlendCoeff::kOne,  skgpu::BlendCoeff::kISA),
169         /* dst-over */   make_simple_blendInfo(skgpu::BlendCoeff::kIDA,  skgpu::BlendCoeff::kOne),
170         /* src-in */     make_simple_blendInfo(skgpu::BlendCoeff::kDA,   skgpu::BlendCoeff::kZero),
171         /* dst-in */     make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSA),
172         /* src-out */    make_simple_blendInfo(skgpu::BlendCoeff::kIDA,  skgpu::BlendCoeff::kZero),
173         /* dst-out */    make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kISA),
174         /* src-atop */   make_simple_blendInfo(skgpu::BlendCoeff::kDA,   skgpu::BlendCoeff::kISA),
175         /* dst-atop */   make_simple_blendInfo(skgpu::BlendCoeff::kIDA,  skgpu::BlendCoeff::kSA),
176         /* xor */        make_simple_blendInfo(skgpu::BlendCoeff::kIDA,  skgpu::BlendCoeff::kISA),
177         /* plus */       make_simple_blendInfo(skgpu::BlendCoeff::kOne,  skgpu::BlendCoeff::kOne),
178         /* modulate */   make_simple_blendInfo(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSC),
179         /* screen */     make_simple_blendInfo(skgpu::BlendCoeff::kOne,  skgpu::BlendCoeff::kISC)
180 };
181 
182 } // anonymous namespace
183 
184 //--------------------------------------------------------------------------------------------------
185 // ShaderInfo
186 
ShaderInfo(UniquePaintParamsID id,const ShaderCodeDictionary * dict,const RuntimeEffectDictionary * rteDict,const char * ssboIndex)187 ShaderInfo::ShaderInfo(UniquePaintParamsID id,
188                        const ShaderCodeDictionary* dict,
189                        const RuntimeEffectDictionary* rteDict,
190                        const char* ssboIndex)
191         : fRuntimeEffectDictionary(rteDict)
192         , fSsboIndex(ssboIndex)
193         , fSnippetRequirementFlags(SnippetRequirementFlags::kNone) {
194     PaintParamsKey key = dict->lookup(id);
195     SkASSERT(key.isValid()); // invalid keys should have been caught by invalid paint ID earlier
196 
197     fRootNodes = key.getRootNodes(dict, &fShaderNodeAlloc);
198     // Aggregate snippet requirements across root nodes and look for fixed-function blend IDs in
199     // the root to initialize the HW blend info.
200     SkDEBUGCODE(bool fixedFuncBlendFound = false;)
201     for (const ShaderNode* root : fRootNodes) {
202         // TODO: This is brittle as it relies on PaintParams::toKey() putting the final fixed
203         // function blend block at the root level. This can be improved with more structure to the
204         // key creation.
205         if (root->codeSnippetId() < kBuiltInCodeSnippetIDCount &&
206             root->codeSnippetId() >= kFixedFunctionBlendModeIDOffset) {
207             SkASSERT(root->numChildren() == 0);
208             // This should occur at most once
209             SkASSERT(!fixedFuncBlendFound);
210             SkDEBUGCODE(fixedFuncBlendFound = true;)
211 
212             fBlendMode = static_cast<SkBlendMode>(root->codeSnippetId() -
213                                                   kFixedFunctionBlendModeIDOffset);
214             SkASSERT(static_cast<int>(fBlendMode) >= 0 &&
215                      fBlendMode <= SkBlendMode::kLastCoeffMode);
216             fBlendInfo = gBlendTable[static_cast<int>(fBlendMode)];
217         } else {
218             fSnippetRequirementFlags |= root->requiredFlags();
219         }
220     }
221 }
222 
append_color_output(std::string * mainBody,BlendFormula::OutputType outputType,const char * outColor,const char * inColor)223 void append_color_output(std::string* mainBody,
224                          BlendFormula::OutputType outputType,
225                          const char* outColor,
226                          const char* inColor) {
227     switch (outputType) {
228         case BlendFormula::kNone_OutputType:
229             SkSL::String::appendf(mainBody, "%s = half4(0.0);", outColor);
230             break;
231         case BlendFormula::kCoverage_OutputType:
232             SkSL::String::appendf(mainBody, "%s = outputCoverage;", outColor);
233             break;
234         case BlendFormula::kModulate_OutputType:
235             SkSL::String::appendf(mainBody, "%s = %s * outputCoverage;", outColor, inColor);
236             break;
237         case BlendFormula::kSAModulate_OutputType:
238             SkSL::String::appendf(mainBody, "%s = %s.a * outputCoverage;", outColor, inColor);
239             break;
240         case BlendFormula::kISAModulate_OutputType:
241             SkSL::String::appendf(
242                     mainBody, "%s = (1.0 - %s.a) * outputCoverage;", outColor, inColor);
243             break;
244         case BlendFormula::kISCModulate_OutputType:
245             SkSL::String::appendf(
246                     mainBody, "%s = (half4(1.0) - %s) * outputCoverage;", outColor, inColor);
247             break;
248         default:
249             SkUNREACHABLE;
250             break;
251     }
252 }
253 
254 // The current, incomplete, model for shader construction is:
255 //   - Static code snippets (which can have an arbitrary signature) live in the Graphite
256 //     pre-compiled modules, which are located at `src/sksl/sksl_graphite_frag.sksl` and
257 //     `src/sksl/sksl_graphite_frag_es2.sksl`.
258 //   - Glue code is generated in a `main` method which calls these static code snippets.
259 //     The glue code is responsible for:
260 //            1) gathering the correct (mangled) uniforms
261 //            2) passing the uniforms and any other parameters to the helper method
262 //   - The result of the final code snippet is then copied into "sk_FragColor".
263 //   Note: each entry's 'fStaticFunctionName' field is expected to match the name of a function
264 //   in the Graphite pre-compiled module.
toSkSL(const Caps * caps,const RenderStep * step,bool useStorageBuffers,int * numTexturesAndSamplersUsed,int * numPaintUniforms,int * renderStepUniformTotalBytes,int * paintUniformsTotalBytes,bool * hasGradientBuffer,Swizzle writeSwizzle)265 std::string ShaderInfo::toSkSL(const Caps* caps,
266                                const RenderStep* step,
267                                bool useStorageBuffers,
268                                int* numTexturesAndSamplersUsed,
269                                int* numPaintUniforms,
270                                int* renderStepUniformTotalBytes,
271                                int* paintUniformsTotalBytes,
272                                bool* hasGradientBuffer,
273                                Swizzle writeSwizzle) {
274     // If we're doing analytic coverage, we must also be doing shading.
275     SkASSERT(step->coverage() == Coverage::kNone || step->performsShading());
276     const bool hasStepUniforms = step->numUniforms() > 0 && step->coverage() != Coverage::kNone;
277     const bool useStepStorageBuffer = useStorageBuffers && hasStepUniforms;
278     const bool useShadingStorageBuffer = useStorageBuffers && step->performsShading();
279     const bool useGradientStorageBuffer = useStorageBuffers && (fSnippetRequirementFlags
280                                                     & SnippetRequirementFlags::kGradientBuffer);
281 
282     const bool defineLocalCoordsVarying = this->needsLocalCoords();
283     std::string preamble = EmitVaryings(step,
284                                         /*direction=*/"in",
285                                         /*emitSsboIndicesVarying=*/useShadingStorageBuffer,
286                                         defineLocalCoordsVarying);
287 
288     // The uniforms are mangled by having their index in 'fEntries' as a suffix (i.e., "_%d")
289     // TODO: replace hard-coded bufferIDs with the backend's step and paint uniform-buffer indices.
290     // TODO: The use of these indices is Metal-specific. We should replace these functions with
291     // API-independent ones.
292     const ResourceBindingRequirements& bindingReqs = caps->resourceBindingRequirements();
293     if (hasStepUniforms) {
294         if (useStepStorageBuffer) {
295             preamble += EmitRenderStepStorageBuffer(/*bufferID=*/1, step->uniforms());
296         } else {
297             preamble += EmitRenderStepUniforms(/*bufferID=*/1,
298                                                bindingReqs.fUniformBufferLayout,
299                                                step->uniforms(),
300                                                renderStepUniformTotalBytes);
301         }
302     }
303 
304     bool wrotePaintColor = false;
305     if (useShadingStorageBuffer) {
306         preamble += EmitPaintParamsStorageBuffer(/*bufferID=*/2,
307                                                  fRootNodes,
308                                                  numPaintUniforms,
309                                                  &wrotePaintColor);
310         SkSL::String::appendf(&preamble, "uint %s;\n", this->ssboIndex());
311     } else {
312         preamble += EmitPaintParamsUniforms(/*bufferID=*/2,
313                                             bindingReqs.fUniformBufferLayout,
314                                             fRootNodes,
315                                             numPaintUniforms,
316                                             paintUniformsTotalBytes,
317                                             &wrotePaintColor);
318     }
319 
320     if (useGradientStorageBuffer) {
321         SkASSERT(caps->storageBufferSupport());
322 
323         // In metal the vertex and instance buffer occupy slots 3 and 4 so we use slot 5 in that
324         // case. In dawn and vulkan that is not the case so we can occupy slot 3, and those two
325         // apis also do separate texture/sampler bindings.
326         int binding = bindingReqs.fSeparateTextureAndSamplerBinding ? 3 : 5;
327         SkSL::String::appendf(&preamble,
328                               "layout (binding=%d) readonly buffer FSGradientBuffer {\n"
329                               "    float fsGradientBuffer[];\n"
330                               "};\n", binding);
331         *hasGradientBuffer = true;
332     }
333 
334     {
335         int binding = 0;
336         preamble += EmitTexturesAndSamplers(bindingReqs, fRootNodes, &binding);
337         if (step->hasTextures()) {
338             preamble += step->texturesAndSamplersSkSL(bindingReqs, &binding);
339         }
340 
341         // Report back to the caller how many textures and samplers are used.
342         if (numTexturesAndSamplersUsed) {
343             *numTexturesAndSamplersUsed = binding;
344         }
345     }
346 
347     if (step->emitsPrimitiveColor()) {
348         // TODO: Define this in the main body, and then pass it down into snippets like we do with
349         // the local coordinates varying.
350         preamble += "half4 primitiveColor;";
351     }
352 
353     // Emit preamble declarations and helper functions required for snippets. In the default case
354     // this adds functions that bind a node's specific mangled uniforms to the snippet's
355     // implementation in the SkSL modules.
356     emit_preambles(*this, fRootNodes, /*treeLabel=*/"", &preamble);
357 
358     std::string mainBody = "void main() {";
359     // Set initial color. This will typically be optimized out by SkSL in favor of the paint
360     // specifying a color with a solid color shader.
361     mainBody += "half4 initialColor = half4(0);";
362 
363     if (useShadingStorageBuffer) {
364         SkSL::String::appendf(&mainBody,
365                               "%s = %s.y;\n",
366                               this->ssboIndex(),
367                               RenderStep::ssboIndicesVarying());
368     }
369 
370     if (step->emitsPrimitiveColor()) {
371         mainBody += step->fragmentColorSkSL();
372     }
373 
374     // While looping through root nodes to emit shader code, skip the clip shader node if it's found
375     // and keep it to apply later during coverage calculation.
376     const ShaderNode* clipShaderNode = nullptr;
377 
378     // Emit shader main body code, invoking each root node's expression, forwarding the previous
379     // node's output to the next.
380     static constexpr char kUnusedDstColor[] = "half4(1)";
381     static constexpr char kUnusedLocalCoords[] = "float2(0)";
382     ShaderSnippet::Args args = {"initialColor",
383                                 kUnusedDstColor,
384                                 this->needsLocalCoords() ? "localCoordsVar" : kUnusedLocalCoords};
385     for (const ShaderNode* node : fRootNodes) {
386         if (node->codeSnippetId() == (int) BuiltInCodeSnippetID::kClipShader) {
387             SkASSERT(!clipShaderNode);
388             clipShaderNode = node;
389             continue;
390         }
391         // This exclusion of the final Blend can be removed once we've resolved the final
392         // blend parenting issue w/in the key
393         if (node->codeSnippetId() >= kBuiltInCodeSnippetIDCount ||
394             node->codeSnippetId() < kFixedFunctionBlendModeIDOffset) {
395             args.fPriorStageOutput = emit_glue_code_for_entry(*this, node, args, &mainBody);
396         }
397     }
398 
399     if (writeSwizzle != Swizzle::RGBA()) {
400         SkSL::String::appendf(&mainBody, "%s = %s.%s;", args.fPriorStageOutput.c_str(),
401                                                         args.fPriorStageOutput.c_str(),
402                                                         writeSwizzle.asString().c_str());
403     }
404 
405     const char* outColor = args.fPriorStageOutput.c_str();
406     const Coverage coverage = step->coverage();
407     if (coverage != Coverage::kNone || clipShaderNode) {
408         if (useStepStorageBuffer) {
409             SkSL::String::appendf(&mainBody,
410                                   "uint stepSsboIndex = %s.x;\n",
411                                   RenderStep::ssboIndicesVarying());
412             mainBody += EmitUniformsFromStorageBuffer("step", "stepSsboIndex", step->uniforms());
413         }
414 
415         mainBody += "half4 outputCoverage = half4(1);";
416         mainBody += step->fragmentCoverageSkSL();
417 
418         if (clipShaderNode) {
419             std::string clipShaderOutput =
420                     emit_glue_code_for_entry(*this, clipShaderNode, args, &mainBody);
421             SkSL::String::appendf(&mainBody, "outputCoverage *= %s.a;", clipShaderOutput.c_str());
422         }
423 
424         // TODO: Determine whether draw is opaque and pass that to GetBlendFormula.
425         BlendFormula coverageBlendFormula =
426                 coverage == Coverage::kLCD
427                         ? skgpu::GetLCDBlendFormula(fBlendMode)
428                         : skgpu::GetBlendFormula(
429                                   /*isOpaque=*/false, /*hasCoverage=*/true, fBlendMode);
430 
431         if (this->needsSurfaceColor()) {
432             // If this draw uses a non-coherent dst read, we want to keep the existing dst color (or
433             // whatever has been previously drawn) when there's no coverage. This helps for batching
434             // text draws that need to read from a dst copy for blends. However, this only helps the
435             // case where the outer bounding boxes of each letter overlap and not two actual parts
436             // of the text.
437             DstReadRequirement dstReadReq = caps->getDstReadRequirement();
438             if (dstReadReq == DstReadRequirement::kTextureCopy ||
439                 dstReadReq == DstReadRequirement::kTextureSample) {
440                 // We don't think any shaders actually output negative coverage, but just as a
441                 // safety check for floating point precision errors, we compare with <= here. We
442                 // just check the RGB values of the coverage, since the alpha may not have been set
443                 // when using LCD. If we are using single-channel coverage, alpha will be equal to
444                 // RGB anyway.
445                 mainBody +=
446                     "if (all(lessThanEqual(outputCoverage.rgb, half3(0)))) {"
447                         "discard;"
448                     "}";
449             }
450 
451             // Use originally-specified BlendInfo and blend with dst manually.
452             SkSL::String::appendf(
453                     &mainBody,
454                     "sk_FragColor = %s * outputCoverage + surfaceColor * (1.0 - outputCoverage);",
455                     outColor);
456             if (coverage == Coverage::kLCD) {
457                 SkSL::String::appendf(
458                         &mainBody,
459                         "half3 lerpRGB = mix(surfaceColor.aaa, %s.aaa, outputCoverage.rgb);"
460                         "sk_FragColor.a = max(max(lerpRGB.r, lerpRGB.g), lerpRGB.b);",
461                         outColor);
462             }
463 
464         } else {
465             fBlendInfo = {coverageBlendFormula.equation(),
466                           coverageBlendFormula.srcCoeff(),
467                           coverageBlendFormula.dstCoeff(),
468                           SK_PMColor4fTRANSPARENT,
469                           coverageBlendFormula.modifiesDst()};
470 
471             if (coverage == Coverage::kLCD) {
472                 mainBody += "outputCoverage.a = max(max(outputCoverage.r, "
473                                                        "outputCoverage.g), "
474                                                    "outputCoverage.b);";
475             }
476             append_color_output(
477                     &mainBody, coverageBlendFormula.primaryOutput(), "sk_FragColor", outColor);
478             if (coverageBlendFormula.hasSecondaryOutput()) {
479                 append_color_output(&mainBody,
480                                     coverageBlendFormula.secondaryOutput(),
481                                     "sk_SecondaryFragColor",
482                                     outColor);
483             }
484         }
485 
486     } else {
487         SkSL::String::appendf(&mainBody, "sk_FragColor = %s;", outColor);
488     }
489     mainBody += "}\n";
490 
491     return preamble + "\n" + mainBody;
492 }
493 
494 //--------------------------------------------------------------------------------------------------
495 // ShaderCodeDictionary
496 
findOrCreate(PaintParamsKeyBuilder * builder)497 UniquePaintParamsID ShaderCodeDictionary::findOrCreate(PaintParamsKeyBuilder* builder) {
498     AutoLockBuilderAsKey keyView{builder};
499     if (!keyView->isValid()) {
500         return UniquePaintParamsID::InvalidID();
501     }
502 
503     SkAutoSpinlock lock{fSpinLock};
504 
505     UniquePaintParamsID* existingEntry = fPaintKeyToID.find(*keyView);
506     if (existingEntry) {
507         SkASSERT(fIDToPaintKey[(*existingEntry).asUInt()] == *keyView);
508         return *existingEntry;
509     }
510 
511     // Detach from the builder and copy into the arena
512     PaintParamsKey key = keyView->clone(&fArena);
513     UniquePaintParamsID newID{SkTo<uint32_t>(fIDToPaintKey.size())};
514 
515     fPaintKeyToID.set(key, newID);
516     fIDToPaintKey.push_back(key);
517     return newID;
518 }
519 
lookup(UniquePaintParamsID codeID) const520 PaintParamsKey ShaderCodeDictionary::lookup(UniquePaintParamsID codeID) const {
521     if (!codeID.isValid()) {
522         return PaintParamsKey::Invalid();
523     }
524 
525     SkAutoSpinlock lock{fSpinLock};
526     SkASSERT(codeID.asUInt() < SkTo<uint32_t>(fIDToPaintKey.size()));
527     return fIDToPaintKey[codeID.asUInt()];
528 }
529 
getUniforms(BuiltInCodeSnippetID id) const530 SkSpan<const Uniform> ShaderCodeDictionary::getUniforms(BuiltInCodeSnippetID id) const {
531     return fBuiltInCodeSnippets[(int) id].fUniforms;
532 }
533 
getEntry(int codeSnippetID) const534 const ShaderSnippet* ShaderCodeDictionary::getEntry(int codeSnippetID) const {
535     if (codeSnippetID < 0) {
536         return nullptr;
537     }
538 
539     if (codeSnippetID < kBuiltInCodeSnippetIDCount) {
540         return &fBuiltInCodeSnippets[codeSnippetID];
541     }
542 
543     SkAutoSpinlock lock{fSpinLock};
544 
545     if (codeSnippetID >= kSkiaKnownRuntimeEffectsStart &&
546         codeSnippetID < kSkiaKnownRuntimeEffectsStart + kStableKeyCnt) {
547         int knownRTECodeSnippetID = codeSnippetID - kSkiaKnownRuntimeEffectsStart;
548 
549         // TODO(b/238759147): if the snippet hasn't been initialized, get the SkRuntimeEffect and
550         // initialize it here
551         SkASSERT(fKnownRuntimeEffectCodeSnippets[knownRTECodeSnippetID].fPreambleGenerator);
552         return &fKnownRuntimeEffectCodeSnippets[knownRTECodeSnippetID];
553     }
554 
555     // TODO(b/238759147): handle Android and chrome known runtime effects
556 
557     if (codeSnippetID >= kUnknownRuntimeEffectIDStart) {
558         int userDefinedCodeSnippetID = codeSnippetID - kUnknownRuntimeEffectIDStart;
559         if (userDefinedCodeSnippetID < SkTo<int>(fUserDefinedCodeSnippets.size())) {
560             return fUserDefinedCodeSnippets[userDefinedCodeSnippetID].get();
561         }
562     }
563 
564     return nullptr;
565 }
566 
567 //--------------------------------------------------------------------------------------------------
568 namespace {
569 
append_default_snippet_arguments(const ShaderInfo & shaderInfo,const ShaderNode * node,const ShaderSnippet::Args & args,SkSpan<const std::string> childOutputs)570 std::string append_default_snippet_arguments(const ShaderInfo& shaderInfo,
571                                              const ShaderNode* node,
572                                              const ShaderSnippet::Args& args,
573                                              SkSpan<const std::string> childOutputs) {
574     std::string code = "(";
575 
576     const char* separator = "";
577 
578     const ShaderSnippet* entry = node->entry();
579 
580     // Append prior-stage output color.
581     if (entry->needsPriorStageOutput()) {
582         code += args.fPriorStageOutput;
583         separator = ", ";
584     }
585 
586     // Append blender destination color.
587     if (entry->needsBlenderDstColor()) {
588         code += separator;
589         code += args.fBlenderDstColor;
590         separator = ", ";
591     }
592 
593     // Append fragment coordinates.
594     if (entry->needsLocalCoords()) {
595         code += separator;
596         code += args.fFragCoord;
597         separator = ", ";
598     }
599 
600     // Append uniform names.
601     for (size_t i = 0; i < entry->fUniforms.size(); ++i) {
602         code += separator;
603         separator = ", ";
604         code += get_mangled_uniform_name(shaderInfo, entry->fUniforms[i], node->keyIndex());
605     }
606 
607     // Append samplers.
608     for (size_t i = 0; i < entry->fTexturesAndSamplers.size(); ++i) {
609         code += separator;
610         code += get_mangled_sampler_name(entry->fTexturesAndSamplers[i], node->keyIndex());
611         separator = ", ";
612     }
613 
614     // Append child output names.
615     for (const std::string& childOutputVar : childOutputs) {
616         code += separator;
617         separator = ", ";
618         code += childOutputVar;
619     }
620     code.push_back(')');
621 
622     return code;
623 }
624 
emit_helper_function(const ShaderInfo & shaderInfo,const ShaderNode * node)625 std::string emit_helper_function(const ShaderInfo& shaderInfo,
626                                  const ShaderNode* node) {
627     // Create a helper function that invokes each of the children, then calls the entry's snippet
628     // and passes all the child outputs along as arguments.
629     const ShaderSnippet* entry = node->entry();
630     std::string helperFnName = get_mangled_name(entry->fStaticFunctionName, node->keyIndex());
631     std::string helperFn = SkSL::String::printf(
632             "half4 %s(half4 inColor, half4 destColor, float2 pos) {",
633             helperFnName.c_str());
634     TArray<std::string> childOutputVarNames;
635     const ShaderSnippet::Args args = {"inColor", "destColor", "pos"};
636     for (const ShaderNode* child : node->children()) {
637         // Emit glue code into our helper function body (i.e. lifting the child execution up front
638         // so their outputs can be passed to the static module function for the node's snippet).
639         childOutputVarNames.push_back(emit_glue_code_for_entry(shaderInfo, child, args, &helperFn));
640     }
641 
642     // Finally, invoke the snippet from the helper function, passing uniforms and child outputs.
643     std::string snippetArgList = append_default_snippet_arguments(shaderInfo, node,
644                                                                   args, childOutputVarNames);
645     SkSL::String::appendf(&helperFn,
646                               "return %s%s;"
647                           "}",
648                           entry->fStaticFunctionName, snippetArgList.c_str());
649     return helperFn;
650 }
651 
652 // If we have no children, the default expression just calls a built-in snippet with the signature:
653 //     half4 BuiltinFunctionName(/* default snippet arguments */);
654 //
655 // If we do have children, we will have created a glue function in the preamble and that is called
656 // instead. Its signature looks like this:
657 //     half4 BuiltinFunctionName_N(half4 inColor, half4 destColor, float2 pos);
658 
GenerateDefaultExpression(const ShaderInfo & shaderInfo,const ShaderNode * node,const ShaderSnippet::Args & args)659 std::string GenerateDefaultExpression(const ShaderInfo& shaderInfo,
660                                       const ShaderNode* node,
661                                       const ShaderSnippet::Args& args) {
662     if (node->numChildren() == 0) {
663         // We don't have any children; return an expression which invokes the snippet directly.
664         return node->entry()->fStaticFunctionName +
665                append_default_snippet_arguments(shaderInfo, node, args, /*childOutputs=*/{});
666     } else {
667         // Return an expression which invokes the helper function from the preamble.
668         std::string helperFnName =
669                 get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
670         return SkSL::String::printf(
671                 "%s(%.*s, %.*s, %.*s)",
672                 helperFnName.c_str(),
673                 (int)args.fPriorStageOutput.size(), args.fPriorStageOutput.data(),
674                 (int)args.fBlenderDstColor.size(),  args.fBlenderDstColor.data(),
675                 (int)args.fFragCoord.size(),        args.fFragCoord.data());
676     }
677 }
678 
679 // If we have no children, we don't need to add anything into the preamble.
680 // If we have child entries, we create a function in the preamble with a signature of:
681 //     half4 BuiltinFunctionName_N(half4 inColor, half4 destColor, float2 pos) { ... }
682 // This function invokes each child in sequence, and then calls the built-in function, passing all
683 // uniforms and child outputs along:
684 //     half4 BuiltinFunctionName(/* all uniforms as parameters */,
685 //                               /* all child output variable names as parameters */);
GenerateDefaultPreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)686 std::string GenerateDefaultPreamble(const ShaderInfo& shaderInfo,
687                                     const ShaderNode* node) {
688     if (node->numChildren() > 0) {
689         // Create a helper function which invokes all the child snippets.
690         return emit_helper_function(shaderInfo, node);
691     } else {
692         // We don't need a helper function
693         return "";
694     }
695 }
696 
697 //--------------------------------------------------------------------------------------------------
698 static constexpr Uniform kDstReadSampleUniforms[] = {
699         { "dstTextureCoords", SkSLType::kFloat4 },
700 };
701 
702 static constexpr TextureAndSampler kDstReadSampleTexturesAndSamplers[] = {
703         {"dstSampler"},
704 };
705 
GenerateDstReadSampleExpression(const ShaderInfo & shaderInfo,const ShaderNode * node,const ShaderSnippet::Args & args)706 std::string GenerateDstReadSampleExpression(const ShaderInfo& shaderInfo,
707                                             const ShaderNode* node,
708                                             const ShaderSnippet::Args& args) {
709     const ShaderSnippet* entry = node->entry();
710     std::string sampler =
711             get_mangled_sampler_name(entry->fTexturesAndSamplers[0], node->keyIndex());
712     std::string coords =
713             get_mangled_uniform_name(shaderInfo, entry->fUniforms[0], node->keyIndex());
714     std::string helperFnName = get_mangled_name(entry->fStaticFunctionName, node->keyIndex());
715 
716     return SkSL::String::printf("%s(%s, %s)",
717                                 helperFnName.c_str(),
718                                 coords.c_str(),
719                                 sampler.c_str());
720 }
721 
GenerateDstReadSamplePreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)722 std::string GenerateDstReadSamplePreamble(const ShaderInfo& shaderInfo, const ShaderNode* node) {
723     std::string helperFnName =
724             get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
725 
726     return SkSL::String::printf(
727             "half4 surfaceColor;"  // we save off the original dstRead color to combine w/ coverage
728             "half4 %s(float4 coords, sampler2D dstSampler) {"
729                 "surfaceColor = sample(dstSampler, (sk_FragCoord.xy - coords.xy) * coords.zw);"
730                 "return surfaceColor;"
731             "}",
732             helperFnName.c_str());
733 }
734 
735 //--------------------------------------------------------------------------------------------------
GenerateDstReadFetchExpression(const ShaderInfo & shaderInfo,const ShaderNode * node,const ShaderSnippet::Args & args)736 std::string GenerateDstReadFetchExpression(const ShaderInfo& shaderInfo,
737                                            const ShaderNode* node,
738                                            const ShaderSnippet::Args& args) {
739     std::string helperFnName =
740             get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
741 
742     return SkSL::String::printf("%s()", helperFnName.c_str());
743 }
744 
GenerateDstReadFetchPreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)745 std::string GenerateDstReadFetchPreamble(const ShaderInfo& shaderInfo, const ShaderNode* node) {
746     std::string helperFnName =
747             get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
748 
749     return SkSL::String::printf(
750             "half4 surfaceColor;"  // we save off the original dstRead color to combine w/ coverage
751             "half4 %s() {"
752                 "surfaceColor = sk_LastFragColor;"
753                 "return surfaceColor;"
754             "}",
755             helperFnName.c_str());
756 }
757 
758 //--------------------------------------------------------------------------------------------------
759 static constexpr int kNumClipShaderChildren = 1;
760 
GenerateClipShaderExpression(const ShaderInfo & shaderInfo,const ShaderNode * node,const ShaderSnippet::Args & args)761 std::string GenerateClipShaderExpression(const ShaderInfo& shaderInfo,
762                                          const ShaderNode* node,
763                                          const ShaderSnippet::Args& args) {
764     SkASSERT(node->numChildren() == kNumClipShaderChildren);
765     static constexpr char kUnusedSrcColor[] = "half4(1)";
766     static constexpr char kUnusedDstColor[] = "half4(1)";
767     return emit_expression_for_entry(
768             shaderInfo, node->child(0), {kUnusedSrcColor, kUnusedDstColor, "sk_FragCoord.xy"});
769 }
770 
GenerateClipShaderPreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)771 std::string GenerateClipShaderPreamble(const ShaderInfo& shaderInfo, const ShaderNode* node) {
772     // No preamble is used for clip shaders. The child shader is called directly with sk_FragCoord.
773     return "";
774 }
775 
776 //--------------------------------------------------------------------------------------------------
777 static constexpr int kFourStopGradient = 4;
778 static constexpr int kEightStopGradient = 8;
779 
780 static constexpr Uniform kLinearGradientUniforms4[] = {
781         { "colors",      SkSLType::kFloat4, kFourStopGradient },
782         { "offsets",     SkSLType::kFloat4 },
783         { "tilemode",    SkSLType::kInt },
784         { "colorSpace",  SkSLType::kInt },
785         { "doUnPremul",  SkSLType::kInt },
786 };
787 static constexpr Uniform kLinearGradientUniforms8[] = {
788         { "colors",      SkSLType::kFloat4, kEightStopGradient },
789         { "offsets",     SkSLType::kFloat4, 2 },
790         { "tilemode",    SkSLType::kInt },
791         { "colorSpace",  SkSLType::kInt },
792         { "doUnPremul",  SkSLType::kInt },
793 };
794 static constexpr Uniform kLinearGradientUniformsTexture[] = {
795         { "numStops",    SkSLType::kInt },
796         { "tilemode",    SkSLType::kInt },
797         { "colorSpace",  SkSLType::kInt },
798         { "doUnPremul",  SkSLType::kInt },
799 };
800 
801 static constexpr Uniform kLinearGradientUniformsBuffer[] = {
802         { "numStops",    SkSLType::kInt },
803         { "bufferOffset",   SkSLType::kInt },
804         { "tilemode",    SkSLType::kInt },
805         { "colorSpace",  SkSLType::kInt },
806         { "doUnPremul",  SkSLType::kInt },
807 };
808 
809 static constexpr Uniform kRadialGradientUniforms4[] = {
810         { "colors",      SkSLType::kFloat4, kFourStopGradient },
811         { "offsets",     SkSLType::kFloat4 },
812         { "tilemode",    SkSLType::kInt },
813         { "colorSpace",  SkSLType::kInt },
814         { "doUnPremul",  SkSLType::kInt },
815 };
816 static constexpr Uniform kRadialGradientUniforms8[] = {
817         { "colors",      SkSLType::kFloat4, kEightStopGradient },
818         { "offsets",     SkSLType::kFloat4, 2 },
819         { "tilemode",    SkSLType::kInt },
820         { "colorSpace",  SkSLType::kInt },
821         { "doUnPremul",  SkSLType::kInt },
822 };
823 static constexpr Uniform kRadialGradientUniformsTexture[] = {
824         { "numStops",    SkSLType::kInt },
825         { "tilemode",    SkSLType::kInt },
826         { "colorSpace",  SkSLType::kInt },
827         { "doUnPremul",  SkSLType::kInt },
828 };
829 static constexpr Uniform kRadialGradientUniformsBuffer[] = {
830         { "numStops",    SkSLType::kInt },
831         { "bufferOffset",   SkSLType::kInt },
832         { "tilemode",    SkSLType::kInt },
833         { "colorSpace",  SkSLType::kInt },
834         { "doUnPremul",  SkSLType::kInt },
835 };
836 
837 static constexpr Uniform kSweepGradientUniforms4[] = {
838         { "colors",      SkSLType::kFloat4, kFourStopGradient },
839         { "offsets",     SkSLType::kFloat4 },
840         { "bias",        SkSLType::kFloat },
841         { "scale",       SkSLType::kFloat },
842         { "tilemode",    SkSLType::kInt },
843         { "colorSpace",  SkSLType::kInt },
844         { "doUnPremul",  SkSLType::kInt },
845 };
846 static constexpr Uniform kSweepGradientUniforms8[] = {
847         { "colors",      SkSLType::kFloat4, kEightStopGradient },
848         { "offsets",     SkSLType::kFloat4, 2 },
849         { "bias",        SkSLType::kFloat },
850         { "scale",       SkSLType::kFloat },
851         { "tilemode",    SkSLType::kInt },
852         { "colorSpace",  SkSLType::kInt },
853         { "doUnPremul",  SkSLType::kInt },
854 };
855 static constexpr Uniform kSweepGradientUniformsTexture[] = {
856         { "bias",        SkSLType::kFloat },
857         { "scale",       SkSLType::kFloat },
858         { "numStops",    SkSLType::kInt },
859         { "tilemode",    SkSLType::kInt },
860         { "colorSpace",  SkSLType::kInt },
861         { "doUnPremul",  SkSLType::kInt },
862 };
863 static constexpr Uniform kSweepGradientUniformsBuffer[] = {
864         { "bias",        SkSLType::kFloat },
865         { "scale",       SkSLType::kFloat },
866         { "numStops",    SkSLType::kInt },
867         { "bufferOffset",   SkSLType::kInt },
868         { "tilemode",    SkSLType::kInt },
869         { "colorSpace",  SkSLType::kInt },
870         { "doUnPremul",  SkSLType::kInt },
871 };
872 
873 static constexpr Uniform kConicalGradientUniforms4[] = {
874         { "colors",      SkSLType::kFloat4, kFourStopGradient },
875         { "offsets",     SkSLType::kFloat4 },
876         { "radius0",     SkSLType::kFloat },
877         { "dRadius",     SkSLType::kFloat },
878         { "a",           SkSLType::kFloat },
879         { "invA",        SkSLType::kFloat },
880         { "tilemode",    SkSLType::kInt },
881         { "colorSpace",  SkSLType::kInt },
882         { "doUnPremul",  SkSLType::kInt },
883 };
884 static constexpr Uniform kConicalGradientUniforms8[] = {
885         { "colors",      SkSLType::kFloat4, kEightStopGradient },
886         { "offsets",     SkSLType::kFloat4, 2 },
887         { "radius0",     SkSLType::kFloat },
888         { "dRadius",     SkSLType::kFloat },
889         { "a",           SkSLType::kFloat },
890         { "invA",        SkSLType::kFloat },
891         { "tilemode",    SkSLType::kInt },
892         { "colorSpace",  SkSLType::kInt },
893         { "doUnPremul",  SkSLType::kInt },
894 };
895 static constexpr Uniform kConicalGradientUniformsTexture[] = {
896         { "radius0",     SkSLType::kFloat },
897         { "dRadius",     SkSLType::kFloat },
898         { "a",           SkSLType::kFloat },
899         { "invA",        SkSLType::kFloat },
900         { "numStops",    SkSLType::kInt },
901         { "tilemode",    SkSLType::kInt },
902         { "colorSpace",  SkSLType::kInt },
903         { "doUnPremul",  SkSLType::kInt },
904 };
905 static constexpr Uniform kConicalGradientUniformsBuffer[] = {
906         { "radius0",     SkSLType::kFloat },
907         { "dRadius",     SkSLType::kFloat },
908         { "a",           SkSLType::kFloat },
909         { "invA",        SkSLType::kFloat },
910         { "numStops",    SkSLType::kInt },
911         { "bufferOffset",   SkSLType::kInt },
912         { "tilemode",    SkSLType::kInt },
913         { "colorSpace",  SkSLType::kInt },
914         { "doUnPremul",  SkSLType::kInt },
915 };
916 
917 static constexpr TextureAndSampler kTextureGradientTexturesAndSamplers[] = {
918         {"colorAndOffsetSampler"},
919 };
920 
921 static constexpr char kLinearGradient4Name[] = "sk_linear_grad_4_shader";
922 static constexpr char kLinearGradient8Name[] = "sk_linear_grad_8_shader";
923 static constexpr char kLinearGradientTextureName[] = "sk_linear_grad_tex_shader";
924 static constexpr char kLinearGradientBufferName[] = "sk_linear_grad_buf_shader";
925 
926 static constexpr char kRadialGradient4Name[] = "sk_radial_grad_4_shader";
927 static constexpr char kRadialGradient8Name[] = "sk_radial_grad_8_shader";
928 static constexpr char kRadialGradientTextureName[] = "sk_radial_grad_tex_shader";
929 static constexpr char kRadialGradientBufferName[] = "sk_radial_grad_buf_shader";
930 
931 static constexpr char kSweepGradient4Name[] = "sk_sweep_grad_4_shader";
932 static constexpr char kSweepGradient8Name[] = "sk_sweep_grad_8_shader";
933 static constexpr char kSweepGradientTextureName[] = "sk_sweep_grad_tex_shader";
934 static constexpr char kSweepGradientBufferName[] = "sk_sweep_grad_buf_shader";
935 
936 static constexpr char kConicalGradient4Name[] = "sk_conical_grad_4_shader";
937 static constexpr char kConicalGradient8Name[] = "sk_conical_grad_8_shader";
938 static constexpr char kConicalGradientTextureName[] = "sk_conical_grad_tex_shader";
939 static constexpr char kConicalGradientBufferName[] = "sk_conical_grad_buf_shader";
940 
941 // These expression and preamble generators are only needed until we support passing unsized
942 // arrays into SkSL module functions (b/343510513).
GenerateGradientBufferExpression(const ShaderInfo & shaderInfo,const ShaderNode * node,const ShaderSnippet::Args & args)943 std::string GenerateGradientBufferExpression(const ShaderInfo& shaderInfo,
944                                              const ShaderNode* node,
945                                              const ShaderSnippet::Args& args) {
946     std::string helperFnName =
947             get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
948     return helperFnName + append_default_snippet_arguments(shaderInfo, node, args, {});
949 }
950 
GenerateGradientBufferPreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)951 std::string GenerateGradientBufferPreamble(const ShaderInfo& shaderInfo,
952                                            const ShaderNode* node) {
953     SkASSERT(node->codeSnippetId() == (int) BuiltInCodeSnippetID::kLinearGradientShaderBuffer ||
954              node->codeSnippetId() == (int) BuiltInCodeSnippetID::kRadialGradientShaderBuffer ||
955              node->codeSnippetId() == (int) BuiltInCodeSnippetID::kSweepGradientShaderBuffer ||
956              node->codeSnippetId() == (int) BuiltInCodeSnippetID::kConicalGradientShaderBuffer);
957     SkASSERT(node->numChildren() == 0);
958 
959     const char* gradArgs;
960     const char* layoutFnCall;
961     switch (node->codeSnippetId()) {
962         case (int) BuiltInCodeSnippetID::kLinearGradientShaderBuffer:
963             gradArgs = "float2 coords";
964             layoutFnCall = "linear_grad_layout(coords)";
965             break;
966         case (int) BuiltInCodeSnippetID::kRadialGradientShaderBuffer:
967             gradArgs = "float2 coords";
968             layoutFnCall = "radial_grad_layout(coords)";
969             break;
970         case (int) BuiltInCodeSnippetID::kSweepGradientShaderBuffer:
971             gradArgs = "float2 coords, float biasParam, float scaleParam";
972             layoutFnCall = "sweep_grad_layout(biasParam, scaleParam, coords)";
973             break;
974         case (int) BuiltInCodeSnippetID::kConicalGradientShaderBuffer:
975             gradArgs = "float2 coords, float radius0Param, float dRadiusParam, "
976                             "float aParam, float invAParam";
977             layoutFnCall = "conical_grad_layout(radius0Param, dRadiusParam, "
978                                 "aParam, invAParam, coords)";
979             break;
980     }
981 
982     std::string helperFnName =
983             get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
984     return SkSL::String::printf(
985                 "half4 %s(%s, int numStops, int bufferOffset, int tileMode,"
986                          "int colorSpace, int doUnpremul) {"
987                     "float2 t = %s;"
988                     "t = tile_grad(tileMode, t);"
989 
990                     // Colorize
991                     "half4 color = half4(0);"
992                     "if (t.y >= 0) {"
993                         "if (t.x == 0) {"
994                             // Start from 1 since bufferOffset + 0 is holding the
995                             // color stop's offset value.
996                             "color = half4(fsGradientBuffer[bufferOffset + 1],"
997                                           "fsGradientBuffer[bufferOffset + 2],"
998                                           "fsGradientBuffer[bufferOffset + 3],"
999                                           "fsGradientBuffer[bufferOffset + 4]);"
1000                         "} else if (t.x == 1) {"
1001                             "int endBufferIdx = bufferOffset + numStops * 5;"
1002                             "color = half4(fsGradientBuffer[endBufferIdx - 4],"
1003                                           "fsGradientBuffer[endBufferIdx - 3],"
1004                                           "fsGradientBuffer[endBufferIdx - 2],"
1005                                           "fsGradientBuffer[endBufferIdx - 1]);"
1006                         "} else {"
1007                             // Binary search for the matching adjacent offsets
1008                             // running log(numStops).
1009                             "int low = 0;"
1010                             "int high = numStops - 1;"
1011                             "for (int i = 1; i < numStops; i += i) {"
1012                                 "int mid = (low + high) / 2;"
1013                                 "float offset = fsGradientBuffer[bufferOffset + mid * 5];"
1014                                 "if (t.x < offset) {"
1015                                     "high = mid;"
1016                                 "} else {"
1017                                     "low = mid;"
1018                                 "}"
1019                             "}"
1020                             "int lowBufferIdx = bufferOffset + low * 5;"
1021                             "float lowOffset = fsGradientBuffer[lowBufferIdx];"
1022                             "half4 lowColor = half4(fsGradientBuffer[lowBufferIdx + 1],"
1023                                                    "fsGradientBuffer[lowBufferIdx + 2],"
1024                                                    "fsGradientBuffer[lowBufferIdx + 3],"
1025                                                    "fsGradientBuffer[lowBufferIdx + 4]);"
1026 
1027                             "int highBufferIdx = bufferOffset + high * 5;"
1028                             "float highOffset = fsGradientBuffer[highBufferIdx];"
1029                             "if (highOffset == lowOffset) {"
1030                                 // If the t value falls exactly on a color stop, both lowOffset
1031                                 // and highOffset will be exactly the same so we avoid having
1032                                 // 0/0=NaN as our mix value.
1033                                 "color = lowColor;"
1034                             "} else {"
1035                                 "half4 highColor = half4(fsGradientBuffer[highBufferIdx + 1],"
1036                                                         "fsGradientBuffer[highBufferIdx + 2],"
1037                                                         "fsGradientBuffer[highBufferIdx + 3],"
1038                                                         "fsGradientBuffer[highBufferIdx + 4]);"
1039 
1040                                 "color = half4(mix(lowColor,"
1041                                                   "highColor,"
1042                                                   "(t.x - lowOffset) /"
1043                                                   "(highOffset - lowOffset)));"
1044                             "}"
1045                         "}"
1046                     "}"
1047 
1048                     "return interpolated_to_rgb_unpremul(color,"
1049                                                         "colorSpace,"
1050                                                         "doUnpremul);"
1051                 "}",
1052                 helperFnName.c_str(),
1053                 gradArgs,
1054                 layoutFnCall);
1055 }
1056 
1057 
1058 //--------------------------------------------------------------------------------------------------
1059 static constexpr Uniform kSolidShaderUniforms[] = {
1060         { "color", SkSLType::kFloat4 }
1061 };
1062 
1063 static constexpr char kSolidShaderName[] = "sk_solid_shader";
1064 
1065 //--------------------------------------------------------------------------------------------------
1066 static constexpr Uniform kPaintColorUniforms[] = { Uniform::PaintColor() };
1067 
1068 static constexpr char kRGBPaintColorName[] = "sk_rgb_opaque";
1069 static constexpr char kAlphaOnlyPaintColorName[] = "sk_alpha_only";
1070 
1071 //--------------------------------------------------------------------------------------------------
1072 static constexpr Uniform kLocalMatrixShaderUniforms[] = {
1073         { "localMatrix", SkSLType::kFloat4x4 },
1074 };
1075 
1076 static constexpr int kNumLocalMatrixShaderChildren = 1;
1077 
1078 static constexpr char kLocalMatrixShaderName[] = "LocalMatrix";
1079 
1080 // Create a helper function that multiplies coordinates by a local matrix, invokes the child
1081 // entry with those updated coordinates, and returns the result. This helper function meets the
1082 // requirements for use with GenerateDefaultExpression, so there's no need to have a separate
1083 // special GenerateLocalMatrixExpression.
GenerateLocalMatrixPreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)1084 std::string GenerateLocalMatrixPreamble(const ShaderInfo& shaderInfo,
1085                                         const ShaderNode* node) {
1086     SkASSERT(node->codeSnippetId() == (int) BuiltInCodeSnippetID::kLocalMatrixShader);
1087     SkASSERT(node->numChildren() == kNumLocalMatrixShaderChildren);
1088 
1089     // Get the child's evaluation expression.
1090     static constexpr char kUnusedDestColor[] = "half4(1)";
1091     std::string childExpr = emit_expression_for_entry(shaderInfo, node->child(0),
1092                                                       {"inColor", kUnusedDestColor, "coords"});
1093     std::string localMatrixUni =
1094             get_mangled_uniform_name(shaderInfo, node->entry()->fUniforms[0], node->keyIndex());
1095 
1096     std::string helperFnName =
1097             get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
1098     return SkSL::String::printf("half4 %s(half4 inColor, half4 destColor, float2 coords) {"
1099                                     "coords = (%s * coords.xy01).xy;"
1100                                     "return %s;"
1101                                 "}",
1102                                 helperFnName.c_str(),
1103                                 localMatrixUni.c_str(),
1104                                 childExpr.c_str());
1105 }
1106 
1107 //--------------------------------------------------------------------------------------------------
1108 static constexpr Uniform kImageShaderUniforms[] = {
1109         { "invImgSize",            SkSLType::kFloat2 },
1110         { "subset",                SkSLType::kFloat4 },
1111         { "tilemodeX",             SkSLType::kInt },
1112         { "tilemodeY",             SkSLType::kInt },
1113         { "filterMode",            SkSLType::kInt },
1114         // The next 5 uniforms are for the color space transformation
1115         { "csXformFlags",          SkSLType::kInt },
1116         { "csXformSrcKind",        SkSLType::kInt },
1117         { "csXformGamutTransform", SkSLType::kHalf3x3 },
1118         { "csXformDstKind",        SkSLType::kInt },
1119         { "csXformCoeffs",         SkSLType::kHalf4x4 },
1120 };
1121 
1122 static constexpr Uniform kCubicImageShaderUniforms[] = {
1123         { "invImgSize",            SkSLType::kFloat2 },
1124         { "subset",                SkSLType::kFloat4 },
1125         { "tilemodeX",             SkSLType::kInt },
1126         { "tilemodeY",             SkSLType::kInt },
1127         { "cubicCoeffs",           SkSLType::kHalf4x4 },
1128         // The next 5 uniforms are for the color space transformation
1129         { "csXformFlags",          SkSLType::kInt },
1130         { "csXformSrcKind",        SkSLType::kInt },
1131         { "csXformGamutTransform", SkSLType::kHalf3x3 },
1132         { "csXformDstKind",        SkSLType::kInt },
1133         { "csXformCoeffs",         SkSLType::kHalf4x4 },
1134 };
1135 
1136 static constexpr Uniform kHWImageShaderUniforms[] = {
1137         { "invImgSize",            SkSLType::kFloat2 },
1138         // The next 5 uniforms are for the color space transformation
1139         { "csXformFlags",          SkSLType::kInt },
1140         { "csXformSrcKind",        SkSLType::kInt },
1141         { "csXformGamutTransform", SkSLType::kHalf3x3 },
1142         { "csXformDstKind",        SkSLType::kInt },
1143         { "csXformCoeffs",         SkSLType::kHalf4x4 },
1144 };
1145 
1146 static constexpr TextureAndSampler kISTexturesAndSamplers[] = {
1147         {"sampler"},
1148 };
1149 
1150 static_assert(0 == static_cast<int>(SkTileMode::kClamp),  "ImageShader code depends on SkTileMode");
1151 static_assert(1 == static_cast<int>(SkTileMode::kRepeat), "ImageShader code depends on SkTileMode");
1152 static_assert(2 == static_cast<int>(SkTileMode::kMirror), "ImageShader code depends on SkTileMode");
1153 static_assert(3 == static_cast<int>(SkTileMode::kDecal),  "ImageShader code depends on SkTileMode");
1154 
1155 static_assert(0 == static_cast<int>(SkFilterMode::kNearest),
1156               "ImageShader code depends on SkFilterMode");
1157 static_assert(1 == static_cast<int>(SkFilterMode::kLinear),
1158               "ImageShader code depends on SkFilterMode");
1159 
1160 static_assert(0 == static_cast<int>(ReadSwizzle::kRGBA),
1161               "ImageShader code depends on ReadSwizzle");
1162 static_assert(1 == static_cast<int>(ReadSwizzle::kRGB1),
1163               "ImageShader code depends on ReadSwizzle");
1164 static_assert(2 == static_cast<int>(ReadSwizzle::kRRR1),
1165               "ImageShader code depends on ReadSwizzle");
1166 static_assert(3 == static_cast<int>(ReadSwizzle::kBGRA),
1167               "ImageShader code depends on ReadSwizzle");
1168 static_assert(4 == static_cast<int>(ReadSwizzle::k000R),
1169               "ImageShader code depends on ReadSwizzle");
1170 
1171 static constexpr char kImageShaderName[] = "sk_image_shader";
1172 static constexpr char kCubicImageShaderName[] = "sk_cubic_image_shader";
1173 static constexpr char kHWImageShaderName[] = "sk_hw_image_shader";
1174 
1175 //--------------------------------------------------------------------------------------------------
1176 
1177 static constexpr Uniform kYUVImageShaderUniforms[] = {
1178         { "invImgSizeY",           SkSLType::kFloat2 },
1179         { "invImgSizeUV",          SkSLType::kFloat2 },  // Relative to Y's texel space
1180         { "subset",                SkSLType::kFloat4 },
1181         { "linearFilterUVInset",   SkSLType::kFloat2 },
1182         { "tilemodeX",             SkSLType::kInt },
1183         { "tilemodeY",             SkSLType::kInt },
1184         { "filterModeY",           SkSLType::kInt },
1185         { "filterModeUV",          SkSLType::kInt },
1186         { "channelSelectY",        SkSLType::kHalf4 },
1187         { "channelSelectU",        SkSLType::kHalf4 },
1188         { "channelSelectV",        SkSLType::kHalf4 },
1189         { "channelSelectA",        SkSLType::kHalf4 },
1190         { "yuvToRGBMatrix",        SkSLType::kHalf3x3 },
1191         { "yuvToRGBTranslate",     SkSLType::kFloat3 },
1192 };
1193 
1194 static constexpr Uniform kCubicYUVImageShaderUniforms[] = {
1195         { "invImgSizeY",           SkSLType::kFloat2 },
1196         { "invImgSizeUV",          SkSLType::kFloat2 },  // Relative to Y's texel space
1197         { "subset",                SkSLType::kFloat4 },
1198         { "tilemodeX",             SkSLType::kInt },
1199         { "tilemodeY",             SkSLType::kInt },
1200         { "cubicCoeffs",           SkSLType::kHalf4x4 },
1201         { "channelSelectY",        SkSLType::kHalf4 },
1202         { "channelSelectU",        SkSLType::kHalf4 },
1203         { "channelSelectV",        SkSLType::kHalf4 },
1204         { "channelSelectA",        SkSLType::kHalf4 },
1205         { "yuvToRGBMatrix",        SkSLType::kHalf3x3 },
1206         { "yuvToRGBTranslate",     SkSLType::kFloat3 },
1207 };
1208 
1209 static constexpr TextureAndSampler kYUVISTexturesAndSamplers[] = {
1210     { "samplerY" },
1211     { "samplerU" },
1212     { "samplerV" },
1213     { "samplerA" },
1214 };
1215 
1216 static constexpr char kYUVImageShaderName[] = "sk_yuv_image_shader";
1217 static constexpr char kCubicYUVImageShaderName[] = "sk_cubic_yuv_image_shader";
1218 
1219 //--------------------------------------------------------------------------------------------------
1220 static constexpr Uniform kCoordClampShaderUniforms[] = {
1221         { "subset", SkSLType::kFloat4 },
1222 };
1223 
1224 static constexpr char kCoordClampShaderName[] = "CoordClamp";
1225 
1226 static constexpr int kNumCoordClampShaderChildren = 1;
1227 
1228 // Create a helper function that clamps the local coords to the subset, invokes the child
1229 // entry with those updated coordinates, and returns the result. This helper function meets the
1230 // requirements for use with GenerateDefaultExpression, so there's no need to have a separate
1231 // special GenerateCoordClampExpression.
1232 // TODO: this has a lot of overlap with GenerateLocalMatrixPreamble
GenerateCoordClampPreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)1233 std::string GenerateCoordClampPreamble(const ShaderInfo& shaderInfo,
1234                                        const ShaderNode* node) {
1235     SkASSERT(node->codeSnippetId() == (int) BuiltInCodeSnippetID::kCoordClampShader);
1236     SkASSERT(node->numChildren() == kNumCoordClampShaderChildren);
1237 
1238     // Get the child's evaluation expression.
1239     static constexpr char kUnusedDestColor[] = "half4(1)";
1240     std::string childExpr = emit_expression_for_entry(shaderInfo, node->child(0),
1241                                                       {"inColor", kUnusedDestColor, "coords"});
1242 
1243     std::string subsetUni =
1244             get_mangled_uniform_name(shaderInfo, node->entry()->fUniforms[0], node->keyIndex());
1245 
1246     std::string helperFnName =
1247             get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
1248     return SkSL::String::printf("half4 %s(half4 inColor, half4 destColor, float2 coords) {"
1249                                     "coords = clamp(coords, %s.LT, %s.RB);"
1250                                     "return %s;"
1251                                 "}",
1252                                 helperFnName.c_str(),
1253                                 subsetUni.c_str(),
1254                                 subsetUni.c_str(),
1255                                 childExpr.c_str());
1256 }
1257 
1258 
1259 //--------------------------------------------------------------------------------------------------
1260 static constexpr Uniform kDitherShaderUniforms[] = {
1261         { "range", SkSLType::kHalf },
1262 };
1263 
1264 static constexpr TextureAndSampler kDitherTexturesAndSamplers[] = {
1265         {"sampler"},
1266 };
1267 
1268 static constexpr char kDitherShaderName[] = "sk_dither_shader";
1269 
1270 //--------------------------------------------------------------------------------------------------
1271 static constexpr Uniform kPerlinNoiseShaderUniforms[] = {
1272         { "baseFrequency", SkSLType::kFloat2 },
1273         { "stitchData",    SkSLType::kFloat2 },
1274         { "noiseType",     SkSLType::kInt },
1275         { "numOctaves",    SkSLType::kInt },
1276         { "stitching",     SkSLType::kInt },
1277 };
1278 
1279 static constexpr TextureAndSampler kPerlinNoiseShaderTexturesAndSamplers[] = {
1280         { "permutationsSampler" },
1281         { "noiseSampler" },
1282 };
1283 
1284 static constexpr char kPerlinNoiseShaderName[] = "perlin_noise_shader";
1285 
1286 //--------------------------------------------------------------------------------------------------
1287 static constexpr Uniform CoeffBlendderUniforms[] = {
1288         { "coeffs", SkSLType::kHalf4 },
1289 };
1290 
1291 static constexpr char kCoeffBlenderName[] = "sk_coeff_blend";
1292 
1293 //--------------------------------------------------------------------------------------------------
1294 static constexpr Uniform kBlendModeBlenderUniforms[] = {
1295         { "blendMode", SkSLType::kInt },
1296 };
1297 
1298 static constexpr char kBlendModeBlenderName[] = "sk_blend";
1299 
1300 //--------------------------------------------------------------------------------------------------
1301 static constexpr int kNumBlendShaderChildren = 3;
1302 
GenerateBlendShaderPreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)1303 std::string GenerateBlendShaderPreamble(const ShaderInfo& shaderInfo,
1304                                         const ShaderNode* node) {
1305     // Children are src, dst, and blender
1306     SkASSERT(node->numChildren() == 3);
1307 
1308     // Create a helper function that invokes the src and dst children, then calls the blend child
1309     // with the src and dst results.
1310     std::string helperFn = SkSL::String::printf(
1311             "half4 %s(half4 inColor, half4 destColor, float2 pos) {",
1312             get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex()).c_str());
1313 
1314     // Get src and dst colors.
1315     const ShaderSnippet::Args args = {"inColor", "destColor", "pos"};
1316     std::string srcVar = emit_glue_code_for_entry(shaderInfo, node->child(0), args, &helperFn);
1317     std::string dstVar = emit_glue_code_for_entry(shaderInfo, node->child(1), args, &helperFn);
1318 
1319     // Do the blend.
1320     static constexpr char kUnusedLocalCoords[] = "float2(0)";
1321 
1322     std::string blendResultVar = emit_glue_code_for_entry(
1323             shaderInfo, node->child(2), {srcVar, dstVar, kUnusedLocalCoords}, &helperFn);
1324 
1325     SkSL::String::appendf(&helperFn,
1326                               "return %s;"
1327                           "}",
1328                           blendResultVar.c_str());
1329     return helperFn;
1330 }
1331 
1332 //--------------------------------------------------------------------------------------------------
1333 class GraphitePipelineCallbacks : public SkSL::PipelineStage::Callbacks {
1334 public:
GraphitePipelineCallbacks(const ShaderInfo & shaderInfo,const ShaderNode * node,std::string * preamble,const SkRuntimeEffect * effect)1335     GraphitePipelineCallbacks(const ShaderInfo& shaderInfo,
1336                               const ShaderNode* node,
1337                               std::string* preamble,
1338                               const SkRuntimeEffect* effect)
1339             : fShaderInfo(shaderInfo)
1340             , fNode(node)
1341             , fPreamble(preamble)
1342             , fEffect(effect) {}
1343 
declareUniform(const SkSL::VarDeclaration * decl)1344     std::string declareUniform(const SkSL::VarDeclaration* decl) override {
1345         std::string result = get_mangled_name(std::string(decl->var()->name()), fNode->keyIndex());
1346         if (fShaderInfo.ssboIndex()) {
1347             result = EmitStorageBufferAccess("fs", fShaderInfo.ssboIndex(), result.c_str());
1348         }
1349         return result;
1350     }
1351 
defineFunction(const char * decl,const char * body,bool isMain)1352     void defineFunction(const char* decl, const char* body, bool isMain) override {
1353         if (isMain) {
1354             SkSL::String::appendf(
1355                  fPreamble,
1356                  "half4 %s(half4 inColor, half4 destColor, float2 coords) {"
1357                      "%s"
1358                  "}",
1359                  get_mangled_name(fNode->entry()->fName, fNode->keyIndex()).c_str(),
1360                  body);
1361         } else {
1362             SkSL::String::appendf(fPreamble, "%s {%s}\n", decl, body);
1363         }
1364     }
1365 
declareFunction(const char * decl)1366     void declareFunction(const char* decl) override {
1367         *fPreamble += std::string(decl);
1368     }
1369 
defineStruct(const char * definition)1370     void defineStruct(const char* definition) override {
1371         *fPreamble += std::string(definition);
1372     }
1373 
declareGlobal(const char * declaration)1374     void declareGlobal(const char* declaration) override {
1375         *fPreamble += std::string(declaration);
1376     }
1377 
sampleShader(int index,std::string coords)1378     std::string sampleShader(int index, std::string coords) override {
1379         return emit_expression_for_entry(fShaderInfo, fNode->child(index),
1380                                          {"inColor", "destColor", coords});
1381     }
1382 
sampleColorFilter(int index,std::string color)1383     std::string sampleColorFilter(int index, std::string color) override {
1384         return emit_expression_for_entry(fShaderInfo, fNode->child(index),
1385                                          {color, "destColor", "coords"});
1386     }
1387 
sampleBlender(int index,std::string src,std::string dst)1388     std::string sampleBlender(int index, std::string src, std::string dst) override {
1389         return emit_expression_for_entry(fShaderInfo, fNode->child(index),
1390                                          {src, dst, "coords"});
1391     }
1392 
toLinearSrgb(std::string color)1393     std::string toLinearSrgb(std::string color) override {
1394         if (!SkRuntimeEffectPriv::UsesColorTransform(fEffect)) {
1395             return color;
1396         }
1397 
1398         color = SkSL::String::printf("(%s).rgb1", color.c_str());
1399         std::string helper = get_mangled_name("toLinearSRGB", fNode->keyIndex());
1400         std::string xformedColor = SkSL::String::printf("%s(%s)",
1401                                     helper.c_str(),
1402                                     color.c_str());
1403         return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
1404     }
1405 
1406 
fromLinearSrgb(std::string color)1407     std::string fromLinearSrgb(std::string color) override {
1408         if (!SkRuntimeEffectPriv::UsesColorTransform(fEffect)) {
1409             return color;
1410         }
1411 
1412         color = SkSL::String::printf("(%s).rgb1", color.c_str());
1413         std::string helper = get_mangled_name("fromLinearSRGB", fNode->keyIndex());
1414         std::string xformedColor = SkSL::String::printf("%s(%s)",
1415                                                         helper.c_str(),
1416                                                         color.c_str());
1417         return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
1418     }
1419 
getMangledName(const char * name)1420     std::string getMangledName(const char* name) override {
1421         return get_mangled_name(name, fNode->keyIndex());
1422     }
1423 
1424 private:
1425     const ShaderInfo& fShaderInfo;
1426     const ShaderNode* fNode;
1427     std::string* fPreamble;
1428     const SkRuntimeEffect* fEffect;
1429 };
1430 
GenerateRuntimeShaderPreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)1431 std::string GenerateRuntimeShaderPreamble(const ShaderInfo& shaderInfo,
1432                                           const ShaderNode* node) {
1433     // Find this runtime effect in the runtime-effect dictionary.
1434     SkASSERT(node->codeSnippetId() >= kBuiltInCodeSnippetIDCount);
1435     const SkRuntimeEffect* effect;
1436     if (node->codeSnippetId() < kSkiaKnownRuntimeEffectsStart + kStableKeyCnt) {
1437         effect = GetKnownRuntimeEffect(static_cast<StableKey>(node->codeSnippetId()));
1438     } else {
1439         SkASSERT(node->codeSnippetId() >= kUnknownRuntimeEffectIDStart);
1440         effect = shaderInfo.runtimeEffectDictionary()->find(node->codeSnippetId());
1441     }
1442     SkASSERT(effect);
1443 
1444     const SkSL::Program& program = SkRuntimeEffectPriv::Program(*effect);
1445 
1446     std::string preamble;
1447     if (SkRuntimeEffectPriv::UsesColorTransform(effect)) {
1448         SkSL::String::appendf(
1449                 &preamble,
1450                 "half4 %s(half4 inColor) {"
1451                     "return sk_color_space_transform(inColor, %s, %s, %s, %s, %s);"
1452                 "}",
1453                 get_mangled_name("toLinearSRGB", node->keyIndex()).c_str(),
1454                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[0],
1455                                          node->keyIndex()).c_str(),
1456                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[1],
1457                                          node->keyIndex()).c_str(),
1458                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[2],
1459                                          node->keyIndex()).c_str(),
1460                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[3],
1461                                          node->keyIndex()).c_str(),
1462                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[4],
1463                                          node->keyIndex()).c_str());
1464         SkSL::String::appendf(
1465                 &preamble,
1466                 "half4 %s(half4 inColor) {"
1467                     "return sk_color_space_transform(inColor, %s, %s, %s, %s, %s);"
1468                 "}",
1469                 get_mangled_name("fromLinearSRGB", node->keyIndex()).c_str(),
1470                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[5],
1471                                          node->keyIndex()).c_str(),
1472                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[6],
1473                                          node->keyIndex()).c_str(),
1474                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[7],
1475                                          node->keyIndex()).c_str(),
1476                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[8],
1477                                          node->keyIndex()).c_str(),
1478                 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[9],
1479                                          node->keyIndex()).c_str());
1480     }
1481 
1482     GraphitePipelineCallbacks callbacks{shaderInfo, node, &preamble, effect};
1483     SkSL::PipelineStage::ConvertProgram(program, "coords", "inColor", "destColor", &callbacks);
1484     return preamble;
1485 }
1486 
GenerateRuntimeShaderExpression(const ShaderInfo & shaderInfo,const ShaderNode * node,const ShaderSnippet::Args & args)1487 std::string GenerateRuntimeShaderExpression(const ShaderInfo& shaderInfo,
1488                                             const ShaderNode* node,
1489                                             const ShaderSnippet::Args& args) {
1490     return SkSL::String::printf(
1491             "%s(%.*s, %.*s, %.*s)",
1492             get_mangled_name(node->entry()->fName, node->keyIndex()).c_str(),
1493             (int)args.fPriorStageOutput.size(), args.fPriorStageOutput.data(),
1494             (int)args.fBlenderDstColor.size(),  args.fBlenderDstColor.data(),
1495             (int)args.fFragCoord.size(),        args.fFragCoord.data());
1496 }
1497 
1498 //--------------------------------------------------------------------------------------------------
1499 // TODO: investigate the implications of having separate hlsa and rgba matrix colorfilters. It
1500 // may be that having them separate will not contribute to combinatorial explosion.
1501 static constexpr Uniform kMatrixColorFilterUniforms[] = {
1502         { "matrix",    SkSLType::kFloat4x4 },
1503         { "translate", SkSLType::kFloat4 },
1504         { "inHSL",     SkSLType::kInt },
1505 };
1506 
1507 static constexpr char kMatrixColorFilterName[] = "sk_matrix_colorfilter";
1508 
1509 //--------------------------------------------------------------------------------------------------
1510 static constexpr char kComposeName[] = "Compose";
1511 
1512 static constexpr int kNumComposeChildren = 2;
1513 
1514 // Compose two children, assuming the first child is the innermost.
GenerateNestedChildrenPreamble(const ShaderInfo & shaderInfo,const ShaderNode * node)1515 std::string GenerateNestedChildrenPreamble(const ShaderInfo& shaderInfo,
1516                                            const ShaderNode* node) {
1517     SkASSERT(node->numChildren() == 2);
1518 
1519     // Evaluate inner child.
1520     static constexpr char kUnusedDestColor[] = "half4(1)";
1521     std::string innerColor = emit_expression_for_entry(shaderInfo, node->child(0),
1522                                                        {"inColor", kUnusedDestColor, "coords"});
1523 
1524     // Evaluate outer child.
1525     std::string outerColor = emit_expression_for_entry(shaderInfo, node->child(1),
1526                                                        {innerColor, kUnusedDestColor, "coords"});
1527 
1528     // Create a helper function that invokes the inner expression, then passes that result to the
1529     // outer expression, and returns the composed result.
1530     std::string helperFnName = get_mangled_name(node->entry()->fName, node->keyIndex());
1531     return SkSL::String::printf("half4 %s(half4 inColor, half4 destColor, float2 coords) {"
1532                                     "return %s;"
1533                                 "}",
1534                                 helperFnName.c_str(),
1535                                 outerColor.c_str());
1536 }
1537 
1538 //--------------------------------------------------------------------------------------------------
1539 static constexpr TextureAndSampler kTableColorFilterTexturesAndSamplers[] = {
1540         {"tableSampler"},
1541 };
1542 
1543 static constexpr char kTableColorFilterName[] = "sk_table_colorfilter";
1544 
1545 //--------------------------------------------------------------------------------------------------
1546 static constexpr char kGaussianColorFilterName[] = "sk_gaussian_colorfilter";
1547 
1548 //--------------------------------------------------------------------------------------------------
1549 static constexpr Uniform kColorSpaceTransformUniforms[] = {
1550         { "flags",          SkSLType::kInt },
1551         { "srcKind",        SkSLType::kInt },
1552         { "gamutTransform", SkSLType::kHalf3x3 },
1553         { "dstKind",        SkSLType::kInt },
1554         { "csXformCoeffs",  SkSLType::kHalf4x4 },
1555 };
1556 
1557 static_assert(0 == static_cast<int>(skcms_TFType_Invalid),
1558               "ColorSpaceTransform code depends on skcms_TFType");
1559 static_assert(1 == static_cast<int>(skcms_TFType_sRGBish),
1560               "ColorSpaceTransform code depends on skcms_TFType");
1561 static_assert(2 == static_cast<int>(skcms_TFType_PQish),
1562               "ColorSpaceTransform code depends on skcms_TFType");
1563 static_assert(3 == static_cast<int>(skcms_TFType_HLGish),
1564               "ColorSpaceTransform code depends on skcms_TFType");
1565 static_assert(4 == static_cast<int>(skcms_TFType_HLGinvish),
1566               "ColorSpaceTransform code depends on skcms_TFType");
1567 
1568 // TODO: We can meaningfully check these when we can use C++20 features.
1569 // static_assert(0x1 == SkColorSpaceXformSteps::Flags{.unpremul = true}.mask(),
1570 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1571 // static_assert(0x2 == SkColorSpaceXformSteps::Flags{.linearize = true}.mask(),
1572 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1573 // static_assert(0x4 == SkColorSpaceXformSteps::Flags{.gamut_transform = true}.mask(),
1574 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1575 // static_assert(0x8 == SkColorSpaceXformSteps::Flags{.encode = true}.mask(),
1576 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1577 // static_assert(0x10 == SkColorSpaceXformSteps::Flags{.premul = true}.mask(),
1578 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1579 
1580 static constexpr char kColorSpaceTransformName[] = "sk_color_space_transform";
1581 
1582 //--------------------------------------------------------------------------------------------------
1583 static constexpr char kErrorName[] = "sk_error";
1584 
1585 //--------------------------------------------------------------------------------------------------
1586 static constexpr char kPassthroughShaderName[] = "sk_passthrough";
1587 
1588 //--------------------------------------------------------------------------------------------------
1589 
GeneratePrimitiveColorExpression(const ShaderInfo &,const ShaderNode * node,const ShaderSnippet::Args &)1590 std::string GeneratePrimitiveColorExpression(const ShaderInfo&,
1591                                              const ShaderNode* node,
1592                                              const ShaderSnippet::Args&) {
1593     return "primitiveColor";
1594 }
1595 
1596 //--------------------------------------------------------------------------------------------------
1597 
1598 } // anonymous namespace
1599 
1600 #if defined(SK_DEBUG)
isValidID(int snippetID) const1601 bool ShaderCodeDictionary::isValidID(int snippetID) const {
1602     if (snippetID < 0) {
1603         return false;
1604     }
1605 
1606     if (snippetID < kBuiltInCodeSnippetIDCount) {
1607         return true;
1608     }
1609     if (snippetID >= kSkiaKnownRuntimeEffectsStart && snippetID < kSkiaKnownRuntimeEffectsEnd) {
1610         return snippetID < kSkiaKnownRuntimeEffectsStart + kStableKeyCnt;
1611     }
1612 
1613     SkAutoSpinlock lock{fSpinLock};
1614 
1615     if (snippetID >= kUnknownRuntimeEffectIDStart) {
1616         int userDefinedCodeSnippetID = snippetID - kUnknownRuntimeEffectIDStart;
1617         return userDefinedCodeSnippetID < SkTo<int>(fUserDefinedCodeSnippets.size());
1618     }
1619 
1620     return false;
1621 }
1622 
dump(UniquePaintParamsID id) const1623 void ShaderCodeDictionary::dump(UniquePaintParamsID id) const {
1624     this->lookup(id).dump(this, id);
1625 }
1626 #endif
1627 
1628 #if defined(GRAPHITE_TEST_UTILS)
1629 
addRuntimeEffectSnippet(const char * functionName)1630 int ShaderCodeDictionary::addRuntimeEffectSnippet(const char* functionName) {
1631     SkAutoSpinlock lock{fSpinLock};
1632 
1633     fUserDefinedCodeSnippets.push_back(
1634             std::make_unique<ShaderSnippet>("UserDefined",
1635                                             SkSpan<const Uniform>(),            // no uniforms
1636                                             SnippetRequirementFlags::kNone,
1637                                             SkSpan<const TextureAndSampler>(),  // no samplers
1638                                             functionName,
1639                                             GenerateDefaultExpression,
1640                                             GenerateDefaultPreamble,
1641                                             kNoChildren));
1642 
1643     return kUnknownRuntimeEffectIDStart + fUserDefinedCodeSnippets.size() - 1;
1644 }
1645 
1646 #endif // GRAPHITE_TEST_UTILS
1647 
uniform_type_to_sksl_type(const SkRuntimeEffect::Uniform & u)1648 static SkSLType uniform_type_to_sksl_type(const SkRuntimeEffect::Uniform& u) {
1649     using Type = SkRuntimeEffect::Uniform::Type;
1650     if (u.flags & SkRuntimeEffect::Uniform::kHalfPrecision_Flag) {
1651         switch (u.type) {
1652             case Type::kFloat:    return SkSLType::kHalf;
1653             case Type::kFloat2:   return SkSLType::kHalf2;
1654             case Type::kFloat3:   return SkSLType::kHalf3;
1655             case Type::kFloat4:   return SkSLType::kHalf4;
1656             case Type::kFloat2x2: return SkSLType::kHalf2x2;
1657             case Type::kFloat3x3: return SkSLType::kHalf3x3;
1658             case Type::kFloat4x4: return SkSLType::kHalf4x4;
1659             // NOTE: shorts cannot be uniforms, so we shouldn't ever get here.
1660             // Defensively return the full precision integer type.
1661             case Type::kInt:      SkDEBUGFAIL("unsupported uniform type"); return SkSLType::kInt;
1662             case Type::kInt2:     SkDEBUGFAIL("unsupported uniform type"); return SkSLType::kInt2;
1663             case Type::kInt3:     SkDEBUGFAIL("unsupported uniform type"); return SkSLType::kInt3;
1664             case Type::kInt4:     SkDEBUGFAIL("unsupported uniform type"); return SkSLType::kInt4;
1665         }
1666     } else {
1667         switch (u.type) {
1668             case Type::kFloat:    return SkSLType::kFloat;
1669             case Type::kFloat2:   return SkSLType::kFloat2;
1670             case Type::kFloat3:   return SkSLType::kFloat3;
1671             case Type::kFloat4:   return SkSLType::kFloat4;
1672             case Type::kFloat2x2: return SkSLType::kFloat2x2;
1673             case Type::kFloat3x3: return SkSLType::kFloat3x3;
1674             case Type::kFloat4x4: return SkSLType::kFloat4x4;
1675             case Type::kInt:      return SkSLType::kInt;
1676             case Type::kInt2:     return SkSLType::kInt2;
1677             case Type::kInt3:     return SkSLType::kInt3;
1678             case Type::kInt4:     return SkSLType::kInt4;
1679         }
1680     }
1681     SkUNREACHABLE;
1682 }
1683 
addTextToArena(std::string_view text)1684 const char* ShaderCodeDictionary::addTextToArena(std::string_view text) {
1685     char* textInArena = fArena.makeArrayDefault<char>(text.size() + 1);
1686     memcpy(textInArena, text.data(), text.size());
1687     textInArena[text.size()] = '\0';
1688     return textInArena;
1689 }
1690 
convertUniforms(const SkRuntimeEffect * effect)1691 SkSpan<const Uniform> ShaderCodeDictionary::convertUniforms(const SkRuntimeEffect* effect) {
1692     using rteUniform = SkRuntimeEffect::Uniform;
1693     SkSpan<const rteUniform> uniforms = effect->uniforms();
1694 
1695     int numBaseUniforms = uniforms.size();
1696     int xtraUniforms = 0;
1697     if (SkRuntimeEffectPriv::UsesColorTransform(effect)) {
1698         xtraUniforms += std::size(kRuntimeEffectColorSpaceTransformUniforms);
1699     }
1700 
1701     // Convert the SkRuntimeEffect::Uniform array into its Uniform equivalent.
1702     int numUniforms = numBaseUniforms + xtraUniforms;
1703     Uniform* uniformArray = fArena.makeInitializedArray<Uniform>(numUniforms, [&](int index) {
1704         if (index >= numBaseUniforms) {
1705             return kRuntimeEffectColorSpaceTransformUniforms[index - numBaseUniforms];
1706         }
1707 
1708         const rteUniform* u;
1709         u = &uniforms[index];
1710 
1711         // The existing uniform names live in the passed-in SkRuntimeEffect and may eventually
1712         // disappear. Copy them into fArena. (It's safe to do this within makeInitializedArray; the
1713         // entire array is allocated in one big slab before any initialization calls are done.)
1714         const char* name = this->addTextToArena(u->name);
1715 
1716         // Add one Uniform to our array.
1717         SkSLType type = uniform_type_to_sksl_type(*u);
1718         return (u->flags & rteUniform::kArray_Flag) ? Uniform(name, type, u->count)
1719                                                     : Uniform(name, type);
1720     });
1721 
1722     return SkSpan<const Uniform>(uniformArray, numUniforms);
1723 }
1724 
findOrCreateRuntimeEffectSnippet(const SkRuntimeEffect * effect)1725 int ShaderCodeDictionary::findOrCreateRuntimeEffectSnippet(const SkRuntimeEffect* effect) {
1726     SkEnumBitMask<SnippetRequirementFlags> snippetFlags = SnippetRequirementFlags::kNone;
1727     if (effect->allowShader()) {
1728         snippetFlags |= SnippetRequirementFlags::kLocalCoords;
1729     }
1730     if (effect->allowBlender()) {
1731         snippetFlags |= SnippetRequirementFlags::kBlenderDstColor;
1732     }
1733 
1734     SkAutoSpinlock lock{fSpinLock};
1735 
1736     if (int stableKey = SkRuntimeEffectPriv::StableKey(*effect)) {
1737         SkASSERT(stableKey >= kSkiaKnownRuntimeEffectsStart &&
1738                  stableKey < kSkiaKnownRuntimeEffectsStart + kStableKeyCnt);
1739 
1740         int index = stableKey - kSkiaKnownRuntimeEffectsStart;
1741 
1742         if (!fKnownRuntimeEffectCodeSnippets[index].fExpressionGenerator) {
1743             const char* name = get_known_rte_name(static_cast<StableKey>(stableKey));
1744             fKnownRuntimeEffectCodeSnippets[index] = ShaderSnippet(
1745                     name,
1746                     this->convertUniforms(effect),
1747                     snippetFlags,
1748                     /* texturesAndSamplers= */ {},
1749                     name,
1750                     GenerateRuntimeShaderExpression,
1751                     GenerateRuntimeShaderPreamble,
1752                     (int)effect->children().size());
1753         }
1754 
1755         return stableKey;
1756     }
1757 
1758     // Use the combination of {SkSL program hash, uniform size} as our key.
1759     // In the unfortunate event of a hash collision, at least we'll have the right amount of
1760     // uniform data available.
1761     RuntimeEffectKey key;
1762     key.fHash = SkRuntimeEffectPriv::Hash(*effect);
1763     key.fUniformSize = effect->uniformSize();
1764 
1765     int32_t* existingCodeSnippetID = fRuntimeEffectMap.find(key);
1766     if (existingCodeSnippetID) {
1767         return *existingCodeSnippetID;
1768     }
1769 
1770     // TODO: the memory for user-defined entries could go in the dictionary's arena but that
1771     // would have to be a thread safe allocation since the arena also stores entries for
1772     // 'fHash' and 'fEntryVector'
1773     fUserDefinedCodeSnippets.push_back(
1774         std::make_unique<ShaderSnippet>("RuntimeEffect",
1775                                         this->convertUniforms(effect),
1776                                         snippetFlags,
1777                                         /* texturesAndSamplers= */SkSpan<const TextureAndSampler>(),
1778                                         kRuntimeShaderName,
1779                                         GenerateRuntimeShaderExpression,
1780                                         GenerateRuntimeShaderPreamble,
1781                                         (int)effect->children().size()));
1782 
1783     int newCodeSnippetID = kUnknownRuntimeEffectIDStart + fUserDefinedCodeSnippets.size() - 1;
1784 
1785     fRuntimeEffectMap.set(key, newCodeSnippetID);
1786     return newCodeSnippetID;
1787 }
1788 
ShaderCodeDictionary()1789 ShaderCodeDictionary::ShaderCodeDictionary() {
1790     // The 0th index is reserved as invalid
1791     fIDToPaintKey.push_back(PaintParamsKey::Invalid());
1792 
1793     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kError] = {
1794             "Error",
1795             { },     // no uniforms
1796             SnippetRequirementFlags::kNone,
1797             { },     // no samplers
1798             kErrorName,
1799             GenerateDefaultExpression,
1800             GenerateDefaultPreamble,
1801             kNoChildren
1802     };
1803     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPriorOutput] = {
1804             "PassthroughShader",
1805             { },     // no uniforms
1806             SnippetRequirementFlags::kPriorStageOutput,
1807             { },     // no samplers
1808             kPassthroughShaderName,
1809             GenerateDefaultExpression,
1810             GenerateDefaultPreamble,
1811             kNoChildren
1812     };
1813     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSolidColorShader] = {
1814             "SolidColor",
1815             SkSpan(kSolidShaderUniforms),
1816             SnippetRequirementFlags::kNone,
1817             { },     // no samplers
1818             kSolidShaderName,
1819             GenerateDefaultExpression,
1820             GenerateDefaultPreamble,
1821             kNoChildren
1822     };
1823     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRGBPaintColor] = {
1824             "RGBPaintColor",
1825             SkSpan(kPaintColorUniforms),
1826             SnippetRequirementFlags::kNone,
1827             { },     // no samplers
1828             kRGBPaintColorName,
1829             GenerateDefaultExpression,
1830             GenerateDefaultPreamble,
1831             kNoChildren
1832     };
1833     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kAlphaOnlyPaintColor] = {
1834             "AlphaOnlyPaintColor",
1835             SkSpan(kPaintColorUniforms),
1836             SnippetRequirementFlags::kNone,
1837             { },     // no samplers
1838             kAlphaOnlyPaintColorName,
1839             GenerateDefaultExpression,
1840             GenerateDefaultPreamble,
1841             kNoChildren
1842     };
1843     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLinearGradientShader4] = {
1844             "LinearGradient4",
1845             SkSpan(kLinearGradientUniforms4),
1846             SnippetRequirementFlags::kLocalCoords,
1847             { },     // no samplers
1848             kLinearGradient4Name,
1849             GenerateDefaultExpression,
1850             GenerateDefaultPreamble,
1851             kNoChildren
1852     };
1853     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLinearGradientShader8] = {
1854             "LinearGradient8",
1855             SkSpan(kLinearGradientUniforms8),
1856             SnippetRequirementFlags::kLocalCoords,
1857             { },     // no samplers
1858             kLinearGradient8Name,
1859             GenerateDefaultExpression,
1860             GenerateDefaultPreamble,
1861             kNoChildren
1862     };
1863     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLinearGradientShaderTexture] = {
1864             "LinearGradientTexture",
1865             SkSpan(kLinearGradientUniformsTexture),
1866             SnippetRequirementFlags::kLocalCoords,
1867             SkSpan(kTextureGradientTexturesAndSamplers),
1868             kLinearGradientTextureName,
1869             GenerateDefaultExpression,
1870             GenerateDefaultPreamble,
1871             kNoChildren
1872     };
1873     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLinearGradientShaderBuffer] = {
1874             "LinearGradientBuffer",
1875             SkSpan(kLinearGradientUniformsBuffer),
1876             SnippetRequirementFlags::kLocalCoords | SnippetRequirementFlags::kGradientBuffer,
1877             { },     // no samplers
1878             kLinearGradientBufferName,
1879             GenerateGradientBufferExpression,
1880             GenerateGradientBufferPreamble,
1881             kNoChildren
1882     };
1883     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRadialGradientShader4] = {
1884             "RadialGradient4",
1885             SkSpan(kRadialGradientUniforms4),
1886             SnippetRequirementFlags::kLocalCoords,
1887             { },     // no samplers
1888             kRadialGradient4Name,
1889             GenerateDefaultExpression,
1890             GenerateDefaultPreamble,
1891             kNoChildren
1892     };
1893     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRadialGradientShader8] = {
1894             "RadialGradient8",
1895             SkSpan(kRadialGradientUniforms8),
1896             SnippetRequirementFlags::kLocalCoords,
1897             { },     // no samplers
1898             kRadialGradient8Name,
1899             GenerateDefaultExpression,
1900             GenerateDefaultPreamble,
1901             kNoChildren
1902     };
1903     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRadialGradientShaderTexture] = {
1904             "RadialGradientTexture",
1905             SkSpan(kRadialGradientUniformsTexture),
1906             SnippetRequirementFlags::kLocalCoords,
1907             SkSpan(kTextureGradientTexturesAndSamplers),
1908             kRadialGradientTextureName,
1909             GenerateDefaultExpression,
1910             GenerateDefaultPreamble,
1911             kNoChildren
1912     };
1913     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRadialGradientShaderBuffer] = {
1914             "RadialGradientBuffer",
1915             SkSpan(kRadialGradientUniformsBuffer),
1916             SnippetRequirementFlags::kLocalCoords | SnippetRequirementFlags::kGradientBuffer,
1917             { },     // no samplers
1918             kRadialGradientBufferName,
1919             GenerateGradientBufferExpression,
1920             GenerateGradientBufferPreamble,
1921             kNoChildren
1922     };
1923     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSweepGradientShader4] = {
1924             "SweepGradient4",
1925             SkSpan(kSweepGradientUniforms4),
1926             SnippetRequirementFlags::kLocalCoords,
1927             { },     // no samplers
1928             kSweepGradient4Name,
1929             GenerateDefaultExpression,
1930             GenerateDefaultPreamble,
1931             kNoChildren
1932     };
1933     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSweepGradientShader8] = {
1934             "SweepGradient8",
1935             SkSpan(kSweepGradientUniforms8),
1936             SnippetRequirementFlags::kLocalCoords,
1937             { },     // no samplers
1938             kSweepGradient8Name,
1939             GenerateDefaultExpression,
1940             GenerateDefaultPreamble,
1941             kNoChildren
1942     };
1943     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSweepGradientShaderTexture] = {
1944             "SweepGradientTexture",
1945             SkSpan(kSweepGradientUniformsTexture),
1946             SnippetRequirementFlags::kLocalCoords,
1947             SkSpan(kTextureGradientTexturesAndSamplers),
1948             kSweepGradientTextureName,
1949             GenerateDefaultExpression,
1950             GenerateDefaultPreamble,
1951             kNoChildren
1952     };
1953     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSweepGradientShaderBuffer] = {
1954             "SweepGradientBuffer",
1955             SkSpan(kSweepGradientUniformsBuffer),
1956             SnippetRequirementFlags::kLocalCoords | SnippetRequirementFlags::kGradientBuffer,
1957             { },     // no samplers
1958             kSweepGradientBufferName,
1959             GenerateGradientBufferExpression,
1960             GenerateGradientBufferPreamble,
1961             kNoChildren
1962     };
1963     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kConicalGradientShader4] = {
1964             "ConicalGradient4",
1965             SkSpan(kConicalGradientUniforms4),
1966             SnippetRequirementFlags::kLocalCoords,
1967             { },     // no samplers
1968             kConicalGradient4Name,
1969             GenerateDefaultExpression,
1970             GenerateDefaultPreamble,
1971             kNoChildren
1972     };
1973     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kConicalGradientShader8] = {
1974             "ConicalGradient8",
1975             SkSpan(kConicalGradientUniforms8),
1976             SnippetRequirementFlags::kLocalCoords,
1977             { },     // no samplers
1978             kConicalGradient8Name,
1979             GenerateDefaultExpression,
1980             GenerateDefaultPreamble,
1981             kNoChildren
1982     };
1983     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kConicalGradientShaderTexture] = {
1984             "ConicalGradientTexture",
1985             SkSpan(kConicalGradientUniformsTexture),
1986             SnippetRequirementFlags::kLocalCoords,
1987             SkSpan(kTextureGradientTexturesAndSamplers),
1988             kConicalGradientTextureName,
1989             GenerateDefaultExpression,
1990             GenerateDefaultPreamble,
1991             kNoChildren
1992     };
1993     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kConicalGradientShaderBuffer] = {
1994             "ConicalGradientBuffer",
1995             SkSpan(kConicalGradientUniformsBuffer),
1996             SnippetRequirementFlags::kLocalCoords | SnippetRequirementFlags::kGradientBuffer,
1997             { },     // no samplers
1998             kConicalGradientBufferName,
1999             GenerateGradientBufferExpression,
2000             GenerateGradientBufferPreamble,
2001             kNoChildren
2002     };
2003     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLocalMatrixShader] = {
2004             "LocalMatrixShader",
2005             SkSpan(kLocalMatrixShaderUniforms),
2006             (SnippetRequirementFlags::kPriorStageOutput |
2007              SnippetRequirementFlags::kLocalCoords),
2008             { },     // no samplers
2009             kLocalMatrixShaderName,
2010             GenerateDefaultExpression,
2011             GenerateLocalMatrixPreamble,
2012             kNumLocalMatrixShaderChildren
2013     };
2014     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kImageShader] = {
2015             "ImageShader",
2016             SkSpan(kImageShaderUniforms),
2017             SnippetRequirementFlags::kLocalCoords,
2018             SkSpan(kISTexturesAndSamplers),
2019             kImageShaderName,
2020             GenerateDefaultExpression,
2021             GenerateDefaultPreamble,
2022             kNoChildren
2023     };
2024     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCubicImageShader] = {
2025             "CubicImageShader",
2026             SkSpan(kCubicImageShaderUniforms),
2027             SnippetRequirementFlags::kLocalCoords,
2028             SkSpan(kISTexturesAndSamplers),
2029             kCubicImageShaderName,
2030             GenerateDefaultExpression,
2031             GenerateDefaultPreamble,
2032             kNoChildren
2033     };
2034     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kHWImageShader] = {
2035             "HardwareImageShader",
2036             SkSpan(kHWImageShaderUniforms),
2037             SnippetRequirementFlags::kLocalCoords,
2038             SkSpan(kISTexturesAndSamplers),
2039             kHWImageShaderName,
2040             GenerateDefaultExpression,
2041             GenerateDefaultPreamble,
2042             kNoChildren
2043     };
2044     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kYUVImageShader] = {
2045             "YUVImageShader",
2046             SkSpan(kYUVImageShaderUniforms),
2047             SnippetRequirementFlags::kLocalCoords,
2048             SkSpan(kYUVISTexturesAndSamplers),
2049             kYUVImageShaderName,
2050             GenerateDefaultExpression,
2051             GenerateDefaultPreamble,
2052             kNoChildren
2053     };
2054     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCubicYUVImageShader] = {
2055             "CubicYUVImageShader",
2056             SkSpan(kCubicYUVImageShaderUniforms),
2057             SnippetRequirementFlags::kLocalCoords,
2058             SkSpan(kYUVISTexturesAndSamplers),
2059             kCubicYUVImageShaderName,
2060             GenerateDefaultExpression,
2061             GenerateDefaultPreamble,
2062             kNoChildren
2063     };
2064     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCoordClampShader] = {
2065             "CoordClampShader",
2066             SkSpan(kCoordClampShaderUniforms),
2067             SnippetRequirementFlags::kLocalCoords,
2068             { },     // no samplers
2069             kCoordClampShaderName,
2070             GenerateDefaultExpression,
2071             GenerateCoordClampPreamble,
2072             kNumCoordClampShaderChildren
2073     };
2074     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kDitherShader] = {
2075             "DitherShader",
2076             SkSpan(kDitherShaderUniforms),
2077             (SnippetRequirementFlags::kPriorStageOutput | SnippetRequirementFlags::kLocalCoords),
2078             SkSpan(kDitherTexturesAndSamplers),
2079             kDitherShaderName,
2080             GenerateDefaultExpression,
2081             GenerateDefaultPreamble,
2082             kNoChildren
2083     };
2084     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPerlinNoiseShader] = {
2085             "PerlinNoiseShader",
2086             SkSpan(kPerlinNoiseShaderUniforms),
2087             SnippetRequirementFlags::kLocalCoords,
2088             SkSpan(kPerlinNoiseShaderTexturesAndSamplers),
2089             kPerlinNoiseShaderName,
2090             GenerateDefaultExpression,
2091             GenerateDefaultPreamble,
2092             kNoChildren
2093     };
2094     // SkColorFilter snippets
2095     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kMatrixColorFilter] = {
2096             "MatrixColorFilter",
2097             SkSpan(kMatrixColorFilterUniforms),
2098             SnippetRequirementFlags::kPriorStageOutput,
2099             { },     // no samplers
2100             kMatrixColorFilterName,
2101             GenerateDefaultExpression,
2102             GenerateDefaultPreamble,
2103             kNoChildren
2104     };
2105     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kTableColorFilter] = {
2106             "TableColorFilter",
2107             { },     // no uniforms
2108             SnippetRequirementFlags::kPriorStageOutput,
2109             SkSpan(kTableColorFilterTexturesAndSamplers),
2110             kTableColorFilterName,
2111             GenerateDefaultExpression,
2112             GenerateDefaultPreamble,
2113             kNoChildren
2114     };
2115     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kGaussianColorFilter] = {
2116             "GaussianColorFilter",
2117             { },     // no uniforms
2118             SnippetRequirementFlags::kPriorStageOutput,
2119             { },     // no samplers
2120             kGaussianColorFilterName,
2121             GenerateDefaultExpression,
2122             GenerateDefaultPreamble,
2123             kNoChildren
2124     };
2125     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kColorSpaceXformColorFilter] = {
2126             "ColorSpaceTransform",
2127             SkSpan(kColorSpaceTransformUniforms),
2128             SnippetRequirementFlags::kPriorStageOutput,
2129             { },     // no samplers
2130             kColorSpaceTransformName,
2131             GenerateDefaultExpression,
2132             GenerateDefaultPreamble,
2133             kNoChildren
2134     };
2135 
2136     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kBlendShader] = {
2137             "BlendShader",
2138             { },     // no uniforms
2139             SnippetRequirementFlags::kNone,
2140             { },     // no samplers
2141             "BlendShader",
2142             GenerateDefaultExpression,
2143             GenerateBlendShaderPreamble,
2144             kNumBlendShaderChildren
2145     };
2146     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCoeffBlender] = {
2147             "CoeffBlender",
2148             SkSpan(CoeffBlendderUniforms),
2149             SnippetRequirementFlags::kPriorStageOutput | SnippetRequirementFlags::kBlenderDstColor,
2150             { },     // no samplers
2151             kCoeffBlenderName,
2152             GenerateDefaultExpression,
2153             GenerateDefaultPreamble,
2154             kNoChildren
2155     };
2156     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kBlendModeBlender] = {
2157             "BlendModeBlender",
2158             SkSpan(kBlendModeBlenderUniforms),
2159             SnippetRequirementFlags::kPriorStageOutput | SnippetRequirementFlags::kBlenderDstColor,
2160             { },     // no samplers
2161             kBlendModeBlenderName,
2162             GenerateDefaultExpression,
2163             GenerateDefaultPreamble,
2164             kNoChildren
2165     };
2166 
2167     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPrimitiveColor] = {
2168             "PrimitiveColor",
2169             { },                // no uniforms
2170             SnippetRequirementFlags::kNone,
2171             { },                // no samplers
2172             "primitive color",  // no static sksl
2173             GeneratePrimitiveColorExpression,
2174             GenerateDefaultPreamble,
2175             kNoChildren
2176     };
2177 
2178     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kDstReadSample] = {
2179             "DstReadSample",
2180             SkSpan(kDstReadSampleUniforms),
2181             SnippetRequirementFlags::kSurfaceColor,
2182             SkSpan(kDstReadSampleTexturesAndSamplers),
2183             "InitSurfaceColor",
2184             GenerateDstReadSampleExpression,
2185             GenerateDstReadSamplePreamble,
2186             kNoChildren
2187     };
2188     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kDstReadFetch] = {
2189             "DstReadFetch",
2190             { },     // no uniforms
2191             SnippetRequirementFlags::kSurfaceColor,
2192             { },     // no samplers
2193             "InitSurfaceColor",
2194             GenerateDstReadFetchExpression,
2195             GenerateDstReadFetchPreamble,
2196             kNoChildren
2197     };
2198 
2199     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kClipShader] = {
2200             "ClipShader",
2201             { },            // no uniforms
2202             SnippetRequirementFlags::kNone,
2203             { },            // no samplers
2204             "clip shader",  // no static sksl
2205             GenerateClipShaderExpression,
2206             GenerateClipShaderPreamble,
2207             kNumClipShaderChildren
2208     };
2209 
2210     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCompose] = {
2211             "Compose",
2212             { },     // no uniforms
2213             SnippetRequirementFlags::kPriorStageOutput,
2214             { },     // no samplers
2215             kComposeName,
2216             GenerateDefaultExpression,
2217             GenerateNestedChildrenPreamble,
2218             kNumComposeChildren
2219     };
2220 
2221     // Fixed-function blend mode snippets are all the same, their functionality is entirely defined
2222     // by their unique code snippet IDs.
2223     for (int i = 0; i <= (int) SkBlendMode::kLastCoeffMode; ++i) {
2224         int ffBlendModeID = kFixedFunctionBlendModeIDOffset + i;
2225         fBuiltInCodeSnippets[ffBlendModeID] = {
2226                 SkBlendMode_Name(static_cast<SkBlendMode>(i)),
2227                 { },     // no uniforms
2228                 SnippetRequirementFlags::kPriorStageOutput |
2229                 SnippetRequirementFlags::kBlenderDstColor,
2230                 { },     // no samplers
2231                 skgpu::BlendFuncName(static_cast<SkBlendMode>(i)),
2232                 GenerateDefaultExpression,
2233                 GenerateDefaultPreamble,
2234                 kNoChildren
2235         };
2236     }
2237 }
2238 
2239 // Verify that the built-in code IDs for fixed function blending are consistent with SkBlendMode.
2240 // clang-format off
2241 static_assert((int)SkBlendMode::kClear    == (int)BuiltInCodeSnippetID::kFixedFunctionClearBlendMode    - kFixedFunctionBlendModeIDOffset);
2242 static_assert((int)SkBlendMode::kSrc      == (int)BuiltInCodeSnippetID::kFixedFunctionSrcBlendMode      - kFixedFunctionBlendModeIDOffset);
2243 static_assert((int)SkBlendMode::kDst      == (int)BuiltInCodeSnippetID::kFixedFunctionDstBlendMode      - kFixedFunctionBlendModeIDOffset);
2244 static_assert((int)SkBlendMode::kSrcOver  == (int)BuiltInCodeSnippetID::kFixedFunctionSrcOverBlendMode  - kFixedFunctionBlendModeIDOffset);
2245 static_assert((int)SkBlendMode::kDstOver  == (int)BuiltInCodeSnippetID::kFixedFunctionDstOverBlendMode  - kFixedFunctionBlendModeIDOffset);
2246 static_assert((int)SkBlendMode::kSrcIn    == (int)BuiltInCodeSnippetID::kFixedFunctionSrcInBlendMode    - kFixedFunctionBlendModeIDOffset);
2247 static_assert((int)SkBlendMode::kDstIn    == (int)BuiltInCodeSnippetID::kFixedFunctionDstInBlendMode    - kFixedFunctionBlendModeIDOffset);
2248 static_assert((int)SkBlendMode::kSrcOut   == (int)BuiltInCodeSnippetID::kFixedFunctionSrcOutBlendMode   - kFixedFunctionBlendModeIDOffset);
2249 static_assert((int)SkBlendMode::kDstOut   == (int)BuiltInCodeSnippetID::kFixedFunctionDstOutBlendMode   - kFixedFunctionBlendModeIDOffset);
2250 static_assert((int)SkBlendMode::kSrcATop  == (int)BuiltInCodeSnippetID::kFixedFunctionSrcATopBlendMode  - kFixedFunctionBlendModeIDOffset);
2251 static_assert((int)SkBlendMode::kDstATop  == (int)BuiltInCodeSnippetID::kFixedFunctionDstATopBlendMode  - kFixedFunctionBlendModeIDOffset);
2252 static_assert((int)SkBlendMode::kXor      == (int)BuiltInCodeSnippetID::kFixedFunctionXorBlendMode      - kFixedFunctionBlendModeIDOffset);
2253 static_assert((int)SkBlendMode::kPlus     == (int)BuiltInCodeSnippetID::kFixedFunctionPlusBlendMode     - kFixedFunctionBlendModeIDOffset);
2254 static_assert((int)SkBlendMode::kModulate == (int)BuiltInCodeSnippetID::kFixedFunctionModulateBlendMode - kFixedFunctionBlendModeIDOffset);
2255 static_assert((int)SkBlendMode::kScreen   == (int)BuiltInCodeSnippetID::kFixedFunctionScreenBlendMode   - kFixedFunctionBlendModeIDOffset);
2256 // clang-format on
2257 
2258 } // namespace skgpu::graphite
2259