Backed out changeset 9438150c5258 (bug 1262265) for mass android test bustage CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Mon, 11 Apr 2016 15:42:37 -0700
changeset 292650 cc130a8f204d7cabd016c1ac2cd15ddc661a6f72
parent 292649 fdbce2b4457876ab90f70b5bb8d99de2834f4d01
child 292662 968ccb3b3ed87f564a7a44036961e8d6155eb6e4
push id74944
push userkwierso@gmail.com
push dateMon, 11 Apr 2016 22:42:47 +0000
treeherdermozilla-inbound@cc130a8f204d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1262265
milestone48.0a1
backs out9438150c5258f3c48e20d24e4a6c602ea4de423f
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 9438150c5258 (bug 1262265) for mass android test bustage CLOSED TREE MozReview-Commit-ID: FsPsAyGT3Vi
dom/canvas/WebGLContext.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextCGL.h
gfx/gl/GLContextEAGL.h
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEAGL.mm
gfx/gl/GLLibraryLoader.cpp
gfx/gl/GLLibraryLoader.h
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1470,17 +1470,17 @@ static bool
 CheckContextLost(GLContext* gl, bool* const out_isGuilty)
 {
     MOZ_ASSERT(gl);
     MOZ_ASSERT(out_isGuilty);
 
     bool isEGL = gl->GetContextType() == gl::GLContextType::EGL;
 
     GLenum resetStatus = LOCAL_GL_NO_ERROR;
-    if (gl->IsSupported(GLFeature::robustness)) {
+    if (gl->HasRobustness()) {
         gl->MakeCurrent();
         resetStatus = gl->fGetGraphicsResetStatus();
     } else if (isEGL) {
         // Simulate a ARB_robustness guilty context loss for when we
         // get an EGL_CONTEXT_LOST error. It may not actually be guilty,
         // but we can't make any distinction.
         if (!gl->MakeCurrent(true) && gl->IsContextLost()) {
             resetStatus = LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB;
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -60,17 +60,17 @@ uint32_t GLContext::sDebugMode = 0;
 // If adding defines, don't forget to undefine symbols. See #undef block below.
 #define CORE_SYMBOL(x) { (PRFuncPtr*) &mSymbols.f##x, { #x, nullptr } }
 #define CORE_EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x, #x #y, #x #z, nullptr } }
 #define EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, nullptr } }
 #define EXT_SYMBOL3(x,y,z,w) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, #x #w, nullptr } }
 #define END_SYMBOLS { nullptr, { nullptr } }
 
 // should match the order of GLExtensions, and be null-terminated.
-static const char* const sExtensionNames[] = {
+static const char *const sExtensionNames[] = {
     "NO_EXTENSION",
     "GL_AMD_compressed_ATC_texture",
     "GL_ANGLE_depth_texture",
     "GL_ANGLE_framebuffer_blit",
     "GL_ANGLE_framebuffer_multisample",
     "GL_ANGLE_instanced_arrays",
     "GL_ANGLE_texture_compression_dxt3",
     "GL_ANGLE_texture_compression_dxt5",
@@ -394,25 +394,27 @@ ParseGLVersion(GLContext* gl, uint32_t* 
         return false;
     }
 
     *out_version = (uint32_t)majorVersion * 100 + (uint32_t)minorVersion * 10;
     return true;
 }
 
 GLContext::GLContext(const SurfaceCaps& caps,
-                     GLContext* sharedContext,
-                     bool isOffscreen)
-  : mIsOffscreen(isOffscreen),
+          GLContext* sharedContext,
+          bool isOffscreen)
+  : mInitialized(false),
+    mIsOffscreen(isOffscreen),
     mContextLost(false),
     mVersion(0),
     mProfile(ContextProfile::Unknown),
     mShadingLanguageVersion(0),
     mVendor(GLVendor::Other),
     mRenderer(GLRenderer::Other),
+    mHasRobustness(false),
     mTopError(LOCAL_GL_NO_ERROR),
     mSharedContext(sharedContext),
     mCaps(caps),
     mScreen(nullptr),
     mLockedSurface(nullptr),
     mMaxTextureSize(0),
     mMaxCubeMapTextureSize(0),
     mMaxTextureImageSize(0),
@@ -452,103 +454,37 @@ GLContext::StaticDebugCallback(GLenum so
                                const GLchar* message,
                                const GLvoid* userParam)
 {
     GLContext* gl = (GLContext*)userParam;
     gl->DebugCallback(source, type, id, severity, length, message);
 }
 
 static void
-ClearSymbols(const GLLibraryLoader::SymLoadStruct* symbols)
+ClearSymbols(GLLibraryLoader::SymLoadStruct *symbols)
 {
     while (symbols->symPointer) {
         *symbols->symPointer = nullptr;
         symbols++;
     }
 }
 
 bool
-GLContext::InitWithPrefix(const char* prefix, bool trygl)
-{
-    MOZ_RELEASE_ASSERT(!mSymbols.fBindFramebuffer,
-                       "InitWithPrefix should only be called once.");
-
-    ScopedGfxFeatureReporter reporter("GL Context");
-
-    if (!InitWithPrefixImpl(prefix, trygl)) {
-        // If initialization fails, zero the symbols to avoid hard-to-understand bugs.
-        mSymbols.Zero();
-        NS_WARNING("GLContext::InitWithPrefix failed!");
-        return false;
-    }
-
-    reporter.SetSuccessful();
-    return true;
-}
-
-static bool
-LoadGLSymbols(GLContext* gl, const char* prefix, bool trygl,
-              const GLLibraryLoader::SymLoadStruct* list, const char* desc)
-{
-    if (gl->LoadSymbols(list, trygl, prefix))
-        return true;
-
-    ClearSymbols(list);
-
-    if (desc) {
-        const nsPrintfCString err("Failed to load symbols for %s.", desc);
-        NS_ERROR(err.BeginReading());
-    }
-    return false;
-}
-
-bool
-GLContext::LoadExtSymbols(const char* prefix, bool trygl, const SymLoadStruct* list,
-                          GLExtensions ext)
+GLContext::InitWithPrefix(const char *prefix, bool trygl)
 {
-    const char* extName = sExtensionNames[size_t(ext)];
-    if (!LoadGLSymbols(this, prefix, trygl, list, extName)) {
-        MarkExtensionUnsupported(ext);
-        return false;
-    }
-    return true;
-};
-
-bool
-GLContext::LoadFeatureSymbols(const char* prefix, bool trygl, const SymLoadStruct* list,
-                              GLFeature feature)
-{
-    const char* featureName = GetFeatureName(feature);
-    if (!LoadGLSymbols(this, prefix, trygl, list, featureName)) {
-        MarkUnsupported(feature);
-        return false;
+    ScopedGfxFeatureReporter reporter("GL Context");
+
+    if (mInitialized) {
+        reporter.SetSuccessful();
+        return true;
     }
-    return true;
-};
-
-bool
-GLContext::InitWithPrefixImpl(const char* prefix, bool trygl)
-{
+
     mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs();
 
-#ifdef MOZ_GL_DEBUG
-    if (gfxEnv::GlDebug())
-        sDebugMode |= DebugEnabled;
-
-    // enables extra verbose output, informing of the start and finish of every GL call.
-    // useful e.g. to record information to investigate graphics system crashes/lockups
-    if (gfxEnv::GlDebugVerbose())
-        sDebugMode |= DebugTrace;
-
-    // aborts on GL error. Can be useful to debug quicker code that is known not to generate any GL error in principle.
-    if (gfxEnv::GlDebugAbortOnError())
-        sDebugMode |= DebugAbortOnError;
-#endif
-
-    const SymLoadStruct coreSymbols[] = {
+    SymLoadStruct symbols[] = {
         { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBlendColor, { "BlendColor", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBlendEquation, { "BlendEquation", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBlendEquationSeparate, { "BlendEquationSeparate", "BlendEquationSeparateEXT", nullptr } },
@@ -665,932 +601,1198 @@ GLContext::InitWithPrefixImpl(const char
         { (PRFuncPtr*) &mSymbols.fCreateShader, { "CreateShader", "CreateShaderARB", nullptr } },
 
         { (PRFuncPtr*) &mSymbols.fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fDeleteShader, { "DeleteShader", "DeleteShaderARB", nullptr } },
 
         END_SYMBOLS
+
     };
 
-    if (!LoadGLSymbols(this, prefix, trygl, coreSymbols, "GL"))
-        return false;
-
-    ////////////////
-
+    mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
     MakeCurrent();
-    MOZ_ASSERT(mProfile != ContextProfile::Unknown);
-
-    uint32_t version = 0;
-    ParseGLVersion(this, &version);
-
-    mShadingLanguageVersion = 100;
-    ParseGLSLVersion(this, &mShadingLanguageVersion);
-
-    if (ShouldSpew()) {
-        printf_stderr("OpenGL version detected: %u\n", version);
-        printf_stderr("OpenGL shading language version detected: %u\n", mShadingLanguageVersion);
-        printf_stderr("OpenGL vendor: %s\n", fGetString(LOCAL_GL_VENDOR));
-        printf_stderr("OpenGL renderer: %s\n", fGetString(LOCAL_GL_RENDERER));
+    if (mInitialized) {
+        MOZ_ASSERT(mProfile != ContextProfile::Unknown);
+
+        uint32_t version = 0;
+        ParseGLVersion(this, &version);
+
+        mShadingLanguageVersion = 100;
+        ParseGLSLVersion(this, &mShadingLanguageVersion);
+
+        if (ShouldSpew()) {
+            printf_stderr("OpenGL version detected: %u\n", version);
+            printf_stderr("OpenGL shading language version detected: %u\n", mShadingLanguageVersion);
+            printf_stderr("OpenGL vendor: %s\n", fGetString(LOCAL_GL_VENDOR));
+            printf_stderr("OpenGL renderer: %s\n", fGetString(LOCAL_GL_RENDERER));
+        }
+
+        if (version >= mVersion) {
+            mVersion = version;
+        }
+        // Don't fail if version < mVersion, see bug 999445,
+        // Mac OSX 10.6/10.7 machines with Intel GPUs claim only OpenGL 1.4 but
+        // have all the GL2+ extensions that we need.
     }
 
-    if (version >= mVersion) {
-        mVersion = version;
-    }
-    // Don't fail if version < mVersion, see bug 999445,
-    // Mac OSX 10.6/10.7 machines with Intel GPUs claim only OpenGL 1.4 but
-    // have all the GL2+ extensions that we need.
-
-    ////////////////
-
     // Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
-    if (IsGLES()) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDepthRangef, { "DepthRangef", nullptr } },
-            END_SYMBOLS
-        };
-
-        if (!LoadGLSymbols(this, prefix, trygl, symbols, "OpenGL ES"))
-            return false;
-    } else {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fClearDepth, { "ClearDepth", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDepthRange, { "DepthRange", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fMapBuffer, { "MapBuffer", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fPointParameterf, { "PointParameterf", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDrawBuffer, { "DrawBuffer", nullptr } },
-            // The following functions are only used by Skia/GL in desktop mode.
-            // Other parts of Gecko should avoid using these
-            { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fClientActiveTexture, { "ClientActiveTexture", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDisableClientState, { "DisableClientState", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fEnableClientState, { "EnableClientState", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fLoadIdentity, { "LoadIdentity", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fLoadMatrixf, { "LoadMatrixf", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fMatrixMode, { "MatrixMode", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fTexGeni, { "TexGeni", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fTexGenf, { "TexGenf", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fTexGenfv, { "TexGenfv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fVertexPointer, { "VertexPointer", nullptr } },
-            END_SYMBOLS
-        };
-
-        if (!LoadGLSymbols(this, prefix, trygl, symbols, "Desktop OpenGL"))
-            return false;
-    }
-
-    ////////////////
-
-    const char* glVendorString = (const char*)fGetString(LOCAL_GL_VENDOR);
-    const char* glRendererString = (const char*)fGetString(LOCAL_GL_RENDERER);
-    if (!glVendorString || !glRendererString)
-        return false;
-
-    // The order of these strings must match up with the order of the enum
-    // defined in GLContext.h for vendor IDs.
-    const char* vendorMatchStrings[size_t(GLVendor::Other)] = {
-        "Intel",
-        "NVIDIA",
-        "ATI",
-        "Qualcomm",
-        "Imagination",
-        "nouveau",
-        "Vivante",
-        "VMware, Inc.",
-        "ARM"
-    };
-
-    mVendor = GLVendor::Other;
-    for (size_t i = 0; i < size_t(GLVendor::Other); ++i) {
-        if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) {
-            mVendor = GLVendor(i);
-            break;
-        }
-    }
-
-    // The order of these strings must match up with the order of the enum
-    // defined in GLContext.h for renderer IDs.
-    const char* rendererMatchStrings[size_t(GLRenderer::Other)] = {
-        "Adreno 200",
-        "Adreno 205",
-        "Adreno (TM) 200",
-        "Adreno (TM) 205",
-        "Adreno (TM) 320",
-        "Adreno (TM) 420",
-        "PowerVR SGX 530",
-        "PowerVR SGX 540",
-        "NVIDIA Tegra",
-        "Android Emulator",
-        "Gallium 0.4 on llvmpipe",
-        "Intel HD Graphics 3000 OpenGL Engine",
-        "Microsoft Basic Render Driver"
-    };
-
-    mRenderer = GLRenderer::Other;
-    for (size_t i = 0; i < size_t(GLRenderer::Other); ++i) {
-        if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) {
-            mRenderer = GLRenderer(i);
-            break;
-        }
-    }
-
-    if (ShouldSpew()) {
-        const char* vendors[size_t(GLVendor::Other)] = {
-            "Intel",
-            "NVIDIA",
-            "ATI",
-            "Qualcomm"
-        };
-
-        MOZ_ASSERT(glVendorString);
-        if (mVendor < GLVendor::Other) {
-            printf_stderr("OpenGL vendor ('%s') recognized as: %s\n",
-                          glVendorString, vendors[size_t(mVendor)]);
-        } else {
-            printf_stderr("OpenGL vendor ('%s') not recognized.\n", glVendorString);
-        }
-    }
-
-    ////////////////
-
-    // We need this for retrieving the list of extensions on Core profiles.
-    if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetStringi, { "GetStringi", nullptr } },
-            END_SYMBOLS
-        };
-
-        if (LoadGLSymbols(this, prefix, trygl, symbols, "get_string_indexed")) {
-            MOZ_RELEASE_ASSERT(false, "get_string_indexed is required!");
-            return false;
-        }
-    }
-
-    InitExtensions();
-    InitFeatures();
-
-    // Disable extensions with partial or incorrect support.
-    if (WorkAroundDriverBugs()) {
-        if (Renderer() == GLRenderer::AdrenoTM320) {
-            MarkUnsupported(GLFeature::standard_derivatives);
-        }
-
-        if (Vendor() == GLVendor::Vivante) {
-            // bug 958256
-            MarkUnsupported(GLFeature::standard_derivatives);
-        }
-
-        if (Renderer() == GLRenderer::MicrosoftBasicRenderDriver) {
-            // Bug 978966: on Microsoft's "Basic Render Driver" (software renderer)
-            // multisampling hardcodes blending with the default blendfunc, which breaks WebGL.
-            MarkUnsupported(GLFeature::framebuffer_multisample);
-        }
-
-#ifdef XP_MACOSX
-        // The Mac Nvidia driver, for versions up to and including 10.8,
-        // don't seem to properly support this.  See 814839
-        // this has been fixed in Mac OS X 10.9. See 907946
-        // and it also works in 10.8.3 and higher.  See 1094338.
-        if (Vendor() == gl::GLVendor::NVIDIA &&
-            !nsCocoaFeatures::IsAtLeastVersion(10,8,3))
-        {
-            MarkUnsupported(GLFeature::depth_texture);
-        }
-#endif
-    }
-
-    if (IsExtensionSupported(GLContext::ARB_pixel_buffer_object)) {
-        MOZ_ASSERT((mSymbols.fMapBuffer && mSymbols.fUnmapBuffer),
-                   "ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer"
-                   " being available!");
-    }
-
-    ////////////////////////////////////////////////////////////////////////////
-
-    const auto fnLoadForFeature = [this, prefix, trygl](const SymLoadStruct* list,
-                                                        GLFeature feature)
-    {
-        return this->LoadFeatureSymbols(prefix, trygl, list, feature);
-    };
-
-    // Check for ARB_framebuffer_objects
-    if (IsSupported(GLFeature::framebuffer_object)) {
-        // https://www.opengl.org/registry/specs/ARB/framebuffer_object.txt
-        const SymLoadStruct symbols[] = {
-            CORE_SYMBOL(IsRenderbuffer),
-            CORE_SYMBOL(BindRenderbuffer),
-            CORE_SYMBOL(DeleteRenderbuffers),
-            CORE_SYMBOL(GenRenderbuffers),
-            CORE_SYMBOL(RenderbufferStorage),
-            CORE_SYMBOL(RenderbufferStorageMultisample),
-            CORE_SYMBOL(GetRenderbufferParameteriv),
-            CORE_SYMBOL(IsFramebuffer),
-            CORE_SYMBOL(BindFramebuffer),
-            CORE_SYMBOL(DeleteFramebuffers),
-            CORE_SYMBOL(GenFramebuffers),
-            CORE_SYMBOL(CheckFramebufferStatus),
-            CORE_SYMBOL(FramebufferTexture2D),
-            CORE_SYMBOL(FramebufferTextureLayer),
-            CORE_SYMBOL(FramebufferRenderbuffer),
-            CORE_SYMBOL(GetFramebufferAttachmentParameteriv),
-            CORE_SYMBOL(BlitFramebuffer),
-            CORE_SYMBOL(GenerateMipmap),
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::framebuffer_object);
-    }
-
-    if (!IsSupported(GLFeature::framebuffer_object)) {
-        // Check for aux symbols based on extensions
-        if (IsSupported(GLFeature::framebuffer_object_EXT_OES)) {
-            const SymLoadStruct symbols[] = {
-                CORE_EXT_SYMBOL2(IsRenderbuffer, EXT, OES),
-                CORE_EXT_SYMBOL2(BindRenderbuffer, EXT, OES),
-                CORE_EXT_SYMBOL2(DeleteRenderbuffers, EXT, OES),
-                CORE_EXT_SYMBOL2(GenRenderbuffers, EXT, OES),
-                CORE_EXT_SYMBOL2(RenderbufferStorage, EXT, OES),
-                CORE_EXT_SYMBOL2(GetRenderbufferParameteriv, EXT, OES),
-                CORE_EXT_SYMBOL2(IsFramebuffer, EXT, OES),
-                CORE_EXT_SYMBOL2(BindFramebuffer, EXT, OES),
-                CORE_EXT_SYMBOL2(DeleteFramebuffers, EXT, OES),
-                CORE_EXT_SYMBOL2(GenFramebuffers, EXT, OES),
-                CORE_EXT_SYMBOL2(CheckFramebufferStatus, EXT, OES),
-                CORE_EXT_SYMBOL2(FramebufferTexture2D, EXT, OES),
-                CORE_EXT_SYMBOL2(FramebufferRenderbuffer, EXT, OES),
-                CORE_EXT_SYMBOL2(GetFramebufferAttachmentParameteriv, EXT, OES),
-                CORE_EXT_SYMBOL2(GenerateMipmap, EXT, OES),
+    if (mInitialized) {
+        if (IsGLES()) {
+            SymLoadStruct symbols_ES2[] = {
+                { (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDepthRangef, { "DepthRangef", nullptr } },
                 END_SYMBOLS
             };
-            fnLoadForFeature(symbols, GLFeature::framebuffer_object_EXT_OES);
-        }
-
-        if (IsSupported(GLFeature::framebuffer_blit)) {
-            const SymLoadStruct symbols[] = {
-                EXT_SYMBOL3(BlitFramebuffer, ANGLE, EXT, NV),
-                END_SYMBOLS
-            };
-            fnLoadForFeature(symbols, GLFeature::framebuffer_blit);
-        }
-
-        if (IsSupported(GLFeature::framebuffer_multisample)) {
-            const SymLoadStruct symbols[] = {
-                EXT_SYMBOL3(RenderbufferStorageMultisample, ANGLE, APPLE, EXT),
+
+            if (!LoadSymbols(&symbols_ES2[0], trygl, prefix)) {
+                NS_ERROR("OpenGL ES 2.0 supported, but symbols could not be loaded.");
+                mInitialized = false;
+            }
+        } else {
+            SymLoadStruct symbols_desktop[] = {
+                { (PRFuncPtr*) &mSymbols.fClearDepth, { "ClearDepth", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDepthRange, { "DepthRange", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fMapBuffer, { "MapBuffer", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fPointParameterf, { "PointParameterf", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDrawBuffer, { "DrawBuffer", nullptr } },
+                    // These functions are only used by Skia/GL in desktop mode.
+                    // Other parts of Gecko should avoid using these
+                    { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fClientActiveTexture, { "ClientActiveTexture", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fDisableClientState, { "DisableClientState", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fEnableClientState, { "EnableClientState", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fLoadIdentity, { "LoadIdentity", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fLoadMatrixf, { "LoadMatrixf", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fMatrixMode, { "MatrixMode", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fTexGeni, { "TexGeni", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fTexGenf, { "TexGenf", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fTexGenfv, { "TexGenfv", nullptr } },
+                    { (PRFuncPtr*) &mSymbols.fVertexPointer, { "VertexPointer", nullptr } },
                 END_SYMBOLS
             };
-            fnLoadForFeature(symbols, GLFeature::framebuffer_multisample);
-        }
-
-        if (IsExtensionSupported(GLContext::ARB_geometry_shader4) ||
-            IsExtensionSupported(GLContext::NV_geometry_program4))
-        {
-            const SymLoadStruct symbols[] = {
-                EXT_SYMBOL2(FramebufferTextureLayer, ARB, EXT),
-                END_SYMBOLS
-            };
-            if (!LoadGLSymbols(this, prefix, trygl, symbols,
-                               "ARB_geometry_shader4/NV_geometry_program4"))
-            {
-                MarkExtensionUnsupported(GLContext::ARB_geometry_shader4);
-                MarkExtensionUnsupported(GLContext::NV_geometry_program4);
+
+            if (!LoadSymbols(&symbols_desktop[0], trygl, prefix)) {
+                NS_ERROR("Desktop symbols failed to load.");
+                mInitialized = false;
             }
         }
     }
 
-    if (!IsSupported(GLFeature::framebuffer_object) &&
-        !IsSupported(GLFeature::framebuffer_object_EXT_OES))
-    {
-        NS_ERROR("GLContext requires support for framebuffer objects.");
-        return false;
-    }
-    MOZ_RELEASE_ASSERT(mSymbols.fBindFramebuffer);
-
-    ////////////////
-
-    LoadMoreSymbols(prefix, trygl);
-
-    ////////////////////////////////////////////////////////////////////////////
-
-    raw_fGetIntegerv(LOCAL_GL_VIEWPORT, mViewportRect);
-    raw_fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mScissorRect);
-    raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
-    raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize);
-    raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
-    raw_fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
-
-#ifdef XP_MACOSX
-    if (mWorkAroundDriverBugs) {
-        if (mVendor == GLVendor::Intel) {
-            // see bug 737182 for 2D textures, bug 684882 for cube map textures.
-            mMaxTextureSize        = std::min(mMaxTextureSize,        4096);
-            mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 512);
-            // for good measure, we align renderbuffers on what we do for 2D textures
-            mMaxRenderbufferSize   = std::min(mMaxRenderbufferSize,   4096);
-            mNeedsTextureSizeChecks = true;
-        } else if (mVendor == GLVendor::NVIDIA) {
-            if (nsCocoaFeatures::OnMountainLionOrLater()) {
-                // See bug 879656.  8192 fails, 8191 works.
-                mMaxTextureSize = std::min(mMaxTextureSize, 8191);
-                mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 8191);
-            } else {
-                // See bug 877949.
-                mMaxTextureSize = std::min(mMaxTextureSize, 4096);
-                mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);
-            }
-
-            // Part of the bug 879656, but it also doesn't hurt the 877949
-            mNeedsTextureSizeChecks = true;
-        }
-    }
-#endif
-#ifdef MOZ_X11
-    if (mWorkAroundDriverBugs) {
-        if (mVendor == GLVendor::Nouveau) {
-            // see bug 814716. Clamp MaxCubeMapTextureSize at 2K for Nouveau.
-            mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 2048);
-            mNeedsTextureSizeChecks = true;
-        } else if (mVendor == GLVendor::Intel) {
-            // Bug 1199923. Driver seems to report a larger max size than
-            // actually supported.
-            mMaxTextureSize /= 2;
-            mMaxRenderbufferSize /= 2;
-            mNeedsTextureSizeChecks = true;
-        }
-    }
-#endif
-    if (mWorkAroundDriverBugs &&
-        Renderer() == GLRenderer::AdrenoTM420) {
-        // see bug 1194923. Calling glFlush before glDeleteFramebuffers
-        // prevents occasional driver crash.
-        mNeedsFlushBeforeDeleteFB = true;
-    }
-
-    mMaxTextureImageSize = mMaxTextureSize;
-
-    if (IsSupported(GLFeature::framebuffer_multisample)) {
-        fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples);
-    }
-
-    ////////////////////////////////////////////////////////////////////////////
-
-    // We're ready for final setup.
-    fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
-
-    // TODO: Remove SurfaceCaps::any.
-    if (mCaps.any) {
-        mCaps.any = false;
-        mCaps.color = true;
-        mCaps.alpha = false;
-    }
-
-    UpdateGLFormats(mCaps);
-
-    mTexGarbageBin = new TextureGarbageBin(this);
-
-    MOZ_ASSERT(IsCurrent());
-
-    if (DebugMode() && IsExtensionSupported(KHR_debug)) {
-        fEnable(LOCAL_GL_DEBUG_OUTPUT);
-        fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS);
-        fDebugMessageCallback(&StaticDebugCallback, (void*)this);
-        fDebugMessageControl(LOCAL_GL_DONT_CARE,
-                             LOCAL_GL_DONT_CARE,
-                             LOCAL_GL_DONT_CARE,
-                             0, nullptr,
-                             true);
-    }
-
-    mVersionString = nsPrintfCString("%u.%u.%u", mVersion / 100, (mVersion / 10) % 10,
-                                     mVersion % 10);
-    return true;
-}
-
-void
-GLContext::LoadMoreSymbols(const char* prefix, bool trygl)
-{
-    const auto fnLoadForExt = [this, prefix, trygl](const SymLoadStruct* list,
-                                                    GLExtensions ext)
-    {
-        return this->LoadExtSymbols(prefix, trygl, list, ext);
-    };
-
-    const auto fnLoadForFeature = [this, prefix, trygl](const SymLoadStruct* list,
-                                                        GLFeature feature)
-    {
-        return this->LoadFeatureSymbols(prefix, trygl, list, feature);
-    };
-
-    const auto fnLoadFeatureByCore = [this, fnLoadForFeature](const SymLoadStruct* coreList,
-                                                              const SymLoadStruct* extList,
-                                                              GLFeature feature)
-    {
-        const bool useCore = this->IsFeatureProvidedByCoreSymbols(feature);
-        const auto list = useCore ? coreList : extList;
-        return fnLoadForFeature(list, feature);
-    };
-
-    bool hasRobustness = false;
-    if (SupportsRobustness()) {
-        if (IsExtensionSupported(ARB_robustness)) {
-            const SymLoadStruct symbols[] = {
-                { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusARB", nullptr } },
-                END_SYMBOLS
-            };
-            if (fnLoadForExt(symbols, ARB_robustness)) {
-                hasRobustness = true;
+    const char *glVendorString = nullptr;
+    const char *glRendererString = nullptr;
+
+    if (mInitialized) {
+        // The order of these strings must match up with the order of the enum
+        // defined in GLContext.h for vendor IDs
+        glVendorString = (const char *)fGetString(LOCAL_GL_VENDOR);
+        if (!glVendorString)
+            mInitialized = false;
+
+        const char *vendorMatchStrings[size_t(GLVendor::Other)] = {
+                "Intel",
+                "NVIDIA",
+                "ATI",
+                "Qualcomm",
+                "Imagination",
+                "nouveau",
+                "Vivante",
+                "VMware, Inc.",
+                "ARM"
+        };
+
+        mVendor = GLVendor::Other;
+        for (size_t i = 0; i < size_t(GLVendor::Other); ++i) {
+            if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) {
+                mVendor = GLVendor(i);
+                break;
             }
         }
 
-        if (!hasRobustness && IsExtensionSupported(EXT_robustness)) {
-            const SymLoadStruct symbols[] = {
-                { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusEXT", nullptr } },
-                END_SYMBOLS
-            };
-            if (fnLoadForExt(symbols, EXT_robustness)) {
-                hasRobustness = true;
+        // The order of these strings must match up with the order of the enum
+        // defined in GLContext.h for renderer IDs
+        glRendererString = (const char *)fGetString(LOCAL_GL_RENDERER);
+        if (!glRendererString)
+            mInitialized = false;
+
+        const char *rendererMatchStrings[size_t(GLRenderer::Other)] = {
+                "Adreno 200",
+                "Adreno 205",
+                "Adreno (TM) 200",
+                "Adreno (TM) 205",
+                "Adreno (TM) 320",
+                "Adreno (TM) 420",
+                "PowerVR SGX 530",
+                "PowerVR SGX 540",
+                "NVIDIA Tegra",
+                "Android Emulator",
+                "Gallium 0.4 on llvmpipe",
+                "Intel HD Graphics 3000 OpenGL Engine",
+                "Microsoft Basic Render Driver"
+        };
+
+        mRenderer = GLRenderer::Other;
+        for (size_t i = 0; i < size_t(GLRenderer::Other); ++i) {
+            if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) {
+                mRenderer = GLRenderer(i);
+                break;
             }
         }
     }
-    if (!hasRobustness) {
-        MarkUnsupported(GLFeature::robustness);
-    }
-
-    if (IsSupported(GLFeature::sync)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fFenceSync,      { "FenceSync",      nullptr } },
-            { (PRFuncPtr*) &mSymbols.fIsSync,         { "IsSync",         nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDeleteSync,     { "DeleteSync",     nullptr } },
-            { (PRFuncPtr*) &mSymbols.fClientWaitSync, { "ClientWaitSync", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fWaitSync,       { "WaitSync",       nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetInteger64v,  { "GetInteger64v",  nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetSynciv,      { "GetSynciv",      nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::sync);
-    }
-
-    if (IsExtensionSupported(OES_EGL_image)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fEGLImageTargetTexture2D, { "EGLImageTargetTexture2DOES", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fEGLImageTargetRenderbufferStorage, { "EGLImageTargetRenderbufferStorageOES", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForExt(symbols, OES_EGL_image);
-    }
-
-    if (IsExtensionSupported(APPLE_texture_range)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fTextureRangeAPPLE, { "TextureRangeAPPLE", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForExt(symbols, APPLE_texture_range);
-    }
-
-    if (IsSupported(GLFeature::vertex_array_object)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fIsVertexArray, { "IsVertexArray", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGenVertexArrays, { "GenVertexArrays", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArray", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArrays", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fIsVertexArray, { "IsVertexArrayARB", "IsVertexArrayOES", "IsVertexArrayAPPLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGenVertexArrays, { "GenVertexArraysARB", "GenVertexArraysOES", "GenVertexArraysAPPLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArrayARB", "BindVertexArrayOES", "BindVertexArrayAPPLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArraysARB", "DeleteVertexArraysOES", "DeleteVertexArraysAPPLE", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::vertex_array_object);
-    }
-
-    if (IsSupported(GLFeature::draw_instanced)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fDrawArraysInstanced, { "DrawArraysInstanced", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDrawElementsInstanced, { "DrawElementsInstanced", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fDrawArraysInstanced, { "DrawArraysInstancedARB", "DrawArraysInstancedEXT", "DrawArraysInstancedNV", "DrawArraysInstancedANGLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDrawElementsInstanced, { "DrawElementsInstancedARB", "DrawElementsInstancedEXT", "DrawElementsInstancedNV", "DrawElementsInstancedANGLE", nullptr }
-            },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::draw_instanced);
-    }
-
-    if (IsSupported(GLFeature::instanced_arrays)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fVertexAttribDivisor, { "VertexAttribDivisor", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fVertexAttribDivisor, { "VertexAttribDivisorARB", "VertexAttribDivisorNV", "VertexAttribDivisorANGLE", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::instanced_arrays);
-    }
-
-    if (IsSupported(GLFeature::texture_storage)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fTexStorage2D, { "TexStorage2D", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fTexStorage3D, { "TexStorage3D", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fTexStorage2D, { "TexStorage2DEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fTexStorage3D, { "TexStorage3DEXT", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_storage);
-    }
-
-    if (IsSupported(GLFeature::sampler_objects)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGenSamplers, { "GenSamplers", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDeleteSamplers, { "DeleteSamplers", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fIsSampler, { "IsSampler", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fBindSampler, { "BindSampler", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fSamplerParameteri, { "SamplerParameteri", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fSamplerParameteriv, { "SamplerParameteriv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fSamplerParameterf, { "SamplerParameterf", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fSamplerParameterfv, { "SamplerParameterfv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetSamplerParameteriv, { "GetSamplerParameteriv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetSamplerParameterfv, { "GetSamplerParameterfv", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::sampler_objects);
-    }
-
-    // ARB_transform_feedback2/NV_transform_feedback2 is a
-    // superset of EXT_transform_feedback/NV_transform_feedback
-    // and adds glPauseTransformFeedback &
-    // glResumeTransformFeedback, which are required for WebGL2.
-    if (IsSupported(GLFeature::transform_feedback2)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fBindBufferBase, { "BindBufferBase", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fBindBufferRange, { "BindBufferRange", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, { "GenTransformFeedbacks", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, { "BindTransformFeedback", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, { "DeleteTransformFeedbacks", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, { "IsTransformFeedback", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, { "BeginTransformFeedback", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, { "EndTransformFeedback", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, { "TransformFeedbackVaryings", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, { "GetTransformFeedbackVarying", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, { "PauseTransformFeedback", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, { "ResumeTransformFeedback", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fBindBufferBase, { "BindBufferBaseEXT", "BindBufferBaseNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fBindBufferRange, { "BindBufferRangeEXT", "BindBufferRangeNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, { "GenTransformFeedbacksNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, { "BindTransformFeedbackNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, { "DeleteTransformFeedbacksNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, { "IsTransformFeedbackNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, { "BeginTransformFeedbackEXT", "BeginTransformFeedbackNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, { "EndTransformFeedbackEXT", "EndTransformFeedbackNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, { "TransformFeedbackVaryingsEXT", "TransformFeedbackVaryingsNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, { "GetTransformFeedbackVaryingEXT", "GetTransformFeedbackVaryingNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, { "PauseTransformFeedbackNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, { "ResumeTransformFeedbackNV", nullptr } },
-            END_SYMBOLS
-        };
-        if (!fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_storage)) {
-            // Also mark bind_buffer_offset as unsupported.
-            MarkUnsupported(GLFeature::bind_buffer_offset);
+
+
+#ifdef MOZ_GL_DEBUG
+    if (gfxEnv::GlDebug())
+        sDebugMode |= DebugEnabled;
+
+    // enables extra verbose output, informing of the start and finish of every GL call.
+    // useful e.g. to record information to investigate graphics system crashes/lockups
+    if (gfxEnv::GlDebugVerbose())
+        sDebugMode |= DebugTrace;
+
+    // aborts on GL error. Can be useful to debug quicker code that is known not to generate any GL error in principle.
+    if (gfxEnv::GlDebugAbortOnError())
+        sDebugMode |= DebugAbortOnError;
+#endif
+
+    if (mInitialized) {
+        if (ShouldSpew()) {
+            const char* vendors[size_t(GLVendor::Other)] = {
+                "Intel",
+                "NVIDIA",
+                "ATI",
+                "Qualcomm"
+            };
+
+            MOZ_ASSERT(glVendorString);
+            if (mVendor < GLVendor::Other) {
+                printf_stderr("OpenGL vendor ('%s') recognized as: %s\n",
+                              glVendorString, vendors[size_t(mVendor)]);
+            } else {
+                printf_stderr("OpenGL vendor ('%s') unrecognized\n", glVendorString);
+            }
+        }
+
+        if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) {
+            SymLoadStruct moreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetStringi,    { "GetStringi", nullptr } },
+                END_SYMBOLS
+            };
+
+            MOZ_ALWAYS_TRUE(LoadSymbols(moreSymbols, trygl, prefix));
+        }
+
+        InitExtensions();
+        InitFeatures();
+
+        // Disable extensions with partial or incorrect support.
+        if (WorkAroundDriverBugs()) {
+            if (Renderer() == GLRenderer::AdrenoTM320) {
+                MarkUnsupported(GLFeature::standard_derivatives);
+            }
+
+            if (Vendor() == GLVendor::Vivante) {
+                // bug 958256
+                MarkUnsupported(GLFeature::standard_derivatives);
+            }
+
+            if (Renderer() == GLRenderer::MicrosoftBasicRenderDriver) {
+                // Bug 978966: on Microsoft's "Basic Render Driver" (software renderer)
+                // multisampling hardcodes blending with the default blendfunc, which breaks WebGL.
+                MarkUnsupported(GLFeature::framebuffer_multisample);
+            }
+
+#ifdef XP_MACOSX
+            // The Mac Nvidia driver, for versions up to and including 10.8,
+            // don't seem to properly support this.  See 814839
+            // this has been fixed in Mac OS X 10.9. See 907946
+            // and it also works in 10.8.3 and higher.  See 1094338.
+            if (Vendor() == gl::GLVendor::NVIDIA &&
+                !nsCocoaFeatures::IsAtLeastVersion(10,8,3))
+            {
+                MarkUnsupported(GLFeature::depth_texture);
+            }
+#endif
         }
-    }
-
-    if (IsSupported(GLFeature::bind_buffer_offset)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fBindBufferOffset, { "BindBufferOffset", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fBindBufferOffset,
-              { "BindBufferOffsetEXT", "BindBufferOffsetNV", nullptr }
-            },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::bind_buffer_offset);
-    }
-
-    if (IsSupported(GLFeature::query_counter)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fQueryCounter, { "QueryCounter", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fQueryCounter, { "QueryCounterEXT", "QueryCounterANGLE", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::query_counter);
-    }
-
-    if (IsSupported(GLFeature::query_objects)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQuery", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueries", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueries", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQuery", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryiv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuiv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fIsQuery, { "IsQuery", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQueryEXT", "BeginQueryANGLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueriesEXT", "GenQueriesANGLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueriesEXT", "DeleteQueriesANGLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQueryEXT", "EndQueryANGLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryivEXT", "GetQueryivANGLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuivEXT", "GetQueryObjectuivANGLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fIsQuery, { "IsQueryEXT", "IsQueryANGLE", nullptr } },
-            END_SYMBOLS
-        };
-        if (!fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::query_objects)) {
-            MarkUnsupported(GLFeature::get_query_object_i64v);
-            MarkUnsupported(GLFeature::get_query_object_iv);
-            MarkUnsupported(GLFeature::occlusion_query);
-            MarkUnsupported(GLFeature::occlusion_query_boolean);
-            MarkUnsupported(GLFeature::occlusion_query2);
+
+        NS_ASSERTION(!IsExtensionSupported(GLContext::ARB_pixel_buffer_object) ||
+                     (mSymbols.fMapBuffer && mSymbols.fUnmapBuffer),
+                     "ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer being available!");
+
+        if (SupportsRobustness()) {
+            mHasRobustness = false;
+
+            if (IsExtensionSupported(ARB_robustness)) {
+                SymLoadStruct robustnessSymbols[] = {
+                    { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusARB", nullptr } },
+                    END_SYMBOLS
+                };
+
+                if (!LoadSymbols(&robustnessSymbols[0], trygl, prefix)) {
+                    NS_ERROR("GL supports ARB_robustness without supplying GetGraphicsResetStatusARB.");
+
+                    mSymbols.fGetGraphicsResetStatus = nullptr;
+                } else {
+                    mHasRobustness = true;
+                }
+            }
+            if (!IsExtensionSupported(ARB_robustness) &&
+                IsExtensionSupported(EXT_robustness)) {
+                SymLoadStruct robustnessSymbols[] = {
+                    { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusEXT", nullptr } },
+                    END_SYMBOLS
+                };
+
+                if (!LoadSymbols(&robustnessSymbols[0], trygl, prefix)) {
+                    NS_ERROR("GL supports EXT_robustness without supplying GetGraphicsResetStatusEXT.");
+
+                    mSymbols.fGetGraphicsResetStatus = nullptr;
+                } else {
+                    mHasRobustness = true;
+                }
+            }
+
+            if (!mHasRobustness) {
+                MarkUnsupported(GLFeature::robustness);
+            }
         }
-    }
-
-    if (IsSupported(GLFeature::get_query_object_i64v)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, { "GetQueryObjecti64v", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, { "GetQueryObjectui64v", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, { "GetQueryObjecti64vEXT", "GetQueryObjecti64vANGLE", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, { "GetQueryObjectui64vEXT", "GetQueryObjectui64vANGLE", nullptr } },
-            END_SYMBOLS
-        };
-        if (!fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::get_query_object_i64v)) {
-            MarkUnsupported(GLFeature::query_counter);
+
+        // Check for ARB_framebuffer_objects
+        if (IsSupported(GLFeature::framebuffer_object)) {
+            // https://www.opengl.org/registry/specs/ARB/framebuffer_object.txt
+            SymLoadStruct coreSymbols[] = {
+                CORE_SYMBOL(IsRenderbuffer),
+                CORE_SYMBOL(BindRenderbuffer),
+                CORE_SYMBOL(DeleteRenderbuffers),
+                CORE_SYMBOL(GenRenderbuffers),
+                CORE_SYMBOL(RenderbufferStorage),
+                CORE_SYMBOL(RenderbufferStorageMultisample),
+                CORE_SYMBOL(GetRenderbufferParameteriv),
+                CORE_SYMBOL(IsFramebuffer),
+                CORE_SYMBOL(BindFramebuffer),
+                CORE_SYMBOL(DeleteFramebuffers),
+                CORE_SYMBOL(GenFramebuffers),
+                CORE_SYMBOL(CheckFramebufferStatus),
+                CORE_SYMBOL(FramebufferTexture2D),
+                CORE_SYMBOL(FramebufferTextureLayer),
+                CORE_SYMBOL(FramebufferRenderbuffer),
+                CORE_SYMBOL(GetFramebufferAttachmentParameteriv),
+                CORE_SYMBOL(BlitFramebuffer),
+                CORE_SYMBOL(GenerateMipmap),
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(coreSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports framebuffer_object without supplying its functions.");
+                MarkUnsupported(GLFeature::framebuffer_object);
+            }
+        }
+
+        if (!IsSupported(GLFeature::framebuffer_object)) {
+            // Check for aux symbols based on extensions
+            if (IsSupported(GLFeature::framebuffer_object_EXT_OES))
+            {
+                SymLoadStruct extSymbols[] = {
+                    CORE_EXT_SYMBOL2(IsRenderbuffer, EXT, OES),
+                    CORE_EXT_SYMBOL2(BindRenderbuffer, EXT, OES),
+                    CORE_EXT_SYMBOL2(DeleteRenderbuffers, EXT, OES),
+                    CORE_EXT_SYMBOL2(GenRenderbuffers, EXT, OES),
+                    CORE_EXT_SYMBOL2(RenderbufferStorage, EXT, OES),
+                    CORE_EXT_SYMBOL2(GetRenderbufferParameteriv, EXT, OES),
+                    CORE_EXT_SYMBOL2(IsFramebuffer, EXT, OES),
+                    CORE_EXT_SYMBOL2(BindFramebuffer, EXT, OES),
+                    CORE_EXT_SYMBOL2(DeleteFramebuffers, EXT, OES),
+                    CORE_EXT_SYMBOL2(GenFramebuffers, EXT, OES),
+                    CORE_EXT_SYMBOL2(CheckFramebufferStatus, EXT, OES),
+                    CORE_EXT_SYMBOL2(FramebufferTexture2D, EXT, OES),
+                    CORE_EXT_SYMBOL2(FramebufferRenderbuffer, EXT, OES),
+                    CORE_EXT_SYMBOL2(GetFramebufferAttachmentParameteriv, EXT, OES),
+                    CORE_EXT_SYMBOL2(GenerateMipmap, EXT, OES),
+                    END_SYMBOLS
+                };
+
+                if (!LoadSymbols(extSymbols, trygl, prefix)) {
+                    NS_ERROR("GL supports framebuffer_object without supplying its functions.");
+                }
+            }
+
+            if (IsSupported(GLFeature::framebuffer_blit)) {
+                SymLoadStruct extSymbols[] = {
+                    EXT_SYMBOL3(BlitFramebuffer, ANGLE, EXT, NV),
+                    END_SYMBOLS
+                };
+
+                if (!LoadSymbols(extSymbols, trygl, prefix)) {
+                    NS_ERROR("GL supports framebuffer_blit without supplying its functions.");
+                }
+            }
+
+            if (IsSupported(GLFeature::framebuffer_multisample)) {
+                SymLoadStruct extSymbols[] = {
+                    EXT_SYMBOL3(RenderbufferStorageMultisample, ANGLE, APPLE, EXT),
+                    END_SYMBOLS
+                };
+
+                if (!LoadSymbols(extSymbols, trygl, prefix)) {
+                    NS_ERROR("GL supports framebuffer_multisample without supplying its functions.");
+                }
+            }
+
+            if (IsExtensionSupported(GLContext::ARB_geometry_shader4) ||
+                IsExtensionSupported(GLContext::NV_geometry_program4))
+            {
+                SymLoadStruct extSymbols[] = {
+                    EXT_SYMBOL2(FramebufferTextureLayer, ARB, EXT),
+                    END_SYMBOLS
+                };
+
+                if (!LoadSymbols(extSymbols, trygl, prefix)) {
+                    NS_ERROR("GL supports geometry_shader4 withot supplying its functions.");
+                }
+            }
+        }
+
+        if (!IsSupported(GLFeature::framebuffer_object) &&
+            !IsSupported(GLFeature::framebuffer_object_EXT_OES))
+        {
+            NS_ERROR("GLContext requires framebuffer object support.");
+            mInitialized = false;
         }
     }
 
-    if (IsSupported(GLFeature::get_query_object_iv)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectiv", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectivEXT", "GetQueryObjectivANGLE", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::get_query_object_iv);
-    }
-
-    if (IsSupported(GLFeature::clear_buffers)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fClearBufferfi,  { "ClearBufferfi",  nullptr } },
-            { (PRFuncPtr*) &mSymbols.fClearBufferfv,  { "ClearBufferfv",  nullptr } },
-            { (PRFuncPtr*) &mSymbols.fClearBufferiv,  { "ClearBufferiv",  nullptr } },
-            { (PRFuncPtr*) &mSymbols.fClearBufferuiv, { "ClearBufferuiv", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::clear_buffers);
-    }
-
-    if (IsSupported(GLFeature::copy_buffer)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fCopyBufferSubData, { "CopyBufferSubData", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::copy_buffer);
-    }
-
-    if (IsSupported(GLFeature::draw_buffers)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffersARB", "DrawBuffersEXT", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::draw_buffers);
-    }
-
-    if (IsSupported(GLFeature::draw_range_elements)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fDrawRangeElements, { "DrawRangeElements", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fDrawRangeElements, { "DrawRangeElementsEXT", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::draw_range_elements);
-    }
-
-    if (IsSupported(GLFeature::get_integer_indexed)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetIntegeri_v, { "GetIntegeri_v", nullptr } },
-            END_SYMBOLS
+    if (mInitialized) {
+        if (IsSupported(GLFeature::sync)) {
+            SymLoadStruct syncSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fFenceSync,      { "FenceSync",      nullptr } },
+                { (PRFuncPtr*) &mSymbols.fIsSync,         { "IsSync",         nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDeleteSync,     { "DeleteSync",     nullptr } },
+                { (PRFuncPtr*) &mSymbols.fClientWaitSync, { "ClientWaitSync", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fWaitSync,       { "WaitSync",       nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetInteger64v,  { "GetInteger64v",  nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetSynciv,      { "GetSynciv",      nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&syncSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports sync without supplying its functions.");
+
+                MarkExtensionUnsupported(ARB_sync);
+                ClearSymbols(syncSymbols);
+            }
+        }
+
+        if (IsExtensionSupported(OES_EGL_image)) {
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fEGLImageTargetTexture2D, { "EGLImageTargetTexture2DOES", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fEGLImageTargetRenderbufferStorage, { "EGLImageTargetRenderbufferStorageOES", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports OES_EGL_image without supplying its functions.");
+
+                MarkExtensionUnsupported(OES_EGL_image);
+                ClearSymbols(extSymbols);
+            }
+        }
+
+        if (IsExtensionSupported(APPLE_texture_range)) {
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fTextureRangeAPPLE, { "TextureRangeAPPLE", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports APPLE_texture_range without supplying its functions.");
+
+                ClearSymbols(extSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::vertex_array_object)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fIsVertexArray, { "IsVertexArray", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGenVertexArrays, { "GenVertexArrays", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArray", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArrays", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fIsVertexArray, { "IsVertexArrayARB", "IsVertexArrayOES", "IsVertexArrayAPPLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGenVertexArrays, { "GenVertexArraysARB", "GenVertexArraysOES", "GenVertexArraysAPPLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArrayARB", "BindVertexArrayOES", "BindVertexArrayAPPLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArraysARB", "DeleteVertexArraysOES", "DeleteVertexArraysAPPLE", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::vertex_array_object);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports Vertex Array Object without supplying its functions.");
+
+                MarkUnsupported(GLFeature::vertex_array_object);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::draw_instanced)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fDrawArraysInstanced, { "DrawArraysInstanced", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDrawElementsInstanced, { "DrawElementsInstanced", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fDrawArraysInstanced, { "DrawArraysInstancedARB", "DrawArraysInstancedEXT", "DrawArraysInstancedNV", "DrawArraysInstancedANGLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDrawElementsInstanced, { "DrawElementsInstancedARB", "DrawElementsInstancedEXT", "DrawElementsInstancedNV", "DrawElementsInstancedANGLE", nullptr }
+                },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::draw_instanced);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports instanced draws without supplying its functions.");
+
+                MarkUnsupported(GLFeature::draw_instanced);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::instanced_arrays)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fVertexAttribDivisor, { "VertexAttribDivisor", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fVertexAttribDivisor, { "VertexAttribDivisorARB", "VertexAttribDivisorNV", "VertexAttribDivisorANGLE", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::instanced_arrays);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports array instanced without supplying it function.");
+
+                MarkUnsupported(GLFeature::instanced_arrays);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::texture_storage)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fTexStorage2D, { "TexStorage2D", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fTexStorage3D, { "TexStorage3D", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fTexStorage2D, { "TexStorage2DEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fTexStorage3D, { "TexStorage3DEXT", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::texture_storage);
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports texture storage without supplying its functions.");
+
+                MarkUnsupported(GLFeature::texture_storage);
+                MarkExtensionSupported(useCore ? ARB_texture_storage : EXT_texture_storage);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::sampler_objects)) {
+            SymLoadStruct samplerObjectsSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGenSamplers, { "GenSamplers", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDeleteSamplers, { "DeleteSamplers", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fIsSampler, { "IsSampler", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fBindSampler, { "BindSampler", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fSamplerParameteri, { "SamplerParameteri", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fSamplerParameteriv, { "SamplerParameteriv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fSamplerParameterf, { "SamplerParameterf", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fSamplerParameterfv, { "SamplerParameterfv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetSamplerParameteriv, { "GetSamplerParameteriv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetSamplerParameterfv, { "GetSamplerParameterfv", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(samplerObjectsSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports sampler objects without supplying its functions.");
+
+                MarkUnsupported(GLFeature::sampler_objects);
+                ClearSymbols(samplerObjectsSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::texture_storage)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fTexStorage2D, { "TexStorage2D", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fTexStorage3D, { "TexStorage3D", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(coreSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports texture storage without supplying its functions.");
+
+                MarkUnsupported(GLFeature::texture_storage);
+                MarkExtensionUnsupported(ARB_texture_storage);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        // ARB_transform_feedback2/NV_transform_feedback2 is a
+        // superset of EXT_transform_feedback/NV_transform_feedback
+        // and adds glPauseTransformFeedback &
+        // glResumeTransformFeedback, which are required for WebGL2.
+        if (IsSupported(GLFeature::transform_feedback2)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fBindBufferBase, { "BindBufferBase", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fBindBufferRange, { "BindBufferRange", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, { "GenTransformFeedbacks", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, { "BindTransformFeedback", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, { "DeleteTransformFeedbacks", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, { "IsTransformFeedback", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, { "BeginTransformFeedback", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, { "EndTransformFeedback", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, { "TransformFeedbackVaryings", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, { "GetTransformFeedbackVarying", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, { "PauseTransformFeedback", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, { "ResumeTransformFeedback", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fBindBufferBase, { "BindBufferBaseEXT", "BindBufferBaseNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fBindBufferRange, { "BindBufferRangeEXT", "BindBufferRangeNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, { "GenTransformFeedbacksNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, { "BindTransformFeedbackNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, { "DeleteTransformFeedbacksNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, { "IsTransformFeedbackNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, { "BeginTransformFeedbackEXT", "BeginTransformFeedbackNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, { "EndTransformFeedbackEXT", "EndTransformFeedbackNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, { "TransformFeedbackVaryingsEXT", "TransformFeedbackVaryingsNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, { "GetTransformFeedbackVaryingEXT", "GetTransformFeedbackVaryingNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, { "PauseTransformFeedbackNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, { "ResumeTransformFeedbackNV", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::transform_feedback2);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports transform feedback without supplying its functions.");
+
+                MarkUnsupported(GLFeature::transform_feedback2);
+                MarkUnsupported(GLFeature::bind_buffer_offset);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::bind_buffer_offset)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fBindBufferOffset, { "BindBufferOffset", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fBindBufferOffset,
+                  { "BindBufferOffsetEXT", "BindBufferOffsetNV", nullptr }
+                },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::bind_buffer_offset);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports BindBufferOffset without supplying its function.");
+
+                MarkUnsupported(GLFeature::bind_buffer_offset);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::query_counter)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fQueryCounter, { "QueryCounter", nullptr } },
+                END_SYMBOLS
+            };
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fQueryCounter, { "QueryCounterEXT", "QueryCounterANGLE", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::query_counter);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports query counters without supplying its functions.");
+
+                MarkUnsupported(GLFeature::query_counter);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::query_objects)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQuery", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueries", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueries", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQuery", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryiv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuiv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fIsQuery, { "IsQuery", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQueryEXT", "BeginQueryANGLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueriesEXT", "GenQueriesANGLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueriesEXT", "DeleteQueriesANGLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQueryEXT", "EndQueryANGLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryivEXT", "GetQueryivANGLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuivEXT", "GetQueryObjectuivANGLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fIsQuery, { "IsQueryEXT", "IsQueryANGLE", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::query_objects);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports query objects without supplying its functions.");
+
+                MarkUnsupported(GLFeature::query_objects);
+                MarkUnsupported(GLFeature::get_query_object_i64v);
+                MarkUnsupported(GLFeature::get_query_object_iv);
+                MarkUnsupported(GLFeature::occlusion_query);
+                MarkUnsupported(GLFeature::occlusion_query_boolean);
+                MarkUnsupported(GLFeature::occlusion_query2);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::get_query_object_i64v)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, { "GetQueryObjecti64v", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, { "GetQueryObjectui64v", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, { "GetQueryObjecti64vEXT", "GetQueryObjecti64vANGLE", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, { "GetQueryObjectui64vEXT", "GetQueryObjectui64vANGLE", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::get_query_object_i64v);
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports 64 bit query object getters without supplying its functions.");
+
+                MarkUnsupported(GLFeature::get_query_object_i64v);
+                MarkUnsupported(GLFeature::query_counter);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::get_query_object_iv)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectiv", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectivEXT", "GetQueryObjectivANGLE", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::get_query_object_iv);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports query objects iv getter without supplying its function.");
+
+                MarkUnsupported(GLFeature::get_query_object_iv);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::clear_buffers)) {
+            SymLoadStruct clearBuffersSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fClearBufferfi,  { "ClearBufferfi",  nullptr } },
+                { (PRFuncPtr*) &mSymbols.fClearBufferfv,  { "ClearBufferfv",  nullptr } },
+                { (PRFuncPtr*) &mSymbols.fClearBufferiv,  { "ClearBufferiv",  nullptr } },
+                { (PRFuncPtr*) &mSymbols.fClearBufferuiv, { "ClearBufferuiv", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(clearBuffersSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports clear_buffers without supplying its functions.");
+
+                MarkUnsupported(GLFeature::clear_buffers);
+                ClearSymbols(clearBuffersSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::copy_buffer)) {
+            SymLoadStruct copyBufferSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fCopyBufferSubData, { "CopyBufferSubData", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(copyBufferSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports copy_buffer without supplying its function.");
+
+                MarkUnsupported(GLFeature::copy_buffer);
+                ClearSymbols(copyBufferSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::draw_buffers)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffersARB", "DrawBuffersEXT", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::draw_buffers);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports draw_buffers without supplying its functions.");
+
+                MarkUnsupported(GLFeature::draw_buffers);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::draw_range_elements)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fDrawRangeElements, { "DrawRangeElements", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fDrawRangeElements, { "DrawRangeElementsEXT", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::draw_range_elements);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports draw_range_elements without supplying its functions.");
+
+                MarkUnsupported(GLFeature::draw_range_elements);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::get_integer_indexed)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetIntegeri_v, { "GetIntegeri_v", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] ={
+                { (PRFuncPtr*) &mSymbols.fGetIntegeri_v, { "GetIntegerIndexedvEXT", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::get_integer_indexed);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports get_integer_indexed without supplying its functions.");
+
+                MarkUnsupported(GLFeature::get_integer_indexed);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::get_integer64_indexed)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetInteger64i_v, { "GetInteger64i_v", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(coreSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports get_integer64_indexed without supplying its functions.");
+
+                MarkUnsupported(GLFeature::get_integer64_indexed);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::gpu_shader4)) {
+            SymLoadStruct gpuShader4Symbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetVertexAttribIiv, { "GetVertexAttribIiv", "GetVertexAttribIivEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetVertexAttribIuiv, { "GetVertexAttribIuiv", "GetVertexAttribIuivEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fVertexAttribI4i, { "VertexAttribI4i", "VertexAttribI4iEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fVertexAttribI4iv, { "VertexAttribI4iv","VertexAttribI4ivEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fVertexAttribI4ui, { "VertexAttribI4ui", "VertexAttribI4uiEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fVertexAttribI4uiv, { "VertexAttribI4uiv", "VertexAttribI4uivEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fVertexAttribIPointer, { "VertexAttribIPointer", "VertexAttribIPointerEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniform1ui,  { "Uniform1ui", "Uniform1uiEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniform2ui,  { "Uniform2ui", "Uniform2uiEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniform3ui,  { "Uniform3ui", "Uniform3uiEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniform4ui,  { "Uniform4ui", "Uniform4uiEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniform1uiv, { "Uniform1uiv", "Uniform1uivEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniform2uiv, { "Uniform2uiv", "Uniform2uivEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniform3uiv, { "Uniform3uiv", "Uniform3uivEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniform4uiv, { "Uniform4uiv", "Uniform4uivEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetFragDataLocation, { "GetFragDataLocation", "GetFragDataLocationEXT", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetUniformuiv, { "GetUniformuiv", "GetUniformuivEXT", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(gpuShader4Symbols, trygl, prefix)) {
+                NS_ERROR("GL supports gpu_shader4 without supplying its functions.");
+
+                MarkUnsupported(GLFeature::gpu_shader4);
+                ClearSymbols(gpuShader4Symbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::map_buffer_range)) {
+            SymLoadStruct mapBufferRangeSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fMapBufferRange, { "MapBufferRange", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fFlushMappedBufferRange, { "FlushMappedBufferRange", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(mapBufferRangeSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports map_buffer_range without supplying its functions.");
+
+                MarkUnsupported(GLFeature::map_buffer_range);
+                ClearSymbols(mapBufferRangeSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::texture_3D)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fTexImage3D, { "TexImage3D", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3D", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3DEXT", "TexSubImage3DOES", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::texture_3D);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports 3D textures without supplying functions.");
+
+                MarkUnsupported(GLFeature::texture_3D);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::texture_3D_compressed)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fCompressedTexImage3D, { "CompressedTexImage3D", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage3D, { "CompressedTexSubImage3D", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fCompressedTexImage3D, { "CompressedTexImage3DARB", "CompressedTexImage3DOES", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage3D, { "CompressedTexSubImage3DARB", "CompressedTexSubImage3DOES", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::texture_3D_compressed);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports 3D textures without supplying functions.");
+
+                MarkUnsupported(GLFeature::texture_3D_compressed);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::texture_3D_copy)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fCopyTexSubImage3D, { "CopyTexSubImage3D", nullptr } },
+                END_SYMBOLS
+            };
+
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fCopyTexSubImage3D, { "CopyTexSubImage3DEXT", "CopyTexSubImage3DOES", nullptr } },
+                END_SYMBOLS
+            };
+
+            bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::texture_3D_copy);
+
+            if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports 3D textures without supplying functions.");
+
+                MarkUnsupported(GLFeature::texture_3D_copy);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::uniform_buffer_object)) {
+            // Note: Don't query for glGetActiveUniformName because it is not
+            // supported by GL ES 3.
+            SymLoadStruct uboSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetUniformIndices, { "GetUniformIndices", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetActiveUniformsiv, { "GetActiveUniformsiv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetUniformBlockIndex, { "GetUniformBlockIndex", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockiv, { "GetActiveUniformBlockiv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockName, { "GetActiveUniformBlockName", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniformBlockBinding, { "UniformBlockBinding", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&uboSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports ARB_uniform_buffer_object without supplying its functions.");
+
+                MarkExtensionUnsupported(ARB_uniform_buffer_object);
+                MarkUnsupported(GLFeature::uniform_buffer_object);
+                ClearSymbols(uboSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::uniform_matrix_nonsquare)) {
+            SymLoadStruct umnSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fUniformMatrix2x3fv, { "UniformMatrix2x3fv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniformMatrix2x4fv, { "UniformMatrix2x4fv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniformMatrix3x2fv, { "UniformMatrix3x2fv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniformMatrix3x4fv, { "UniformMatrix3x4fv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniformMatrix4x2fv, { "UniformMatrix4x2fv", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fUniformMatrix4x3fv, { "UniformMatrix4x3fv", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&umnSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports uniform matrix with non-square dim without supplying its functions.");
+
+                MarkUnsupported(GLFeature::uniform_matrix_nonsquare);
+                ClearSymbols(umnSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::internalformat_query)) {
+            SymLoadStruct coreSymbols[] = {
+                CORE_SYMBOL(GetInternalformativ),
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&coreSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports internalformat query without supplying its functions.");
+
+                MarkUnsupported(GLFeature::internalformat_query);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::invalidate_framebuffer)) {
+            SymLoadStruct invSymbols[] = {
+                { (PRFuncPtr *) &mSymbols.fInvalidateFramebuffer,    { "InvalidateFramebuffer", nullptr } },
+                { (PRFuncPtr *) &mSymbols.fInvalidateSubFramebuffer, { "InvalidateSubFramebuffer", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&invSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports framebuffer invalidation without supplying its functions.");
+
+                MarkUnsupported(GLFeature::invalidate_framebuffer);
+                ClearSymbols(invSymbols);
+            }
+        }
+
+        if (IsExtensionSupported(KHR_debug)) {
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fDebugMessageControl,  { "DebugMessageControl",  "DebugMessageControlKHR",  nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDebugMessageInsert,   { "DebugMessageInsert",   "DebugMessageInsertKHR",   nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDebugMessageCallback, { "DebugMessageCallback", "DebugMessageCallbackKHR", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetDebugMessageLog,   { "GetDebugMessageLog",   "GetDebugMessageLogKHR",   nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetPointerv,          { "GetPointerv",          "GetPointervKHR",          nullptr } },
+                { (PRFuncPtr*) &mSymbols.fPushDebugGroup,       { "PushDebugGroup",       "PushDebugGroupKHR",       nullptr } },
+                { (PRFuncPtr*) &mSymbols.fPopDebugGroup,        { "PopDebugGroup",        "PopDebugGroupKHR",        nullptr } },
+                { (PRFuncPtr*) &mSymbols.fObjectLabel,          { "ObjectLabel",          "ObjectLabelKHR",          nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetObjectLabel,       { "GetObjectLabel",       "GetObjectLabelKHR",       nullptr } },
+                { (PRFuncPtr*) &mSymbols.fObjectPtrLabel,       { "ObjectPtrLabel",       "ObjectPtrLabelKHR",       nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetObjectPtrLabel,    { "GetObjectPtrLabel",    "GetObjectPtrLabelKHR",    nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports KHR_debug without supplying its functions.");
+
+                MarkExtensionUnsupported(KHR_debug);
+                ClearSymbols(extSymbols);
+            }
+        }
+
+        if (IsExtensionSupported(NV_fence)) {
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGenFences,    { "GenFencesNV",    nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDeleteFences, { "DeleteFencesNV", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fSetFence,     { "SetFenceNV",     nullptr } },
+                { (PRFuncPtr*) &mSymbols.fTestFence,    { "TestFenceNV",    nullptr } },
+                { (PRFuncPtr*) &mSymbols.fFinishFence,  { "FinishFenceNV",  nullptr } },
+                { (PRFuncPtr*) &mSymbols.fIsFence,      { "IsFenceNV",      nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetFenceiv,   { "GetFenceivNV",   nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports NV_fence without supplying its functions.");
+
+                MarkExtensionUnsupported(NV_fence);
+                ClearSymbols(extSymbols);
+            }
+        }
+
+        if (IsSupported(GLFeature::read_buffer)) {
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports read_buffer without supplying its functions.");
+
+                MarkUnsupported(GLFeature::read_buffer);
+                ClearSymbols(extSymbols);
+            }
+        }
+
+        if (IsExtensionSupported(APPLE_framebuffer_multisample)) {
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fResolveMultisampleFramebufferAPPLE, { "ResolveMultisampleFramebufferAPPLE", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports APPLE_framebuffer_multisample without supplying its functions.");
+
+                MarkExtensionUnsupported(APPLE_framebuffer_multisample);
+                ClearSymbols(extSymbols);
+            }
+        }
+
+        // Load developer symbols, don't fail if we can't find them.
+        SymLoadStruct auxSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } },
+                END_SYMBOLS
         };
-        const SymLoadStruct extSymbols[] ={
-            { (PRFuncPtr*) &mSymbols.fGetIntegeri_v, { "GetIntegerIndexedvEXT", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::get_integer_indexed);
-    }
-
-    if (IsSupported(GLFeature::get_integer64_indexed)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetInteger64i_v, { "GetInteger64i_v", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::get_integer64_indexed);
-    }
-
-    if (IsSupported(GLFeature::gpu_shader4)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetVertexAttribIiv, { "GetVertexAttribIiv", "GetVertexAttribIivEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetVertexAttribIuiv, { "GetVertexAttribIuiv", "GetVertexAttribIuivEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fVertexAttribI4i, { "VertexAttribI4i", "VertexAttribI4iEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fVertexAttribI4iv, { "VertexAttribI4iv","VertexAttribI4ivEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fVertexAttribI4ui, { "VertexAttribI4ui", "VertexAttribI4uiEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fVertexAttribI4uiv, { "VertexAttribI4uiv", "VertexAttribI4uivEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fVertexAttribIPointer, { "VertexAttribIPointer", "VertexAttribIPointerEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniform1ui,  { "Uniform1ui", "Uniform1uiEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniform2ui,  { "Uniform2ui", "Uniform2uiEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniform3ui,  { "Uniform3ui", "Uniform3uiEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniform4ui,  { "Uniform4ui", "Uniform4uiEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniform1uiv, { "Uniform1uiv", "Uniform1uivEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniform2uiv, { "Uniform2uiv", "Uniform2uivEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniform3uiv, { "Uniform3uiv", "Uniform3uivEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniform4uiv, { "Uniform4uiv", "Uniform4uivEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetFragDataLocation, { "GetFragDataLocation", "GetFragDataLocationEXT", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetUniformuiv, { "GetUniformuiv", "GetUniformuivEXT", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::gpu_shader4);
-    }
-
-    if (IsSupported(GLFeature::map_buffer_range)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fMapBufferRange, { "MapBufferRange", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fFlushMappedBufferRange, { "FlushMappedBufferRange", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::map_buffer_range);
-    }
-
-    if (IsSupported(GLFeature::texture_3D)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fTexImage3D, { "TexImage3D", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3D", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3DEXT", "TexSubImage3DOES", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_3D);
+        bool warnOnFailures = DebugMode();
+        LoadSymbols(&auxSymbols[0], trygl, prefix, warnOnFailures);
     }
 
-    if (IsSupported(GLFeature::texture_3D_compressed)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fCompressedTexImage3D, { "CompressedTexImage3D", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage3D, { "CompressedTexSubImage3D", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fCompressedTexImage3D, { "CompressedTexImage3DARB", "CompressedTexImage3DOES", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage3D, { "CompressedTexSubImage3DARB", "CompressedTexSubImage3DOES", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_3D_compressed);
-    }
-
-    if (IsSupported(GLFeature::texture_3D_copy)) {
-        const SymLoadStruct coreSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fCopyTexSubImage3D, { "CopyTexSubImage3D", nullptr } },
-            END_SYMBOLS
-        };
-        const SymLoadStruct extSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fCopyTexSubImage3D, { "CopyTexSubImage3DEXT", "CopyTexSubImage3DOES", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadFeatureByCore(coreSymbols, extSymbols, GLFeature::texture_3D_copy);
-    }
-
-    if (IsSupported(GLFeature::uniform_buffer_object)) {
-        // Note: Don't query for glGetActiveUniformName because it is not
-        // supported by GL ES 3.
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetUniformIndices, { "GetUniformIndices", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetActiveUniformsiv, { "GetActiveUniformsiv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetUniformBlockIndex, { "GetUniformBlockIndex", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockiv, { "GetActiveUniformBlockiv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetActiveUniformBlockName, { "GetActiveUniformBlockName", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniformBlockBinding, { "UniformBlockBinding", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::uniform_buffer_object);
-    }
-
-    if (IsSupported(GLFeature::uniform_matrix_nonsquare)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fUniformMatrix2x3fv, { "UniformMatrix2x3fv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniformMatrix2x4fv, { "UniformMatrix2x4fv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniformMatrix3x2fv, { "UniformMatrix3x2fv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniformMatrix3x4fv, { "UniformMatrix3x4fv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniformMatrix4x2fv, { "UniformMatrix4x2fv", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fUniformMatrix4x3fv, { "UniformMatrix4x3fv", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::uniform_matrix_nonsquare);
-    }
-
-    if (IsSupported(GLFeature::internalformat_query)) {
-        const SymLoadStruct symbols[] = {
-            CORE_SYMBOL(GetInternalformativ),
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::internalformat_query);
+    if (mInitialized) {
+        raw_fGetIntegerv(LOCAL_GL_VIEWPORT, mViewportRect);
+        raw_fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mScissorRect);
+        raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+        raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize);
+        raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
+        raw_fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
+
+#ifdef XP_MACOSX
+        if (mWorkAroundDriverBugs) {
+            if (mVendor == GLVendor::Intel) {
+                // see bug 737182 for 2D textures, bug 684882 for cube map textures.
+                mMaxTextureSize        = std::min(mMaxTextureSize,        4096);
+                mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 512);
+                // for good measure, we align renderbuffers on what we do for 2D textures
+                mMaxRenderbufferSize   = std::min(mMaxRenderbufferSize,   4096);
+                mNeedsTextureSizeChecks = true;
+            } else if (mVendor == GLVendor::NVIDIA) {
+                if (nsCocoaFeatures::OnMountainLionOrLater()) {
+                    // See bug 879656.  8192 fails, 8191 works.
+                    mMaxTextureSize = std::min(mMaxTextureSize, 8191);
+                    mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 8191);
+                } else {
+                    // See bug 877949.
+                    mMaxTextureSize = std::min(mMaxTextureSize, 4096);
+                    mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);
+                }
+
+                // Part of the bug 879656, but it also doesn't hurt the 877949
+                mNeedsTextureSizeChecks = true;
+            }
+        }
+#endif
+#ifdef MOZ_X11
+        if (mWorkAroundDriverBugs) {
+            if (mVendor == GLVendor::Nouveau) {
+                // see bug 814716. Clamp MaxCubeMapTextureSize at 2K for Nouveau.
+                mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 2048);
+                mNeedsTextureSizeChecks = true;
+            } else if (mVendor == GLVendor::Intel) {
+                // Bug 1199923. Driver seems to report a larger max size than
+                // actually supported.
+                mMaxTextureSize /= 2;
+                mMaxRenderbufferSize /= 2;
+                mNeedsTextureSizeChecks = true;
+            }
+        }
+#endif
+        if (mWorkAroundDriverBugs &&
+            Renderer() == GLRenderer::AdrenoTM420) {
+            // see bug 1194923. Calling glFlush before glDeleteFramebuffers
+            // prevents occasional driver crash.
+            mNeedsFlushBeforeDeleteFB = true;
+        }
+
+        mMaxTextureImageSize = mMaxTextureSize;
+
+        if (IsSupported(GLFeature::framebuffer_multisample)) {
+            fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples);
+        }
+
+        // We're ready for final setup.
+        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+
+        // TODO: Remove SurfaceCaps::any.
+        if (mCaps.any) {
+            mCaps.any = false;
+            mCaps.color = true;
+            mCaps.alpha = false;
+        }
+
+        UpdateGLFormats(mCaps);
+
+        mTexGarbageBin = new TextureGarbageBin(this);
+
+        MOZ_ASSERT(IsCurrent());
+
+        if (DebugMode() && IsExtensionSupported(KHR_debug)) {
+            fEnable(LOCAL_GL_DEBUG_OUTPUT);
+            fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS);
+            fDebugMessageCallback(&StaticDebugCallback, (void*)this);
+            fDebugMessageControl(LOCAL_GL_DONT_CARE,
+                                 LOCAL_GL_DONT_CARE,
+                                 LOCAL_GL_DONT_CARE,
+                                 0, nullptr,
+                                 true);
+        }
+
+        reporter.SetSuccessful();
+    } else {
+        // if initialization fails, ensure all symbols are zero, to avoid hard-to-understand bugs
+        mSymbols.Zero();
+        NS_WARNING("InitWithPrefix failed!");
     }
 
-    if (IsSupported(GLFeature::invalidate_framebuffer)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr *) &mSymbols.fInvalidateFramebuffer,    { "InvalidateFramebuffer", nullptr } },
-            { (PRFuncPtr *) &mSymbols.fInvalidateSubFramebuffer, { "InvalidateSubFramebuffer", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::invalidate_framebuffer);
-    }
-
-    if (IsExtensionSupported(KHR_debug)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fDebugMessageControl,  { "DebugMessageControl",  "DebugMessageControlKHR",  nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDebugMessageInsert,   { "DebugMessageInsert",   "DebugMessageInsertKHR",   nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDebugMessageCallback, { "DebugMessageCallback", "DebugMessageCallbackKHR", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetDebugMessageLog,   { "GetDebugMessageLog",   "GetDebugMessageLogKHR",   nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetPointerv,          { "GetPointerv",          "GetPointervKHR",          nullptr } },
-            { (PRFuncPtr*) &mSymbols.fPushDebugGroup,       { "PushDebugGroup",       "PushDebugGroupKHR",       nullptr } },
-            { (PRFuncPtr*) &mSymbols.fPopDebugGroup,        { "PopDebugGroup",        "PopDebugGroupKHR",        nullptr } },
-            { (PRFuncPtr*) &mSymbols.fObjectLabel,          { "ObjectLabel",          "ObjectLabelKHR",          nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetObjectLabel,       { "GetObjectLabel",       "GetObjectLabelKHR",       nullptr } },
-            { (PRFuncPtr*) &mSymbols.fObjectPtrLabel,       { "ObjectPtrLabel",       "ObjectPtrLabelKHR",       nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetObjectPtrLabel,    { "GetObjectPtrLabel",    "GetObjectPtrLabelKHR",    nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForExt(symbols, KHR_debug);
-    }
-
-    if (IsExtensionSupported(NV_fence)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGenFences,    { "GenFencesNV",    nullptr } },
-            { (PRFuncPtr*) &mSymbols.fDeleteFences, { "DeleteFencesNV", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fSetFence,     { "SetFenceNV",     nullptr } },
-            { (PRFuncPtr*) &mSymbols.fTestFence,    { "TestFenceNV",    nullptr } },
-            { (PRFuncPtr*) &mSymbols.fFinishFence,  { "FinishFenceNV",  nullptr } },
-            { (PRFuncPtr*) &mSymbols.fIsFence,      { "IsFenceNV",      nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetFenceiv,   { "GetFenceivNV",   nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForExt(symbols, NV_fence);
-    }
-
-    if (IsSupported(GLFeature::read_buffer)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForFeature(symbols, GLFeature::read_buffer);
-    }
-
-    if (IsExtensionSupported(APPLE_framebuffer_multisample)) {
-        const SymLoadStruct symbols[] = {
-            { (PRFuncPtr*) &mSymbols.fResolveMultisampleFramebufferAPPLE, { "ResolveMultisampleFramebufferAPPLE", nullptr } },
-            END_SYMBOLS
-        };
-        fnLoadForExt(symbols, APPLE_framebuffer_multisample);
-    }
-
-    // Load developer symbols, don't fail if we can't find them.
-    const SymLoadStruct devSymbols[] = {
-            { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
-            { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } },
-            END_SYMBOLS
-    };
-    const bool warnOnFailures = DebugMode();
-    LoadSymbols(devSymbols, trygl, prefix, warnOnFailures);
+    mVersionString = nsPrintfCString("%u.%u.%u", mVersion / 100, (mVersion / 10) % 10, mVersion % 10);
+
+    return mInitialized;
 }
 
 #undef CORE_SYMBOL
 #undef CORE_EXT_SYMBOL2
 #undef EXT_SYMBOL2
 #undef EXT_SYMBOL3
 #undef END_SYMBOLS
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -336,16 +336,17 @@ public:
     /**
      * Get the default framebuffer for this context.
      */
     virtual GLuint GetDefaultFramebuffer() {
         return 0;
     }
 
 protected:
+    bool mInitialized;
     bool mIsOffscreen;
     bool mContextLost;
 
     /**
      * mVersion store the OpenGL's version, multiplied by 100. For example, if
      * the context is an OpenGL 2.1 context, mVersion value will be 210.
      */
     uint32_t mVersion;
@@ -353,18 +354,18 @@ protected:
     ContextProfile mProfile;
 
     uint32_t mShadingLanguageVersion;
 
     GLVendor mVendor;
     GLRenderer mRenderer;
 
     void SetProfileVersion(ContextProfile profile, uint32_t version) {
-        MOZ_ASSERT(!mSymbols.fBindFramebuffer,
-                   "SetProfileVersion can only be called before initialization!");
+        MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before"
+                                  " initialization!");
         MOZ_ASSERT(profile != ContextProfile::Unknown &&
                    profile != ContextProfile::OpenGL,
                    "Invalid `profile` for SetProfileVersion");
         MOZ_ASSERT(version >= 100, "Invalid `version` for SetProfileVersion");
 
         mVersion = version;
         mProfile = profile;
     }
@@ -548,26 +549,33 @@ private:
 
     /**
      * Is this feature supported using the core (unsuffixed) symbols?
      */
     bool IsFeatureProvidedByCoreSymbols(GLFeature feature);
 
 // -----------------------------------------------------------------------------
 // Robustness handling
-private:
+public:
+    bool HasRobustness() const {
+        return mHasRobustness;
+    }
+
     /**
      * The derived class is expected to provide information on whether or not it
      * supports robustness.
      */
     virtual bool SupportsRobustness() const = 0;
 
-public:
+private:
+    bool mHasRobustness;
+
 // -----------------------------------------------------------------------------
 // Error handling
+public:
     static const char* GLErrorToString(GLenum aError) {
         switch (aError) {
             case LOCAL_GL_INVALID_ENUM:
                 return "GL_INVALID_ENUM";
             case LOCAL_GL_INVALID_VALUE:
                 return "GL_INVALID_VALUE";
             case LOCAL_GL_INVALID_OPERATION:
                 return "GL_INVALID_OPERATION";
@@ -2208,16 +2216,18 @@ public:
     }
 
     void fDeleteTextures(GLsizei n, const GLuint* names) {
         raw_fDeleteTextures(n, names);
         TRACKING_CONTEXT(DeletedTextures(this, n, names));
     }
 
     GLenum fGetGraphicsResetStatus() {
+        MOZ_ASSERT(mHasRobustness);
+
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fGetGraphicsResetStatus);
         GLenum ret = mSymbols.fGetGraphicsResetStatus();
         AFTER_GL_CALL;
         return ret;
     }
 
 
@@ -3495,27 +3505,18 @@ public:
         return mTexGarbageBin;
     }
 
     void EmptyTexGarbageBin();
 
     bool IsOffscreenSizeAllowed(const gfx::IntSize& aSize) const;
 
 protected:
-    bool InitWithPrefix(const char* prefix, bool trygl);
-
-private:
-    bool InitWithPrefixImpl(const char* prefix, bool trygl);
-    void LoadMoreSymbols(const char* prefix, bool trygl);
-    bool LoadExtSymbols(const char* prefix, bool trygl, const SymLoadStruct* list,
-                        GLExtensions ext);
-    bool LoadFeatureSymbols(const char* prefix, bool trygl, const SymLoadStruct* list,
-                            GLFeature feature);
-
-protected:
+    bool InitWithPrefix(const char *prefix, bool trygl);
+
     void InitExtensions();
 
     GLint mViewportRect[4];
     GLint mScissorRect[4];
 
     GLint mMaxTextureSize;
     GLint mMaxCubeMapTextureSize;
     GLint mMaxTextureImageSize;
--- a/gfx/gl/GLContextCGL.h
+++ b/gfx/gl/GLContextCGL.h
@@ -50,17 +50,17 @@ public:
     virtual bool IsCurrent() override;
 
     virtual GLenum GetPreferredARGB32Format() const override;
 
     virtual bool SetupLookupFunction() override;
 
     virtual bool IsDoubleBuffered() const override;
 
-    virtual bool SupportsRobustness() const override { return false; }
+    virtual bool SupportsRobustness() const override;
 
     virtual bool SwapBuffers() override;
 };
 
 } // namespace gl
 } // namespace mozilla
 
 #endif // GLCONTEXTCGL_H_
--- a/gfx/gl/GLContextEAGL.h
+++ b/gfx/gl/GLContextEAGL.h
@@ -47,17 +47,17 @@ public:
     virtual bool MakeCurrentImpl(bool aForce) override;
 
     virtual bool IsCurrent() override;
 
     virtual bool SetupLookupFunction() override;
 
     virtual bool IsDoubleBuffered() const override;
 
-    virtual bool SupportsRobustness() const override { return false; }
+    virtual bool SupportsRobustness() const override;
 
     virtual bool SwapBuffers() override;
 
     virtual GLuint GetDefaultFramebuffer() override {
         return mBackbufferFB;
     }
 
     virtual bool RenewSurface(nsIWidget* aWidget) override {
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -150,16 +150,22 @@ GLContextCGL::SetupLookupFunction()
 
 bool
 GLContextCGL::IsDoubleBuffered() const
 {
   return sCGLLibrary.UseDoubleBufferedWindows();
 }
 
 bool
+GLContextCGL::SupportsRobustness() const
+{
+    return false;
+}
+
+bool
 GLContextCGL::SwapBuffers()
 {
   PROFILER_LABEL("GLContextCGL", "SwapBuffers",
     js::ProfileEntry::Category::GRAPHICS);
 
   [mContext flushBuffer];
   return true;
 }
--- a/gfx/gl/GLContextProviderEAGL.mm
+++ b/gfx/gl/GLContextProviderEAGL.mm
@@ -138,16 +138,22 @@ GLContextEAGL::SetupLookupFunction()
 
 bool
 GLContextEAGL::IsDoubleBuffered() const
 {
     return true;
 }
 
 bool
+GLContextEAGL::SupportsRobustness() const
+{
+    return false;
+}
+
+bool
 GLContextEAGL::SwapBuffers()
 {
   PROFILER_LABEL("GLContextEAGL", "SwapBuffers",
     js::ProfileEntry::Category::GRAPHICS);
 
   [mContext presentRenderbuffer:LOCAL_GL_RENDERBUFFER];
   return true;
 }
--- a/gfx/gl/GLLibraryLoader.cpp
+++ b/gfx/gl/GLLibraryLoader.cpp
@@ -19,17 +19,17 @@ GLLibraryLoader::OpenLibrary(const char 
     mLibrary = PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL);
     if (!mLibrary)
         return false;
 
     return true;
 }
 
 bool
-GLLibraryLoader::LoadSymbols(const SymLoadStruct *firstStruct,
+GLLibraryLoader::LoadSymbols(SymLoadStruct *firstStruct,
                              bool tryplatform,
                              const char *prefix,
                              bool warnOnFailure)
 {
     return LoadSymbols(mLibrary,
                        firstStruct,
                        tryplatform ? mLookupFunc : nullptr,
                        prefix,
@@ -59,25 +59,25 @@ GLLibraryLoader::LookupSymbol(PRLibrary 
         res = PR_FindFunctionSymbolAndLibrary(sym, &leakedLibRef);
     }
 
     return res;
 }
 
 bool
 GLLibraryLoader::LoadSymbols(PRLibrary *lib,
-                             const SymLoadStruct *firstStruct,
+                             SymLoadStruct *firstStruct,
                              PlatformLookupFunction lookupFunction,
                              const char *prefix,
                              bool warnOnFailure)
 {
     char sbuf[MAX_SYMBOL_LENGTH * 2];
     int failCount = 0;
 
-    const SymLoadStruct *ss = firstStruct;
+    SymLoadStruct *ss = firstStruct;
     while (ss->symPointer) {
         *ss->symPointer = 0;
 
         for (int i = 0; i < MAX_SYMBOL_NAMES; i++) {
             if (ss->symNames[i] == nullptr)
                 break;
 
             const char *s = ss->symNames[i];
--- a/gfx/gl/GLLibraryLoader.h
+++ b/gfx/gl/GLLibraryLoader.h
@@ -30,29 +30,29 @@ public:
         MAX_SYMBOL_LENGTH = 128
     };
 
     typedef struct {
         PRFuncPtr *symPointer;
         const char *symNames[MAX_SYMBOL_NAMES];
     } SymLoadStruct;
 
-    bool LoadSymbols(const SymLoadStruct *firstStruct,
+    bool LoadSymbols(SymLoadStruct *firstStruct,
                      bool tryplatform = false,
                      const char *prefix = nullptr,
                      bool warnOnFailure = true);
 
     /*
      * Static version of the functions in this class
      */
     static PRFuncPtr LookupSymbol(PRLibrary *lib,
                                   const char *symname,
                                   PlatformLookupFunction lookupFunction = nullptr);
     static bool LoadSymbols(PRLibrary *lib,
-                            const SymLoadStruct *firstStruct,
+                            SymLoadStruct *firstStruct,
                             PlatformLookupFunction lookupFunction = nullptr,
                             const char *prefix = nullptr,
                             bool warnOnFailure = true);
 protected:
     GLLibraryLoader() {
         mLibrary = nullptr;
         mLookupFunc = nullptr;
     }