Replace glue-code generators with expression generators.

A runtime effect needs to be able to invoke a child snippet from
a `child.eval()` expression anywhere. Because `eval` occurs in an
expression context, we don't have the ability to emit multiple
statements. This CL restructures our glue-code generation functions to
return expressions instead of outputting statements, so that they can
be used as subexpressions.

Change-Id: I930bfef2c668323d68f6fd5795621cf42e1bf4eb
Bug: skia:13508
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/558542
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
John Stiles 2022-07-14 12:33:37 -04:00 committed by SkCQ
parent 5556c2ca9a
commit c28ff1f69a
2 changed files with 94 additions and 125 deletions

View File

@ -136,9 +136,12 @@ static std::string emit_glue_code_for_entry(const SkShaderInfo& shaderInfo,
currentPreLocalName = parentPreLocalName;
}
(reader.entry()->fGlueCodeGenerator)(shaderInfo, scopeOutputVar, entryIndex, reader,
priorStageOutputName, currentPreLocalName,
preamble, mainBody, indent + 1);
std::string expr = (reader.entry()->fExpressionGenerator)(shaderInfo, entryIndex,
reader, priorStageOutputName,
currentPreLocalName, preamble);
add_indent(mainBody, indent + 1);
SkSL::String::appendf(mainBody, "%s = %s;\n", scopeOutputVar.c_str(), expr.c_str());
add_indent(mainBody, indent);
*mainBody += "}\n";
@ -347,15 +350,12 @@ static std::string append_default_snippet_arguments(const SkShaderSnippet* entry
// The default glue code just calls a built-in function with the signature:
// half4 BuiltinFunctionName(/* all uniforms as parameters */);
// and stores the result in a variable named "resultName".
void GenerateDefaultGlueCode(const SkShaderInfo& shaderInfo,
const std::string& resultName,
std::string GenerateDefaultGlueCode(const SkShaderInfo& shaderInfo,
int* entryIndex,
const SkPaintParamsKey::BlockReader& reader,
const std::string& priorStageOutputName,
const std::string& currentPreLocalName,
std::string* preamble,
std::string* mainBody,
int indent) {
std::string* preamble) {
#if defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
const SkShaderSnippet* entry = reader.entry();
SkASSERT(entry->fNumChildren == 0);
@ -366,11 +366,11 @@ void GenerateDefaultGlueCode(const SkShaderInfo& shaderInfo,
SkASSERT(entry->fUniforms.front().type() == SkSLType::kFloat4x4);
}
add_indent(mainBody, indent);
SkSL::String::appendf(mainBody, "%s = %s", resultName.c_str(), entry->fStaticFunctionName);
*mainBody += append_default_snippet_arguments(entry, *entryIndex, currentPreLocalName,
return entry->fStaticFunctionName +
append_default_snippet_arguments(entry, *entryIndex, currentPreLocalName,
/*childOutputs=*/{});
*mainBody += ";\n";
#else
return priorStageOutputName;
#endif // defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
}
@ -380,15 +380,12 @@ void GenerateDefaultGlueCode(const SkShaderInfo& shaderInfo,
// uniforms and child outputs along:
// half4 BuiltinFunctionName(/* all uniforms as parameters */,
// /* all child output variable names as parameters */);
void GenerateDefaultGlueCodeWithChildren(const SkShaderInfo& shaderInfo,
const std::string& resultName,
std::string GenerateDefaultGlueCodeWithChildren(const SkShaderInfo& shaderInfo,
int* entryIndex,
const SkPaintParamsKey::BlockReader& reader,
const std::string& priorStageOutputName,
const std::string& currentPreLocalName,
std::string* preamble,
std::string* mainBody,
int indent) {
std::string* preamble) {
#if defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
const SkShaderSnippet* entry = reader.entry();
SkASSERT(entry->fNumChildren > 0);
@ -423,14 +420,13 @@ void GenerateDefaultGlueCodeWithChildren(const SkShaderInfo& shaderInfo,
// Add the helper function to the bottom of the preamble.
*preamble += helperFn;
// Invoke the helper function from the main body.
add_indent(mainBody, indent);
SkSL::String::appendf(mainBody,
"%s = %s(%s, %s);",
resultName.c_str(),
// Return an expression invoking the helper function.
return SkSL::String::printf("%s(%s, %s)",
helperFnName.c_str(),
priorStageOutputName.c_str(),
currentPreLocalName.c_str());
#else
return priorStageOutputName;
#endif // defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
}
@ -563,15 +559,12 @@ static constexpr char kImageShaderName[] = "sk_compute_coords";
// Ideally the "compute_coords" code snippet could just take texture and
// sampler references and do everything. That is going to take more time to figure out though so,
// for the sake of expediency, we're generating custom code to do the sampling.
void GenerateImageShaderGlueCode(const SkShaderInfo&,
const std::string& resultName,
std::string GenerateImageShaderGlueCode(const SkShaderInfo&,
int* entryIndex,
const SkPaintParamsKey::BlockReader& reader,
const std::string& priorStageOutputName,
const std::string& currentPreLocalName,
std::string* preamble,
std::string* mainBody,
int indent) {
std::string* preamble) {
#if defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
std::string samplerVarName = std::string("sampler_") + std::to_string(*entryIndex) + "_0";
@ -582,9 +575,8 @@ void GenerateImageShaderGlueCode(const SkShaderInfo&,
std::string imgWidthName = reader.entry()->getMangledUniformName(4, *entryIndex);
std::string imgHeightName = reader.entry()->getMangledUniformName(5, *entryIndex);
add_indent(mainBody, indent);
SkSL::String::appendf(mainBody,
"float2 coords = %s(%s * dev2LocalUni, %s, %s, %s, %s, %s);",
return SkSL::String::printf("sample(%s, %s(%s * dev2LocalUni, %s, %s, %s, %s, %s))",
samplerVarName.c_str(),
reader.entry()->fStaticFunctionName,
currentPreLocalName.c_str(),
subsetName.c_str(),
@ -592,12 +584,8 @@ void GenerateImageShaderGlueCode(const SkShaderInfo&,
tmYName.c_str(),
imgWidthName.c_str(),
imgHeightName.c_str());
add_indent(mainBody, indent);
SkSL::String::appendf(mainBody,
"%s = sample(%s, coords);\n",
resultName.c_str(),
samplerVarName.c_str());
#else
return priorStageOutputName;
#endif // defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
}
@ -687,15 +675,12 @@ private:
#endif
void GenerateRuntimeShaderGlueCode(const SkShaderInfo& shaderInfo,
const std::string& resultName,
std::string GenerateRuntimeShaderGlueCode(const SkShaderInfo& shaderInfo,
int* entryIndex,
const SkPaintParamsKey::BlockReader& reader,
const std::string& priorStageOutputName,
const std::string& currentPreLocalName,
std::string* preamble,
std::string* mainBody,
int indent) {
std::string* preamble) {
#if defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
const SkShaderSnippet* entry = reader.entry();
@ -713,14 +698,14 @@ void GenerateRuntimeShaderGlueCode(const SkShaderInfo& shaderInfo,
// TODO: we can eliminate this uniform entirely if it's the identity matrix.
// TODO: if we could inherit the parent's transform, this could be removed entirely.
SkASSERT(entry->needsLocalCoords());
SkASSERT(reader.entry()->fUniforms[0].type() == SkSLType::kFloat4x4);
SkASSERT(entry->fUniforms.front().type() == SkSLType::kFloat4x4);
add_indent(mainBody, indent);
SkSL::String::appendf(mainBody, "%s = %s_%d(%s, %s);\n",
resultName.c_str(),
return SkSL::String::printf("%s_%d(%s, %s)",
entry->fName, *entryIndex,
currentPreLocalName.c_str(),
priorStageOutputName.c_str());
#else
return priorStageOutputName;
#endif // defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
}
@ -730,27 +715,21 @@ static constexpr char kErrorName[] = "sk_error";
//--------------------------------------------------------------------------------------------------
// This method generates the glue code for the case where the SkBlendMode-based blending is
// handled with fixed function blending.
void GenerateFixedFunctionBlenderGlueCode(const SkShaderInfo&,
const std::string& resultName,
std::string GenerateFixedFunctionBlenderGlueCode(const SkShaderInfo&,
int* entryIndex,
const SkPaintParamsKey::BlockReader& reader,
const std::string& priorStageOutputName,
const std::string& currentPreLocalName,
std::string* preamble,
std::string* mainBody,
int indent) {
std::string* preamble) {
#if defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
SkASSERT(reader.entry()->fUniforms.empty());
SkASSERT(reader.numDataPayloadFields() == 0);
// The actual blending is set up via the fixed function pipeline so we don't actually
// need to access the blend mode in the glue code.
add_indent(mainBody, indent);
*mainBody += "// Fixed-function blending\n";
add_indent(mainBody, indent);
SkSL::String::appendf(mainBody, "%s = %s;", resultName.c_str(), priorStageOutputName.c_str());
#endif // defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
return priorStageOutputName;
}
//--------------------------------------------------------------------------------------------------
@ -764,34 +743,26 @@ static constexpr char kBlendHelperName[] = "sk_blend";
// in the shader (i.e., fixed function blending isn't possible).
// It exists as custom glue code so that we can deal with the dest reads. If that can be
// standardized (e.g., via a snippets requirement flag) this could be removed.
void GenerateShaderBasedBlenderGlueCode(const SkShaderInfo&,
const std::string& resultName,
std::string GenerateShaderBasedBlenderGlueCode(const SkShaderInfo&,
int* entryIndex,
const SkPaintParamsKey::BlockReader& reader,
const std::string& priorStageOutputName,
const std::string& currentPreLocalName,
std::string* preamble,
std::string* mainBody,
int indent) {
std::string* preamble) {
#if defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
SkASSERT(reader.entry()->fUniforms.size() == 1);
SkASSERT(reader.numDataPayloadFields() == 0);
std::string uniformName = reader.entry()->getMangledUniformName(0, *entryIndex);
add_indent(mainBody, indent);
*mainBody += "// Shader-based blending\n";
// TODO: emit function to perform dest read into preamble, and replace half(1) with that call
// TODO: emit code to perform dest read here
add_indent(mainBody, indent);
*mainBody += "half4 dummyDst = half4(1);\n";
add_indent(mainBody, indent);
SkSL::String::appendf(mainBody, "%s = %s(%s, %s, dummyDst);",
resultName.c_str(),
return SkSL::String::printf("%s(%s, %s, half4(1))",
reader.entry()->fStaticFunctionName,
uniformName.c_str(),
priorStageOutputName.c_str());
#else
return priorStageOutputName;
#endif // defined(SK_GRAPHITE_ENABLED) && defined(SK_ENABLE_SKSL)
}
@ -820,7 +791,7 @@ int SkShaderCodeDictionary::addUserDefinedSnippet(
SnippetRequirementFlags snippetRequirementFlags,
SkSpan<const SkTextureAndSampler> texturesAndSamplers,
const char* functionName,
SkShaderSnippet::GenerateGlueCodeForEntry glueCodeGenerator,
SkShaderSnippet::GenerateExpressionForSnippetFn expressionGenerator,
int numChildren,
SkSpan<const SkPaintParamsKey::DataPayloadField> dataPayloadExpectations) {
// TODO: the memory for user-defined entries could go in the dictionary's arena but that
@ -831,7 +802,7 @@ int SkShaderCodeDictionary::addUserDefinedSnippet(
snippetRequirementFlags,
texturesAndSamplers,
functionName,
glueCodeGenerator,
expressionGenerator,
numChildren,
dataPayloadExpectations));

View File

@ -47,15 +47,13 @@ enum class SnippetRequirementFlags : uint32_t {
SK_MAKE_BITMASK_OPS(SnippetRequirementFlags);
struct SkShaderSnippet {
using GenerateGlueCodeForEntry = void (*)(const SkShaderInfo& shaderInfo,
const std::string& resultName,
using GenerateExpressionForSnippetFn =
std::string (*)(const SkShaderInfo& shaderInfo,
int* entryIndex, // for uniform name mangling
const SkPaintParamsKey::BlockReader&,
const std::string& priorStageOutputName,
const std::string& currentPreLocalName,
std::string* preamble,
std::string* mainBody,
int indent);
std::string* preamble);
SkShaderSnippet() = default;
@ -64,7 +62,7 @@ struct SkShaderSnippet {
SnippetRequirementFlags snippetRequirementFlags,
SkSpan<const SkTextureAndSampler> texturesAndSamplers,
const char* functionName,
GenerateGlueCodeForEntry glueCodeGenerator,
GenerateExpressionForSnippetFn expressionGenerator,
int numChildren,
SkSpan<const SkPaintParamsKey::DataPayloadField> dataPayloadExpectations)
: fName(name)
@ -72,7 +70,7 @@ struct SkShaderSnippet {
, fSnippetRequirementFlags(snippetRequirementFlags)
, fTexturesAndSamplers(texturesAndSamplers)
, fStaticFunctionName(functionName)
, fGlueCodeGenerator(glueCodeGenerator)
, fExpressionGenerator(expressionGenerator)
, fNumChildren(numChildren)
, fDataPayloadExpectations(dataPayloadExpectations) {}
@ -87,7 +85,7 @@ struct SkShaderSnippet {
SnippetRequirementFlags fSnippetRequirementFlags;
SkSpan<const SkTextureAndSampler> fTexturesAndSamplers;
const char* fStaticFunctionName = nullptr;
GenerateGlueCodeForEntry fGlueCodeGenerator = nullptr;
GenerateExpressionForSnippetFn fExpressionGenerator = nullptr;
int fNumChildren = 0;
SkSpan<const SkPaintParamsKey::DataPayloadField> fDataPayloadExpectations;
};
@ -233,7 +231,7 @@ private:
SnippetRequirementFlags snippetRequirementFlags,
SkSpan<const SkTextureAndSampler> texturesAndSamplers,
const char* functionName,
SkShaderSnippet::GenerateGlueCodeForEntry glueCodeGenerator,
SkShaderSnippet::GenerateExpressionForSnippetFn expressionGenerator,
int numChildren,
SkSpan<const SkPaintParamsKey::DataPayloadField> dataPayloadExpectations);