Add GrStencilBuffer as a separate resource type from render target
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 3 Aug 2011 15:18:33 +0000 (15:18 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 3 Aug 2011 15:18:33 +0000 (15:18 +0000)
This is a resubmission of the changes in r2026 with fixes for FBO completeness issues.

Review URL: http://codereview.appspot.com/4837046/

git-svn-id: http://skia.googlecode.com/svn/trunk@2035 2bbb7eff-a529-9590-31e7-b0007b416f81

gpu/include/GrGpu.h
gpu/include/GrRenderTarget.h
gpu/src/GrGLRenderTarget.cpp
gpu/src/GrGLRenderTarget.h
gpu/src/GrGLStencilBuffer.h [new file with mode: 0644]
gpu/src/GrGpu.cpp
gpu/src/GrGpuGL.cpp
gpu/src/GrGpuGL.h
gpu/src/GrRenderTarget.cpp
gpu/src/GrStencilBuffer.h [new file with mode: 0644]
gyp/gpu.gyp

index ef03bdbe3e7d6288bdce6fdceeea8577330d8c98..fff40fb1474ce61360ff7299cb831771d1336ad9 100644 (file)
@@ -19,6 +19,7 @@
 class GrContext;
 class GrIndexBufferAllocPool;
 class GrResource;
+class GrStencilBuffer;
 class GrVertexBufferAllocPool;
 
 /**
@@ -313,12 +314,13 @@ public:
 
     /**
      * Called to tell Gpu object that all GrResources have been lost and should
-     * be abandoned.
+     * be abandoned. Overrides must call INHERITED::abandonResources().
      */
     virtual void abandonResources();
 
     /**
-     * Called to tell Gpu object to release all GrResources.
+     * Called to tell Gpu object to release all GrResources. Overrides must call
+     * INHERITED::releaseResources().
      */
     void releaseResources();
 
@@ -469,6 +471,16 @@ protected:
                                int vertexCount,
                                int indexCount) = 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 createStencilBufferForRenderTarget(GrRenderTarget* rt,
+                                                    int width, 
+                                                    int height) = 0;
+
+    // attaches an existing SB to an existing RT.
+    virtual bool attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
+                                                   GrRenderTarget* rt) = 0;
 
     // The GrGpu typically records the clients requested state and then flushes
     // deltas from previous state at draw time. This function does the
@@ -513,6 +525,9 @@ private:
 
     GrResource*                 fResourceHead;
 
+    // Given a rt, find or create a stencil buffer and attach it
+    bool attachStencilBufferToRenderTarget(GrRenderTarget* target);
+
     // GrDrawTarget overrides
     virtual void onDrawIndexed(GrPrimitiveType type,
                                int startVertex,
index a5616b989599a27d6d3de4dff06d1bc1bc001269..06d62a40bef3338fed0ecfc470222db824a3614f 100644 (file)
 #ifndef GrRenderTarget_DEFINED
 #define GrRenderTarget_DEFINED
 
-#include "GrClip.h"
 #include "GrRect.h"
 #include "GrResource.h"
 
+class GrStencilBuffer;
 class GrTexture;
 
 /**
@@ -50,11 +50,6 @@ public:
      */
     int config() const { return fConfig; }
 
-    /**
-     * @return the number of stencil bits in the rendertarget
-     */
-    int stencilBits() const { return fStencilBits; }
-
     /**
      * @return the texture associated with the rendertarget, may be NULL.
      */
@@ -145,20 +140,25 @@ public:
     };
     virtual ResolveType getResolveType() const = 0;
 
+    /**
+     * GrStencilBuffer is not part of the public API.
+     */
+    GrStencilBuffer* getStencilBuffer() const { return fStencilBuffer; }
+    void setStencilBuffer(GrStencilBuffer* stencilBuffer);
+
 protected:
     GrRenderTarget(GrGpu* gpu,
                    GrTexture* texture,
                    int width,
                    int height,
                    GrPixelConfig config,
-                   int stencilBits,
                    int sampleCnt)
         : INHERITED(gpu)
+        , fStencilBuffer(NULL)
         , fTexture(texture)
         , fWidth(width)
         , fHeight(height)
         , fConfig(config)
-        , fStencilBits(stencilBits)
         , fSampleCnt(sampleCnt)
     {
         fResolveRect.setLargestInverted();
@@ -175,20 +175,16 @@ protected:
         fTexture = NULL;
     }
 
+    GrStencilBuffer*  fStencilBuffer;
+
 private:
-    GrTexture* fTexture; // not ref'ed
+    GrTexture*      fTexture; // not ref'ed
     int             fWidth;
     int             fHeight;
     GrPixelConfig   fConfig;
-    int             fStencilBits;
     int             fSampleCnt;
     GrIRect         fResolveRect;
 
-    // GrGpu keeps a cached clip in the render target to avoid redundantly
-    // rendering the clip into the same stencil buffer.
-    friend class GrGpu;
-    GrClip     fLastStencilClip;
-
     typedef GrResource INHERITED;
 };
 
index 7be8b32f83c7e9b5cf0680fc0e112c68f5671394..38b9eb7a530f1648bc34e51dc212599a5c0b2364 100644 (file)
@@ -19,7 +19,6 @@ void GrGLRenderTarget::init(const Desc& desc,
     fRTFBOID                = desc.fRTFBOID;
     fTexFBOID               = desc.fTexFBOID;
     fMSColorRenderbufferID  = desc.fMSColorRenderbufferID;
-    fStencilRenderbufferID  = desc.fStencilRenderbufferID;
     fViewport               = viewport;
     fOwnIDs                 = desc.fOwnIDs;
     fTexIDObj               = texID;
@@ -32,8 +31,7 @@ GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu,
                                    GrGLTexID* texID,
                                    GrGLTexture* texture)
     : INHERITED(gpu, texture, viewport.fWidth,
-                viewport.fHeight, desc.fConfig,
-                desc.fStencilBits, desc.fSampleCnt) {
+                viewport.fHeight, desc.fConfig, desc.fSampleCnt) {
     GrAssert(NULL != texID);
     GrAssert(NULL != texture);
     // FBO 0 can't also be a texture, right?
@@ -46,8 +44,7 @@ GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu,
                                    const Desc& desc,
                                    const GrGLIRect& viewport)
     : INHERITED(gpu, NULL, viewport.fWidth,
-                viewport.fHeight, desc.fConfig,
-                desc.fStencilBits, desc.fSampleCnt) {
+                viewport.fHeight, desc.fConfig, desc.fSampleCnt) {
     this->init(desc, viewport, NULL);
 }
 
@@ -60,29 +57,26 @@ void GrGLRenderTarget::onRelease() {
         if (fRTFBOID && fRTFBOID != fTexFBOID) {
             GR_GL(DeleteFramebuffers(1, &fRTFBOID));
         }
-        if (fStencilRenderbufferID) {
-            GR_GL(DeleteRenderbuffers(1, &fStencilRenderbufferID));
-        }
         if (fMSColorRenderbufferID) {
             GR_GL(DeleteRenderbuffers(1, &fMSColorRenderbufferID));
         }
     }
     fRTFBOID                = 0;
     fTexFBOID               = 0;
-    fStencilRenderbufferID  = 0;
     fMSColorRenderbufferID  = 0;
     GrSafeUnref(fTexIDObj);
     fTexIDObj = NULL;
+    GrSafeSetNull(fStencilBuffer);
 }
 
 void GrGLRenderTarget::onAbandon() {
     fRTFBOID                = 0;
     fTexFBOID               = 0;
-    fStencilRenderbufferID  = 0;
     fMSColorRenderbufferID  = 0;
     if (NULL != fTexIDObj) {
         fTexIDObj->abandon();
         fTexIDObj = NULL;
     }
+    GrSafeSetNull(fStencilBuffer);
 }
 
index 3d64fabd37bbd3eab6afd08e553be4c6228fdc5f..5aeb36dc65b5eaa9fa665ce3f6dbc079c76b8e20 100644 (file)
@@ -28,11 +28,9 @@ public:
     struct Desc {
         GrGLuint      fRTFBOID;
         GrGLuint      fTexFBOID;
-        GrGLuint      fStencilRenderbufferID;
         GrGLuint      fMSColorRenderbufferID;
         bool          fOwnIDs;
         GrPixelConfig fConfig;
-        int           fStencilBits;
         int           fSampleCnt;
     };
 
@@ -87,7 +85,7 @@ protected:
 private:
     GrGLuint      fRTFBOID;
     GrGLuint      fTexFBOID;
-    GrGLuint      fStencilRenderbufferID;
+
     GrGLuint      fMSColorRenderbufferID;
 
     // Should this object delete IDs when it is destroyed or does someone
diff --git a/gpu/src/GrGLStencilBuffer.h b/gpu/src/GrGLStencilBuffer.h
new file mode 100644 (file)
index 0000000..97394e3
--- /dev/null
@@ -0,0 +1,72 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrGLStencilBuffer_DEFINED
+#define GrGLStencilBuffer_DEFINED
+
+#include "GrGLInterface.h"
+#include "GrStencilBuffer.h"
+
+class GrGLStencilBuffer : public GrStencilBuffer {
+public:
+    static const GrGLenum kUnknownInternalFormat = ~0;
+    struct Format {
+        GrGLenum  fInternalFormat;
+        GrGLuint  fStencilBits;
+        GrGLuint  fTotalBits;
+        bool      fPacked;
+    };
+
+    GrGLStencilBuffer(GrGpu* gpu, GrGLint rbid, 
+                      int width, int height,
+                      const Format& format) 
+        : GrStencilBuffer(gpu, width, height, format.fStencilBits)
+        , fFormat(format)
+        , fRenderbufferID(rbid) {
+    }
+
+    virtual ~GrGLStencilBuffer() {
+        this->release();
+    }
+
+    virtual size_t sizeInBytes() const {
+        return this->width() * this->height() * fFormat.fTotalBits;
+    }
+
+    GrGLuint renderbufferID() const {
+        return fRenderbufferID;
+    }
+
+    const Format& format() const {
+        return fFormat;
+    }
+
+protected:
+    virtual void onRelease() {
+        if (0 != fRenderbufferID) {
+            GR_GL(DeleteRenderbuffers(1, &fRenderbufferID));
+            fRenderbufferID = 0;
+        }
+    }
+
+    virtual void onAbandon() {
+        fRenderbufferID = 0;
+    }
+
+private:
+    Format fFormat;
+    // may be zero for external SBs associated with external RTs
+    // (we don't require the client to give us the id, just tell
+    // us how many bits of stencil there are).
+    GrGLuint fRenderbufferID;
+
+    typedef GrStencilBuffer INHERITED;
+};
+
+#endif
index c89dd4e4bb34b5e1cce1bc65d66949124f8e4970..be84e270d5cd1c20965a55ee1b3d221df0600dc4 100644 (file)
@@ -8,12 +8,12 @@
 
 
 #include "GrGpu.h"
-#include "GrTextStrike.h"
+#include "GrBufferAllocPool.h"
 #include "GrClipIterator.h"
 #include "GrIndexBuffer.h"
-#include "GrVertexBuffer.h"
-#include "GrBufferAllocPool.h"
 #include "GrPathRenderer.h"
+#include "GrGLStencilBuffer.h"
+#include "GrVertexBuffer.h"
 
 // probably makes no sense for this to be less than a page
 static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
@@ -140,7 +140,24 @@ void GrGpu::unimpl(const char msg[]) {
 GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
                                 const void* srcData, size_t rowBytes) {
     this->handleDirtyContext();
-    return this->onCreateTexture(desc, srcData, rowBytes);
+    GrTexture* tex = this->onCreateTexture(desc, srcData, rowBytes);
+    if (NULL != tex && 
+        (kRenderTarget_GrTextureFlagBit & desc.fFlags) &&
+        !(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
+        GrAssert(NULL != tex->asRenderTarget());
+        // TODO: defer this and attach dynamically
+        if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) {
+            tex->unref();
+            return NULL;
+        }
+    }
+    return tex;
+}
+
+bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
+    // TODO: use a cache of stencil buffers rather than create per-rt.
+    return this->createStencilBufferForRenderTarget(rt, rt->width(),
+                                                    rt->height());
 }
 
 GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
@@ -398,14 +415,22 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
         fClipInStencil = !fClip.isRect() && !fClip.isEmpty() && 
                          !bounds.isEmpty();
 
+        // TODO: dynamically attach a SB when needed.
+        GrStencilBuffer* stencilBuffer = rt.getStencilBuffer();
+        if (fClipInStencil && NULL == stencilBuffer) {
+            return false;
+        }
+
         if (fClipInStencil &&
-            fClip != rt.fLastStencilClip) {
+            stencilBuffer->mustRenderClip(fClip, rt.width(), rt.height())) {
+
+            stencilBuffer->setLastClip(fClip, rt.width(), rt.height());
 
-            rt.fLastStencilClip = fClip;
             // we set the current clip to the bounds so that our recursive
             // draws are scissored to them. We use the copy of the complex clip
-            // in the rt to render
-            const GrClip& clip = rt.fLastStencilClip;
+            // we just stashed on the SB to render from. We set it back after
+            // we finish drawing it into the stencil.
+            const GrClip& clip = stencilBuffer->getLastClip();
             fClip.setFromRect(bounds);
 
             AutoStateRestore asr(this);
@@ -420,7 +445,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
             this->disableState(kNoColorWrites_StateBit);
 #endif
             int count = clip.getElementCount();
-            int clipBit = rt.stencilBits();
+            int clipBit = stencilBuffer->bits();
             clipBit = (1 << (clipBit-1));
 
             // often we'll see the first two elements of the clip are
index 249897246c59a3322b1ce61fe098b8bf14fc88f0..9586c12f91501744a8f0efc398ca4122ceea0951 100644 (file)
@@ -8,6 +8,7 @@
 
 
 #include "GrGpuGL.h"
+#include "GrGLStencilBuffer.h"
 #include "GrTypes.h"
 #include "SkTemplates.h"
 
@@ -515,9 +516,14 @@ GrGpuGL::GrGpuGL()
     }
 
     fLastSuccessfulStencilFmtIdx = 0;
+
+    fStencilClearFBO = 0;
 }
 
 GrGpuGL::~GrGpuGL() {
+    if (fStencilClearFBO) {
+        GR_GL(DeleteFramebuffers(1, &fStencilClearFBO));
+    }
 }
 
 void GrGpuGL::resetContext() {
@@ -589,6 +595,21 @@ void GrGpuGL::resetContext() {
     fHWDrawState.fRenderTarget = NULL;
 }
 
+void GrGpuGL::abandonResources() {
+    INHERITED::abandonResources();
+
+    fStencilClearFBO = 0;
+}
+
+void GrGpuGL::releaseResources() {
+    INHERITED::releaseResources();
+
+    if (fStencilClearFBO) {
+        GR_GL(DeleteFramebuffers(1, &fStencilClearFBO));
+        fStencilClearFBO = 0;
+    }
+}
+
 GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) {
 
     bool isTexture = kTexture_GrPlatformSurfaceType == desc.fSurfaceType ||
@@ -597,6 +618,8 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
                           kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
 
     GrGLRenderTarget::Desc rtDesc;
+    GrGLStencilBuffer* sb = NULL;
+
     if (isRenderTarget) {
         rtDesc.fRTFBOID = desc.fPlatformRenderTarget;
 #if GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
@@ -615,7 +638,6 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
         }
         // we don't know what the RB ids are without glGets and we don't care
         // since we aren't responsible for deleting them.
-        rtDesc.fStencilRenderbufferID = 0;
         rtDesc.fMSColorRenderbufferID = 0;
 #if GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
         rtDesc.fSampleCnt = desc.fSampleCnt;
@@ -629,7 +651,15 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
             rtDesc.fSampleCnt = 0;
         }
 #endif
-        rtDesc.fStencilBits = desc.fStencilBits;
+        if (desc.fStencilBits) {
+            GrGLStencilBuffer::Format format;
+            format.fInternalFormat = GrGLStencilBuffer::kUnknownInternalFormat;
+            format.fPacked = false;
+            format.fStencilBits = desc.fStencilBits;
+            format.fTotalBits = desc.fStencilBits;
+            sb = new GrGLStencilBuffer(this, 0, desc.fWidth,
+                                       desc.fHeight, format);
+        }
         rtDesc.fOwnIDs = false;
     }
 
@@ -655,7 +685,9 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
 
         params.invalidate(); // rather than do glGets.
         if (isRenderTarget) {
-            return new GrGLTexture(this, texDesc, rtDesc, params);
+            GrTexture* tex = new GrGLTexture(this, texDesc, rtDesc, params);
+            tex->asRenderTarget()->setStencilBuffer(sb);
+            return tex;
         } else {
             return new GrGLTexture(this, texDesc, params);
         }
@@ -666,7 +698,9 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
         viewport.fWidth  = desc.fWidth;
         viewport.fHeight = desc.fHeight;
 
-        return new GrGLRenderTarget(this, rtDesc, viewport);
+        GrGLRenderTarget* rt =  new GrGLRenderTarget(this, rtDesc, viewport);
+        rt->setStencilBuffer(sb);
+        return rt;
     }
 }
 
@@ -815,14 +849,25 @@ GrRenderTarget* GrGpuGL::onCreateRenderTargetFrom3DApiState() {
     GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, (GrGLint*)&rtDesc.fRTFBOID);
     rtDesc.fTexFBOID = rtDesc.fRTFBOID;
     rtDesc.fMSColorRenderbufferID = 0;
-    rtDesc.fStencilRenderbufferID = 0;
 
     bool arbFBO = (GR_GL_SUPPORT_DESKTOP && (fGLVersion > 3.0 ||
                    this->hasExtension("GL_ARB_framebuffer_object")));
 
     GrGLIRect viewport;
     viewport.setFromGLViewport();
-    rtDesc.fStencilBits = get_fbo_stencil_bits(arbFBO);
+    int stencilBits = get_fbo_stencil_bits(arbFBO);
+
+    GrGLStencilBuffer* sb = NULL;
+    if (stencilBits) {
+        GrGLStencilBuffer::Format format;
+        // we could query this but we don't really need it
+        format.fInternalFormat = GrGLStencilBuffer::kUnknownInternalFormat;
+        format.fPacked = false;
+        format.fStencilBits = stencilBits;
+        format.fTotalBits = stencilBits;
+        sb = new GrGLStencilBuffer(this, 0, viewport.fWidth,
+                                   viewport.fHeight, format);
+    }
 
     GR_GL_GetIntegerv(GR_GL_SAMPLES, &rtDesc.fSampleCnt);
     GrGLenum fmat = get_fbo_color_format();
@@ -837,10 +882,13 @@ GrRenderTarget* GrGpuGL::onCreateRenderTargetFrom3DApiState() {
 
     rtDesc.fOwnIDs = false;
 
-    return new GrGLRenderTarget(this, rtDesc, viewport);
+    GrGLRenderTarget* target = new GrGLRenderTarget(this, rtDesc, viewport);
+    target->setStencilBuffer(sb);
+    return target;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+static const GrGLuint kUnknownBitCount = ~0;
 
 void GrGpuGL::setupStencilFormats() {
 
@@ -849,12 +897,14 @@ void GrGpuGL::setupStencilFormats() {
 
     // these consts are in order of most preferred to least preferred
     // we don't bother with GL_STENCIL_INDEX1 or GL_DEPTH32F_STENCIL8
-    static const StencilFormat gS8    = {GR_GL_STENCIL_INDEX8,     8,                 false};
-    static const StencilFormat gS16   = {GR_GL_STENCIL_INDEX16,    16,                false};
-    static const StencilFormat gD24S8 = {GR_GL_DEPTH24_STENCIL8,   8,                 true };
-    static const StencilFormat gS4    = {GR_GL_STENCIL_INDEX4,     4,                 false};
-    static const StencilFormat gS     = {GR_GL_STENCIL_INDEX,      gUNKNOWN_BITCOUNT, false};
-    static const StencilFormat gDS    = {GR_GL_DEPTH_STENCIL,      gUNKNOWN_BITCOUNT, true };
+    static const GrGLStencilBuffer::Format
+                  // internal Format      stencil bits      total bits        packed?
+        gS8    = {GR_GL_STENCIL_INDEX8,   8,                8,                false},
+        gS16   = {GR_GL_STENCIL_INDEX16,  16,               16,               false},
+        gD24S8 = {GR_GL_DEPTH24_STENCIL8, 8,                32,               true },
+        gS4    = {GR_GL_STENCIL_INDEX4,   4,                4,                false},
+        gS     = {GR_GL_STENCIL_INDEX,    kUnknownBitCount, kUnknownBitCount, false},
+        gDS    = {GR_GL_DEPTH_STENCIL,    kUnknownBitCount, kUnknownBitCount, true };
 
     if (GR_GL_SUPPORT_DESKTOP) {
         bool supportsPackedDS = fGLVersion >= 3.0f || 
@@ -1036,6 +1086,86 @@ void GrGpuGL::allocateAndUploadTexData(const GrGLTexture::Desc& desc,
     }
 }
 
+bool GrGpuGL::createRenderTargetObjects(int width, int height,
+                                        GrGLuint texID,
+                                        GrGLRenderTarget::Desc* desc) {
+    desc->fMSColorRenderbufferID = 0;
+    desc->fRTFBOID = 0;
+    desc->fTexFBOID = 0;
+    desc->fOwnIDs = true;
+
+    GrGLenum status;
+    GrGLint err;
+
+    GR_GL(GenFramebuffers(1, &desc->fTexFBOID));
+    if (!desc->fTexFBOID) {
+        goto FAILED;
+    }
+    
+    GrGLenum msColorFormat;
+
+    // If we are using multisampling we will create two FBOS. We render
+    // to one and then resolve to the texture bound to the other.
+    if (desc->fSampleCnt > 1 && kNone_MSFBO != fMSFBOType) {
+        GR_GL(GenFramebuffers(1, &desc->fRTFBOID));
+        GR_GL(GenRenderbuffers(1, &desc->fMSColorRenderbufferID));
+        if (!desc->fRTFBOID ||
+            !desc->fMSColorRenderbufferID || 
+            !this->fboInternalFormat(desc->fConfig, &msColorFormat)) {
+            goto FAILED;
+        }
+    } else {
+        desc->fRTFBOID = desc->fTexFBOID;
+    }
+
+    if (desc->fRTFBOID != desc->fTexFBOID) {
+        GrAssert(desc->fSampleCnt > 1);
+        GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER,
+                               desc->fMSColorRenderbufferID));
+        GR_GL_NO_ERR(RenderbufferStorageMultisample(GR_GL_RENDERBUFFER, 
+                                                    desc->fSampleCnt,
+                                                    msColorFormat,
+                                                    width, height));
+        err = GrGLGetGLInterface()->fGetError();
+        if (err != GR_GL_NO_ERROR) {
+            goto FAILED;
+        }
+        GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fRTFBOID));
+        GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, 
+                                      GR_GL_COLOR_ATTACHMENT0,
+                                      GR_GL_RENDERBUFFER,
+                                      desc->fMSColorRenderbufferID));
+        GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+        if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
+            goto FAILED;
+        }
+    }
+    GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fTexFBOID));
+
+    GR_GL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
+                               GR_GL_COLOR_ATTACHMENT0,
+                               GR_GL_TEXTURE_2D,
+                               texID, 0));
+    status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+    if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
+        goto FAILED;
+    }
+
+    return true;
+
+FAILED:
+    if (desc->fMSColorRenderbufferID) {
+        GR_GL(DeleteRenderbuffers(1, &desc->fMSColorRenderbufferID));
+    }
+    if (desc->fRTFBOID != desc->fTexFBOID) {
+        GR_GL(DeleteFramebuffers(1, &desc->fRTFBOID));
+    }
+    if (desc->fTexFBOID) {
+        GR_GL(DeleteFramebuffers(1, &desc->fTexFBOID));
+    }
+    return false;
+}
+
 // good to set a break-point here to know when createTexture fails
 static GrTexture* return_null_texture() {
 //    GrAssert(!"null texture");
@@ -1073,7 +1203,6 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
     glTexDesc.fFormat        = desc.fFormat;
     glTexDesc.fOwnsID        = true;
 
-    glRTDesc.fStencilRenderbufferID = 0;
     glRTDesc.fMSColorRenderbufferID = 0;
     glRTDesc.fRTFBOID = 0;
     glRTDesc.fTexFBOID = 0;
@@ -1092,7 +1221,7 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
     // can be drawn to by the outside world without the client having
     // to render upside down.
     glTexDesc.fOrientation = renderTarget ? GrGLTexture::kBottomUp_Orientation :
-                                         GrGLTexture::kTopDown_Orientation;
+                                            GrGLTexture::kTopDown_Orientation;
 
     GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
     glRTDesc.fSampleCnt = fAASamples[desc.fAALevel];
@@ -1109,9 +1238,9 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
         }
 
         glTexDesc.fAllocWidth = GrMax(fMinRenderTargetWidth,
-                                   glTexDesc.fAllocWidth);
+                                      glTexDesc.fAllocWidth);
         glTexDesc.fAllocHeight = GrMax(fMinRenderTargetHeight,
-                                    glTexDesc.fAllocHeight);
+                                       glTexDesc.fAllocHeight);
         if (glTexDesc.fAllocWidth > fMaxRenderTargetSize ||
             glTexDesc.fAllocHeight > fMaxRenderTargetSize) {
             return return_null_texture();
@@ -1147,198 +1276,220 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
 
     this->allocateAndUploadTexData(glTexDesc, internalFormat,srcData, rowBytes);
 
+    GrGLTexture* tex;
     if (renderTarget) {
         GrGLenum msColorRenderbufferFormat = -1;
 #if GR_COLLECT_STATS
         ++fStats.fRenderTargetCreateCnt;
 #endif
-        bool failed = true;
-        GrGLenum status;
-        GrGLint err;
-
-        GR_GL(GenFramebuffers(1, &glRTDesc.fTexFBOID));
-        GrAssert(glRTDesc.fTexFBOID);
-
-        // If we are using multisampling and we will create two FBOS We render
-        // to one and then resolve to the texture bound to the other.
-        if (glRTDesc.fSampleCnt > 0 && kNone_MSFBO != fMSFBOType) {
-            GR_GL(GenFramebuffers(1, &glRTDesc.fRTFBOID));
-            GrAssert(0 != glRTDesc.fRTFBOID);
-            GR_GL(GenRenderbuffers(1, &glRTDesc.fMSColorRenderbufferID));
-            GrAssert(0 != glRTDesc.fMSColorRenderbufferID);
-            if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
-                GR_GL(DeleteRenderbuffers(1, &glRTDesc.fMSColorRenderbufferID));
-                GR_GL(DeleteTextures(1, &glTexDesc.fTextureID));
-                GR_GL(DeleteFramebuffers(1, &glRTDesc.fTexFBOID));
-                GR_GL(DeleteFramebuffers(1, &glRTDesc.fRTFBOID));
-                return return_null_texture();
-            }
-        } else {
-            glRTDesc.fRTFBOID = glRTDesc.fTexFBOID;
-        }
-        if (!(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
-            GR_GL(GenRenderbuffers(1, &glRTDesc.fStencilRenderbufferID));
-            GrAssert(0 != glRTDesc.fStencilRenderbufferID);
+        if (!this->createRenderTargetObjects(glTexDesc.fAllocWidth,
+                                             glTexDesc.fAllocHeight,
+                                             glTexDesc.fTextureID,
+                                             &glRTDesc)) {
+            GR_GL(DeleteTextures(1, &glTexDesc.fTextureID));
+            return return_null_texture();
         }
+        tex = new GrGLTexture(this, glTexDesc, glRTDesc, DEFAULT_PARAMS);
+    } else {
+        tex = new GrGLTexture(this, glTexDesc, DEFAULT_PARAMS);
+    }
+#ifdef TRACE_TEXTURE_CREATION
+    GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
+             tex->fTextureID, width, height, tex->fUploadByteCount);
+#endif
+    return tex;
+}
 
-        // someone suggested that some systems might require
-        // unbinding the texture before we call FramebufferTexture2D
-        // (seems unlikely)
-        GR_GL(BindTexture(GR_GL_TEXTURE_2D, 0));
+namespace {
+void inline get_stencil_rb_sizes(GrGLuint rb, GrGLStencilBuffer::Format* format) {
+    // we shouldn't ever know one size and not the other
+    GrAssert((kUnknownBitCount == format->fStencilBits) ==
+             (kUnknownBitCount == format->fTotalBits));
+    if (kUnknownBitCount == format->fStencilBits) {
+        GR_GL_GetRenderbufferParameteriv(GR_GL_RENDERBUFFER,
+                                         GR_GL_RENDERBUFFER_STENCIL_SIZE,
+                                         (GrGLint*)&format->fStencilBits);
+        if (format->fPacked) {
+            GR_GL_GetRenderbufferParameteriv(GR_GL_RENDERBUFFER,
+                                             GR_GL_RENDERBUFFER_DEPTH_SIZE,
+                                             (GrGLint*)&format->fTotalBits);
+            format->fTotalBits += format->fStencilBits;
+        } else {
+            format->fTotalBits = format->fStencilBits;
+        }
+    }
+}
+}
 
-        err = ~GR_GL_NO_ERROR;
+bool GrGpuGL::createStencilBufferForRenderTarget(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 RT that isnt also a texture).
+    GrAssert(rt->asTexture());
+    // if this thing is bloated for NPOT reasons we'll have to bloat the SB 
+    // as well.
+    GrGLTexture* tex = (GrGLTexture*) rt->asTexture();
+    width = GrMax(width, tex->allocWidth());
+    height = GrMax(height, tex->allocWidth());
+
+    int samples = rt->numSamples();
+    GrGLuint sbID;
+    GR_GL(GenRenderbuffers(1, &sbID));
+    if (!sbID) {
+        return false;
+    }
 
-        int stencilFmtCnt;
-        if (glRTDesc.fStencilRenderbufferID) {
-            stencilFmtCnt = fStencilFormats.count();
+    GrGLStencilBuffer* sb = NULL;
+
+    int stencilFmtCnt = fStencilFormats.count();
+    for (int i = 0; i < stencilFmtCnt; ++i) {
+        GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbID));
+        // we start with the last stencil format that succeeded in hopes
+        // that we won't go through this loop more than once after the
+        // first (painful) stencil creation.
+        int sIdx = (i + fLastSuccessfulStencilFmtIdx) % stencilFmtCnt;
+        // we do this if so that we don't call the multisample
+        // version on a GL that doesn't have an MSAA extension.
+        if (samples > 1) {
+            GR_GL_NO_ERR(RenderbufferStorageMultisample(
+                                        GR_GL_RENDERBUFFER,
+                                        samples,
+                                        fStencilFormats[sIdx].fInternalFormat,
+                                        width,
+                                        height));
         } else {
-            stencilFmtCnt = 1; // only 1 attempt when we don't need a stencil
-        }
-
-        for (int i = 0; i < stencilFmtCnt; ++i) {
-            // we start with the last stencil format that succeeded in hopes
-            // that we won't go through this loop more than once after the
-            // first (painful) stencil creation.
-            int sIdx = (i + fLastSuccessfulStencilFmtIdx) % stencilFmtCnt;
-            
-            if (glRTDesc.fStencilRenderbufferID) {
-                GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER,
-                                       glRTDesc.fStencilRenderbufferID));
-                if (glRTDesc.fSampleCnt > 0) {
-                    GR_GL_NO_ERR(RenderbufferStorageMultisample(
-                                                GR_GL_RENDERBUFFER,
-                                                glRTDesc.fSampleCnt,
-                                                fStencilFormats[sIdx].fEnum,
-                                                glTexDesc.fAllocWidth,
-                                                glTexDesc.fAllocHeight));
-                } else {
-                    GR_GL_NO_ERR(RenderbufferStorage(GR_GL_RENDERBUFFER,
-                                                     fStencilFormats[sIdx].fEnum,
-                                                     glTexDesc.fAllocWidth,
-                                                     glTexDesc.fAllocHeight));
-                }
-                err = GrGLGetGLInterface()->fGetError();
-                if (err != GR_GL_NO_ERROR) {
-                    continue;
-                }
-            }
-            if (glRTDesc.fRTFBOID != glRTDesc.fTexFBOID) {
-                GrAssert(glRTDesc.fSampleCnt > 0);
-                GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER,
-                                       glRTDesc.fMSColorRenderbufferID));
-                GR_GL_NO_ERR(RenderbufferStorageMultisample(
-                                                   GR_GL_RENDERBUFFER,
-                                                   glRTDesc.fSampleCnt,
-                                                   msColorRenderbufferFormat,
-                                                   glTexDesc.fAllocWidth,
-                                                   glTexDesc.fAllocHeight));
-                err = GrGLGetGLInterface()->fGetError();
-                if (err != GR_GL_NO_ERROR) {
-                    continue;
-                }
-            }
-            GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, glRTDesc.fTexFBOID));
+            GR_GL_NO_ERR(RenderbufferStorage(GR_GL_RENDERBUFFER,
+                                        fStencilFormats[sIdx].fInternalFormat,
+                                        width, height));
+        }
 
-#if GR_COLLECT_STATS
-            ++fStats.fRenderTargetChngCnt;
-#endif
-            GR_GL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
-                                        GR_GL_COLOR_ATTACHMENT0,
-                                        GR_GL_TEXTURE_2D,
-                                        glTexDesc.fTextureID, 0));
-            if (glRTDesc.fRTFBOID != glRTDesc.fTexFBOID) {
-                GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
-                if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
-                    continue;
+        GrGLenum err = GrGLGetGLInterface()->fGetError();
+        if (err == GR_GL_NO_ERROR) {
+            // After sized formats we attempt an unsized format and take whatever
+            // sizes GL gives us. In that case we query for the size.
+            GrGLStencilBuffer::Format format = fStencilFormats[sIdx];
+            get_stencil_rb_sizes(sbID, &format);
+            sb = new GrGLStencilBuffer(this, sbID, width, height, format);
+            if (this->attachStencilBufferToRenderTarget(sb, rt)) {
+                fLastSuccessfulStencilFmtIdx = sIdx;
+                sb->unref();
+                fHWDrawState.fRenderTarget = NULL;
+                // initial clear zeros the entire sb by attaching it alone
+                // to an fbo (that we create here on demand).
+                if (!fStencilClearFBO) {
+                    GR_GL(GenFramebuffers(1, &fStencilClearFBO));
+                    if (0 == fStencilClearFBO) {
+                        rt->setStencilBuffer(NULL);
+                        return false;
+                    }
+                    GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBO));
+                    if (GR_GL_SUPPORT_DESKTOP) {
+                        // We won't be binding a color buffer, set the draw
+                        // buffer to NONE to avoid
+                        // FRAMEBUFFER_INCOMPLETE_READ_BUFFER.
+                        GR_GL(DrawBuffer(GR_GL_NONE));
+                        // We bind to FRAMEBUFFER not DRAW_FRAMEBUFFER or
+                        // READ_FRAMEBUFFER because earlier versions of desktop
+                        // GL and unextended ES only have FRAMEBUFFER. But this
+                        // means we're binding both READ and DRAW when 
+                        // FramebufferBlit is supported. So to avoid 
+                        // FRAMEBUFFER_INCOMPLETE_READ_BUFFER status we also set
+                        // the read buffer to none.
+                        GR_GL(ReadBuffer(GR_GL_NONE));
+                        // DrawBuffer and ReadBuffer are framebuffer state so
+                        // we only have to set these the first time.
+                    }
+                } else {
+                    GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBO));
                 }
-                GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, glRTDesc.fRTFBOID));
-            #if GR_COLLECT_STATS
-                ++fStats.fRenderTargetChngCnt;
-            #endif
                 GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                              GR_GL_COLOR_ATTACHMENT0,
-                                              GR_GL_RENDERBUFFER,
-                                              glRTDesc.fMSColorRenderbufferID));
-
-            }
-            if (glRTDesc.fStencilRenderbufferID) {
-                // bind the stencil to rt fbo if present, othewise the tex fbo
-                GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                              GR_GL_STENCIL_ATTACHMENT,
-                                              GR_GL_RENDERBUFFER,
-                                              glRTDesc.fStencilRenderbufferID));
-                // if it is a packed format bind to depth also, otherwise 
-                // we may get an unsupported fbo completeness result
+                                                GR_GL_STENCIL_ATTACHMENT,
+                                                GR_GL_RENDERBUFFER, sbID));
                 if (fStencilFormats[sIdx].fPacked) {
                     GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                                  GR_GL_DEPTH_ATTACHMENT,
-                                                  GR_GL_RENDERBUFFER,
-                                                  glRTDesc.fStencilRenderbufferID));
-                }
-            }
-            status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
-
-            if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
-                // undo the depth bind
-                if (glRTDesc.fStencilRenderbufferID && 
-                    fStencilFormats[sIdx].fPacked) {
-                    GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                                  GR_GL_DEPTH_ATTACHMENT,
-                                                  GR_GL_RENDERBUFFER, 0));
-                }
-                continue;
-            }
-            // we're successful!
-            failed = false;
-            if (glRTDesc.fStencilRenderbufferID) {
-                fLastSuccessfulStencilFmtIdx = sIdx;
-                if (gUNKNOWN_BITCOUNT == fStencilFormats[sIdx].fBits) {
-                    GR_GL_GetIntegerv(GR_GL_STENCIL_BITS, (GrGLint*)&glRTDesc.fStencilBits);
+                                                GR_GL_DEPTH_ATTACHMENT,
+                                                GR_GL_RENDERBUFFER, sbID));
                 } else {
-                    glRTDesc.fStencilBits = fStencilFormats[sIdx].fBits;
+                    GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                                    GR_GL_DEPTH_ATTACHMENT,
+                                                    GR_GL_RENDERBUFFER, 0));
                 }
-            }
-            break;
-        }
-        if (failed) {
-            if (glRTDesc.fStencilRenderbufferID) {
-                GR_GL(DeleteRenderbuffers(1, &glRTDesc.fStencilRenderbufferID));
-            }
-            if (glRTDesc.fMSColorRenderbufferID) {
-                GR_GL(DeleteRenderbuffers(1, &glRTDesc.fMSColorRenderbufferID));
-            }
-            if (glRTDesc.fRTFBOID != glRTDesc.fTexFBOID) {
-                GR_GL(DeleteFramebuffers(1, &glRTDesc.fRTFBOID));
-            }
-            if (glRTDesc.fTexFBOID) {
-                GR_GL(DeleteFramebuffers(1, &glRTDesc.fTexFBOID));
-            }
-            GR_GL(DeleteTextures(1, &glTexDesc.fTextureID));
-            return return_null_texture();
+#if GR_DEBUG
+                GrGLenum status = 
+                    GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+                GrAssert(GR_GL_FRAMEBUFFER_COMPLETE == status);
+#endif
+
+                this->flushScissor(NULL);
+                GR_GL(ClearStencil(0));
+                GR_GL(Clear(GR_GL_STENCIL_BUFFER_BIT));
+                return true;
+           }
+           sb->abandon(); // otherwise we lose sbID
+           sb->unref();
         }
     }
-#ifdef TRACE_TEXTURE_CREATION
-    GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
-             tex->fTextureID, width, height, tex->fUploadByteCount);
+    GR_GL(DeleteRenderbuffers(1, &sbID));
+    return NULL;
+}
+
+bool GrGpuGL::attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
+                                                GrRenderTarget* rt) {
+    GrGLRenderTarget* glrt = (GrGLRenderTarget*) rt;
+
+    GrGLuint fbo = glrt->renderFBOID();
+
+    if (NULL == sb) {
+        if (NULL != rt->getStencilBuffer()) {
+            GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                          GR_GL_STENCIL_ATTACHMENT,
+                                          GR_GL_RENDERBUFFER, 0));
+            GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                          GR_GL_DEPTH_ATTACHMENT,
+                                          GR_GL_RENDERBUFFER, 0));
+#if GR_DEBUG
+            GrGLenum status = 
+                GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+            GrAssert(GR_GL_FRAMEBUFFER_COMPLETE == status);
 #endif
-    if (renderTarget) {
-        GrGLTexture* tex = new GrGLTexture(this, glTexDesc, 
-                                           glRTDesc, DEFAULT_PARAMS);
-        GrRenderTarget* rt = tex->asRenderTarget();
-        // We've messed with FBO state but may not have set the correct viewport
-        // so just dirty the rendertarget state to force a resend.
+        }
+        return true;
+    } else {
+        GrGLStencilBuffer* glsb = (GrGLStencilBuffer*) sb;
+        GrGLuint rb = glsb->renderbufferID();
+
         fHWDrawState.fRenderTarget = NULL;
 
-        // clear the new stencil buffer if we have one
-        if (!(desc.fFlags & kNoStencil_GrTextureFlagBit)) {
-            GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
-            fCurrDrawState.fRenderTarget = rt;
-            this->clearStencil(0, ~0);
-            fCurrDrawState.fRenderTarget = rtSave;
+        GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo));
+        GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                      GR_GL_STENCIL_ATTACHMENT,
+                                      GR_GL_RENDERBUFFER, rb));
+        if (glsb->format().fPacked) {
+            GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                          GR_GL_DEPTH_ATTACHMENT,
+                                          GR_GL_RENDERBUFFER, rb));
+        } else {
+            GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                          GR_GL_DEPTH_ATTACHMENT,
+                                          GR_GL_RENDERBUFFER, 0));
+        }
+
+        GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+        if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
+            GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                          GR_GL_STENCIL_ATTACHMENT,
+                                          GR_GL_RENDERBUFFER, 0));
+            if (glsb->format().fPacked) {
+                GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+                                              GR_GL_DEPTH_ATTACHMENT,
+                                              GR_GL_RENDERBUFFER, 0));
+            }
+            return false;
+        } else {
+            rt->setStencilBuffer(sb);
+            return true;
         }
-        return tex;
-    } else {
-        return new GrGLTexture(this, glTexDesc, DEFAULT_PARAMS);
     }
 }
 
@@ -1468,20 +1619,25 @@ void GrGpuGL::clearStencil(uint32_t value, uint32_t mask) {
 
 void GrGpuGL::clearStencilClip(const GrIRect& rect) {
     GrAssert(NULL != fCurrDrawState.fRenderTarget);
+
+    // this should only be called internally when we know we have a
+    // stencil buffer.
+    GrAssert(NULL != fCurrDrawState.fRenderTarget->getStencilBuffer());
 #if 0
-    GrGLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
+    GrGLint stencilBitCount = 
+        fCurrDrawState.fRenderTarget->getStencilBuffer()->bits();
     GrAssert(stencilBitCount > 0);
     GrGLint clipStencilMask  = (1 << (stencilBitCount - 1));
 #else
     // we could just clear the clip bit but when we go through
-    // angle a partial stencil mask will cause clears to be
+    // ANGLE a partial stencil mask will cause clears to be
     // turned into draws. Our contract on GrDrawTarget says that
     // changing the clip between stencil passes may or may not
     // zero the client's clip bits. So we just clear the whole thing.
     static const GrGLint clipStencilMask  = ~0;
 #endif
     this->flushRenderTarget(&GrIRect::EmptyIRect());
-    flushScissor(&rect);
+    this->flushScissor(&rect);
     GR_GL(StencilMask(clipStencilMask));
     GR_GL(ClearStencil(0));
     GR_GL(Clear(GR_GL_STENCIL_BUFFER_BIT));
@@ -1794,7 +1950,13 @@ void GrGpuGL::flushStencil() {
                 GrAssert(settings->fFrontFailOp != kDecWrap_StencilOp);
             }
     #endif
-            int stencilBits = fCurrDrawState.fRenderTarget->stencilBits();
+            int stencilBits = 0;
+            GrStencilBuffer* stencilBuffer = 
+                            fCurrDrawState.fRenderTarget->getStencilBuffer();
+            if (NULL != stencilBuffer) {
+                stencilBits = stencilBuffer->bits();
+            }
+            // TODO: dynamically attach a stencil buffer
             GrAssert(stencilBits ||
                      (GrStencilSettings::gDisabled ==
                       fCurrDrawState.fStencilSettings));
index 59e32cf5ae77db59a3905e9a6e0048df975369d4..6dbc9d7dd5bb893b6c5368cecf6d70851f2c6cbd 100644 (file)
 #define GrGpuGL_DEFINED
 
 #include "GrGpu.h"
+#include "GrGLIndexBuffer.h"
 #include "GrGLIRect.h"
+#include "GrGLStencilBuffer.h"
 #include "GrGLTexture.h"
-
 #include "GrGLVertexBuffer.h"
-#include "GrGLIndexBuffer.h"
 
 #include "SkString.h"
 
@@ -69,8 +69,9 @@ protected:
     } fHWBounds;
 
     // GrGpu overrides
-    // overrides from GrGpu
     virtual void resetContext();
+    virtual void abandonResources();
+    virtual void releaseResources();
 
     virtual GrTexture* onCreateTexture(const GrTextureDesc& desc,
                                        const void* srcData,
@@ -81,6 +82,10 @@ protected:
                                                bool dynamic);
     virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc);
     virtual GrRenderTarget* onCreateRenderTargetFrom3DApiState();
+    virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt,
+                                                    int width, int height);
+    virtual bool attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
+                                                   GrRenderTarget* rt);
 
     virtual void onClear(const GrIRect* rect, GrColor color);
 
@@ -173,12 +178,16 @@ private:
                       GrGLenum* internalFormat,
                       GrGLenum* format,
                       GrGLenum* type);
-    // helper for onCreateTexture
+    // helpers for onCreateTexture
     void allocateAndUploadTexData(const GrGLTexture::Desc& desc,
                                   GrGLenum internalFormat,
                                   const void* data,
                                   size_t rowBytes);
 
+    bool createRenderTargetObjects(int width, int height,
+                                   GrGLuint texID,
+                                   GrGLRenderTarget::Desc* desc);
+
     bool fboInternalFormat(GrPixelConfig config, GrGLenum* format);
 
     friend class GrGLVertexBuffer;
@@ -186,16 +195,13 @@ private:
     friend class GrGLTexture;
     friend class GrGLRenderTarget;
 
-    static const GrGLuint gUNKNOWN_BITCOUNT = ~0;
-
-    struct StencilFormat {
-        GrGLenum  fEnum;
-        GrGLuint  fBits;
-        bool      fPacked;
-    };
-
-    GrTArray<StencilFormat, true> fStencilFormats;
 
+    GrTArray<GrGLStencilBuffer::Format, true> fStencilFormats;
+    // we want to clear stencil buffers when they are created. We want to clear
+    // the entire buffer even if it is larger than the color attachment. We
+    // attach it to this fbo with no color attachment to do the initial clear.
+    GrGLuint fStencilClearFBO;
+    
     bool fHWBlendDisabled;
 
     GrGLuint fAASamples[4];
index 186fe8e55285a9381c608a0bd7fd705cca80cee0..042bc59395440c2c8f7b154e0c4a009cbe322472 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "GrContext.h"
 #include "GrGpu.h"
+#include "GrStencilBuffer.h"
 
 bool GrRenderTarget::readPixels(int left, int top, int width, int height,
                                 GrPixelConfig config, void* buffer) {
@@ -30,7 +31,7 @@ size_t GrRenderTarget::sizeInBytes() const {
     } else {
         colorBits = GrBytesPerPixel(fConfig);
     }
-    return fWidth * fHeight * (fStencilBits + colorBits);
+    return fWidth * fHeight * colorBits;
 }
 
 void GrRenderTarget::flagAsNeedingResolve(const GrIRect* rect) {
@@ -55,4 +56,8 @@ void GrRenderTarget::overrideResolveRect(const GrIRect rect) {
             fResolveRect.setLargestInverted();
         }
     }
+}
+
+void GrRenderTarget::setStencilBuffer(GrStencilBuffer* stencilBuffer) {
+    GrSafeAssign(fStencilBuffer, stencilBuffer);
 }
\ No newline at end of file
diff --git a/gpu/src/GrStencilBuffer.h b/gpu/src/GrStencilBuffer.h
new file mode 100644 (file)
index 0000000..34fbe11
--- /dev/null
@@ -0,0 +1,69 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrStencilBuffer_DEFINED
+#define GrStencilBuffer_DEFINED
+
+#include "GrClip.h"
+#include "GrResource.h"
+
+class GrStencilBuffer : public GrResource {
+public:
+    int width() const { return fWidth; }
+    int height() const { return fHeight; }
+    int bits() const { return fBits; }
+
+    // called to note the last clip drawn to this buffer.
+    void setLastClip(const GrClip& clip, int width, int height) {
+        fLastClip = clip;
+        fLastClipWidth = width;
+        fLastClipHeight = height;
+        GrAssert(width <= fWidth);
+        GrAssert(height <= fHeight);
+    }
+
+    // called to determine if we have to render the clip into SB.
+    bool mustRenderClip(const GrClip& clip, int width, int height) const {
+        // The clip is in device space. That is it doesn't scale to fit a
+        // smaller RT. It is just truncated on the right / bottom edges.
+        // Note that this assumes that the viewport origin never moves within
+        // the stencil buffer. This is valid today.
+        return width > fLastClipWidth ||
+               height > fLastClipHeight ||
+               clip != fLastClip;
+    }
+
+    const GrClip& getLastClip() const {
+        return fLastClip;
+    }
+
+protected:
+    GrStencilBuffer(GrGpu* gpu, int width, int height, int bits)
+        : GrResource(gpu)
+        , fWidth(width)
+        , fHeight(height)
+        , fBits(bits)
+        , fLastClip()
+        , fLastClipWidth(-1)
+        , fLastClipHeight(-1) {
+    }
+
+private:
+    int fWidth;
+    int fHeight;
+    int fBits;
+
+    GrClip     fLastClip;
+    int        fLastClipWidth;
+    int        fLastClipHeight;
+
+    typedef GrResource INHERITED;
+};
+
+#endif
index f25e158e3e5c329588b700764e0713798893a64c..f96e39cce34dd8fa78aa609476060ea614b76714 100644 (file)
         '../gpu/src/GrGLProgram.h',
         '../gpu/src/GrGLRenderTarget.cpp',
         '../gpu/src/GrGLRenderTarget.h',
+        '../gpu/src/GrGLStencilBuffer.h',
         '../gpu/src/GrGLTexture.cpp',
         '../gpu/src/GrGLTexture.h',
         '../gpu/src/GrGLUtil.cpp',
         '../gpu/src/GrResourceCache.cpp',
         '../gpu/src/GrResourceCache.h',
         '../gpu/src/GrStencil.cpp',
+        '../gpu/src/GrStencilBuffer.h',
         '../gpu/src/GrTesselatedPathRenderer.cpp',
         '../gpu/src/GrTextContext.cpp',
         '../gpu/src/GrTextStrike.cpp',