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:
parent
5556c2ca9a
commit
c28ff1f69a
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user