Flutter Engine
The Flutter Engine
Public Member Functions | List of all members
skgpu::graphite::ShaderInfo Class Reference

#include <ShaderCodeDictionary.h>

Public Member Functions

 ShaderInfo (UniquePaintParamsID id, const ShaderCodeDictionary *dict, const RuntimeEffectDictionary *rteDict, const char *ssboIndex)
 
bool needsLocalCoords () const
 
bool needsSurfaceColor () const
 
const RuntimeEffectDictionaryruntimeEffectDictionary () const
 
const char * ssboIndex () const
 
const skgpu::BlendInfoblendInfo () const
 
const skia_private::TArray< uint32_t > & data () const
 
std::string toSkSL (const Caps *caps, const RenderStep *step, bool useStorageBuffers, int *numTexturesAndSamplersUsed, int *numPaintUniforms, int *renderStepUniformTotalBytes, int *paintUniformsTotalBytes, bool *hasGradientBuffer, Swizzle writeSwizzle)
 

Detailed Description

Definition at line 185 of file ShaderCodeDictionary.h.

Constructor & Destructor Documentation

◆ ShaderInfo()

skgpu::graphite::ShaderInfo::ShaderInfo ( UniquePaintParamsID  id,
const ShaderCodeDictionary dict,
const RuntimeEffectDictionary rteDict,
const char *  ssboIndex 
)

Definition at line 187 of file ShaderCodeDictionary.cpp.

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}
SkBlendMode fBlendMode
Definition: Layer.cpp:55
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkBlendMode
Definition: SkBlendMode.h:38
@ kLastCoeffMode
last porter duff blend mode
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
string root
Definition: scale_cpu.py:20
static constexpr int kFixedFunctionBlendModeIDOffset
static constexpr int kBuiltInCodeSnippetIDCount

Member Function Documentation

◆ blendInfo()

const skgpu::BlendInfo & skgpu::graphite::ShaderInfo::blendInfo ( ) const
inline

Definition at line 203 of file ShaderCodeDictionary.h.

203{ return fBlendInfo; }

◆ data()

const skia_private::TArray< uint32_t > & skgpu::graphite::ShaderInfo::data ( ) const
inline

Definition at line 205 of file ShaderCodeDictionary.h.

205{ return fData; }

◆ needsLocalCoords()

bool skgpu::graphite::ShaderInfo::needsLocalCoords ( ) const
inline

Definition at line 192 of file ShaderCodeDictionary.h.

192 {
193 return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kLocalCoords);
194 }
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35

◆ needsSurfaceColor()

bool skgpu::graphite::ShaderInfo::needsSurfaceColor ( ) const
inline

Definition at line 195 of file ShaderCodeDictionary.h.

195 {
196 return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kSurfaceColor);
197 }

◆ runtimeEffectDictionary()

const RuntimeEffectDictionary * skgpu::graphite::ShaderInfo::runtimeEffectDictionary ( ) const
inline

Definition at line 198 of file ShaderCodeDictionary.h.

198 {
199 return fRuntimeEffectDictionary;
200 }

◆ ssboIndex()

const char * skgpu::graphite::ShaderInfo::ssboIndex ( ) const
inline

Definition at line 201 of file ShaderCodeDictionary.h.

201{ return fSsboIndex; }

◆ toSkSL()

std::string skgpu::graphite::ShaderInfo::toSkSL ( const Caps caps,
const RenderStep step,
bool  useStorageBuffers,
int numTexturesAndSamplersUsed,
int numPaintUniforms,
int renderStepUniformTotalBytes,
int paintUniformsTotalBytes,
bool *  hasGradientBuffer,
Swizzle  writeSwizzle 
)

Definition at line 284 of file ShaderCodeDictionary.cpp.

292 {
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) {
340 SkASSERT(caps->storageBufferSupport());
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) {
405 if (node->codeSnippetId() == (int) BuiltInCodeSnippetID::kClipShader) {
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
412 if (node->codeSnippetId() >= kBuiltInCodeSnippetIDCount ||
413 node->codeSnippetId() < kFixedFunctionBlendModeIDOffset) {
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}
static int step(int x, SkScalar min, SkScalar max)
Definition: BlurTest.cpp:215
constexpr SkPMColor4f SK_PMColor4fTRANSPARENT
Definition: SkColorData.h:378
static constexpr Swizzle RGBA()
Definition: Swizzle.h:66
static const char * ssboIndicesVarying()
Definition: Renderer.h:139
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
std::string void appendf(std::string *str, const char *fmt,...) SK_PRINTF_LIKE(2
Definition: SkSLString.cpp:92
std::string EmitPaintParamsUniforms(int bufferID, const Layout layout, SkSpan< const ShaderNode * > nodes, int *numUniforms, int *uniformsTotalBytes, bool *wrotePaintColor)
std::string EmitTexturesAndSamplers(const ResourceBindingRequirements &bindingReqs, SkSpan< const ShaderNode * > nodes, int *binding)
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
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)
Definition: GpuTools.h:21
BlendFormula GetBlendFormula(bool isOpaque, bool hasCoverage, SkBlendMode xfermode)
BlendFormula GetLCDBlendFormula(SkBlendMode xfermode)

The documentation for this class was generated from the following files: