Child fragment processors are now written as separate functions
Bug: skia:
Change-Id: Icbf8f542637a874b3e2d3513d932b39728fa5e77
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/229385
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
index 4101860..dec2c96 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
@@ -16,21 +16,33 @@
this->onSetData(pdman, processor);
}
-void GrGLSLFragmentProcessor::emitChild(int childIndex, const char* inputColor, EmitArgs& args) {
- this->internalEmitChild(childIndex, inputColor, args.fOutputColor, args);
+void GrGLSLFragmentProcessor::invokeChild(int childIndex, const char* inputColor, EmitArgs& args) {
+ while (childIndex >= (int) fFunctionNames.size()) {
+ fFunctionNames.emplace_back();
+ }
+ this->internalInvokeChild(childIndex, inputColor, args.fOutputColor, args);
}
-void GrGLSLFragmentProcessor::emitChild(int childIndex, const char* inputColor,
- SkString* outputColor, EmitArgs& args) {
+void GrGLSLFragmentProcessor::invokeChild(int childIndex, const char* inputColor,
+ SkString* outputColor, EmitArgs& args) {
SkASSERT(outputColor);
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
outputColor->append(fragBuilder->getMangleString());
fragBuilder->codeAppendf("half4 %s;", outputColor->c_str());
- this->internalEmitChild(childIndex, inputColor, outputColor->c_str(), args);
+ while (childIndex >= (int) fFunctionNames.size()) {
+ fFunctionNames.emplace_back();
+ }
+ if (fFunctionNames[childIndex].size() == 0) {
+ this->internalInvokeChild(childIndex, inputColor, outputColor->c_str(), args);
+ } else {
+ fragBuilder->codeAppendf("%s = %s(%s);", outputColor->c_str(),
+ fFunctionNames[childIndex].c_str(),
+ inputColor ? inputColor : "half4(1)");
+ }
}
-void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inputColor,
- const char* outputColor, EmitArgs& args) {
+void GrGLSLFragmentProcessor::internalInvokeChild(int childIndex, const char* inputColor,
+ const char* outputColor, EmitArgs& args) {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
fragBuilder->onBeforeChildProcEmitCode(); // call first so mangleString is updated
@@ -48,24 +60,24 @@
const GrFragmentProcessor& childProc = args.fFp.childProcessor(childIndex);
- // emit the code for the child in its own scope
- fragBuilder->codeAppend("{\n");
- fragBuilder->codeAppendf("// Child Index %d (mangle: %s): %s\n", childIndex,
- fragBuilder->getMangleString().c_str(), childProc.name());
TransformedCoordVars coordVars = args.fTransformedCoords.childInputs(childIndex);
TextureSamplers textureSamplers = args.fTexSamplers.childInputs(childIndex);
- // EmitArgs properly updates inputColor to half4(1) if it was null
EmitArgs childArgs(fragBuilder,
args.fUniformHandler,
args.fShaderCaps,
childProc,
outputColor,
- inputName.size() > 0 ? inputName.c_str() : nullptr,
+ "_input",
coordVars,
textureSamplers);
- this->childProcessor(childIndex)->emitCode(childArgs);
- fragBuilder->codeAppend("}\n");
+ fFunctionNames[childIndex] = fragBuilder->writeProcessorFunction(
+ this->childProcessor(childIndex),
+ childArgs);
+ fragBuilder->codeAppendf("%s = %s(%s);\n", outputColor,
+ fFunctionNames[childIndex].c_str(),
+ inputName.size() > 0 ? inputName.c_str()
+ : "half4(1)");
fragBuilder->onAfterChildProcEmitCode();
}
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h
index 4a8ce70..c9971a2 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.h
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h
@@ -136,31 +136,31 @@
return fChildProcessors[index];
}
- // Emit the child with the default input color (solid white)
- inline void emitChild(int childIndex, SkString* outputColor, EmitArgs& parentArgs) {
- this->emitChild(childIndex, nullptr, outputColor, parentArgs);
+ // Invoke the child with the default input color (solid white)
+ inline void invokeChild(int childIndex, SkString* outputColor, EmitArgs& parentArgs) {
+ this->invokeChild(childIndex, nullptr, outputColor, parentArgs);
}
- /** Will emit the code of a child proc in its own scope. Pass in the parent's EmitArgs and
- * emitChild will automatically extract the coords and samplers of that child and pass them
- * on to the child's emitCode(). Also, any uniforms or functions emitted by the child will
- * have their names mangled to prevent redefinitions. The output color name is also mangled
- * therefore in an in/out param. It will be declared in mangled form by emitChild(). It is
- * legal to pass nullptr as inputColor, since all fragment processors are required to work
- * without an input color.
+ /** Invokes a child proc in its own scope. Pass in the parent's EmitArgs and invokeChild will
+ * automatically extract the coords and samplers of that child and pass them on to the child's
+ * emitCode(). Also, any uniforms or functions emitted by the child will have their names
+ * mangled to prevent redefinitions. The output color name is also mangled therefore in an
+ * in/out param. It will be declared in mangled form by invokeChild(). It is legal to pass
+ * nullptr as inputColor, since all fragment processors are required to work without an input
+ * color.
*/
- void emitChild(int childIndex, const char* inputColor, SkString* outputColor,
- EmitArgs& parentArgs);
+ void invokeChild(int childIndex, const char* inputColor, SkString* outputColor,
+ EmitArgs& parentArgs);
// Use the parent's output color to hold child's output, and use the
// default input color of solid white
- inline void emitChild(int childIndex, EmitArgs& args) {
+ inline void invokeChild(int childIndex, EmitArgs& args) {
// null pointer cast required to disambiguate the function call
- this->emitChild(childIndex, (const char*) nullptr, args);
+ this->invokeChild(childIndex, (const char*) nullptr, args);
}
/** Variation that uses the parent's output color variable to hold the child's output.*/
- void emitChild(int childIndex, const char* inputColor, EmitArgs& parentArgs);
+ void invokeChild(int childIndex, const char* inputColor, EmitArgs& parentArgs);
/**
* Pre-order traversal of a GLSLFP hierarchy, or of multiple trees with roots in an array of
@@ -189,7 +189,10 @@
virtual void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) {}
private:
- void internalEmitChild(int, const char*, const char*, EmitArgs&);
+ void internalInvokeChild(int, const char*, const char*, EmitArgs&);
+
+ // one per child; either not present or empty string if not yet emitted
+ SkTArray<SkString> fFunctionNames;
SkTArray<GrGLSLFragmentProcessor*, true> fChildProcessors;
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index 2b6894a..986ad37 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -156,6 +156,26 @@
this->codeAppendf("}");
}
+SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor* fp,
+ GrGLSLFragmentProcessor::EmitArgs& args) {
+ this->onBeforeChildProcEmitCode();
+ this->nextStage();
+ this->codeAppendf("half4 %s;\n", args.fOutputColor);
+ fp->emitCode(args);
+ this->codeAppendf("return %s;", args.fOutputColor);
+ GrShaderVar inColor(args.fInputColor, kHalf4_GrSLType);
+ SkString result;
+ this->emitFunction(kHalf4_GrSLType,
+ "stage",
+ 1,
+ &inColor,
+ this->code().c_str(),
+ &result);
+ this->deleteStage();
+ this->onAfterChildProcEmitCode();
+ return result;
+}
+
const char* GrGLSLFragmentShaderBuilder::dstColor() {
SkDEBUGCODE(fHasReadDstColorThisStage_DebugOnly = true;)
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
index 050029c..e454fc8 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -10,6 +10,7 @@
#include "include/gpu/GrBlend.h"
#include "src/gpu/GrProcessor.h"
+#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLShaderBuilder.h"
class GrRenderTarget;
@@ -97,6 +98,9 @@
virtual void onBeforeChildProcEmitCode() = 0;
virtual void onAfterChildProcEmitCode() = 0;
+ virtual SkString writeProcessorFunction(GrGLSLFragmentProcessor* fp,
+ GrGLSLFragmentProcessor::EmitArgs& args);
+
virtual const SkString& getMangleString() const = 0;
virtual void forceHighPrecision() = 0;
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h
index 0086e85..959d24a 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -198,6 +198,11 @@
fCodeIndex++;
}
+ void deleteStage() {
+ fShaderStrings.pop_back();
+ fCodeIndex--;
+ }
+
SkString& extensions() { return fShaderStrings[kExtensions]; }
SkString& definitions() { return fShaderStrings[kDefinitions]; }
SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }