• 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 "include/private/SkOpts_spi.h"
15 #include "include/private/SkSLString.h"
16 #include "src/core/SkColorSpacePriv.h"
17 #include "src/core/SkColorSpaceXformSteps.h"
18 #include "src/core/SkRuntimeEffectPriv.h"
19 #include "src/core/SkSLTypeShared.h"
20 #include "src/gpu/graphite/Caps.h"
21 #include "src/gpu/graphite/ContextUtils.h"
22 #include "src/gpu/graphite/ReadWriteSwizzle.h"
23 #include "src/gpu/graphite/Renderer.h"
24 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
25 #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
26 #include "src/sksl/ir/SkSLVarDeclarations.h"
27 
28 #include <new>
29 
30 namespace {
31 
get_mangled_name(const std::string & baseName,int manglingSuffix)32 std::string get_mangled_name(const std::string& baseName, int manglingSuffix) {
33     return baseName + "_" + std::to_string(manglingSuffix);
34 }
35 
36 } // anonymous namespace
37 
38 namespace skgpu::graphite {
39 
40 using DataPayloadField = PaintParamsKey::DataPayloadField;
41 using DataPayloadType = PaintParamsKey::DataPayloadType;
42 
getMangledUniformName(const ShaderInfo & shaderInfo,int uniformIdx,int mangleId) const43 std::string ShaderSnippet::getMangledUniformName(const ShaderInfo& shaderInfo,
44                                                  int uniformIdx,
45                                                  int mangleId) const {
46     std::string result;
47     result = fUniforms[uniformIdx].name() + std::string("_") + std::to_string(mangleId);
48     if (shaderInfo.ssboIndex()) {
49         result = EmitStorageBufferAccess("fs", shaderInfo.ssboIndex(), result.c_str());
50     }
51     return result;
52 }
53 
getMangledSamplerName(int samplerIdx,int mangleId) const54 std::string ShaderSnippet::getMangledSamplerName(int samplerIdx, int mangleId) const {
55     std::string result;
56     result = fTexturesAndSamplers[samplerIdx].name() + std::string("_") + std::to_string(mangleId);
57     return result;
58 }
59 
60 // Returns an expression to invoke this entry.
emit_expression_for_entry(const ShaderInfo & shaderInfo,int entryIndex,ShaderSnippet::Args args)61 static std::string emit_expression_for_entry(const ShaderInfo& shaderInfo,
62                                              int entryIndex,
63                                              ShaderSnippet::Args args) {
64     const PaintParamsKey::BlockReader& reader = shaderInfo.blockReader(entryIndex);
65     const ShaderSnippet* entry = reader.entry();
66 
67     return entry->fExpressionGenerator(shaderInfo, entryIndex, reader, args);
68 }
69 
70 // Emit the glue code needed to invoke a single static helper isolated within its own scope.
71 // Glue code will assign the resulting color into a variable `half4 outColor%d`, where the %d is
72 // filled in with 'entryIndex'.
emit_glue_code_for_entry(const ShaderInfo & shaderInfo,int entryIndex,const ShaderSnippet::Args & args,std::string * funcBody)73 static std::string emit_glue_code_for_entry(const ShaderInfo& shaderInfo,
74                                             int entryIndex,
75                                             const ShaderSnippet::Args& args,
76                                             std::string* funcBody) {
77     const ShaderSnippet* entry = shaderInfo.blockReader(entryIndex).entry();
78 
79     std::string expr = emit_expression_for_entry(shaderInfo, entryIndex, args);
80     std::string outputVar = get_mangled_name("outColor", entryIndex);
81     SkSL::String::appendf(funcBody,
82                           "// %s\n"
83                           "half4 %s = %s;",
84                           entry->fName,
85                           outputVar.c_str(),
86                           expr.c_str());
87     return outputVar;
88 }
89 
emit_preamble_for_entry(const ShaderInfo & shaderInfo,int * entryIndex,std::string * preamble)90 static void emit_preamble_for_entry(const ShaderInfo& shaderInfo,
91                                     int* entryIndex,
92                                     std::string* preamble) {
93     const PaintParamsKey::BlockReader& reader = shaderInfo.blockReader(*entryIndex);
94 
95     [[maybe_unused]] int startingEntryIndex = *entryIndex;
96     reader.entry()->fPreambleGenerator(shaderInfo, entryIndex, reader, preamble);
97 
98     // Preamble generators are responsible for increasing the entry index as entries are consumed.
99     SkASSERT(*entryIndex > startingEntryIndex);
100 }
101 
102 // The current, incomplete, model for shader construction is:
103 //   - Static code snippets (which can have an arbitrary signature) live in the Graphite
104 //     pre-compiled module, which is located at `src/sksl/sksl_graphite_frag.sksl`.
105 //   - Glue code is generated in a `main` method which calls these static code snippets.
106 //     The glue code is responsible for:
107 //            1) gathering the correct (mangled) uniforms
108 //            2) passing the uniforms and any other parameters to the helper method
109 //   - The result of the final code snippet is then copied into "sk_FragColor".
110 //   Note: each entry's 'fStaticFunctionName' field is expected to match the name of a function
111 //   in the Graphite pre-compiled module.
toSkSL(const ResourceBindingRequirements & bindingReqs,const RenderStep * step,const bool useStorageBuffers,const bool defineLocalCoordsVarying,int * numTexturesAndSamplersUsed) const112 std::string ShaderInfo::toSkSL(const ResourceBindingRequirements& bindingReqs,
113                                const RenderStep* step,
114                                const bool useStorageBuffers,
115                                const bool defineLocalCoordsVarying,
116                                int* numTexturesAndSamplersUsed) const {
117     std::string preamble = EmitVaryings(step,
118                                         /*direction=*/"in",
119                                         /*emitShadingSsboIndexVarying=*/useStorageBuffers,
120                                         defineLocalCoordsVarying);
121 
122     // The uniforms are mangled by having their index in 'fEntries' as a suffix (i.e., "_%d")
123     // TODO: replace hard-coded bufferIDs with the backend's step and paint uniform-buffer indices.
124     // TODO: The use of these indices is Metal-specific. We should replace these functions with
125     // API-independent ones.
126     if (step->numUniforms() > 0) {
127         preamble += EmitRenderStepUniforms(
128                 /*bufferID=*/1, "Step", bindingReqs.fUniformBufferLayout, step->uniforms());
129     }
130     if (this->ssboIndex()) {
131         preamble += EmitPaintParamsStorageBuffer(/*bufferID=*/2, "FS", "fs", fBlockReaders);
132     } else {
133         preamble += EmitPaintParamsUniforms(
134                 /*bufferID=*/2,
135                 "FS",
136                 useStorageBuffers ? bindingReqs.fStorageBufferLayout
137                                   : bindingReqs.fUniformBufferLayout,
138                 fBlockReaders);
139     }
140 
141     {
142         int binding = 0;
143         preamble += EmitTexturesAndSamplers(bindingReqs, fBlockReaders, &binding);
144         if (step->hasTextures()) {
145             preamble += step->texturesAndSamplersSkSL(bindingReqs, &binding);
146         }
147 
148         // Report back to the caller how many textures and samplers are used.
149         if (numTexturesAndSamplersUsed) {
150             *numTexturesAndSamplersUsed = binding;
151         }
152     }
153 
154     std::string mainBody = "void main() {";
155     // Set initial color. This will typically be optimized out by SkSL in favor of the paint
156     // specifying a color with a solid color shader.
157     std::string lastOutputVar = "initialColor";
158     mainBody += "half4 initialColor = half4(0);";
159 
160     if (step->emitsPrimitiveColor()) {
161         mainBody += "half4 primitiveColor;";
162         mainBody += step->fragmentColorSkSL();
163     }
164 
165     for (int entryIndex = 0; entryIndex < (int)fBlockReaders.size();) {
166         // Emit shader main body code. This never alters the preamble or increases the entry index.
167         static constexpr char kUnusedDestColor[] = "half4(1)";
168         static constexpr char kUnusedLocalCoordinates[] = "float2(0)";
169         const std::string localCoordinates = this->needsLocalCoords() ? "localCoordsVar"
170                                                                       : kUnusedLocalCoordinates;
171         lastOutputVar = emit_glue_code_for_entry(*this, entryIndex, {lastOutputVar,
172                                                  kUnusedDestColor, localCoordinates},
173                                                  &mainBody);
174 
175         // Emit preamble code. This iterates over all the children as well, and increases the entry
176         // index as we go.
177         emit_preamble_for_entry(*this, &entryIndex, &preamble);
178     }
179 
180     if (step->emitsCoverage()) {
181         mainBody += "half4 outputCoverage;";
182         mainBody += step->fragmentCoverageSkSL();
183         SkSL::String::appendf(&mainBody, "sk_FragColor = %s * outputCoverage;",
184                               lastOutputVar.c_str());
185     } else {
186         SkSL::String::appendf(&mainBody, "sk_FragColor = %s;", lastOutputVar.c_str());
187     }
188     mainBody += "}\n";
189 
190     return preamble + "\n" + mainBody;
191 }
192 
makeEntry(const PaintParamsKey & key,const skgpu::BlendInfo & blendInfo)193 ShaderCodeDictionary::Entry* ShaderCodeDictionary::makeEntry(const PaintParamsKey& key,
194                                                              const skgpu::BlendInfo& blendInfo) {
195     uint8_t* newKeyData = fArena.makeArray<uint8_t>(key.sizeInBytes());
196     memcpy(newKeyData, key.data(), key.sizeInBytes());
197 
198     SkSpan<const uint8_t> newKeyAsSpan = SkSpan(newKeyData, key.sizeInBytes());
199     return fArena.make([&](void *ptr) { return new(ptr) Entry(newKeyAsSpan, blendInfo); });
200 }
201 
operator ()(PaintParamsKeyPtr p) const202 size_t ShaderCodeDictionary::PaintParamsKeyPtr::Hash::operator()(PaintParamsKeyPtr p) const {
203     return SkOpts::hash_fn(p.fKey->data(), p.fKey->sizeInBytes(), 0);
204 }
205 
operator ()(RuntimeEffectKey k) const206 size_t ShaderCodeDictionary::RuntimeEffectKey::Hash::operator()(RuntimeEffectKey k) const {
207     return SkOpts::hash_fn(&k, sizeof(k), 0);
208 }
209 
findOrCreate(PaintParamsKeyBuilder * builder)210 const ShaderCodeDictionary::Entry* ShaderCodeDictionary::findOrCreate(
211         PaintParamsKeyBuilder* builder) {
212     PaintParamsKey key = builder->lockAsKey();
213 
214     SkAutoSpinlock lock{fSpinLock};
215 
216     Entry** existingEntry = fHash.find(PaintParamsKeyPtr{&key});
217     if (existingEntry) {
218         SkASSERT(fEntryVector[(*existingEntry)->uniqueID().asUInt()] == *existingEntry);
219         return *existingEntry;
220     }
221 
222     Entry* newEntry = this->makeEntry(key, builder->blendInfo());
223     newEntry->setUniqueID(fEntryVector.size());
224     fHash.set(PaintParamsKeyPtr{&newEntry->paintParamsKey()}, newEntry);
225     fEntryVector.push_back(newEntry);
226 
227     return newEntry;
228 }
229 
lookup(UniquePaintParamsID codeID) const230 const ShaderCodeDictionary::Entry* ShaderCodeDictionary::lookup(
231         UniquePaintParamsID codeID) const {
232 
233     if (!codeID.isValid()) {
234         return nullptr;
235     }
236 
237     SkAutoSpinlock lock{fSpinLock};
238 
239     SkASSERT(codeID.asUInt() < fEntryVector.size());
240 
241     return fEntryVector[codeID.asUInt()];
242 }
243 
getUniforms(BuiltInCodeSnippetID id) const244 SkSpan<const Uniform> ShaderCodeDictionary::getUniforms(BuiltInCodeSnippetID id) const {
245     return fBuiltInCodeSnippets[(int) id].fUniforms;
246 }
247 
dataPayloadExpectations(int codeSnippetID) const248 SkSpan<const DataPayloadField> ShaderCodeDictionary::dataPayloadExpectations(
249         int codeSnippetID) const {
250     // All callers of this entry point should already have ensured that 'codeSnippetID' is valid
251     return this->getEntry(codeSnippetID)->fDataPayloadExpectations;
252 }
253 
getEntry(int codeSnippetID) const254 const ShaderSnippet* ShaderCodeDictionary::getEntry(int codeSnippetID) const {
255     if (codeSnippetID < 0) {
256         return nullptr;
257     }
258 
259     if (codeSnippetID < kBuiltInCodeSnippetIDCount) {
260         return &fBuiltInCodeSnippets[codeSnippetID];
261     }
262 
263     int userDefinedCodeSnippetID = codeSnippetID - kBuiltInCodeSnippetIDCount;
264     if (userDefinedCodeSnippetID < SkTo<int>(fUserDefinedCodeSnippets.size())) {
265         return fUserDefinedCodeSnippets[userDefinedCodeSnippetID].get();
266     }
267 
268     return nullptr;
269 }
270 
getShaderInfo(UniquePaintParamsID uniqueID,ShaderInfo * info) const271 void ShaderCodeDictionary::getShaderInfo(UniquePaintParamsID uniqueID,
272                                          ShaderInfo* info) const {
273     auto entry = this->lookup(uniqueID);
274 
275     entry->paintParamsKey().toShaderInfo(this, info);
276     info->setBlendInfo(entry->blendInfo());
277 }
278 
279 //--------------------------------------------------------------------------------------------------
280 namespace {
281 
append_default_snippet_arguments(const ShaderInfo & shaderInfo,const ShaderSnippet * entry,int entryIndex,const ShaderSnippet::Args & args,SkSpan<const std::string> childOutputs)282 static std::string append_default_snippet_arguments(const ShaderInfo& shaderInfo,
283                                                     const ShaderSnippet* entry,
284                                                     int entryIndex,
285                                                     const ShaderSnippet::Args& args,
286                                                     SkSpan<const std::string> childOutputs) {
287     std::string code = "(";
288 
289     const char* separator = "";
290 
291     // Append prior-stage output color.
292     if (entry->needsPriorStageOutput()) {
293         code += args.fPriorStageOutput;
294         separator = ", ";
295     }
296 
297     // Append destination color.
298     if (entry->needsDestColor()) {
299         code += separator;
300         code += args.fDestColor;
301         separator = ", ";
302     }
303 
304     // Append fragment coordinates.
305     if (entry->needsLocalCoords()) {
306         code += separator;
307         code += args.fFragCoord;
308         separator = ", ";
309     }
310 
311     // Append uniform names.
312     for (size_t i = 0; i < entry->fUniforms.size(); ++i) {
313         code += separator;
314         separator = ", ";
315         code += entry->getMangledUniformName(shaderInfo, i, entryIndex);
316     }
317 
318     // Append samplers.
319     for (size_t i = 0; i < entry->fTexturesAndSamplers.size(); ++i) {
320         code += separator;
321         code += entry->getMangledSamplerName(i, entryIndex);
322         separator = ", ";
323     }
324 
325     // Append child output names.
326     for (const std::string& childOutputVar : childOutputs) {
327         code += separator;
328         separator = ", ";
329         code += childOutputVar;
330     }
331     code.push_back(')');
332 
333     return code;
334 }
335 
emit_helper_function(const ShaderInfo & shaderInfo,int * entryIndex,std::string * preamble)336 static void emit_helper_function(const ShaderInfo& shaderInfo,
337                                  int* entryIndex,
338                                  std::string* preamble) {
339     const PaintParamsKey::BlockReader& reader = shaderInfo.blockReader(*entryIndex);
340     const ShaderSnippet* entry = reader.entry();
341 
342     const int numChildren = reader.numChildren();
343     SkASSERT(numChildren == entry->fNumChildren);
344 
345     // Advance over the parent entry.
346     int curEntryIndex = *entryIndex;
347     *entryIndex += 1;
348 
349     // Create a helper function that invokes each of the children, then calls the entry's snippet
350     // and passes all the child outputs along as arguments.
351     std::string helperFnName = get_mangled_name(entry->fStaticFunctionName, curEntryIndex);
352     std::string helperFn = SkSL::String::printf(
353             "half4 %s(half4 inColor, half4 destColor, float2 pos) {",
354             helperFnName.c_str());
355     std::vector<std::string> childOutputVarNames;
356     const ShaderSnippet::Args args = {"inColor", "destColor", "pos"};
357     for (int j = 0; j < numChildren; ++j) {
358         // Emit glue code into our helper function body.
359         std::string childOutputVar = emit_glue_code_for_entry(shaderInfo, *entryIndex, args,
360                                                               &helperFn);
361         childOutputVarNames.push_back(std::move(childOutputVar));
362 
363         // If this entry itself requires a preamble, handle that here. This will advance the
364         // entry index forward as required.
365         emit_preamble_for_entry(shaderInfo, entryIndex, preamble);
366     }
367 
368     // Finally, invoke the snippet from the helper function, passing uniforms and child outputs.
369     std::string snippetArgList = append_default_snippet_arguments(shaderInfo, entry, curEntryIndex,
370                                                                   args, childOutputVarNames);
371     SkSL::String::appendf(&helperFn,
372                               "return %s%s;"
373                           "}",
374                           entry->fStaticFunctionName, snippetArgList.c_str());
375 
376     // Add our new helper function to the bottom of the preamble.
377     *preamble += helperFn;
378 }
379 
380 // If we have no children, the default expression just calls a built-in snippet with the signature:
381 //     half4 BuiltinFunctionName(/* default snippet arguments */);
382 //
383 // If we do have children, we will have created a glue function in the preamble and that is called
384 // instead. Its signature looks like this:
385 //     half4 BuiltinFunctionName_N(half4 inColor, half4 destColor, float2 pos);
386 
GenerateDefaultExpression(const ShaderInfo & shaderInfo,int entryIndex,const PaintParamsKey::BlockReader & reader,const ShaderSnippet::Args & args)387 std::string GenerateDefaultExpression(const ShaderInfo& shaderInfo,
388                                       int entryIndex,
389                                       const PaintParamsKey::BlockReader& reader,
390                                       const ShaderSnippet::Args& args) {
391     const ShaderSnippet* entry = reader.entry();
392     if (entry->fNumChildren == 0) {
393         // We don't have any children; return an expression which invokes the snippet directly.
394         return entry->fStaticFunctionName + append_default_snippet_arguments(shaderInfo,
395                                                                              entry,
396                                                                              entryIndex,
397                                                                              args,
398                                                                              /*childOutputs=*/{});
399     } else {
400         // Return an expression which invokes the helper function from the preamble.
401         std::string helperFnName = get_mangled_name(entry->fStaticFunctionName, entryIndex);
402         return SkSL::String::printf("%s(%.*s, %.*s, %.*s)",
403                                   helperFnName.c_str(),
404                                   (int)args.fPriorStageOutput.size(), args.fPriorStageOutput.data(),
405                                   (int)args.fDestColor.size(),        args.fDestColor.data(),
406                                   (int)args.fFragCoord.size(),        args.fFragCoord.data());
407     }
408 }
409 
410 // If we have no children, we don't need to add anything into the preamble.
411 // If we have child entries, we create a function in the preamble with a signature of:
412 //     half4 BuiltinFunctionName_N(half4 inColor, half4 destColor, float2 pos) { ... }
413 // This function invokes each child in sequence, and then calls the built-in function, passing all
414 // uniforms and child outputs along:
415 //     half4 BuiltinFunctionName(/* all uniforms as parameters */,
416 //                               /* all child output variable names as parameters */);
GenerateDefaultPreamble(const ShaderInfo & shaderInfo,int * entryIndex,const PaintParamsKey::BlockReader & reader,std::string * preamble)417 void GenerateDefaultPreamble(const ShaderInfo& shaderInfo,
418                              int* entryIndex,
419                              const PaintParamsKey::BlockReader& reader,
420                              std::string* preamble) {
421     const ShaderSnippet* entry = reader.entry();
422 
423     if (entry->fNumChildren > 0) {
424         // Create a helper function which invokes all the child snippets.
425         emit_helper_function(shaderInfo, entryIndex, preamble);
426     } else {
427         // We don't need a helper function; just advance over this entry.
428         SkASSERT(reader.numChildren() == 0);
429         *entryIndex += 1;
430     }
431 }
432 
433 //--------------------------------------------------------------------------------------------------
434 static constexpr int kFourStopGradient = 4;
435 static constexpr int kEightStopGradient = 8;
436 
437 static constexpr Uniform kLinearGradientUniforms4[7] = {
438         { "colors",      SkSLType::kFloat4, kFourStopGradient },
439         { "offsets",     SkSLType::kFloat,  kFourStopGradient },
440         { "point0",      SkSLType::kFloat2 },
441         { "point1",      SkSLType::kFloat2 },
442         { "tilemode",    SkSLType::kInt },
443         { "colorSpace",  SkSLType::kInt },
444         { "doUnPremul",  SkSLType::kInt },
445 };
446 static constexpr Uniform kLinearGradientUniforms8[7] = {
447         { "colors",      SkSLType::kFloat4, kEightStopGradient },
448         { "offsets",     SkSLType::kFloat,  kEightStopGradient },
449         { "point0",      SkSLType::kFloat2 },
450         { "point1",      SkSLType::kFloat2 },
451         { "tilemode",    SkSLType::kInt },
452         { "colorSpace",  SkSLType::kInt },
453         { "doUnPremul",  SkSLType::kInt },
454 };
455 
456 static constexpr Uniform kRadialGradientUniforms4[7] = {
457         { "colors",      SkSLType::kFloat4, kFourStopGradient },
458         { "offsets",     SkSLType::kFloat,  kFourStopGradient },
459         { "center",      SkSLType::kFloat2 },
460         { "radius",      SkSLType::kFloat },
461         { "tilemode",    SkSLType::kInt },
462         { "colorSpace",  SkSLType::kInt },
463         { "doUnPremul",  SkSLType::kInt },
464 };
465 static constexpr Uniform kRadialGradientUniforms8[7] = {
466         { "colors",      SkSLType::kFloat4, kEightStopGradient },
467         { "offsets",     SkSLType::kFloat,  kEightStopGradient },
468         { "center",      SkSLType::kFloat2 },
469         { "radius",      SkSLType::kFloat },
470         { "tilemode",    SkSLType::kInt },
471         { "colorSpace",  SkSLType::kInt },
472         { "doUnPremul",  SkSLType::kInt },
473 };
474 
475 static constexpr Uniform kSweepGradientUniforms4[8] = {
476         { "colors",      SkSLType::kFloat4, kFourStopGradient },
477         { "offsets",     SkSLType::kFloat,  kFourStopGradient },
478         { "center",      SkSLType::kFloat2 },
479         { "bias",        SkSLType::kFloat },
480         { "scale",       SkSLType::kFloat },
481         { "tilemode",    SkSLType::kInt },
482         { "colorSpace",  SkSLType::kInt },
483         { "doUnPremul",  SkSLType::kInt },
484 };
485 static constexpr Uniform kSweepGradientUniforms8[8] = {
486         { "colors",      SkSLType::kFloat4, kEightStopGradient },
487         { "offsets",     SkSLType::kFloat,  kEightStopGradient },
488         { "center",      SkSLType::kFloat2 },
489         { "bias",        SkSLType::kFloat },
490         { "scale",       SkSLType::kFloat },
491         { "tilemode",    SkSLType::kInt },
492         { "colorSpace",  SkSLType::kInt },
493         { "doUnPremul",  SkSLType::kInt },
494 };
495 
496 static constexpr Uniform kConicalGradientUniforms4[9] = {
497         { "colors",      SkSLType::kFloat4, kFourStopGradient },
498         { "offsets",     SkSLType::kFloat,  kFourStopGradient },
499         { "point0",      SkSLType::kFloat2 },
500         { "point1",      SkSLType::kFloat2 },
501         { "radius0",     SkSLType::kFloat },
502         { "radius1",     SkSLType::kFloat },
503         { "tilemode",    SkSLType::kInt },
504         { "colorSpace",  SkSLType::kInt },
505         { "doUnPremul",  SkSLType::kInt },
506 };
507 static constexpr Uniform kConicalGradientUniforms8[9] = {
508         { "colors",      SkSLType::kFloat4, kEightStopGradient },
509         { "offsets",     SkSLType::kFloat,  kEightStopGradient },
510         { "point0",      SkSLType::kFloat2 },
511         { "point1",      SkSLType::kFloat2 },
512         { "radius0",     SkSLType::kFloat },
513         { "radius1",     SkSLType::kFloat },
514         { "tilemode",    SkSLType::kInt },
515         { "colorSpace",  SkSLType::kInt },
516         { "doUnPremul",  SkSLType::kInt },
517 };
518 
519 static constexpr char kLinearGradient4Name[] = "sk_linear_grad_4_shader";
520 static constexpr char kLinearGradient8Name[] = "sk_linear_grad_8_shader";
521 static constexpr char kRadialGradient4Name[] = "sk_radial_grad_4_shader";
522 static constexpr char kRadialGradient8Name[] = "sk_radial_grad_8_shader";
523 static constexpr char kSweepGradient4Name[] = "sk_sweep_grad_4_shader";
524 static constexpr char kSweepGradient8Name[] = "sk_sweep_grad_8_shader";
525 static constexpr char kConicalGradient4Name[] = "sk_conical_grad_4_shader";
526 static constexpr char kConicalGradient8Name[] = "sk_conical_grad_8_shader";
527 
528 //--------------------------------------------------------------------------------------------------
529 static constexpr Uniform kSolidShaderUniforms[] = {
530         { "color", SkSLType::kFloat4 }
531 };
532 
533 static constexpr char kSolidShaderName[] = "sk_solid_shader";
534 
535 //--------------------------------------------------------------------------------------------------
536 static constexpr Uniform kLocalMatrixShaderUniforms[] = {
537         { "localMatrix", SkSLType::kFloat4x4 },
538 };
539 
540 static constexpr int kNumLocalMatrixShaderChildren = 1;
541 
542 static constexpr char kLocalMatrixShaderName[] = "LocalMatrix";
543 
GenerateLocalMatrixPreamble(const ShaderInfo & shaderInfo,int * entryIndex,const PaintParamsKey::BlockReader & reader,std::string * preamble)544 void GenerateLocalMatrixPreamble(const ShaderInfo& shaderInfo,
545                                  int* entryIndex,
546                                  const PaintParamsKey::BlockReader& reader,
547                                  std::string* preamble) {
548     const ShaderSnippet* entry = reader.entry();
549     SkASSERT(entry->fNumChildren == kNumLocalMatrixShaderChildren);
550 
551     // Advance over the parent entry.
552     int curEntryIndex = *entryIndex;
553     *entryIndex += 1;
554 
555     // Get the child's evaluation expression.
556     static constexpr char kUnusedDestColor[] = "half4(1)";
557     std::string childExpr = emit_expression_for_entry(shaderInfo, *entryIndex,
558                                                       {"inColor", kUnusedDestColor, "coords"});
559     // Emit preamble code for child.
560     emit_preamble_for_entry(shaderInfo, entryIndex, preamble);
561 
562     std::string localMatrixUni = reader.entry()->getMangledUniformName(shaderInfo, 0,
563                                                                        curEntryIndex);
564 
565     /**
566      * Create a helper function that multiplies coordinates by a local matrix, invokes the child
567      * entry with those updated coordinates, and returns the result. This helper function meets the
568      * requirements for use with GenerateDefaultExpression, so there's no need to have a separate
569      * special GenerateLocalMatrixExpression.
570      */
571     std::string helperFnName = get_mangled_name(entry->fStaticFunctionName, curEntryIndex);
572     SkSL::String::appendf(preamble,
573                           "half4 %s(half4 inColor, half4 destColor, float2 coords) {"
574                               "coords = (%s * coords.xy01).xy;"
575                               "return %s;"
576                           "}",
577                           helperFnName.c_str(),
578                           localMatrixUni.c_str(),
579                           childExpr.c_str());
580 }
581 
582 //--------------------------------------------------------------------------------------------------
583 static constexpr int kNumXferFnCoeffs = 7;
584 
585 static constexpr Uniform kImageShaderUniforms[] = {
586         { "imgSize",               SkSLType::kFloat2 },
587         { "subset",                SkSLType::kFloat4 },
588         { "tilemodeX",             SkSLType::kInt },
589         { "tilemodeY",             SkSLType::kInt },
590         { "filterMode",            SkSLType::kInt },
591         { "useCubic",              SkSLType::kInt },
592         { "cubicCoeffs",           SkSLType::kFloat4x4 },
593         { "readSwizzle",           SkSLType::kInt },
594         // The next 6 uniforms are for the color space transformation
595         { "csXformFlags",          SkSLType::kInt },
596         { "csXformSrcKind",        SkSLType::kInt },
597         { "csXformDstKind",        SkSLType::kInt },
598         { "csXformSrcCoeffs",      SkSLType::kHalf, kNumXferFnCoeffs },
599         { "csXformDstCoeffs",      SkSLType::kHalf, kNumXferFnCoeffs },
600         { "csXformGamutTransform", SkSLType::kHalf3x3 },
601 };
602 
603 static constexpr TextureAndSampler kISTexturesAndSamplers[] = {
604         {"sampler"},
605 };
606 
607 static_assert(0 == static_cast<int>(SkTileMode::kClamp),  "ImageShader code depends on SkTileMode");
608 static_assert(1 == static_cast<int>(SkTileMode::kRepeat), "ImageShader code depends on SkTileMode");
609 static_assert(2 == static_cast<int>(SkTileMode::kMirror), "ImageShader code depends on SkTileMode");
610 static_assert(3 == static_cast<int>(SkTileMode::kDecal),  "ImageShader code depends on SkTileMode");
611 
612 static_assert(0 == static_cast<int>(SkFilterMode::kNearest),
613               "ImageShader code depends on SkFilterMode");
614 static_assert(1 == static_cast<int>(SkFilterMode::kLinear),
615               "ImageShader code depends on SkFilterMode");
616 
617 static_assert(0 == static_cast<int>(ReadSwizzle::kRGBA),
618               "ImageShader code depends on ReadSwizzle");
619 static_assert(1 == static_cast<int>(ReadSwizzle::kRGB1),
620               "ImageShader code depends on ReadSwizzle");
621 static_assert(2 == static_cast<int>(ReadSwizzle::kRRRR),
622               "ImageShader code depends on ReadSwizzle");
623 static_assert(3 == static_cast<int>(ReadSwizzle::kRRR1),
624               "ImageShader code depends on ReadSwizzle");
625 static_assert(4 == static_cast<int>(ReadSwizzle::kBGRA),
626               "ImageShader code depends on ReadSwizzle");
627 
628 static constexpr char kImageShaderName[] = "sk_image_shader";
629 
630 //--------------------------------------------------------------------------------------------------
631 static constexpr Uniform kPorterDuffBlendShaderUniforms[] = {
632         { "blendConstants", SkSLType::kHalf4 },
633 };
634 
635 static constexpr char kPorterDuffBlendShaderName[] = "porter_duff_blend_shader";
636 
637 //--------------------------------------------------------------------------------------------------
638 static constexpr Uniform kBlendShaderUniforms[] = {
639         { "blendMode", SkSLType::kInt },
640 };
641 
642 static constexpr char kBlendShaderName[] = "sk_blend_shader";
643 
644 static constexpr int kNumBlendShaderChildren = 2;
645 
646 //--------------------------------------------------------------------------------------------------
647 static constexpr char kColorFilterShaderName[] = "ColorFilterShader";
648 
649 static constexpr int kNumColorFilterShaderChildren = 2;
650 
651 //--------------------------------------------------------------------------------------------------
652 static constexpr char kRuntimeShaderName[] = "RuntimeEffect";
653 
654 class GraphitePipelineCallbacks : public SkSL::PipelineStage::Callbacks {
655 public:
GraphitePipelineCallbacks(const ShaderInfo & shaderInfo,int entryIndex,const std::vector<int> & childEntryIndices,std::string * preamble)656     GraphitePipelineCallbacks(const ShaderInfo& shaderInfo,
657                               int entryIndex,
658                               const std::vector<int>& childEntryIndices,
659                               std::string* preamble)
660             : fShaderInfo(shaderInfo)
661             , fEntryIndex(entryIndex)
662             , fChildEntryIndices(childEntryIndices)
663             , fPreamble(preamble) {}
664 
declareUniform(const SkSL::VarDeclaration * decl)665     std::string declareUniform(const SkSL::VarDeclaration* decl) override {
666         std::string result = get_mangled_name(std::string(decl->var()->name()), fEntryIndex);
667         if (fShaderInfo.ssboIndex()) {
668             result = EmitStorageBufferAccess("fs", fShaderInfo.ssboIndex(), result.c_str());
669         }
670         return result;
671     }
672 
defineFunction(const char * decl,const char * body,bool isMain)673     void defineFunction(const char* decl, const char* body, bool isMain) override {
674         if (isMain) {
675             SkSL::String::appendf(
676                  fPreamble,
677                  "half4 %s_%d(half4 inColor, half4 destColor, float2 coords) {"
678                      "float2 pos = coords;"
679                      "%s"
680                  "}",
681                  kRuntimeShaderName,
682                  fEntryIndex,
683                  body);
684         } else {
685             SkSL::String::appendf(fPreamble, "%s {%s}\n", decl, body);
686         }
687     }
688 
declareFunction(const char * decl)689     void declareFunction(const char* decl) override {
690         *fPreamble += std::string(decl) + ";";
691     }
692 
defineStruct(const char * definition)693     void defineStruct(const char* definition) override {
694         *fPreamble += std::string(definition) + ";";
695     }
696 
declareGlobal(const char * declaration)697     void declareGlobal(const char* declaration) override {
698         *fPreamble += std::string(declaration) + ";";
699     }
700 
sampleShader(int index,std::string coords)701     std::string sampleShader(int index, std::string coords) override {
702         SkASSERT(index >= 0 && index < (int)fChildEntryIndices.size());
703         return emit_expression_for_entry(fShaderInfo, fChildEntryIndices[index],
704                                          {"inColor", "destColor", coords});
705     }
706 
sampleColorFilter(int index,std::string color)707     std::string sampleColorFilter(int index, std::string color) override {
708         SkASSERT(index >= 0 && index < (int)fChildEntryIndices.size());
709         return emit_expression_for_entry(fShaderInfo, fChildEntryIndices[index],
710                                          {color, "destColor", "coords"});
711     }
712 
sampleBlender(int index,std::string src,std::string dst)713     std::string sampleBlender(int index, std::string src, std::string dst) override {
714         return emit_expression_for_entry(fShaderInfo, fChildEntryIndices[index],
715                                          {src, dst, "coords"});
716     }
717 
toLinearSrgb(std::string color)718     std::string toLinearSrgb(std::string color) override {
719         // TODO(skia:13508): implement to-linear-SRGB child effect
720         return color;
721     }
fromLinearSrgb(std::string color)722     std::string fromLinearSrgb(std::string color) override {
723         // TODO(skia:13508): implement from-linear-SRGB child effect
724         return color;
725     }
726 
getMangledName(const char * name)727     std::string getMangledName(const char* name) override {
728         return get_mangled_name(name, fEntryIndex);
729     }
730 
731 private:
732     const ShaderInfo& fShaderInfo;
733     int fEntryIndex;
734     const std::vector<int>& fChildEntryIndices;
735     std::string* fPreamble;
736 };
737 
GenerateRuntimeShaderPreamble(const ShaderInfo & shaderInfo,int * entryIndex,const PaintParamsKey::BlockReader & reader,std::string * preamble)738 void GenerateRuntimeShaderPreamble(const ShaderInfo& shaderInfo,
739                                    int* entryIndex,
740                                    const PaintParamsKey::BlockReader& reader,
741                                    std::string* preamble) {
742     const ShaderSnippet* entry = reader.entry();
743 
744     // Advance over the parent entry.
745     int curEntryIndex = *entryIndex;
746     *entryIndex += 1;
747 
748     // Emit the preambles for all of our child effects (and advance the entry-index past them).
749     // This computes the indices of our child effects, which we use when invoking them below.
750     std::vector<int> childEntryIndices;
751     childEntryIndices.reserve(entry->fNumChildren);
752     for (int j = 0; j < entry->fNumChildren; ++j) {
753         childEntryIndices.push_back(*entryIndex);
754         emit_preamble_for_entry(shaderInfo, entryIndex, preamble);
755     }
756 
757     // Find this runtime effect in the runtime-effect dictionary.
758     const int codeSnippetId = reader.codeSnippetId();
759     const SkRuntimeEffect* effect = shaderInfo.runtimeEffectDictionary()->find(codeSnippetId);
760     SkASSERT(effect);
761     const SkSL::Program& program = SkRuntimeEffectPriv::Program(*effect);
762 
763     GraphitePipelineCallbacks callbacks{shaderInfo, curEntryIndex, childEntryIndices, preamble};
764     SkASSERT(std::string_view(entry->fName) == kRuntimeShaderName);  // the callbacks assume this
765     SkSL::PipelineStage::ConvertProgram(program, "pos", "inColor", "destColor", &callbacks);
766 }
767 
GenerateRuntimeShaderExpression(const ShaderInfo & shaderInfo,int entryIndex,const PaintParamsKey::BlockReader & reader,const ShaderSnippet::Args & args)768 std::string GenerateRuntimeShaderExpression(const ShaderInfo& shaderInfo,
769                                             int entryIndex,
770                                             const PaintParamsKey::BlockReader& reader,
771                                             const ShaderSnippet::Args& args) {
772     const ShaderSnippet* entry = reader.entry();
773     return SkSL::String::printf("%s_%d(%.*s, %.*s, %.*s)",
774                                 entry->fName,
775                                 entryIndex,
776                                 (int)args.fPriorStageOutput.size(), args.fPriorStageOutput.data(),
777                                 (int)args.fDestColor.size(),        args.fDestColor.data(),
778                                 (int)args.fFragCoord.size(),        args.fFragCoord.data());
779 }
780 
781 //--------------------------------------------------------------------------------------------------
782 // TODO: investigate the implications of having separate hlsa and rgba matrix colorfilters. It
783 // may be that having them separate will not contribute to combinatorial explosion.
784 static constexpr Uniform kMatrixColorFilterUniforms[] = {
785         { "matrix",    SkSLType::kFloat4x4 },
786         { "translate", SkSLType::kFloat4 },
787         { "inHSL",     SkSLType::kInt },
788 };
789 
790 static constexpr char kMatrixColorFilterName[] = "sk_matrix_colorfilter";
791 
792 //--------------------------------------------------------------------------------------------------
793 static constexpr Uniform kBlendColorFilterUniforms[] = {
794         { "blendMode", SkSLType::kInt },
795         { "color",     SkSLType::kFloat4 }
796 };
797 
798 static constexpr char kBlendColorFilterName[] = "sk_blend_colorfilter";
799 
800 //--------------------------------------------------------------------------------------------------
801 static constexpr char kComposeColorFilterName[] = "ComposeColorFilter";
802 
803 static constexpr int kNumComposeColorFilterChildren = 2;
804 
GenerateNestedChildrenPreamble(const ShaderInfo & shaderInfo,int * entryIndex,const PaintParamsKey::BlockReader & reader,std::string * preamble)805 void GenerateNestedChildrenPreamble(const ShaderInfo& shaderInfo,
806                                     int* entryIndex,
807                                     const PaintParamsKey::BlockReader& reader,
808                                     std::string* preamble) {
809     const ShaderSnippet* entry = reader.entry();
810     SkASSERT(entry->fNumChildren == 2);
811 
812     // Advance over the parent entry.
813     int curEntryIndex = *entryIndex;
814     *entryIndex += 1;
815 
816     // Evaluate inner child.
817     static constexpr char kUnusedDestColor[] = "half4(1)";
818     std::string innerColor = emit_expression_for_entry(shaderInfo, *entryIndex, {"inColor",
819                                                        kUnusedDestColor, "coords"});
820 
821     // Emit preamble code for inner child.
822     emit_preamble_for_entry(shaderInfo, entryIndex, preamble);
823 
824     // Evaluate outer child.
825     std::string outerColor = emit_expression_for_entry(shaderInfo, *entryIndex, {innerColor,
826                                                        kUnusedDestColor, "coords"});
827 
828     // Emit preamble code for outer child.
829     emit_preamble_for_entry(shaderInfo, entryIndex, preamble);
830 
831     // Create a helper function that invokes the inner expression, then passes that result to the
832     // outer expression, and returns the composed result.
833     std::string helperFnName = get_mangled_name(entry->fStaticFunctionName, curEntryIndex);
834     SkSL::String::appendf(
835             preamble,
836             "half4 %s(half4 inColor, half4 destColor, float2 coords) {"
837                 "return %s;"
838             "}",
839             helperFnName.c_str(),
840             outerColor.c_str());
841 }
842 
843 //--------------------------------------------------------------------------------------------------
844 static constexpr TextureAndSampler kTableColorFilterTexturesAndSamplers[] = {
845         {"tableSampler"},
846 };
847 
848 static constexpr char kTableColorFilterName[] = "sk_table_colorfilter";
849 
850 //--------------------------------------------------------------------------------------------------
851 static constexpr char kGaussianColorFilterName[] = "sk_gaussian_colorfilter";
852 
853 //--------------------------------------------------------------------------------------------------
854 static constexpr Uniform kColorSpaceTransformUniforms[] = {
855         { "flags",          SkSLType::kInt },
856         { "srcKind",        SkSLType::kInt },
857         { "dstKind",        SkSLType::kInt },
858         { "srcCoeffs",      SkSLType::kHalf, kNumXferFnCoeffs },
859         { "dstCoeffs",      SkSLType::kHalf, kNumXferFnCoeffs },
860         { "gamutTransform", SkSLType::kHalf3x3 },
861 };
862 
863 static_assert(0 == static_cast<int>(skcms_TFType_Invalid),
864               "ColorSpaceTransform code depends on skcms_TFType");
865 static_assert(1 == static_cast<int>(skcms_TFType_sRGBish),
866               "ColorSpaceTransform code depends on skcms_TFType");
867 static_assert(2 == static_cast<int>(skcms_TFType_PQish),
868               "ColorSpaceTransform code depends on skcms_TFType");
869 static_assert(3 == static_cast<int>(skcms_TFType_HLGish),
870               "ColorSpaceTransform code depends on skcms_TFType");
871 static_assert(4 == static_cast<int>(skcms_TFType_HLGinvish),
872               "ColorSpaceTransform code depends on skcms_TFType");
873 
874 // TODO: We can meaningfully check these when we can use C++20 features.
875 // static_assert(0x1 == SkColorSpaceXformSteps::Flags{.unpremul = true}.mask(),
876 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
877 // static_assert(0x2 == SkColorSpaceXformSteps::Flags{.linearize = true}.mask(),
878 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
879 // static_assert(0x4 == SkColorSpaceXformSteps::Flags{.gamut_transform = true}.mask(),
880 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
881 // static_assert(0x8 == SkColorSpaceXformSteps::Flags{.encode = true}.mask(),
882 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
883 // static_assert(0x10 == SkColorSpaceXformSteps::Flags{.premul = true}.mask(),
884 //               "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
885 
886 static constexpr char kColorSpaceTransformName[] = "sk_color_space_transform";
887 
888 //--------------------------------------------------------------------------------------------------
889 static constexpr char kErrorName[] = "sk_error";
890 
891 //--------------------------------------------------------------------------------------------------
892 static constexpr char kPassthroughShaderName[] = "sk_passthrough";
893 
894 //--------------------------------------------------------------------------------------------------
895 static constexpr char kPassthroughBlenderName[] = "blend_src_over";
896 
897 //--------------------------------------------------------------------------------------------------
898 static constexpr PaintParamsKey::DataPayloadField kFixedFunctionDataFields[] = {
899     { "blendMode", PaintParamsKey::DataPayloadType::kByte, 1},
900 };
901 
902 // This method generates the glue code for the case where the SkBlendMode-based blending is
903 // handled with fixed function blending.
GenerateFixedFunctionBlenderExpression(const ShaderInfo &,int entryIndex,const PaintParamsKey::BlockReader & reader,const ShaderSnippet::Args & args)904 std::string GenerateFixedFunctionBlenderExpression(const ShaderInfo&,
905                                                    int entryIndex,
906                                                    const PaintParamsKey::BlockReader& reader,
907                                                    const ShaderSnippet::Args& args) {
908     SkASSERT(reader.entry()->fUniforms.empty());
909     SkASSERT(reader.numDataPayloadFields() == 1);
910 
911     // The actual blending is set up via the fixed function pipeline so we don't actually
912     // need to access the blend mode in the glue code.
913     return std::string(args.fPriorStageOutput);
914 }
915 
916 //--------------------------------------------------------------------------------------------------
917 static constexpr Uniform kShaderBasedBlenderUniforms[] = {
918         { "blendMode", SkSLType::kInt },
919 };
920 
921 static constexpr char kBlendHelperName[] = "sk_blend";
922 
923 // This method generates the glue code for the case where the SkBlendMode-based blending must occur
924 // in the shader (i.e., fixed function blending isn't possible).
925 // It exists as custom glue code so that we can deal with the dest reads. If that can be
926 // standardized (e.g., via a snippets requirement flag) this could be removed.
GenerateShaderBasedBlenderExpression(const ShaderInfo & shaderInfo,int entryIndex,const PaintParamsKey::BlockReader & reader,const ShaderSnippet::Args & args)927 std::string GenerateShaderBasedBlenderExpression(const ShaderInfo& shaderInfo,
928                                                  int entryIndex,
929                                                  const PaintParamsKey::BlockReader& reader,
930                                                  const ShaderSnippet::Args& args) {
931     const bool usePrimitiveColorAsDst = reader.entry()->needsDestColor();
932 
933     SkASSERT(reader.entry()->fUniforms.size() == 1);
934     SkASSERT(reader.numDataPayloadFields() == 0);
935 
936     std::string uniformName = reader.entry()->getMangledUniformName(shaderInfo, 0, entryIndex);
937 
938     // TODO: emit function to perform dest read into preamble, and replace half4(1) with that call
939     // (The `args.destColor` variable might seem tempting here, but this is used for programmatic
940     // src+dest blends within the shader, not for blends against the destination surface.)
941     const char * destColor = usePrimitiveColorAsDst ? "primitiveColor" : "half4(1)";
942 
943     return SkSL::String::printf("%s(%s, %.*s, %s)",
944                                 reader.entry()->fStaticFunctionName,
945                                 uniformName.c_str(),
946                                 (int)args.fPriorStageOutput.size(), args.fPriorStageOutput.data(),
947                                 destColor);
948 }
949 
950 //--------------------------------------------------------------------------------------------------
951 
952 } // anonymous namespace
953 
isValidID(int snippetID) const954 bool ShaderCodeDictionary::isValidID(int snippetID) const {
955     if (snippetID < 0) {
956         return false;
957     }
958 
959     if (snippetID < kBuiltInCodeSnippetIDCount) {
960         return true;
961     }
962 
963     int userDefinedCodeSnippetID = snippetID - kBuiltInCodeSnippetIDCount;
964     return userDefinedCodeSnippetID < SkTo<int>(fUserDefinedCodeSnippets.size());
965 }
966 
967 static constexpr int kNoChildren = 0;
968 
addUserDefinedSnippet(const char * name,SkSpan<const Uniform> uniforms,SkEnumBitMask<SnippetRequirementFlags> snippetRequirementFlags,SkSpan<const TextureAndSampler> texturesAndSamplers,const char * functionName,ShaderSnippet::GenerateExpressionForSnippetFn expressionGenerator,ShaderSnippet::GeneratePreambleForSnippetFn preambleGenerator,int numChildren,SkSpan<const PaintParamsKey::DataPayloadField> dataPayloadExpectations)969 int ShaderCodeDictionary::addUserDefinedSnippet(
970         const char* name,
971         SkSpan<const Uniform> uniforms,
972         SkEnumBitMask<SnippetRequirementFlags> snippetRequirementFlags,
973         SkSpan<const TextureAndSampler> texturesAndSamplers,
974         const char* functionName,
975         ShaderSnippet::GenerateExpressionForSnippetFn expressionGenerator,
976         ShaderSnippet::GeneratePreambleForSnippetFn preambleGenerator,
977         int numChildren,
978         SkSpan<const PaintParamsKey::DataPayloadField> dataPayloadExpectations) {
979     // TODO: the memory for user-defined entries could go in the dictionary's arena but that
980     // would have to be a thread safe allocation since the arena also stores entries for
981     // 'fHash' and 'fEntryVector'
982     fUserDefinedCodeSnippets.push_back(std::make_unique<ShaderSnippet>(name,
983                                                                        uniforms,
984                                                                        snippetRequirementFlags,
985                                                                        texturesAndSamplers,
986                                                                        functionName,
987                                                                        expressionGenerator,
988                                                                        preambleGenerator,
989                                                                        numChildren,
990                                                                        dataPayloadExpectations));
991 
992     return kBuiltInCodeSnippetIDCount + fUserDefinedCodeSnippets.size() - 1;
993 }
994 
995 // TODO: this version needs to be removed
addUserDefinedSnippet(const char * name,SkSpan<const DataPayloadField> dataPayloadExpectations)996 int ShaderCodeDictionary::addUserDefinedSnippet(
997         const char* name,
998         SkSpan<const DataPayloadField> dataPayloadExpectations) {
999     return this->addUserDefinedSnippet("UserDefined",
1000                                        {},  // no uniforms
1001                                        SnippetRequirementFlags::kNone,
1002                                        {},  // no samplers
1003                                        name,
1004                                        GenerateDefaultExpression,
1005                                        GenerateDefaultPreamble,
1006                                        kNoChildren,
1007                                        dataPayloadExpectations);
1008 }
1009 
uniform_type_to_sksl_type(const SkRuntimeEffect::Uniform & u)1010 static SkSLType uniform_type_to_sksl_type(const SkRuntimeEffect::Uniform& u) {
1011     using Type = SkRuntimeEffect::Uniform::Type;
1012     if (u.flags & SkRuntimeEffect::Uniform::kHalfPrecision_Flag) {
1013         switch (u.type) {
1014             case Type::kFloat:    return SkSLType::kHalf;
1015             case Type::kFloat2:   return SkSLType::kHalf2;
1016             case Type::kFloat3:   return SkSLType::kHalf3;
1017             case Type::kFloat4:   return SkSLType::kHalf4;
1018             case Type::kFloat2x2: return SkSLType::kHalf2x2;
1019             case Type::kFloat3x3: return SkSLType::kHalf3x3;
1020             case Type::kFloat4x4: return SkSLType::kHalf4x4;
1021             case Type::kInt:      return SkSLType::kShort;
1022             case Type::kInt2:     return SkSLType::kShort2;
1023             case Type::kInt3:     return SkSLType::kShort3;
1024             case Type::kInt4:     return SkSLType::kShort4;
1025         }
1026     } else {
1027         switch (u.type) {
1028             case Type::kFloat:    return SkSLType::kFloat;
1029             case Type::kFloat2:   return SkSLType::kFloat2;
1030             case Type::kFloat3:   return SkSLType::kFloat3;
1031             case Type::kFloat4:   return SkSLType::kFloat4;
1032             case Type::kFloat2x2: return SkSLType::kFloat2x2;
1033             case Type::kFloat3x3: return SkSLType::kFloat3x3;
1034             case Type::kFloat4x4: return SkSLType::kFloat4x4;
1035             case Type::kInt:      return SkSLType::kInt;
1036             case Type::kInt2:     return SkSLType::kInt2;
1037             case Type::kInt3:     return SkSLType::kInt3;
1038             case Type::kInt4:     return SkSLType::kInt4;
1039         }
1040     }
1041     SkUNREACHABLE;
1042 }
1043 
addTextToArena(std::string_view text)1044 const char* ShaderCodeDictionary::addTextToArena(std::string_view text) {
1045     char* textInArena = fArena.makeArrayDefault<char>(text.size() + 1);
1046     memcpy(textInArena, text.data(), text.size());
1047     textInArena[text.size()] = '\0';
1048     return textInArena;
1049 }
1050 
convertUniforms(const SkRuntimeEffect * effect)1051 SkSpan<const Uniform> ShaderCodeDictionary::convertUniforms(const SkRuntimeEffect* effect) {
1052     using rteUniform = SkRuntimeEffect::Uniform;
1053     SkSpan<const rteUniform> uniforms = effect->uniforms();
1054 
1055     // Convert the SkRuntimeEffect::Uniform array into its Uniform equivalent.
1056     int numUniforms = uniforms.size();
1057     Uniform* uniformArray = fArena.makeInitializedArray<Uniform>(numUniforms, [&](int index) {
1058         const rteUniform* u;
1059         u = &uniforms[index];
1060 
1061         // The existing uniform names live in the passed-in SkRuntimeEffect and may eventually
1062         // disappear. Copy them into fArena. (It's safe to do this within makeInitializedArray; the
1063         // entire array is allocated in one big slab before any initialization calls are done.)
1064         const char* name = this->addTextToArena(u->name);
1065 
1066         // Add one Uniform to our array.
1067         SkSLType type = uniform_type_to_sksl_type(*u);
1068         return (u->flags & rteUniform::kArray_Flag) ? Uniform(name, type, u->count)
1069                                                     : Uniform(name, type);
1070     });
1071 
1072     return SkSpan<const Uniform>(uniformArray, numUniforms);
1073 }
1074 
findOrCreateRuntimeEffectSnippet(const SkRuntimeEffect * effect)1075 int ShaderCodeDictionary::findOrCreateRuntimeEffectSnippet(const SkRuntimeEffect* effect) {
1076     // Use the combination of {SkSL program hash, uniform size} as our key.
1077     // In the unfortunate event of a hash collision, at least we'll have the right amount of
1078     // uniform data available.
1079     RuntimeEffectKey key;
1080     key.fHash = SkRuntimeEffectPriv::Hash(*effect);
1081     key.fUniformSize = effect->uniformSize();
1082 
1083     SkAutoSpinlock lock{fSpinLock};
1084 
1085     int32_t* existingCodeSnippetID = fRuntimeEffectMap.find(key);
1086     if (existingCodeSnippetID) {
1087         return *existingCodeSnippetID;
1088     }
1089 
1090     SkEnumBitMask<SnippetRequirementFlags> snippetFlags = SnippetRequirementFlags::kNone;
1091     if (effect->allowShader()) {
1092         snippetFlags |= SnippetRequirementFlags::kLocalCoords;
1093     }
1094     if (effect->allowBlender()) {
1095         snippetFlags |= SnippetRequirementFlags::kDestColor;
1096     }
1097     int newCodeSnippetID = this->addUserDefinedSnippet("RuntimeEffect",
1098                                                        this->convertUniforms(effect),
1099                                                        snippetFlags,
1100                                                        /*texturesAndSamplers=*/{},
1101                                                        kRuntimeShaderName,
1102                                                        GenerateRuntimeShaderExpression,
1103                                                        GenerateRuntimeShaderPreamble,
1104                                                        (int)effect->children().size(),
1105                                                        /*dataPayloadExpectations=*/{});
1106     fRuntimeEffectMap.set(key, newCodeSnippetID);
1107     return newCodeSnippetID;
1108 }
1109 
ShaderCodeDictionary()1110 ShaderCodeDictionary::ShaderCodeDictionary() {
1111     // The 0th index is reserved as invalid
1112     fEntryVector.push_back(nullptr);
1113 
1114     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kError] = {
1115             "Error",
1116             { },     // no uniforms
1117             SnippetRequirementFlags::kNone,
1118             { },     // no samplers
1119             kErrorName,
1120             GenerateDefaultExpression,
1121             GenerateDefaultPreamble,
1122             kNoChildren,
1123             { }      // no data payload
1124     };
1125     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPassthroughShader] = {
1126             "PassthroughShader",
1127             { },     // no uniforms
1128             SnippetRequirementFlags::kPriorStageOutput,
1129             { },     // no samplers
1130             kPassthroughShaderName,
1131             GenerateDefaultExpression,
1132             GenerateDefaultPreamble,
1133             kNoChildren,
1134             { }      // no data payload
1135     };
1136     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPassthroughBlender] = {
1137             "PassthroughBlender",
1138             {},      // no uniforms
1139             SnippetRequirementFlags::kPriorStageOutput | SnippetRequirementFlags::kDestColor,
1140             {},      // no samplers
1141             kPassthroughBlenderName,
1142             GenerateDefaultExpression,
1143             GenerateDefaultPreamble,
1144             kNoChildren,
1145             {}       // no data payload
1146     };
1147     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSolidColorShader] = {
1148             "SolidColor",
1149             SkSpan(kSolidShaderUniforms),
1150             SnippetRequirementFlags::kNone,
1151             { },     // no samplers
1152             kSolidShaderName,
1153             GenerateDefaultExpression,
1154             GenerateDefaultPreamble,
1155             kNoChildren,
1156             { }      // no data payload
1157     };
1158     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLinearGradientShader4] = {
1159             "LinearGradient4",
1160             SkSpan(kLinearGradientUniforms4),
1161             SnippetRequirementFlags::kLocalCoords,
1162             { },     // no samplers
1163             kLinearGradient4Name,
1164             GenerateDefaultExpression,
1165             GenerateDefaultPreamble,
1166             kNoChildren,
1167             { }      // no data payload
1168     };
1169     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLinearGradientShader8] = {
1170             "LinearGradient8",
1171             SkSpan(kLinearGradientUniforms8),
1172             SnippetRequirementFlags::kLocalCoords,
1173             { },     // no samplers
1174             kLinearGradient8Name,
1175             GenerateDefaultExpression,
1176             GenerateDefaultPreamble,
1177             kNoChildren,
1178             { }      // no data payload
1179     };
1180     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRadialGradientShader4] = {
1181             "RadialGradient4",
1182             SkSpan(kRadialGradientUniforms4),
1183             SnippetRequirementFlags::kLocalCoords,
1184             { },     // no samplers
1185             kRadialGradient4Name,
1186             GenerateDefaultExpression,
1187             GenerateDefaultPreamble,
1188             kNoChildren,
1189             { }      // no data payload
1190     };
1191     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRadialGradientShader8] = {
1192             "RadialGradient8",
1193             SkSpan(kRadialGradientUniforms8),
1194             SnippetRequirementFlags::kLocalCoords,
1195             { },     // no samplers
1196             kRadialGradient8Name,
1197             GenerateDefaultExpression,
1198             GenerateDefaultPreamble,
1199             kNoChildren,
1200             { }      // no data payload
1201     };
1202     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSweepGradientShader4] = {
1203             "SweepGradient4",
1204             SkSpan(kSweepGradientUniforms4),
1205             SnippetRequirementFlags::kLocalCoords,
1206             { },     // no samplers
1207             kSweepGradient4Name,
1208             GenerateDefaultExpression,
1209             GenerateDefaultPreamble,
1210             kNoChildren,
1211             { }      // no data payload
1212     };
1213     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSweepGradientShader8] = {
1214             "SweepGradient8",
1215             SkSpan(kSweepGradientUniforms8),
1216             SnippetRequirementFlags::kLocalCoords,
1217             { },     // no samplers
1218             kSweepGradient8Name,
1219             GenerateDefaultExpression,
1220             GenerateDefaultPreamble,
1221             kNoChildren,
1222             { }      // no data payload
1223     };
1224     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kConicalGradientShader4] = {
1225             "ConicalGradient4",
1226             SkSpan(kConicalGradientUniforms4),
1227             SnippetRequirementFlags::kLocalCoords,
1228             { },     // no samplers
1229             kConicalGradient4Name,
1230             GenerateDefaultExpression,
1231             GenerateDefaultPreamble,
1232             kNoChildren,
1233             { }      // no data payload
1234     };
1235     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kConicalGradientShader8] = {
1236             "ConicalGradient8",
1237             SkSpan(kConicalGradientUniforms8),
1238             SnippetRequirementFlags::kLocalCoords,
1239             { },     // no samplers
1240             kConicalGradient8Name,
1241             GenerateDefaultExpression,
1242             GenerateDefaultPreamble,
1243             kNoChildren,
1244             { }      // no data payload
1245     };
1246     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLocalMatrixShader] = {
1247             "LocalMatrixShader",
1248             SkSpan(kLocalMatrixShaderUniforms),
1249             (SnippetRequirementFlags::kPriorStageOutput |
1250              SnippetRequirementFlags::kLocalCoords),
1251             { },     // no samplers
1252             kLocalMatrixShaderName,
1253             GenerateDefaultExpression,
1254             GenerateLocalMatrixPreamble,
1255             kNumLocalMatrixShaderChildren,
1256             { }      // no data payload
1257     };
1258     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kImageShader] = {
1259             "ImageShader",
1260             SkSpan(kImageShaderUniforms),
1261             SnippetRequirementFlags::kLocalCoords,
1262             SkSpan(kISTexturesAndSamplers),
1263             kImageShaderName,
1264             GenerateDefaultExpression,
1265             GenerateDefaultPreamble,
1266             kNoChildren,
1267             { }      // no data payload
1268     };
1269     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPorterDuffBlendShader] = {
1270             "PorterDuffBlendShader",
1271             SkSpan(kPorterDuffBlendShaderUniforms),
1272             SnippetRequirementFlags::kNone,
1273             { },     // no samplers
1274             kPorterDuffBlendShaderName,
1275             GenerateDefaultExpression,
1276             GenerateDefaultPreamble,
1277             kNumBlendShaderChildren,
1278             { }      // no data payload
1279     };
1280 
1281     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kBlendShader] = {
1282             "BlendShader",
1283             SkSpan(kBlendShaderUniforms),
1284             SnippetRequirementFlags::kNone,
1285             { },     // no samplers
1286             kBlendShaderName,
1287             GenerateDefaultExpression,
1288             GenerateDefaultPreamble,
1289             kNumBlendShaderChildren,
1290             { }      // no data payload
1291     };
1292 
1293     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kColorFilterShader] = {
1294             "ColorFilterShader",
1295             {},      // no uniforms
1296             SnippetRequirementFlags::kNone,
1297             { },     // no samplers
1298             kColorFilterShaderName,
1299             GenerateDefaultExpression,
1300             GenerateNestedChildrenPreamble,
1301             kNumColorFilterShaderChildren,
1302             { }      // no data payload
1303     };
1304 
1305     // SkColorFilter snippets
1306     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kMatrixColorFilter] = {
1307             "MatrixColorFilter",
1308             SkSpan(kMatrixColorFilterUniforms),
1309             SnippetRequirementFlags::kPriorStageOutput,
1310             { },     // no samplers
1311             kMatrixColorFilterName,
1312             GenerateDefaultExpression,
1313             GenerateDefaultPreamble,
1314             kNoChildren,
1315             { }      // no data payload
1316     };
1317     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kBlendColorFilter] = {
1318             "BlendColorFilter",
1319             SkSpan(kBlendColorFilterUniforms),
1320             SnippetRequirementFlags::kPriorStageOutput,
1321             { },     // no samplers
1322             kBlendColorFilterName,
1323             GenerateDefaultExpression,
1324             GenerateDefaultPreamble,
1325             kNoChildren,
1326             { }      // no data payload
1327     };
1328     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kComposeColorFilter] = {
1329             "ComposeColorFilter",
1330             { },     // no uniforms
1331             SnippetRequirementFlags::kPriorStageOutput,
1332             { },     // no samplers
1333             kComposeColorFilterName,
1334             GenerateDefaultExpression,
1335             GenerateNestedChildrenPreamble,
1336             kNumComposeColorFilterChildren,
1337             { }      // no data payload
1338     };
1339     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kTableColorFilter] = {
1340             "TableColorFilter",
1341             { },     // no uniforms
1342             SnippetRequirementFlags::kPriorStageOutput,
1343             SkSpan(kTableColorFilterTexturesAndSamplers),
1344             kTableColorFilterName,
1345             GenerateDefaultExpression,
1346             GenerateDefaultPreamble,
1347             kNoChildren,
1348             { }      // no data payload
1349     };
1350     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kGaussianColorFilter] = {
1351             "GaussianColorFilter",
1352             { },     // no uniforms
1353             SnippetRequirementFlags::kPriorStageOutput,
1354             { },     // no samplers
1355             kGaussianColorFilterName,
1356             GenerateDefaultExpression,
1357             GenerateDefaultPreamble,
1358             kNoChildren,
1359             { }      // no data payload
1360     };
1361     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kColorSpaceXformColorFilter] = {
1362             "ColorSpaceTransform",
1363             SkSpan(kColorSpaceTransformUniforms),
1364             SnippetRequirementFlags::kPriorStageOutput,
1365             { },     // no samplers
1366             kColorSpaceTransformName,
1367             GenerateDefaultExpression,
1368             GenerateDefaultPreamble,
1369             kNoChildren,
1370             { }      // no data payload
1371     };
1372     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kFixedFunctionBlender] = {
1373             "FixedFunctionBlender",
1374             { },     // no uniforms
1375             SnippetRequirementFlags::kNone,
1376             { },     // no samplers
1377             "FF-blending",  // fixed function blending doesn't use static SkSL
1378             GenerateFixedFunctionBlenderExpression,
1379             GenerateDefaultPreamble,
1380             kNoChildren,
1381             kFixedFunctionDataFields
1382     };
1383     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kShaderBasedBlender] = {
1384             "ShaderBasedBlender",
1385             SkSpan(kShaderBasedBlenderUniforms),
1386             SnippetRequirementFlags::kNone,
1387             { },     // no samplers
1388             kBlendHelperName,
1389             GenerateShaderBasedBlenderExpression,
1390             GenerateDefaultPreamble,
1391             kNoChildren,
1392             { }      // no data payload
1393     };
1394     fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPrimitiveColorShaderBasedBlender] = {
1395             "PrimitiveColorShaderBasedBlender",
1396             SkSpan(kShaderBasedBlenderUniforms),
1397             SnippetRequirementFlags::kDestColor,
1398             { },     // no samplers
1399             kBlendHelperName,
1400             GenerateShaderBasedBlenderExpression,
1401             GenerateDefaultPreamble,
1402             kNoChildren,
1403             { }      // no data payload
1404     };
1405 }
1406 
1407 } // namespace skgpu::graphite
1408