GrXPFactory::createXferProcessor now takes GrPipelineAnalysisColor and GrPipelineAnalysisCoverage rather than GrProcessorSet::FragmentProcessorAnalysis.
This will make it so ops do not have to retain the analysis or rerun it to create pipelines at flush time.
Change-Id: Ib28ba65de425b20c2647329275f209aec168c3df
Reviewed-on: https://skia-review.googlesource.com/10474
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
#include "ops/GrOp.h"
void GrPipeline::init(const InitArgs& args) {
- SkASSERT(args.fAnalysis);
+ if (args.fAnalysis) {
+ SkASSERT(args.fAnalysis->outputColor() == args.fInputColor);
+ SkASSERT(args.fAnalysis->outputCoverage() == args.fInputCoverage);
+ }
SkASSERT(args.fRenderTarget);
fRenderTarget.reset(args.fRenderTarget);
sk_sp<GrXferProcessor> xferProcessor;
const GrXPFactory* xpFactory = args.fProcessors->xpFactory();
if (xpFactory) {
- xferProcessor.reset(xpFactory->createXferProcessor(*args.fAnalysis, hasMixedSamples,
+ xferProcessor.reset(xpFactory->createXferProcessor(args.fInputColor,
+ args.fInputCoverage, hasMixedSamples,
&args.fDstTexture, *args.fCaps));
SkASSERT(xferProcessor);
} else {
// This may return nullptr in the common case of src-over implemented using hw blending.
xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
- *args.fCaps, *args.fAnalysis, hasMixedSamples, &args.fDstTexture));
+ *args.fCaps, args.fInputColor, args.fInputCoverage, hasMixedSamples,
+ &args.fDstTexture));
}
fXferProcessor.reset(xferProcessor.get());
}
- // This is for the legacy GrPipeline creation in GrMeshDrawOp where analysis does not
- // eliminate fragment processors from GrProcessorSet.
- GrColor overrideColor = GrColor_ILLEGAL;
- int colorFPsToEliminate =
- args.fAnalysis->getInputColorOverrideAndColorProcessorEliminationCount(&overrideColor);
- colorFPsToEliminate = SkTMax(colorFPsToEliminate, 0);
- if (args.fAnalysis->isInputColorIgnored()) {
- // No need to have an override color if it isn't even going to be used.
- overrideColor = GrColor_ILLEGAL;
- colorFPsToEliminate = args.fProcessors->numColorFragmentProcessors();
+ // This is for the legacy GrPipeline creation in GrMeshDrawOp where analysis does not eliminate
+ // fragment processors from GrProcessorSet.
+ int colorFPsToEliminate = 0;
+ if (args.fAnalysis) {
+ GrColor overrideColor = GrColor_ILLEGAL;
+ colorFPsToEliminate =
+ args.fAnalysis->getInputColorOverrideAndColorProcessorEliminationCount(
+ &overrideColor);
+ colorFPsToEliminate = SkTMax(colorFPsToEliminate, 0);
+ if (args.fAnalysis->isInputColorIgnored()) {
+ // No need to have an override color if it isn't even going to be used.
+ overrideColor = GrColor_ILLEGAL;
+ colorFPsToEliminate = args.fProcessors->numColorFragmentProcessors();
+ }
}
// Copy GrFragmentProcessors from GrPipelineBuilder to Pipeline, possibly removing some of the
uint32_t fFlags = 0;
GrDrawFace fDrawFace = GrDrawFace::kBoth;
const GrProcessorSet* fProcessors = nullptr;
- const GrProcessorSet::FragmentProcessorAnalysis* fAnalysis;
+ GrPipelineAnalysisColor fInputColor;
+ GrPipelineAnalysisCoverage fInputCoverage = GrPipelineAnalysisCoverage::kNone;
+ // This is only used for GrMeshDrawOp's legacy pipeline creation system.
+ const GrProcessorSet::FragmentProcessorAnalysis* fAnalysis = nullptr;
const GrUserStencilSettings* fUserStencil = &GrUserStencilSettings::kUnused;
const GrAppliedClip* fAppliedClip = nullptr;
GrRenderTarget* fRenderTarget = nullptr;
return false;
}
+ bool operator==(const GrPipelineAnalysisColor& that) const {
+ if (fFlags != that.fFlags) {
+ return false;
+ }
+ return (kColorIsKnown_Flag & fFlags) ? fColor == that.fColor : true;
+ }
+
private:
enum Flags {
kColorIsKnown_Flag = 0x1,
GrPipelineAnalysisColor outputColor = colorInfo.outputColor();
if (outputColor.isConstant(&fKnownOutputColor)) {
- fOutputColorType = static_cast<unsigned>(outputColor.isOpaque() ? ColorType::kOpaqueConstant
- : ColorType::kConstant);
+ fOutputColorType = static_cast<unsigned>(ColorType::kConstant);
} else if (outputColor.isOpaque()) {
fOutputColorType = static_cast<unsigned>(ColorType::kOpaque);
} else {
}
bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
bool isInputColorIgnored() const { return fIgnoresInputColor; }
- bool isOutputColorOpaque() const {
- return ColorType::kOpaque == this->outputColorType() ||
- ColorType::kOpaqueConstant == this->outputColorType();
- }
- bool hasKnownOutputColor(GrColor* color = nullptr) const {
- bool constant = ColorType::kConstant == this->outputColorType() ||
- ColorType::kOpaqueConstant == this->outputColorType();
- if (constant && color) {
- *color = fKnownOutputColor;
- }
- return constant;
- }
- GrPipelineAnalysisCoverage outputCoverageType() const {
+ GrPipelineAnalysisCoverage outputCoverage() const {
return static_cast<GrPipelineAnalysisCoverage>(fOutputCoverageType);
}
- bool hasCoverage() const {
- return this->outputCoverageType() != GrPipelineAnalysisCoverage::kNone;
+ GrPipelineAnalysisColor outputColor() const {
+ switch (this->outputColorType()) {
+ case ColorType::kConstant:
+ return fKnownOutputColor;
+ case ColorType::kOpaque:
+ return GrPipelineAnalysisColor::Opaque::kYes;
+ case ColorType::kUnknown:
+ return GrPipelineAnalysisColor::Opaque::kNo;
+ }
+ SkFAIL("Unexpected color type");
+ return GrPipelineAnalysisColor::Opaque::kNo;
}
private:
- enum class ColorType : unsigned { kUnknown, kOpaqueConstant, kConstant, kOpaque };
+ enum class ColorType : unsigned { kUnknown, kConstant, kOpaque };
ColorType outputColorType() const { return static_cast<ColorType>(fOutputColorType); }
args.fRenderTarget = rt;
args.fCaps = this->caps();
args.fAnalysis = &analysis;
+ args.fInputColor = analysis.outputColor();
+ args.fInputCoverage = analysis.outputCoverage();
if (analysis.requiresDstTexture()) {
this->setupDstTexture(rt, clip, bounds, &args.fDstTexture);
return result;
}
-GrXferProcessor* GrXPFactory::createXferProcessor(const FragmentProcessorAnalysis& analysis,
+GrXferProcessor* GrXPFactory::createXferProcessor(const GrPipelineAnalysisColor& color,
+ GrPipelineAnalysisCoverage coverage,
bool hasMixedSamples,
const DstTexture* dstTexture,
const GrCaps& caps) const {
-#ifdef SK_DEBUG
- if (analysis.requiresDstTexture()) {
- if (!caps.shaderCaps()->dstReadInShaderSupport()) {
- SkASSERT(dstTexture && dstTexture->texture());
- } else {
- SkASSERT(!dstTexture || !dstTexture->texture());
- }
- } else {
- SkASSERT(!dstTexture || !dstTexture->texture());
- }
SkASSERT(!hasMixedSamples || caps.shaderCaps()->dualSourceBlendingSupport());
-#endif
- return this->onCreateXferProcessor(caps, analysis, hasMixedSamples, dstTexture);
+ return this->onCreateXferProcessor(caps, color, coverage, hasMixedSamples, dstTexture);
}
typedef GrXferProcessor::DstTexture DstTexture;
- GrXferProcessor* createXferProcessor(const FragmentProcessorAnalysis&,
+ GrXferProcessor* createXferProcessor(const GrPipelineAnalysisColor&,
+ GrPipelineAnalysisCoverage,
bool hasMixedSamples,
const DstTexture*,
const GrCaps& caps) const;
private:
virtual GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
- const FragmentProcessorAnalysis&,
+ const GrPipelineAnalysisColor&,
+ GrPipelineAnalysisCoverage,
bool hasMixedSamples,
const DstTexture*) const = 0;
return nullptr;
}
-GrXferProcessor* GrCoverageSetOpXPFactory::onCreateXferProcessor(
- const GrCaps& caps,
- const FragmentProcessorAnalysis& analysis,
- bool hasMixedSamples,
- const DstTexture* dst) const {
+GrXferProcessor* GrCoverageSetOpXPFactory::onCreateXferProcessor(const GrCaps& caps,
+ const GrPipelineAnalysisColor&,
+ GrPipelineAnalysisCoverage,
+ bool hasMixedSamples,
+ const DstTexture*) const {
// We don't support inverting coverage with mixed samples. We don't expect to ever want this in
// the future, however we could at some point make this work using an inverted coverage
// modulation table. Note that an inverted table still won't work if there are coverage procs.
private:
constexpr GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage);
- GrXferProcessor* onCreateXferProcessor(const GrCaps&,
- const FragmentProcessorAnalysis&,
- bool hasMixedSamples,
+ GrXferProcessor* onCreateXferProcessor(const GrCaps&, const GrPipelineAnalysisColor&,
+ GrPipelineAnalysisCoverage, bool hasMixedSamples,
const DstTexture*) const override;
AnalysisProperties analysisProperties(const GrPipelineAnalysisColor&,
: fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {}
private:
- GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
- const FragmentProcessorAnalysis&,
- bool hasMixedSamples,
+ GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, const GrPipelineAnalysisColor&,
+ GrPipelineAnalysisCoverage, bool hasMixedSamples,
const DstTexture*) const override;
AnalysisProperties analysisProperties(const GrPipelineAnalysisColor&,
#endif
GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
- const FragmentProcessorAnalysis& analysis,
+ const GrPipelineAnalysisColor&,
+ GrPipelineAnalysisCoverage coverage,
bool hasMixedSamples,
const DstTexture* dstTexture) const {
SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
- if (can_use_hw_blend_equation(fHWBlendEquation, analysis.outputCoverageType(), caps)) {
+ if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
SkASSERT(!dstTexture || !dstTexture->texture());
return new CustomXP(fMode, fHWBlendEquation);
}
}
///////////////////////////////////////////////////////////////////////////////
-GrXferProcessor* GrDisableColorXPFactory::onCreateXferProcessor(
- const GrCaps& caps,
- const FragmentProcessorAnalysis& analysis,
- bool hasMixedSamples,
- const DstTexture* dst) const {
+GrXferProcessor* GrDisableColorXPFactory::onCreateXferProcessor(const GrCaps& caps,
+ const GrPipelineAnalysisColor&,
+ GrPipelineAnalysisCoverage,
+ bool hasMixedSamples,
+ const DstTexture* dst) const {
return DisableColorXP::Create();
}
AnalysisProperties::kIgnoresInputColor;
}
- GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
- const FragmentProcessorAnalysis&,
- bool hasMixedSamples,
+ GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, const GrPipelineAnalysisColor&,
+ GrPipelineAnalysisCoverage, bool hasMixedSamples,
const DstTexture* dstTexture) const override;
GR_DECLARE_XP_FACTORY_TEST;
class PDLCDXferProcessor : public GrXferProcessor {
public:
- static GrXferProcessor* Create(SkBlendMode xfermode, const FragmentProcessorAnalysis& analysis);
+ static GrXferProcessor* Create(SkBlendMode xfermode, const GrPipelineAnalysisColor& inputColor);
~PDLCDXferProcessor() override;
}
GrXferProcessor* PDLCDXferProcessor::Create(SkBlendMode xfermode,
- const FragmentProcessorAnalysis& analysis) {
+ const GrPipelineAnalysisColor& color) {
if (SkBlendMode::kSrcOver != xfermode) {
return nullptr;
}
GrColor blendConstant;
- if (!analysis.hasKnownOutputColor(&blendConstant)) {
+ if (!color.isConstant(&blendConstant)) {
return nullptr;
}
blendConstant = GrUnpremulColor(blendConstant);
}
}
-GrXferProcessor* GrPorterDuffXPFactory::onCreateXferProcessor(
- const GrCaps& caps,
- const FragmentProcessorAnalysis& analysis,
- bool hasMixedSamples,
- const DstTexture* dstTexture) const {
+GrXferProcessor* GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
+ const GrPipelineAnalysisColor& color,
+ GrPipelineAnalysisCoverage coverage,
+ bool hasMixedSamples,
+ const DstTexture* dstTexture) const {
BlendFormula blendFormula;
- if (analysis.outputCoverageType() == GrPipelineAnalysisCoverage::kLCD) {
- if (SkBlendMode::kSrcOver == fBlendMode && analysis.hasKnownOutputColor() &&
+ if (coverage == GrPipelineAnalysisCoverage::kLCD) {
+ if (SkBlendMode::kSrcOver == fBlendMode && color.isConstant() &&
!caps.shaderCaps()->dualSourceBlendingSupport() &&
!caps.shaderCaps()->dstReadInShaderSupport()) {
// If we don't have dual source blending or in shader dst reads, we fall back to this
// trick for rendering SrcOver LCD text instead of doing a dst copy.
SkASSERT(!dstTexture || !dstTexture->texture());
- return PDLCDXferProcessor::Create(fBlendMode, analysis);
+ return PDLCDXferProcessor::Create(fBlendMode, color);
}
blendFormula = get_lcd_blend_formula(fBlendMode);
} else {
- blendFormula = get_blend_formula(analysis.isOutputColorOpaque(), analysis.hasCoverage(),
- hasMixedSamples, fBlendMode);
+ blendFormula =
+ get_blend_formula(color.isOpaque(), GrPipelineAnalysisCoverage::kNone != coverage,
+ hasMixedSamples, fBlendMode);
}
if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
const GrCaps& caps,
- const FragmentProcessorAnalysis& analysis,
+ const GrPipelineAnalysisColor& color,
+ GrPipelineAnalysisCoverage coverage,
bool hasMixedSamples,
const GrXferProcessor::DstTexture* dstTexture) {
-
// We want to not make an xfer processor if possible. Thus for the simple case where we are not
// doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from
// the general case where we convert a src-over blend that has solid coverage and an opaque
// color to src-mode, which allows disabling of blending.
- if (analysis.outputCoverageType() != GrPipelineAnalysisCoverage::kLCD) {
+ if (coverage != GrPipelineAnalysisCoverage::kLCD) {
// We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
// We don't simply return the address of that XP here because our caller would have to unref
// it and since it is a global object and GrProgramElement's ref-cnting system is not thread
return nullptr;
}
- if (analysis.hasKnownOutputColor() && !caps.shaderCaps()->dualSourceBlendingSupport() &&
+ if (color.isConstant() && !caps.shaderCaps()->dualSourceBlendingSupport() &&
!caps.shaderCaps()->dstReadInShaderSupport()) {
// If we don't have dual source blending or in shader dst reads, we fall
// back to this trick for rendering SrcOver LCD text instead of doing a
// dst copy.
SkASSERT(!dstTexture || !dstTexture->texture());
- return PDLCDXferProcessor::Create(SkBlendMode::kSrcOver, analysis);
+ return PDLCDXferProcessor::Create(SkBlendMode::kSrcOver, color);
}
BlendFormula blendFormula;
/** Because src-over is so common we special case it for performance reasons. If this returns
null then the SimpleSrcOverXP() below should be used. */
static GrXferProcessor* CreateSrcOverXferProcessor(const GrCaps& caps,
- const FragmentProcessorAnalysis&,
+ const GrPipelineAnalysisColor& color,
+ GrPipelineAnalysisCoverage coverage,
bool hasMixedSamples,
const GrXferProcessor::DstTexture*);
private:
constexpr GrPorterDuffXPFactory(SkBlendMode);
- GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
- const FragmentProcessorAnalysis&,
- bool hasMixedSamples,
+ GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, const GrPipelineAnalysisColor&,
+ GrPipelineAnalysisCoverage, bool hasMixedSamples,
const DstTexture*) const override;
AnalysisProperties analysisProperties(const GrPipelineAnalysisColor&,
state->gpu()->handleDirtyContext();
+ // TODO: Don't reanalyze the processors.
GrProcessorSet::FragmentProcessorAnalysis analysis;
GrPipelineAnalysisCoverage coverageInput;
if (GrAAType::kCoverage == fInfo.aaType() ||
GrPipeline pipeline;
GrPipeline::InitArgs args;
- args.fAnalysis = &analysis;
+ args.fInputColor = analysis.outputColor();
+ args.fInputCoverage = analysis.outputCoverage();
args.fAppliedClip = clip;
args.fCaps = &state->caps();
args.fProcessors = &fProcessors;
0xffff>()
};
GrPipeline::InitArgs args;
+ auto analysis = this->fragmentProcessorAnalysis();
args.fProcessors = &this->processors();
args.fFlags = GrAA::kYes == fAA ? GrPipeline::kHWAntialias_Flag : 0;
args.fUserStencil = &kCoverPass;
args.fRenderTarget = state.drawOpArgs().fRenderTarget;
args.fCaps = &state.caps();
args.fDstTexture = state.drawOpArgs().fDstTexture;
- args.fAnalysis =
- &this->doFragmentProcessorAnalysis(state.caps(), state.drawOpArgs().fAppliedClip);
+ args.fInputColor = analysis.outputColor();
+ args.fInputCoverage = analysis.outputCoverage();
return pipeline->init(args);
}
GrScissorState dummyScissor;
GrWindowRectsState dummyWindows;
- GrProcessorSet::FragmentProcessorAnalysis analysis;
GrPipeline::InitArgs args;
dummyBuilder.getPipelineInitArgs(&args);
args.fRenderTarget = dc->accessRenderTarget();
- args.fAnalysis = &analysis;
args.fCaps = dc->caps();
args.fDstTexture = GrXferProcessor::DstTexture();
pipeline->init(args);
fCompatibleWithCoverageAsAlpha = analysis.isCompatibleWithCoverageAsAlpha();
fCanCombineOverlappedStencilAndCover = analysis.canCombineOverlappedStencilAndCover();
fIgnoresInputColor = analysis.isInputColorIgnored();
- sk_sp<GrXferProcessor> xp(xpf->createXferProcessor(analysis, false, nullptr, caps));
+ sk_sp<GrXferProcessor> xp(
+ xpf->createXferProcessor(inputColor, inputCoverage, false, nullptr, caps));
TEST_ASSERT(!analysis.requiresDstTexture());
GetXPOutputTypes(xp.get(), &fPrimaryOutputType, &fSecondaryOutputType);
xp->getBlendInfo(&fBlendInfo);
}
static void test_lcd_coverage_fallback_case(skiatest::Reporter* reporter, const GrCaps& caps) {
- class TestLCDCoverageOp : public GrMeshDrawOp {
- public:
- DEFINE_OP_CLASS_ID
-
- TestLCDCoverageOp() : INHERITED(ClassID()) {}
-
- const char* name() const override { return "Test LCD Text Op"; }
-
- private:
- void getFragmentProcessorAnalysisInputs(
- GrPipelineAnalysisColor* color,
- GrPipelineAnalysisCoverage* coverage) const override {
- color->setToConstant(GrColorPackRGBA(123, 45, 67, 221));
- *coverage = GrPipelineAnalysisCoverage::kLCD;
- }
-
- void applyPipelineOptimizations(const PipelineOptimizations&) override {}
- bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
- void onPrepareDraws(Target*) const override {}
-
- typedef GrMeshDrawOp INHERITED;
- } testLCDCoverageOp;
-
- GrProcessorSet::FragmentProcessorAnalysis analysis;
- testLCDCoverageOp.analyzeProcessors(&analysis, GrProcessorSet(GrPaint()), nullptr, caps);
-
- SkASSERT(analysis.hasKnownOutputColor());
- SkASSERT(analysis.outputCoverageType() == GrPipelineAnalysisCoverage::kLCD);
-
- TEST_ASSERT(!analysis.requiresDstTexture());
-
const GrXPFactory* xpf = GrPorterDuffXPFactory::Get(SkBlendMode::kSrcOver);
- sk_sp<GrXferProcessor> xp(xpf->createXferProcessor(analysis, false, nullptr, caps));
+ GrPipelineAnalysisColor color = GrColorPackRGBA(123, 45, 67, 221);
+ GrPipelineAnalysisCoverage coverage = GrPipelineAnalysisCoverage::kLCD;
+ SkASSERT(!(GrXPFactory::GetAnalysisProperties(xpf, color, coverage, caps) &
+ GrXPFactory::AnalysisProperties::kRequiresDstTexture));
+ sk_sp<GrXferProcessor> xp(xpf->createXferProcessor(color, coverage, false, nullptr, caps));
if (!xp) {
ERRORF(reporter, "Failed to create an XP with LCD coverage.");
return;
caps);
GrXferProcessor::DstTexture* dstTexture =
analysis.requiresDstTexture() ? &fakeDstTexture : nullptr;
- sk_sp<GrXferProcessor> xp(
- xpf->createXferProcessor(analysis, false, dstTexture, caps));
+ sk_sp<GrXferProcessor> xp(xpf->createXferProcessor(colorInput, coverageType, false,
+ dstTexture, caps));
if (!xp) {
ERRORF(reporter, "Failed to create an XP without dual source blending.");
return;