Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
 
std::string toSkSL (const Caps *caps, const RenderStep *step, bool useStorageBuffers, int *numTexturesAndSamplersUsed, int *numPaintUniforms, int *renderStepUniformTotalBytes, int *paintUniformsTotalBytes, Swizzle writeSwizzle)
 

Detailed Description

Definition at line 173 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 // TODO: This is brittle as it relies on PaintParams::toKey() putting the final fixed
203 // function blend block at the root level. This can be improved with more structure to the
204 // key creation.
205 if (root->codeSnippetId() < kBuiltInCodeSnippetIDCount &&
206 root->codeSnippetId() >= kFixedFunctionBlendModeIDOffset) {
207 SkASSERT(root->numChildren() == 0);
208 // This should occur at most once
209 SkASSERT(!fixedFuncBlendFound);
210 SkDEBUGCODE(fixedFuncBlendFound = true;)
211
212 fBlendMode = static_cast<SkBlendMode>(root->codeSnippetId() -
214 SkASSERT(static_cast<int>(fBlendMode) >= 0 &&
216 fBlendInfo = gBlendTable[static_cast<int>(fBlendMode)];
217 } else {
218 fSnippetRequirementFlags |= root->requiredFlags();
219 }
220 }
221}
SkBlendMode fBlendMode
Definition Layer.cpp:55
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBlendMode
Definition SkBlendMode.h:38
@ kLastCoeffMode
last porter duff blend mode
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static constexpr int kFixedFunctionBlendModeIDOffset
static constexpr int kBuiltInCodeSnippetIDCount

Member Function Documentation

◆ blendInfo()

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

Definition at line 191 of file ShaderCodeDictionary.h.

191{ return fBlendInfo; }

◆ needsLocalCoords()

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

Definition at line 180 of file ShaderCodeDictionary.h.

180 {
181 return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kLocalCoords);
182 }
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35

◆ needsSurfaceColor()

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

Definition at line 183 of file ShaderCodeDictionary.h.

183 {
184 return SkToBool(fSnippetRequirementFlags & SnippetRequirementFlags::kSurfaceColor);
185 }

◆ runtimeEffectDictionary()

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

Definition at line 186 of file ShaderCodeDictionary.h.

186 {
187 return fRuntimeEffectDictionary;
188 }

◆ ssboIndex()

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

Definition at line 189 of file ShaderCodeDictionary.h.

189{ 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,
Swizzle  writeSwizzle 
)

Definition at line 265 of file ShaderCodeDictionary.cpp.

272 {
273 // If we're doing analytic coverage, we must also be doing shading.
274 SkASSERT(step->coverage() == Coverage::kNone || step->performsShading());
275 const bool hasStepUniforms = step->numUniforms() > 0 && step->coverage() != Coverage::kNone;
276 const bool useStepStorageBuffer = useStorageBuffers && hasStepUniforms;
277 const bool useShadingStorageBuffer = useStorageBuffers && step->performsShading();
278
279 const bool defineLocalCoordsVarying = this->needsLocalCoords();
280 std::string preamble = EmitVaryings(step,
281 /*direction=*/"in",
282 /*emitSsboIndicesVarying=*/useShadingStorageBuffer,
283 defineLocalCoordsVarying);
284
285 // The uniforms are mangled by having their index in 'fEntries' as a suffix (i.e., "_%d")
286 // TODO: replace hard-coded bufferIDs with the backend's step and paint uniform-buffer indices.
287 // TODO: The use of these indices is Metal-specific. We should replace these functions with
288 // API-independent ones.
289 const ResourceBindingRequirements& bindingReqs = caps->resourceBindingRequirements();
290 if (hasStepUniforms) {
291 if (useStepStorageBuffer) {
292 preamble += EmitRenderStepStorageBuffer(/*bufferID=*/1, step->uniforms());
293 } else {
294 preamble += EmitRenderStepUniforms(/*bufferID=*/1,
295 bindingReqs.fUniformBufferLayout,
296 step->uniforms(),
297 renderStepUniformTotalBytes);
298 }
299 }
300
301 bool wrotePaintColor = false;
302 if (useShadingStorageBuffer) {
303 preamble += EmitPaintParamsStorageBuffer(/*bufferID=*/2,
304 fRootNodes,
305 numPaintUniforms,
306 &wrotePaintColor);
307 SkSL::String::appendf(&preamble, "uint %s;\n", this->ssboIndex());
308 } else {
309 preamble += EmitPaintParamsUniforms(/*bufferID=*/2,
310 bindingReqs.fUniformBufferLayout,
311 fRootNodes,
312 numPaintUniforms,
313 paintUniformsTotalBytes,
314 &wrotePaintColor);
315 }
316
317 {
318 int binding = 0;
319 preamble += EmitTexturesAndSamplers(bindingReqs, fRootNodes, &binding);
320 if (step->hasTextures()) {
321 preamble += step->texturesAndSamplersSkSL(bindingReqs, &binding);
322 }
323
324 // Report back to the caller how many textures and samplers are used.
325 if (numTexturesAndSamplersUsed) {
326 *numTexturesAndSamplersUsed = binding;
327 }
328 }
329
330 if (step->emitsPrimitiveColor()) {
331 // TODO: Define this in the main body, and then pass it down into snippets like we do with
332 // the local coordinates varying.
333 preamble += "half4 primitiveColor;";
334 }
335
336 // Emit preamble declarations and helper functions required for snippets. In the default case
337 // this adds functions that bind a node's specific mangled uniforms to the snippet's
338 // implementation in the SkSL modules.
339 emit_preambles(*this, fRootNodes, /*treeLabel=*/"", &preamble);
340
341 std::string mainBody = "void main() {";
342 // Set initial color. This will typically be optimized out by SkSL in favor of the paint
343 // specifying a color with a solid color shader.
344 mainBody += "half4 initialColor = half4(0);";
345
346 if (useShadingStorageBuffer) {
347 SkSL::String::appendf(&mainBody,
348 "%s = %s.y;\n",
349 this->ssboIndex(),
351 }
352
353 if (step->emitsPrimitiveColor()) {
354 mainBody += step->fragmentColorSkSL();
355 }
356
357 // While looping through root nodes to emit shader code, skip the clip shader node if it's found
358 // and keep it to apply later during coverage calculation.
359 const ShaderNode* clipShaderNode = nullptr;
360
361 // Emit shader main body code, invoking each root node's expression, forwarding the previous
362 // node's output to the next.
363 static constexpr char kUnusedDstColor[] = "half4(1)";
364 static constexpr char kUnusedLocalCoords[] = "float2(0)";
365 ShaderSnippet::Args args = {"initialColor",
366 kUnusedDstColor,
367 this->needsLocalCoords() ? "localCoordsVar" : kUnusedLocalCoords};
368 for (const ShaderNode* node : fRootNodes) {
369 if (node->codeSnippetId() == (int) BuiltInCodeSnippetID::kClipShader) {
370 SkASSERT(!clipShaderNode);
371 clipShaderNode = node;
372 continue;
373 }
374 // This exclusion of the final Blend can be removed once we've resolved the final
375 // blend parenting issue w/in the key
376 if (node->codeSnippetId() >= kBuiltInCodeSnippetIDCount ||
377 node->codeSnippetId() < kFixedFunctionBlendModeIDOffset) {
378 args.fPriorStageOutput = emit_glue_code_for_entry(*this, node, args, &mainBody);
379 }
380 }
381
382 if (writeSwizzle != Swizzle::RGBA()) {
383 SkSL::String::appendf(&mainBody, "%s = %s.%s;", args.fPriorStageOutput.c_str(),
384 args.fPriorStageOutput.c_str(),
385 writeSwizzle.asString().c_str());
386 }
387
388 const char* outColor = args.fPriorStageOutput.c_str();
389 const Coverage coverage = step->coverage();
390 if (coverage != Coverage::kNone || clipShaderNode) {
391 if (useStepStorageBuffer) {
392 SkSL::String::appendf(&mainBody,
393 "uint stepSsboIndex = %s.x;\n",
395 mainBody += EmitUniformsFromStorageBuffer("step", "stepSsboIndex", step->uniforms());
396 }
397
398 mainBody += "half4 outputCoverage = half4(1);";
399 mainBody += step->fragmentCoverageSkSL();
400
401 if (clipShaderNode) {
402 std::string clipShaderOutput =
403 emit_glue_code_for_entry(*this, clipShaderNode, args, &mainBody);
404 SkSL::String::appendf(&mainBody, "outputCoverage *= %s.a;", clipShaderOutput.c_str());
405 }
406
407 // TODO: Determine whether draw is opaque and pass that to GetBlendFormula.
408 BlendFormula coverageBlendFormula =
412 /*isOpaque=*/false, /*hasCoverage=*/true, fBlendMode);
413
414 if (this->needsSurfaceColor()) {
415 // If this draw uses a non-coherent dst read, we want to keep the existing dst color (or
416 // whatever has been previously drawn) when there's no coverage. This helps for batching
417 // text draws that need to read from a dst copy for blends. However, this only helps the
418 // case where the outer bounding boxes of each letter overlap and not two actual parts
419 // of the text.
420 DstReadRequirement dstReadReq = caps->getDstReadRequirement();
421 if (dstReadReq == DstReadRequirement::kTextureCopy ||
423 // We don't think any shaders actually output negative coverage, but just as a
424 // safety check for floating point precision errors, we compare with <= here. We
425 // just check the RGB values of the coverage, since the alpha may not have been set
426 // when using LCD. If we are using single-channel coverage, alpha will be equal to
427 // RGB anyway.
428 mainBody +=
429 "if (all(lessThanEqual(outputCoverage.rgb, half3(0)))) {"
430 "discard;"
431 "}";
432 }
433
434 // Use originally-specified BlendInfo and blend with dst manually.
436 &mainBody,
437 "sk_FragColor = %s * outputCoverage + surfaceColor * (1.0 - outputCoverage);",
438 outColor);
439 if (coverage == Coverage::kLCD) {
441 &mainBody,
442 "half3 lerpRGB = mix(surfaceColor.aaa, %s.aaa, outputCoverage.rgb);"
443 "sk_FragColor.a = max(max(lerpRGB.r, lerpRGB.g), lerpRGB.b);",
444 outColor);
445 }
446
447 } else {
448 fBlendInfo = {coverageBlendFormula.equation(),
449 coverageBlendFormula.srcCoeff(),
450 coverageBlendFormula.dstCoeff(),
452 coverageBlendFormula.modifiesDst()};
453
454 if (coverage == Coverage::kLCD) {
455 mainBody += "outputCoverage.a = max(max(outputCoverage.r, "
456 "outputCoverage.g), "
457 "outputCoverage.b);";
458 }
460 &mainBody, coverageBlendFormula.primaryOutput(), "sk_FragColor", outColor);
461 if (coverageBlendFormula.hasSecondaryOutput()) {
462 append_color_output(&mainBody,
463 coverageBlendFormula.secondaryOutput(),
464 "sk_SecondaryFragColor",
465 outColor);
466 }
467 }
468
469 } else {
470 SkSL::String::appendf(&mainBody, "sk_FragColor = %s;", outColor);
471 }
472 mainBody += "}\n";
473
474 return preamble + "\n" + mainBody;
475}
static int step(int x, SkScalar min, SkScalar max)
Definition BlurTest.cpp:215
constexpr SkPMColor4f SK_PMColor4fTRANSPARENT
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
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)
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)
BlendFormula GetBlendFormula(bool isOpaque, bool hasCoverage, SkBlendMode xfermode)
BlendFormula GetLCDBlendFormula(SkBlendMode xfermode)

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