Move ProgramImpl definitions into Processor subclass headers.
Move ProgramImpl function definitions into Processor subclass cpp files.
Delete separate h/cpp files.
Modify GrGLSLVaryingHandler::addPassThroughAttribute to break #include
cycle. It now takes a ShaderVar rather than a GP::Attribute, making
it slightly more flexible as the input can be any variable defined
in the vertex shader.
Bug: skia:11358
Change-Id: I94ee8cd44d29e194216592ecae5fd28de785c975
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/438596
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index edc5850..856e011 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -5,15 +5,17 @@
* found in the LICENSE file.
*/
-#include "src/core/SkRuntimeEffectPriv.h"
#include "src/gpu/GrFragmentProcessor.h"
+
+#include "src/core/SkRuntimeEffectPriv.h"
#include "src/gpu/GrPipeline.h"
#include "src/gpu/GrProcessorAnalysis.h"
+#include "src/gpu/GrShaderCaps.h"
#include "src/gpu/effects/GrBlendFragmentProcessor.h"
#include "src/gpu/effects/GrSkSLFP.h"
#include "src/gpu/effects/GrTextureEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
+#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
#include "src/gpu/glsl/GrGLSLUniformHandler.h"
@@ -925,3 +927,132 @@
return HighPrecisionFragmentProcessor::Make(std::move(fp));
}
+
+//////////////////////////////////////////////////////////////////////////////
+
+using ProgramImpl = GrFragmentProcessor::ProgramImpl;
+
+void ProgramImpl::setData(const GrGLSLProgramDataManager& pdman,
+ const GrFragmentProcessor& processor) {
+ this->onSetData(pdman, processor);
+}
+
+void ProgramImpl::emitChildFunctions(EmitArgs& args) {
+ for (int i = 0; i < this->numChildProcessors(); ++i) {
+ ProgramImpl* childGLSLFP = this->childProcessor(i);
+ if (!childGLSLFP) {
+ continue;
+ }
+
+ const GrFragmentProcessor* childFP = args.fFp.childProcessor(i);
+ SkASSERT(childFP);
+
+ EmitArgs childArgs(args.fFragBuilder,
+ args.fUniformHandler,
+ args.fShaderCaps,
+ *childFP,
+ childFP->isBlendFunction() ? "_src" : "_input",
+ "_dst",
+ "_coords");
+ args.fFragBuilder->writeProcessorFunction(childGLSLFP, childArgs);
+ }
+}
+
+SkString ProgramImpl::invokeChild(int childIndex,
+ const char* inputColor,
+ const char* destColor,
+ EmitArgs& args,
+ SkSL::String skslCoords) {
+ SkASSERT(childIndex >= 0);
+
+ if (!inputColor) {
+ inputColor = args.fInputColor;
+ }
+
+ const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
+ if (!childProc) {
+ // If no child processor is provided, return the input color as-is.
+ return SkString(inputColor);
+ }
+
+ auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
+ inputColor);
+
+ if (childProc->isBlendFunction()) {
+ if (!destColor) {
+ destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
+ }
+ invocation.appendf(", %s", destColor);
+ }
+
+ // Assert that the child has no sample matrix. A uniform matrix sample call would go through
+ // invokeChildWithMatrix, not here.
+ SkASSERT(!childProc->sampleUsage().isUniformMatrix());
+
+ if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
+ SkASSERT(!childProc->sampleUsage().isFragCoord() || skslCoords == "sk_FragCoord.xy");
+ // The child's function takes a half4 color and a float2 coordinate
+ invocation.appendf(", %s", skslCoords.empty() ? args.fSampleCoord : skslCoords.c_str());
+ }
+
+ invocation.append(")");
+ return invocation;
+}
+
+SkString ProgramImpl::invokeChildWithMatrix(int childIndex,
+ const char* inputColor,
+ const char* destColor,
+ EmitArgs& args) {
+ SkASSERT(childIndex >= 0);
+
+ if (!inputColor) {
+ inputColor = args.fInputColor;
+ }
+
+ const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
+ if (!childProc) {
+ // If no child processor is provided, return the input color as-is.
+ return SkString(inputColor);
+ }
+
+ SkASSERT(childProc->sampleUsage().isUniformMatrix());
+
+ // Every uniform matrix has the same (initial) name. Resolve that into the mangled name:
+ GrShaderVar uniform = args.fUniformHandler->getUniformMapping(
+ args.fFp, SkString(SkSL::SampleUsage::MatrixUniformName()));
+ SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
+ const SkString& matrixName(uniform.getName());
+
+ auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
+ inputColor);
+
+ if (childProc->isBlendFunction()) {
+ if (!destColor) {
+ destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
+ }
+ invocation.appendf(", %s", destColor);
+ }
+
+ // Produce a string containing the call to the helper function. We have a uniform variable
+ // containing our transform (matrixName). If the parent coords were produced by uniform
+ // transforms, then the entire expression (matrixName * coords) is lifted to a vertex shader
+ // and is stored in a varying. In that case, childProc will not be sampled explicitly, so its
+ // function signature will not take in coords.
+ //
+ // In all other cases, we need to insert sksl to compute matrix * parent coords and then invoke
+ // the function.
+ if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
+ // Only check perspective for this specific matrix transform, not the aggregate FP property.
+ // Any parent perspective will have already been applied when evaluated in the FS.
+ if (childProc->sampleUsage().hasPerspective()) {
+ invocation.appendf(", proj((%s) * %s.xy1)", matrixName.c_str(), args.fSampleCoord);
+ } else if (args.fShaderCaps->nonsquareMatrixSupport()) {
+ invocation.appendf(", float3x2(%s) * %s.xy1", matrixName.c_str(), args.fSampleCoord);
+ } else {
+ invocation.appendf(", ((%s) * %s.xy1).xy", matrixName.c_str(), args.fSampleCoord);
+ }
+ }
+
+ invocation.append(")");
+ return invocation;
+}