Use glGetStringi to get extensions when available.
Review URL: https://codereview.chromium.org/12328111

git-svn-id: http://skia.googlecode.com/svn/trunk@7872 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLContextInfo.cpp b/src/gpu/gl/GrGLContextInfo.cpp
index 7a33ac7..1522618 100644
--- a/src/gpu/gl/GrGLContextInfo.cpp
+++ b/src/gpu/gl/GrGLContextInfo.cpp
@@ -31,7 +31,7 @@
     fGLVersion = ctx.fGLVersion;
     fGLSLGeneration = ctx.fGLSLGeneration;
     fVendor = ctx.fVendor;
-    fExtensionString = ctx.fExtensionString;
+    fExtensions = ctx.fExtensions;
     fGLCaps = ctx.fGLCaps;
     return *this;
 }
@@ -42,7 +42,7 @@
     fGLVersion = GR_GL_VER(0, 0);
     fGLSLGeneration = static_cast<GrGLSLGeneration>(0);
     fVendor = kOther_GrGLVendor;
-    fExtensionString = "";
+    fExtensions.reset();
     fGLCaps.reset();
 }
 
@@ -50,14 +50,13 @@
     this->reset();
     // We haven't validated the GrGLInterface yet, so check for GetString
     // function pointer
-    if (NULL != interface->fGetString) {
-
+    if (interface->fGetString) {
         const GrGLubyte* verUByte;
         GR_GL_CALL_RET(interface, verUByte, GetString(GR_GL_VERSION));
         const char* ver = reinterpret_cast<const char*>(verUByte);
         GrGLBinding binding = GrGLGetBindingInUseFromString(ver);
 
-        if (interface->validate(binding)) {
+        if (0 != binding && interface->validate(binding) && fExtensions.init(binding, interface)) {
 
             fInterface = interface;
             interface->ref();
@@ -69,9 +68,6 @@
             fGLSLGeneration = GrGetGLSLGeneration(fBindingInUse,
                                                   this->interface());
 
-            const GrGLubyte* ext;
-            GR_GL_CALL_RET(interface, ext, GetString(GR_GL_EXTENSIONS));
-            fExtensionString = reinterpret_cast<const char*>(ext);
             fVendor = GrGLGetVendor(interface);
             fGLCaps.init(*this);
             return true;
diff --git a/src/gpu/gl/GrGLContextInfo.h b/src/gpu/gl/GrGLContextInfo.h
index a6c997f..bfadabe 100644
--- a/src/gpu/gl/GrGLContextInfo.h
+++ b/src/gpu/gl/GrGLContextInfo.h
@@ -9,6 +9,7 @@
 #ifndef GrGLContextInfo_DEFINED
 #define GrGLContextInfo_DEFINED
 
+#include "gl/GrGLExtensions.h"
 #include "gl/GrGLInterface.h"
 #include "GrGLCaps.h"
 #include "GrGLSL.h"
@@ -70,7 +71,7 @@
         if (!this->isInitialized()) {
             return false;
         }
-        return GrGLHasExtensionFromString(ext, fExtensionString.c_str());
+        return fExtensions.has(ext);
     }
 
 private:
@@ -81,7 +82,7 @@
     GrGLVersion          fGLVersion;
     GrGLSLGeneration     fGLSLGeneration;
     GrGLVendor           fVendor;
-    SkString             fExtensionString;
+    GrGLExtensions       fExtensions;
     GrGLCaps             fGLCaps;
 };
 
diff --git a/src/gpu/gl/GrGLCreateNullInterface.cpp b/src/gpu/gl/GrGLCreateNullInterface.cpp
index d221218..da6491a 100644
--- a/src/gpu/gl/GrGLCreateNullInterface.cpp
+++ b/src/gpu/gl/GrGLCreateNullInterface.cpp
@@ -215,6 +215,7 @@
         interface->fGetShaderInfoLog = noOpGLGetInfoLog;
         interface->fGetShaderiv = noOpGLGetShaderOrProgramiv;
         interface->fGetString = noOpGLGetString;
+        interface->fGetStringi = noOpGLGetStringi;
         interface->fGetTexLevelParameteriv = noOpGLGetTexLevelParameteriv;
         interface->fGetUniformLocation = noOpGLGetUniformLocation;
         interface->fLineWidth = noOpGLLineWidth;
diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h
index 852c025..e0e8398 100644
--- a/src/gpu/gl/GrGLDefines.h
+++ b/src/gpu/gl/GrGLDefines.h
@@ -10,6 +10,11 @@
 #ifndef GrGLDefines_DEFINED
 #define GrGLDefines_DEFINED
 
+/* Profiles */
+#define GR_GL_CONTEXT_PROFILE_MASK              0x9126
+#define GR_GL_CONTEXT_CORE_PROFILE_BIT          0x00000001
+#define GR_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+
 // The following constants consist of the intersection of GL constants
 // exported by GLES 1.0, GLES 2.0, and desktop GL required by the system.
 
@@ -356,6 +361,9 @@
 #define GR_GL_VERSION                        0x1F02
 #define GR_GL_EXTENSIONS                     0x1F03
 
+/* StringCounts */
+#define GR_GL_NUM_EXTENSIONS                 0x821D
+
 /* Pixel Mode / Transfer */
 #define GR_GL_UNPACK_ROW_LENGTH              0x0CF2
 #define GR_GL_PACK_ROW_LENGTH                0x0D02
diff --git a/src/gpu/gl/GrGLExtensions.cpp b/src/gpu/gl/GrGLExtensions.cpp
new file mode 100644
index 0000000..b5df2cc
--- /dev/null
+++ b/src/gpu/gl/GrGLExtensions.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gl/GrGLExtensions.h"
+#include "gl/GrGLDefines.h"
+#include "gl/GrGLUtil.h"
+
+bool GrGLExtensions::init(GrGLBinding binding,
+                          GrGLGetStringProc getString,
+                          GrGLGetStringiProc getStringi,
+                          GrGLGetIntegervProc getIntegerv) {
+    fStrings.reset();
+    if (NULL == getString) {
+        return false;
+    }
+    bool indexed = false;
+    if (kDesktop_GrGLBinding == binding) {
+        const GrGLubyte* verString = getString(GR_GL_VERSION);
+        if (NULL == verString) {
+            return false;
+        }
+        GrGLVersion version = GrGLGetVersionFromString((const char*) verString);
+        indexed = version >= GR_GL_VER(3, 0);
+    }
+    if (indexed) {
+        if (NULL == getStringi || NULL == getIntegerv) {
+            return false;
+        }
+        GrGLint extensionCnt = 0;
+        getIntegerv(GR_GL_NUM_EXTENSIONS, &extensionCnt);
+        fStrings.push_back_n(extensionCnt);
+        for (int i = 0; i < extensionCnt; ++i) {
+            const char* ext = (const char*) getStringi(GR_GL_EXTENSIONS, i);
+            fStrings[i] = ext;
+        }
+    } else {
+        const char* extensions = (const char*) getString(GR_GL_EXTENSIONS);
+        if (NULL == extensions) {
+            return false;
+        }
+        // First count the extensions so that we don't cause the array to malloc multiple times.
+        int extensionCnt = 1;
+        const char* e = (const char*) extensions;
+        while (NULL != (e = strchr(e+1, ' '))) {
+            e += 1;
+            ++extensionCnt;
+        }
+        fStrings.push_back_n(extensionCnt);
+        
+        int i = 0;
+        while (true) {
+            size_t length = strcspn(extensions, " ");
+            GrAssert(i < extensionCnt);
+            fStrings[i].set(extensions, length);
+            ++i;
+            if ('\0' == extensions[length]) {
+                break;
+            }
+            extensions += length + 1;
+        }
+        GrAssert(i == extensionCnt);
+    }
+    return true;
+}
+
+bool GrGLExtensions::has(const char* ext) const {
+    // TODO: Sort the extensions and binary search.
+    int count = fStrings.count();
+    for (int i = 0; i < count; ++i) {
+        if (fStrings[i].equals(ext)) {
+            return true;
+        }
+    }
+    return false;
+}
diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp
index 61020bc..f1be64f 100644
--- a/src/gpu/gl/GrGLInterface.cpp
+++ b/src/gpu/gl/GrGLInterface.cpp
@@ -7,7 +7,8 @@
 
 
 #include "gl/GrGLInterface.h"
-#include "GrGLUtil.h"
+#include "gl/GrGLExtensions.h"
+#include "gl/GrGLUtil.h"
 
 #include <stdio.h>
 
@@ -37,6 +38,11 @@
     if (0 == (binding & fBindingsExported)) {
         return false;
     }
+    
+    GrGLExtensions extensions;
+    if (!extensions.init(binding, this)) {
+        return false;
+    }
 
     // functions that are always required
     if (NULL == fActiveTexture ||
@@ -131,9 +137,7 @@
         return false;
     }
 
-    const char* ext;
     GrGLVersion glVer = GrGLGetVersion(this);
-    ext = (const char*)fGetString(GR_GL_EXTENSIONS);
 
     // Now check that baseline ES/Desktop fns not covered above are present
     // and that we have fn pointers for any advertised extensions that we will
@@ -160,15 +164,13 @@
         if (glVer >= GR_GL_VER(3,0) && NULL == fBindFragDataLocation) {
             return false;
         }
-        if (glVer >= GR_GL_VER(2,0) ||
-            GrGLHasExtensionFromString("GL_ARB_draw_buffers", ext)) {
+        if (glVer >= GR_GL_VER(2,0) || extensions.has("GL_ARB_draw_buffers")) {
             if (NULL == fDrawBuffers) {
                 return false;
             }
         }
 
-        if (glVer >= GR_GL_VER(1,5) ||
-            GrGLHasExtensionFromString("GL_ARB_occlusion_query", ext)) {
+        if (glVer >= GR_GL_VER(1,5) || extensions.has("GL_ARB_occlusion_query")) {
             if (NULL == fGenQueries ||
                 NULL == fDeleteQueries ||
                 NULL == fBeginQuery ||
@@ -180,15 +182,14 @@
             }
         }
         if (glVer >= GR_GL_VER(3,3) ||
-            GrGLHasExtensionFromString("GL_ARB_timer_query", ext) ||
-            GrGLHasExtensionFromString("GL_EXT_timer_query", ext)) {
+            extensions.has("GL_ARB_timer_query") ||
+            extensions.has("GL_EXT_timer_query")) {
             if (NULL == fGetQueryObjecti64v ||
                 NULL == fGetQueryObjectui64v) {
                 return false;
             }
         }
-        if (glVer >= GR_GL_VER(3,3) ||
-            GrGLHasExtensionFromString("GL_ARB_timer_query", ext)) {
+        if (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) {
             if (NULL == fQueryCounter) {
                 return false;
             }
@@ -202,7 +203,7 @@
              NULL == fLoadMatrixf)) {
             return false;
         }
-        if (false && GrGLHasExtensionFromString("GL_NV_path_rendering", ext)) {
+        if (false && extensions.has("GL_NV_path_rendering")) {
             if (NULL == fPathCommands ||
                 NULL == fPathCoords ||
                 NULL == fPathSubCommands ||
@@ -259,8 +260,8 @@
 
     // optional function on desktop before 1.3
     if (kDesktop_GrGLBinding != binding ||
-        (glVer >= GR_GL_VER(1,3) ||
-        GrGLHasExtensionFromString("GL_ARB_texture_compression", ext))) {
+        (glVer >= GR_GL_VER(1,3)) ||
+        extensions.has("GL_ARB_texture_compression")) {
         if (NULL == fCompressedTexImage2D) {
             return false;
         }
@@ -279,13 +280,13 @@
     // There is a desktop ARB extension and an ES+desktop EXT extension
     if (kDesktop_GrGLBinding == binding) {
         if (glVer >= GR_GL_VER(4,2) ||
-            GrGLHasExtensionFromString("GL_ARB_texture_storage", ext) ||
-            GrGLHasExtensionFromString("GL_EXT_texture_storage", ext)) {
+            extensions.has("GL_ARB_texture_storage") ||
+            extensions.has("GL_EXT_texture_storage")) {
             if (NULL == fTexStorage2D) {
                 return false;
             }
         }
-    } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", ext)) {
+    } else if (extensions.has("GL_EXT_texture_storage")) {
         if (NULL == fTexStorage2D) {
             return false;
         }
@@ -294,29 +295,29 @@
     // FBO MSAA
     if (kDesktop_GrGLBinding == binding) {
         // GL 3.0 and the ARB extension have multisample + blit
-        if (glVer >= GR_GL_VER(3,0) || GrGLHasExtensionFromString("GL_ARB_framebuffer_object", ext)) {
+        if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) {
             if (NULL == fRenderbufferStorageMultisample ||
                 NULL == fBlitFramebuffer) {
                 return false;
             }
         } else {
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit", ext) &&
+            if (extensions.has("GL_EXT_framebuffer_blit") &&
                 NULL == fBlitFramebuffer) {
                 return false;
             }
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", ext) &&
+            if (extensions.has("GL_EXT_framebuffer_multisample") &&
                 NULL == fRenderbufferStorageMultisample) {
                 return false;
             }
         }
     } else {
-        if (GrGLHasExtensionFromString("GL_CHROMIUM_framebuffer_multisample", ext)) {
+        if (extensions.has("GL_CHROMIUM_framebuffer_multisample")) {
             if (NULL == fRenderbufferStorageMultisample ||
                 NULL == fBlitFramebuffer) {
                 return false;
             }
         }
-        if (GrGLHasExtensionFromString("GL_APPLE_framebuffer_multisample", ext)) {
+        if (extensions.has("GL_APPLE_framebuffer_multisample")) {
             if (NULL == fRenderbufferStorageMultisample ||
                 NULL == fResolveMultisampleFramebuffer) {
                 return false;
@@ -327,8 +328,7 @@
     // On ES buffer mapping is an extension. On Desktop
     // buffer mapping was part of original VBO extension
     // which we require.
-    if (kDesktop_GrGLBinding == binding ||
-        GrGLHasExtensionFromString("GL_OES_mapbuffer", ext)) {
+    if (kDesktop_GrGLBinding == binding || extensions.has("GL_OES_mapbuffer")) {
         if (NULL == fMapBuffer ||
             NULL == fUnmapBuffer) {
             return false;
@@ -337,12 +337,17 @@
 
     // Dual source blending
     if (kDesktop_GrGLBinding == binding &&
-        (glVer >= GR_GL_VER(3,3) ||
-         GrGLHasExtensionFromString("GL_ARB_blend_func_extended", ext))) {
+        (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_blend_func_extended"))) {
         if (NULL == fBindFragDataLocationIndexed) {
             return false;
         }
     }
+    
+    if (kDesktop_GrGLBinding == binding && glVer >= GR_GL_VER(3, 0)) {
+        if (NULL == fGetStringi) {
+            return false;
+        }
+    }
 
     return true;
 }
diff --git a/src/gpu/gl/GrGLNoOpInterface.cpp b/src/gpu/gl/GrGLNoOpInterface.cpp
index 5dd6e66..e830ee1 100644
--- a/src/gpu/gl/GrGLNoOpInterface.cpp
+++ b/src/gpu/gl/GrGLNoOpInterface.cpp
@@ -6,6 +6,8 @@
  */
 
 #include "GrGLNoOpInterface.h"
+#include "SkString.h"
+#include "SkThread.h"
 
 // the OpenGLES 2.0 spec says this must be >= 128
 static const GrGLint kDefaultMaxVertexUniformVectors = 128;
@@ -19,6 +21,33 @@
 // the OpenGLES 2.0 spec says this must be >= 8
 static const GrGLint kDefaultMaxVaryingVectors = 8;
 
+static const char* kExtensions[] = {
+    "GL_ARB_framebuffer_object",
+    "GL_ARB_blend_func_extended",
+    "GL_ARB_timer_query",
+    "GL_ARB_draw_buffers",
+    "GL_ARB_occlusion_query",
+    "GL_EXT_blend_color",
+    "GL_EXT_stencil_wrap"
+};
+
+namespace {
+const GrGLubyte* combined_extensions_string() {
+    static SkString gExtString;
+    static SkMutex gMutex;
+    gMutex.acquire();
+    if (0 == gExtString.size()) {
+        for (size_t i = 0; i < GR_ARRAY_COUNT(kExtensions) - 1; ++i) {
+            gExtString.append(kExtensions[i]);
+            gExtString.append(" ");
+        }
+        gExtString.append(kExtensions[GR_ARRAY_COUNT(kExtensions) - 1]);
+    }
+    gMutex.release();
+    return (const GrGLubyte*) gExtString.c_str();
+}
+}
+
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLBlendColor(GrGLclampf red,
                                               GrGLclampf green,
                                               GrGLclampf blue,
@@ -53,9 +82,9 @@
 }
 
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLColorMask(GrGLboolean red,
-                                              GrGLboolean green,
-                                              GrGLboolean blue,
-                                              GrGLboolean alpha) {
+                                             GrGLboolean green,
+                                             GrGLboolean blue,
+                                             GrGLboolean alpha) {
 }
 
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLCompileShader(GrGLuint shader) {
@@ -132,9 +161,9 @@
 }
 
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLScissor(GrGLint x,
-                                            GrGLint y,
-                                            GrGLsizei width,
-                                            GrGLsizei height) {
+                                           GrGLint y,
+                                           GrGLsizei width,
+                                           GrGLsizei height) {
 }
 
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLShaderSource(GrGLuint shader,
@@ -318,15 +347,15 @@
 }
 
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLViewport(GrGLint x,
-                                             GrGLint y,
-                                             GrGLsizei width,
-                                             GrGLsizei height) {
+                                            GrGLint y,
+                                            GrGLsizei width,
+                                            GrGLsizei height) {
 }
 
   GrGLvoid GR_GL_FUNCTION_TYPE noOpGLGetFramebufferAttachmentParameteriv(GrGLenum target,
-                                                                        GrGLenum attachment,
-                                                                        GrGLenum pname,
-                                                                        GrGLint* params) {
+                                                                         GrGLenum attachment,
+                                                                         GrGLenum pname,
+                                                                         GrGLint* params) {
 }
 
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLGetRenderbufferParameteriv(GrGLenum target,
@@ -393,6 +422,9 @@
     // TODO: remove from Ganesh the #defines for gets we don't use.
     // We would like to minimize gets overall due to performance issues
     switch (pname) {
+        case GR_GL_CONTEXT_PROFILE_MASK:
+            *params = GR_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
+            break;
         case GR_GL_STENCIL_BITS:
             *params = 8;
             break;
@@ -440,6 +472,9 @@
         case GR_GL_MAX_VARYING_VECTORS:
             *params = kDefaultMaxVaryingVectors;
             break;
+        case GR_GL_NUM_EXTENSIONS:
+            *params = GR_ARRAY_COUNT(kExtensions);
+            break;
         default:
             GrCrash("Unexpected pname to GetIntegerv");
    }
@@ -448,7 +483,7 @@
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLGetInfoLog(GrGLuint program,
                                               GrGLsizei bufsize,
                                               GrGLsizei* length,
-                                               char* infolog) {
+                                              char* infolog) {
     if (length) {
         *length = 0;
    }
@@ -534,7 +569,7 @@
 const GrGLubyte* GR_GL_FUNCTION_TYPE noOpGLGetString(GrGLenum name) {
     switch (name) {
         case GR_GL_EXTENSIONS:
-            return (const GrGLubyte*)"GL_ARB_framebuffer_object GL_ARB_blend_func_extended GL_ARB_timer_query GL_ARB_draw_buffers GL_ARB_occlusion_query GL_EXT_blend_color GL_EXT_stencil_wrap";
+            return combined_extensions_string();
         case GR_GL_VERSION:
             return (const GrGLubyte*)"4.0 Debug GL";
         case GR_GL_SHADING_LANGUAGE_VERSION:
@@ -544,11 +579,25 @@
         case GR_GL_RENDERER:
             return (const GrGLubyte*)"The Debug (Non-)Renderer";
         default:
-            GrCrash("Unexpected name to GetString");
+            GrCrash("Unexpected name passed to GetString");
             return NULL;
    }
 }
 
+const GrGLubyte* GR_GL_FUNCTION_TYPE noOpGLGetStringi(GrGLenum name, GrGLuint i) {
+    switch (name) {
+        case GR_GL_EXTENSIONS:
+            if (static_cast<size_t>(i) <= GR_ARRAY_COUNT(kExtensions)) {
+                return (const GrGLubyte*) kExtensions[i];
+            } else {
+                return NULL;
+            }
+        default:
+            GrCrash("Unexpected name passed to GetStringi");
+            return NULL;
+    }
+}
+
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLGetTexLevelParameteriv(GrGLenum target,
                                                           GrGLint level,
                                                           GrGLenum pname,
@@ -558,8 +607,7 @@
     GrCrash("Should never query texture parameters.");
 }
 
-GrGLint GR_GL_FUNCTION_TYPE noOpGLGetUniformLocation(GrGLuint program,
-                                                     const char* name) {
+GrGLint GR_GL_FUNCTION_TYPE noOpGLGetUniformLocation(GrGLuint program, const char* name) {
     static int gUniLocation = 0;
     return ++gUniLocation;
 }
diff --git a/src/gpu/gl/GrGLNoOpInterface.h b/src/gpu/gl/GrGLNoOpInterface.h
index 0b3865d..79695e5 100644
--- a/src/gpu/gl/GrGLNoOpInterface.h
+++ b/src/gpu/gl/GrGLNoOpInterface.h
@@ -335,6 +335,8 @@
 
 const GrGLubyte* GR_GL_FUNCTION_TYPE noOpGLGetString(GrGLenum name);
 
+const GrGLubyte* GR_GL_FUNCTION_TYPE noOpGLGetStringi(GrGLenum name, GrGLuint i);
+
 GrGLvoid GR_GL_FUNCTION_TYPE noOpGLGetTexLevelParameteriv(GrGLenum target,
                                                           GrGLint level,
                                                           GrGLenum pname,
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index 88c81b7..f4c5da6 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -8,7 +8,6 @@
 
 #include "GrGLUtil.h"
 
-
 void GrGLClearErr(const GrGLInterface* gl) {
     while (GR_GL_NO_ERROR != gl->fGetError()) {}
 }
@@ -149,23 +148,6 @@
     return 0;
 }
 
-bool GrGLHasExtensionFromString(const char* ext, const char* extensionString) {
-    int extLength = strlen(ext);
-
-    while (true) {
-        int n = strcspn(extensionString, " ");
-        if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
-            return true;
-        }
-        if (0 == extensionString[n]) {
-            return false;
-        }
-        extensionString += n+1;
-    }
-
-    return false;
-}
-
 GrGLVendor GrGLGetVendorFromString(const char* vendorString) {
     if (NULL != vendorString) {
         if (0 == strcmp(vendorString, "ARM")) {
@@ -181,12 +163,6 @@
     return kOther_GrGLVendor;
 }
 
-bool GrGLHasExtension(const GrGLInterface* gl, const char* ext) {
-    const GrGLubyte* glstr;
-    GR_GL_CALL_RET(gl, glstr, GetString(GR_GL_EXTENSIONS));
-    return GrGLHasExtensionFromString(ext, (const char*) glstr);
-}
-
 GrGLBinding GrGLGetBindingInUse(const GrGLInterface* gl) {
     const GrGLubyte* v;
     GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION));
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index 30995a9..ea84480 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -71,11 +71,9 @@
 GrGLVersion GrGLGetVersionFromString(const char* versionString);
 GrGLBinding GrGLGetBindingInUseFromString(const char* versionString);
 GrGLSLVersion GrGLGetGLSLVersionFromString(const char* versionString);
-bool GrGLHasExtensionFromString(const char* ext, const char* extensionString);
 GrGLVendor GrGLGetVendorFromString(const char* vendorString);
 
 // these variants call glGetString()
-bool GrGLHasExtension(const GrGLInterface*, const char* ext);
 GrGLBinding GrGLGetBindingInUse(const GrGLInterface*);
 GrGLVersion GrGLGetVersion(const GrGLInterface*);
 GrGLSLVersion GrGLGetGLSLVersion(const GrGLInterface*);
diff --git a/src/gpu/gl/SkGLContext.cpp b/src/gpu/gl/SkGLContext.cpp
index c1b9505..6076845 100644
--- a/src/gpu/gl/SkGLContext.cpp
+++ b/src/gpu/gl/SkGLContext.cpp
@@ -6,7 +6,7 @@
  * found in the LICENSE file.
  */
 #include "gl/SkGLContext.h"
-#include "gl/GrGLUtil.h"
+#include "GrGLUtil.h"
 
 SK_DEFINE_INST_COUNT(SkGLContext)
 
@@ -29,10 +29,6 @@
     SkSafeUnref(fGL);
 }
 
-bool SkGLContext::hasExtension(const char* extensionName) const {
-    return GrGLHasExtensionFromString(extensionName, fExtensionString.c_str());
-}
-
 bool SkGLContext::init(int width, int height) {
     if (fGL) {
         fGL->unref();
@@ -43,8 +39,13 @@
     if (fGL) {
         const GrGLubyte* temp;
 
-        SK_GL_RET(*this, temp, GetString(GR_GL_EXTENSIONS));
-        fExtensionString = reinterpret_cast<const char*>(temp);
+        GrGLBinding bindingInUse = GrGLGetBindingInUse(this->gl());
+
+        if (!fGL->validate(bindingInUse) || !fExtensions.init(bindingInUse, fGL)) {
+            fGL = NULL;
+            this->destroyGLContext();
+            return false;
+        }
 
         SK_GL_RET(*this, temp, GetString(GR_GL_VERSION));
         const char* versionStr = reinterpret_cast<const char*>(temp);
@@ -56,8 +57,6 @@
             SK_GL_RET(*this, error, GetError());
         } while (GR_GL_NO_ERROR != error);
 
-        GrGLBinding bindingInUse = GrGLGetBindingInUse(this->gl());
-
         SK_GL(*this, GenFramebuffers(1, &fFBO));
         SK_GL(*this, BindFramebuffer(GR_GL_FRAMEBUFFER, fFBO));
         SK_GL(*this, GenRenderbuffers(1, &fColorBufferID));
@@ -83,12 +82,11 @@
         // depth stencil being available.
         bool supportsPackedDepthStencil;
         if (kES2_GrGLBinding == bindingInUse) {
-            supportsPackedDepthStencil =
-                    this->hasExtension("GL_OES_packed_depth_stencil");
+            supportsPackedDepthStencil = this->hasExtension("GL_OES_packed_depth_stencil");
         } else {
             supportsPackedDepthStencil = version >= GR_GL_VER(3,0) ||
-                    this->hasExtension("GL_EXT_packed_depth_stencil") ||
-                    this->hasExtension("GL_ARB_framebuffer_object");
+                                         this->hasExtension("GL_EXT_packed_depth_stencil") ||
+                                         this->hasExtension("GL_ARB_framebuffer_object");
         }
 
         if (supportsPackedDepthStencil) {
diff --git a/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp b/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp
index ef76586..ab3501c 100644
--- a/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp
+++ b/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp
@@ -814,6 +814,7 @@
     interface->fGetShaderInfoLog = noOpGLGetInfoLog;
     interface->fGetShaderiv = noOpGLGetShaderOrProgramiv;
     interface->fGetString = noOpGLGetString;
+    interface->fGetStringi = noOpGLGetStringi;
     interface->fGetTexLevelParameteriv = noOpGLGetTexLevelParameteriv;
     interface->fGetUniformLocation = noOpGLGetUniformLocation;
     interface->fLineWidth = noOpGLLineWidth;
diff --git a/src/gpu/gl/mac/GrGLCreateNativeInterface_mac.cpp b/src/gpu/gl/mac/GrGLCreateNativeInterface_mac.cpp
index fce96f4..7307540 100644
--- a/src/gpu/gl/mac/GrGLCreateNativeInterface_mac.cpp
+++ b/src/gpu/gl/mac/GrGLCreateNativeInterface_mac.cpp
@@ -8,7 +8,8 @@
 
 
 #include "gl/GrGLInterface.h"
-#include "../GrGLUtil.h"
+#include "gl/GrGLExtensions.h"
+#include "GrGLUtil.h"
 
 #include <OpenGL/gl.h>
 #include <OpenGL/glext.h>
@@ -31,8 +32,12 @@
         glInterface.reset(interface);
         const char* verStr = (const char*) glGetString(GL_VERSION);
         GrGLVersion ver = GrGLGetVersionFromString(verStr);
-        const char* extStr = (const char*) glGetString(GL_EXTENSIONS);
-
+        GrGLExtensions extensions;
+        GrGLGetStringiProc glGetStringi = (GrGLGetStringiProc) GetProcAddress("glGetStringi");
+        if (!extensions.init(kDesktop_GrGLBinding, glGetString, glGetStringi, glGetIntegerv)) {
+            glInterface.reset(NULL);
+            return NULL;
+        }
         interface->fBindingsExported = kDesktop_GrGLBinding;
         interface->fActiveTexture = glActiveTexture;
         interface->fAttachShader = glAttachShader;
@@ -51,8 +56,8 @@
 
         if (ver >= GR_GL_VER(1,4)) {
             interface->fBlendColor = glBlendColor;
-        } else if (GrGLHasExtensionFromString("GL_ARB_imaging", extStr) ||
-                   GrGLHasExtensionFromString("GL_EXT_blend_color", extStr)) {
+        } else if (extensions.has("GL_ARB_imaging") ||
+                   extensions.has("GL_EXT_blend_color")) {
             GET_PROC(BlendColor);
         }
 
@@ -74,8 +79,7 @@
         interface->fDeleteTextures = glDeleteTextures;
         interface->fDepthMask = glDepthMask;
         interface->fDisable = glDisable;
-        interface->fDisableVertexAttribArray =
-                                            glDisableVertexAttribArray;
+        interface->fDisableVertexAttribArray = glDisableVertexAttribArray;
         interface->fDrawArrays = glDrawArrays;
         interface->fDrawBuffer = glDrawBuffer;
         interface->fDrawBuffers = glDrawBuffers;
@@ -99,6 +103,7 @@
         interface->fGetShaderInfoLog = glGetShaderInfoLog;
         interface->fGetShaderiv = glGetShaderiv;
         interface->fGetString = glGetString;
+        interface->fGetStringi = glGetStringi;
         interface->fGetTexLevelParameteriv = glGetTexLevelParameteriv;
         interface->fGenTextures = glGenTextures;
         interface->fGetUniformLocation = glGetUniformLocation;
@@ -131,10 +136,9 @@
     #elif GL_EXT_texture_storage
         interface->fTexStorage2D = glTexStorage2DEXT;
     #else
-        if (ver >= GR_GL_VER(4,2) ||
-            GrGLHasExtensionFromString("GL_ARB_texture_storage", extStr)) {
+        if (ver >= GR_GL_VER(4,2) || extensions.has("GL_ARB_texture_storage")) {
             GET_PROC(TexStorage2D);
-        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extStr)) {
+        } else if (extensions.has("GL_EXT_texture_storage")) {
             GET_PROC_SUFFIX(TexStorage2D, EXT);
         }
     #endif
@@ -165,7 +169,7 @@
         interface->fVertexAttribPointer = glVertexAttribPointer;
         interface->fViewport = glViewport;
 
-        if (ver >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_timer_query", extStr)) {
+        if (ver >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) {
             // ARB extension doesn't use the ARB suffix on the function name
             #if GL_ARB_timer_query || GL_VERSION_3_3
                 interface->fQueryCounter = glQueryCounter;
@@ -176,7 +180,7 @@
                 interface->fGetQueryObjecti64v = GET_PROC(GetQueryObjecti64v);
                 interface->fGetQueryObjectui64v = GET_PROC(GetQueryObjectui64v);
             #endif
-        } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extStr)) {
+        } else if (extensions.has("GL_EXT_timer_query")) {
             #if GL_EXT_timer_query
                 interface->fGetQueryObjecti64v = glGetQueryObjecti64vEXT;
                 interface->fGetQueryObjectui64v = glGetQueryObjectui64vEXT;
@@ -186,7 +190,7 @@
             #endif
         }
 
-        if (ver >= GR_GL_VER(3,0) || GrGLHasExtensionFromString("GL_ARB_framebuffer_object", extStr)) {
+        if (ver >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) {
             // ARB extension doesn't use the ARB suffix on the function names
             #if GL_VERSION_3_0 || GL_ARB_framebuffer_object
                 interface->fGenFramebuffers = glGenFramebuffers;
@@ -220,7 +224,7 @@
                 interface->fBlitFramebuffer = GET_PROC(BlitFramebuffer);
             #endif
         } else {
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object", extStr)) {
+            if (extensions.has("GL_EXT_framebuffer_object")) {
                 #if GL_EXT_framebuffer_object
                     interface->fGenFramebuffers = glGenFramebuffersEXT;
                     interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameterivEXT;
@@ -249,14 +253,14 @@
                     interface->fBindRenderbuffer = GET_PROC_SUFFIX(BindRenderbuffer, EXT);
                 #endif
             }
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", extStr)) {
+            if (extensions.has("GL_EXT_framebuffer_multisample")) {
                 #if GL_EXT_framebuffer_multisample
                     interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT;
                 #else
                     interface->fRenderbufferStorageMultisample = GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
                 #endif
             }
-            if (GrGLHasExtensionFromString("", extStr)) {
+            if (extensions.has("GL_EXT_framebuffer_blit")) {
                 #if GL_EXT_framebuffer_blit
                     interface->fBlitFramebuffer = glBlitFramebufferEXT;
                 #else
@@ -264,7 +268,7 @@
                 #endif
             }
         }
-        if (ver >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_blend_func_extended", extStr)) {
+        if (ver >= GR_GL_VER(3,3) || extensions.has("GL_ARB_blend_func_extended")) {
             // ARB extension doesn't use the ARB suffix on the function name
             #if GL_VERSION_3_3 || GL_ARB_blend_func_extended
                 interface->fBindFragDataLocationIndexed = glBindFragDataLocationIndexed;
@@ -272,8 +276,6 @@
                 interface->fBindFragDataLocationIndexed = GET_PROC(BindFragDataLocationIndexed);
             #endif
         }
-
-        interface->fBindingsExported = kDesktop_GrGLBinding;
     }
     glInterface.get()->ref();
     return glInterface.get();
diff --git a/src/gpu/gl/mac/SkNativeGLContext_mac.cpp b/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
index 460fad7..b821f3d 100644
--- a/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
+++ b/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
@@ -36,7 +36,7 @@
 
     CGLPixelFormatAttribute attributes[] = {
 #if 0
-        kCGLPFAOpenGLProfile, kCGLOGLPVersion_3_2_Core,
+        kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core,
 #endif
         (CGLPixelFormatAttribute)0
     };
diff --git a/src/gpu/gl/mesa/GrGLCreateMesaInterface.cpp b/src/gpu/gl/mesa/GrGLCreateMesaInterface.cpp
index 1b4b7f6..74f6a51 100644
--- a/src/gpu/gl/mesa/GrGLCreateMesaInterface.cpp
+++ b/src/gpu/gl/mesa/GrGLCreateMesaInterface.cpp
@@ -6,7 +6,7 @@
  * found in the LICENSE file.
  */
 
-
+#include "gl/GrGLExtensions.h"
 #include "gl/GrGLInterface.h"
 #include "../GrGLUtil.h"
 
@@ -23,9 +23,20 @@
 
 const GrGLInterface* GrGLCreateMesaInterface() {
     if (NULL != OSMesaGetCurrentContext()) {
-        GrGLGetStringProc getString = (GrGLGetStringProc) OSMesaGetProcAddress("glGetString");
+
+        GrGLGetStringProc getString =
+            (GrGLGetStringProc) OSMesaGetProcAddress("glGetString");
+        GrGLGetStringiProc glGetStringi =
+            (GrGLGetStringiProc) OSMesaGetProcAddress("glGetStringi");
+        GrGLGetIntegervProc glGetIntegerv =
+        (GrGLGetIntegervProc) OSMesaGetProcAddress("glGetIntegerv");
+
+        GrGLExtensions extensions;
+        if (!extensions.init(kDesktop_GrGLBinding, glGetString, glGetStringi, glGetIntegerv)) {
+            return NULL;
+        }
+
         const char* versionString = (const char*) getString(GL_VERSION);
-        const char* extString = (const char*) getString(GL_EXTENSIONS);
         GrGLVersion glVer = GrGLGetVersionFromString(versionString);
 
         if (glVer < GR_GL_VER(1,5)) {
@@ -44,8 +55,8 @@
         GR_GL_GET_PROC(BlendFunc);
 
         if (glVer >= GR_GL_VER(1,4) ||
-            GrGLHasExtensionFromString("GL_ARB_imaging", extString) ||
-            GrGLHasExtensionFromString("GL_EXT_blend_color", extString)) {
+            extensions.has("GL_ARB_imaging") ||
+            extensions.has("GL_EXT_blend_color")) {
             GR_GL_GET_PROC(BlendColor);
         }
 
@@ -85,12 +96,11 @@
         GR_GL_GET_PROC(GetIntegerv);
         GR_GL_GET_PROC(GetProgramInfoLog);
         GR_GL_GET_PROC(GetProgramiv);
-        if (glVer >= GR_GL_VER(3,3) ||
-            GrGLHasExtensionFromString("GL_ARB_timer_query", extString)) {
+        if (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) {
             GR_GL_GET_PROC(GetQueryObjecti64v);
             GR_GL_GET_PROC(GetQueryObjectui64v)
             GR_GL_GET_PROC(QueryCounter);
-        } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extString)) {
+        } else if (extensions.has("GL_EXT_timer_query")) {
             GR_GL_GET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
             GR_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
         }
@@ -100,6 +110,7 @@
         GR_GL_GET_PROC(GetShaderInfoLog);
         GR_GL_GET_PROC(GetShaderiv);
         GR_GL_GET_PROC(GetString);
+        GR_GL_GET_PROC(GetStringi);
         GR_GL_GET_PROC(GetTexLevelParameteriv);
         GR_GL_GET_PROC(GenTextures);
         GR_GL_GET_PROC(GetUniformLocation);
@@ -152,9 +163,7 @@
 
         // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
         // GL_ARB_framebuffer_object doesn't use ARB suffix.)
-        if (glVer >= GR_GL_VER(3,0) ||
-            GrGLHasExtensionFromString("GL_ARB_framebuffer_object",
-                                        extString)) {
+        if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) {
             GR_GL_GET_PROC(GenFramebuffers);
             GR_GL_GET_PROC(GetFramebufferAttachmentParameteriv);
             GR_GL_GET_PROC(GetRenderbufferParameteriv);
@@ -169,8 +178,7 @@
             GR_GL_GET_PROC(BindRenderbuffer);
             GR_GL_GET_PROC(RenderbufferStorageMultisample);
             GR_GL_GET_PROC(BlitFramebuffer);
-        } else if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object",
-                                              extString)) {
+        } else if (extensions.has("GL_EXT_framebuffer_object")) {
             GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
             GR_GL_GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
             GR_GL_GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
@@ -183,12 +191,10 @@
             GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
             GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
             GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample",
-                                           extString)) {
+            if (extensions.has("GL_EXT_framebuffer_multisample")) {
                 GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
             }
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit",
-                                           extString)) {
+            if (extensions.has("GL_EXT_framebuffer_blit")) {
                 GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
             }
         } else {
diff --git a/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp b/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp
index 04d35d1..2965e7f 100644
--- a/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp
+++ b/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp
@@ -7,6 +7,7 @@
  */
 
 
+#include "gl/GrGLExtensions.h"
 #include "gl/GrGLInterface.h"
 #include "../GrGLUtil.h"
 
@@ -22,10 +23,19 @@
 
 const GrGLInterface* GrGLCreateNativeInterface() {
     if (NULL != glXGetCurrentContext()) {
+
         const char* versionString = (const char*) glGetString(GL_VERSION);
-        const char* extString = (const char*) glGetString(GL_EXTENSIONS);
         GrGLVersion glVer = GrGLGetVersionFromString(versionString);
 
+        // This may or may not succeed depending on the gl version.
+        GrGLGetStringiProc glGetStringi =
+            (GrGLGetStringiProc) glXGetProcAddress(reinterpret_cast<const GLubyte*>("glGetStringi"));
+
+        GrGLExtensions extensions;
+        if (!extensions.init(kDesktop_GrGLBinding, glGetString, glGetStringi, glGetIntegerv)) {
+            return NULL;
+        }
+
         if (glVer < GR_GL_VER(1,5)) {
             // We must have array and element_array buffer objects.
             return NULL;
@@ -43,8 +53,8 @@
         interface->fBlendFunc = glBlendFunc;
 
         if (glVer >= GR_GL_VER(1,4) ||
-            GrGLHasExtensionFromString("GL_ARB_imaging", extString) ||
-            GrGLHasExtensionFromString("GL_EXT_blend_color", extString)) {
+            extensions.has("GL_ARB_imaging") ||
+            extensions.has("GL_EXT_blend_color")) {
             GR_GL_GET_PROC(BlendColor);
         }
 
@@ -83,12 +93,11 @@
         interface->fGetIntegerv = glGetIntegerv;
         GR_GL_GET_PROC(GetQueryObjectiv);
         GR_GL_GET_PROC(GetQueryObjectuiv);
-        if (glVer >= GR_GL_VER(3,3) ||
-            GrGLHasExtensionFromString("GL_ARB_timer_query", extString)) {
+        if (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) {
             GR_GL_GET_PROC(GetQueryObjecti64v);
             GR_GL_GET_PROC(GetQueryObjectui64v);
             GR_GL_GET_PROC(QueryCounter);
-        } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extString)) {
+        } else if (extensions.has("GL_EXT_timer_query")) {
             GR_GL_GET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
             GR_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
         }
@@ -98,6 +107,7 @@
         GR_GL_GET_PROC(GetShaderInfoLog);
         GR_GL_GET_PROC(GetShaderiv);
         interface->fGetString = glGetString;
+        GR_GL_GET_PROC(GetStringi);
         interface->fGetTexLevelParameteriv = glGetTexLevelParameteriv;
         GR_GL_GET_PROC(GenQueries);
         interface->fGenTextures = glGenTextures;
@@ -108,8 +118,7 @@
         interface->fPixelStorei = glPixelStorei;
         interface->fReadBuffer = glReadBuffer;
         interface->fReadPixels = glReadPixels;
-        if (GrGLHasExtensionFromString("GL_NV_framebuffer_multisample_coverage",
-                                       extString)) {
+        if (extensions.has("GL_NV_framebuffer_multisample_coverage")) {
             GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisampleCoverage, NV);
         }
         interface->fScissor = glScissor;
@@ -123,10 +132,9 @@
         interface->fTexImage2D = glTexImage2D;
         interface->fTexParameteri = glTexParameteri;
         interface->fTexParameteriv = glTexParameteriv;
-        if (glVer >= GR_GL_VER(4,2) ||
-            GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
+        if (glVer >= GR_GL_VER(4,2) || extensions.has("GL_ARB_texture_storage")) {
             GR_GL_GET_PROC(TexStorage2D);
-        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
+        } else if (extensions.has("GL_EXT_texture_storage")) {
             GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
         }
         interface->fTexSubImage2D = glTexSubImage2D;
@@ -158,9 +166,7 @@
 
         // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
         // GL_ARB_framebuffer_object doesn't use ARB suffix.)
-        if (glVer >= GR_GL_VER(3,0) ||
-            GrGLHasExtensionFromString("GL_ARB_framebuffer_object",
-                                       extString)) {
+        if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) {
             GR_GL_GET_PROC(GenFramebuffers);
             GR_GL_GET_PROC(GetFramebufferAttachmentParameteriv);
             GR_GL_GET_PROC(GetRenderbufferParameteriv);
@@ -175,8 +181,7 @@
             GR_GL_GET_PROC(BindRenderbuffer);
             GR_GL_GET_PROC(RenderbufferStorageMultisample);
             GR_GL_GET_PROC(BlitFramebuffer);
-        } else if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object",
-                                              extString)) {
+        } else if (extensions.has("GL_EXT_framebuffer_object")) {
             GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
             GR_GL_GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
             GR_GL_GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
@@ -189,12 +194,10 @@
             GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
             GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
             GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample",
-                                             extString)) {
+            if (extensions.has("GL_EXT_framebuffer_multisample")) {
                 GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
             }
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit",
-                                             extString)) {
+            if (extensions.has("GL_EXT_framebuffer_blit")) {
                 GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
             }
         } else {
diff --git a/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp b/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp
index 64f073a..e08d8d4 100644
--- a/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp
+++ b/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp
@@ -7,8 +7,9 @@
  */
 
 
+#include "gl/GrGLExtensions.h"
 #include "gl/GrGLInterface.h"
-#include "../GrGLUtil.h"
+#include "gl/GrGLUtil.h"
 #define WIN32_LEAN_AND_MEAN
 #include <Windows.h>
 
@@ -48,12 +49,26 @@
     if (NULL == alu.get()) {
         return NULL;
     }
-    GrGLGetStringProc glGetString =
-        (GrGLGetStringProc) GetProcAddress(alu.get(), "glGetString");
 
     if (NULL != wglGetCurrentContext()) {
+
+        // These should always be present and don't require wglGetProcAddress
+        GrGLGetStringProc glGetString =
+            (GrGLGetStringProc) GetProcAddress(alu.get(), "glGetString");
+        GrGLGetIntegervProc glGetIntegerv =
+            (GrGLGetIntegervProc) GetProcAddress(alu.get(), "glGetIntegerv");
+        if (NULL == glGetString || NULL == glGetIntegerv) {
+            return NULL;
+        }
+
+        // This may or may not succeed depending on the gl version.
+        GrGLGetStringiProc glGetStringi = (GrGLGetStringiProc)  wglGetProcAddress("glGetStringi");
+
+        GrGLExtensions extensions;
+        if (!extensions.init(kDesktop_GrGLBinding, glGetString, glGetStringi, glGetIntegerv)) {
+            return NULL;
+        }
         const char* versionString = (const char*) glGetString(GR_GL_VERSION);
-        const char* extString = (const char*) glGetString(GR_GL_EXTENSIONS);
         GrGLVersion glVer = GrGLGetVersionFromString(versionString);
 
         if (glVer < GR_GL_VER(1,5)) {
@@ -68,8 +83,8 @@
         SET_PROC(BlendFunc)
 
         if (glVer >= GR_GL_VER(1,4) ||
-            GrGLHasExtensionFromString("GL_ARB_imaging", extString) ||
-            GrGLHasExtensionFromString("GL_EXT_blend_color", extString)) {
+            extensions.has("GL_ARB_imaging") ||
+            extensions.has("GL_EXT_blend_color")) {
             WGL_SET_PROC(BlendColor);
         }
 
@@ -107,10 +122,9 @@
         SET_PROC(TexImage2D)
         SET_PROC(TexParameteri)
         SET_PROC(TexParameteriv)
-        if (glVer >= GR_GL_VER(4,2) ||
-            GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
+        if (glVer >= GR_GL_VER(4,2) || extensions.has("GL_ARB_texture_storage")) {
             WGL_SET_PROC(TexStorage2D);
-        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
+        } else if (extensions.has("GL_EXT_texture_storage")) {
             WGL_SET_PROC_SUFFIX(TexStorage2D, EXT);
         }
         SET_PROC(TexSubImage2D)
@@ -142,12 +156,11 @@
         WGL_SET_PROC(GetQueryiv);
         WGL_SET_PROC(GetQueryObjectiv);
         WGL_SET_PROC(GetQueryObjectuiv);
-        if (glVer > GR_GL_VER(3,3) ||
-            GrGLHasExtensionFromString("GL_ARB_timer_query", extString)) {
+        if (glVer > GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) {
             WGL_SET_PROC(GetQueryObjecti64v);
             WGL_SET_PROC(GetQueryObjectui64v);
             WGL_SET_PROC(QueryCounter);
-        } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extString)) {
+        } else if (extensions.has("GL_EXT_timer_query")) {
             WGL_SET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
             WGL_SET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
         }
@@ -155,9 +168,10 @@
         WGL_SET_PROC(GetProgramiv);
         WGL_SET_PROC(GetShaderInfoLog);
         WGL_SET_PROC(GetShaderiv);
+        WGL_SET_PROC(GetStringi)
         WGL_SET_PROC(GetUniformLocation);
         WGL_SET_PROC(LinkProgram);
-        if (GrGLHasExtensionFromString("GL_NV_framebuffer_multisample_coverage", extString)) {
+        if (extensions.has("GL_NV_framebuffer_multisample_coverage")) {
             WGL_SET_PROC_SUFFIX(RenderbufferStorageMultisampleCoverage, NV);
         }
         WGL_SET_PROC(ShaderSource);
@@ -190,8 +204,7 @@
 
         // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
         // GL_ARB_framebuffer_object doesn't use ARB suffix.)
-        if (glVer > GR_GL_VER(3,0) ||
-            GrGLHasExtensionFromString("GL_ARB_framebuffer_object", extString)) {
+        if (glVer > GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) {
             WGL_SET_PROC(GenFramebuffers);
             WGL_SET_PROC(GetFramebufferAttachmentParameteriv);
             WGL_SET_PROC(GetRenderbufferParameteriv);
@@ -206,8 +219,7 @@
             WGL_SET_PROC(BindRenderbuffer);
             WGL_SET_PROC(RenderbufferStorageMultisample);
             WGL_SET_PROC(BlitFramebuffer);
-        } else if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object",
-                   extString)) {
+        } else if (extensions.has("GL_EXT_framebuffer_object")) {
             WGL_SET_PROC_SUFFIX(GenFramebuffers, EXT);
             WGL_SET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
             WGL_SET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
@@ -220,10 +232,10 @@
             WGL_SET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
             WGL_SET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
             WGL_SET_PROC_SUFFIX(BindRenderbuffer, EXT);
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", extString)) {
+            if (extensions.has("GL_EXT_framebuffer_multisample")) {
                 WGL_SET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
             }
-            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit", extString)) {
+            if (extensions.has("GL_EXT_framebuffer_blit")) {
                 WGL_SET_PROC_SUFFIX(BlitFramebuffer, EXT);
             }
         } else {
@@ -234,7 +246,7 @@
         WGL_SET_PROC(MapBuffer);
         WGL_SET_PROC(UnmapBuffer);
 
-        if (GrGLHasExtensionFromString("GL_NV_path_rendering", extString)) {
+        if (extensions.has("GL_NV_path_rendering")) {
             WGL_SET_PROC_SUFFIX(PathCommands, NV);
             WGL_SET_PROC_SUFFIX(PathCoords, NV);
             WGL_SET_PROC_SUFFIX(PathSubCommands, NV);