Reduce glGets for stencil bits.
Clean up GL vs Gr rect conventions for viewport and scissor.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@813 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 0423483..7ce8f35 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -242,9 +242,11 @@
 

 ///////////////////////////////////////////////////////////////////////////////

 

-GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,

-                                                      int width, int height) {

-    return fGpu->createPlatformRenderTarget(platformRenderTarget,

+GrRenderTarget* GrContext::createPlatformRenderTarget(

+                                                intptr_t platformRenderTarget,

+                                                int stencilBits,

+                                                int width, int height) {

+    return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits,

                                             width, height);

 }

 

diff --git a/gpu/src/GrGLIRect.h b/gpu/src/GrGLIRect.h
new file mode 100644
index 0000000..b8638c0
--- /dev/null
+++ b/gpu/src/GrGLIRect.h
@@ -0,0 +1,64 @@
+#include "GrGLConfig.h"
+
+#ifndef GrGLIRect_DEFINED
+#define GrGLIRect_DEFINED
+
+/**
+ * Helper struct for dealing with the fact that Ganesh and GL use different
+ * window coordinate systems (top-down vs bottom-up)
+ */
+struct GrGLIRect {
+    GLint   fLeft;
+    GLint   fBottom;
+    GLsizei fWidth;
+    GLsizei fHeight;
+
+    void pushToGLViewport() const {
+        GR_GL(Viewport(fLeft, fBottom, fWidth, fHeight)); 
+    }
+
+    void pushToGLScissor() const {
+        GR_GL(Scissor(fLeft, fBottom, fWidth, fHeight));
+    }
+
+    void setFromGLViewport() {
+        GR_STATIC_ASSERT(sizeof(*this) == 4*sizeof(GLint));
+        GR_GL_GetIntegerv(GL_VIEWPORT, (GLint*) this);
+    }
+
+    // sometimes we have a GrIRect from the client that we
+    // want to simultaneously make relative to GL's viewport
+    // and convert from top-down to bottom-up.
+    void setRelativeTo(const GrGLIRect& glRect,
+                       int leftOffset,
+                       int topOffset,
+                       int width,
+                       int height) {
+        fLeft = glRect.fLeft + leftOffset;
+        fWidth = width;
+        fBottom = glRect.fBottom + (glRect.fHeight - topOffset - height);
+        fHeight = height;
+
+        GrAssert(fLeft >= 0);
+        GrAssert(fWidth >= 0);
+        GrAssert(fBottom >= 0);
+        GrAssert(fHeight >= 0);
+    }
+
+    bool contains(const GrGLIRect& glRect) const {
+        return fLeft <= glRect.fLeft &&
+               fBottom <= glRect.fBottom &&
+               fLeft + fWidth >=  glRect.fLeft + glRect.fWidth &&
+               fBottom + fHeight >=  glRect.fBottom + glRect.fHeight;
+    }
+
+    void invalidate() {fLeft = fWidth = fBottom = fHeight = -1;}
+
+    bool operator ==(const GrGLIRect& glRect) const {
+        return 0 == memcmp(this, &glRect, sizeof(GrGLIRect));
+    }
+
+    bool operator !=(const GrGLIRect& glRect) const {return !(*this == glRect);}
+};
+
+#endif
\ No newline at end of file
diff --git a/gpu/src/GrGLTexture.cpp b/gpu/src/GrGLTexture.cpp
index 110535f..9fd1f57 100644
--- a/gpu/src/GrGLTexture.cpp
+++ b/gpu/src/GrGLTexture.cpp
@@ -18,20 +18,20 @@
 #include "GrGLTexture.h"
 #include "GrGpuGL.h"
 
-GrGLRenderTarget::GrGLRenderTarget(const GLRenderTargetIDs& ids, 
-                                   const GrIRect& viewport,
+GrGLRenderTarget::GrGLRenderTarget(const GLRenderTargetIDs& ids,
+                                   GLuint stencilBits,
+                                   const GrGLIRect& viewport,
                                    GrGLTexture* texture,
                                    GrGpuGL* gl) : INHERITED(texture) {
     fGL                     = gl;
     fRTFBOID                = ids.fRTFBOID;
     fTexFBOID               = ids.fTexFBOID;
     fStencilRenderbufferID  = ids.fStencilRenderbufferID;
+    fStencilBits            = stencilBits;
     fMSColorRenderbufferID  = ids.fMSColorRenderbufferID;
     fNeedsResolve           = false;
     fViewport               = viewport;
     fOwnIDs                 = ids.fOwnIDs;
-    // viewport should be GL's viewport with top >= bottom
-    GrAssert(viewport.height() <= 0);
 }
 
 GrGLRenderTarget::~GrGLRenderTarget() {
@@ -99,14 +99,15 @@
     GrAssert(0 != textureDesc.fTextureID);
 
     if (rtIDs.fTexFBOID) {
-        GrIRect vp;
+        // we render to the top left
+        GrGLIRect vp;
         vp.fLeft   = 0;
-        vp.fRight  = (int32_t) textureDesc.fContentWidth;
-        // viewport for GL is top > bottom 
-        vp.fTop    = (int32_t) textureDesc.fAllocHeight;
-        vp.fBottom = (int32_t) textureDesc.fAllocHeight - 
-                     (int32_t)textureDesc.fContentHeight;
-        fRenderTarget = new GrGLRenderTarget(rtIDs, vp, this, gl);
+        vp.fWidth  = textureDesc.fContentWidth;
+        vp.fHeight = textureDesc.fContentHeight;
+        vp.fBottom = textureDesc.fAllocHeight - textureDesc.fContentHeight;
+
+        fRenderTarget = new GrGLRenderTarget(rtIDs, textureDesc.fStencilBits, 
+                                             vp, this, gl);
     }
 }
 
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index ba13372..c3c8f18 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -458,11 +458,10 @@
         fHWDrawState.fSamplerStates[s].setMatrix(GrMatrix::InvalidMatrix());
     }
 
-    GR_GL(Scissor(0,0,0,0));
-    fHWBounds.fScissorRect.setLTRB(0,0,0,0);
+    fHWBounds.fScissorRect.invalidate();
     fHWBounds.fScissorEnabled = false;
     GR_GL(Disable(GL_SCISSOR_TEST));
-    fHWBounds.fViewportRect.setLTRB(-1,-1,-1,-1);
+    fHWBounds.fViewportRect.invalidate();
 
     // disabling the stencil test also disables
     // stencil buffer writes
@@ -491,24 +490,26 @@
 
 GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
                                                 intptr_t platformRenderTarget,
-                                                int width, int height) {
+                                                int stencilBits,
+                                                int width, 
+                                                int height) {
     GrGLRenderTarget::GLRenderTargetIDs rtIDs;
     rtIDs.fStencilRenderbufferID = 0;
     rtIDs.fMSColorRenderbufferID = 0;
     rtIDs.fTexFBOID              = 0;
     rtIDs.fOwnIDs                = false;
-
-    GrIRect viewport;
+    GrGLIRect viewport;
 
     // viewport is in GL coords (top >= bottom)
-    viewport.setLTRB(0, height, width, 0);
+    viewport.fLeft      = 0;
+    viewport.fBottom    = 0;
+    viewport.fWidth     = width;
+    viewport.fHeight    = height;
 
     rtIDs.fRTFBOID  = (GLuint)platformRenderTarget;
     rtIDs.fTexFBOID = (GLuint)platformRenderTarget;
 
-    GrGLRenderTarget* rt = new GrGLRenderTarget(rtIDs, viewport, NULL, this);
-
-    return rt;
+    return new GrGLRenderTarget(rtIDs, stencilBits, viewport, NULL, this);
 }
 
 GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiState() {
@@ -520,37 +521,37 @@
     rtIDs.fMSColorRenderbufferID = 0;
     rtIDs.fStencilRenderbufferID = 0;
 
-    GLint vp[4];
-    GR_GL_GetIntegerv(GL_VIEWPORT, vp);
-    GrIRect viewportRect;
-    viewportRect.setLTRB(vp[0],
-                         vp[1] + vp[3],
-                         vp[0] + vp[2],
-                         vp[1]);
+    GrGLIRect viewport;
+    viewport.setFromGLViewport();
+    GLuint stencilBits;
+    GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&stencilBits);
+
     rtIDs.fOwnIDs = false;
 
-    return new GrGLRenderTarget(rtIDs,
-                                viewportRect,
-                                NULL,
-                                this);
+    return new GrGLRenderTarget(rtIDs, stencilBits, viewport, NULL, this);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
+static const GLuint UNKNOWN_BITS = ~0;
+
 // defines stencil formats from more to less preferred
-GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {
-    GR_STENCIL_INDEX8,
+struct {
+    GLenum  fEnum;
+    GLuint  fBits;
+} gStencilFormats[] = {
+    {GR_STENCIL_INDEX8,     8},
 
 #if GR_SUPPORT_GLDESKTOP
-    GR_STENCIL_INDEX16,
+    {GR_STENCIL_INDEX16,    16},
 #endif
 
-    GR_DEPTH24_STENCIL8,
-    GR_STENCIL_INDEX4,
+    {GR_DEPTH24_STENCIL8,   8},
+    {GR_STENCIL_INDEX4,     4},
 
 #if GR_SUPPORT_GLDESKTOP
-    GL_STENCIL_INDEX,
-    GR_DEPTH_STENCIL,
+    {GL_STENCIL_INDEX,      UNKNOWN_BITS},
+    {GR_DEPTH_STENCIL,      UNKNOWN_BITS}
 #endif
 };
 
@@ -588,6 +589,7 @@
     glDesc.fContentHeight = desc.fHeight;
     glDesc.fAllocWidth    = desc.fWidth;
     glDesc.fAllocHeight   = desc.fHeight;
+    glDesc.fStencilBits   = 0;
     glDesc.fFormat        = desc.fFormat;
 
     bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
@@ -800,7 +802,7 @@
         if (!(kNoPathRendering_TextureFlag & desc.fFlags)) {
             GR_GLEXT(fExts, GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
             GrAssert(0 != rtIDs.fStencilRenderbufferID);
-            attempts = GR_ARRAY_COUNT(GR_GL_STENCIL_FORMAT_ARRAY);
+            attempts = GR_ARRAY_COUNT(gStencilFormats);
         }
 
         // someone suggested that some systems might require
@@ -817,13 +819,13 @@
                     GR_GLEXT_NO_ERR(fExts, RenderbufferStorageMultisample(
                                                 GR_RENDERBUFFER,
                                                 samples,
-                                                GR_GL_STENCIL_FORMAT_ARRAY[i],
+                                                gStencilFormats[i].fEnum,
                                                 glDesc.fAllocWidth,
                                                 glDesc.fAllocHeight));
                 } else {
                     GR_GLEXT_NO_ERR(fExts, RenderbufferStorage(
                                                 GR_RENDERBUFFER,
-                                                GR_GL_STENCIL_FORMAT_ARRAY[i],
+                                                gStencilFormats[i].fEnum,
                                                 glDesc.fAllocWidth,
                                                 glDesc.fAllocHeight));
                 }
@@ -927,6 +929,13 @@
             }
             // we're successful!
             failed = false;
+            if (rtIDs.fStencilRenderbufferID) {
+                if (UNKNOWN_BITS == gStencilFormats[i].fBits) {
+                    GR_GL_GetIntegerv(GL_STENCIL_BITS, (GLint*)&glDesc.fStencilBits);
+                } else {
+                    glDesc.fStencilBits = gStencilFormats[i].fBits;
+                }
+            }
             break;
         }
         if (failed) {
@@ -1020,29 +1029,23 @@
 
 void GrGpuGL::flushScissor(const GrIRect* rect) {
     GrAssert(NULL != fCurrDrawState.fRenderTarget);
-    const GrIRect& vp =
+    const GrGLIRect& vp =
             ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
 
-    if (NULL != rect &&
-        rect->contains(vp)) {
-        rect = NULL;
+    GrGLIRect scissor;
+    if (NULL != rect) {
+        scissor.setRelativeTo(vp, rect->fLeft, rect->fTop, 
+                              rect->width(), rect->height());
+        if (scissor.contains(vp)) {
+            rect = NULL;
+        }
     }
 
     if (NULL != rect) {
-        GrIRect scissor;
-        // viewport is already in GL coords
-        // create a scissor in GL coords (top > bottom)
-        scissor.setLTRB(vp.fLeft + rect->fLeft,
-                        vp.fTop  - rect->fTop,
-                        vp.fLeft + rect->fRight,
-                        vp.fTop  - rect->fBottom);
-
         if (fHWBounds.fScissorRect != scissor) {
-            GR_GL(Scissor(scissor.fLeft, scissor.fBottom,
-                          scissor.width(), -scissor.height()));
+            scissor.pushToGLScissor();
             fHWBounds.fScissorRect = scissor;
         }
-
         if (!fHWBounds.fScissorEnabled) {
             GR_GL(Enable(GL_SCISSOR_TEST));
             fHWBounds.fScissorEnabled = true;
@@ -1088,9 +1091,9 @@
     fDirtyFlags.fWriteMaskChanged = true;
 }
 
-void GrGpuGL::eraseStencilClip() {
-    GLint stencilBitCount;
-    GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
+void GrGpuGL::eraseStencilClip() {    
+    GrAssert(NULL != fCurrDrawState.fRenderTarget);
+    GLint stencilBitCount = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getStencilBits();
     GrAssert(stencilBitCount > 0);
     GLint clipStencilMask  = (1 << (stencilBitCount - 1));
     eraseStencil(0, clipStencilMask);
@@ -1114,10 +1117,13 @@
     }
     flushRenderTarget();
 
-    const GrIRect& vp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
-
-    // Brian says that viewport rects are already upside down (grrrrr)
-    GR_GL(ReadPixels(left, -vp.height() - top - height, width, height,
+    const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->viewport();
+    
+    // the read rect is viewport-relative
+    GrGLIRect readRect;
+    readRect.setRelativeTo(glvp, left, top, width, height);
+    GR_GL(ReadPixels(readRect.fLeft, readRect.fBottom,
+                     readRect.fWidth, readRect.fHeight, 
                      format, type, buffer));
 
     // now reverse the order of the rows, since GL's are bottom-to-top, but our
@@ -1158,14 +1164,11 @@
             GrPrintf("-- glCheckFramebufferStatus %x\n", status);
         }
     #endif
-        fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
-        const GrIRect& vp = rt->viewport();
         fDirtyFlags.fRenderTargetChanged = true;
-        if (fHWBounds.fViewportRect != vp) {
-            GR_GL(Viewport(vp.fLeft,
-                           vp.fBottom,
-                           vp.width(),
-                           -vp.height()));
+        fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
+        const GrGLIRect& vp = rt->viewport();
+        if (true || fHWBounds.fViewportRect != vp) {
+            vp.pushToGLViewport();
             fHWBounds.fViewportRect = vp;
         }
     }
@@ -1242,7 +1245,7 @@
             GR_GL(Enable(GL_SCISSOR_TEST));
             GR_GL(Scissor(left, bottom, right-left, top-bottom));
             GR_GLEXT(fExts, ResolveMultisampleFramebuffer());
-            fHWBounds.fScissorRect.setEmpty();
+            fHWBounds.fScissorRect.invalidate();
             fHWBounds.fScissorEnabled = true;
         } else {
             GR_GLEXT(fExts, BlitFramebuffer(left, bottom, right, top,
@@ -1269,10 +1272,9 @@
          fHWDrawState.fReverseFill != fCurrDrawState.fReverseFill);
 
     if (stencilChange) {
-        GLint stencilBitCount;
         GLint clipStencilMask;
         GLint pathStencilMask;
-        GR_GL_GetIntegerv(GL_STENCIL_BITS, &stencilBitCount);
+        GLint stencilBitCount = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getStencilBits();
         GrAssert(stencilBitCount > 0 ||
                  kNone_StencilPass == fCurrDrawState.fStencilPass);
         clipStencilMask  = (1 << (stencilBitCount - 1));
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index a2ccc12..017d9ea 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -20,6 +20,7 @@
 
 #include "GrGpu.h"
 #include "GrGLConfig.h"
+#include "GrGLIRect.h"
 #include "GrGLTexture.h"
 
 #include "GrGLVertexBuffer.h"
@@ -40,6 +41,7 @@
 
     virtual GrRenderTarget* createPlatformRenderTarget(
                                                  intptr_t platformRenderTarget,
+                                                 int stencilBits,
                                                  int width, int height);
 
     virtual GrRenderTarget* createRenderTargetFrom3DApiState();
@@ -87,7 +89,11 @@
     void resetDirtyFlags();
 
     // last scissor / viewport scissor state seen by the GL.
-    BoundsState fHWBounds;
+    struct {
+        bool        fScissorEnabled;
+        GrGLIRect   fScissorRect;
+        GrGLIRect   fViewportRect;
+    } fHWBounds;
 
     GrGLExts fExts;
 
@@ -185,31 +191,4 @@
     typedef GrGpu INHERITED;
 };
 
-bool has_gl_extension(const char* ext);
-void gl_version(int* major, int* minor);
-
-/**
- *  GrGL_RestoreResetRowLength() will reset GL_UNPACK_ROW_LENGTH to 0. We write
- *  this wrapper, since GL_UNPACK_ROW_LENGTH is not available on all GL versions
- */
-#if GR_SUPPORT_GLDESKTOP
-    static inline void GrGL_RestoreResetRowLength() {
-        GR_GL(PixelStorei(GL_UNPACK_ROW_LENGTH, 0));
-    }
-#else
-    #define GrGL_RestoreResetRowLength()
-#endif
-
-/*
- *  Some drivers want the var-int arg to be zero-initialized on input.
- */
-#define GR_GL_INIT_ZERO     0
-#define GR_GL_GetIntegerv(e, p)     \
-    do {                            \
-        *(p) = GR_GL_INIT_ZERO;     \
-        GR_GL(GetIntegerv(e, p));   \
-    } while (0)
-
-#endif
-
-
+#endif
\ No newline at end of file