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