Remove accessRenderTarget calls in service of binding stencil buffer

Change-Id: Ifca6e21c619a0433ecf0b8699d92661f8c3068a8
Reviewed-on: https://skia-review.googlesource.com/31243
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/include/private/GrRenderTargetProxy.h b/include/private/GrRenderTargetProxy.h
index 0bfa294..4794eff 100644
--- a/include/private/GrRenderTargetProxy.h
+++ b/include/private/GrRenderTargetProxy.h
@@ -35,6 +35,12 @@
                                                              : GrFSAAType::kUnifiedMSAA;
     }
 
+    /*
+     * When instantiated does this proxy require a stencil buffer?
+     */
+    void setNeedsStencil() { fNeedsStencil = true; }
+    bool needsStencil() const { return fNeedsStencil; }
+
     /**
      * Returns the number of samples/pixel in the stencil buffer (Zero if non-MSAA).
      */
@@ -74,6 +80,8 @@
     size_t onUninstantiatedGpuMemorySize() const override;
 
     int                 fSampleCnt;
+    bool                fNeedsStencil;
+
     // For wrapped render targets the actual GrRenderTarget is stored in the GrIORefProxy class.
     // For deferred proxies that pointer is filled in when we need to instantiate the
     // deferred resource.
diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h
index efd078a..21438f6 100644
--- a/include/private/GrSurfaceProxy.h
+++ b/include/private/GrSurfaceProxy.h
@@ -372,11 +372,11 @@
     virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0;
     void assign(sk_sp<GrSurface> surface);
 
-    sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt,
+    sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt, bool needsStencil,
                                        GrSurfaceFlags flags, bool isMipMapped,
                                        SkDestinationSurfaceColorMode mipColorMode) const;
 
-    bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
+    bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, bool needsStencil,
                          GrSurfaceFlags flags, bool isMipMapped,
                          SkDestinationSurfaceColorMode mipColorMode);
 
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index 0a63e40..49d5635 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -338,16 +338,7 @@
         }
     }
 
-    GrRenderTarget* rt = renderTargetContext->accessRenderTarget();
-    if (!rt) {
-        return true;
-    }
-
-    // use the stencil clip if we can't represent the clip as a rectangle.
-    if (!context->resourceProvider()->attachStencilAttachment(rt)) {
-        SkDebugf("WARNING: failed to attach stencil buffer for clip mask. Clip will be ignored.\n");
-        return true;
-    }
+    renderTargetContext->setNeedsStencil();
 
     // This relies on the property that a reduced sub-rect of the last clip will contain all the
     // relevant window rectangles that were in the last clip. This subtle requirement will go away
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index e76b5ff..10f21e8 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -648,22 +648,12 @@
     // attempt this in a situation that would require coverage AA.
     SkASSERT(!appliedClip.clipCoverageFragmentProcessor());
 
-    GrRenderTarget* rt = fRenderTargetContext->accessRenderTarget();
-    if (!rt) {
-        return;
-    }
-    GrStencilAttachment* stencilAttachment =
-            fRenderTargetContext->fContext->resourceProvider()->attachStencilAttachment(rt);
-    if (!stencilAttachment) {
-        SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
-        return;
-    }
+    fRenderTargetContext->setNeedsStencil();
 
     std::unique_ptr<GrOp> op = GrStencilPathOp::Make(viewMatrix,
                                                      useHWAA,
                                                      path->getFillType(),
                                                      appliedClip.hasStencilClip(),
-                                                     stencilAttachment->bits(),
                                                      appliedClip.scissorState(),
                                                      path);
     if (!op) {
@@ -1763,16 +1753,7 @@
         appliedClip.hasStencilClip()) {
         this->getOpList()->setRequiresStencil();
 
-        // This forces instantiation of the render target.
-        GrRenderTarget* rt = this->accessRenderTarget();
-        if (!rt) {
-            return SK_InvalidUniqueID;
-        }
-
-        if (!fContext->resourceProvider()->attachStencilAttachment(rt)) {
-            SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
-            return SK_InvalidUniqueID;
-        }
+        this->setNeedsStencil();
     }
 
     GrXferProcessor::DstProxy dstProxy;
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index f012ebb..2b9308a 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -328,6 +328,8 @@
 
     bool wasAbandoned() const;
 
+    void setNeedsStencil() { fRenderTargetProxy->setNeedsStencil(); }
+
     GrRenderTarget* accessRenderTarget() {
         // TODO: usage of this entry point needs to be reduced and potentially eliminated
         // since it ends the deferral of the GrRenderTarget's allocation
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index 8380911..fff3d0b 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -22,6 +22,7 @@
                                          SkBackingFit fit, SkBudgeted budgeted, uint32_t flags)
         : INHERITED(desc, fit, budgeted, flags)
         , fSampleCnt(desc.fSampleCnt)
+        , fNeedsStencil(false)
         , fRenderTargetFlags(GrRenderTargetFlags::kNone) {
     // Since we know the newly created render target will be internal, we are able to precompute
     // what the flags will ultimately end up being.
@@ -37,6 +38,7 @@
 GrRenderTargetProxy::GrRenderTargetProxy(sk_sp<GrSurface> surf, GrSurfaceOrigin origin)
     : INHERITED(std::move(surf), origin, SkBackingFit::kExact)
     , fSampleCnt(fTarget->asRenderTarget()->numStencilSamples())
+    , fNeedsStencil(false)
     , fRenderTargetFlags(fTarget->asRenderTarget()->renderTargetPriv().flags()) {
 }
 
@@ -49,7 +51,7 @@
 bool GrRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) {
     static constexpr GrSurfaceFlags kFlags = kRenderTarget_GrSurfaceFlag;
 
-    if (!this->instantiateImpl(resourceProvider, fSampleCnt, kFlags,
+    if (!this->instantiateImpl(resourceProvider, fSampleCnt, fNeedsStencil, kFlags,
                                /* isMipped = */ false,
                                SkDestinationSurfaceColorMode::kLegacy)) {
         return false;
@@ -64,8 +66,8 @@
 sk_sp<GrSurface> GrRenderTargetProxy::createSurface(GrResourceProvider* resourceProvider) const {
     static constexpr GrSurfaceFlags kFlags = kRenderTarget_GrSurfaceFlag;
 
-    sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, fSampleCnt, kFlags,
-                                                       /* isMipped = */ false,
+    sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, fSampleCnt, fNeedsStencil,
+                                                       kFlags, /* isMipped = */ false,
                                                        SkDestinationSurfaceColorMode::kLegacy);
     if (!surface) {
         return nullptr;
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index f863940..6a55270 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -43,8 +43,26 @@
     SkASSERT(!fLastOpList);
 }
 
+static bool attach_stencil_if_needed(GrResourceProvider* resourceProvider,
+                                     GrSurface* surface, bool needsStencil) {
+    if (needsStencil) {
+        GrRenderTarget* rt = surface->asRenderTarget();
+        if (!rt) {
+            SkASSERT(0);
+            return false;
+        }
+
+        if (!resourceProvider->attachStencilAttachment(rt)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(
-                                                GrResourceProvider* resourceProvider, int sampleCnt,
+                                                GrResourceProvider* resourceProvider,
+                                                int sampleCnt, bool needsStencil,
                                                 GrSurfaceFlags flags, bool isMipMapped,
                                                 SkDestinationSurfaceColorMode mipColorMode) const {
     GrSurfaceDesc desc;
@@ -65,8 +83,14 @@
     } else {
         surface.reset(resourceProvider->createTexture(desc, fBudgeted, fFlags).release());
     }
-    if (surface) {
-        surface->asTexture()->texturePriv().setMipColorMode(mipColorMode);
+    if (!surface) {
+        return nullptr;
+    }
+
+    surface->asTexture()->texturePriv().setMipColorMode(mipColorMode);
+
+    if (!attach_stencil_if_needed(resourceProvider, surface.get(), needsStencil)) {
+        return nullptr;
     }
 
     return surface;
@@ -85,14 +109,14 @@
 }
 
 bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
-                                     GrSurfaceFlags flags, bool isMipMapped,
+                                     bool needsStencil, GrSurfaceFlags flags, bool isMipMapped,
                                      SkDestinationSurfaceColorMode mipColorMode) {
     if (fTarget) {
-        return true;
+        return attach_stencil_if_needed(resourceProvider, fTarget, needsStencil);
     }
 
-    sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, sampleCnt, flags,
-                                                       isMipMapped, mipColorMode);
+    sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, sampleCnt, needsStencil,
+                                                       flags, isMipMapped, mipColorMode);
     if (!surface) {
         return false;
     }
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index 21533df..5bacc97 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -24,8 +24,8 @@
 }
 
 bool GrTextureProxy::instantiate(GrResourceProvider* resourceProvider) {
-    if (!this->instantiateImpl(resourceProvider, 0, kNone_GrSurfaceFlags, fIsMipMapped,
-                               fMipColorMode)) {
+    if (!this->instantiateImpl(resourceProvider, 0, /* needsStencil = */ false,
+                               kNone_GrSurfaceFlags, fIsMipMapped, fMipColorMode)) {
         return false;
     }
 
@@ -34,7 +34,9 @@
 }
 
 sk_sp<GrSurface> GrTextureProxy::createSurface(GrResourceProvider* resourceProvider) const {
-    sk_sp<GrSurface> surface= this->createSurfaceImpl(resourceProvider, 0, kNone_GrSurfaceFlags,
+    sk_sp<GrSurface> surface= this->createSurfaceImpl(resourceProvider, 0,
+                                                      /* needsStencil = */ false,
+                                                      kNone_GrSurfaceFlags,
                                                       fIsMipMapped, fMipColorMode);
     if (!surface) {
         return nullptr;
diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp
index 1bb0e23..4a4d79c 100644
--- a/src/gpu/GrTextureRenderTargetProxy.cpp
+++ b/src/gpu/GrTextureRenderTargetProxy.cpp
@@ -48,8 +48,8 @@
 bool GrTextureRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) {
     static constexpr GrSurfaceFlags kFlags = kRenderTarget_GrSurfaceFlag;
 
-    if (!this->instantiateImpl(resourceProvider, this->numStencilSamples(), kFlags,
-                               this->isMipMapped(), this->mipColorMode())) {
+    if (!this->instantiateImpl(resourceProvider, this->numStencilSamples(), this->needsStencil(),
+                               kFlags, this->isMipMapped(), this->mipColorMode())) {
         return false;
     }
     SkASSERT(fTarget->asRenderTarget());
@@ -63,8 +63,8 @@
     static constexpr GrSurfaceFlags kFlags = kRenderTarget_GrSurfaceFlag;
 
     sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, this->numStencilSamples(),
-                                                       kFlags, this->isMipMapped(),
-                                                       this->mipColorMode());
+                                                       this->needsStencil(), kFlags,
+                                                       this->isMipMapped(), this->mipColorMode());
     if (!surface) {
         return nullptr;
     }
diff --git a/src/gpu/ops/GrStencilPathOp.cpp b/src/gpu/ops/GrStencilPathOp.cpp
index 53a55cc..4c89ec0 100644
--- a/src/gpu/ops/GrStencilPathOp.cpp
+++ b/src/gpu/ops/GrStencilPathOp.cpp
@@ -9,10 +9,18 @@
 
 #include "GrGpu.h"
 #include "GrOpFlushState.h"
+#include "GrRenderTargetPriv.h"
 
 void GrStencilPathOp::onExecute(GrOpFlushState* state) {
+    GrRenderTarget* rt = state->drawOpArgs().renderTarget();
+    SkASSERT(rt);
+
+    int numStencilBits = rt->renderTargetPriv().numStencilBits();
+    GrStencilSettings stencil(GrPathRendering::GetStencilPassSettings(fFillType),
+                              fHasStencilClip, numStencilBits);
+
     GrPathRendering::StencilPathArgs args(fUseHWAA, state->drawOpArgs().fProxy,
-                                          &fViewMatrix, &fScissor, &fStencil);
+                                          &fViewMatrix, &fScissor, &stencil);
     state->gpu()->pathRendering()->stencilPath(args, fPath.get());
 }
 
diff --git a/src/gpu/ops/GrStencilPathOp.h b/src/gpu/ops/GrStencilPathOp.h
index 45240be..64df726 100644
--- a/src/gpu/ops/GrStencilPathOp.h
+++ b/src/gpu/ops/GrStencilPathOp.h
@@ -23,13 +23,11 @@
                                       bool useHWAA,
                                       GrPathRendering::FillType fillType,
                                       bool hasStencilClip,
-                                      int numStencilBits,
                                       const GrScissorState& scissor,
                                       const GrPath* path) {
 
         return std::unique_ptr<GrOp>(new GrStencilPathOp(viewMatrix, useHWAA, fillType,
-                                                         hasStencilClip, numStencilBits, scissor,
-                                                         path));
+                                                         hasStencilClip, scissor, path));
     }
 
     const char* name() const override { return "StencilPathOp"; }
@@ -46,14 +44,13 @@
                     bool useHWAA,
                     GrPathRendering::FillType fillType,
                     bool hasStencilClip,
-                    int numStencilBits,
                     const GrScissorState& scissor,
                     const GrPath* path)
             : INHERITED(ClassID())
             , fViewMatrix(viewMatrix)
             , fUseHWAA(useHWAA)
-            , fStencil(GrPathRendering::GetStencilPassSettings(fillType), hasStencilClip,
-                       numStencilBits)
+            , fFillType(fillType)
+            , fHasStencilClip(hasStencilClip)
             , fScissor(scissor)
             , fPath(path) {
         this->setBounds(path->getBounds(), HasAABloat::kNo, IsZeroArea::kNo);
@@ -67,7 +64,8 @@
 
     SkMatrix                                          fViewMatrix;
     bool                                              fUseHWAA;
-    GrStencilSettings                                 fStencil;
+    GrPathRendering::FillType                         fFillType;
+    bool                                              fHasStencilClip;
     GrScissorState                                    fScissor;
     GrPendingIOResource<const GrPath, kRead_GrIOType> fPath;