Create GrXferProcessor while doing GrProcessorSet analysis.

Bug: skia:
Change-Id: I62a628f9c0536ffb05c8f9d0c9ded5657f93b48e
Reviewed-on: https://skia-review.googlesource.com/11482
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2017-04-07 15:37:58 -04:00 committed by Skia Commit-Bot
parent 44320dda94
commit 0ae0e23696
17 changed files with 239 additions and 335 deletions

View File

@ -20,6 +20,8 @@
void GrPipeline::init(const InitArgs& args) {
SkASSERT(args.fRenderTarget);
SkASSERT(args.fProcessors);
SkASSERT(args.fProcessors->isFinalized());
fRenderTarget.reset(args.fRenderTarget);
@ -48,17 +50,8 @@ void GrPipeline::init(const InitArgs& args) {
fDrawFace = static_cast<int16_t>(args.fDrawFace);
bool isHWAA = kHWAntialias_Flag & args.fFlags;
fXferProcessor.reset(args.fProcessors->xferProcessor());
// Create XferProcessor from DS's XPFactory
{
bool hasMixedSamples =
args.fRenderTarget->isMixedSampled() && (isHWAA || this->isStencilEnabled());
sk_sp<GrXferProcessor> xferProcessor =
GrXPFactory::MakeXferProcessor(args.fProcessors->xpFactory(), args.fXPInputColor,
args.fXPInputCoverage, hasMixedSamples, *args.fCaps);
fXferProcessor.reset(xferProcessor.get());
}
if (args.fDstTexture.texture()) {
fDstTexture.reset(args.fDstTexture.texture());
fDstTextureOffset = args.fDstTexture.offset();

View File

@ -56,9 +56,7 @@ public:
struct InitArgs {
uint32_t fFlags = 0;
GrDrawFace fDrawFace = GrDrawFace::kBoth;
const GrProcessorSet* fProcessors = nullptr;
GrProcessorAnalysisColor fXPInputColor;
GrProcessorAnalysisCoverage fXPInputCoverage = GrProcessorAnalysisCoverage::kNone;
const GrProcessorSet* fProcessors = nullptr; // Must be finalized
const GrUserStencilSettings* fUserStencil = &GrUserStencilSettings::kUnused;
const GrAppliedClip* fAppliedClip = nullptr;
GrRenderTarget* fRenderTarget = nullptr;

View File

@ -63,12 +63,12 @@ public:
const GrProcessorSet& processors() const { return fProcessors; }
void analyzeAndEliminateFragmentProcessors(GrProcessorSet::Analysis* analysis,
const GrProcessorAnalysisColor& colorInput,
const GrProcessorAnalysisCoverage coverageInput,
const GrAppliedClip* clip, const GrCaps& caps) {
fProcessors.analyzeAndEliminateFragmentProcessors(analysis, colorInput, coverageInput, clip,
caps);
GrProcessorSet::Analysis finalizeProcessors(const GrProcessorAnalysisColor& colorInput,
const GrProcessorAnalysisCoverage coverageInput,
const GrAppliedClip* clip, bool isMixedSamples,
const GrCaps& caps, GrColor* overrideColor) {
return fProcessors.finalize(colorInput, coverageInput, clip, isMixedSamples, caps,
overrideColor);
}
/// @}

View File

@ -9,9 +9,9 @@
#include "GrAppliedClip.h"
#include "GrCaps.h"
#include "GrXferProcessor.h"
#include "effects/GrPorterDuffXferProcessor.h"
GrProcessorSet::GrProcessorSet(GrPaint&& paint) {
fXPFactory = paint.fXPFactory;
GrProcessorSet::GrProcessorSet(GrPaint&& paint) : fXP(paint.getXPFactory()) {
fFlags = 0;
if (paint.numColorFragmentProcessors() <= kMaxColorProcessors) {
fColorFragmentProcessorCnt = paint.numColorFragmentProcessors();
@ -40,27 +40,22 @@ GrProcessorSet::GrProcessorSet(GrPaint&& paint) {
GrProcessorSet::~GrProcessorSet() {
for (int i = fFragmentProcessorOffset; i < fFragmentProcessors.count(); ++i) {
if (this->isPendingExecution()) {
if (this->isFinalized()) {
fFragmentProcessors[i]->completedExecution();
} else {
fFragmentProcessors[i]->unref();
}
}
}
void GrProcessorSet::makePendingExecution() {
SkASSERT(!(kPendingExecution_Flag & fFlags));
fFlags |= kPendingExecution_Flag;
for (int i = fFragmentProcessorOffset; i < fFragmentProcessors.count(); ++i) {
fFragmentProcessors[i]->addPendingExecution();
fFragmentProcessors[i]->unref();
if (this->isFinalized() && this->xferProcessor()) {
this->xferProcessor()->completedExecution();
}
}
bool GrProcessorSet::operator==(const GrProcessorSet& that) const {
SkASSERT(this->isFinalized());
SkASSERT(that.isFinalized());
int fpCount = this->numFragmentProcessors();
if (((fFlags ^ that.fFlags) & ~kPendingExecution_Flag) ||
fpCount != that.numFragmentProcessors() ||
if (((fFlags ^ that.fFlags) & ~kFinalized_Flag) || fpCount != that.numFragmentProcessors() ||
fColorFragmentProcessorCnt != that.fColorFragmentProcessorCnt) {
return false;
}
@ -72,34 +67,43 @@ bool GrProcessorSet::operator==(const GrProcessorSet& that) const {
return false;
}
}
if (fXPFactory != that.fXPFactory) {
return false;
// Most of the time both of these are null
if (!this->xferProcessor() && !that.xferProcessor()) {
return true;
}
return true;
const GrXferProcessor& thisXP = this->xferProcessor()
? *this->xferProcessor()
: GrPorterDuffXPFactory::SimpleSrcOverXP();
const GrXferProcessor& thatXP = that.xferProcessor()
? *that.xferProcessor()
: GrPorterDuffXPFactory::SimpleSrcOverXP();
return thisXP.isEqual(thatXP);
}
//////////////////////////////////////////////////////////////////////////////
GrProcessorSet::Analysis GrProcessorSet::finalize(const GrProcessorAnalysisColor& colorInput,
const GrProcessorAnalysisCoverage coverageInput,
const GrAppliedClip* clip, bool isMixedSamples,
const GrCaps& caps, GrColor* overrideInputColor) {
SkASSERT(!this->isFinalized());
SkASSERT(!fFragmentProcessorOffset);
void GrProcessorSet::Analysis::internalInit(const GrProcessorAnalysisColor& colorInput,
const GrProcessorAnalysisCoverage coverageInput,
const GrProcessorSet& processors,
const GrFragmentProcessor* clipFP,
const GrCaps& caps) {
GrColorFragmentProcessorAnalysis colorInfo(colorInput);
fCompatibleWithCoverageAsAlpha = GrProcessorAnalysisCoverage::kLCD != coverageInput;
fValidInputColor = colorInput.isConstant(&fInputColor);
GrProcessorSet::Analysis analysis;
const GrFragmentProcessor* const* fps =
processors.fFragmentProcessors.get() + processors.fFragmentProcessorOffset;
colorInfo.analyzeProcessors(fps, processors.fColorFragmentProcessorCnt);
fCompatibleWithCoverageAsAlpha &= colorInfo.allProcessorsCompatibleWithCoverageAsAlpha();
fps += processors.fColorFragmentProcessorCnt;
int n = processors.numCoverageFragmentProcessors();
const GrFragmentProcessor* clipFP = clip ? clip->clipCoverageFragmentProcessor() : nullptr;
GrColorFragmentProcessorAnalysis colorAnalysis(colorInput);
analysis.fCompatibleWithCoverageAsAlpha = GrProcessorAnalysisCoverage::kLCD != coverageInput;
const GrFragmentProcessor* const* fps = fFragmentProcessors.get() + fFragmentProcessorOffset;
colorAnalysis.analyzeProcessors(fps, fColorFragmentProcessorCnt);
analysis.fCompatibleWithCoverageAsAlpha &=
colorAnalysis.allProcessorsCompatibleWithCoverageAsAlpha();
fps += fColorFragmentProcessorCnt;
int n = this->numCoverageFragmentProcessors();
bool hasCoverageFP = n > 0;
bool coverageUsesLocalCoords = false;
for (int i = 0; i < n; ++i) {
if (!fps[i]->compatibleWithCoverageAsAlpha()) {
fCompatibleWithCoverageAsAlpha = false;
analysis.fCompatibleWithCoverageAsAlpha = false;
// Other than tests that exercise atypical behavior we expect all coverage FPs to be
// compatible with the coverage-as-alpha optimization.
GrCapsDebugf(&caps, "Coverage FP is not compatible with coverage as alpha.\n");
@ -108,21 +112,14 @@ void GrProcessorSet::Analysis::internalInit(const GrProcessorAnalysisColor& colo
}
if (clipFP) {
fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
coverageUsesLocalCoords |= clipFP->usesLocalCoords();
hasCoverageFP = true;
}
fInitialColorProcessorsToEliminate = colorInfo.initialProcessorsToEliminate(&fInputColor);
fValidInputColor |= SkToBool(fInitialColorProcessorsToEliminate);
GrProcessorAnalysisColor outputColor = colorInfo.outputColor();
if (outputColor.isConstant(&fKnownOutputColor)) {
fOutputColorType = static_cast<unsigned>(ColorType::kConstant);
} else if (outputColor.isOpaque()) {
fOutputColorType = static_cast<unsigned>(ColorType::kOpaque);
} else {
fOutputColorType = static_cast<unsigned>(ColorType::kUnknown);
}
int colorFPsToEliminate = colorAnalysis.initialProcessorsToEliminate(overrideInputColor);
analysis.fInputColorType = static_cast<Analysis::PackedInputColorType>(
colorFPsToEliminate ? Analysis::kOverridden_InputColorType
: Analysis::kOriginal_InputColorType);
GrProcessorAnalysisCoverage outputCoverage;
if (GrProcessorAnalysisCoverage::kLCD == coverageInput) {
@ -132,82 +129,51 @@ void GrProcessorSet::Analysis::internalInit(const GrProcessorAnalysisColor& colo
} else {
outputCoverage = GrProcessorAnalysisCoverage::kNone;
}
fOutputCoverageType = static_cast<unsigned>(outputCoverage);
GrXPFactory::AnalysisProperties props = GrXPFactory::GetAnalysisProperties(
processors.fXPFactory, colorInfo.outputColor(), outputCoverage, caps);
if (!processors.numCoverageFragmentProcessors() &&
this->xpFactory(), colorAnalysis.outputColor(), outputCoverage, caps);
if (!this->numCoverageFragmentProcessors() &&
GrProcessorAnalysisCoverage::kNone == coverageInput) {
fCanCombineOverlappedStencilAndCover = SkToBool(
analysis.fCanCombineOverlappedStencilAndCover = SkToBool(
props & GrXPFactory::AnalysisProperties::kCanCombineOverlappedStencilAndCover);
} else {
// If we have non-clipping coverage processors we don't try to merge stencil steps as its
// unclear whether it will be correct. We don't expect this to happen in practice.
fCanCombineOverlappedStencilAndCover = false;
analysis.fCanCombineOverlappedStencilAndCover = false;
}
fRequiresDstTexture = SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresDstTexture);
fIgnoresInputColor = SkToBool(props & GrXPFactory::AnalysisProperties::kIgnoresInputColor);
fCompatibleWithCoverageAsAlpha &=
analysis.fRequiresDstTexture =
SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresDstTexture);
analysis.fCompatibleWithCoverageAsAlpha &=
SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithAlphaAsCoverage);
fRequiresBarrierBetweenOverlappingDraws = SkToBool(
analysis.fRequiresBarrierBetweenOverlappingDraws = SkToBool(
props & GrXPFactory::AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws);
if (props & GrXPFactory::AnalysisProperties::kIgnoresInputColor) {
fInitialColorProcessorsToEliminate = processors.numColorFragmentProcessors();
// If the output of the last color stage is known then the kIgnoresInputColor optimization
// may depend upon it being the input to the xp.
if (!outputColor.isConstant(&fInputColor)) {
// Otherwise, the only property the XP factory could have relied upon to compute
// kIgnoresInputColor is opaqueness.
fInputColor = GrColor_WHITE;
}
fValidInputColor = true;
fUsesLocalCoords = coverageUsesLocalCoords;
colorFPsToEliminate = this->numColorFragmentProcessors();
analysis.fInputColorType =
static_cast<Analysis::PackedInputColorType>(Analysis::kIgnored_InputColorType);
analysis.fUsesLocalCoords = coverageUsesLocalCoords;
} else {
fUsesLocalCoords = coverageUsesLocalCoords | colorInfo.usesLocalCoords();
analysis.fUsesLocalCoords = coverageUsesLocalCoords | colorAnalysis.usesLocalCoords();
}
}
void GrProcessorSet::Analysis::init(const GrProcessorAnalysisColor& colorInput,
const GrProcessorAnalysisCoverage coverageInput,
const GrProcessorSet& processors,
const GrAppliedClip* appliedClip,
const GrCaps& caps) {
const GrFragmentProcessor* clipFP =
appliedClip ? appliedClip->clipCoverageFragmentProcessor() : nullptr;
this->internalInit(colorInput, coverageInput, processors, clipFP, caps);
fIsInitializedWithProcessorSet = true;
}
GrProcessorSet::Analysis::Analysis(const GrProcessorAnalysisColor& colorInput,
const GrProcessorAnalysisCoverage coverageInput,
const GrXPFactory* factory,
const GrCaps& caps)
: Analysis() {
GrPaint paint;
paint.setXPFactory(factory);
this->internalInit(colorInput, coverageInput, GrProcessorSet(std::move(paint)), nullptr, caps);
}
void GrProcessorSet::analyzeAndEliminateFragmentProcessors(
Analysis* analysis,
const GrProcessorAnalysisColor& colorInput,
const GrProcessorAnalysisCoverage coverageInput,
const GrAppliedClip* clip,
const GrCaps& caps) {
analysis->init(colorInput, coverageInput, *this, clip, caps);
if (analysis->fInitialColorProcessorsToEliminate > 0) {
for (unsigned i = 0; i < analysis->fInitialColorProcessorsToEliminate; ++i) {
if (this->isPendingExecution()) {
fFragmentProcessors[i + fFragmentProcessorOffset]->completedExecution();
} else {
fFragmentProcessors[i + fFragmentProcessorOffset]->unref();
}
fFragmentProcessors[i + fFragmentProcessorOffset] = nullptr;
}
fFragmentProcessorOffset += analysis->fInitialColorProcessorsToEliminate;
fColorFragmentProcessorCnt -= analysis->fInitialColorProcessorsToEliminate;
SkASSERT(fFragmentProcessorOffset + fColorFragmentProcessorCnt <=
fFragmentProcessors.count());
analysis->fInitialColorProcessorsToEliminate = 0;
for (int i = 0; i < colorFPsToEliminate; ++i) {
fFragmentProcessors[i]->unref();
fFragmentProcessors[i] = nullptr;
}
for (int i = colorFPsToEliminate; i < fFragmentProcessors.count(); ++i) {
fFragmentProcessors[i]->addPendingExecution();
fFragmentProcessors[i]->unref();
}
fFragmentProcessorOffset = colorFPsToEliminate;
fColorFragmentProcessorCnt -= colorFPsToEliminate;
auto xp = GrXPFactory::MakeXferProcessor(this->xpFactory(), colorAnalysis.outputColor(),
outputCoverage, isMixedSamples, caps);
fXP.fProcessor = xp.get();
if (fXP.fProcessor) {
fXP.fProcessor->addPendingExecution();
}
fFlags |= kFinalized_Flag;
analysis.fIsInitialized = true;
return analysis;
}

View File

@ -14,6 +14,7 @@
#include "SkTemplates.h"
class GrAppliedClip;
class GrXferProcessor;
class GrXPFactory;
class GrProcessorSet : private SkNoncopyable {
@ -22,14 +23,6 @@ public:
~GrProcessorSet();
/**
* If an op is recorded with this processor set then this must be called to ensure pending
* reads and writes are propagated to resources referred to by the processors. Otherwise,
* data hazards may occur.
*/
void makePendingExecution();
bool isPendingExecution() const { return SkToBool(kPendingExecution_Flag & fFlags); }
int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; }
int numCoverageFragmentProcessors() const {
return this->numFragmentProcessors() - fColorFragmentProcessorCnt;
@ -46,7 +39,10 @@ public:
return fFragmentProcessors[idx + fColorFragmentProcessorCnt + fFragmentProcessorOffset];
}
const GrXPFactory* xpFactory() const { return fXPFactory; }
const GrXferProcessor* xferProcessor() const {
SkASSERT(this->isFinalized());
return fXP.fProcessor;
}
bool usesDistanceVectorField() const { return SkToBool(fFlags & kUseDistanceVectorField_Flag); }
bool disableOutputConversionToSRGB() const {
@ -54,74 +50,20 @@ public:
}
bool allowSRGBInputs() const { return SkToBool(fFlags & kAllowSRGBInputs_Flag); }
/** Comparisons are only legal on finalized processor sets. */
bool operator==(const GrProcessorSet& that) const;
bool operator!=(const GrProcessorSet& that) const { return !(*this == that); }
/**
* This is used to track analysis of color and coverage values through the processors.
* This is used to report results of processor analysis when a processor set is finalized (see
* below).
*/
class Analysis {
public:
/**
* This constructor allows an op to record its initial color in an Analysis member and then
* then run analysis later when the analysis inputs are available. If the analysis produces
* color fragment processor elimination then the input color is replaced by the expected
* input to the first non-eliminated processor. Otherwise, the original input color is
* preserved. The only reason to use this is to save space on the op by not separately
* storing the initial color.
*/
explicit Analysis(GrColor initialColor) : Analysis() {
fInputColor = initialColor;
fValidInputColor = true;
}
Analysis()
: fIsInitializedWithProcessorSet(false)
, fCompatibleWithCoverageAsAlpha(true)
, fValidInputColor(false)
, fRequiresDstTexture(false)
, fCanCombineOverlappedStencilAndCover(true)
, fIgnoresInputColor(false)
, fRequiresBarrierBetweenOverlappingDraws(false)
, fOutputCoverageType(static_cast<unsigned>(GrProcessorAnalysisCoverage::kNone))
, fOutputColorType(static_cast<unsigned>(ColorType::kUnknown))
, fInitialColorProcessorsToEliminate(0) {}
// This version is used by a unit test that assumes no clip and no fragment processors.
Analysis(const GrProcessorAnalysisColor&, GrProcessorAnalysisCoverage, const GrXPFactory*,
const GrCaps&);
void init(const GrProcessorAnalysisColor&, GrProcessorAnalysisCoverage,
const GrProcessorSet&, const GrAppliedClip*, const GrCaps&);
bool isInitializedWithProcessorSet() const { return fIsInitializedWithProcessorSet; }
/**
* If the return is greater than or equal to zero then 'newInputColor' should be used as the
* input color to the GrPipeline derived from this processor set, replacing the GrDrawOp's
* initial color. If the return is less than zero then newInputColor has not been
* modified and no modification need be made to the pipeline's input color by the op.
*/
int getInputColorOverrideAndColorProcessorEliminationCount(GrColor* newInputColor) const {
if (fValidInputColor) {
*newInputColor = fInputColor;
return fInitialColorProcessorsToEliminate;
}
SkASSERT(!fInitialColorProcessorsToEliminate);
return -1;
}
/**
* Valid if initialProcessorsToEliminate returns true or this analysis was initialized with
* a known color via constructor or init(). If color fragment processors are eliminated then
* this returns the expected input to the first non-eliminated processors. Otherwise it is
* the color passed to the constructor or init().
*/
GrColor inputColor() const {
SkASSERT(fValidInputColor);
return fInputColor;
}
Analysis(const Analysis&) = default;
Analysis() { *reinterpret_cast<uint32_t*>(this) = 0; }
bool isInitialized() const { return fIsInitialized; }
bool usesLocalCoords() const { return fUsesLocalCoords; }
bool requiresDstTexture() const { return fRequiresDstTexture; }
bool canCombineOverlappedStencilAndCover() const {
@ -131,60 +73,54 @@ public:
return fRequiresBarrierBetweenOverlappingDraws;
}
bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
bool isInputColorIgnored() const { return fIgnoresInputColor; }
GrProcessorAnalysisCoverage outputCoverage() const {
return static_cast<GrProcessorAnalysisCoverage>(fOutputCoverageType);
}
GrProcessorAnalysisColor outputColor() const {
switch (this->outputColorType()) {
case ColorType::kConstant:
return fKnownOutputColor;
case ColorType::kOpaque:
return GrProcessorAnalysisColor::Opaque::kYes;
case ColorType::kUnknown:
return GrProcessorAnalysisColor::Opaque::kNo;
}
SkFAIL("Unexpected color type");
return GrProcessorAnalysisColor::Opaque::kNo;
bool inputColorIsIgnored() const { return fInputColorType == kIgnored_InputColorType; }
bool inputColorIsOverridden() const {
return fInputColorType == kOverridden_InputColorType;
}
private:
enum class ColorType : unsigned { kUnknown, kConstant, kOpaque };
enum InputColorType : uint32_t {
kOriginal_InputColorType,
kOverridden_InputColorType,
kIgnored_InputColorType
};
ColorType outputColorType() const { return static_cast<ColorType>(fOutputColorType); }
// MSVS 2015 won't pack different underlying types
using PackedBool = uint32_t;
using PackedInputColorType = uint32_t;
void internalInit(const GrProcessorAnalysisColor&, const GrProcessorAnalysisCoverage,
const GrProcessorSet&, const GrFragmentProcessor* clipFP, const GrCaps&);
// MSVS 2015 won't pack a bool with an unsigned.
using PackedBool = unsigned;
PackedBool fIsInitializedWithProcessorSet : 1;
PackedBool fUsesLocalCoords : 1;
PackedBool fCompatibleWithCoverageAsAlpha : 1;
PackedBool fValidInputColor : 1;
PackedBool fRequiresDstTexture : 1;
PackedBool fCanCombineOverlappedStencilAndCover : 1;
// These could be removed if we created the XP from the XPFactory when doing analysis.
PackedBool fIgnoresInputColor : 1;
PackedBool fRequiresBarrierBetweenOverlappingDraws : 1;
unsigned fOutputCoverageType : 2;
unsigned fOutputColorType : 2;
unsigned fInitialColorProcessorsToEliminate : 32 - 12;
GrColor fInputColor;
// This could be removed if we created the XP from the XPFactory when doing analysis.
GrColor fKnownOutputColor;
PackedBool fIsInitialized : 1;
PackedInputColorType fInputColorType : 2;
friend class GrProcessorSet;
};
GR_STATIC_ASSERT(sizeof(Analysis) == 2 * sizeof(GrColor) + sizeof(uint32_t));
GR_STATIC_ASSERT(sizeof(Analysis) == sizeof(uint32_t));
void analyzeAndEliminateFragmentProcessors(Analysis*,
const GrProcessorAnalysisColor& colorInput,
const GrProcessorAnalysisCoverage coverageInput,
const GrAppliedClip*, const GrCaps&);
/**
* This analyzes the processors given an op's input color and coverage as well as a clip. The
* state of the processor set may change to an equivalent but more optimal set of processors.
* This new state requires that the caller respect the returned 'inputColorOverride'. This is
* indicated by the returned Analysis's inputColorIsOverriden(). 'inputColorOverride' will not
* be written if the analysis does not override the input color.
*
* This must be called before the processor set is used to construct a GrPipeline and may only
* be called once.
*
* This also puts the processors in "pending execution" state and must be called when an op
* that owns a processor set is recorded to ensure pending and writes are propagated to
* resources referred to by the processors. Otherwise, data hazards may occur.
*/
Analysis finalize(const GrProcessorAnalysisColor& colorInput,
const GrProcessorAnalysisCoverage coverageInput, const GrAppliedClip*,
bool isMixedSamples, const GrCaps&, GrColor* inputColorOverride);
bool isFinalized() const { return SkToBool(kFinalized_Flag & fFlags); }
private:
// This absurdly large limit allows Analysis and this to pack fields together.
@ -194,11 +130,22 @@ private:
kUseDistanceVectorField_Flag = 0x1,
kDisableOutputConversionToSRGB_Flag = 0x2,
kAllowSRGBInputs_Flag = 0x4,
kPendingExecution_Flag = 0x8
kFinalized_Flag = 0x8
};
const GrXPFactory* fXPFactory = nullptr;
union XP {
XP(const GrXPFactory* factory) : fFactory(factory) {}
const GrXPFactory* fFactory;
const GrXferProcessor* fProcessor;
};
const GrXPFactory* xpFactory() const {
SkASSERT(!this->isFinalized());
return fXP.fFactory;
}
SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors;
XP fXP;
uint8_t fColorFragmentProcessorCnt;
uint8_t fFragmentProcessorOffset = 0;
uint8_t fFlags;

View File

@ -1688,30 +1688,33 @@ uint32_t GrRenderTargetContext::addLegacyMeshDrawOp(GrPipelineBuilder&& pipeline
}
GrResourceProvider* resourceProvider = fContext->resourceProvider();
if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) {
bool usesStencil = pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip();
if (usesStencil) {
if (!resourceProvider->attachStencilAttachment(this->accessRenderTarget())) {
SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
return SK_InvalidUniqueID;
}
}
GrProcessorSet::Analysis analysis;
op->analyzeProcessors(&analysis, &pipelineBuilder, &appliedClip, *this->caps());
bool isMixedSamples = fRenderTargetProxy->isMixedSampled() &&
(pipelineBuilder.isHWAntialias() || usesStencil);
GrColor overrideColor;
GrProcessorSet::Analysis analysis = op->analyzeUpdateAndRecordProcessors(
&pipelineBuilder, &appliedClip, isMixedSamples, *this->caps(), &overrideColor);
GrPipeline::InitArgs args;
pipelineBuilder.getPipelineInitArgs(&args);
args.fAppliedClip = &appliedClip;
args.fRenderTarget = rt;
args.fCaps = this->caps();
args.fXPInputColor = analysis.outputColor();
args.fXPInputCoverage = analysis.outputCoverage();
if (analysis.requiresDstTexture()) {
if (!this->setupDstTexture(fRenderTargetProxy.get(), clip, bounds, &args.fDstTexture)) {
return SK_InvalidUniqueID;
}
}
op->initPipeline(args, analysis);
op->initPipeline(args, analysis, overrideColor);
// TODO: We need to add pipeline dependencies on textures, etc before recording this op.
op->setClippedBounds(bounds);
return this->getOpList()->addOp(std::move(op), this);

View File

@ -332,17 +332,19 @@ void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar
}
bool InstancedRendering::Op::xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) {
GrProcessorSet::Analysis analysis;
SkASSERT(State::kRecordingDraws == fInstancedRendering->fState);
GrProcessorAnalysisCoverage coverageInput;
bool isMixedSamples = false;
if (GrAAType::kCoverage == fInfo.aaType() ||
(GrAAType::kNone == fInfo.aaType() && !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) {
coverageInput = GrProcessorAnalysisCoverage::kSingleChannel;
} else {
coverageInput = GrProcessorAnalysisCoverage::kNone;
isMixedSamples = GrAAType::kMixedSamples == fInfo.aaType();
}
fProcessors.analyzeAndEliminateFragmentProcessors(&analysis, this->getSingleInstance().fColor,
coverageInput, clip, caps);
fAnalysisColor = analysis.outputColor();
GrProcessorSet::Analysis analysis =
fProcessors.finalize(this->getSingleInstance().fColor, coverageInput, clip,
isMixedSamples, caps, &this->getSingleDraw().fInstance.fColor);
Draw& draw = this->getSingleDraw(); // This will assert if we have > 1 command.
SkASSERT(draw.fGeometry.isEmpty());
@ -363,11 +365,6 @@ bool InstancedRendering::Op::xpRequiresDstTexture(const GrCaps& caps, const GrAp
fInstancedRendering->fParams.push_back_n(fParams.count(), fParams.begin());
}
GrColor overrideColor;
if (analysis.getInputColorOverrideAndColorProcessorEliminationCount(&overrideColor) >= 0) {
SkASSERT(State::kRecordingDraws == fInstancedRendering->fState);
this->getSingleDraw().fInstance.fColor = overrideColor;
}
fInfo.fCannotTweakAlphaForCoverage = !analysis.isCompatibleWithCoverageAsAlpha();
fInfo.fUsesLocalCoords = analysis.usesLocalCoords();
@ -378,7 +375,6 @@ bool InstancedRendering::Op::xpRequiresDstTexture(const GrCaps& caps, const GrAp
void InstancedRendering::Op::wasRecorded() {
SkASSERT(!fIsTracked);
fInstancedRendering->fTrackedOps.addToTail(this);
fProcessors.makePendingExecution();
fIsTracked = true;
}
@ -413,7 +409,6 @@ bool InstancedRendering::Op::onCombineIfPossible(GrOp* other, const GrCaps& caps
this->joinBounds(*that);
fInfo = combinedInfo;
fPixelLoad += that->fPixelLoad;
fAnalysisColor = GrProcessorAnalysisColor::Combine(fAnalysisColor, that->fAnalysisColor);
// Adopt the other op's draws.
fNumDraws += that->fNumDraws;
fNumChangesInGeometry += that->fNumChangesInGeometry;
@ -470,21 +465,9 @@ void InstancedRendering::Op::onExecute(GrOpFlushState* state) {
state->gpu()->handleDirtyContext();
const GrAppliedClip* clip = state->drawOpArgs().fAppliedClip;
GrProcessorAnalysisCoverage coverage;
if (GrAAType::kCoverage == fInfo.aaType() ||
(clip && clip->clipCoverageFragmentProcessor()) ||
(GrAAType::kNone == fInfo.aaType() && !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) {
coverage = GrProcessorAnalysisCoverage::kSingleChannel;
} else {
coverage = GrProcessorAnalysisCoverage::kNone;
}
GrPipeline pipeline;
GrPipeline::InitArgs args;
args.fXPInputColor = fAnalysisColor;
args.fXPInputCoverage = coverage;
args.fAppliedClip = clip;
args.fAppliedClip = state->drawOpArgs().fAppliedClip;
args.fCaps = &state->caps();
args.fProcessors = &fProcessors;
args.fFlags = GrAATypeIsHW(fInfo.aaType()) ? GrPipeline::kHWAntialias_Flag : 0;

View File

@ -151,7 +151,6 @@ protected:
OpInfo fInfo;
SkScalar fPixelLoad;
GrProcessorSet fProcessors;
GrProcessorAnalysisColor fAnalysisColor;
SkSTArray<5, ParamsTexel, true> fParams;
bool fIsTracked : 1;
bool fRequiresBarrierOnOverlap : 1;

View File

@ -76,7 +76,8 @@ public:
* This is called after the GrAppliedClip has been computed and just prior to recording the op
* or combining it with a previously recorded op. It is used to determine whether a copy of the
* destination (or destination texture itself) needs to be provided to the xp when this op
* executes.
* executes. This is guaranteed to be called before an op is recorded. However, this is also
* called on ops that are not recorded because they combine with a previously recorded op.
*/
virtual bool xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*) = 0;

View File

@ -12,13 +12,15 @@
#include "SkTemplates.h"
GrDrawPathOpBase::GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint,
GrPathRendering::FillType fill, GrAA aa)
GrPathRendering::FillType fill, GrAAType aaType)
: INHERITED(classID)
, fViewMatrix(viewMatrix)
, fInputColor(paint.getColor())
, fProcessorSet(std::move(paint))
, fAnalysis(paint.getColor())
, fFillType(fill)
, fAA(aa) {}
, fAAType(aaType) {
SkASSERT(fAAType != GrAAType::kCoverage);
}
SkString GrDrawPathOp::dumpInfo() const {
SkString string;
@ -38,16 +40,13 @@ void GrDrawPathOpBase::initPipeline(const GrOpFlushState& state, GrPipeline* pip
0xffff>()
};
GrPipeline::InitArgs args;
auto analysis = this->processorAnalysis();
args.fProcessors = &this->processors();
args.fFlags = GrAA::kYes == fAA ? GrPipeline::kHWAntialias_Flag : 0;
args.fFlags = GrAATypeIsHW(fAAType) ? GrPipeline::kHWAntialias_Flag : 0;
args.fUserStencil = &kCoverPass;
args.fAppliedClip = state.drawOpArgs().fAppliedClip;
args.fRenderTarget = state.drawOpArgs().fRenderTarget;
args.fCaps = &state.caps();
args.fDstTexture = state.drawOpArgs().fDstTexture;
args.fXPInputColor = analysis.outputColor();
args.fXPInputCoverage = analysis.outputCoverage();
return pipeline->init(args);
}
@ -90,9 +89,9 @@ SkString GrDrawPathRangeOp::dumpInfo() const {
GrDrawPathRangeOp::GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x,
SkScalar y, GrPaint&& paint, GrPathRendering::FillType fill,
GrAA aa, GrPathRange* range, const InstanceData* instanceData,
const SkRect& bounds)
: INHERITED(ClassID(), viewMatrix, std::move(paint), fill, aa)
GrAAType aaType, GrPathRange* range,
const InstanceData* instanceData, const SkRect& bounds)
: INHERITED(ClassID(), viewMatrix, std::move(paint), fill, aaType)
, fPathRange(range)
, fTotalPathCount(instanceData->count())
, fScale(scale) {

View File

@ -23,31 +23,33 @@ class GrPaint;
class GrDrawPathOpBase : public GrDrawOp {
protected:
GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint,
GrPathRendering::FillType fill, GrAA aa);
GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&&,
GrPathRendering::FillType, GrAAType);
FixedFunctionFlags fixedFunctionFlags() const override {
return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil;
if (GrAATypeIsHW(fAAType)) {
return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil;
}
return FixedFunctionFlags::kUsesStencil;
}
bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
return this->doProcessorAnalysis(caps, clip).requiresDstTexture();
}
void wasRecorded() override { fProcessorSet.makePendingExecution(); }
protected:
const SkMatrix& viewMatrix() const { return fViewMatrix; }
GrColor color() const { return fAnalysis.inputColor(); }
GrColor color() const { return fInputColor; }
GrPathRendering::FillType fillType() const { return fFillType; }
const GrProcessorSet& processors() const { return fProcessorSet; }
void initPipeline(const GrOpFlushState&, GrPipeline*);
const GrProcessorSet::Analysis& doProcessorAnalysis(const GrCaps& caps,
const GrAppliedClip* clip) {
fProcessorSet.analyzeAndEliminateFragmentProcessors(
&fAnalysis, fAnalysis.inputColor(), GrProcessorAnalysisCoverage::kNone, clip, caps);
bool isMixedSamples = GrAAType::kMixedSamples == fAAType;
fAnalysis = fProcessorSet.finalize(fInputColor, GrProcessorAnalysisCoverage::kNone, clip,
isMixedSamples, caps, &fInputColor);
return fAnalysis;
}
const GrProcessorSet::Analysis& processorAnalysis() const {
SkASSERT(fAnalysis.isInitializedWithProcessorSet());
SkASSERT(fAnalysis.isInitialized());
return fAnalysis;
}
@ -55,10 +57,11 @@ private:
void onPrepare(GrOpFlushState*) final {}
SkMatrix fViewMatrix;
GrColor fInputColor;
GrProcessorSet fProcessorSet;
GrProcessorSet::Analysis fAnalysis;
GrPathRendering::FillType fFillType;
GrAA fAA;
GrAAType fAAType;
typedef GrDrawOp INHERITED;
};
@ -67,9 +70,10 @@ class GrDrawPathOp final : public GrDrawPathOpBase {
public:
DEFINE_OP_CLASS_ID
static std::unique_ptr<GrDrawOp> Make(const SkMatrix& viewMatrix, GrPaint&& paint, GrAA aa,
GrPath* path) {
return std::unique_ptr<GrDrawOp>(new GrDrawPathOp(viewMatrix, std::move(paint), aa, path));
static std::unique_ptr<GrDrawOp> Make(const SkMatrix& viewMatrix, GrPaint&& paint,
GrAAType aaType, GrPath* path) {
return std::unique_ptr<GrDrawOp>(
new GrDrawPathOp(viewMatrix, std::move(paint), aaType, path));
}
const char* name() const override { return "DrawPath"; }
@ -77,8 +81,8 @@ public:
SkString dumpInfo() const override;
private:
GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAA aa, const GrPath* path)
: GrDrawPathOpBase(ClassID(), viewMatrix, std::move(paint), path->getFillType(), aa)
GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAAType aaType, const GrPath* path)
: GrDrawPathOpBase(ClassID(), viewMatrix, std::move(paint), path->getFillType(), aaType)
, fPath(path) {
this->setTransformedBounds(path->getBounds(), viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
}
@ -160,11 +164,12 @@ public:
static std::unique_ptr<GrDrawOp> Make(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x,
SkScalar y, GrPaint&& paint,
GrPathRendering::FillType fill, GrAA aa,
GrPathRendering::FillType fill, GrAAType aaType,
GrPathRange* range, const InstanceData* instanceData,
const SkRect& bounds) {
return std::unique_ptr<GrDrawOp>(new GrDrawPathRangeOp(
viewMatrix, scale, x, y, std::move(paint), fill, aa, range, instanceData, bounds));
return std::unique_ptr<GrDrawOp>(new GrDrawPathRangeOp(viewMatrix, scale, x, y,
std::move(paint), fill, aaType,
range, instanceData, bounds));
}
const char* name() const override { return "DrawPathRange"; }
@ -173,8 +178,8 @@ public:
private:
GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, SkScalar y,
GrPaint&& paint, GrPathRendering::FillType fill, GrAA aa, GrPathRange* range,
const InstanceData* instanceData, const SkRect& bounds);
GrPaint&& paint, GrPathRendering::FillType fill, GrAAType aaType,
GrPathRange* range, const InstanceData* instanceData, const SkRect& bounds);
TransformType transformType() const { return fDraws.head()->fInstanceData->transformType(); }

View File

@ -101,20 +101,22 @@ public:
* Performs analysis of the fragment processors in GrProcessorSet and GrAppliedClip using the
* initial color and coverage from this op's geometry processor.
*/
void analyzeProcessors(GrProcessorSet::Analysis* analysis,
GrPipelineBuilder* pipelineBuilder,
const GrAppliedClip* appliedClip,
const GrCaps& caps) const {
GrProcessorSet::Analysis analyzeUpdateAndRecordProcessors(GrPipelineBuilder* pipelineBuilder,
const GrAppliedClip* appliedClip,
bool isMixedSamples,
const GrCaps& caps,
GrColor* overrideColor) const {
GrProcessorAnalysisColor inputColor;
GrProcessorAnalysisCoverage inputCoverage;
this->getProcessorAnalysisInputs(&inputColor, &inputCoverage);
pipelineBuilder->analyzeAndEliminateFragmentProcessors(analysis, inputColor, inputCoverage,
appliedClip, caps);
return pipelineBuilder->finalizeProcessors(inputColor, inputCoverage, appliedClip,
isMixedSamples, caps, overrideColor);
}
void initPipeline(const GrPipeline::InitArgs& args, const GrProcessorSet::Analysis& analysis) {
void initPipeline(const GrPipeline::InitArgs& args, const GrProcessorSet::Analysis& analysis,
GrColor overrideColor) {
fPipeline.init(args);
this->applyPipelineOptimizations(PipelineOptimizations(analysis));
this->applyPipelineOptimizations(PipelineOptimizations(analysis, overrideColor));
}
/**
@ -138,11 +140,11 @@ protected:
*/
class PipelineOptimizations {
public:
PipelineOptimizations(const GrProcessorSet::Analysis& analysis) {
PipelineOptimizations(const GrProcessorSet::Analysis& analysis, GrColor overrideColor) {
fFlags = 0;
if (analysis.getInputColorOverrideAndColorProcessorEliminationCount(&fOverrideColor) >=
0) {
if (analysis.inputColorIsOverridden()) {
fFlags |= kUseOverrideColor_Flag;
fOverrideColor = overrideColor;
}
if (analysis.usesLocalCoords()) {
fFlags |= kReadsLocalCoords_Flag;

View File

@ -145,9 +145,8 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
std::move(coverOp));
}
} else {
GrAA aa = GrBoolToAA(GrAATypeIsHW(args.fAAType));
std::unique_ptr<GrDrawOp> op =
GrDrawPathOp::Make(viewMatrix, std::move(args.fPaint), aa, path.get());
GrDrawPathOp::Make(viewMatrix, std::move(args.fPaint), args.fAAType, path.get());
args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
}

View File

@ -570,9 +570,7 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
SkScalar y, const SkIRect& clipBounds,
GrAtlasTextContext* fallbackTextContext,
const SkPaint& originalSkPaint) const {
GrAA runAA = this->isAntiAlias();
SkASSERT(fInstanceData);
SkASSERT(renderTargetContext->isStencilBufferMultisampled() || GrAA::kNo == runAA);
if (fInstanceData->count()) {
static constexpr GrUserStencilSettings kCoverPass(
@ -606,9 +604,18 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
renderTargetContext->height());
// The run's "font" overrides the anti-aliasing of the passed in SkPaint!
GrAAType aaType;
if (this->aa() == GrAA::kYes) {
SkASSERT(renderTargetContext->isStencilBufferMultisampled());
aaType = renderTargetContext->isUnifiedMultisampled() ? GrAAType::kMSAA
: GrAAType::kMixedSamples;
} else {
aaType = GrAAType::kNone;
}
std::unique_ptr<GrDrawOp> op = GrDrawPathRangeOp::Make(
viewMatrix, fTextRatio, fTextInverseRatio * x, fTextInverseRatio * y,
std::move(grPaint), GrPathRendering::kWinding_FillType, runAA, glyphs.get(),
std::move(grPaint), GrPathRendering::kWinding_FillType, aaType, glyphs.get(),
fInstanceData.get(), bounds);
renderTargetContext->addDrawOp(clip, std::move(op));

View File

@ -83,7 +83,7 @@ private:
size_t computeSizeInCache() const;
GrAA isAntiAlias() const { return fFont.isAntiAlias() ? GrAA::kYes : GrAA::kNo; }
GrAA aa() const { return fFont.isAntiAlias() ? GrAA::kYes : GrAA::kNo; }
private:
typedef GrDrawPathRangeOp::InstanceData InstanceData;

View File

@ -91,17 +91,8 @@ public:
virtual ~TestSampleLocationsInterface() {}
};
static void construct_dummy_pipeline(GrRenderTargetContext* dc, GrPipeline* pipeline) {
GrPipelineBuilder dummyBuilder(GrPaint(), GrAAType::kNone);
GrScissorState dummyScissor;
GrWindowRectsState dummyWindows;
GrPipeline::InitArgs args;
dummyBuilder.getPipelineInitArgs(&args);
args.fRenderTarget = dc->accessRenderTarget();
args.fCaps = dc->caps();
args.fDstTexture = GrXferProcessor::DstTexture();
pipeline->init(args);
static sk_sp<GrPipeline> construct_dummy_pipeline(GrRenderTargetContext* dc) {
return sk_sp<GrPipeline>(new GrPipeline(dc->accessRenderTarget(), SkBlendMode::kSrcOver));
}
void assert_equal(skiatest::Reporter* reporter, const SamplePattern& pattern,
@ -146,11 +137,10 @@ void test_sampleLocations(skiatest::Reporter* reporter, TestSampleLocationsInter
for (int i = 0; i < numTestPatterns; ++i) {
testInterface->overrideSamplePattern(kTestPatterns[i]);
for (GrRenderTargetContext* dc : {bottomUps[i].get(), topDowns[i].get()}) {
GrPipeline dummyPipeline;
construct_dummy_pipeline(dc, &dummyPipeline);
sk_sp<GrPipeline> dummyPipeline = construct_dummy_pipeline(dc);
GrRenderTarget* rt = dc->accessRenderTarget();
assert_equal(reporter, kTestPatterns[i],
rt->renderTargetPriv().getMultisampleSpecs(dummyPipeline),
rt->renderTargetPriv().getMultisampleSpecs(*dummyPipeline),
kBottomLeft_GrSurfaceOrigin == rt->origin());
}
}

View File

@ -55,16 +55,30 @@ enum {
kISCModulate_OutputType
};
static GrProcessorSet::Analysis do_analysis(const GrXPFactory* xpf,
const GrProcessorAnalysisColor& colorInput,
GrProcessorAnalysisCoverage coverageInput,
const GrCaps& caps) {
GrPaint paint;
paint.setXPFactory(xpf);
GrProcessorSet procs(std::move(paint));
GrColor overrideColor;
GrProcessorSet::Analysis analysis =
procs.finalize(colorInput, coverageInput, nullptr, false, caps, &overrideColor);
return analysis;
}
class GrPorterDuffTest {
public:
struct XPInfo {
XPInfo(skiatest::Reporter* reporter, SkBlendMode xfermode, const GrCaps& caps,
GrProcessorAnalysisColor inputColor, GrProcessorAnalysisCoverage inputCoverage) {
const GrXPFactory* xpf = GrPorterDuffXPFactory::Get(xfermode);
GrProcessorSet::Analysis analysis(inputColor, inputCoverage, xpf, caps);
GrProcessorSet::Analysis analysis = do_analysis(xpf, inputColor, inputCoverage, caps);
fCompatibleWithCoverageAsAlpha = analysis.isCompatibleWithCoverageAsAlpha();
fCanCombineOverlappedStencilAndCover = analysis.canCombineOverlappedStencilAndCover();
fIgnoresInputColor = analysis.isInputColorIgnored();
fIgnoresInputColor = analysis.inputColorIsIgnored();
sk_sp<GrXferProcessor> xp(
GrXPFactory::MakeXferProcessor(xpf, inputColor, inputCoverage, false, caps));
TEST_ASSERT(!analysis.requiresDstTexture());
@ -1040,8 +1054,6 @@ DEF_GPUTEST(PorterDuffNoDualSourceBlending, reporter, /*factory*/) {
for (int m = 0; m <= (int)SkBlendMode::kLastCoeffMode; m++) {
SkBlendMode xfermode = static_cast<SkBlendMode>(m);
const GrXPFactory* xpf = GrPorterDuffXPFactory::Get(xfermode);
GrProcessorSet::Analysis analysis;
analysis = GrProcessorSet::Analysis(colorInput, coverageType, xpf, caps);
sk_sp<GrXferProcessor> xp(
GrXPFactory::MakeXferProcessor(xpf, colorInput, coverageType, false, caps));
if (!xp) {