Add 'isBlendFunction' as a FP flag and 'destColor' to EmitArgs.
Blend functions are fragment processors that take two arguments, a source color and dest color. Change-Id: Ia26fadae42610fd8849716ad68db867cfa082169 Bug: skia:12257 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/433361 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Brian Osman <brianosman@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
109f54d200
commit
0ce9592410
@ -241,6 +241,11 @@ public:
|
||||
return SkToBool(fFlags & kWillReadDstColor_Flag);
|
||||
}
|
||||
|
||||
/** Does the SkSL for this FP take two colors as its input arguments? */
|
||||
bool isBlendFunction() const {
|
||||
return SkToBool(fFlags & kIsBlendFunction_Flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* True if this FP refers directly to the sample coordinate parameter of its function
|
||||
* (e.g. uses EmitArgs::fSampleCoord in emitCode()). This also returns true if the
|
||||
@ -465,6 +470,12 @@ protected:
|
||||
fFlags |= kWillReadDstColor_Flag;
|
||||
}
|
||||
|
||||
// FP implementations must set this flag if their GrGLSLFragmentProcessor's emitCode() function
|
||||
// emits a blend function (taking two color inputs instead of just one).
|
||||
void setIsBlendFunction() {
|
||||
fFlags |= kIsBlendFunction_Flag;
|
||||
}
|
||||
|
||||
void mergeOptimizationFlags(OptimizationFlags flags) {
|
||||
SkASSERT((flags & ~kAll_OptimizationFlags) == 0);
|
||||
fFlags &= (flags | ~kAll_OptimizationFlags);
|
||||
@ -498,13 +509,14 @@ private:
|
||||
|
||||
// Does not propagate at all
|
||||
kUsesSampleCoordsDirectly_Flag = kFirstPrivateFlag << 1,
|
||||
kIsBlendFunction_Flag = kFirstPrivateFlag << 2,
|
||||
|
||||
// Propagates down the FP to all its leaves
|
||||
kSampledWithExplicitCoords_Flag = kFirstPrivateFlag << 2,
|
||||
kNetTransformHasPerspective_Flag = kFirstPrivateFlag << 3,
|
||||
kSampledWithExplicitCoords_Flag = kFirstPrivateFlag << 3,
|
||||
kNetTransformHasPerspective_Flag = kFirstPrivateFlag << 4,
|
||||
|
||||
// Propagates up the FP tree to the root
|
||||
kWillReadDstColor_Flag = kFirstPrivateFlag << 4,
|
||||
kWillReadDstColor_Flag = kFirstPrivateFlag << 5,
|
||||
};
|
||||
void addAndPushFlagToChildren(PrivateFlags flag);
|
||||
|
||||
|
@ -19,22 +19,24 @@ void GrGLSLFragmentProcessor::setData(const GrGLSLProgramDataManager& pdman,
|
||||
|
||||
void GrGLSLFragmentProcessor::emitChildFunction(int childIndex, EmitArgs& args) {
|
||||
SkASSERT(childIndex >= 0);
|
||||
SkASSERT(args.fFp.childProcessor(childIndex));
|
||||
const GrFragmentProcessor* childFP = args.fFp.childProcessor(childIndex);
|
||||
SkASSERT(childFP);
|
||||
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
while (childIndex >= (int) fFunctionNames.size()) {
|
||||
fFunctionNames.emplace_back();
|
||||
}
|
||||
|
||||
// Emit the child's helper function if this is the first time we've seen a call
|
||||
if (fFunctionNames[childIndex].size() == 0) {
|
||||
if (fFunctionNames[childIndex].isEmpty()) {
|
||||
EmitArgs childArgs(fragBuilder,
|
||||
args.fUniformHandler,
|
||||
args.fShaderCaps,
|
||||
*args.fFp.childProcessor(childIndex),
|
||||
"_input",
|
||||
*childFP,
|
||||
childFP->isBlendFunction() ? "_src" : "_input",
|
||||
"_dst",
|
||||
"_coords");
|
||||
fFunctionNames[childIndex] =
|
||||
fragBuilder->writeProcessorFunction(this->childProcessor(childIndex), childArgs);
|
||||
GrGLSLFragmentProcessor* childGLSLFP = this->childProcessor(childIndex);
|
||||
fFunctionNames[childIndex] = fragBuilder->writeProcessorFunction(childGLSLFP, childArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,19 +33,20 @@ public:
|
||||
stages.
|
||||
|
||||
@param fragBuilder Interface used to emit code in the shaders.
|
||||
@param uniformHandler Interface used for accessing information about our uniforms
|
||||
@param caps The capabilities of the GPU which will render this FP
|
||||
@param fp The processor that generated this program stage.
|
||||
@param key The key that was computed by GenKey() from the generating
|
||||
GrProcessor.
|
||||
@param outputColor A predefined half4 in the FS in which the stage should place its
|
||||
output color (or coverage).
|
||||
@param inputColor A half4 that holds the input color to the stage in the FS. This may
|
||||
be nullptr in which case the fInputColor is set to "half4(1.0)"
|
||||
(solid white) so this is guaranteed non-null.
|
||||
@param inputColor A half4 that holds the input color to the stage in the FS (or the
|
||||
source color, for blend processors). nullptr inputs are converted
|
||||
to "half4(1.0)" (solid white) during construction.
|
||||
TODO: Better system for communicating optimization info
|
||||
(e.g. input color is solid white, trans black, known to be opaque,
|
||||
etc.) that allows the processor to communicate back similar known
|
||||
info about its output.
|
||||
@param sampleCoord The name of a local coord reference to a float2 variable.
|
||||
@param destColor A half4 that holds the dest color to the stage. Only meaningful
|
||||
when the "is blend processor" FP flag is set.
|
||||
@param sampleCoord The name of a local coord reference to a float2 variable. Only
|
||||
meaningful when the "references sample coords" FP flag is set.
|
||||
*/
|
||||
struct EmitArgs {
|
||||
EmitArgs(GrGLSLFPFragmentBuilder* fragBuilder,
|
||||
@ -53,18 +54,21 @@ public:
|
||||
const GrShaderCaps* caps,
|
||||
const GrFragmentProcessor& fp,
|
||||
const char* inputColor,
|
||||
const char* destColor,
|
||||
const char* sampleCoord)
|
||||
: fFragBuilder(fragBuilder)
|
||||
, fUniformHandler(uniformHandler)
|
||||
, fShaderCaps(caps)
|
||||
, fFp(fp)
|
||||
, fInputColor(inputColor ? inputColor : "half4(1.0)")
|
||||
, fDestColor(destColor)
|
||||
, fSampleCoord(sampleCoord) {}
|
||||
GrGLSLFPFragmentBuilder* fFragBuilder;
|
||||
GrGLSLUniformHandler* fUniformHandler;
|
||||
const GrShaderCaps* fShaderCaps;
|
||||
const GrFragmentProcessor& fFp;
|
||||
const char* fInputColor;
|
||||
const char* fDestColor;
|
||||
const char* fSampleCoord;
|
||||
};
|
||||
|
||||
|
@ -23,23 +23,26 @@ SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor
|
||||
this->onBeforeChildProcEmitCode();
|
||||
this->nextStage();
|
||||
|
||||
// An FP's function signature is theoretically always main(half4 color, float2 _coords).
|
||||
// However, if it is only sampled by a chain of uniform matrix expressions (or legacy coord
|
||||
// transforms), the value that would have been passed to _coords is lifted to the vertex shader
|
||||
// and stored in a unique varying. In that case it uses that variable and does not have a
|
||||
// second actual argument for _coords.
|
||||
// FIXME: An alternative would be to have all FP functions have a float2 argument, and the
|
||||
// parent FP invokes it with the varying reference when it's been lifted to the vertex shader.
|
||||
size_t paramCount = 2;
|
||||
// Conceptually, an FP is always sampled at a particular coordinate. However, if it is only
|
||||
// sampled by a chain of uniform matrix expressions (or legacy coord transforms), the value that
|
||||
// would have been passed to _coords is lifted to the vertex shader and stored in a unique
|
||||
// varying. In that case it uses that variable and we do not pass a second argument for _coords.
|
||||
GrShaderVar params[] = { GrShaderVar(args.fInputColor, kHalf4_GrSLType),
|
||||
GrShaderVar(args.fSampleCoord, kFloat2_GrSLType) };
|
||||
SkSpan<GrShaderVar> paramSpan = SkMakeSpan(params, SK_ARRAY_COUNT(params));
|
||||
|
||||
if (!args.fFp.isSampledWithExplicitCoords()) {
|
||||
if (args.fFp.isBlendFunction()) {
|
||||
// Blend functions take two colors as input, and never take coordinates.
|
||||
// Replace the sampleCoord parameter with destination color.
|
||||
params[1] = GrShaderVar(args.fDestColor, kHalf4_GrSLType);
|
||||
} else if (args.fFp.isSampledWithExplicitCoords()) {
|
||||
// We are passing explicit coords; the function keeps its two arguments as-is.
|
||||
} else {
|
||||
// Sampled with a uniform matrix expression and/or a legacy coord transform. The actual
|
||||
// transformation code is emitted in the vertex shader, so this only has to access it.
|
||||
// Add a float2 _coords variable that maps to the associated varying and replaces the
|
||||
// absent 2nd argument to the fp's function.
|
||||
paramCount = 1;
|
||||
paramSpan = paramSpan.first(1);
|
||||
|
||||
if (args.fFp.referencesSampleCoords()) {
|
||||
GrShaderVar varying = fProgramBuilder->varyingCoordsForFragmentProcessor(&args.fFp);
|
||||
@ -61,13 +64,12 @@ SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // else the function keeps its two arguments
|
||||
}
|
||||
|
||||
fp->emitCode(args);
|
||||
|
||||
SkString funcName = this->getMangledFunctionName(args.fFp.name());
|
||||
this->emitFunction(kHalf4_GrSLType, funcName.c_str(), {params, paramCount},
|
||||
this->code().c_str());
|
||||
this->emitFunction(kHalf4_GrSLType, funcName.c_str(), paramSpan, this->code().c_str());
|
||||
this->deleteStage();
|
||||
this->onAfterChildProcEmitCode();
|
||||
return funcName;
|
||||
|
@ -185,7 +185,8 @@ SkString GrGLSLProgramBuilder::emitFragProc(const GrFragmentProcessor& fp,
|
||||
this->uniformHandler(),
|
||||
this->shaderCaps(),
|
||||
fp,
|
||||
"_input",
|
||||
fp.isBlendFunction() ? "_src" : "_input",
|
||||
"_dst",
|
||||
"_coords");
|
||||
auto name = fFS.writeProcessorFunction(&glslFP, args);
|
||||
fFS.codeAppendf("%s = %s(%s);", output.c_str(), name.c_str(), input.c_str());
|
||||
|
Loading…
Reference in New Issue
Block a user