Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
ShaderCodeDictionary.cpp
Go to the documentation of this file.
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
9
19#include "src/gpu/Swizzle.h"
25#include "src/sksl/SkSLString.h"
26#include "src/sksl/SkSLUtil.h"
29
30#include <new>
31
32using namespace skia_private;
33using namespace SkKnownRuntimeEffects;
34
35namespace skgpu::graphite {
36
37static constexpr int kNoChildren = 0;
38static constexpr char kRuntimeShaderName[] = "RuntimeEffect";
39
40static_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.
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
61namespace {
62
63const 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;
69#undef M2
70#undef M1
71#undef M
72 }
73
75}
76
77std::string get_mangled_name(const std::string& baseName, int manglingSuffix) {
78 return baseName + "_" + std::to_string(manglingSuffix);
79}
80
81std::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
98std::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.
103std::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()'.
112std::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'.
129void emit_preambles(const ShaderInfo& shaderInfo,
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
154constexpr skgpu::BlendInfo make_simple_blendInfo(skgpu::BlendCoeff srcCoeff,
155 skgpu::BlendCoeff dstCoeff) {
157 srcCoeff,
158 dstCoeff,
161}
162
163static constexpr int kNumCoeffModes = (int)SkBlendMode::kLastCoeffMode + 1;
164static 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
187ShaderInfo::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() -
214 SkASSERT(static_cast<int>(fBlendMode) >= 0 &&
216 fBlendInfo = gBlendTable[static_cast<int>(fBlendMode)];
217 } else {
218 fSnippetRequirementFlags |= root->requiredFlags();
219 }
220 }
221}
222
223void append_color_output(std::string* mainBody,
224 BlendFormula::OutputType outputType,
225 const char* outColor,
226 const char* inColor) {
227 switch (outputType) {
229 SkSL::String::appendf(mainBody, "%s = half4(0.0);", outColor);
230 break;
232 SkSL::String::appendf(mainBody, "%s = outputCoverage;", outColor);
233 break;
235 SkSL::String::appendf(mainBody, "%s = %s * outputCoverage;", outColor, inColor);
236 break;
238 SkSL::String::appendf(mainBody, "%s = %s.a * outputCoverage;", outColor, inColor);
239 break;
242 mainBody, "%s = (1.0 - %s.a) * outputCoverage;", outColor, inColor);
243 break;
246 mainBody, "%s = (half4(1.0) - %s) * outputCoverage;", outColor, inColor);
247 break;
248 default:
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.
265std::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 Swizzle writeSwizzle) {
273 // If we're doing analytic coverage, we must also be doing shading.
274 SkASSERT(step->coverage() == Coverage::kNone || step->performsShading());
275 const bool hasStepUniforms = step->numUniforms() > 0 && step->coverage() != Coverage::kNone;
276 const bool useStepStorageBuffer = useStorageBuffers && hasStepUniforms;
277 const bool useShadingStorageBuffer = useStorageBuffers && step->performsShading();
278
279 const bool defineLocalCoordsVarying = this->needsLocalCoords();
280 std::string preamble = EmitVaryings(step,
281 /*direction=*/"in",
282 /*emitSsboIndicesVarying=*/useShadingStorageBuffer,
283 defineLocalCoordsVarying);
284
285 // The uniforms are mangled by having their index in 'fEntries' as a suffix (i.e., "_%d")
286 // TODO: replace hard-coded bufferIDs with the backend's step and paint uniform-buffer indices.
287 // TODO: The use of these indices is Metal-specific. We should replace these functions with
288 // API-independent ones.
289 const ResourceBindingRequirements& bindingReqs = caps->resourceBindingRequirements();
290 if (hasStepUniforms) {
291 if (useStepStorageBuffer) {
292 preamble += EmitRenderStepStorageBuffer(/*bufferID=*/1, step->uniforms());
293 } else {
294 preamble += EmitRenderStepUniforms(/*bufferID=*/1,
295 bindingReqs.fUniformBufferLayout,
296 step->uniforms(),
297 renderStepUniformTotalBytes);
298 }
299 }
300
301 bool wrotePaintColor = false;
302 if (useShadingStorageBuffer) {
303 preamble += EmitPaintParamsStorageBuffer(/*bufferID=*/2,
304 fRootNodes,
305 numPaintUniforms,
306 &wrotePaintColor);
307 SkSL::String::appendf(&preamble, "uint %s;\n", this->ssboIndex());
308 } else {
309 preamble += EmitPaintParamsUniforms(/*bufferID=*/2,
310 bindingReqs.fUniformBufferLayout,
311 fRootNodes,
312 numPaintUniforms,
313 paintUniformsTotalBytes,
314 &wrotePaintColor);
315 }
316
317 {
318 int binding = 0;
319 preamble += EmitTexturesAndSamplers(bindingReqs, fRootNodes, &binding);
320 if (step->hasTextures()) {
321 preamble += step->texturesAndSamplersSkSL(bindingReqs, &binding);
322 }
323
324 // Report back to the caller how many textures and samplers are used.
325 if (numTexturesAndSamplersUsed) {
326 *numTexturesAndSamplersUsed = binding;
327 }
328 }
329
330 if (step->emitsPrimitiveColor()) {
331 // TODO: Define this in the main body, and then pass it down into snippets like we do with
332 // the local coordinates varying.
333 preamble += "half4 primitiveColor;";
334 }
335
336 // Emit preamble declarations and helper functions required for snippets. In the default case
337 // this adds functions that bind a node's specific mangled uniforms to the snippet's
338 // implementation in the SkSL modules.
339 emit_preambles(*this, fRootNodes, /*treeLabel=*/"", &preamble);
340
341 std::string mainBody = "void main() {";
342 // Set initial color. This will typically be optimized out by SkSL in favor of the paint
343 // specifying a color with a solid color shader.
344 mainBody += "half4 initialColor = half4(0);";
345
346 if (useShadingStorageBuffer) {
347 SkSL::String::appendf(&mainBody,
348 "%s = %s.y;\n",
349 this->ssboIndex(),
351 }
352
353 if (step->emitsPrimitiveColor()) {
354 mainBody += step->fragmentColorSkSL();
355 }
356
357 // While looping through root nodes to emit shader code, skip the clip shader node if it's found
358 // and keep it to apply later during coverage calculation.
359 const ShaderNode* clipShaderNode = nullptr;
360
361 // Emit shader main body code, invoking each root node's expression, forwarding the previous
362 // node's output to the next.
363 static constexpr char kUnusedDstColor[] = "half4(1)";
364 static constexpr char kUnusedLocalCoords[] = "float2(0)";
365 ShaderSnippet::Args args = {"initialColor",
366 kUnusedDstColor,
367 this->needsLocalCoords() ? "localCoordsVar" : kUnusedLocalCoords};
368 for (const ShaderNode* node : fRootNodes) {
369 if (node->codeSnippetId() == (int) BuiltInCodeSnippetID::kClipShader) {
370 SkASSERT(!clipShaderNode);
371 clipShaderNode = node;
372 continue;
373 }
374 // This exclusion of the final Blend can be removed once we've resolved the final
375 // blend parenting issue w/in the key
376 if (node->codeSnippetId() >= kBuiltInCodeSnippetIDCount ||
377 node->codeSnippetId() < kFixedFunctionBlendModeIDOffset) {
378 args.fPriorStageOutput = emit_glue_code_for_entry(*this, node, args, &mainBody);
379 }
380 }
381
382 if (writeSwizzle != Swizzle::RGBA()) {
383 SkSL::String::appendf(&mainBody, "%s = %s.%s;", args.fPriorStageOutput.c_str(),
384 args.fPriorStageOutput.c_str(),
385 writeSwizzle.asString().c_str());
386 }
387
388 const char* outColor = args.fPriorStageOutput.c_str();
389 const Coverage coverage = step->coverage();
390 if (coverage != Coverage::kNone || clipShaderNode) {
391 if (useStepStorageBuffer) {
392 SkSL::String::appendf(&mainBody,
393 "uint stepSsboIndex = %s.x;\n",
395 mainBody += EmitUniformsFromStorageBuffer("step", "stepSsboIndex", step->uniforms());
396 }
397
398 mainBody += "half4 outputCoverage = half4(1);";
399 mainBody += step->fragmentCoverageSkSL();
400
401 if (clipShaderNode) {
402 std::string clipShaderOutput =
403 emit_glue_code_for_entry(*this, clipShaderNode, args, &mainBody);
404 SkSL::String::appendf(&mainBody, "outputCoverage *= %s.a;", clipShaderOutput.c_str());
405 }
406
407 // TODO: Determine whether draw is opaque and pass that to GetBlendFormula.
408 BlendFormula coverageBlendFormula =
409 coverage == Coverage::kLCD
412 /*isOpaque=*/false, /*hasCoverage=*/true, fBlendMode);
413
414 if (this->needsSurfaceColor()) {
415 // If this draw uses a non-coherent dst read, we want to keep the existing dst color (or
416 // whatever has been previously drawn) when there's no coverage. This helps for batching
417 // text draws that need to read from a dst copy for blends. However, this only helps the
418 // case where the outer bounding boxes of each letter overlap and not two actual parts
419 // of the text.
420 DstReadRequirement dstReadReq = caps->getDstReadRequirement();
421 if (dstReadReq == DstReadRequirement::kTextureCopy ||
423 // We don't think any shaders actually output negative coverage, but just as a
424 // safety check for floating point precision errors, we compare with <= here. We
425 // just check the RGB values of the coverage, since the alpha may not have been set
426 // when using LCD. If we are using single-channel coverage, alpha will be equal to
427 // RGB anyway.
428 mainBody +=
429 "if (all(lessThanEqual(outputCoverage.rgb, half3(0)))) {"
430 "discard;"
431 "}";
432 }
433
434 // Use originally-specified BlendInfo and blend with dst manually.
436 &mainBody,
437 "sk_FragColor = %s * outputCoverage + surfaceColor * (1.0 - outputCoverage);",
438 outColor);
439 if (coverage == Coverage::kLCD) {
441 &mainBody,
442 "half3 lerpRGB = mix(surfaceColor.aaa, %s.aaa, outputCoverage.rgb);"
443 "sk_FragColor.a = max(max(lerpRGB.r, lerpRGB.g), lerpRGB.b);",
444 outColor);
445 }
446
447 } else {
448 fBlendInfo = {coverageBlendFormula.equation(),
449 coverageBlendFormula.srcCoeff(),
450 coverageBlendFormula.dstCoeff(),
452 coverageBlendFormula.modifiesDst()};
453
454 if (coverage == Coverage::kLCD) {
455 mainBody += "outputCoverage.a = max(max(outputCoverage.r, "
456 "outputCoverage.g), "
457 "outputCoverage.b);";
458 }
460 &mainBody, coverageBlendFormula.primaryOutput(), "sk_FragColor", outColor);
461 if (coverageBlendFormula.hasSecondaryOutput()) {
462 append_color_output(&mainBody,
463 coverageBlendFormula.secondaryOutput(),
464 "sk_SecondaryFragColor",
465 outColor);
466 }
467 }
468
469 } else {
470 SkSL::String::appendf(&mainBody, "sk_FragColor = %s;", outColor);
471 }
472 mainBody += "}\n";
473
474 return preamble + "\n" + mainBody;
475}
476
477//--------------------------------------------------------------------------------------------------
478// ShaderCodeDictionary
479
481 AutoLockBuilderAsKey keyView{builder};
482 if (!keyView->isValid()) {
484 }
485
486 SkAutoSpinlock lock{fSpinLock};
487
488 UniquePaintParamsID* existingEntry = fPaintKeyToID.find(*keyView);
489 if (existingEntry) {
490 SkASSERT(fIDToPaintKey[(*existingEntry).asUInt()] == *keyView);
491 return *existingEntry;
492 }
493
494 // Detach from the builder and copy into the arena
495 PaintParamsKey key = keyView->clone(&fArena);
496 UniquePaintParamsID newID{SkTo<uint32_t>(fIDToPaintKey.size())};
497
498 fPaintKeyToID.set(key, newID);
499 fIDToPaintKey.push_back(key);
500 return newID;
501}
502
504 if (!codeID.isValid()) {
506 }
507
508 SkAutoSpinlock lock{fSpinLock};
509 SkASSERT(codeID.asUInt() < SkTo<uint32_t>(fIDToPaintKey.size()));
510 return fIDToPaintKey[codeID.asUInt()];
511}
512
514 return fBuiltInCodeSnippets[(int) id].fUniforms;
515}
516
517const ShaderSnippet* ShaderCodeDictionary::getEntry(int codeSnippetID) const {
518 if (codeSnippetID < 0) {
519 return nullptr;
520 }
521
522 if (codeSnippetID < kBuiltInCodeSnippetIDCount) {
523 return &fBuiltInCodeSnippets[codeSnippetID];
524 }
525
526 SkAutoSpinlock lock{fSpinLock};
527
528 if (codeSnippetID >= kSkiaKnownRuntimeEffectsStart &&
530 int knownRTECodeSnippetID = codeSnippetID - kSkiaKnownRuntimeEffectsStart;
531
532 // TODO(b/238759147): if the snippet hasn't been initialized, get the SkRuntimeEffect and
533 // initialize it here
534 SkASSERT(fKnownRuntimeEffectCodeSnippets[knownRTECodeSnippetID].fPreambleGenerator);
535 return &fKnownRuntimeEffectCodeSnippets[knownRTECodeSnippetID];
536 }
537
538 // TODO(b/238759147): handle Android and chrome known runtime effects
539
540 if (codeSnippetID >= kUnknownRuntimeEffectIDStart) {
541 int userDefinedCodeSnippetID = codeSnippetID - kUnknownRuntimeEffectIDStart;
542 if (userDefinedCodeSnippetID < SkTo<int>(fUserDefinedCodeSnippets.size())) {
543 return fUserDefinedCodeSnippets[userDefinedCodeSnippetID].get();
544 }
545 }
546
547 return nullptr;
548}
549
550//--------------------------------------------------------------------------------------------------
551namespace {
552
553std::string append_default_snippet_arguments(const ShaderInfo& shaderInfo,
554 const ShaderNode* node,
556 SkSpan<const std::string> childOutputs) {
557 std::string code = "(";
558
559 const char* separator = "";
560
561 const ShaderSnippet* entry = node->entry();
562
563 // Append prior-stage output color.
564 if (entry->needsPriorStageOutput()) {
565 code += args.fPriorStageOutput;
566 separator = ", ";
567 }
568
569 // Append blender destination color.
570 if (entry->needsBlenderDstColor()) {
571 code += separator;
572 code += args.fBlenderDstColor;
573 separator = ", ";
574 }
575
576 // Append fragment coordinates.
577 if (entry->needsLocalCoords()) {
578 code += separator;
579 code += args.fFragCoord;
580 separator = ", ";
581 }
582
583 // Append uniform names.
584 for (size_t i = 0; i < entry->fUniforms.size(); ++i) {
585 code += separator;
586 separator = ", ";
587 code += get_mangled_uniform_name(shaderInfo, entry->fUniforms[i], node->keyIndex());
588 }
589
590 // Append samplers.
591 for (size_t i = 0; i < entry->fTexturesAndSamplers.size(); ++i) {
592 code += separator;
593 code += get_mangled_sampler_name(entry->fTexturesAndSamplers[i], node->keyIndex());
594 separator = ", ";
595 }
596
597 // Append child output names.
598 for (const std::string& childOutputVar : childOutputs) {
599 code += separator;
600 separator = ", ";
601 code += childOutputVar;
602 }
603 code.push_back(')');
604
605 return code;
606}
607
608std::string emit_helper_function(const ShaderInfo& shaderInfo,
609 const ShaderNode* node) {
610 // Create a helper function that invokes each of the children, then calls the entry's snippet
611 // and passes all the child outputs along as arguments.
612 const ShaderSnippet* entry = node->entry();
613 std::string helperFnName = get_mangled_name(entry->fStaticFunctionName, node->keyIndex());
614 std::string helperFn = SkSL::String::printf(
615 "half4 %s(half4 inColor, half4 destColor, float2 pos) {",
616 helperFnName.c_str());
617 TArray<std::string> childOutputVarNames;
618 const ShaderSnippet::Args args = {"inColor", "destColor", "pos"};
619 for (const ShaderNode* child : node->children()) {
620 // Emit glue code into our helper function body (i.e. lifting the child execution up front
621 // so their outputs can be passed to the static module function for the node's snippet).
622 childOutputVarNames.push_back(emit_glue_code_for_entry(shaderInfo, child, args, &helperFn));
623 }
624
625 // Finally, invoke the snippet from the helper function, passing uniforms and child outputs.
626 std::string snippetArgList = append_default_snippet_arguments(shaderInfo, node,
627 args, childOutputVarNames);
628 SkSL::String::appendf(&helperFn,
629 "return %s%s;"
630 "}",
631 entry->fStaticFunctionName, snippetArgList.c_str());
632 return helperFn;
633}
634
635// If we have no children, the default expression just calls a built-in snippet with the signature:
636// half4 BuiltinFunctionName(/* default snippet arguments */);
637//
638// If we do have children, we will have created a glue function in the preamble and that is called
639// instead. Its signature looks like this:
640// half4 BuiltinFunctionName_N(half4 inColor, half4 destColor, float2 pos);
641
642std::string GenerateDefaultExpression(const ShaderInfo& shaderInfo,
643 const ShaderNode* node,
644 const ShaderSnippet::Args& args) {
645 if (node->numChildren() == 0) {
646 // We don't have any children; return an expression which invokes the snippet directly.
647 return node->entry()->fStaticFunctionName +
648 append_default_snippet_arguments(shaderInfo, node, args, /*childOutputs=*/{});
649 } else {
650 // Return an expression which invokes the helper function from the preamble.
651 std::string helperFnName =
652 get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
654 "%s(%.*s, %.*s, %.*s)",
655 helperFnName.c_str(),
656 (int)args.fPriorStageOutput.size(), args.fPriorStageOutput.data(),
657 (int)args.fBlenderDstColor.size(), args.fBlenderDstColor.data(),
658 (int)args.fFragCoord.size(), args.fFragCoord.data());
659 }
660}
661
662// If we have no children, we don't need to add anything into the preamble.
663// If we have child entries, we create a function in the preamble with a signature of:
664// half4 BuiltinFunctionName_N(half4 inColor, half4 destColor, float2 pos) { ... }
665// This function invokes each child in sequence, and then calls the built-in function, passing all
666// uniforms and child outputs along:
667// half4 BuiltinFunctionName(/* all uniforms as parameters */,
668// /* all child output variable names as parameters */);
669std::string GenerateDefaultPreamble(const ShaderInfo& shaderInfo,
670 const ShaderNode* node) {
671 if (node->numChildren() > 0) {
672 // Create a helper function which invokes all the child snippets.
673 return emit_helper_function(shaderInfo, node);
674 } else {
675 // We don't need a helper function
676 return "";
677 }
678}
679
680//--------------------------------------------------------------------------------------------------
681static constexpr Uniform kDstReadSampleUniforms[] = {
682 { "dstTextureCoords", SkSLType::kFloat4 },
683};
684
685static constexpr TextureAndSampler kDstReadSampleTexturesAndSamplers[] = {
686 {"dstSampler"},
687};
688
689std::string GenerateDstReadSampleExpression(const ShaderInfo& shaderInfo,
690 const ShaderNode* node,
691 const ShaderSnippet::Args& args) {
692 const ShaderSnippet* entry = node->entry();
693 std::string sampler =
694 get_mangled_sampler_name(entry->fTexturesAndSamplers[0], node->keyIndex());
695 std::string coords =
696 get_mangled_uniform_name(shaderInfo, entry->fUniforms[0], node->keyIndex());
697 std::string helperFnName = get_mangled_name(entry->fStaticFunctionName, node->keyIndex());
698
699 return SkSL::String::printf("%s(%s, %s)",
700 helperFnName.c_str(),
701 coords.c_str(),
702 sampler.c_str());
703}
704
705std::string GenerateDstReadSamplePreamble(const ShaderInfo& shaderInfo, const ShaderNode* node) {
706 std::string helperFnName =
707 get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
708
710 "half4 surfaceColor;" // we save off the original dstRead color to combine w/ coverage
711 "half4 %s(float4 coords, sampler2D dstSampler) {"
712 "surfaceColor = sample(dstSampler, (sk_FragCoord.xy - coords.xy) * coords.zw);"
713 "return surfaceColor;"
714 "}",
715 helperFnName.c_str());
716}
717
718//--------------------------------------------------------------------------------------------------
719std::string GenerateDstReadFetchExpression(const ShaderInfo& shaderInfo,
720 const ShaderNode* node,
721 const ShaderSnippet::Args& args) {
722 std::string helperFnName =
723 get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
724
725 return SkSL::String::printf("%s()", helperFnName.c_str());
726}
727
728std::string GenerateDstReadFetchPreamble(const ShaderInfo& shaderInfo, const ShaderNode* node) {
729 std::string helperFnName =
730 get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
731
733 "half4 surfaceColor;" // we save off the original dstRead color to combine w/ coverage
734 "half4 %s() {"
735 "surfaceColor = sk_LastFragColor;"
736 "return surfaceColor;"
737 "}",
738 helperFnName.c_str());
739}
740
741//--------------------------------------------------------------------------------------------------
742static constexpr int kNumClipShaderChildren = 1;
743
744std::string GenerateClipShaderExpression(const ShaderInfo& shaderInfo,
745 const ShaderNode* node,
746 const ShaderSnippet::Args& args) {
747 SkASSERT(node->numChildren() == kNumClipShaderChildren);
748 static constexpr char kUnusedSrcColor[] = "half4(1)";
749 static constexpr char kUnusedDstColor[] = "half4(1)";
750 return emit_expression_for_entry(
751 shaderInfo, node->child(0), {kUnusedSrcColor, kUnusedDstColor, "sk_FragCoord.xy"});
752}
753
754std::string GenerateClipShaderPreamble(const ShaderInfo& shaderInfo, const ShaderNode* node) {
755 // No preamble is used for clip shaders. The child shader is called directly with sk_FragCoord.
756 return "";
757}
758
759//--------------------------------------------------------------------------------------------------
760static constexpr int kFourStopGradient = 4;
761static constexpr int kEightStopGradient = 8;
762
763static constexpr Uniform kLinearGradientUniforms4[] = {
764 { "colors", SkSLType::kFloat4, kFourStopGradient },
765 { "offsets", SkSLType::kFloat4 },
766 { "point0", SkSLType::kFloat2 },
767 { "point1", SkSLType::kFloat2 },
768 { "tilemode", SkSLType::kInt },
769 { "colorSpace", SkSLType::kInt },
770 { "doUnPremul", SkSLType::kInt },
771};
772static constexpr Uniform kLinearGradientUniforms8[] = {
773 { "colors", SkSLType::kFloat4, kEightStopGradient },
774 { "offsets", SkSLType::kFloat4, 2 },
775 { "point0", SkSLType::kFloat2 },
776 { "point1", SkSLType::kFloat2 },
777 { "tilemode", SkSLType::kInt },
778 { "colorSpace", SkSLType::kInt },
779 { "doUnPremul", SkSLType::kInt },
780};
781static constexpr Uniform kLinearGradientUniformsTexture[] = {
782 { "point0", SkSLType::kFloat2 },
783 { "point1", SkSLType::kFloat2 },
784 { "numStops", SkSLType::kInt },
785 { "tilemode", SkSLType::kInt },
786 { "colorSpace", SkSLType::kInt },
787 { "doUnPremul", SkSLType::kInt },
788};
789
790static constexpr TextureAndSampler kTextureGradientTexturesAndSamplers[] = {
791 {"colorAndOffsetSampler"},
792};
793
794static constexpr Uniform kRadialGradientUniforms4[] = {
795 { "colors", SkSLType::kFloat4, kFourStopGradient },
796 { "offsets", SkSLType::kFloat4 },
797 { "center", SkSLType::kFloat2 },
798 { "radius", SkSLType::kFloat },
799 { "tilemode", SkSLType::kInt },
800 { "colorSpace", SkSLType::kInt },
801 { "doUnPremul", SkSLType::kInt },
802};
803static constexpr Uniform kRadialGradientUniforms8[] = {
804 { "colors", SkSLType::kFloat4, kEightStopGradient },
805 { "offsets", SkSLType::kFloat4, 2 },
806 { "center", SkSLType::kFloat2 },
807 { "radius", SkSLType::kFloat },
808 { "tilemode", SkSLType::kInt },
809 { "colorSpace", SkSLType::kInt },
810 { "doUnPremul", SkSLType::kInt },
811};
812static constexpr Uniform kRadialGradientUniformsTexture[] = {
813 { "center", SkSLType::kFloat2 },
814 { "radius", SkSLType::kFloat },
815 { "numStops", SkSLType::kInt },
816 { "tilemode", SkSLType::kInt },
817 { "colorSpace", SkSLType::kInt },
818 { "doUnPremul", SkSLType::kInt },
819};
820
821static constexpr Uniform kSweepGradientUniforms4[] = {
822 { "colors", SkSLType::kFloat4, kFourStopGradient },
823 { "offsets", SkSLType::kFloat4 },
824 { "center", SkSLType::kFloat2 },
825 { "bias", SkSLType::kFloat },
826 { "scale", SkSLType::kFloat },
827 { "tilemode", SkSLType::kInt },
828 { "colorSpace", SkSLType::kInt },
829 { "doUnPremul", SkSLType::kInt },
830};
831static constexpr Uniform kSweepGradientUniforms8[] = {
832 { "colors", SkSLType::kFloat4, kEightStopGradient },
833 { "offsets", SkSLType::kFloat4, 2 },
834 { "center", SkSLType::kFloat2 },
835 { "bias", SkSLType::kFloat },
836 { "scale", SkSLType::kFloat },
837 { "tilemode", SkSLType::kInt },
838 { "colorSpace", SkSLType::kInt },
839 { "doUnPremul", SkSLType::kInt },
840};
841static constexpr Uniform kSweepGradientUniformsTexture[] = {
842 { "center", SkSLType::kFloat2 },
843 { "bias", SkSLType::kFloat },
844 { "scale", SkSLType::kFloat },
845 { "numStops", SkSLType::kInt },
846 { "tilemode", SkSLType::kInt },
847 { "colorSpace", SkSLType::kInt },
848 { "doUnPremul", SkSLType::kInt },
849};
850
851static constexpr Uniform kConicalGradientUniforms4[] = {
852 { "colors", SkSLType::kFloat4, kFourStopGradient },
853 { "offsets", SkSLType::kFloat4 },
854 { "point0", SkSLType::kFloat2 },
855 { "point1", SkSLType::kFloat2 },
856 { "radius0", SkSLType::kFloat },
857 { "radius1", SkSLType::kFloat },
858 { "tilemode", SkSLType::kInt },
859 { "colorSpace", SkSLType::kInt },
860 { "doUnPremul", SkSLType::kInt },
861};
862static constexpr Uniform kConicalGradientUniforms8[] = {
863 { "colors", SkSLType::kFloat4, kEightStopGradient },
864 { "offsets", SkSLType::kFloat4, 2 },
865 { "point0", SkSLType::kFloat2 },
866 { "point1", SkSLType::kFloat2 },
867 { "radius0", SkSLType::kFloat },
868 { "radius1", SkSLType::kFloat },
869 { "tilemode", SkSLType::kInt },
870 { "colorSpace", SkSLType::kInt },
871 { "doUnPremul", SkSLType::kInt },
872};
873static constexpr Uniform kConicalGradientUniformsTexture[] = {
874 { "point0", SkSLType::kFloat2 },
875 { "point1", SkSLType::kFloat2 },
876 { "radius0", SkSLType::kFloat },
877 { "radius1", SkSLType::kFloat },
878 { "numStops", SkSLType::kInt },
879 { "tilemode", SkSLType::kInt },
880 { "colorSpace", SkSLType::kInt },
881 { "doUnPremul", SkSLType::kInt },
882};
883
884static constexpr char kLinearGradient4Name[] = "sk_linear_grad_4_shader";
885static constexpr char kLinearGradient8Name[] = "sk_linear_grad_8_shader";
886static constexpr char kLinearGradientTextureName[] = "sk_linear_grad_tex_shader";
887
888static constexpr char kRadialGradient4Name[] = "sk_radial_grad_4_shader";
889static constexpr char kRadialGradient8Name[] = "sk_radial_grad_8_shader";
890static constexpr char kRadialGradientTextureName[] = "sk_radial_grad_tex_shader";
891
892static constexpr char kSweepGradient4Name[] = "sk_sweep_grad_4_shader";
893static constexpr char kSweepGradient8Name[] = "sk_sweep_grad_8_shader";
894static constexpr char kSweepGradientTextureName[] = "sk_sweep_grad_tex_shader";
895
896static constexpr char kConicalGradient4Name[] = "sk_conical_grad_4_shader";
897static constexpr char kConicalGradient8Name[] = "sk_conical_grad_8_shader";
898static constexpr char kConicalGradientTextureName[] = "sk_conical_grad_tex_shader";
899
900//--------------------------------------------------------------------------------------------------
901static constexpr Uniform kSolidShaderUniforms[] = {
902 { "color", SkSLType::kFloat4 }
903};
904
905static constexpr char kSolidShaderName[] = "sk_solid_shader";
906
907//--------------------------------------------------------------------------------------------------
908static constexpr Uniform kPaintColorUniforms[] = { Uniform::PaintColor() };
909
910static constexpr char kRGBPaintColorName[] = "sk_rgb_opaque";
911static constexpr char kAlphaOnlyPaintColorName[] = "sk_alpha_only";
912
913//--------------------------------------------------------------------------------------------------
914static constexpr Uniform kLocalMatrixShaderUniforms[] = {
915 { "localMatrix", SkSLType::kFloat4x4 },
916};
917
918static constexpr int kNumLocalMatrixShaderChildren = 1;
919
920static constexpr char kLocalMatrixShaderName[] = "LocalMatrix";
921
922// Create a helper function that multiplies coordinates by a local matrix, invokes the child
923// entry with those updated coordinates, and returns the result. This helper function meets the
924// requirements for use with GenerateDefaultExpression, so there's no need to have a separate
925// special GenerateLocalMatrixExpression.
926std::string GenerateLocalMatrixPreamble(const ShaderInfo& shaderInfo,
927 const ShaderNode* node) {
928 SkASSERT(node->codeSnippetId() == (int) BuiltInCodeSnippetID::kLocalMatrixShader);
929 SkASSERT(node->numChildren() == kNumLocalMatrixShaderChildren);
930
931 // Get the child's evaluation expression.
932 static constexpr char kUnusedDestColor[] = "half4(1)";
933 std::string childExpr = emit_expression_for_entry(shaderInfo, node->child(0),
934 {"inColor", kUnusedDestColor, "coords"});
935 std::string localMatrixUni =
936 get_mangled_uniform_name(shaderInfo, node->entry()->fUniforms[0], node->keyIndex());
937
938 std::string helperFnName =
939 get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
940 return SkSL::String::printf("half4 %s(half4 inColor, half4 destColor, float2 coords) {"
941 "coords = (%s * coords.xy01).xy;"
942 "return %s;"
943 "}",
944 helperFnName.c_str(),
945 localMatrixUni.c_str(),
946 childExpr.c_str());
947}
948
949//--------------------------------------------------------------------------------------------------
950static constexpr Uniform kImageShaderUniforms[] = {
951 { "invImgSize", SkSLType::kFloat2 },
952 { "subset", SkSLType::kFloat4 },
953 { "tilemodeX", SkSLType::kInt },
954 { "tilemodeY", SkSLType::kInt },
955 { "filterMode", SkSLType::kInt },
956 // The next 5 uniforms are for the color space transformation
957 { "csXformFlags", SkSLType::kInt },
958 { "csXformSrcKind", SkSLType::kInt },
959 { "csXformGamutTransform", SkSLType::kHalf3x3 },
960 { "csXformDstKind", SkSLType::kInt },
961 { "csXformCoeffs", SkSLType::kHalf4x4 },
962};
963
964static constexpr Uniform kCubicImageShaderUniforms[] = {
965 { "invImgSize", SkSLType::kFloat2 },
966 { "subset", SkSLType::kFloat4 },
967 { "tilemodeX", SkSLType::kInt },
968 { "tilemodeY", SkSLType::kInt },
969 { "cubicCoeffs", SkSLType::kHalf4x4 },
970 // The next 5 uniforms are for the color space transformation
971 { "csXformFlags", SkSLType::kInt },
972 { "csXformSrcKind", SkSLType::kInt },
973 { "csXformGamutTransform", SkSLType::kHalf3x3 },
974 { "csXformDstKind", SkSLType::kInt },
975 { "csXformCoeffs", SkSLType::kHalf4x4 },
976};
977
978static constexpr Uniform kHWImageShaderUniforms[] = {
979 { "invImgSize", SkSLType::kFloat2 },
980 // The next 5 uniforms are for the color space transformation
981 { "csXformFlags", SkSLType::kInt },
982 { "csXformSrcKind", SkSLType::kInt },
983 { "csXformGamutTransform", SkSLType::kHalf3x3 },
984 { "csXformDstKind", SkSLType::kInt },
985 { "csXformCoeffs", SkSLType::kHalf4x4 },
986};
987
988static constexpr TextureAndSampler kISTexturesAndSamplers[] = {
989 {"sampler"},
990};
991
992static_assert(0 == static_cast<int>(SkTileMode::kClamp), "ImageShader code depends on SkTileMode");
993static_assert(1 == static_cast<int>(SkTileMode::kRepeat), "ImageShader code depends on SkTileMode");
994static_assert(2 == static_cast<int>(SkTileMode::kMirror), "ImageShader code depends on SkTileMode");
995static_assert(3 == static_cast<int>(SkTileMode::kDecal), "ImageShader code depends on SkTileMode");
996
997static_assert(0 == static_cast<int>(SkFilterMode::kNearest),
998 "ImageShader code depends on SkFilterMode");
999static_assert(1 == static_cast<int>(SkFilterMode::kLinear),
1000 "ImageShader code depends on SkFilterMode");
1001
1002static_assert(0 == static_cast<int>(ReadSwizzle::kRGBA),
1003 "ImageShader code depends on ReadSwizzle");
1004static_assert(1 == static_cast<int>(ReadSwizzle::kRGB1),
1005 "ImageShader code depends on ReadSwizzle");
1006static_assert(2 == static_cast<int>(ReadSwizzle::kRRR1),
1007 "ImageShader code depends on ReadSwizzle");
1008static_assert(3 == static_cast<int>(ReadSwizzle::kBGRA),
1009 "ImageShader code depends on ReadSwizzle");
1010static_assert(4 == static_cast<int>(ReadSwizzle::k000R),
1011 "ImageShader code depends on ReadSwizzle");
1012
1013static constexpr char kImageShaderName[] = "sk_image_shader";
1014static constexpr char kCubicImageShaderName[] = "sk_cubic_image_shader";
1015static constexpr char kHWImageShaderName[] = "sk_hw_image_shader";
1016
1017//--------------------------------------------------------------------------------------------------
1018
1019static constexpr Uniform kYUVImageShaderUniforms[] = {
1020 { "invImgSizeY", SkSLType::kFloat2 },
1021 { "invImgSizeUV", SkSLType::kFloat2 }, // Relative to Y's texel space
1022 { "subset", SkSLType::kFloat4 },
1023 { "linearFilterUVInset", SkSLType::kFloat2 },
1024 { "tilemodeX", SkSLType::kInt },
1025 { "tilemodeY", SkSLType::kInt },
1026 { "filterModeY", SkSLType::kInt },
1027 { "filterModeUV", SkSLType::kInt },
1028 { "channelSelectY", SkSLType::kHalf4 },
1029 { "channelSelectU", SkSLType::kHalf4 },
1030 { "channelSelectV", SkSLType::kHalf4 },
1031 { "channelSelectA", SkSLType::kHalf4 },
1032 { "yuvToRGBMatrix", SkSLType::kHalf3x3 },
1033 { "yuvToRGBTranslate", SkSLType::kFloat3 },
1034};
1035
1036static constexpr Uniform kCubicYUVImageShaderUniforms[] = {
1037 { "invImgSizeY", SkSLType::kFloat2 },
1038 { "invImgSizeUV", SkSLType::kFloat2 }, // Relative to Y's texel space
1039 { "subset", SkSLType::kFloat4 },
1040 { "tilemodeX", SkSLType::kInt },
1041 { "tilemodeY", SkSLType::kInt },
1042 { "cubicCoeffs", SkSLType::kHalf4x4 },
1043 { "channelSelectY", SkSLType::kHalf4 },
1044 { "channelSelectU", SkSLType::kHalf4 },
1045 { "channelSelectV", SkSLType::kHalf4 },
1046 { "channelSelectA", SkSLType::kHalf4 },
1047 { "yuvToRGBMatrix", SkSLType::kHalf3x3 },
1048 { "yuvToRGBTranslate", SkSLType::kFloat3 },
1049};
1050
1051static constexpr TextureAndSampler kYUVISTexturesAndSamplers[] = {
1052 { "samplerY" },
1053 { "samplerU" },
1054 { "samplerV" },
1055 { "samplerA" },
1056};
1057
1058static constexpr char kYUVImageShaderName[] = "sk_yuv_image_shader";
1059static constexpr char kCubicYUVImageShaderName[] = "sk_cubic_yuv_image_shader";
1060
1061//--------------------------------------------------------------------------------------------------
1062static constexpr Uniform kCoordClampShaderUniforms[] = {
1063 { "subset", SkSLType::kFloat4 },
1064};
1065
1066static constexpr char kCoordClampShaderName[] = "CoordClamp";
1067
1068static constexpr int kNumCoordClampShaderChildren = 1;
1069
1070// Create a helper function that clamps the local coords to the subset, invokes the child
1071// entry with those updated coordinates, and returns the result. This helper function meets the
1072// requirements for use with GenerateDefaultExpression, so there's no need to have a separate
1073// special GenerateCoordClampExpression.
1074// TODO: this has a lot of overlap with GenerateLocalMatrixPreamble
1075std::string GenerateCoordClampPreamble(const ShaderInfo& shaderInfo,
1076 const ShaderNode* node) {
1077 SkASSERT(node->codeSnippetId() == (int) BuiltInCodeSnippetID::kCoordClampShader);
1078 SkASSERT(node->numChildren() == kNumCoordClampShaderChildren);
1079
1080 // Get the child's evaluation expression.
1081 static constexpr char kUnusedDestColor[] = "half4(1)";
1082 std::string childExpr = emit_expression_for_entry(shaderInfo, node->child(0),
1083 {"inColor", kUnusedDestColor, "coords"});
1084
1085 std::string subsetUni =
1086 get_mangled_uniform_name(shaderInfo, node->entry()->fUniforms[0], node->keyIndex());
1087
1088 std::string helperFnName =
1089 get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex());
1090 return SkSL::String::printf("half4 %s(half4 inColor, half4 destColor, float2 coords) {"
1091 "coords = clamp(coords, %s.LT, %s.RB);"
1092 "return %s;"
1093 "}",
1094 helperFnName.c_str(),
1095 subsetUni.c_str(),
1096 subsetUni.c_str(),
1097 childExpr.c_str());
1098}
1099
1100
1101//--------------------------------------------------------------------------------------------------
1102static constexpr Uniform kDitherShaderUniforms[] = {
1103 { "range", SkSLType::kHalf },
1104};
1105
1106static constexpr TextureAndSampler kDitherTexturesAndSamplers[] = {
1107 {"sampler"},
1108};
1109
1110static constexpr char kDitherShaderName[] = "sk_dither_shader";
1111
1112//--------------------------------------------------------------------------------------------------
1113static constexpr Uniform kPerlinNoiseShaderUniforms[] = {
1114 { "baseFrequency", SkSLType::kFloat2 },
1115 { "stitchData", SkSLType::kFloat2 },
1116 { "noiseType", SkSLType::kInt },
1117 { "numOctaves", SkSLType::kInt },
1118 { "stitching", SkSLType::kInt },
1119};
1120
1121static constexpr TextureAndSampler kPerlinNoiseShaderTexturesAndSamplers[] = {
1122 { "permutationsSampler" },
1123 { "noiseSampler" },
1124};
1125
1126static constexpr char kPerlinNoiseShaderName[] = "perlin_noise_shader";
1127
1128//--------------------------------------------------------------------------------------------------
1129static constexpr Uniform CoeffBlendderUniforms[] = {
1130 { "coeffs", SkSLType::kHalf4 },
1131};
1132
1133static constexpr char kCoeffBlenderName[] = "sk_coeff_blend";
1134
1135//--------------------------------------------------------------------------------------------------
1136static constexpr Uniform kBlendModeBlenderUniforms[] = {
1137 { "blendMode", SkSLType::kInt },
1138};
1139
1140static constexpr char kBlendModeBlenderName[] = "sk_blend";
1141
1142//--------------------------------------------------------------------------------------------------
1143static constexpr int kNumBlendShaderChildren = 3;
1144
1145std::string GenerateBlendShaderPreamble(const ShaderInfo& shaderInfo,
1146 const ShaderNode* node) {
1147 // Children are src, dst, and blender
1148 SkASSERT(node->numChildren() == 3);
1149
1150 // Create a helper function that invokes the src and dst children, then calls the blend child
1151 // with the src and dst results.
1152 std::string helperFn = SkSL::String::printf(
1153 "half4 %s(half4 inColor, half4 destColor, float2 pos) {",
1154 get_mangled_name(node->entry()->fStaticFunctionName, node->keyIndex()).c_str());
1155
1156 // Get src and dst colors.
1157 const ShaderSnippet::Args args = {"inColor", "destColor", "pos"};
1158 std::string srcVar = emit_glue_code_for_entry(shaderInfo, node->child(0), args, &helperFn);
1159 std::string dstVar = emit_glue_code_for_entry(shaderInfo, node->child(1), args, &helperFn);
1160
1161 // Do the blend.
1162 static constexpr char kUnusedLocalCoords[] = "float2(0)";
1163
1164 std::string blendResultVar = emit_glue_code_for_entry(
1165 shaderInfo, node->child(2), {srcVar, dstVar, kUnusedLocalCoords}, &helperFn);
1166
1167 SkSL::String::appendf(&helperFn,
1168 "return %s;"
1169 "}",
1170 blendResultVar.c_str());
1171 return helperFn;
1172}
1173
1174//--------------------------------------------------------------------------------------------------
1175class GraphitePipelineCallbacks : public SkSL::PipelineStage::Callbacks {
1176public:
1177 GraphitePipelineCallbacks(const ShaderInfo& shaderInfo,
1178 const ShaderNode* node,
1179 std::string* preamble,
1180 const SkRuntimeEffect* effect)
1181 : fShaderInfo(shaderInfo)
1182 , fNode(node)
1183 , fPreamble(preamble)
1184 , fEffect(effect) {}
1185
1186 std::string declareUniform(const SkSL::VarDeclaration* decl) override {
1187 std::string result = get_mangled_name(std::string(decl->var()->name()), fNode->keyIndex());
1188 if (fShaderInfo.ssboIndex()) {
1189 result = EmitStorageBufferAccess("fs", fShaderInfo.ssboIndex(), result.c_str());
1190 }
1191 return result;
1192 }
1193
1194 void defineFunction(const char* decl, const char* body, bool isMain) override {
1195 if (isMain) {
1197 fPreamble,
1198 "half4 %s(half4 inColor, half4 destColor, float2 coords) {"
1199 "%s"
1200 "}",
1201 get_mangled_name(fNode->entry()->fName, fNode->keyIndex()).c_str(),
1202 body);
1203 } else {
1204 SkSL::String::appendf(fPreamble, "%s {%s}\n", decl, body);
1205 }
1206 }
1207
1208 void declareFunction(const char* decl) override {
1209 *fPreamble += std::string(decl);
1210 }
1211
1212 void defineStruct(const char* definition) override {
1213 *fPreamble += std::string(definition);
1214 }
1215
1216 void declareGlobal(const char* declaration) override {
1217 *fPreamble += std::string(declaration);
1218 }
1219
1220 std::string sampleShader(int index, std::string coords) override {
1221 return emit_expression_for_entry(fShaderInfo, fNode->child(index),
1222 {"inColor", "destColor", coords});
1223 }
1224
1225 std::string sampleColorFilter(int index, std::string color) override {
1226 return emit_expression_for_entry(fShaderInfo, fNode->child(index),
1227 {color, "destColor", "coords"});
1228 }
1229
1230 std::string sampleBlender(int index, std::string src, std::string dst) override {
1231 return emit_expression_for_entry(fShaderInfo, fNode->child(index),
1232 {src, dst, "coords"});
1233 }
1234
1235 std::string toLinearSrgb(std::string color) override {
1237 return color;
1238 }
1239
1240 color = SkSL::String::printf("(%s).rgb1", color.c_str());
1241 std::string helper = get_mangled_name("toLinearSRGB", fNode->keyIndex());
1242 std::string xformedColor = SkSL::String::printf("%s(%s)",
1243 helper.c_str(),
1244 color.c_str());
1245 return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
1246 }
1247
1248
1249 std::string fromLinearSrgb(std::string color) override {
1251 return color;
1252 }
1253
1254 color = SkSL::String::printf("(%s).rgb1", color.c_str());
1255 std::string helper = get_mangled_name("fromLinearSRGB", fNode->keyIndex());
1256 std::string xformedColor = SkSL::String::printf("%s(%s)",
1257 helper.c_str(),
1258 color.c_str());
1259 return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
1260 }
1261
1262 std::string getMangledName(const char* name) override {
1263 return get_mangled_name(name, fNode->keyIndex());
1264 }
1265
1266private:
1267 const ShaderInfo& fShaderInfo;
1268 const ShaderNode* fNode;
1269 std::string* fPreamble;
1270 const SkRuntimeEffect* fEffect;
1271};
1272
1273std::string GenerateRuntimeShaderPreamble(const ShaderInfo& shaderInfo,
1274 const ShaderNode* node) {
1275 // Find this runtime effect in the runtime-effect dictionary.
1276 SkASSERT(node->codeSnippetId() >= kBuiltInCodeSnippetIDCount);
1277 const SkRuntimeEffect* effect;
1278 if (node->codeSnippetId() < kSkiaKnownRuntimeEffectsStart + kStableKeyCnt) {
1279 effect = GetKnownRuntimeEffect(static_cast<StableKey>(node->codeSnippetId()));
1280 } else {
1281 SkASSERT(node->codeSnippetId() >= kUnknownRuntimeEffectIDStart);
1282 effect = shaderInfo.runtimeEffectDictionary()->find(node->codeSnippetId());
1283 }
1284 SkASSERT(effect);
1285
1286 const SkSL::Program& program = SkRuntimeEffectPriv::Program(*effect);
1287
1288 std::string preamble;
1291 &preamble,
1292 "half4 %s(half4 inColor) {"
1293 "return sk_color_space_transform(inColor, %s, %s, %s, %s, %s);"
1294 "}",
1295 get_mangled_name("toLinearSRGB", node->keyIndex()).c_str(),
1296 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[0],
1297 node->keyIndex()).c_str(),
1298 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[1],
1299 node->keyIndex()).c_str(),
1300 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[2],
1301 node->keyIndex()).c_str(),
1302 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[3],
1303 node->keyIndex()).c_str(),
1304 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[4],
1305 node->keyIndex()).c_str());
1307 &preamble,
1308 "half4 %s(half4 inColor) {"
1309 "return sk_color_space_transform(inColor, %s, %s, %s, %s, %s);"
1310 "}",
1311 get_mangled_name("fromLinearSRGB", node->keyIndex()).c_str(),
1312 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[5],
1313 node->keyIndex()).c_str(),
1314 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[6],
1315 node->keyIndex()).c_str(),
1316 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[7],
1317 node->keyIndex()).c_str(),
1318 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[8],
1319 node->keyIndex()).c_str(),
1320 get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[9],
1321 node->keyIndex()).c_str());
1322 }
1323
1324 GraphitePipelineCallbacks callbacks{shaderInfo, node, &preamble, effect};
1325 SkSL::PipelineStage::ConvertProgram(program, "coords", "inColor", "destColor", &callbacks);
1326 return preamble;
1327}
1328
1329std::string GenerateRuntimeShaderExpression(const ShaderInfo& shaderInfo,
1330 const ShaderNode* node,
1331 const ShaderSnippet::Args& args) {
1332 return SkSL::String::printf(
1333 "%s(%.*s, %.*s, %.*s)",
1334 get_mangled_name(node->entry()->fName, node->keyIndex()).c_str(),
1335 (int)args.fPriorStageOutput.size(), args.fPriorStageOutput.data(),
1336 (int)args.fBlenderDstColor.size(), args.fBlenderDstColor.data(),
1337 (int)args.fFragCoord.size(), args.fFragCoord.data());
1338}
1339
1340//--------------------------------------------------------------------------------------------------
1341// TODO: investigate the implications of having separate hlsa and rgba matrix colorfilters. It
1342// may be that having them separate will not contribute to combinatorial explosion.
1343static constexpr Uniform kMatrixColorFilterUniforms[] = {
1344 { "matrix", SkSLType::kFloat4x4 },
1345 { "translate", SkSLType::kFloat4 },
1346 { "inHSL", SkSLType::kInt },
1347};
1348
1349static constexpr char kMatrixColorFilterName[] = "sk_matrix_colorfilter";
1350
1351//--------------------------------------------------------------------------------------------------
1352static constexpr char kComposeName[] = "Compose";
1353
1354static constexpr int kNumComposeChildren = 2;
1355
1356// Compose two children, assuming the first child is the innermost.
1357std::string GenerateNestedChildrenPreamble(const ShaderInfo& shaderInfo,
1358 const ShaderNode* node) {
1359 SkASSERT(node->numChildren() == 2);
1360
1361 // Evaluate inner child.
1362 static constexpr char kUnusedDestColor[] = "half4(1)";
1363 std::string innerColor = emit_expression_for_entry(shaderInfo, node->child(0),
1364 {"inColor", kUnusedDestColor, "coords"});
1365
1366 // Evaluate outer child.
1367 std::string outerColor = emit_expression_for_entry(shaderInfo, node->child(1),
1368 {innerColor, kUnusedDestColor, "coords"});
1369
1370 // Create a helper function that invokes the inner expression, then passes that result to the
1371 // outer expression, and returns the composed result.
1372 std::string helperFnName = get_mangled_name(node->entry()->fName, node->keyIndex());
1373 return SkSL::String::printf("half4 %s(half4 inColor, half4 destColor, float2 coords) {"
1374 "return %s;"
1375 "}",
1376 helperFnName.c_str(),
1377 outerColor.c_str());
1378}
1379
1380//--------------------------------------------------------------------------------------------------
1381static constexpr TextureAndSampler kTableColorFilterTexturesAndSamplers[] = {
1382 {"tableSampler"},
1383};
1384
1385static constexpr char kTableColorFilterName[] = "sk_table_colorfilter";
1386
1387//--------------------------------------------------------------------------------------------------
1388static constexpr char kGaussianColorFilterName[] = "sk_gaussian_colorfilter";
1389
1390//--------------------------------------------------------------------------------------------------
1391static constexpr Uniform kColorSpaceTransformUniforms[] = {
1392 { "flags", SkSLType::kInt },
1393 { "srcKind", SkSLType::kInt },
1394 { "gamutTransform", SkSLType::kHalf3x3 },
1395 { "dstKind", SkSLType::kInt },
1396 { "csXformCoeffs", SkSLType::kHalf4x4 },
1397};
1398
1399static_assert(0 == static_cast<int>(skcms_TFType_Invalid),
1400 "ColorSpaceTransform code depends on skcms_TFType");
1401static_assert(1 == static_cast<int>(skcms_TFType_sRGBish),
1402 "ColorSpaceTransform code depends on skcms_TFType");
1403static_assert(2 == static_cast<int>(skcms_TFType_PQish),
1404 "ColorSpaceTransform code depends on skcms_TFType");
1405static_assert(3 == static_cast<int>(skcms_TFType_HLGish),
1406 "ColorSpaceTransform code depends on skcms_TFType");
1407static_assert(4 == static_cast<int>(skcms_TFType_HLGinvish),
1408 "ColorSpaceTransform code depends on skcms_TFType");
1409
1410// TODO: We can meaningfully check these when we can use C++20 features.
1411// static_assert(0x1 == SkColorSpaceXformSteps::Flags{.unpremul = true}.mask(),
1412// "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1413// static_assert(0x2 == SkColorSpaceXformSteps::Flags{.linearize = true}.mask(),
1414// "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1415// static_assert(0x4 == SkColorSpaceXformSteps::Flags{.gamut_transform = true}.mask(),
1416// "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1417// static_assert(0x8 == SkColorSpaceXformSteps::Flags{.encode = true}.mask(),
1418// "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1419// static_assert(0x10 == SkColorSpaceXformSteps::Flags{.premul = true}.mask(),
1420// "ColorSpaceTransform code depends on SkColorSpaceXformSteps::Flags");
1421
1422static constexpr char kColorSpaceTransformName[] = "sk_color_space_transform";
1423
1424//--------------------------------------------------------------------------------------------------
1425static constexpr char kErrorName[] = "sk_error";
1426
1427//--------------------------------------------------------------------------------------------------
1428static constexpr char kPassthroughShaderName[] = "sk_passthrough";
1429
1430//--------------------------------------------------------------------------------------------------
1431
1432std::string GeneratePrimitiveColorExpression(const ShaderInfo&,
1433 const ShaderNode* node,
1434 const ShaderSnippet::Args&) {
1435 return "primitiveColor";
1436}
1437
1438//--------------------------------------------------------------------------------------------------
1439
1440} // anonymous namespace
1441
1442#if defined(SK_DEBUG)
1443bool ShaderCodeDictionary::isValidID(int snippetID) const {
1444 if (snippetID < 0) {
1445 return false;
1446 }
1447
1448 if (snippetID < kBuiltInCodeSnippetIDCount) {
1449 return true;
1450 }
1451 if (snippetID >= kSkiaKnownRuntimeEffectsStart && snippetID < kSkiaKnownRuntimeEffectsEnd) {
1452 return snippetID < kSkiaKnownRuntimeEffectsStart + kStableKeyCnt;
1453 }
1454
1455 SkAutoSpinlock lock{fSpinLock};
1456
1457 if (snippetID >= kUnknownRuntimeEffectIDStart) {
1458 int userDefinedCodeSnippetID = snippetID - kUnknownRuntimeEffectIDStart;
1459 return userDefinedCodeSnippetID < SkTo<int>(fUserDefinedCodeSnippets.size());
1460 }
1461
1462 return false;
1463}
1464#endif
1465
1466#if defined(GRAPHITE_TEST_UTILS)
1467
1468int ShaderCodeDictionary::addRuntimeEffectSnippet(const char* functionName) {
1469 SkAutoSpinlock lock{fSpinLock};
1470
1471 fUserDefinedCodeSnippets.push_back(
1472 std::make_unique<ShaderSnippet>("UserDefined",
1473 SkSpan<const Uniform>(), // no uniforms
1475 SkSpan<const TextureAndSampler>(), // no samplers
1476 functionName,
1477 GenerateDefaultExpression,
1478 GenerateDefaultPreamble,
1479 kNoChildren));
1480
1481 return kUnknownRuntimeEffectIDStart + fUserDefinedCodeSnippets.size() - 1;
1482}
1483
1484#endif // GRAPHITE_TEST_UTILS
1485
1489 switch (u.type) {
1490 case Type::kFloat: return SkSLType::kHalf;
1491 case Type::kFloat2: return SkSLType::kHalf2;
1492 case Type::kFloat3: return SkSLType::kHalf3;
1493 case Type::kFloat4: return SkSLType::kHalf4;
1494 case Type::kFloat2x2: return SkSLType::kHalf2x2;
1495 case Type::kFloat3x3: return SkSLType::kHalf3x3;
1496 case Type::kFloat4x4: return SkSLType::kHalf4x4;
1497 // NOTE: shorts cannot be uniforms, so we shouldn't ever get here.
1498 // Defensively return the full precision integer type.
1499 case Type::kInt: SkDEBUGFAIL("unsupported uniform type"); return SkSLType::kInt;
1500 case Type::kInt2: SkDEBUGFAIL("unsupported uniform type"); return SkSLType::kInt2;
1501 case Type::kInt3: SkDEBUGFAIL("unsupported uniform type"); return SkSLType::kInt3;
1502 case Type::kInt4: SkDEBUGFAIL("unsupported uniform type"); return SkSLType::kInt4;
1503 }
1504 } else {
1505 switch (u.type) {
1506 case Type::kFloat: return SkSLType::kFloat;
1507 case Type::kFloat2: return SkSLType::kFloat2;
1508 case Type::kFloat3: return SkSLType::kFloat3;
1509 case Type::kFloat4: return SkSLType::kFloat4;
1510 case Type::kFloat2x2: return SkSLType::kFloat2x2;
1511 case Type::kFloat3x3: return SkSLType::kFloat3x3;
1512 case Type::kFloat4x4: return SkSLType::kFloat4x4;
1513 case Type::kInt: return SkSLType::kInt;
1514 case Type::kInt2: return SkSLType::kInt2;
1515 case Type::kInt3: return SkSLType::kInt3;
1516 case Type::kInt4: return SkSLType::kInt4;
1517 }
1518 }
1520}
1521
1522const char* ShaderCodeDictionary::addTextToArena(std::string_view text) {
1523 char* textInArena = fArena.makeArrayDefault<char>(text.size() + 1);
1524 memcpy(textInArena, text.data(), text.size());
1525 textInArena[text.size()] = '\0';
1526 return textInArena;
1527}
1528
1529SkSpan<const Uniform> ShaderCodeDictionary::convertUniforms(const SkRuntimeEffect* effect) {
1530 using rteUniform = SkRuntimeEffect::Uniform;
1531 SkSpan<const rteUniform> uniforms = effect->uniforms();
1532
1533 int numBaseUniforms = uniforms.size();
1534 int xtraUniforms = 0;
1536 xtraUniforms += std::size(kRuntimeEffectColorSpaceTransformUniforms);
1537 }
1538
1539 // Convert the SkRuntimeEffect::Uniform array into its Uniform equivalent.
1540 int numUniforms = numBaseUniforms + xtraUniforms;
1541 Uniform* uniformArray = fArena.makeInitializedArray<Uniform>(numUniforms, [&](int index) {
1542 if (index >= numBaseUniforms) {
1543 return kRuntimeEffectColorSpaceTransformUniforms[index - numBaseUniforms];
1544 }
1545
1546 const rteUniform* u;
1547 u = &uniforms[index];
1548
1549 // The existing uniform names live in the passed-in SkRuntimeEffect and may eventually
1550 // disappear. Copy them into fArena. (It's safe to do this within makeInitializedArray; the
1551 // entire array is allocated in one big slab before any initialization calls are done.)
1552 const char* name = this->addTextToArena(u->name);
1553
1554 // Add one Uniform to our array.
1556 return (u->flags & rteUniform::kArray_Flag) ? Uniform(name, type, u->count)
1557 : Uniform(name, type);
1558 });
1559
1560 return SkSpan<const Uniform>(uniformArray, numUniforms);
1561}
1562
1565 if (effect->allowShader()) {
1567 }
1568 if (effect->allowBlender()) {
1570 }
1571
1572 SkAutoSpinlock lock{fSpinLock};
1573
1574 if (int stableKey = SkRuntimeEffectPriv::StableKey(*effect)) {
1577
1578 int index = stableKey - kSkiaKnownRuntimeEffectsStart;
1579
1580 if (!fKnownRuntimeEffectCodeSnippets[index].fExpressionGenerator) {
1581 const char* name = get_known_rte_name(static_cast<StableKey>(stableKey));
1582 fKnownRuntimeEffectCodeSnippets[index] = ShaderSnippet(
1583 name,
1584 this->convertUniforms(effect),
1585 snippetFlags,
1586 /* texturesAndSamplers= */ {},
1587 name,
1588 GenerateRuntimeShaderExpression,
1589 GenerateRuntimeShaderPreamble,
1590 (int)effect->children().size());
1591 }
1592
1593 return stableKey;
1594 }
1595
1596 // Use the combination of {SkSL program hash, uniform size} as our key.
1597 // In the unfortunate event of a hash collision, at least we'll have the right amount of
1598 // uniform data available.
1599 RuntimeEffectKey key;
1600 key.fHash = SkRuntimeEffectPriv::Hash(*effect);
1601 key.fUniformSize = effect->uniformSize();
1602
1603 int32_t* existingCodeSnippetID = fRuntimeEffectMap.find(key);
1604 if (existingCodeSnippetID) {
1605 return *existingCodeSnippetID;
1606 }
1607
1608 // TODO: the memory for user-defined entries could go in the dictionary's arena but that
1609 // would have to be a thread safe allocation since the arena also stores entries for
1610 // 'fHash' and 'fEntryVector'
1611 fUserDefinedCodeSnippets.push_back(
1612 std::make_unique<ShaderSnippet>("RuntimeEffect",
1613 this->convertUniforms(effect),
1614 snippetFlags,
1615 /* texturesAndSamplers= */SkSpan<const TextureAndSampler>(),
1617 GenerateRuntimeShaderExpression,
1618 GenerateRuntimeShaderPreamble,
1619 (int)effect->children().size()));
1620
1621 int newCodeSnippetID = kUnknownRuntimeEffectIDStart + fUserDefinedCodeSnippets.size() - 1;
1622
1623 fRuntimeEffectMap.set(key, newCodeSnippetID);
1624 return newCodeSnippetID;
1625}
1626
1628 // The 0th index is reserved as invalid
1629 fIDToPaintKey.push_back(PaintParamsKey::Invalid());
1630
1631 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kError] = {
1632 "Error",
1633 { }, // no uniforms
1635 { }, // no samplers
1636 kErrorName,
1637 GenerateDefaultExpression,
1638 GenerateDefaultPreamble,
1640 };
1641 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPriorOutput] = {
1642 "PassthroughShader",
1643 { }, // no uniforms
1645 { }, // no samplers
1646 kPassthroughShaderName,
1647 GenerateDefaultExpression,
1648 GenerateDefaultPreamble,
1650 };
1651 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSolidColorShader] = {
1652 "SolidColor",
1653 SkSpan(kSolidShaderUniforms),
1655 { }, // no samplers
1656 kSolidShaderName,
1657 GenerateDefaultExpression,
1658 GenerateDefaultPreamble,
1660 };
1661 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRGBPaintColor] = {
1662 "RGBPaintColor",
1663 SkSpan(kPaintColorUniforms),
1665 { }, // no samplers
1666 kRGBPaintColorName,
1667 GenerateDefaultExpression,
1668 GenerateDefaultPreamble,
1670 };
1671 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kAlphaOnlyPaintColor] = {
1672 "AlphaOnlyPaintColor",
1673 SkSpan(kPaintColorUniforms),
1675 { }, // no samplers
1676 kAlphaOnlyPaintColorName,
1677 GenerateDefaultExpression,
1678 GenerateDefaultPreamble,
1680 };
1681 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLinearGradientShader4] = {
1682 "LinearGradient4",
1683 SkSpan(kLinearGradientUniforms4),
1685 { }, // no samplers
1686 kLinearGradient4Name,
1687 GenerateDefaultExpression,
1688 GenerateDefaultPreamble,
1690 };
1691 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLinearGradientShader8] = {
1692 "LinearGradient8",
1693 SkSpan(kLinearGradientUniforms8),
1695 { }, // no samplers
1696 kLinearGradient8Name,
1697 GenerateDefaultExpression,
1698 GenerateDefaultPreamble,
1700 };
1702 "LinearGradientTexture",
1703 SkSpan(kLinearGradientUniformsTexture),
1705 SkSpan(kTextureGradientTexturesAndSamplers),
1706 kLinearGradientTextureName,
1707 GenerateDefaultExpression,
1708 GenerateDefaultPreamble,
1710 };
1711 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRadialGradientShader4] = {
1712 "RadialGradient4",
1713 SkSpan(kRadialGradientUniforms4),
1715 { }, // no samplers
1716 kRadialGradient4Name,
1717 GenerateDefaultExpression,
1718 GenerateDefaultPreamble,
1720 };
1721 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kRadialGradientShader8] = {
1722 "RadialGradient8",
1723 SkSpan(kRadialGradientUniforms8),
1725 { }, // no samplers
1726 kRadialGradient8Name,
1727 GenerateDefaultExpression,
1728 GenerateDefaultPreamble,
1730 };
1732 "RadialGradientTexture",
1733 SkSpan(kRadialGradientUniformsTexture),
1735 SkSpan(kTextureGradientTexturesAndSamplers),
1736 kRadialGradientTextureName,
1737 GenerateDefaultExpression,
1738 GenerateDefaultPreamble,
1740 };
1741 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSweepGradientShader4] = {
1742 "SweepGradient4",
1743 SkSpan(kSweepGradientUniforms4),
1745 { }, // no samplers
1746 kSweepGradient4Name,
1747 GenerateDefaultExpression,
1748 GenerateDefaultPreamble,
1750 };
1751 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSweepGradientShader8] = {
1752 "SweepGradient8",
1753 SkSpan(kSweepGradientUniforms8),
1755 { }, // no samplers
1756 kSweepGradient8Name,
1757 GenerateDefaultExpression,
1758 GenerateDefaultPreamble,
1760 };
1761 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kSweepGradientShaderTexture] = {
1762 "SweepGradientTexture",
1763 SkSpan(kSweepGradientUniformsTexture),
1765 SkSpan(kTextureGradientTexturesAndSamplers),
1766 kSweepGradientTextureName,
1767 GenerateDefaultExpression,
1768 GenerateDefaultPreamble,
1770 };
1771 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kConicalGradientShader4] = {
1772 "ConicalGradient4",
1773 SkSpan(kConicalGradientUniforms4),
1775 { }, // no samplers
1776 kConicalGradient4Name,
1777 GenerateDefaultExpression,
1778 GenerateDefaultPreamble,
1780 };
1781 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kConicalGradientShader8] = {
1782 "ConicalGradient8",
1783 SkSpan(kConicalGradientUniforms8),
1785 { }, // no samplers
1786 kConicalGradient8Name,
1787 GenerateDefaultExpression,
1788 GenerateDefaultPreamble,
1790 };
1792 "ConicalGradientTexture",
1793 SkSpan(kConicalGradientUniformsTexture),
1795 SkSpan(kTextureGradientTexturesAndSamplers),
1796 kConicalGradientTextureName,
1797 GenerateDefaultExpression,
1798 GenerateDefaultPreamble,
1800 };
1801 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kLocalMatrixShader] = {
1802 "LocalMatrixShader",
1803 SkSpan(kLocalMatrixShaderUniforms),
1806 { }, // no samplers
1807 kLocalMatrixShaderName,
1808 GenerateDefaultExpression,
1809 GenerateLocalMatrixPreamble,
1810 kNumLocalMatrixShaderChildren
1811 };
1812 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kImageShader] = {
1813 "ImageShader",
1814 SkSpan(kImageShaderUniforms),
1816 SkSpan(kISTexturesAndSamplers),
1817 kImageShaderName,
1818 GenerateDefaultExpression,
1819 GenerateDefaultPreamble,
1821 };
1822 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCubicImageShader] = {
1823 "CubicImageShader",
1824 SkSpan(kCubicImageShaderUniforms),
1826 SkSpan(kISTexturesAndSamplers),
1827 kCubicImageShaderName,
1828 GenerateDefaultExpression,
1829 GenerateDefaultPreamble,
1831 };
1832 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kHWImageShader] = {
1833 "HardwareImageShader",
1834 SkSpan(kHWImageShaderUniforms),
1836 SkSpan(kISTexturesAndSamplers),
1837 kHWImageShaderName,
1838 GenerateDefaultExpression,
1839 GenerateDefaultPreamble,
1841 };
1842 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kYUVImageShader] = {
1843 "YUVImageShader",
1844 SkSpan(kYUVImageShaderUniforms),
1846 SkSpan(kYUVISTexturesAndSamplers),
1847 kYUVImageShaderName,
1848 GenerateDefaultExpression,
1849 GenerateDefaultPreamble,
1851 };
1852 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCubicYUVImageShader] = {
1853 "CubicYUVImageShader",
1854 SkSpan(kCubicYUVImageShaderUniforms),
1856 SkSpan(kYUVISTexturesAndSamplers),
1857 kCubicYUVImageShaderName,
1858 GenerateDefaultExpression,
1859 GenerateDefaultPreamble,
1861 };
1862 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCoordClampShader] = {
1863 "CoordClampShader",
1864 SkSpan(kCoordClampShaderUniforms),
1866 { }, // no samplers
1867 kCoordClampShaderName,
1868 GenerateDefaultExpression,
1869 GenerateCoordClampPreamble,
1870 kNumCoordClampShaderChildren
1871 };
1872 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kDitherShader] = {
1873 "DitherShader",
1874 SkSpan(kDitherShaderUniforms),
1876 SkSpan(kDitherTexturesAndSamplers),
1877 kDitherShaderName,
1878 GenerateDefaultExpression,
1879 GenerateDefaultPreamble,
1881 };
1882 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPerlinNoiseShader] = {
1883 "PerlinNoiseShader",
1884 SkSpan(kPerlinNoiseShaderUniforms),
1886 SkSpan(kPerlinNoiseShaderTexturesAndSamplers),
1887 kPerlinNoiseShaderName,
1888 GenerateDefaultExpression,
1889 GenerateDefaultPreamble,
1891 };
1892 // SkColorFilter snippets
1893 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kMatrixColorFilter] = {
1894 "MatrixColorFilter",
1895 SkSpan(kMatrixColorFilterUniforms),
1897 { }, // no samplers
1898 kMatrixColorFilterName,
1899 GenerateDefaultExpression,
1900 GenerateDefaultPreamble,
1902 };
1903 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kTableColorFilter] = {
1904 "TableColorFilter",
1905 { }, // no uniforms
1907 SkSpan(kTableColorFilterTexturesAndSamplers),
1908 kTableColorFilterName,
1909 GenerateDefaultExpression,
1910 GenerateDefaultPreamble,
1912 };
1913 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kGaussianColorFilter] = {
1914 "GaussianColorFilter",
1915 { }, // no uniforms
1917 { }, // no samplers
1918 kGaussianColorFilterName,
1919 GenerateDefaultExpression,
1920 GenerateDefaultPreamble,
1922 };
1923 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kColorSpaceXformColorFilter] = {
1924 "ColorSpaceTransform",
1925 SkSpan(kColorSpaceTransformUniforms),
1927 { }, // no samplers
1928 kColorSpaceTransformName,
1929 GenerateDefaultExpression,
1930 GenerateDefaultPreamble,
1932 };
1933
1934 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kBlendShader] = {
1935 "BlendShader",
1936 { }, // no uniforms
1938 { }, // no samplers
1939 "BlendShader",
1940 GenerateDefaultExpression,
1941 GenerateBlendShaderPreamble,
1942 kNumBlendShaderChildren
1943 };
1944 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCoeffBlender] = {
1945 "CoeffBlender",
1946 SkSpan(CoeffBlendderUniforms),
1948 { }, // no samplers
1949 kCoeffBlenderName,
1950 GenerateDefaultExpression,
1951 GenerateDefaultPreamble,
1953 };
1954 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kBlendModeBlender] = {
1955 "BlendModeBlender",
1956 SkSpan(kBlendModeBlenderUniforms),
1958 { }, // no samplers
1959 kBlendModeBlenderName,
1960 GenerateDefaultExpression,
1961 GenerateDefaultPreamble,
1963 };
1964
1965 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kPrimitiveColor] = {
1966 "PrimitiveColor",
1967 { }, // no uniforms
1969 { }, // no samplers
1970 "primitive color", // no static sksl
1971 GeneratePrimitiveColorExpression,
1972 GenerateDefaultPreamble,
1974 };
1975
1976 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kDstReadSample] = {
1977 "DstReadSample",
1978 SkSpan(kDstReadSampleUniforms),
1980 SkSpan(kDstReadSampleTexturesAndSamplers),
1981 "InitSurfaceColor",
1982 GenerateDstReadSampleExpression,
1983 GenerateDstReadSamplePreamble,
1985 };
1986 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kDstReadFetch] = {
1987 "DstReadFetch",
1988 { }, // no uniforms
1990 { }, // no samplers
1991 "InitSurfaceColor",
1992 GenerateDstReadFetchExpression,
1993 GenerateDstReadFetchPreamble,
1995 };
1996
1997 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kClipShader] = {
1998 "ClipShader",
1999 { }, // no uniforms
2001 { }, // no samplers
2002 "clip shader", // no static sksl
2003 GenerateClipShaderExpression,
2004 GenerateClipShaderPreamble,
2005 kNumClipShaderChildren
2006 };
2007
2008 fBuiltInCodeSnippets[(int) BuiltInCodeSnippetID::kCompose] = {
2009 "Compose",
2010 { }, // no uniforms
2012 { }, // no samplers
2013 kComposeName,
2014 GenerateDefaultExpression,
2015 GenerateNestedChildrenPreamble,
2016 kNumComposeChildren
2017 };
2018
2019 // Fixed-function blend mode snippets are all the same, their functionality is entirely defined
2020 // by their unique code snippet IDs.
2021 for (int i = 0; i <= (int) SkBlendMode::kLastCoeffMode; ++i) {
2022 int ffBlendModeID = kFixedFunctionBlendModeIDOffset + i;
2023 fBuiltInCodeSnippets[ffBlendModeID] = {
2024 SkBlendMode_Name(static_cast<SkBlendMode>(i)),
2025 { }, // no uniforms
2028 { }, // no samplers
2029 skgpu::BlendFuncName(static_cast<SkBlendMode>(i)),
2030 GenerateDefaultExpression,
2031 GenerateDefaultPreamble,
2033 };
2034 }
2035}
2036
2037// Verify that the built-in code IDs for fixed function blending are consistent with SkBlendMode.
2038// clang-format off
2054// clang-format on
2055
2056} // namespace skgpu::graphite
static int step(int x, SkScalar min, SkScalar max)
Definition BlurTest.cpp:215
SkColor4f color
SkBlendMode fBlendMode
Definition Layer.cpp:55
#define SkUNREACHABLE
Definition SkAssert.h:135
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SkASSERT(cond)
Definition SkAssert.h:116
SK_API const char * SkBlendMode_Name(SkBlendMode blendMode)
SkBlendMode
Definition SkBlendMode.h:38
@ kSrcOut
r = s * (1-da)
@ kPlus
r = min(s + d, 1)
@ kDstIn
r = d * sa
@ kModulate
r = s*d
@ kLastCoeffMode
last porter duff blend mode
@ kScreen
r = s + d - s*d
@ kSrcOver
r = s + (1-sa)*d
@ kXor
r = s*(1-da) + d*(1-sa)
@ kSrcATop
r = s*da + d*(1-sa)
@ kDstATop
r = d*sa + s*(1-da)
@ kDstOver
r = d + (1-da)*s
@ kDstOut
r = d * (1-sa)
@ kSrcIn
r = s * da
@ kClear
r = 0
constexpr SkPMColor4f SK_PMColor4fTRANSPARENT
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
#define M2(type, initializer)
#define SK_ALL_STABLEKEYS(M, M1, M2)
#define M1(type)
SkSLType
Type::kYUV Type::kRGBA() int(0.7 *637)
T * makeArrayDefault(size_t count)
T * makeInitializedArray(size_t count, Initializer initializer)
static uint32_t StableKey(const SkRuntimeEffect &effect)
static uint32_t Hash(const SkRuntimeEffect &effect)
static const SkSL::Program & Program(const SkRuntimeEffect &effect)
static bool UsesColorTransform(const SkRuntimeEffect *effect)
size_t uniformSize() const
SkSpan< const Child > children() const
bool allowBlender() const
SkSpan< const Uniform > uniforms() const
bool allowShader() const
std::string_view name() const
Definition SkSLSymbol.h:51
Variable * var() const
constexpr size_t size() const
Definition SkSpan_impl.h:95
const char * c_str() const
Definition SkString.h:133
OutputType secondaryOutput() const
skgpu::BlendEquation equation() const
skgpu::BlendCoeff dstCoeff() const
OutputType primaryOutput() const
bool hasSecondaryOutput() const
skgpu::BlendCoeff srcCoeff() const
bool modifiesDst() const
SkString asString() const
Definition Swizzle.cpp:46
static constexpr Swizzle RGBA()
Definition Swizzle.h:66
const ResourceBindingRequirements & resourceBindingRequirements() const
Definition Caps.h:143
DstReadRequirement getDstReadRequirement() const
Definition Caps.cpp:151
PaintParamsKey clone(SkArenaAlloc *) const
static constexpr PaintParamsKey Invalid()
static const char * ssboIndicesVarying()
Definition Renderer.h:139
PaintParamsKey lookup(UniquePaintParamsID) const SK_EXCLUDES(fSpinLock)
UniquePaintParamsID findOrCreate(PaintParamsKeyBuilder *) SK_EXCLUDES(fSpinLock)
int findOrCreateRuntimeEffectSnippet(const SkRuntimeEffect *effect)
SkSpan< const Uniform > getUniforms(BuiltInCodeSnippetID) const
const ShaderSnippet * getEntry(int codeSnippetID) const SK_EXCLUDES(fSpinLock)
const ShaderSnippet * entry() const
static UniquePaintParamsID InvalidID()
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
const char * name
Definition fuchsia.cc:50
std::u16string text
const SkRuntimeEffect * GetKnownRuntimeEffect(StableKey stableKey)
static constexpr int kUnknownRuntimeEffectIDStart
static constexpr int kSkiaKnownRuntimeEffectsEnd
static constexpr int kSkiaBuiltInReservedCnt
static constexpr int kSkiaKnownRuntimeEffectsStart
void ConvertProgram(const Program &program, const char *sampleCoords, const char *inputColor, const char *destColor, Callbacks *callbacks)
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
std::string void appendf(std::string *str, const char *fmt,...) SK_PRINTF_LIKE(2
static constexpr int kFixedFunctionBlendModeIDOffset
std::string EmitPaintParamsUniforms(int bufferID, const Layout layout, SkSpan< const ShaderNode * > nodes, int *numUniforms, int *uniformsTotalBytes, bool *wrotePaintColor)
std::string EmitStorageBufferAccess(const char *bufferNamePrefix, const char *ssboIndex, const char *uniformName)
static constexpr int kNoChildren
std::string EmitTexturesAndSamplers(const ResourceBindingRequirements &bindingReqs, SkSpan< const ShaderNode * > nodes, int *binding)
static constexpr Uniform kRuntimeEffectColorSpaceTransformUniforms[]
std::string EmitRenderStepStorageBuffer(int bufferID, SkSpan< const Uniform > uniforms)
std::string EmitRenderStepUniforms(int bufferID, const Layout layout, SkSpan< const Uniform > uniforms, int *renderStepUniformsTotalBytes)
std::string EmitVaryings(const RenderStep *step, const char *direction, bool emitSsboIndicesVarying, bool emitLocalCoordsVarying)
std::string EmitPaintParamsStorageBuffer(int bufferID, SkSpan< const ShaderNode * > nodes, int *numUniforms, bool *wrotePaintColor)
static constexpr char kRuntimeShaderName[]
static SkSLType uniform_type_to_sksl_type(const SkRuntimeEffect::Uniform &u)
void append_color_output(std::string *mainBody, BlendFormula::OutputType outputType, const char *outColor, const char *inColor)
std::string EmitUniformsFromStorageBuffer(const char *bufferNamePrefix, const char *ssboIndex, SkSpan< const Uniform > uniforms)
static constexpr int kBuiltInCodeSnippetIDCount
const char * BlendFuncName(SkBlendMode mode)
Definition Blend.cpp:18
BlendFormula GetBlendFormula(bool isOpaque, bool hasCoverage, SkBlendMode xfermode)
BlendCoeff
Definition Blend.h:60
BlendFormula GetLCDBlendFormula(SkBlendMode xfermode)
static constexpr bool BlendModifiesDst(BlendEquation equation, BlendCoeff srcCoeff, BlendCoeff dstCoeff)
Definition Blend.h:134
#define M(PROC, DITHER)
@ skcms_TFType_Invalid
@ skcms_TFType_HLGish
@ skcms_TFType_sRGBish
@ skcms_TFType_HLGinvish
@ skcms_TFType_PQish
SkSpan< const TextureAndSampler > fTexturesAndSamplers