Make GLCaps be standalone and be a member of GrGLContextInfo

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



git-svn-id: http://skia.googlecode.com/svn/trunk@3183 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
new file mode 100644
index 0000000..d690ff3
--- /dev/null
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -0,0 +1,295 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLCaps.h"
+#include "GrGLContextInfo.h"
+
+GrGLCaps::GrGLCaps() {
+    this->reset();
+}
+
+void GrGLCaps::reset() {
+    fVerifiedColorConfigs.reset();
+    fStencilFormats.reset();
+    fStencilVerifiedColorConfigs.reset();
+    fMSFBOType = kNone_MSFBOType;
+    fMaxFragmentUniformVectors = 0;
+    fRGBA8RenderbufferSupport = false;
+    fBGRAFormatSupport = false;
+    fBGRAIsInternalFormat = false;
+    fTextureSwizzleSupport = false;
+    fUnpackRowLengthSupport = false;
+    fUnpackFlipYSupport = false;
+    fPackRowLengthSupport = false;
+    fPackFlipYSupport = false;
+    fTextureUsageSupport = false;
+    fTexStorageSupport = false;
+}
+
+GrGLCaps::GrGLCaps(const GrGLCaps& caps) {
+    *this = caps;
+}
+
+GrGLCaps& GrGLCaps::operator = (const GrGLCaps& caps) {
+    fVerifiedColorConfigs = caps.fVerifiedColorConfigs;
+    fStencilFormats = caps.fStencilFormats;
+    fStencilVerifiedColorConfigs = caps.fStencilVerifiedColorConfigs;
+    fMaxFragmentUniformVectors = caps.fMaxFragmentUniformVectors;
+    fMSFBOType = caps.fMSFBOType;
+    fRGBA8RenderbufferSupport = caps.fRGBA8RenderbufferSupport;
+    fBGRAFormatSupport = caps.fBGRAFormatSupport;
+    fBGRAIsInternalFormat = caps.fBGRAIsInternalFormat;
+    fTextureSwizzleSupport = caps.fTextureSwizzleSupport;
+    fUnpackRowLengthSupport = caps.fUnpackRowLengthSupport;
+    fUnpackFlipYSupport = caps.fUnpackFlipYSupport;
+    fPackRowLengthSupport = caps.fPackRowLengthSupport;
+    fPackFlipYSupport = caps.fPackFlipYSupport;
+    fTextureUsageSupport = caps.fTextureUsageSupport;
+    fTexStorageSupport = caps.fTexStorageSupport;
+
+    return *this;
+}
+
+void GrGLCaps::init(const GrGLContextInfo& ctxInfo) {
+
+    this->reset();
+    if (!ctxInfo.isInitialized()) {
+        return;
+    }
+
+    const GrGLInterface* gli = ctxInfo.interface();
+    GrGLBinding binding = ctxInfo.binding();
+    GrGLVersion version = ctxInfo.version();
+
+    if (kES2_GrGLBinding == binding) {
+        GR_GL_GetIntegerv(gli, GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS,
+                          &fMaxFragmentUniformVectors);
+    } else {
+        GrAssert(kDesktop_GrGLBinding == binding);
+        GrGLint max;
+        GR_GL_GetIntegerv(gli, GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max);
+        fMaxFragmentUniformVectors = max / 4;
+    }
+
+    if (kDesktop_GrGLBinding == binding) {
+        fRGBA8RenderbufferSupport = true;
+    } else {
+        fRGBA8RenderbufferSupport = ctxInfo.hasExtension("GL_OES_rgb8_rgba8") ||
+                                    ctxInfo.hasExtension("GL_ARM_rgba8");
+    }
+
+    if (kDesktop_GrGLBinding == binding) {
+        fBGRAFormatSupport = version >= GR_GL_VER(1,2) ||
+                             ctxInfo.hasExtension("GL_EXT_bgra");
+    } else {
+        bool hasBGRAExt = false;
+        if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) {
+            fBGRAFormatSupport = true;
+        } else if (ctxInfo.hasExtension("GL_EXT_texture_format_BGRA8888")) {
+            fBGRAFormatSupport = true;
+            fBGRAIsInternalFormat = true;
+        }
+        GrAssert(fBGRAFormatSupport ||
+                 kSkia8888_PM_GrPixelConfig != kBGRA_8888_PM_GrPixelConfig);
+    }
+
+    if (kDesktop_GrGLBinding == binding) {
+        fTextureSwizzleSupport = version >= GR_GL_VER(3,3) ||
+                                 ctxInfo.hasExtension("GL_ARB_texture_swizzle");
+    } else {
+        fTextureSwizzleSupport = false;
+    }
+
+    if (kDesktop_GrGLBinding == binding) {
+        fUnpackRowLengthSupport = true;
+        fUnpackFlipYSupport = false;
+        fPackRowLengthSupport = true;
+        fPackFlipYSupport = false;
+    } else {
+        fUnpackRowLengthSupport =ctxInfo.hasExtension("GL_EXT_unpack_subimage");
+        fUnpackFlipYSupport = ctxInfo.hasExtension("GL_CHROMIUM_flipy");
+        // no extension for pack row length
+        fPackRowLengthSupport = false;
+        fPackFlipYSupport =
+            ctxInfo.hasExtension("GL_ANGLE_pack_reverse_row_order");
+    }
+
+    fTextureUsageSupport = (kES2_GrGLBinding == binding) &&
+                            ctxInfo.hasExtension("GL_ANGLE_texture_usage");
+
+    // Tex storage is in desktop 4.2 and can be an extension to desktop or ES.
+    fTexStorageSupport = (kDesktop_GrGLBinding == binding &&
+                          version >= GR_GL_VER(4,2)) ||
+                         ctxInfo.hasExtension("GL_ARB_texture_storage") ||
+                         ctxInfo.hasExtension("GL_EXT_texture_storage");
+
+    this->initFSAASupport(ctxInfo);
+    this->initStencilFormats(ctxInfo);
+}
+
+void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo) {
+
+    fMSFBOType = kNone_MSFBOType;
+    if (kDesktop_GrGLBinding != ctxInfo.binding()) {
+       if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
+           // chrome's extension is equivalent to the EXT msaa
+           // and fbo_blit extensions.
+           fMSFBOType = kDesktopEXT_MSFBOType;
+       } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) {
+            fMSFBOType = kAppleES_MSFBOType;
+        }
+    } else {
+        if ((ctxInfo.version() >= GR_GL_VER(3,0)) ||
+            ctxInfo.hasExtension("GL_ARB_framebuffer_object")) {
+            fMSFBOType = GrGLCaps::kDesktopARB_MSFBOType;
+        } else if (ctxInfo.hasExtension("GL_EXT_framebuffer_multisample") &&
+                   ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) {
+            fMSFBOType = GrGLCaps::kDesktopEXT_MSFBOType;
+        }
+    }
+}
+
+namespace {
+const GrGLuint kUnknownBitCount = GrGLStencilBuffer::kUnknownBitCount;
+}
+
+void GrGLCaps::initStencilFormats(const GrGLContextInfo& ctxInfo) {
+
+    // Build up list of legal stencil formats (though perhaps not supported on
+    // the particular gpu/driver) from most preferred to least.
+
+    // 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
+                  // 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 (kDesktop_GrGLBinding == ctxInfo.binding()) {
+        bool supportsPackedDS =
+            ctxInfo.version() >= GR_GL_VER(3,0) || 
+            ctxInfo.hasExtension("GL_EXT_packed_depth_stencil") ||
+            ctxInfo.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 {
+        // ES2 has STENCIL_INDEX8 without extensions but requires extensions
+        // for other formats.
+        // ES doesn't support using the unsized format.
+
+        fStencilFormats.push_back() = gS8;
+        //fStencilFormats.push_back() = gS16;
+        if (ctxInfo.hasExtension("GL_OES_packed_depth_stencil")) {
+            fStencilFormats.push_back() = gD24S8;
+        }
+        if (ctxInfo.hasExtension("GL_OES_stencil4")) {
+            fStencilFormats.push_back() = gS4;
+        }
+    }
+    GrAssert(0 == fStencilVerifiedColorConfigs.count());
+    fStencilVerifiedColorConfigs.push_back_n(fStencilFormats.count());
+}
+
+void GrGLCaps::markColorConfigAndStencilFormatAsVerified(
+                                    GrPixelConfig config,
+                                    const GrGLStencilBuffer::Format& format) {
+#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT
+    return;
+#endif
+    GrAssert((unsigned)config < kGrPixelConfigCount);
+    GrAssert(fStencilFormats.count() == fStencilVerifiedColorConfigs.count());
+    int count = fStencilFormats.count();
+    // we expect a really small number of possible formats so linear search
+    // should be OK
+    GrAssert(count < 16);
+    for (int i = 0; i < count; ++i) {
+        if (format.fInternalFormat ==
+            fStencilFormats[i].fInternalFormat) {
+            fStencilVerifiedColorConfigs[i].markVerified(config);
+            return;
+        }
+    }
+    GrCrash("Why are we seeing a stencil format that "
+            "GrGLCaps doesn't know about.");
+}
+
+bool GrGLCaps::isColorConfigAndStencilFormatVerified(
+                                GrPixelConfig config,
+                                const GrGLStencilBuffer::Format& format) const {
+#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT
+    return false;
+#endif
+    GrAssert((unsigned)config < kGrPixelConfigCount);
+    int count = fStencilFormats.count();
+    // we expect a really small number of possible formats so linear search
+    // should be OK
+    GrAssert(count < 16);
+    for (int i = 0; i < count; ++i) {
+        if (format.fInternalFormat ==
+            fStencilFormats[i].fInternalFormat) {
+            return fStencilVerifiedColorConfigs[i].isVerified(config);
+        }
+    }
+    GrCrash("Why are we seeing a stencil format that "
+            "GLCaps doesn't know about.");
+    return false;
+}
+
+void GrGLCaps::print() const {
+    for (int i = 0; i < fStencilFormats.count(); ++i) {
+        GrPrintf("Stencil Format %d, stencil bits: %02d, total bits: %02d\n",
+                 i,
+                 fStencilFormats[i].fStencilBits,
+                 fStencilFormats[i].fTotalBits);
+    }
+
+    GR_STATIC_ASSERT(0 == kNone_MSFBOType);
+    GR_STATIC_ASSERT(1 == kDesktopARB_MSFBOType);
+    GR_STATIC_ASSERT(2 == kDesktopEXT_MSFBOType);
+    GR_STATIC_ASSERT(3 == kAppleES_MSFBOType);
+    static const char* gMSFBOExtStr[] = {
+        "None",
+        "ARB",
+        "EXT",
+        "Apple",
+    };
+    GrPrintf("MSAA Type: %s\n", gMSFBOExtStr[fMSFBOType]);
+    GrPrintf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors);
+    GrPrintf("Support RGBA8 Render Buffer: %s\n",
+             (fRGBA8RenderbufferSupport ? "YES": "NO"));
+    GrPrintf("BGRA is an internal format: %s\n",
+             (fBGRAIsInternalFormat ? "YES": "NO"));
+    GrPrintf("Support texture swizzle: %s\n",
+             (fTextureSwizzleSupport ? "YES": "NO"));
+    GrPrintf("Unpack Row length support: %s\n",
+             (fUnpackRowLengthSupport ? "YES": "NO"));
+    GrPrintf("Unpack Flip Y support: %s\n",
+             (fUnpackFlipYSupport ? "YES": "NO"));
+    GrPrintf("Pack Row length support: %s\n",
+             (fPackRowLengthSupport ? "YES": "NO"));
+    GrPrintf("Pack Flip Y support: %s\n",
+             (fPackFlipYSupport ? "YES": "NO"));
+}
+
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
new file mode 100644
index 0000000..a5318eb
--- /dev/null
+++ b/src/gpu/gl/GrGLCaps.h
@@ -0,0 +1,227 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrGLCaps_DEFINED
+#define GrGLCaps_DEFINED
+
+#include "GrGLStencilBuffer.h"
+
+class GrGLContextInfo;
+
+/**
+ * Stores some capabilities of a GL context. Most are determined by the GL
+ * version and the extensions string. It also tracks formats that have passed
+ * the FBO completeness test.
+ */
+class GrGLCaps {
+public:
+    typedef GrGLStencilBuffer::Format StencilFormat;
+
+    /**
+     * The type of MSAA for FBOs supported. Different extensions have different
+     * semantics of how / when a resolve is performed.
+     */
+    enum MSFBOType {
+        /**
+         * no support for MSAA FBOs
+         */
+        kNone_MSFBOType = 0,  
+        /**
+         * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object)
+         */
+        kDesktopARB_MSFBOType,
+        /**
+         * earlier GL_EXT_framebuffer* extensions
+         */
+        kDesktopEXT_MSFBOType,
+        /**
+         * GL_APPLE_framebuffer_multisample ES extension
+         */
+        kAppleES_MSFBOType,
+    };
+
+    /**
+     * Creates a GrGLCaps that advertises no support for any extensions,
+     * formats, etc. Call init to initialize from a GrGLContextInfo.
+     */
+    GrGLCaps();
+
+    GrGLCaps(const GrGLCaps& caps);
+
+    GrGLCaps& operator = (const GrGLCaps& caps);
+
+    /**
+     * Resets the caps such that nothing is supported.
+     */
+    void reset();
+
+    /**
+     * Initializes the GrGLCaps to the set of features supported in the current
+     * OpenGL context accessible via ctxInfo.
+     */
+    void init(const GrGLContextInfo& ctxInfo);
+
+    /**
+     * Call to note that a color config has been verified as a valid color
+     * attachment. This may save future calls to glCheckFramebufferStatus
+     * using isConfigVerifiedColorAttachment().
+     */
+    void markConfigAsValidColorAttachment(GrPixelConfig config) {
+        fVerifiedColorConfigs.markVerified(config);
+    }
+
+    /**
+     * Call to check whether a config has been verified as a valid color
+     * attachment.
+     */
+    bool isConfigVerifiedColorAttachment(GrPixelConfig config) const {
+        return fVerifiedColorConfigs.isVerified(config);
+    }
+
+    /**
+     * Call to note that a color config / stencil format pair passed
+     * FBO status check. We may skip calling glCheckFramebufferStatus for
+     * this combination in the future using
+     * isColorConfigAndStencilFormatVerified().
+     */
+    void markColorConfigAndStencilFormatAsVerified(
+                    GrPixelConfig config,
+                    const GrGLStencilBuffer::Format& format);
+
+    /**
+     * Call to check whether color config / stencil format pair has already
+     * passed FBO status check.
+     */
+    bool isColorConfigAndStencilFormatVerified(
+                    GrPixelConfig config,
+                    const GrGLStencilBuffer::Format& format) const;
+
+    /**
+     * Reports the type of MSAA FBO support.
+     */
+    MSFBOType msFBOType() const { return fMSFBOType; }
+
+    /**
+     * Prints the caps info using GrPrintf.
+     */
+    void print() const;
+
+    /**
+     * Gets an array of legal stencil formats. These formats are not guaranteed
+     * to be supported by the driver but are legal GLenum names given the GL
+     * version and extensions supported.
+     */
+    const SkTArray<StencilFormat, true>& stencilFormats() const {
+        return fStencilFormats;
+    }
+
+    /// The maximum number of fragment uniform vectors (GLES has min. 16).
+    int maxFragmentUniformVectors() const { return fMaxFragmentUniformVectors; }
+
+    /// ES requires an extension to support RGBA8 in RenderBufferStorage
+    bool rgba8RenderbufferSupport() const { return fRGBA8RenderbufferSupport; }
+
+    /// Is GL_BGRA supported
+    bool bgraFormatSupport() const { return fBGRAFormatSupport; }
+
+    /**
+     * Depending on the ES extensions present the BGRA external format may
+     * correspond either a BGRA or RGBA internalFormat. On desktop GL it is
+     * RGBA.
+     */
+    bool bgraIsInternalFormat() const { return fBGRAIsInternalFormat; }
+
+    /// GL_ARB_texture_swizzle support
+    bool textureSwizzleSupport() const { return fTextureSwizzleSupport; }
+
+    /// Is there support for GL_UNPACK_ROW_LENGTH
+    bool unpackRowLengthSupport() const { return fUnpackRowLengthSupport; }
+
+    /// Is there support for GL_UNPACK_FLIP_Y
+    bool unpackFlipYSupport() const { return fUnpackFlipYSupport; }
+
+    /// Is there support for GL_PACK_ROW_LENGTH
+    bool packRowLengthSupport() const { return fPackRowLengthSupport; }
+
+    /// Is there support for GL_PACK_REVERSE_ROW_ORDER
+    bool packFlipYSupport() const { return fPackFlipYSupport; }
+
+    /// Is there support for texture parameter GL_TEXTURE_USAGE
+    bool textureUsageSupport() const { return fTextureUsageSupport; }
+
+    /// Is there support for glTexStorage
+    bool texStorageSupport() const { return fTexStorageSupport; }
+
+private:
+    /**
+     * Maintains a bit per GrPixelConfig. It is used to avoid redundantly
+     * performing glCheckFrameBufferStatus for the same config.
+     */
+    struct VerifiedColorConfigs {
+        VerifiedColorConfigs() {
+            this->reset();
+        }
+
+        void reset() {
+            for (int i = 0; i < kNumUints; ++i) {
+                fVerifiedColorConfigs[i] = 0;
+            }
+        }
+
+        static const int kNumUints = (kGrPixelConfigCount  + 31) / 32;
+        uint32_t fVerifiedColorConfigs[kNumUints];
+
+        void markVerified(GrPixelConfig config) {
+#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT
+                return;
+#endif
+            int u32Idx = config / 32;
+            int bitIdx = config % 32;
+            fVerifiedColorConfigs[u32Idx] |= 1 << bitIdx;
+        }
+
+        bool isVerified(GrPixelConfig config) const {
+#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT
+            return false;
+#endif
+            int u32Idx = config / 32;
+            int bitIdx = config % 32;
+            return SkToBool(fVerifiedColorConfigs[u32Idx] & (1 << bitIdx));
+        }
+    };
+
+    void initFSAASupport(const GrGLContextInfo& ctxInfo);
+    void initStencilFormats(const GrGLContextInfo& ctxInfo);
+
+    // tracks configs that have been verified to pass the FBO completeness when
+    // used as a color attachment
+    VerifiedColorConfigs fVerifiedColorConfigs;
+
+    SkTArray<StencilFormat, true> fStencilFormats;
+    // tracks configs that have been verified to pass the FBO completeness when
+    // used as a color attachment when a particular stencil format is used
+    // as a stencil attachment.
+    SkTArray<VerifiedColorConfigs, true> fStencilVerifiedColorConfigs;
+
+    int fMaxFragmentUniformVectors;
+    MSFBOType fMSFBOType;
+
+    bool fRGBA8RenderbufferSupport : 1;
+    bool fBGRAFormatSupport : 1;
+    bool fBGRAIsInternalFormat : 1;
+    bool fTextureSwizzleSupport : 1;
+    bool fUnpackRowLengthSupport : 1;
+    bool fUnpackFlipYSupport : 1;
+    bool fPackRowLengthSupport : 1;
+    bool fPackFlipYSupport : 1;
+    bool fTextureUsageSupport : 1;
+    bool fTexStorageSupport : 1;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGLContextInfo.cpp b/src/gpu/gl/GrGLContextInfo.cpp
index 6fa7d8a..33e19ab 100644
--- a/src/gpu/gl/GrGLContextInfo.cpp
+++ b/src/gpu/gl/GrGLContextInfo.cpp
@@ -32,6 +32,7 @@
     fGLVersion = ctx.fGLVersion;
     fGLSLGeneration = ctx.fGLSLGeneration;
     fExtensionString = ctx.fExtensionString;
+    fGLCaps = ctx.fGLCaps;
     return *this;
 }
 
@@ -41,6 +42,7 @@
     fGLVersion = GR_GL_VER(0, 0);
     fGLSLGeneration = static_cast<GrGLSLGeneration>(0);
     fExtensionString = "";
+    fGLCaps.reset();
 }
 
 bool GrGLContextInfo::initialize(const GrGLInterface* interface) {
@@ -70,6 +72,7 @@
             GR_GL_CALL_RET(interface, ext, GetString(GR_GL_EXTENSIONS));
             fExtensionString = reinterpret_cast<const char*>(ext);
 
+            fGLCaps.init(*this);
             return true;
         }
     }
diff --git a/src/gpu/gl/GrGLContextInfo.h b/src/gpu/gl/GrGLContextInfo.h
index bf77656..b753608 100644
--- a/src/gpu/gl/GrGLContextInfo.h
+++ b/src/gpu/gl/GrGLContextInfo.h
@@ -10,6 +10,7 @@
 #ifndef GrGLContextInfo_DEFINED
 #define GrGLContextInfo_DEFINED
 
+#include "GrGLCaps.h"
 #include "GrGLInterface.h"
 #include "GrGLSL.h"
 
@@ -57,6 +58,8 @@
     GrGLBinding binding() const { return fBindingInUse; }
     GrGLVersion version() const { return fGLVersion; }
     GrGLSLGeneration glslGeneration() const { return fGLSLGeneration; }
+    const GrGLCaps& caps() const { return fGLCaps; }
+    GrGLCaps& caps() { return fGLCaps; }
 
     /**
      * Checks for extension support using a cached copy of the GL_EXTENSIONS
@@ -77,6 +80,7 @@
     GrGLVersion          fGLVersion;
     GrGLSLGeneration     fGLSLGeneration;
     SkString             fExtensionString;
+    GrGLCaps             fGLCaps;
 };
 
 #endif
diff --git a/src/gpu/gl/GrGLStencilBuffer.h b/src/gpu/gl/GrGLStencilBuffer.h
index 02501e7..0995c7d 100644
--- a/src/gpu/gl/GrGLStencilBuffer.h
+++ b/src/gpu/gl/GrGLStencilBuffer.h
@@ -16,6 +16,7 @@
 class GrGLStencilBuffer : public GrStencilBuffer {
 public:
     static const GrGLenum kUnknownInternalFormat = ~0;
+    static const GrGLuint kUnknownBitCount = ~0;
     struct Format {
         GrGLenum  fInternalFormat;
         GrGLuint  fStencilBits;
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 6ce6089..2e09187 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -34,75 +34,6 @@
     #define CHECK_ALLOC_ERROR(iface)          GR_GL_NO_ERROR
 #endif
 
-///////////////////////////////////////////////////////////////////////////////
-
-void GrGpuGL::GLCaps::markConfigAsValidColorAttachment(GrPixelConfig config) {
-#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT
-    return;
-#endif
-    GrAssert(config < kGrPixelConfigCount);
-    int u32Idx = config / 32;
-    int bitIdx = config % 32;
-    fVerifiedColorAttachmentConfigs[u32Idx] |= (1 << bitIdx);
-}
-
-bool GrGpuGL::GLCaps::isConfigVerifiedColorAttachment(
-                                                GrPixelConfig config) const {
-#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT
-    return false;
-#endif
-    GrAssert((unsigned)config < kGrPixelConfigCount);
-    int u32Idx = config / 32;
-    int bitIdx = config % 32;
-    return SkToBool(fVerifiedColorAttachmentConfigs[u32Idx] & (1 << bitIdx));
-}
-
-void GrGpuGL::GLCaps::markColorConfigAndStencilFormatAsVerified(
-                                    GrPixelConfig config,
-                                    const GrGLStencilBuffer::Format& format) {
-#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT
-    return;
-#endif
-    GrAssert((unsigned)config < kGrPixelConfigCount);
-    int count = fStencilFormats.count();
-    // we expect a really small number of possible formats so linear search
-    // should be OK
-    GrAssert(count < 16);
-    for (int i = 0; i < count; ++i) {
-        if (format.fInternalFormat ==
-            fStencilFormats[i].fFormat.fInternalFormat) {
-            int u32Idx = config / 32;
-            int bitIdx = config % 32;
-            fStencilFormats[i].fVerifiedColorConfigs[u32Idx] |= (1 << bitIdx);
-            return;
-        }
-    }
-    SkDEBUGFAIL("Why are we seeing a stencil format that GLCaps doesn't know about.");
-}
-
-bool GrGpuGL::GLCaps::isColorConfigAndStencilFormatVerified(
-                                GrPixelConfig config,
-                                const GrGLStencilBuffer::Format& format) const {
-#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT
-    return false;
-#endif
-    GrAssert((unsigned)config < kGrPixelConfigCount);
-    int count = fStencilFormats.count();
-    // we expect a really small number of possible formats so linear search
-    // should be OK
-    GrAssert(count < 16);
-    for (int i = 0; i < count; ++i) {
-        if (format.fInternalFormat ==
-            fStencilFormats[i].fFormat.fInternalFormat) {
-            int u32Idx = config / 32;
-            int bitIdx = config % 32;
-            return SkToBool(fStencilFormats[i].fVerifiedColorConfigs[u32Idx] &
-                            (1 << bitIdx));
-        }
-    }
-    SkDEBUGFAIL("Why are we seeing a stencil format that GLCaps doesn't know about.");
-    return false;
-}
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -288,8 +219,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static const GrGLuint kUnknownBitCount = ~0;
-
 void GrGpuGL::initCaps() {
     GrGLint maxTextureUnits;
     // check FS and fixed-function texture unit limits
@@ -302,16 +231,6 @@
         GR_GL_GetIntegerv(gl, GR_GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
         GrAssert(maxTextureUnits > GrDrawState::kNumStages);
     }
-    if (kES2_GrGLBinding == this->glBinding()) {
-        GR_GL_GetIntegerv(gl, GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS,
-                          &fGLCaps.fMaxFragmentUniformVectors);
-    } else if (kDesktop_GrGLBinding != this->glBinding()) {
-        GrGLint max;
-        GR_GL_GetIntegerv(gl, GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max);
-        fGLCaps.fMaxFragmentUniformVectors = max / 4;
-    } else {
-        fGLCaps.fMaxFragmentUniformVectors = 16;
-    }
 
     GrGLint numFormats;
     GR_GL_GetIntegerv(gl, GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
@@ -339,51 +258,6 @@
     }
 
     if (kDesktop_GrGLBinding == this->glBinding()) {
-        fGLCaps.fRGBA8RenderbufferSupport = true;
-    } else {
-        fGLCaps.fRGBA8RenderbufferSupport =
-                                    this->hasExtension("GL_OES_rgb8_rgba8") ||
-                                    this->hasExtension("GL_ARM_rgba8");
-    }
-
-
-    if (kDesktop_GrGLBinding == this->glBinding()) {
-        fGLCaps.fBGRAFormatSupport = this->glVersion() >= GR_GL_VER(1,2) ||
-                                     this->hasExtension("GL_EXT_bgra");
-    } else {
-        bool hasBGRAExt = false;
-        if (this->hasExtension("GL_APPLE_texture_format_BGRA8888")) {
-            fGLCaps.fBGRAFormatSupport = true;
-        } else if (this->hasExtension("GL_EXT_texture_format_BGRA8888")) {
-            fGLCaps.fBGRAFormatSupport = true;
-            fGLCaps.fBGRAIsInternalFormat = true;
-        }
-        GrAssert(fGLCaps.fBGRAFormatSupport ||
-                 kSkia8888_PM_GrPixelConfig != kBGRA_8888_PM_GrPixelConfig);
-    }
-
-    if (kDesktop_GrGLBinding == this->glBinding()) {
-        fGLCaps.fTextureSwizzleSupport = this->glVersion() >= GR_GL_VER(3,3) ||
-                                  this->hasExtension("GL_ARB_texture_swizzle");
-    } else {
-        fGLCaps.fTextureSwizzleSupport = false;
-    }
-
-    if (kDesktop_GrGLBinding == this->glBinding()) {
-        fGLCaps.fUnpackRowLengthSupport = true;
-        fGLCaps.fUnpackFlipYSupport = false;
-        fGLCaps.fPackRowLengthSupport = true;
-        fGLCaps.fPackFlipYSupport = false;
-    } else {
-        fGLCaps.fUnpackRowLengthSupport =this->hasExtension("GL_EXT_unpack_subimage");
-        fGLCaps.fUnpackFlipYSupport = this->hasExtension("GL_CHROMIUM_flipy");
-        // no extension for pack row length
-        fGLCaps.fPackRowLengthSupport = false;
-        fGLCaps.fPackFlipYSupport =
-            this->hasExtension("GL_ANGLE_pack_reverse_row_order");
-    }
-
-    if (kDesktop_GrGLBinding == this->glBinding()) {
         fCaps.fBufferLockSupport = true; // we require VBO support and the desktop VBO
                                          // extension includes glMapBuffer.
     } else {
@@ -402,15 +276,6 @@
         fCaps.fNPOTTextureTileSupport = this->hasExtension("GL_OES_texture_npot");
     }
 
-    fGLCaps.fTextureUsageSupport = (kES2_GrGLBinding == this->glBinding()) &&
-                                   this->hasExtension("GL_ANGLE_texture_usage");
-
-    // Tex storage is in desktop 4.2 and can be an extension to desktop or ES.
-    fGLCaps.fTexStorageSupport = (kDesktop_GrGLBinding == this->glBinding() &&
-                                  this->glVersion() >= GR_GL_VER(4,2)) ||
-                                 this->hasExtension("GL_ARB_texture_storage") ||
-                                 this->hasExtension("GL_EXT_texture_storage");
-
     fCaps.fHWAALineSupport = (kDesktop_GrGLBinding == this->glBinding());
 
     ////////////////////////////////////////////////////////////////////////////
@@ -424,93 +289,7 @@
     // attachment, hence this min:
     fCaps.fMaxRenderTargetSize = GrMin(fCaps.fMaxTextureSize, fCaps.fMaxRenderTargetSize);
 
-    this->initFSAASupport();
-    this->initStencilFormats();
-}
-
-void GrGpuGL::initFSAASupport() {
-
-    fGLCaps.fMSFBOType = GLCaps::kNone_MSFBO;
-    if (kDesktop_GrGLBinding != this->glBinding()) {
-       if (this->hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
-           // chrome's extension is equivalent to the EXT msaa
-           // and fbo_blit extensions.
-            fGLCaps.fMSFBOType = GLCaps::kDesktopEXT_MSFBO;
-       } else if (this->hasExtension("GL_APPLE_framebuffer_multisample")) {
-            fGLCaps.fMSFBOType = GLCaps::kAppleES_MSFBO;
-        }
-    } else {
-        if ((this->glVersion() >= GR_GL_VER(3,0)) || this->hasExtension("GL_ARB_framebuffer_object")) {
-            fGLCaps.fMSFBOType = GLCaps::kDesktopARB_MSFBO;
-        } else if (this->hasExtension("GL_EXT_framebuffer_multisample") &&
-                   this->hasExtension("GL_EXT_framebuffer_blit")) {
-            fGLCaps.fMSFBOType = GLCaps::kDesktopEXT_MSFBO;
-        }
-    }
-
-    fCaps.fFSAASupport = GLCaps::kNone_MSFBO != fGLCaps.fMSFBOType;
-}
-
-void GrGpuGL::initStencilFormats() {
-
-    // Build up list of legal stencil formats (though perhaps not supported on
-    // the particular gpu/driver) from most preferred to least.
-
-    // these consts are in order of most preferred to least preferred
-    // we don't bother with GL_STENCIL_INDEX1 or GL_DEPTH32F_STENCIL8
-
-    // Omitting fVerifiedColorConfigs from initializer list should init to 0.
-    static const GLCaps::StencilFormat
-                  // internal Format      stencil bits      total bits        packed?
-        gS8    = {{GR_GL_STENCIL_INDEX8,   8,                8,                false}, {0U}},
-        gS16   = {{GR_GL_STENCIL_INDEX16,  16,               16,               false}, {0U}},
-        gD24S8 = {{GR_GL_DEPTH24_STENCIL8, 8,                32,               true }, {0U}},
-        gS4    = {{GR_GL_STENCIL_INDEX4,   4,                4,                false}, {0U}},
-        gS     = {{GR_GL_STENCIL_INDEX,    kUnknownBitCount, kUnknownBitCount, false}, {0U}},
-        gDS    = {{GR_GL_DEPTH_STENCIL,    kUnknownBitCount, kUnknownBitCount, true }, {0U}};
-
-    if (kDesktop_GrGLBinding == this->glBinding()) {
-        bool supportsPackedDS = this->glVersion() >= GR_GL_VER(3,0) || 
-                                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.
-        fGLCaps.fStencilFormats.push_back() = gS8;
-        fGLCaps.fStencilFormats.push_back() = gS16;
-        if (supportsPackedDS) {
-            fGLCaps.fStencilFormats.push_back() = gD24S8;
-        }
-        fGLCaps.fStencilFormats.push_back() = gS4;
-        if (supportsPackedDS) {
-            fGLCaps.fStencilFormats.push_back() = gDS;
-        }
-    } else {
-        // ES2 has STENCIL_INDEX8 without extensions but requires extensions
-        // for other formats.
-        // ES doesn't support using the unsized format.
-
-        fGLCaps.fStencilFormats.push_back() = gS8;
-        //fStencilFormats.push_back() = gS16;
-        if (this->hasExtension("GL_OES_packed_depth_stencil")) {
-            fGLCaps.fStencilFormats.push_back() = gD24S8;
-        }
-        if (this->hasExtension("GL_OES_stencil4")) {
-            fGLCaps.fStencilFormats.push_back() = gS4;
-        }
-    }
-#if GR_DEBUG
-    // ensure that initially all color / stencil format combos have unverified
-    // fbo status.
-    for (int i = 0; i < fGLCaps.fStencilFormats.count(); ++i) {
-        int numU32 =
-            GR_ARRAY_COUNT(fGLCaps.fStencilFormats[i].fVerifiedColorConfigs);
-        for (int j = 0; j < numU32; ++j) {
-            GrAssert(0 == fGLCaps.fStencilFormats[i].fVerifiedColorConfigs[j]);
-        }
-    }
-#endif
+    fCaps.fFSAASupport = GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType();
 }
 
 GrPixelConfig GrGpuGL::preferredReadPixelsConfig(GrPixelConfig config) const {
@@ -537,7 +316,7 @@
     if (gPrintStartupSpew && !fPrintedCaps) {
         fPrintedCaps = true;
         this->getCaps().print();
-        fGLCaps.print();
+        this->glCaps().print();
     }
 
     // We detect cases when blending is effectively off
@@ -607,16 +386,16 @@
     fHWDrawState.setRenderTarget(NULL);
 
     // we assume these values
-    if (this->glCaps().fUnpackRowLengthSupport) {
+    if (this->glCaps().unpackRowLengthSupport()) {
         GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
     }
-    if (this->glCaps().fPackRowLengthSupport) {
+    if (this->glCaps().packRowLengthSupport()) {
         GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
     }
-    if (this->glCaps().fUnpackFlipYSupport) {
+    if (this->glCaps().unpackFlipYSupport()) {
         GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_FALSE));
     }
-    if (this->glCaps().fPackFlipYSupport) {
+    if (this->glCaps().packFlipYSupport()) {
         GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, GR_GL_FALSE));
     }
 }
@@ -766,7 +545,7 @@
     SkAutoSMalloc<128 * 128> tempStorage;
 
     bool useTexStorage = isNewTexture &&
-                         this->glCaps().fTexStorageSupport;
+                         this->glCaps().texStorageSupport();
     if (useTexStorage) {
         if (kDesktop_GrGLBinding == this->glBinding()) {
             // 565 is not a sized internal format on desktop GL. So on desktop
@@ -807,13 +586,13 @@
     bool glFlipY = false;
     if (NULL != data) {
         if (GrGLTexture::kBottomUp_Orientation == desc.fOrientation) {
-            if (this->glCaps().fUnpackFlipYSupport) {
+            if (this->glCaps().unpackFlipYSupport()) {
                 glFlipY = true;
             } else {
                 swFlipY = true;
             }
         }
-        if (this->glCaps().fUnpackRowLengthSupport && !swFlipY) {
+        if (this->glCaps().unpackRowLengthSupport() && !swFlipY) {
             // can't use this for flipping, only non-neg values allowed. :(
             if (rowBytes != trimRowBytes) {
                 GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
@@ -910,7 +689,7 @@
     }
 
     if (restoreGLRowLength) {
-        GrAssert(this->glCaps().fUnpackRowLengthSupport);
+        GrAssert(this->glCaps().unpackRowLengthSupport());
         GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
     }
     if (glFlipY) {
@@ -941,7 +720,7 @@
     // 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 > 0) {
-        if (GLCaps::kNone_MSFBO == fGLCaps.fMSFBOType) {
+        if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) {
             goto FAILED;
         }
         GL_CALL(GenFramebuffers(1, &desc->fRTFBOID));
@@ -979,12 +758,13 @@
                                       GR_GL_COLOR_ATTACHMENT0,
                                       GR_GL_RENDERBUFFER,
                                       desc->fMSColorRenderbufferID));
-        if (!fGLCaps.isConfigVerifiedColorAttachment(desc->fConfig)) {
+        if (!this->glCaps().isConfigVerifiedColorAttachment(desc->fConfig)) {
             GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
             if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
                 goto FAILED;
             }
-            fGLCaps.markConfigAsValidColorAttachment(desc->fConfig);
+            fGLContextInfo.caps().markConfigAsValidColorAttachment(
+                                                                desc->fConfig);
         }
     }
     GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fTexFBOID));
@@ -993,12 +773,12 @@
                                  GR_GL_COLOR_ATTACHMENT0,
                                  GR_GL_TEXTURE_2D,
                                  texID, 0));
-    if (!fGLCaps.isConfigVerifiedColorAttachment(desc->fConfig)) {
+    if (!this->glCaps().isConfigVerifiedColorAttachment(desc->fConfig)) {
         GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
         if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
             goto FAILED;
         }
-        fGLCaps.markConfigAsValidColorAttachment(desc->fConfig);
+        fGLContextInfo.caps().markConfigAsValidColorAttachment(desc->fConfig);
     }
 
     return true;
@@ -1064,7 +844,7 @@
                                             GrGLTexture::kTopDown_Orientation;
 
     glRTDesc.fSampleCnt = desc.fSampleCnt;
-    if (GLCaps::kNone_MSFBO == fGLCaps.fMSFBOType &&
+    if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() &&
         desc.fSampleCnt) {
         GrPrintf("MSAA RT requested but not supported on this platform.");
     }
@@ -1077,7 +857,7 @@
     }
 
     GL_CALL(GenTextures(1, &glTexDesc.fTextureID));
-    if (renderTarget && this->glCaps().fTextureUsageSupport) {
+    if (renderTarget && this->glCaps().textureUsageSupport()) {
         // provides a hint about how this texture will be used
         GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
                               GR_GL_TEXTURE_USAGE,
@@ -1143,6 +923,9 @@
 }
 
 namespace {
+
+const GrGLuint kUnknownBitCount = GrGLStencilBuffer::kUnknownBitCount;
+
 void inline get_stencil_rb_sizes(const GrGLInterface* gl,
                                  GrGLuint rb, 
                                  GrGLStencilBuffer::Format* format) {
@@ -1183,14 +966,15 @@
 
     GrGLStencilBuffer* sb = NULL;
 
-    int stencilFmtCnt = fGLCaps.fStencilFormats.count();
+    int stencilFmtCnt = this->glCaps().stencilFormats().count();
     for (int i = 0; i < stencilFmtCnt; ++i) {
         GL_CALL(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;
-        const GLCaps::StencilFormat& sFmt = fGLCaps.fStencilFormats[sIdx];
+        const GrGLCaps::StencilFormat& sFmt =
+                this->glCaps().stencilFormats()[sIdx];
         CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
         // we do this "if" so that we don't call the multisample
         // version on a GL that doesn't have an MSAA extension.
@@ -1198,12 +982,12 @@
             GL_ALLOC_CALL(this->glInterface(),
                           RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
                                                          samples,
-                                                         sFmt.fFormat.fInternalFormat,
+                                                         sFmt.fInternalFormat,
                                                          width, height));
         } else {
             GL_ALLOC_CALL(this->glInterface(),
                           RenderbufferStorage(GR_GL_RENDERBUFFER,
-                                              sFmt.fFormat.fInternalFormat,
+                                              sFmt.fInternalFormat,
                                               width, height));
         }
 
@@ -1211,7 +995,7 @@
         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 = sFmt.fFormat;
+            GrGLStencilBuffer::Format format = sFmt;
             get_stencil_rb_sizes(this->glInterface(), sbID, &format);
             sb = new GrGLStencilBuffer(this, sbID, width, height, 
                                        samples, format);
@@ -1270,7 +1054,7 @@
         }
 
         GrGLenum status;
-        if (!fGLCaps.isColorConfigAndStencilFormatVerified(rt->config(),
+        if (!this->glCaps().isColorConfigAndStencilFormatVerified(rt->config(),
                                                            glsb->format())) {
             GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
             if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
@@ -1284,7 +1068,7 @@
                 }
                 return false;
             } else {
-                fGLCaps.markColorConfigAndStencilFormatAsVerified(
+                fGLContextInfo.caps().markColorConfigAndStencilFormatAsVerified(
                     rt->config(),
                     glsb->format());
             }
@@ -1482,13 +1266,13 @@
                                         GrPixelConfig config,
                                         size_t rowBytes) const {
     // if GL can do the flip then we'll never pay for it.
-    if (this->glCaps().fPackFlipYSupport) {
+    if (this->glCaps().packFlipYSupport()) {
         return false;
     }
 
     // If we have to do memcpy to handle non-trim rowBytes then we
     // get the flip for free. Otherwise it costs.
-    if (this->glCaps().fPackRowLengthSupport) {
+    if (this->glCaps().packRowLengthSupport()) {
         return true;
     }
     // If we have to do memcpys to handle rowBytes then y-flip is free
@@ -1559,7 +1343,7 @@
     // a scratch buffer.
     SkAutoSMalloc<32 * sizeof(GrColor)> scratch;
     if (rowBytes != tightRowBytes) {
-        if (this->glCaps().fPackRowLengthSupport) {
+        if (this->glCaps().packRowLengthSupport()) {
             GrAssert(!(rowBytes % sizeof(GrColor)));
             GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, rowBytes / sizeof(GrColor)));
             readDstRowBytes = rowBytes;
@@ -1568,17 +1352,17 @@
             readDst = scratch.get();
         }
     }
-    if (!invertY && this->glCaps().fPackFlipYSupport) {
+    if (!invertY && this->glCaps().packFlipYSupport()) {
         GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, 1));
     }
     GL_CALL(ReadPixels(readRect.fLeft, readRect.fBottom,
                        readRect.fWidth, readRect.fHeight,
                        format, type, readDst));
     if (readDstRowBytes != tightRowBytes) {
-        GrAssert(this->glCaps().fPackRowLengthSupport);
+        GrAssert(this->glCaps().packRowLengthSupport());
         GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
     }
-    if (!invertY && this->glCaps().fPackFlipYSupport) {
+    if (!invertY && this->glCaps().packFlipYSupport()) {
         GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, 0));
         invertY = true;
     }
@@ -1752,7 +1536,7 @@
     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
 
     if (rt->needsResolve()) {
-        GrAssert(GLCaps::kNone_MSFBO != fGLCaps.fMSFBOType);
+        GrAssert(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType());
         GrAssert(rt->textureFBOID() != rt->renderFBOID());
         GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER,
                                 rt->renderFBOID()));
@@ -1770,7 +1554,7 @@
         r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, 
                         dirtyRect.width(), dirtyRect.height());
 
-        if (GLCaps::kAppleES_MSFBO == fGLCaps.fMSFBOType) {
+        if (GrGLCaps::kAppleES_MSFBOType == this->glCaps().msFBOType()) {
             // Apple's extension uses the scissor as the blit bounds.
             GL_CALL(Enable(GR_GL_SCISSOR_TEST));
             GL_CALL(Scissor(r.fLeft, r.fBottom,
@@ -1779,9 +1563,10 @@
             fHWBounds.fScissorRect.invalidate();
             fHWBounds.fScissorEnabled = true;
         } else {
-            if (GLCaps::kDesktopARB_MSFBO != fGLCaps.fMSFBOType) {
+            if (GrGLCaps::kDesktopARB_MSFBOType != this->glCaps().msFBOType()) {
                 // this respects the scissor during the blit, so disable it.
-                GrAssert(GLCaps::kDesktopEXT_MSFBO == fGLCaps.fMSFBOType);
+                GrAssert(GrGLCaps::kDesktopEXT_MSFBOType ==
+                         this->glCaps().msFBOType());
                 this->flushScissor(NULL);
             }
             int right = r.fLeft + r.fWidth;
@@ -2185,7 +1970,7 @@
                                         GR_GL_TEXTURE_WRAP_T,
                                         newTexParams.fWrapT));
             }
-            if (this->glCaps().fTextureSwizzleSupport &&
+            if (this->glCaps().textureSwizzleSupport() &&
                 (setAll ||
                  memcmp(newTexParams.fSwizzleRGBA,
                         oldTexParams.fSwizzleRGBA,
@@ -2347,10 +2132,10 @@
             break;
         case kBGRA_8888_PM_GrPixelConfig:
         case kBGRA_8888_UPM_GrPixelConfig:
-            if (!fGLCaps.fBGRAFormatSupport) {
+            if (!this->glCaps().bgraFormatSupport()) {
                 return false;
             }
-            if (fGLCaps.fBGRAIsInternalFormat) {
+            if (this->glCaps().bgraIsInternalFormat()) {
                 if (getSizedInternalFormat) {
                     *internalFormat = GR_GL_BGRA8;
                 } else {
@@ -2503,42 +2288,7 @@
 int GrGpuGL::getMaxEdges() const {
     // FIXME:  This is a pessimistic estimate based on how many other things
     // want to add uniforms.  This should be centralized somewhere.
-    return GR_CT_MIN(fGLCaps.fMaxFragmentUniformVectors - 8,
+    return GR_CT_MIN(this->glCaps().maxFragmentUniformVectors() - 8,
                      GrDrawState::kMaxEdges);
 }
 
-void GrGpuGL::GLCaps::print() const {
-    for (int i = 0; i < fStencilFormats.count(); ++i) {
-        GrPrintf("Stencil Format %d, stencil bits: %02d, total bits: %02d\n",
-                 i,
-                 fStencilFormats[i].fFormat.fStencilBits,
-                 fStencilFormats[i].fFormat.fTotalBits);
-    }
-
-    GR_STATIC_ASSERT(0 == kNone_MSFBO);
-    GR_STATIC_ASSERT(1 == kDesktopARB_MSFBO);
-    GR_STATIC_ASSERT(2 == kDesktopEXT_MSFBO);
-    GR_STATIC_ASSERT(3 == kAppleES_MSFBO);
-    static const char* gMSFBOExtStr[] = {
-        "None",
-        "ARB",
-        "EXT",
-        "Apple",
-    };
-    GrPrintf("MSAA Type: %s\n", gMSFBOExtStr[fMSFBOType]);
-    GrPrintf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors);
-    GrPrintf("Support RGBA8 Render Buffer: %s\n",
-             (fRGBA8RenderbufferSupport ? "YES": "NO"));
-    GrPrintf("BGRA is an internal format: %s\n",
-             (fBGRAIsInternalFormat ? "YES": "NO"));
-    GrPrintf("Support texture swizzle: %s\n",
-             (fTextureSwizzleSupport ? "YES": "NO"));
-    GrPrintf("Unpack Row length support: %s\n",
-             (fUnpackRowLengthSupport ? "YES": "NO"));
-    GrPrintf("Unpack Flip Y support: %s\n",
-             (fUnpackFlipYSupport ? "YES": "NO"));
-    GrPrintf("Pack Row length support: %s\n",
-             (fPackRowLengthSupport ? "YES": "NO"));
-    GrPrintf("Pack Flip Y support: %s\n",
-             (fPackFlipYSupport ? "YES": "NO"));
-}
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index b3e5060..eac8d4f 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -49,116 +49,6 @@
 protected:
     GrGpuGL(const GrGLContextInfo& ctxInfo);
 
-    struct GLCaps {
-        GLCaps()
-            // make defaults be the most restrictive
-            : fStencilFormats(8) // prealloc space for    stencil formats
-            , fMSFBOType(kNone_MSFBO)
-            , fMaxFragmentUniformVectors(0)
-            , fRGBA8RenderbufferSupport(false)
-            , fBGRAFormatSupport(false)
-            , fBGRAIsInternalFormat(false)
-            , fTextureSwizzleSupport(false)
-            , fUnpackRowLengthSupport(false)
-            , fUnpackFlipYSupport(false)
-            , fPackRowLengthSupport(false)
-            , fPackFlipYSupport(false)
-            , fTextureUsageSupport(false)
-            , fTexStorageSupport(false) {
-            memset(&fVerifiedColorAttachmentConfigs, 0,
-                   sizeof(fVerifiedColorAttachmentConfigs));
-        }
-
-        // Call to note that a color config has been verified as a valid
-        // color attachment. This may save future calls to
-        // CheckFramebufferStatus
-        void markConfigAsValidColorAttachment(GrPixelConfig config);
-
-        // Call to check whether a config has been verified as a valid color
-        // attachment.
-        bool isConfigVerifiedColorAttachment(GrPixelConfig config) const;
-
-        // Call to note that a color config / stencil format pair passed
-        // FBO status check. We may skip calling CheckFramebufferStatus for
-        // this combination in the future.
-        void markColorConfigAndStencilFormatAsVerified(
-                        GrPixelConfig config,
-                        const GrGLStencilBuffer::Format& format);
-
-        // Call to check whether color config / stencil format pair has already
-        // passed FBO status check.
-        bool isColorConfigAndStencilFormatVerified(
-                        GrPixelConfig config,
-                        const GrGLStencilBuffer::Format& format) const;
-
-        void print() const;
-
-        struct StencilFormat {
-            GrGLStencilBuffer::Format fFormat;
-            uint32_t fVerifiedColorConfigs[(kGrPixelConfigCount  + 31) / 32];
-        };
-
-        SkTArray<StencilFormat, true> fStencilFormats;
-
-
-        enum {
-            /**
-             * no support for MSAA FBOs
-             */
-            kNone_MSFBO = 0,  
-            /**
-             * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object)
-             */
-            kDesktopARB_MSFBO,
-            /**
-             * earlier GL_EXT_framebuffer* extensions
-             */
-            kDesktopEXT_MSFBO,
-            /**
-             * GL_APPLE_framebuffer_multisample ES extension
-             */
-            kAppleES_MSFBO,
-        } fMSFBOType;
-
-        // The maximum number of fragment uniform vectors (GLES has min. 16).
-        int fMaxFragmentUniformVectors;
-
-        // ES requires an extension to support RGBA8 in RenderBufferStorage
-        bool fRGBA8RenderbufferSupport;
-
-        // Is GL_BGRA supported
-        bool fBGRAFormatSupport;
-
-        // Depending on the ES extensions present the BGRA external format may
-        // correspond either a BGRA or RGBA internalFormat. On desktop GL it is
-        // RGBA
-        bool fBGRAIsInternalFormat;
-
-        // GL_ARB_texture_swizzle support
-        bool fTextureSwizzleSupport;
-    
-        // Is there support for GL_UNPACK_ROW_LENGTH
-        bool fUnpackRowLengthSupport;
-
-        // Is there support for GL_UNPACK_FLIP_Y
-        bool fUnpackFlipYSupport;
-
-        // Is there support for GL_PACK_ROW_LENGTH
-        bool fPackRowLengthSupport;
-
-        // Is there support for GL_PACK_REVERSE_ROW_ORDER
-        bool fPackFlipYSupport;
-
-        // Is there support for texture parameter GL_TEXTURE_USAGE
-        bool fTextureUsageSupport;
-
-        // Is there support for glTexStorage
-        bool fTexStorageSupport;
-
-    private:
-        uint32_t fVerifiedColorAttachmentConfigs[(kGrPixelConfigCount  + 31) / 32];
-    } fGLCaps;
-
     struct {
         size_t                  fVertexOffset;
         GrVertexLayout          fVertexLayout;
@@ -196,7 +86,7 @@
         GrGLIRect   fViewportRect;
     } fHWBounds;
 
-    const GLCaps& glCaps() const { return fGLCaps; }
+    const GrGLCaps& glCaps() const { return fGLContextInfo.caps(); }
 
     // GrGpu overrides
     virtual void onResetContext() SK_OVERRIDE;
@@ -294,8 +184,7 @@
     static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
 
 private:
-    // Inits GrDrawTarget::Caps and GLCaps, sublcass may enable
-    // additional caps.
+    // Inits GrDrawTarget::Caps, sublcass may enable additional caps.
     void initCaps();
 
     void initFSAASupport();
diff --git a/src/gpu/gl/GrGpuGLShaders.cpp b/src/gpu/gl/GrGpuGLShaders.cpp
index 7fe7d4b..4093a0d 100644
--- a/src/gpu/gl/GrGpuGLShaders.cpp
+++ b/src/gpu/gl/GrGpuGLShaders.cpp
@@ -1091,7 +1091,7 @@
             }
 
             stage.fInConfigFlags = 0;
-            if (!this->glCaps().fTextureSwizzleSupport) {
+            if (!this->glCaps().textureSwizzleSupport()) {
                 if (GrPixelConfigIsAlphaOnly(texture->config())) {
                     // if we don't have texture swizzle support then
                     // the shader must do an alpha smear after reading