GrSkSLFP: Avoid making a global copy of inColor most of the time
We still need *a* copy, to satisfy SkSL that mutates the input color parameter, but it almost never needs to be global, unless there are calls to sample() from a function other than main. With that tweak, we generate much better SkSL/GLSL code from every one of our effects, avoiding the proliferation of global variables. Bug: skia:12140 Change-Id: I5c3bd42df34a095969abcbbc60e69c653a08087a Reviewed-on: https://skia-review.googlesource.com/c/skia/+/424299 Reviewed-by: Ethan Nicholas <ethannicholas@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
e9ab391765
commit
04d79fc594
@ -220,10 +220,11 @@ public:
|
||||
|
||||
private:
|
||||
enum Flags {
|
||||
kUsesSampleCoords_Flag = 0x1,
|
||||
kAllowColorFilter_Flag = 0x2,
|
||||
kAllowShader_Flag = 0x4,
|
||||
kAllowBlender_Flag = 0x8,
|
||||
kUsesSampleCoords_Flag = 0x1,
|
||||
kAllowColorFilter_Flag = 0x2,
|
||||
kAllowShader_Flag = 0x4,
|
||||
kAllowBlender_Flag = 0x8,
|
||||
kSamplesOutsideMain_Flag = 0x10,
|
||||
};
|
||||
|
||||
SkRuntimeEffect(std::unique_ptr<SkSL::Program> baseProgram,
|
||||
@ -243,10 +244,11 @@ private:
|
||||
SkSL::ProgramKind kind);
|
||||
|
||||
uint32_t hash() const { return fHash; }
|
||||
bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); }
|
||||
bool allowShader() const { return (fFlags & kAllowShader_Flag); }
|
||||
bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); }
|
||||
bool allowBlender() const { return (fFlags & kAllowBlender_Flag); }
|
||||
bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); }
|
||||
bool allowShader() const { return (fFlags & kAllowShader_Flag); }
|
||||
bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); }
|
||||
bool allowBlender() const { return (fFlags & kAllowBlender_Flag); }
|
||||
bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); }
|
||||
|
||||
const SkFilterColorProgram* getFilterColorProgram();
|
||||
|
||||
|
@ -206,6 +206,10 @@ SkRuntimeEffect::Result SkRuntimeEffect::Make(std::unique_ptr<SkSL::Program> pro
|
||||
SkASSERT(!SkSL::Analysis::ReferencesFragCoords(*program));
|
||||
}
|
||||
|
||||
if (SkSL::Analysis::CallsSampleOutsideMain(*program)) {
|
||||
flags |= kSamplesOutsideMain_Flag;
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
std::vector<Uniform> uniforms;
|
||||
std::vector<Child> children;
|
||||
|
@ -171,10 +171,18 @@ public:
|
||||
// we call child processors (particularly from helper functions, which can't "see" the
|
||||
// parameter to main). Even from within main, if the code mutates the parameter, calls to
|
||||
// sample should still be passing the original color (by default).
|
||||
GrShaderVar inputColorCopy(args.fFragBuilder->getMangledFunctionName("inColor"),
|
||||
kHalf4_GrSLType);
|
||||
args.fFragBuilder->declareGlobal(inputColorCopy);
|
||||
args.fFragBuilder->codeAppendf("%s = %s;\n", inputColorCopy.c_str(), args.fInputColor);
|
||||
SkString inputColorName;
|
||||
if (fp.fEffect->samplesOutsideMain()) {
|
||||
GrShaderVar inputColorCopy(args.fFragBuilder->getMangledFunctionName("inColor"),
|
||||
kHalf4_GrSLType);
|
||||
args.fFragBuilder->declareGlobal(inputColorCopy);
|
||||
inputColorName = inputColorCopy.getName();
|
||||
args.fFragBuilder->codeAppendf("%s = %s;\n", inputColorName.c_str(), args.fInputColor);
|
||||
} else {
|
||||
inputColorName = args.fFragBuilder->newTmpVarName("inColor");
|
||||
args.fFragBuilder->codeAppendf(
|
||||
"half4 %s = %s;\n", inputColorName.c_str(), args.fInputColor);
|
||||
}
|
||||
|
||||
// Copy the incoming coords to a local variable. Code in main might modify the coords
|
||||
// parameter. fSampleCoord could be a varying, so writes to it would be illegal.
|
||||
@ -198,7 +206,7 @@ public:
|
||||
|
||||
FPCallbacks callbacks(this,
|
||||
args,
|
||||
inputColorCopy.c_str(),
|
||||
inputColorName.c_str(),
|
||||
*program.fContext,
|
||||
fp.uniformData(),
|
||||
fp.uniformFlags());
|
||||
|
@ -151,6 +151,30 @@ public:
|
||||
using INHERITED = ProgramVisitor;
|
||||
};
|
||||
|
||||
// Visitor that searches for calls to sample() from a function other than main()
|
||||
class SampleOutsideMainVisitor : public ProgramVisitor {
|
||||
public:
|
||||
SampleOutsideMainVisitor() {}
|
||||
|
||||
bool visitExpression(const Expression& e) override {
|
||||
if (e.is<FunctionCall>()) {
|
||||
const FunctionDeclaration& f = e.as<FunctionCall>().function();
|
||||
if (f.isBuiltin() && f.name() == "sample") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return INHERITED::visitExpression(e);
|
||||
}
|
||||
|
||||
bool visitProgramElement(const ProgramElement& p) override {
|
||||
return p.is<FunctionDefinition>() &&
|
||||
!p.as<FunctionDefinition>().declaration().isMain() &&
|
||||
INHERITED::visitProgramElement(p);
|
||||
}
|
||||
|
||||
using INHERITED = ProgramVisitor;
|
||||
};
|
||||
|
||||
// Visitor that counts the number of nodes visited
|
||||
class NodeCountVisitor : public ProgramVisitor {
|
||||
public:
|
||||
@ -592,6 +616,11 @@ bool Analysis::ReferencesFragCoords(const Program& program) {
|
||||
return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
|
||||
}
|
||||
|
||||
bool Analysis::CallsSampleOutsideMain(const Program& program) {
|
||||
SampleOutsideMainVisitor visitor;
|
||||
return visitor.visit(program);
|
||||
}
|
||||
|
||||
int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
|
||||
return NodeCountVisitor{limit}.visit(*function.body());
|
||||
}
|
||||
|
@ -50,6 +50,8 @@ struct Analysis {
|
||||
static bool ReferencesSampleCoords(const Program& program);
|
||||
static bool ReferencesFragCoords(const Program& program);
|
||||
|
||||
static bool CallsSampleOutsideMain(const Program& program);
|
||||
|
||||
static int NodeCountUpToLimit(const FunctionDefinition& function, int limit);
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user