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