Add GrFragmentProcessor::Compose for composing two processors.

This is functionally equivalent to RunInSeries, but the implementation
can be simpler, because it doesn't support an arbitrary number of
processors.

In practice, Ganesh no longer calls RunInSeries with more than two
inputs at once, so all existing calls to RunInSeries have been replaced
with Compose.

Change-Id: I719d0a11ed747775af4e99fb9de33323d43e7874
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/305400
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2020-07-22 19:07:15 -04:00 committed by Skia Commit-Bot
parent b25e0650dd
commit 024d745fcc
6 changed files with 110 additions and 27 deletions

View File

@ -698,12 +698,8 @@ public:
} }
// Runtime effect scripts are written to take an input color, not a fragment processor. // Runtime effect scripts are written to take an input color, not a fragment processor.
// We need to evaluate the input and pass it to the runtime filter via RunInSeries. // We need to pass the input to the runtime filter using Compose.
std::unique_ptr<GrFragmentProcessor> fp[] = { return GrFPSuccess(GrFragmentProcessor::Compose(std::move(inputFP), std::move(runtimeFP)));
std::move(inputFP),
std::move(runtimeFP),
};
return GrFPSuccess(GrFragmentProcessor::RunInSeries(fp, SK_ARRAY_COUNT(fp)));
} }
#endif #endif

View File

@ -121,12 +121,8 @@ public:
if (fCoverageFP == nullptr) { if (fCoverageFP == nullptr) {
fCoverageFP = std::move(fp); fCoverageFP = std::move(fp);
} else { } else {
// Run this coverage FP in series with the previously-added coverage. // Compose this coverage FP with the previously-added coverage.
std::unique_ptr<GrFragmentProcessor> series[] = { fCoverageFP = GrFragmentProcessor::Compose(std::move(fCoverageFP), std::move(fp));
std::move(fCoverageFP),
std::move(fp),
};
fCoverageFP = GrFragmentProcessor::RunInSeries(series, SK_ARRAY_COUNT(series));
} }
} }

View File

@ -376,6 +376,8 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(
return GrOverrideInputFragmentProcessor::Make(std::move(fp), color, useUniform); return GrOverrideInputFragmentProcessor::Make(std::move(fp), color, useUniform);
} }
//////////////////////////////////////////////////////////////////////////////
std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::RunInSeries( std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::RunInSeries(
std::unique_ptr<GrFragmentProcessor> series[], int cnt) { std::unique_ptr<GrFragmentProcessor> series[], int cnt) {
class SeriesFragmentProcessor : public GrFragmentProcessor { class SeriesFragmentProcessor : public GrFragmentProcessor {
@ -479,6 +481,99 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::RunInSeries(
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Compose(
std::unique_ptr<GrFragmentProcessor> f, std::unique_ptr<GrFragmentProcessor> g) {
class ComposeProcessor : public GrFragmentProcessor {
public:
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> f,
std::unique_ptr<GrFragmentProcessor> g) {
return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(std::move(f),
std::move(g)));
}
const char* name() const override { return "Compose"; }
std::unique_ptr<GrFragmentProcessor> clone() const override {
return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(*this));
}
private:
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
class GLFP : public GrGLSLFragmentProcessor {
public:
void emitCode(EmitArgs& args) override {
SkString result = this->invokeChild(0, args);
result = this->invokeChild(1, result.c_str(), args);
args.fFragBuilder->codeAppendf("%s = %s;", args.fOutputColor, result.c_str());
}
};
return new GLFP;
}
ComposeProcessor(std::unique_ptr<GrFragmentProcessor> f,
std::unique_ptr<GrFragmentProcessor> g)
: INHERITED(kSeriesFragmentProcessor_ClassID,
f->optimizationFlags() & g->optimizationFlags()) {
this->registerChild(std::move(f));
this->registerChild(std::move(g));
}
ComposeProcessor(const ComposeProcessor& that)
: INHERITED(kSeriesFragmentProcessor_ClassID, that.optimizationFlags()) {
this->cloneAndRegisterAllChildProcessors(that);
}
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
SkPMColor4f color = inColor;
color = ConstantOutputForConstantInput(this->childProcessor(0), color);
color = ConstantOutputForConstantInput(this->childProcessor(1), color);
return color;
}
typedef GrFragmentProcessor INHERITED;
};
// Allow either of the composed functions to be null.
if (f == nullptr) {
return g;
}
if (g == nullptr) {
return f;
}
// Run an optimization pass on this composition.
GrProcessorAnalysisColor inputColor;
inputColor.setToUnknown();
std::unique_ptr<GrFragmentProcessor> series[2] = {std::move(f), std::move(g)};
GrColorFragmentProcessorAnalysis info(inputColor, series, SK_ARRAY_COUNT(series));
SkPMColor4f knownColor;
int leadingFPsToEliminate = info.initialProcessorsToEliminate(&knownColor);
switch (leadingFPsToEliminate) {
default:
// We shouldn't eliminate more than we started with.
SkASSERT(leadingFPsToEliminate <= 2);
[[fallthrough]];
case 0:
// Compose the two processors as requested.
return ComposeProcessor::Make(std::move(series[0]), std::move(series[1]));
case 1:
// Replace the first processor with a constant color.
return ComposeProcessor::Make(GrConstColorProcessor::Make(knownColor),
std::move(series[1]));
case 2:
// Replace the entire composition with a constant color.
return GrConstColorProcessor::Make(knownColor);
}
}
//////////////////////////////////////////////////////////////////////////////
GrFragmentProcessor::CIter::CIter(const GrPaint& paint) { GrFragmentProcessor::CIter::CIter(const GrPaint& paint) {
if (paint.hasCoverageFragmentProcessor()) { if (paint.hasCoverageFragmentProcessor()) {
fFPStack.push_back(paint.getCoverageFragmentProcessor()); fFPStack.push_back(paint.getCoverageFragmentProcessor());

View File

@ -110,6 +110,14 @@ public:
static std::unique_ptr<GrFragmentProcessor> RunInSeries(std::unique_ptr<GrFragmentProcessor>[], static std::unique_ptr<GrFragmentProcessor> RunInSeries(std::unique_ptr<GrFragmentProcessor>[],
int cnt); int cnt);
/**
* Returns a fragment processor that composes two fragment processors `f` and `g` into f(g(x)).
* This is equivalent to running them in series. This is not the same as transfer-mode
* composition; there is no blending step.
*/
static std::unique_ptr<GrFragmentProcessor> Compose(std::unique_ptr<GrFragmentProcessor> f,
std::unique_ptr<GrFragmentProcessor> g);
/** /**
* Makes a copy of this fragment processor that draws equivalently to the original. * Makes a copy of this fragment processor that draws equivalently to the original.
* If the processor has child processors they are cloned as well. * If the processor has child processors they are cloned as well.

View File

@ -927,18 +927,7 @@ std::unique_ptr<GrFragmentProcessor> GrReducedClip::finishAndDetachAnalyticEleme
} }
} }
// Combine the clip and shader FPs using RunInSeries. (RunInSeries will automatically return the // Compose the clip and shader FPs.
// input as-is if we only have one.) return GrFragmentProcessor::Compose(std::move(clipFP), std::move(shaderFP));
SkSTArray<2, std::unique_ptr<GrFragmentProcessor>> seriesFPs;
if (clipFP != nullptr) {
seriesFPs.push_back(std::move(clipFP));
}
if (shaderFP != nullptr) {
seriesFPs.push_back(std::move(shaderFP));
}
return seriesFPs.empty()
? nullptr
: GrFragmentProcessor::RunInSeries(&seriesFPs.front(), seriesFPs.size());
} }

View File

@ -415,8 +415,7 @@ bool SkPaintToGrPaintWithTexture(GrRecordingContext* context,
if (!shaderFP) { if (!shaderFP) {
return false; return false;
} }
std::unique_ptr<GrFragmentProcessor> fpSeries[] = { std::move(shaderFP), std::move(fp) }; shaderFP = GrFragmentProcessor::Compose(std::move(shaderFP), std::move(fp));
shaderFP = GrFragmentProcessor::RunInSeries(fpSeries, 2);
} else { } else {
shaderFP = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp)); shaderFP = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
} }