Don't ref/unref the static src-over xp
authorbsalomon <bsalomon@google.com>
Mon, 21 Dec 2015 21:12:54 +0000 (13:12 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 21 Dec 2015 21:12:55 +0000 (13:12 -0800)
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1540363002

bug=chromium:570301

Review URL: https://codereview.chromium.org/1540363002

include/gpu/effects/GrPorterDuffXferProcessor.h
src/gpu/GrPipeline.cpp
src/gpu/GrPipeline.h
src/gpu/batches/GrDrawBatch.h
src/gpu/effects/GrPorterDuffXferProcessor.cpp
src/gpu/gl/GrGLGpu.cpp
src/gpu/gl/GrGLProgram.cpp
src/gpu/gl/GrGLProgramDesc.cpp
src/gpu/gl/builders/GrGLProgramBuilder.cpp

index be014a6..457c6ea 100644 (file)
@@ -21,10 +21,16 @@ public:
     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,
index 02edd42..e1c733a 100644 (file)
@@ -28,29 +28,30 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
                                                            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
@@ -167,14 +168,12 @@ void GrPipeline::addDependenciesTo(GrRenderTarget* rt) const {
         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);
     }
 }
 
@@ -185,7 +184,7 @@ void GrPipeline::adjustProgramFromOptimizations(const GrPipelineBuilder& pipelin
                                                 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)) {
@@ -221,8 +220,11 @@ bool GrPipeline::AreEqual(const GrPipeline& a, const GrPipeline& b,
         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++) {
index fbfe119..60d0cab 100644 (file)
@@ -103,7 +103,15 @@ public:
     }
     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());
@@ -136,7 +144,7 @@ public:
     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);
     }
 
     /**
index 9401c67..4d4209a 100644 (file)
@@ -83,7 +83,7 @@ public:
                            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;
     }
 
index 69e77cf..11af4b6 100644 (file)
@@ -850,6 +850,12 @@ void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
 ////////////////////////////////////////////////////////////////////////////////////////////////
 // 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,
@@ -860,12 +866,11 @@ GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
         !(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;
index 32242c5..f5c646c 100644 (file)
@@ -1495,7 +1495,7 @@ void GrGLGpu::flushScissor(const GrScissorState& scissorState,
 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());
index 3cf9e4d..c1f5b37 100644 (file)
@@ -89,7 +89,7 @@ void GrGLProgram::setData(const GrPrimitiveProcessor& primProc,
 
     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);
 }
index e3d292c..81f92eb 100644 (file)
@@ -125,7 +125,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
         }
     }
 
-    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)) {
index dc9393d..97fcce5 100644 (file)
@@ -93,7 +93,7 @@ bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr
     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;
 }