Move ref counting out of GrProcessor and into subclasses.

This will allow different subclasses to use different models for lifetime management.

GrXferProcessor moves to simple ref counting since they don't own GrGpuResources.

This also constifies GrXferProcessor factories.

Change-Id: I6bea0ea8de718874063224232f9da50887868b16
Reviewed-on: https://skia-review.googlesource.com/11792
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Salomon 2017-04-10 10:54:25 -04:00 committed by Skia Commit-Bot
parent f9aa9e5169
commit d61c9d93b1
18 changed files with 127 additions and 116 deletions

View File

@ -23,7 +23,7 @@ class GrSwizzle;
GrCoordTransforms to receive a transformation of the local coordinates that map from local space
to the fragment being processed.
*/
class GrFragmentProcessor : public GrResourceIOProcessor {
class GrFragmentProcessor : public GrResourceIOProcessor, public GrProgramElement {
public:
/**
* In many instances (e.g. SkShader::asFragmentProcessor() implementations) it is desirable to
@ -300,6 +300,10 @@ protected:
void setWillUseDistanceVectorField() { fFlags |= kUsesDistanceVectorField_Flag; }
private:
void addPendingIOs() const override { GrResourceIOProcessor::addPendingIOs(); }
void removeRefs() const override { GrResourceIOProcessor::removeRefs(); }
void pendingIOComplete() const override { GrResourceIOProcessor::pendingIOComplete(); }
void notifyRefCntIsZero() const final;
virtual GrColor4f constantOutputForConstantInput(GrColor4f /* inputColor */) const {

View File

@ -61,7 +61,7 @@ private:
Dynamically allocated GrProcessors are managed by a per-thread memory pool. The ref count of an
processor must reach 0 before the thread terminates and the pool is destroyed.
*/
class GrProcessor : public GrProgramElement<GrProcessor> {
class GrProcessor {
public:
virtual ~GrProcessor() = default;
@ -123,6 +123,9 @@ protected:
}
private:
GrProcessor(const GrProcessor&) = delete;
GrProcessor& operator=(const GrProcessor&) = delete;
static uint32_t GenClassID() {
// fCurrProcessorClassID has been initialized to kIllegalProcessorClassID. The
// atomic inc returns the old value not the incremented value. So we add
@ -135,11 +138,6 @@ private:
return id;
}
friend class GrProgramElement<GrProcessor>;
virtual void addPendingIOs() const {}
virtual void removeRefs() const {}
virtual void pendingIOComplete() const {}
enum {
kIllegalProcessorClassID = 0,
};
@ -147,8 +145,6 @@ private:
uint32_t fClassID;
RequiredFeatures fRequiredFeatures;
typedef GrProgramElement INHERITED;
};
GR_MAKE_BITFIELD_OPS(GrProcessor::RequiredFeatures);
@ -195,12 +191,12 @@ protected:
bool hasSameSamplersAndAccesses(const GrResourceIOProcessor&) const;
private:
friend class GrProgramElement<GrProcessor>;
void addPendingIOs() const override;
void removeRefs() const override;
void pendingIOComplete() const override;
// These methods can be used by derived classes that also derive from GrProgramElement.
void addPendingIOs() const;
void removeRefs() const;
void pendingIOComplete() const;
private:
SkSTArray<4, const TextureSampler*, true> fTextureSamplers;
SkSTArray<1, const BufferAccess*, true> fBufferAccesses;
SkSTArray<1, const ImageStorageAccess*, true> fImageStorageAccesses;

View File

@ -17,15 +17,10 @@ class GrGpuResourceRef;
* Note: We are converting GrProcessor from ref counting to a single owner model using move
* semantics. This class will be removed.
*
* Base class for GrProcessor. This exists to manage transitioning a GrProcessor from being owned by
* a client to being scheduled for execution. While a GrProcessor is ref'ed by drawing code its
* GrGpu resources must also be ref'ed to prevent incorrectly recycling them through the cache.
* However, once the GrProcessor is baked into a GrPipeline and the drawing code has stopped ref'ing
* it, it's internal resources can be recycled in some cases.
*
* We track this using two types of refs on GrProgramElement. A regular ref is owned by any client
* that may continue to issue draws that use the GrProgramElement. The GrPipeline owns "pending
* executions" instead of refs. A pending execution is cleared by ~GrPipeline().
* This is used to track "refs" for two separate types GrProcessor ownership. A regular ref is owned
* by any client that may continue to issue draws that use the GrProgramElement. A recorded op or
* GrPipeline uses "pending executions" instead of refs. A pending execution is cleared after the
* draw is executed (or aborted).
*
* While a GrProgramElement is ref'ed any resources it owns are also ref'ed. However, once it gets
* into the state where it has pending executions AND no refs then it converts its ownership of
@ -33,13 +28,18 @@ class GrGpuResourceRef;
* safe to recycle a resource even though we still have buffered GrOps that read or write to the
* the resource.
*
* To make this work the subclass, GrProcessor, implements addPendingIOs and pendingIOComplete. The
* former adds pending reads/writes as appropriate when the processor is recorded in a GrOpList. The
* latter removes them after the op list executes the operation. These calls must propagate to any
* children processors. Similarly, the subclass implements a removeRefs function in order to remove
* refs from resources once the processor is only owned for pending execution.
* To make this work the subclass GrProcessor implements addPendingIOs, removeRefs, and
* pendingIOComplete. addPendingIOs adds pending reads/writes to GrGpuResources owned by the
* processor as appropriate when the processor is recorded in a GrOpList. removeRefs is called when
* the ref count reaches 0 and the GrProcessor is only owned by "pending executions".
* pendingIOComplete occurs if the resource is still owned by a ref but all recorded draws have been
* completed. Whenever pending executions and refs reach zero the processor is deleted.
*
* The GrProcessor may also implement notifyRefCntIsZero in order to change its ownership of child
* processors from ref to pending execution when the processor is first owned exclusively in pending
* execution mode.
*/
template<typename DERIVED> class GrProgramElement : public SkNoncopyable {
class GrProgramElement : public SkNoncopyable {
public:
virtual ~GrProgramElement() {
// fRefCnt can be one when an effect is created statically using GR_CREATE_STATIC_EFFECT
@ -65,7 +65,7 @@ public:
delete this;
return;
} else {
static_cast<const DERIVED*>(this)->removeRefs();
this->removeRefs();
}
}
this->validate();
@ -85,7 +85,7 @@ protected:
void addPendingExecution() const {
this->validate();
if (0 == fPendingExecutions) {
static_cast<const DERIVED*>(this)->addPendingIOs();
this->addPendingIOs();
}
++fPendingExecutions;
this->validate();
@ -99,13 +99,17 @@ protected:
delete this;
return;
} else {
static_cast<const DERIVED*>(this)->pendingIOComplete();
this->pendingIOComplete();
}
}
this->validate();
}
private:
virtual void addPendingIOs() const = 0;
virtual void removeRefs() const = 0;
virtual void pendingIOComplete() const = 0;
/** This will be called when the ref cnt is zero. The object may or may not have pending
executions. */
virtual void notifyRefCntIsZero() const = 0;
@ -114,7 +118,7 @@ private:
// Count of deferred executions not yet issued to the 3D API.
mutable int32_t fPendingExecutions;
// Only this class can access addPendingExecution() and completedExecution().
// Only these classes can access addPendingExecution() and completedExecution().
template <typename T> friend class GrPendingProgramElement;
friend class GrProcessorSet;

View File

@ -50,7 +50,7 @@ void GrPipeline::init(const InitArgs& args) {
fDrawFace = static_cast<int16_t>(args.fDrawFace);
fXferProcessor.reset(args.fProcessors->xferProcessor());
fXferProcessor = args.fProcessors->refXferProcessor();
if (args.fDstTexture.texture()) {
fDstTexture.reset(args.fDstTexture.texture());
@ -103,16 +103,15 @@ void GrPipeline::addDependenciesTo(GrRenderTarget* rt) const {
}
GrPipeline::GrPipeline(GrRenderTarget* rt, SkBlendMode blendmode)
: fRenderTarget(rt)
, fScissorState()
, fWindowRectsState()
, fUserStencilSettings(&GrUserStencilSettings::kUnused)
, fDrawFace(static_cast<uint16_t>(GrDrawFace::kBoth))
, fFlags()
, fXferProcessor(GrPorterDuffXPFactory::CreateNoCoverageXP(blendmode).get())
, fFragmentProcessors()
, fNumColorProcessors(0) {
}
: fRenderTarget(rt)
, fScissorState()
, fWindowRectsState()
, fUserStencilSettings(&GrUserStencilSettings::kUnused)
, fDrawFace(static_cast<uint16_t>(GrDrawFace::kBoth))
, fFlags()
, fXferProcessor(GrPorterDuffXPFactory::MakeNoCoverageXP(blendmode))
, fFragmentProcessors()
, fNumColorProcessors(0) {}
////////////////////////////////////////////////////////////////////////////////

View File

@ -131,7 +131,7 @@ public:
int numFragmentProcessors() const { return fFragmentProcessors.count(); }
const GrXferProcessor& getXferProcessor() const {
if (fXferProcessor.get()) {
if (fXferProcessor) {
return *fXferProcessor.get();
} else {
// A null xp member means the common src-over case. GrXferProcessor's ref'ing
@ -228,7 +228,6 @@ private:
using DstTexture = GrPendingIOResource<GrTexture, kRead_GrIOType>;
using PendingFragmentProcessor = GrPendingProgramElement<const GrFragmentProcessor>;
using FragmentProcessorArray = SkAutoSTArray<8, PendingFragmentProcessor>;
using ProgramXferProcessor = GrPendingProgramElement<const GrXferProcessor>;
DstTexture fDstTexture;
SkIPoint fDstTextureOffset;
@ -238,7 +237,7 @@ private:
const GrUserStencilSettings* fUserStencilSettings;
uint16_t fDrawFace;
uint16_t fFlags;
ProgramXferProcessor fXferProcessor;
sk_sp<const GrXferProcessor> fXferProcessor;
FragmentProcessorArray fFragmentProcessors;
// This value is also the index in fFragmentProcessors where coverage processors begin.

View File

@ -38,7 +38,7 @@ class GrGLSLPrimitiveProcessor;
* GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage
* pipelines, and they must provide some notion of equality
*/
class GrPrimitiveProcessor : public GrResourceIOProcessor {
class GrPrimitiveProcessor : public GrResourceIOProcessor, public GrProgramElement {
public:
// Only the GrGeometryProcessor subclass actually has a geo shader or vertex attributes, but
// we put these calls on the base class to prevent having to cast
@ -114,6 +114,9 @@ protected:
size_t fVertexStride;
private:
void addPendingIOs() const override { GrResourceIOProcessor::addPendingIOs(); }
void removeRefs() const override { GrResourceIOProcessor::removeRefs(); }
void pendingIOComplete() const override { GrResourceIOProcessor::pendingIOComplete(); }
void notifyRefCntIsZero() const final {}
virtual bool hasExplicitLocalCoords() const = 0;

View File

@ -47,7 +47,7 @@ GrProcessorSet::~GrProcessorSet() {
}
}
if (this->isFinalized() && this->xferProcessor()) {
this->xferProcessor()->completedExecution();
this->xferProcessor()->unref();
}
}
@ -168,12 +168,9 @@ GrProcessorSet::Analysis GrProcessorSet::finalize(const GrProcessorAnalysisColor
auto xp = GrXPFactory::MakeXferProcessor(this->xpFactory(), colorAnalysis.outputColor(),
outputCoverage, isMixedSamples, caps);
fXP.fProcessor = xp.get();
if (fXP.fProcessor) {
fXP.fProcessor->addPendingExecution();
}
fFlags |= kFinalized_Flag;
fXP.fProcessor = xp.release();
fFlags |= kFinalized_Flag;
analysis.fIsInitialized = true;
return analysis;
}

View File

@ -43,6 +43,10 @@ public:
SkASSERT(this->isFinalized());
return fXP.fProcessor;
}
sk_sp<const GrXferProcessor> refXferProcessor() const {
SkASSERT(this->isFinalized());
return sk_ref_sp(fXP.fProcessor);
}
bool usesDistanceVectorField() const { return SkToBool(fFlags & kUseDistanceVectorField_Flag); }
bool disableOutputConversionToSRGB() const {

View File

@ -167,11 +167,11 @@ GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties(
return result;
}
sk_sp<GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory,
const GrProcessorAnalysisColor& color,
GrProcessorAnalysisCoverage coverage,
bool hasMixedSamples,
const GrCaps& caps) {
sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory,
const GrProcessorAnalysisColor& color,
GrProcessorAnalysisCoverage coverage,
bool hasMixedSamples,
const GrCaps& caps) {
SkASSERT(!hasMixedSamples || caps.shaderCaps()->dualSourceBlendingSupport());
if (factory) {
return factory->makeXferProcessor(color, coverage, hasMixedSamples, caps);

View File

@ -10,6 +10,7 @@
#include "GrBlend.h"
#include "GrColor.h"
#include "GrNonAtomicRef.h"
#include "GrProcessor.h"
#include "GrProcessorSet.h"
#include "GrTexture.h"
@ -46,7 +47,7 @@ GR_STATIC_ASSERT(SkToBool(kNone_GrXferBarrierType) == false);
* A GrXferProcessor is never installed directly into our draw state, but instead is created from a
* GrXPFactory once we have finalized the state of our draw.
*/
class GrXferProcessor : public GrProcessor {
class GrXferProcessor : public GrProcessor, public GrNonAtomicRef<GrXferProcessor> {
public:
/**
* A texture that contains the dst pixel values and an integer coord offset from device space
@ -177,8 +178,6 @@ protected:
GrXferProcessor(bool willReadDstColor, bool hasMixedSamples);
private:
void notifyRefCntIsZero() const final {}
/**
* Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this xfer
* processor's GL backend implementation.
@ -268,11 +267,11 @@ public:
};
GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(AnalysisProperties);
static sk_sp<GrXferProcessor> MakeXferProcessor(const GrXPFactory*,
const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps& caps);
static sk_sp<const GrXferProcessor> MakeXferProcessor(const GrXPFactory*,
const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps& caps);
static AnalysisProperties GetAnalysisProperties(const GrXPFactory*,
const GrProcessorAnalysisColor&,
@ -283,10 +282,10 @@ protected:
constexpr GrXPFactory() {}
private:
virtual sk_sp<GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&) const = 0;
virtual sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&) const = 0;
/**
* Subclass analysis implementation. This should not return kNeedsDstInTexture as that will be

View File

@ -207,10 +207,11 @@ const GrXPFactory* GrCoverageSetOpXPFactory::Get(SkRegion::Op regionOp, bool inv
return nullptr;
}
sk_sp<GrXferProcessor> GrCoverageSetOpXPFactory::makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps& caps) const {
sk_sp<const GrXferProcessor> GrCoverageSetOpXPFactory::makeXferProcessor(
const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps& caps) 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.

View File

@ -30,9 +30,10 @@ public:
private:
constexpr GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage);
sk_sp<GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage, bool hasMixedSamples,
const GrCaps&) const override;
sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&) const override;
AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&,
const GrProcessorAnalysisCoverage&,

View File

@ -213,10 +213,10 @@ public:
: fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {}
private:
sk_sp<GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&) const override;
sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&) const override;
AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&,
const GrProcessorAnalysisCoverage&,
@ -233,10 +233,11 @@ private:
#pragma GCC diagnostic pop
#endif
sk_sp<GrXferProcessor> CustomXPFactory::makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage coverage,
bool hasMixedSamples,
const GrCaps& caps) const {
sk_sp<const GrXferProcessor> CustomXPFactory::makeXferProcessor(
const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage coverage,
bool hasMixedSamples,
const GrCaps& caps) const {
SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
return sk_sp<GrXferProcessor>(new CustomXP(fMode, fHWBlendEquation));

View File

@ -74,11 +74,12 @@ void DisableColorXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const
}
///////////////////////////////////////////////////////////////////////////////
sk_sp<GrXferProcessor> GrDisableColorXPFactory::makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps& caps) const {
return sk_sp<GrXferProcessor>(new DisableColorXP);
sk_sp<const GrXferProcessor> GrDisableColorXPFactory::makeXferProcessor(
const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps& caps) const {
return sk_sp<const GrXferProcessor>(new DisableColorXP);
}
GR_DEFINE_XP_FACTORY_TEST(GrDisableColorXPFactory);

View File

@ -31,10 +31,10 @@ private:
AnalysisProperties::kIgnoresInputColor;
}
sk_sp<GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&) const override;
sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&) const override;
GR_DECLARE_XP_FACTORY_TEST;

View File

@ -518,8 +518,8 @@ GrGLSLXferProcessor* ShaderPDXferProcessor::createGLSLInstance() const {
class PDLCDXferProcessor : public GrXferProcessor {
public:
static sk_sp<GrXferProcessor> Make(SkBlendMode xfermode,
const GrProcessorAnalysisColor& inputColor);
static sk_sp<const GrXferProcessor> Make(SkBlendMode mode,
const GrProcessorAnalysisColor& inputColor);
~PDLCDXferProcessor() override;
@ -600,9 +600,9 @@ PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
this->initClassID<PDLCDXferProcessor>();
}
sk_sp<GrXferProcessor> PDLCDXferProcessor::Make(SkBlendMode xfermode,
const GrProcessorAnalysisColor& color) {
if (SkBlendMode::kSrcOver != xfermode) {
sk_sp<const GrXferProcessor> PDLCDXferProcessor::Make(SkBlendMode mode,
const GrProcessorAnalysisColor& color) {
if (SkBlendMode::kSrcOver != mode) {
return nullptr;
}
GrColor blendConstant;
@ -696,7 +696,7 @@ const GrXPFactory* GrPorterDuffXPFactory::Get(SkBlendMode blendMode) {
}
}
sk_sp<GrXferProcessor> GrPorterDuffXPFactory::makeXferProcessor(
sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::makeXferProcessor(
const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
bool hasMixedSamples, const GrCaps& caps) const {
BlendFormula blendFormula;
@ -716,9 +716,9 @@ sk_sp<GrXferProcessor> GrPorterDuffXPFactory::makeXferProcessor(
}
if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
return sk_sp<GrXferProcessor>(new ShaderPDXferProcessor(hasMixedSamples, fBlendMode));
return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(hasMixedSamples, fBlendMode));
}
return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula));
return sk_sp<const GrXferProcessor>(new PorterDuffXferProcessor(blendFormula));
}
static inline GrXPFactory::AnalysisProperties analysis_properties(
@ -801,7 +801,7 @@ const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
return gSrcOverXP;
}
sk_sp<GrXferProcessor> GrPorterDuffXPFactory::MakeSrcOverXferProcessor(
sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeSrcOverXferProcessor(
const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
bool hasMixedSamples, const GrCaps& caps) {
// We want to not make an xfer processor if possible. Thus for the simple case where we are not
@ -833,7 +833,7 @@ sk_sp<GrXferProcessor> GrPorterDuffXPFactory::MakeSrcOverXferProcessor(
return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula));
}
sk_sp<GrXferProcessor> GrPorterDuffXPFactory::CreateNoCoverageXP(SkBlendMode blendmode) {
sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeNoCoverageXP(SkBlendMode blendmode) {
BlendFormula formula = get_blend_formula(false, false, false, blendmode);
return sk_make_sp<PorterDuffXferProcessor>(formula);
}

View File

@ -23,12 +23,13 @@ public:
/** 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 sk_sp<GrXferProcessor> MakeSrcOverXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples, const GrCaps&);
static sk_sp<const GrXferProcessor> MakeSrcOverXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&);
/** Returns a simple non-LCD porter duff blend XP with no optimizations or coverage. */
static sk_sp<GrXferProcessor> CreateNoCoverageXP(SkBlendMode);
static sk_sp<const GrXferProcessor> MakeNoCoverageXP(SkBlendMode);
/** This XP implements non-LCD src-over using hw blend with no optimizations. It is returned
by reference because it is global and its ref-cnting methods are not thread safe. */
@ -41,10 +42,10 @@ public:
private:
constexpr GrPorterDuffXPFactory(SkBlendMode);
sk_sp<GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&) const override;
sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
GrProcessorAnalysisCoverage,
bool hasMixedSamples,
const GrCaps&) const override;
AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&,
const GrProcessorAnalysisCoverage&,

View File

@ -79,7 +79,7 @@ public:
fCompatibleWithCoverageAsAlpha = analysis.isCompatibleWithCoverageAsAlpha();
fCanCombineOverlappedStencilAndCover = analysis.canCombineOverlappedStencilAndCover();
fIgnoresInputColor = analysis.inputColorIsIgnored();
sk_sp<GrXferProcessor> xp(
sk_sp<const GrXferProcessor> xp(
GrXPFactory::MakeXferProcessor(xpf, inputColor, inputCoverage, false, caps));
TEST_ASSERT(!analysis.requiresDstTexture());
GetXPOutputTypes(xp.get(), &fPrimaryOutputType, &fSecondaryOutputType);
@ -1006,7 +1006,8 @@ static void test_lcd_coverage_fallback_case(skiatest::Reporter* reporter, const
GrProcessorAnalysisCoverage coverage = GrProcessorAnalysisCoverage::kLCD;
SkASSERT(!(GrXPFactory::GetAnalysisProperties(xpf, color, coverage, caps) &
GrXPFactory::AnalysisProperties::kRequiresDstTexture));
sk_sp<GrXferProcessor> xp(GrXPFactory::MakeXferProcessor(xpf, color, coverage, false, caps));
sk_sp<const GrXferProcessor> xp(
GrXPFactory::MakeXferProcessor(xpf, color, coverage, false, caps));
if (!xp) {
ERRORF(reporter, "Failed to create an XP with LCD coverage.");
return;
@ -1054,7 +1055,7 @@ 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);
sk_sp<GrXferProcessor> xp(
sk_sp<const GrXferProcessor> xp(
GrXPFactory::MakeXferProcessor(xpf, colorInput, coverageType, false, caps));
if (!xp) {
ERRORF(reporter, "Failed to create an XP without dual source blending.");