void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor*) const override;
+
+ /** 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 GrPipelineOptimizations& optimizations,
bool hasMixedSamples,
const GrXferProcessor::DstTexture*);
+ /** 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. */
+ static const GrXferProcessor& SimpleSrcOverXP();
static inline void SrcOverInvariantBlendedColor(
GrColor inputColor,
builder.hasMixedSamples(),
&args.fDstTexture,
*args.fCaps));
+ if (!xferProcessor) {
+ return nullptr;
+ }
} else {
+ // This may return nullptr in the common case of src-over implemented using hw blending.
xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
*args.fCaps,
args.fOpts,
builder.hasMixedSamples(),
&args.fDstTexture));
}
-
- if (!xferProcessor) {
- return nullptr;
- }
-
- GrColor overrideColor = GrColor_ILLEGAL;
+ GrColor overrideColor = GrColor_ILLEGAL;
if (args.fOpts.fColorPOI.firstEffectiveProcessorIndex() != 0) {
overrideColor = args.fOpts.fColorPOI.inputColorToFirstEffectiveProccesor();
}
GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
- optFlags = xferProcessor->getOptimizations(args.fOpts,
- builder.getStencil().doesWrite(),
- &overrideColor,
- *args.fCaps);
+ const GrXferProcessor* xpForOpts = xferProcessor ? xferProcessor.get() :
+ &GrPorterDuffXPFactory::SimpleSrcOverXP();
+ optFlags = xpForOpts->getOptimizations(args.fOpts,
+ builder.getStencil().doesWrite(),
+ &overrideColor,
+ *args.fCaps);
// When path rendering the stencil settings are not always set on the GrPipelineBuilder
// so we must check the draw type. In cases where we will skip drawing we simply return a
add_dependencies_for_processor(fFragmentProcessors[i].get(), rt);
}
- if (fXferProcessor.get()) {
- const GrXferProcessor* xfer = fXferProcessor.get();
+ const GrXferProcessor& xfer = this->getXferProcessor();
- for (int i = 0; i < xfer->numTextures(); ++i) {
- GrTexture* texture = xfer->textureAccess(i).getTexture();
- SkASSERT(rt->getLastDrawTarget());
- rt->getLastDrawTarget()->addDependency(texture);
- }
+ for (int i = 0; i < xfer.numTextures(); ++i) {
+ GrTexture* texture = xfer.textureAccess(i).getTexture();
+ SkASSERT(rt->getLastDrawTarget());
+ rt->getLastDrawTarget()->addDependency(texture);
}
}
int* firstColorProcessorIdx,
int* firstCoverageProcessorIdx) {
fIgnoresCoverage = SkToBool(flags & GrXferProcessor::kIgnoreCoverage_OptFlag);
- fReadsFragPosition = fXferProcessor->willReadFragmentPosition();
+ fReadsFragPosition = this->getXferProcessor().willReadFragmentPosition();
if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) ||
(flags & GrXferProcessor::kOverrideColor_OptFlag)) {
return false;
}
- if (!a.getXferProcessor()->isEqual(*b.getXferProcessor())) {
- return false;
+ // Most of the time both are nullptr
+ if (a.fXferProcessor.get() || b.fXferProcessor.get()) {
+ if (!a.getXferProcessor().isEqual(b.getXferProcessor())) {
+ return false;
+ }
}
for (int i = 0; i < a.numFragmentProcessors(); i++) {
}
int numFragmentProcessors() const { return fFragmentProcessors.count(); }
- const GrXferProcessor* getXferProcessor() const { return fXferProcessor.get(); }
+ const GrXferProcessor& getXferProcessor() const {
+ if (fXferProcessor.get()) {
+ return *fXferProcessor.get();
+ } else {
+ // A null xp member means the common src-over case. GrXferProcessor's ref'ing
+ // mechanism is not thread safe so we do not hold a ref on this global.
+ return GrPorterDuffXPFactory::SimpleSrcOverXP();
+ }
+ }
const GrFragmentProcessor& getColorFragmentProcessor(int idx) const {
SkASSERT(idx < this->numColorFragmentProcessors());
bool snapVerticesToPixelCenters() const { return SkToBool(fFlags & kSnapVertices_Flag); }
GrXferBarrierType xferBarrierType(const GrCaps& caps) const {
- return fXferProcessor->xferBarrierType(fRenderTarget.get(), caps);
+ return this->getXferProcessor().xferBarrierType(fRenderTarget.get(), caps);
}
/**
this->pipeline()->getCoverageFragmentProcessor(i).name(),
this->pipeline()->getCoverageFragmentProcessor(i).dumpInfo().c_str());
}
- string.appendf("XP: %s\n", this->pipeline()->getXferProcessor()->name());
+ string.appendf("XP: %s\n", this->pipeline()->getXferProcessor().name());
return string;
}
////////////////////////////////////////////////////////////////////////////////////////////////
// SrcOver Global functions
////////////////////////////////////////////////////////////////////////////////////////////////
+const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
+ static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff,
+ kISA_GrBlendCoeff);
+ static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
+ return gSrcOverXP;
+}
GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
const GrCaps& caps,
!(optimizations.fCoveragePOI.isSolidWhite() &&
!hasMixedSamples &&
optimizations.fColorPOI.isOpaque())) {
- static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff,
- kISA_GrBlendCoeff);
- static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
- SkASSERT(!dstTexture || !dstTexture->texture());
- gSrcOverXP.ref();
- return &gSrcOverXP;
+ // 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
+ // safe.
+ return nullptr;
}
BlendFormula blendFormula;
bool GrGLGpu::flushGLState(const DrawArgs& args) {
GrXferProcessor::BlendInfo blendInfo;
const GrPipeline& pipeline = *args.fPipeline;
- args.fPipeline->getXferProcessor()->getBlendInfo(&blendInfo);
+ args.fPipeline->getXferProcessor().getBlendInfo(&blendInfo);
this->flushColorWrite(blendInfo.fWriteColor);
this->flushDrawFace(pipeline.getDrawFace());
this->setFragmentData(primProc, pipeline, textureBindings);
- const GrXferProcessor& xp = *pipeline.getXferProcessor();
+ const GrXferProcessor& xp = pipeline.getXferProcessor();
fXferProcessor->fGLProc->setData(fProgramDataManager, xp);
append_texture_bindings(fXferProcessor.get(), xp, textureBindings);
}
}
}
- const GrXferProcessor& xp = *pipeline.getXferProcessor();
+ const GrXferProcessor& xp = pipeline.getXferProcessor();
xp.getGLSLProcessorKey(*gpu->glCaps().glslCaps(), &b);
//**** use glslCaps here?
if (!gen_meta_key(xp, gpu->glCaps(), 0, &b)) {
this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor);
this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs,
inputCoverage);
- this->emitAndInstallXferProc(*this->pipeline().getXferProcessor(), *inputColor, *inputCoverage,
+ this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage,
this->pipeline().ignoresCoverage());
return true;
}