Move some of the adding stencil attachment logic of Gpu and into Render Target.
authoregdaniel <egdaniel@google.com>
Mon, 14 Sep 2015 19:56:10 +0000 (12:56 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 14 Sep 2015 19:56:10 +0000 (12:56 -0700)
The new flow of calls for attaching a Stencil looks like:

Client
  rt->attachStencilAttachment()
    gpu->getStencilAttachment()
      glgpu->createStencilAttachment()
    glrt->completeStencilAttachment() //actually attaches

BUG=skia:

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

16 files changed:
include/gpu/GrRenderTarget.h
src/gpu/GrClipMaskManager.cpp
src/gpu/GrDrawContext.cpp
src/gpu/GrDrawTarget.cpp
src/gpu/GrGpu.cpp
src/gpu/GrGpu.h
src/gpu/GrRenderTarget.cpp
src/gpu/GrRenderTargetPriv.h
src/gpu/GrResourceProvider.cpp
src/gpu/GrResourceProvider.h
src/gpu/GrTest.cpp
src/gpu/gl/GrGLGpu.cpp
src/gpu/gl/GrGLGpu.h
src/gpu/gl/GrGLRenderTarget.cpp
src/gpu/gl/GrGLRenderTarget.h
tests/ResourceCacheTest.cpp

index 8983d53..2309dbd 100644 (file)
@@ -144,15 +144,18 @@ public:
      */
     virtual GrBackendObject getRenderTargetHandle() const = 0;
 
+    // Checked when this object is asked to attach a stencil buffer.
+    virtual bool canAttemptStencilAttachment() const = 0;
+
     // Provides access to functions that aren't part of the public API.
     GrRenderTargetPriv renderTargetPriv();
     const GrRenderTargetPriv renderTargetPriv() const;
 
 protected:
     GrRenderTarget(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc,
-                   SampleConfig sampleConfig)
+                   SampleConfig sampleConfig, GrStencilAttachment* stencil = nullptr)
         : INHERITED(gpu, lifeCycle, desc)
-        , fStencilAttachment(NULL)
+        , fStencilAttachment(stencil)
         , fSampleConfig(sampleConfig) {
         fResolveRect.setLargestInverted();
     }
@@ -162,8 +165,11 @@ protected:
     void onRelease() override;
 
 private:
-    // Checked when this object is asked to attach a stencil buffer.
-    virtual bool canAttemptStencilAttachment() const = 0;
+    // Allows the backends to perform any additional work that is required for attaching a
+    // GrStencilAttachment. When this is called, the GrStencilAttachment has already been put onto
+    // the GrRenderTarget. This function must return false if any failures occur when completing the
+    // stencil attachment.
+    virtual bool completeStencilAttachment() = 0;
 
     friend class GrRenderTargetPriv;
 
index 0f32839..0ab1600 100644 (file)
@@ -717,7 +717,8 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
     SkASSERT(kNone_ClipMaskType == fCurrClipMaskType);
     SkASSERT(rt);
 
-    GrStencilAttachment* stencilAttachment = rt->renderTargetPriv().attachStencilAttachment();
+    GrStencilAttachment* stencilAttachment =
+        fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt);
     if (nullptr == stencilAttachment) {
         return false;
     }
@@ -977,7 +978,8 @@ void GrClipMaskManager::setPipelineBuilderStencil(const GrPipelineBuilder& pipel
 
     int stencilBits = 0;
     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
-    GrStencilAttachment* stencilAttachment = rt->renderTargetPriv().attachStencilAttachment();
+    GrStencilAttachment* stencilAttachment = 
+        fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt);
     if (stencilAttachment) {
         stencilBits = stencilAttachment->bits();
     }
index 3d3be74..94fcee0 100644 (file)
@@ -63,7 +63,8 @@ GrTextContext* GrDrawContext::createTextContext(GrRenderTarget* renderTarget,
     if (fContext->caps()->shaderCaps()->pathRenderingSupport() &&
         renderTarget->isStencilBufferMultisampled() &&
         fSurfaceProps.isUseDeviceIndependentFonts()) {
-        GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
+        GrStencilAttachment* sb =
+            fContext->resourceProvider()->attachStencilAttachment(renderTarget);
         if (sb) {
             return GrStencilAndCoverTextContext::Create(fContext, surfaceProps);
         }
index 076b626..3d5f428 100644 (file)
@@ -215,7 +215,7 @@ void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
     // set stencil settings for path
     GrStencilSettings stencilSettings;
     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
-    GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment();
+    GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
     this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);
 
     GrBatch* batch = GrStencilPathBatch::Create(viewMatrix,
@@ -270,7 +270,7 @@ void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder,
     // Ensure the render target has a stencil buffer and get the stencil settings.
     GrStencilSettings stencilSettings;
     GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
-    GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment();
+    GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
     this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);
     batch->setStencilSettings(stencilSettings);
 
index e1b8ed5..96728f3 100644 (file)
@@ -16,6 +16,7 @@
 #include "GrPathRendering.h"
 #include "GrPipeline.h"
 #include "GrResourceCache.h"
+#include "GrResourceProvider.h"
 #include "GrRenderTargetPriv.h"
 #include "GrStencilAttachment.h"
 #include "GrSurfacePriv.h"
@@ -134,48 +135,6 @@ GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, bool budgeted,
     return tex;
 }
 
-bool GrGpu::attachStencilAttachmentToRenderTarget(GrRenderTarget* rt) {
-    SkASSERT(nullptr == rt->renderTargetPriv().getStencilAttachment());
-    GrUniqueKey sbKey;
-
-    int width = rt->width();
-    int height = rt->height();
-#if 0
-    if (this->caps()->oversizedStencilSupport()) {
-        width  = SkNextPow2(width);
-        height = SkNextPow2(height);
-    }
-#endif
-
-    GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
-        rt->numStencilSamples(), &sbKey);
-    SkAutoTUnref<GrStencilAttachment> sb(static_cast<GrStencilAttachment*>(
-        this->getContext()->getResourceCache()->findAndRefUniqueResource(sbKey)));
-    if (sb) {
-        if (this->attachStencilAttachmentToRenderTarget(sb, rt)) {
-            rt->renderTargetPriv().didAttachStencilAttachment(sb);
-            return true;
-        }
-        return false;
-    }
-    if (this->createStencilAttachmentForRenderTarget(rt, width, height)) {
-        // Right now we're clearing the stencil buffer here after it is
-        // attached to an RT for the first time. When we start matching
-        // stencil buffers with smaller color targets this will no longer
-        // be correct because it won't be guaranteed to clear the entire
-        // sb.
-        // We used to clear down in the GL subclass using a special purpose
-        // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
-        // FBO status.
-        this->clearStencil(rt);
-        GrStencilAttachment* sb = rt->renderTargetPriv().getStencilAttachment();
-        sb->resourcePriv().setUniqueKey(sbKey);
-        return true;
-    } else {
-        return false;
-    }
-}
-
 GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwnership ownership) {
     this->handleDirtyContext();
     GrTexture* tex = this->onWrapBackendTexture(desc, ownership);
@@ -184,7 +143,7 @@ GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwn
     }
     // TODO: defer this and attach dynamically
     GrRenderTarget* tgt = tex->asRenderTarget();
-    if (tgt && !this->attachStencilAttachmentToRenderTarget(tgt)) {
+    if (tgt && !fContext->resourceProvider()->attachStencilAttachment(tgt)) {
         tex->unref();
         return nullptr;
     } else {
index 73a5264..d8e5681 100644 (file)
@@ -369,8 +369,14 @@ public:
     virtual bool isTestingOnlyBackendTexture(GrBackendObject id) const = 0;
     virtual void deleteTestingOnlyBackendTexture(GrBackendObject id) const = 0;
 
-    // Given a rt, find or create a stencil buffer and attach it
-    bool attachStencilAttachmentToRenderTarget(GrRenderTarget* target);
+    // width and height may be larger than rt (if underlying API allows it).
+    // Returns nullptr if compatible sb could not be created, otherwise the caller owns the ref on
+    // the GrStencilAttachment.
+    virtual GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
+                                                                        int width,
+                                                                        int height) = 0;
+    // clears target's entire stencil buffer to 0
+    virtual void clearStencil(GrRenderTarget* target) = 0;
 
     // This is only to be used in GL-specific tests.
     virtual const GrGLContext* glContextForTesting() const { return nullptr; }
@@ -466,17 +472,6 @@ private:
                                const SkIRect& srcRect,
                                const SkIPoint& dstPoint) = 0;
 
-    // width and height may be larger than rt (if underlying API allows it).
-    // Should attach the SB to the RT. Returns false if compatible sb could
-    // not be created.
-    virtual bool createStencilAttachmentForRenderTarget(GrRenderTarget*, int width, int height) = 0;
-
-    // attaches an existing SB to an existing RT.
-    virtual bool attachStencilAttachmentToRenderTarget(GrStencilAttachment*, GrRenderTarget*) = 0;
-
-    // clears target's entire stencil buffer to 0
-    virtual void clearStencil(GrRenderTarget* target) = 0;
-
     void resetContext() {
         this->onResetContext(fResetBits);
         fResetBits = 0;
index 5cb34e8..c16738e 100644 (file)
@@ -55,29 +55,24 @@ void GrRenderTarget::overrideResolveRect(const SkIRect rect) {
 }
 
 void GrRenderTarget::onRelease() {
-    this->renderTargetPriv().didAttachStencilAttachment(nullptr);
+    SkSafeSetNull(fStencilAttachment);
 
     INHERITED::onRelease();
 }
 
 void GrRenderTarget::onAbandon() {
-    this->renderTargetPriv().didAttachStencilAttachment(nullptr);
+    SkSafeSetNull(fStencilAttachment);
 
     INHERITED::onAbandon();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrRenderTargetPriv::didAttachStencilAttachment(GrStencilAttachment* stencilAttachment) {
-    SkRefCnt_SafeAssign(fRenderTarget->fStencilAttachment, stencilAttachment);
-}
-
-GrStencilAttachment* GrRenderTargetPriv::attachStencilAttachment() const {
-    if (fRenderTarget->fStencilAttachment) {
-        return fRenderTarget->fStencilAttachment;
-    }
-    if (!fRenderTarget->wasDestroyed() && fRenderTarget->canAttemptStencilAttachment()) {
-        fRenderTarget->getGpu()->attachStencilAttachmentToRenderTarget(fRenderTarget);
-    }
-    return fRenderTarget->fStencilAttachment;
+bool GrRenderTargetPriv::attachStencilAttachment(GrStencilAttachment* stencil) {
+    fRenderTarget->fStencilAttachment = stencil;
+    if (!fRenderTarget->completeStencilAttachment()) {
+        SkSafeSetNull(fRenderTarget->fStencilAttachment);
+        return false;
+    } 
+    return true;
 }
index 59262f4..f4931db 100644 (file)
@@ -21,12 +21,11 @@ public:
     GrStencilAttachment* getStencilAttachment() const { return fRenderTarget->fStencilAttachment; }
 
     /**
-     * If this render target already has a stencil buffer, return it. Otherwise attempt to attach
-     * one.
+     * Attaches the GrStencilAttachment onto the render target. If stencil is a nullptr then the
+     * currently attached GrStencilAttachment will be removed if one was previously attached. This
+     * function returns false if there were any failure in attaching the GrStencilAttachment.
      */
-    GrStencilAttachment* attachStencilAttachment() const;
-
-    void didAttachStencilAttachment(GrStencilAttachment*);
+    bool attachStencilAttachment(GrStencilAttachment* stencil);
 
 private:
     explicit GrRenderTargetPriv(GrRenderTarget* renderTarget) : fRenderTarget(renderTarget) {}
index d3ab8cc..bd9cc9a 100644 (file)
 #include "GrGpu.h"
 #include "GrIndexBuffer.h"
 #include "GrPathRendering.h"
+#include "GrRenderTarget.h"
+#include "GrRenderTargetPriv.h"
 #include "GrResourceCache.h"
 #include "GrResourceKey.h"
+#include "GrStencilAttachment.h"
 #include "GrVertexBuffer.h"
 
 GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
@@ -163,3 +166,52 @@ GrBatchAtlas* GrResourceProvider::createAtlas(GrPixelConfig config,
     }
     return new GrBatchAtlas(texture, numPlotsX, numPlotsY);
 }
+
+GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) {
+    SkASSERT(rt);
+    if (rt->renderTargetPriv().getStencilAttachment()) {
+        return rt->renderTargetPriv().getStencilAttachment();
+    }
+
+    if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
+        GrUniqueKey sbKey;
+
+        int width = rt->width();
+        int height = rt->height();
+#if 0
+        if (this->caps()->oversizedStencilSupport()) {
+            width  = SkNextPow2(width);
+            height = SkNextPow2(height);
+        }
+#endif
+        bool newStencil = false;
+        GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
+                                                               rt->numStencilSamples(), &sbKey);
+        GrStencilAttachment* stencil = static_cast<GrStencilAttachment*>(
+            this->findAndRefResourceByUniqueKey(sbKey));
+        if (!stencil) {
+            // Need to try and create a new stencil
+            stencil = this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height);
+            if (stencil) {
+                stencil->resourcePriv().setUniqueKey(sbKey);
+                newStencil = true;
+            }
+        }
+        if (rt->renderTargetPriv().attachStencilAttachment(stencil)) {
+            if (newStencil) {
+                // Right now we're clearing the stencil attachment here after it is
+                // attached to an RT for the first time. When we start matching
+                // stencil buffers with smaller color targets this will no longer
+                // be correct because it won't be guaranteed to clear the entire
+                // sb.
+                // We used to clear down in the GL subclass using a special purpose
+                // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
+                // FBO status.
+                this->gpu()->clearStencil(rt);
+            }
+        }
+    }
+    return rt->renderTargetPriv().getStencilAttachment();
+}
+
+
index 72efab1..33a9f3b 100644 (file)
@@ -16,6 +16,8 @@
 class GrBatchAtlas;
 class GrIndexBuffer;
 class GrPath;
+class GrRenderTarget;
+class GrStencilAttachment;
 class GrStrokeInfo;
 class GrVertexBuffer;
 class SkDescriptor;
@@ -134,6 +136,12 @@ public:
     GrBatchAtlas* createAtlas(GrPixelConfig, int width, int height, int numPlotsX, int numPlotsY,
                               GrBatchAtlas::EvictionFunc func, void* data);
 
+    /**
+     * If passed in render target already has a stencil buffer, return it. Otherwise attempt to
+     * attach one.
+     */
+    GrStencilAttachment* attachStencilAttachment(GrRenderTarget* rt);
+
 private:
     const GrIndexBuffer* createInstancedIndexBuffer(const uint16_t* pattern,
                                                     int patternSize,
index 4e697ff..8d6208d 100644 (file)
@@ -255,12 +255,10 @@ private:
 
     void onResolveRenderTarget(GrRenderTarget* target) override { return; }
 
-    bool createStencilAttachmentForRenderTarget(GrRenderTarget*, int width, int height) override {
-        return false;
-    }
-
-    bool attachStencilAttachmentToRenderTarget(GrStencilAttachment*, GrRenderTarget*) override {
-        return false;
+    GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
+                                                                int width,
+                                                                int height) override {
+        return nullptr;
     }
 
     void clearStencil(GrRenderTarget* target) override  {}
index e10b951..c07f704 100644 (file)
@@ -495,20 +495,7 @@ GrRenderTarget* GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDe
     desc.fSampleCnt = SkTMin(wrapDesc.fSampleCnt, this->caps()->maxSampleCount());
     desc.fOrigin = resolve_origin(wrapDesc.fOrigin, true);
 
-    GrRenderTarget* tgt = new GrGLRenderTarget(this, desc, idDesc);
-    if (wrapDesc.fStencilBits) {
-        GrGLStencilAttachment::IDDesc sbDesc;
-        GrGLStencilAttachment::Format format;
-        format.fInternalFormat = GrGLStencilAttachment::kUnknownInternalFormat;
-        format.fPacked = false;
-        format.fStencilBits = wrapDesc.fStencilBits;
-        format.fTotalBits = wrapDesc.fStencilBits;
-        GrGLStencilAttachment* sb = new GrGLStencilAttachment(
-                this, sbDesc, desc.fWidth, desc.fHeight, desc.fSampleCnt, format);
-        tgt->renderTargetPriv().didAttachStencilAttachment(sb);
-        sb->unref();
-    }
-    return tgt;
+    return GrGLRenderTarget::CreateWrapped(this, desc, idDesc, wrapDesc.fStencilBits);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1241,7 +1228,7 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) {
         // Create Framebuffer
         GrGLuint fb;
         GL_CALL(GenFramebuffers(1, &fb));
-        GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb)); 
+        GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb));
         fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
         GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
                                      GR_GL_COLOR_ATTACHMENT0,
@@ -1304,7 +1291,9 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) {
     return fPixelConfigToStencilIndex[config];
 }
 
-bool GrGLGpu::createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int width, int height) {
+GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
+                                                                     int width,
+                                                                     int height) {
     // All internally created RTs are also textures. We don't create
     // SBs for a client's standalone RT (that is a RT that isn't also a texture).
     SkASSERT(rt->asTexture());
@@ -1316,14 +1305,14 @@ bool GrGLGpu::createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int wid
 
     int sIdx = this->getCompatibleStencilIndex(rt->config());
     if (sIdx == kUnsupportedStencilIndex) {
-        return false;
+        return nullptr;
     }
 
     if (!sbDesc.fRenderbufferID) {
         GL_CALL(GenRenderbuffers(1, &sbDesc.fRenderbufferID));
     }
     if (!sbDesc.fRenderbufferID) {
-        return false;
+        return nullptr;
     }
     GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
     const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[sIdx];
@@ -1346,113 +1335,13 @@ bool GrGLGpu::createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int wid
     // whatever sizes GL gives us. In that case we query for the size.
     GrGLStencilAttachment::Format format = sFmt;
     get_stencil_rb_sizes(this->glInterface(), &format);
-    SkAutoTUnref<GrGLStencilAttachment> sb(
-        new GrGLStencilAttachment(this, sbDesc, width, height, samples, format));
-    SkAssertResult(this->attachStencilAttachmentToRenderTarget(sb, rt));
-    rt->renderTargetPriv().didAttachStencilAttachment(sb);
-    // This work around is currently breaking on windows 7 hd2000 bot when we bind a color buffer
-#if 0
-    // Clear the stencil buffer. We use a special purpose FBO for this so that the
-    // entire stencil buffer is cleared, even if it is attached to an FBO with a
-    // smaller color target.
-    if (0 == fStencilClearFBOID) {
-        GL_CALL(GenFramebuffers(1, &fStencilClearFBOID));
-    }
-
-    GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBOID));
-    fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
-    fStats.incRenderTargetBinds();
-    GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                    GR_GL_STENCIL_ATTACHMENT,
-                                    GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
-    if (sFmt.fPacked) {
-        GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                        GR_GL_DEPTH_ATTACHMENT,
-                                        GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
-    }
-
-    GL_CALL(ClearStencil(0));
-    // Many GL implementations seem to have trouble with clearing an FBO with only
-    // a stencil buffer.
-    GrGLuint tempRB;
-    GL_CALL(GenRenderbuffers(1, &tempRB));
-    GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, tempRB));
-    if (samples > 0) {
-        renderbuffer_storage_msaa(fGLContext, samples, GR_GL_RGBA8, width, height);
-    } else {
-        GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, GR_GL_RGBA8, width, height));
-    }
-    GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                    GR_GL_COLOR_ATTACHMENT0,
-                                    GR_GL_RENDERBUFFER, tempRB));
-
-    GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
-
-    GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                    GR_GL_COLOR_ATTACHMENT0,
-                                    GR_GL_RENDERBUFFER, 0));
-    GL_CALL(DeleteRenderbuffers(1, &tempRB));
-
-    // Unbind the SB from the FBO so that we don't keep it alive.
-    GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                    GR_GL_STENCIL_ATTACHMENT,
-                                    GR_GL_RENDERBUFFER, 0));
-    if (sFmt.fPacked) {
-        GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                        GR_GL_DEPTH_ATTACHMENT,
-                                        GR_GL_RENDERBUFFER, 0));
-    }
-#endif
-    return true;
-}
-
-bool GrGLGpu::attachStencilAttachmentToRenderTarget(GrStencilAttachment* sb, GrRenderTarget* rt) {
-    GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(rt);
-
-    GrGLuint fbo = glrt->renderFBOID();
-
-    if (nullptr == sb) {
-        if (rt->renderTargetPriv().getStencilAttachment()) {
-            GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                            GR_GL_STENCIL_ATTACHMENT,
-                                            GR_GL_RENDERBUFFER, 0));
-            GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                            GR_GL_DEPTH_ATTACHMENT,
-                                            GR_GL_RENDERBUFFER, 0));
-#ifdef SK_DEBUG
-            GrGLenum status;
-            GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
-            SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
-#endif
-        }
-        return true;
-    } else {
-        GrGLStencilAttachment* glsb = static_cast<GrGLStencilAttachment*>(sb);
-        GrGLuint rb = glsb->renderbufferID();
-
-        fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
-        fStats.incRenderTargetBinds();
-        GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo));
-        GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                        GR_GL_STENCIL_ATTACHMENT,
-                                        GR_GL_RENDERBUFFER, rb));
-        if (glsb->format().fPacked) {
-            GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                            GR_GL_DEPTH_ATTACHMENT,
-                                            GR_GL_RENDERBUFFER, rb));
-        } else {
-            GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                            GR_GL_DEPTH_ATTACHMENT,
-                                            GR_GL_RENDERBUFFER, 0));
-        }
-
-#ifdef SK_DEBUG
-        GrGLenum status;
-        GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
-        SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
-#endif
-        return true;
-    }
+    GrGLStencilAttachment* stencil = new GrGLStencilAttachment(this,
+                                                               sbDesc,
+                                                               width,
+                                                               height,
+                                                               samples,
+                                                               format);
+    return stencil;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
index fecede0..833f1ff 100644 (file)
@@ -99,6 +99,16 @@ public:
         return &this->glContext();
     }
 
+    void clearStencil(GrRenderTarget*) override;
+
+    void invalidateBoundRenderTarget() {
+        fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+    }
+
+    GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
+                                                                int width,
+                                                                int height) override;
+
     GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h,
                                                     GrPixelConfig config) const override;
     bool isTestingOnlyBackendTexture(GrBackendObject id) const override;
@@ -122,9 +132,6 @@ private:
     GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) override;
     GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&,
                                               GrWrapOwnership) override;
-    bool createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int width, int height) override;
-    bool attachStencilAttachmentToRenderTarget(GrStencilAttachment* sb,
-                                               GrRenderTarget* rt) override;
     // Given a GrPixelConfig return the index into the stencil format array on GrGLCaps to a
     // compatible stencil format.
     int getCompatibleStencilIndex(GrPixelConfig config);
@@ -154,8 +161,6 @@ private:
                        const SkIRect& srcRect,
                        const SkIPoint& dstPoint) override;
 
-    void clearStencil(GrRenderTarget*) override;
-
     // binds texture unit in GL
     void setTextureUnit(int unitIdx);
 
index cb9d310..dfb4e88 100644 (file)
@@ -7,15 +7,20 @@
 
 #include "GrGLRenderTarget.h"
 
+#include "GrRenderTargetPriv.h"
 #include "GrGLGpu.h"
+#include "GrGLUtil.h"
 
 #define GPUGL static_cast<GrGLGpu*>(this->getGpu())
 #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
 
 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
-GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc)
+GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu,
+                                   const GrSurfaceDesc& desc,
+                                   const IDDesc& idDesc,
+                                   GrGLStencilAttachment* stencil)
     : GrSurface(gpu, idDesc.fLifeCycle, desc)
-    , INHERITED(gpu, idDesc.fLifeCycle, desc, idDesc.fSampleConfig) {
+    , INHERITED(gpu, idDesc.fLifeCycle, desc, idDesc.fSampleConfig, stencil) {
     this->init(desc, idDesc);
     this->registerWithCache();
 }
@@ -56,10 +61,77 @@ void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
     SkASSERT(fGpuMemorySize <= WorseCaseSize(desc));
 }
 
+GrGLRenderTarget* GrGLRenderTarget::CreateWrapped(GrGLGpu* gpu,
+                                                  const GrSurfaceDesc& desc,
+                                                  const IDDesc& idDesc,
+                                                  int stencilBits) {
+    GrGLStencilAttachment* sb = nullptr;
+    if (stencilBits) {
+        GrGLStencilAttachment::IDDesc sbDesc;
+        GrGLStencilAttachment::Format format;
+        format.fInternalFormat = GrGLStencilAttachment::kUnknownInternalFormat;
+        format.fPacked = false;
+        format.fStencilBits = stencilBits;
+        format.fTotalBits = stencilBits;
+        // Owndership of sb is passed to the GrRenderTarget so doesn't need to be deleted
+        sb = new GrGLStencilAttachment(gpu, sbDesc, desc.fWidth, desc.fHeight,
+                                       desc.fSampleCnt, format);
+    }
+    return (new GrGLRenderTarget(gpu, desc, idDesc, sb));
+}
+
 size_t GrGLRenderTarget::onGpuMemorySize() const {
     return fGpuMemorySize;
 }
 
+bool GrGLRenderTarget::completeStencilAttachment() {
+    GrGLGpu* gpu = this->getGLGpu();
+    const GrGLInterface* interface = gpu->glInterface();
+    GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
+    if (nullptr == stencil) {
+        if (this->renderTargetPriv().getStencilAttachment()) {
+            GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                                          GR_GL_STENCIL_ATTACHMENT,
+                                                          GR_GL_RENDERBUFFER, 0));
+            GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                                          GR_GL_DEPTH_ATTACHMENT,
+                                                          GR_GL_RENDERBUFFER, 0));
+#ifdef SK_DEBUG
+            GrGLenum status;
+            GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+            SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
+#endif
+        }
+        return true;
+    } else {
+        const GrGLStencilAttachment* glStencil = static_cast<const GrGLStencilAttachment*>(stencil);
+        GrGLuint rb = glStencil->renderbufferID();
+
+        gpu->invalidateBoundRenderTarget();
+        gpu->stats()->incRenderTargetBinds();
+        GR_GL_CALL(interface, BindFramebuffer(GR_GL_FRAMEBUFFER, this->renderFBOID()));
+        GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                                      GR_GL_STENCIL_ATTACHMENT,
+                                                      GR_GL_RENDERBUFFER, rb));
+        if (glStencil->format().fPacked) {
+            GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                                          GR_GL_DEPTH_ATTACHMENT,
+                                                          GR_GL_RENDERBUFFER, rb));
+        } else {
+            GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                                          GR_GL_DEPTH_ATTACHMENT,
+                                                          GR_GL_RENDERBUFFER, 0));
+        }
+
+#ifdef SK_DEBUG
+        GrGLenum status;
+        GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+        SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
+#endif
+        return true;
+    }
+}
+
 void GrGLRenderTarget::onRelease() {
     if (kBorrowed_LifeCycle != fRTLifecycle) {
         if (fTexFBOID) {
@@ -84,3 +156,9 @@ void GrGLRenderTarget::onAbandon() {
     fMSColorRenderbufferID  = 0;
     INHERITED::onAbandon();
 }
+
+GrGLGpu* GrGLRenderTarget::getGLGpu() const {
+    SkASSERT(!this->wasDestroyed());
+    return static_cast<GrGLGpu*>(this->getGpu());
+}
+
index 1e6dc7f..0539a08 100644 (file)
@@ -14,6 +14,7 @@
 #include "SkScalar.h"
 
 class GrGLGpu;
+class GrGLStencilAttachment;
 
 class GrGLRenderTarget : public GrRenderTarget {
 public:
@@ -29,7 +30,10 @@ public:
         GrRenderTarget::SampleConfig fSampleConfig;
     };
 
-    GrGLRenderTarget(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&);
+    static GrGLRenderTarget* CreateWrapped(GrGLGpu*,
+                                           const GrSurfaceDesc&,
+                                           const IDDesc&,
+                                           int stencilBits);
 
     void setViewport(const GrGLIRect& rect) { fViewport = rect; }
     const GrGLIRect& getViewport() const { return fViewport; }
@@ -78,6 +82,13 @@ protected:
     size_t onGpuMemorySize() const override;
 
 private:
+    // This ctor is used only for creating wrapped render targets and is only called for the static
+    // create function CreateWrapped(...).
+    GrGLRenderTarget(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&, GrGLStencilAttachment*);
+
+    GrGLGpu* getGLGpu() const;
+    bool completeStencilAttachment() override;
+
     GrGLuint    fRTFBOID;
     GrGLuint    fTexFBOID;
     GrGLuint    fMSColorRenderbufferID;
index d76da31..6370b92 100644 (file)
@@ -78,33 +78,34 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex
     smallDesc.fSampleCnt = 0;
 
     GrTextureProvider* cache = context->textureProvider();
+    GrResourceProvider* resourceProvider = context->resourceProvider();
     // Test that two budgeted RTs with the same desc share a stencil buffer.
     SkAutoTUnref<GrTexture> smallRT0(cache->createTexture(smallDesc, true));
     if (smallRT0 && smallRT0->asRenderTarget()) {
-        smallRT0->asRenderTarget()->renderTargetPriv().attachStencilAttachment();
+        resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget());
     }
 
     SkAutoTUnref<GrTexture> smallRT1(cache->createTexture(smallDesc, true));
     if (smallRT1 && smallRT1->asRenderTarget()) {
-        smallRT1->asRenderTarget()->renderTargetPriv().attachStencilAttachment();
+        resourceProvider->attachStencilAttachment(smallRT1->asRenderTarget());
     }
 
     REPORTER_ASSERT(reporter,
                     smallRT0 && smallRT1 &&
                     smallRT0->asRenderTarget() && smallRT1->asRenderTarget() &&
-                    smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() ==
-                    smallRT1->asRenderTarget()->renderTargetPriv().getStencilAttachment());
+                    resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) ==
+                    resourceProvider->attachStencilAttachment(smallRT1->asRenderTarget()));
 
     // An unbudgeted RT with the same desc should also share.
     SkAutoTUnref<GrTexture> smallRT2(cache->createTexture(smallDesc, false));
     if (smallRT2 && smallRT2->asRenderTarget()) {
-        smallRT2->asRenderTarget()->renderTargetPriv().attachStencilAttachment();
+        resourceProvider->attachStencilAttachment(smallRT2->asRenderTarget());
     }
     REPORTER_ASSERT(reporter,
                     smallRT0 && smallRT2 &&
                     smallRT0->asRenderTarget() && smallRT2->asRenderTarget() &&
-                    smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() ==
-                    smallRT2->asRenderTarget()->renderTargetPriv().getStencilAttachment());
+                    resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) ==
+                    resourceProvider->attachStencilAttachment(smallRT2->asRenderTarget()));
 
     // An RT with a much larger size should not share.
     GrSurfaceDesc bigDesc;
@@ -115,13 +116,13 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex
     bigDesc.fSampleCnt = 0;
     SkAutoTUnref<GrTexture> bigRT(cache->createTexture(bigDesc, false));
     if (bigRT && bigRT->asRenderTarget()) {
-        bigRT->asRenderTarget()->renderTargetPriv().attachStencilAttachment();
+        resourceProvider->attachStencilAttachment(bigRT->asRenderTarget());
     }
     REPORTER_ASSERT(reporter,
                     smallRT0 && bigRT &&
                     smallRT0->asRenderTarget() && bigRT->asRenderTarget() &&
-                    smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() !=
-                    bigRT->asRenderTarget()->renderTargetPriv().getStencilAttachment());
+                    resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) !=
+                    resourceProvider->attachStencilAttachment(bigRT->asRenderTarget()));
 
     if (context->caps()->maxSampleCount() >= 4) {
         // An RT with a different sample count should not share. 
@@ -129,7 +130,7 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex
         smallMSAADesc.fSampleCnt = 4;
         SkAutoTUnref<GrTexture> smallMSAART0(cache->createTexture(smallMSAADesc, false));
         if (smallMSAART0 && smallMSAART0->asRenderTarget()) {
-            smallMSAART0->asRenderTarget()->renderTargetPriv().attachStencilAttachment();
+            resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget());
         }
 #ifdef SK_BUILD_FOR_ANDROID
         if (!smallMSAART0) {
@@ -140,19 +141,19 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex
         REPORTER_ASSERT(reporter,
                         smallRT0 && smallMSAART0 &&
                         smallRT0->asRenderTarget() && smallMSAART0->asRenderTarget() &&
-                        smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() !=
-                        smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilAttachment());
+                        resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) !=
+                        resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget()));
         // A second MSAA RT should share with the first MSAA RT.
         SkAutoTUnref<GrTexture> smallMSAART1(cache->createTexture(smallMSAADesc, false));
         if (smallMSAART1 && smallMSAART1->asRenderTarget()) {
-            smallMSAART1->asRenderTarget()->renderTargetPriv().attachStencilAttachment();
+            resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget());
         }
         REPORTER_ASSERT(reporter,
                         smallMSAART0 && smallMSAART1 &&
                         smallMSAART0->asRenderTarget() &&
                         smallMSAART1->asRenderTarget() &&
-                        smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilAttachment() ==
-                        smallMSAART1->asRenderTarget()->renderTargetPriv().getStencilAttachment());
+                        resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget()) ==
+                        resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget()));
         // But not one with a larger sample count should not. (Also check that the request for 4
         // samples didn't get rounded up to >= 8 or else they could share.).
         if (context->caps()->maxSampleCount() >= 8 &&
@@ -162,14 +163,14 @@ static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* contex
             smallMSAART1.reset(cache->createTexture(smallMSAADesc, false));
             SkAutoTUnref<GrTexture> smallMSAART1(cache->createTexture(smallMSAADesc, false));
             if (smallMSAART1 && smallMSAART1->asRenderTarget()) {
-                smallMSAART1->asRenderTarget()->renderTargetPriv().attachStencilAttachment();
+                resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget());
             }
             REPORTER_ASSERT(reporter,
                         smallMSAART0 && smallMSAART1 &&
                         smallMSAART0->asRenderTarget() &&
                         smallMSAART1->asRenderTarget() &&
-                        smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilAttachment() !=
-                        smallMSAART1->asRenderTarget()->renderTargetPriv().getStencilAttachment());
+                        resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget()) !=
+                        resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget()));
         }
     }
 }