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