Reduce gets of ext string and check validity of stencil format enums

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



git-svn-id: http://skia.googlecode.com/svn/trunk@1801 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index fe51875..1f9afdc 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -262,7 +262,10 @@
 }
 
 
-GrGpuGL::GrGpuGL() {
+GrGpuGL::GrGpuGL() 
+    : fStencilFormats(8) {
+
+    GrGLClearErr();
 
     if (gPrintStartupSpew) {
         GrPrintf("------------------------- create GrGpuGL %p --------------\n",
@@ -277,9 +280,10 @@
                  GrGLGetGLInterface()->fGetString(GR_GL_EXTENSIONS));
     }
 
-    GrGLClearErr();
+    fGLVersion = gl_version_as_float();
+    fExtensionString = (const char*) GR_GL(GetString(GR_GL_EXTENSIONS));
 
-    resetDirtyFlags();
+    this->resetDirtyFlags();
 
     GrGLint maxTextureUnits;
     // check FS and fixed-function texture unit limits
@@ -307,8 +311,7 @@
     ////////////////////////////////////////////////////////////////////////////
     // Check for supported features.
 
-    int major, minor;
-    gl_version(&major, &minor);
+    this->setupStencilFormats();
 
     GrGLint numFormats;
     GR_GL_GetIntegerv(GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
@@ -333,19 +336,19 @@
     memset(fAASamples, 0, sizeof(fAASamples));
     fMSFBOType = kNone_MSFBO;
     if (GR_GL_SUPPORT_ES) {
-       if (has_gl_extension("GL_CHROMIUM_framebuffer_multisample")) {
+       if (this->hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
            // chrome's extension is equivalent to the EXT msaa
            // and fbo_blit extensions.
             fMSFBOType = kDesktopEXT_MSFBO;
-       } else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
+       } else if (this->hasExtension("GL_APPLE_framebuffer_multisample")) {
             fMSFBOType = kAppleES_MSFBO;
         }
     } else {
         GrAssert(GR_GL_SUPPORT_DESKTOP);
-        if ((major >= 3) || has_gl_extension("GL_ARB_framebuffer_object")) {
+        if ((fGLVersion >= 3.f) || this->hasExtension("GL_ARB_framebuffer_object")) {
             fMSFBOType = kDesktopARB_MSFBO;
-        } else if (has_gl_extension("GL_EXT_framebuffer_multisample") &&
-                   has_gl_extension("GL_EXT_framebuffer_blit")) {
+        } else if (this->hasExtension("GL_EXT_framebuffer_multisample") &&
+                   this->hasExtension("GL_EXT_framebuffer_blit")) {
             fMSFBOType = kDesktopEXT_MSFBO;
         }
     }
@@ -386,10 +389,10 @@
     fFSAASupport = fAASamples[kHigh_GrAALevel] > 0;
 
     if (GR_GL_SUPPORT_DESKTOP) {
-        fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
-                          has_gl_extension("GL_EXT_stencil_wrap");
+        fHasStencilWrap = (fGLVersion >= 1.4f) ||
+                          this->hasExtension("GL_EXT_stencil_wrap");
     } else {
-        fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
+        fHasStencilWrap = (fGLVersion >= 2.0f) || this->hasExtension("GL_OES_stencil_wrap");
     }
     if (gPrintStartupSpew) {
         GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
@@ -399,18 +402,17 @@
         // we could also look for GL_ATI_separate_stencil extension or
         // GL_EXT_stencil_two_side but they use different function signatures
         // than GL2.0+ (and than each other).
-        fTwoSidedStencilSupport = (major >= 2);
+        fTwoSidedStencilSupport = (fGLVersion >= 2.f);
         // supported on GL 1.4 and higher or by extension
-        fStencilWrapOpsSupport = (major > 1) ||
-                                 ((1 == major) && (minor >= 4)) ||
-                                  has_gl_extension("GL_EXT_stencil_wrap");
+        fStencilWrapOpsSupport = (fGLVersion >= 1.4f) ||
+                                  this->hasExtension("GL_EXT_stencil_wrap");
     } else {
         // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
         // an ES1 extension.
-        fTwoSidedStencilSupport = (major >= 2);
+        fTwoSidedStencilSupport = (fGLVersion >= 2.f);
         // stencil wrap support is in ES2, ES1 requires extension.
-        fStencilWrapOpsSupport = (major > 1) ||
-                                  has_gl_extension("GL_OES_stencil_wrap");
+        fStencilWrapOpsSupport = (fGLVersion >= 2.f) ||
+                                 this->hasExtension("GL_OES_stencil_wrap");
     }
     if (gPrintStartupSpew) {
         GrPrintf("Stencil Caps: TwoSide: %s, Wrap: %s\n",
@@ -421,7 +423,7 @@
     if (GR_GL_SUPPORT_DESKTOP) {
         fRGBA8Renderbuffer = true;
     } else {
-        fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
+        fRGBA8Renderbuffer = this->hasExtension("GL_OES_rgb8_rgba8");
     }
     if (gPrintStartupSpew) {
         GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
@@ -430,7 +432,7 @@
 
     if (GR_GL_SUPPORT_ES) {
         if (GR_GL_32BPP_COLOR_FORMAT == GR_GL_BGRA) {
-            GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
+            GrAssert(this->hasExtension("GL_EXT_texture_format_BGRA8888"));
         }
     }
 
@@ -438,7 +440,7 @@
         fBufferLockSupport = true; // we require VBO support and the desktop VBO
                                    // extension includes glMapBuffer.
     } else {
-        fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
+        fBufferLockSupport = this->hasExtension("GL_OES_mapbuffer");
     }
 
     if (gPrintStartupSpew) {
@@ -446,7 +448,8 @@
     }
 
     if (GR_GL_SUPPORT_DESKTOP) {
-        if (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) {
+        if (fGLVersion >= 2.f || 
+            this->hasExtension("GL_ARB_texture_non_power_of_two")) {
             fNPOTTextureTileSupport = true;
             fNPOTTextureSupport = true;
         } else {
@@ -454,12 +457,12 @@
             fNPOTTextureSupport = false;
         }
     } else {
-        if (major >= 2) {
+        if (fGLVersion >= 2.f) {
             fNPOTTextureSupport = true;
-            fNPOTTextureTileSupport = has_gl_extension("GL_OES_texture_npot");
+            fNPOTTextureTileSupport = this->hasExtension("GL_OES_texture_npot");
         } else {
             fNPOTTextureSupport =
-                        has_gl_extension("GL_APPLE_texture_2D_limited_npot");
+                        this->hasExtension("GL_APPLE_texture_2D_limited_npot");
             fNPOTTextureTileSupport = false;
         }
     }
@@ -685,37 +688,57 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static const GrGLuint UNKNOWN_BITS = ~0;
+void GrGpuGL::setupStencilFormats() {
 
-struct StencilFormat {
-    GrGLenum  fEnum;
-    GrGLuint  fBits;
-    bool      fPacked;
-};
+    // Build up list of legal stencil formats (though perhaps not supported on
+    // the particular gpu/driver) from most preferred to least.
 
-const StencilFormat* GrGLStencilFormats(int* count) {
-    // defines stencil formats from more to less preferred
-    static const StencilFormat desktopStencilFormats[] = {
-        {GR_GL_STENCIL_INDEX8,     8,            false},
-        {GR_GL_STENCIL_INDEX16,    16,           false},
-        {GR_GL_DEPTH24_STENCIL8,   8,            true },
-        {GR_GL_STENCIL_INDEX4,     4,            false},
-        {GR_GL_STENCIL_INDEX,      UNKNOWN_BITS, false},
-        {GR_GL_DEPTH_STENCIL,      UNKNOWN_BITS, true },
-    };
-
-    static const StencilFormat esStencilFormats[] = {
-        {GR_GL_STENCIL_INDEX8,     8,   false},
-        {GR_GL_DEPTH24_STENCIL8,   8,   true },
-        {GR_GL_STENCIL_INDEX4,     4,   false},
-    };
+    // 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 };
 
     if (GR_GL_SUPPORT_DESKTOP) {
-        *count = GR_ARRAY_COUNT(desktopStencilFormats);
-        return desktopStencilFormats;
+        bool supportsPackedDS = fGLVersion >= 3.0f || 
+                                this->hasExtension("GL_EXT_packed_depth_stencil") ||
+                                this->hasExtension("GL_ARB_framebuffer_object");
+
+        // S1 thru S16 formats are in GL 3.0+, EXT_FBO, and ARB_FBO since we
+        // require FBO support we can expect these are legal formats and don't
+        // check. These also all support the unsized GL_STENCIL_INDEX.
+        fStencilFormats.push_back() = gS8;
+        fStencilFormats.push_back() = gS16;
+        if (supportsPackedDS) {
+            fStencilFormats.push_back() = gD24S8;
+        }
+        fStencilFormats.push_back() = gS4;
+        if (supportsPackedDS) {
+            fStencilFormats.push_back() = gDS;
+        }
     } else {
-        *count = GR_ARRAY_COUNT(esStencilFormats);
-        return esStencilFormats;
+        // ES2 has STENCIL_INDEX8 without extensions.
+        // ES1 with GL_OES_framebuffer_object (which we require for ES1)
+        // introduces tokens for S1 thu S8 but there are separate extensions
+        // that make them legal (GL_OES_stencil1, ...).
+        // GL_OES_packed_depth_stencil adds DEPTH24_STENCIL8
+        // ES doesn't support using the unsized formats.
+
+        if (fGLVersion >= 2.f || this->hasExtension("GL_OES_stencil8")) {
+            fStencilFormats.push_back() = gS8;
+        }
+        //fStencilFormats.push_back() = gS16;
+        if (this->hasExtension("GL_OES_packed_depth_stencil")) {
+            fStencilFormats.push_back() = gD24S8;
+        }
+        if (this->hasExtension("GL_OES_stencil4")) {
+            fStencilFormats.push_back() = gS4;
+        }
+        // we require some stencil format.
+        GrAssert(fStencilFormats.count() > 0);
     }
 }
 
@@ -983,9 +1006,8 @@
         err = ~GR_GL_NO_ERROR;
 
         int stencilFmtCnt;
-        const StencilFormat* stencilFormats = NULL;
         if (rtIDs.fStencilRenderbufferID) {
-            stencilFormats = GrGLStencilFormats(&stencilFmtCnt);
+            stencilFmtCnt = fStencilFormats.count();
         } else {
             stencilFmtCnt = 1; // only 1 attempt when we don't need a stencil
         }
@@ -1003,12 +1025,12 @@
                     GR_GL_NO_ERR(RenderbufferStorageMultisample(
                                                 GR_GL_RENDERBUFFER,
                                                 samples,
-                                                stencilFormats[sIdx].fEnum,
+                                                fStencilFormats[sIdx].fEnum,
                                                 glDesc.fAllocWidth,
                                                 glDesc.fAllocHeight));
                 } else {
                     GR_GL_NO_ERR(RenderbufferStorage(GR_GL_RENDERBUFFER,
-                                                     stencilFormats[sIdx].fEnum,
+                                                     fStencilFormats[sIdx].fEnum,
                                                      glDesc.fAllocWidth,
                                                      glDesc.fAllocHeight));
                 }
@@ -1064,7 +1086,7 @@
                                               rtIDs.fStencilRenderbufferID));
                 // if it is a packed format bind to depth also, otherwise 
                 // we may get an unsupported fbo completeness result
-                if (stencilFormats[sIdx].fPacked) {
+                if (fStencilFormats[sIdx].fPacked) {
                     GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
                                                   GR_GL_DEPTH_ATTACHMENT,
                                                   GR_GL_RENDERBUFFER,
@@ -1076,7 +1098,7 @@
             if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
                 // undo the depth bind
                 if (rtIDs.fStencilRenderbufferID && 
-                    stencilFormats[sIdx].fPacked) {
+                    fStencilFormats[sIdx].fPacked) {
                     GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
                                                     GR_GL_DEPTH_ATTACHMENT,
                                                     GR_GL_RENDERBUFFER,
@@ -1088,10 +1110,10 @@
             failed = false;
             if (rtIDs.fStencilRenderbufferID) {
                 fLastSuccessfulStencilFmtIdx = sIdx;
-                if (UNKNOWN_BITS == stencilFormats[sIdx].fBits) {
+                if (gUNKNOWN_BITCOUNT == fStencilFormats[sIdx].fBits) {
                     GR_GL_GetIntegerv(GR_GL_STENCIL_BITS, (GrGLint*)&glDesc.fStencilBits);
                 } else {
-                    glDesc.fStencilBits = stencilFormats[sIdx].fBits;
+                    glDesc.fStencilBits = fStencilFormats[sIdx].fBits;
                 }
             }
             break;