Bug 1191042 - Use CreateOffscreen for WebGL instead of CreateHeadless. - r=jrmuizel
☠☠ backed out by a33b2098c4ff ☠ ☠
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 22 Sep 2015 16:49:25 -0700
changeset 263909 f84aedf7a62d08479a37c66d7cbfa72935bb877f
parent 263908 a39e05b423f34e8546a82f702bd48975af082e81
child 263910 384a3e1b2a9944915a145001785b913011a828d1
push id29422
push usercbook@mozilla.com
push dateWed, 23 Sep 2015 10:32:35 +0000
treeherdermozilla-central@abe43c30d78d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1191042
milestone44.0a1
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
Bug 1191042 - Use CreateOffscreen for WebGL instead of CreateHeadless. - r=jrmuizel
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextState.cpp
dom/canvas/WebGLContextUtils.cpp
dom/media/platforms/android/AndroidDecoderModule.cpp
dom/plugins/base/android/ANPOpenGL.cpp
gfx/gl/EGLUtils.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextEGL.h
gfx/gl/GLContextProvider.h
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLContextProviderImpl.h
gfx/gl/GLContextProviderWGL.cpp
gfx/gl/GLContextTypes.h
gfx/gl/GLScreenBuffer.cpp
gfx/gl/SharedSurfaceANGLE.cpp
gfx/gl/SharedSurfaceANGLE.h
gfx/gl/SharedSurfaceEGL.cpp
gfx/gl/moz.build
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -212,16 +212,17 @@ WebGLContextOptions::WebGLContextOptions
         alpha = false;
 }
 
 WebGLContext::WebGLContext()
     : WebGLContextUnchecked(nullptr)
     , mBypassShaderValidation(false)
     , mGLMaxSamples(1)
     , mNeedsFakeNoAlpha(false)
+    , mNeedsFakeNoDepth(false)
     , mNeedsFakeNoStencil(false)
 {
     mGeneration = 0;
     mInvalidated = false;
     mCapturedFrameInvalidated = false;
     mShouldPresent = true;
     mResetLayer = true;
     mOptionsFrozen = false;
@@ -248,16 +249,17 @@ WebGLContext::WebGLContext()
     mViewportX = 0;
     mViewportY = 0;
     mViewportWidth = 0;
     mViewportHeight = 0;
 
     mDitherEnabled = 1;
     mRasterizerDiscardEnabled = 0; // OpenGL ES 3.0 spec p244
     mScissorTestEnabled = 0;
+    mDepthTestEnabled = 0;
     mStencilTestEnabled = 0;
 
     // initialize some GL values: we're going to get them from the GL and use them as the sizes of arrays,
     // so in case glGetIntegerv leaves them uninitialized because of a GL bug, we would have very weird crashes.
     mGLMaxVertexAttribs = 0;
     mGLMaxTextureUnits = 0;
     mGLMaxTextureSize = 0;
     mGLMaxTextureSizeLog2 = 0;
@@ -538,251 +540,244 @@ HasAcceleratedLayers(const nsCOMPtr<nsIG
         return true;
     gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status);
     if (status)
         return true;
 
     return false;
 }
 
-static already_AddRefed<GLContext>
-CreateHeadlessNativeGL(CreateContextFlags flags, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
-                       WebGLContext* webgl)
-{
-    if (!(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE) &&
-        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL))
-    {
-        webgl->GenerateWarning("Refused to create native OpenGL context"
-                               " because of blacklisting.");
-        return nullptr;
-    }
-
-    nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless(flags);
-    if (!gl) {
-        webgl->GenerateWarning("Error during native OpenGL init.");
-        return nullptr;
-    }
-    MOZ_ASSERT(!gl->IsANGLE());
-
-    return gl.forget();
-}
-
-// Note that we have a separate call for ANGLE and EGL, even though
-// right now, we get ANGLE implicitly by using EGL on Windows.
-// Eventually, we want to be able to pick ANGLE-EGL or native EGL.
-static already_AddRefed<GLContext>
-CreateHeadlessANGLE(CreateContextFlags flags, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
-                    WebGLContext* webgl)
-{
-    nsRefPtr<GLContext> gl;
-
-#ifdef XP_WIN
-    gl = gl::GLContextProviderEGL::CreateHeadless(flags);
-    if (!gl) {
-        webgl->GenerateWarning("Error during ANGLE OpenGL init.");
-        return nullptr;
-    }
-    MOZ_ASSERT(gl->IsANGLE());
-#endif
-
-    return gl.forget();
-}
-
-static already_AddRefed<GLContext>
-CreateHeadlessEGL(CreateContextFlags flags, WebGLContext* webgl)
-{
-    nsRefPtr<GLContext> gl;
-
-#ifdef ANDROID
-    gl = gl::GLContextProviderEGL::CreateHeadless(flags);
-    if (!gl) {
-        webgl->GenerateWarning("Error during EGL OpenGL init.");
-        return nullptr;
-    }
-    MOZ_ASSERT(!gl->IsANGLE());
-#endif
-
-    return gl.forget();
-}
-
-static already_AddRefed<GLContext>
-CreateHeadlessGL(CreateContextFlags flags, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
-                 WebGLContext* webgl)
-{
-    bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL");
-    bool disableANGLE = Preferences::GetBool("webgl.disable-angle", false);
-
-    if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"))
-        disableANGLE = true;
-
-    if (!webgl->IsWebGL2()) {
-        flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE;
-    }
-
-    nsRefPtr<GLContext> gl;
-
-    if (preferEGL)
-        gl = CreateHeadlessEGL(flags, webgl);
-
-    if (!gl && !disableANGLE) {
-        gl = CreateHeadlessANGLE(flags, gfxInfo, webgl);
-    }
-
-    if (!gl) {
-        gl = CreateHeadlessNativeGL(flags, gfxInfo, webgl);
-    }
-
-    return gl.forget();
-}
-
-// Try to create a dummy offscreen with the given caps.
-static bool
-CreateOffscreenWithCaps(GLContext* gl, const SurfaceCaps& caps)
-{
-    gfx::IntSize dummySize(16, 16);
-    return gl->InitOffscreen(dummySize, caps);
-}
-
 static void
-PopulateCapFallbackQueue(const SurfaceCaps& baseCaps,
-                         std::queue<SurfaceCaps>* out_fallbackCaps)
+PopulateCapFallbackQueue(const gl::SurfaceCaps& baseCaps,
+                         std::queue<gl::SurfaceCaps>* out_fallbackCaps)
 {
     out_fallbackCaps->push(baseCaps);
 
     // Dropping antialias drops our quality, but not our correctness.
     // The user basically doesn't have to handle if this fails, they
     // just get reduced quality.
     if (baseCaps.antialias) {
-        SurfaceCaps nextCaps(baseCaps);
+        gl::SurfaceCaps nextCaps(baseCaps);
         nextCaps.antialias = false;
         PopulateCapFallbackQueue(nextCaps, out_fallbackCaps);
     }
 
     // If we have to drop one of depth or stencil, we'd prefer to keep
     // depth. However, the client app will need to handle if this
     // doesn't work.
     if (baseCaps.stencil) {
-        SurfaceCaps nextCaps(baseCaps);
+        gl::SurfaceCaps nextCaps(baseCaps);
         nextCaps.stencil = false;
         PopulateCapFallbackQueue(nextCaps, out_fallbackCaps);
     }
 
     if (baseCaps.depth) {
-        SurfaceCaps nextCaps(baseCaps);
+        gl::SurfaceCaps nextCaps(baseCaps);
         nextCaps.depth = false;
         PopulateCapFallbackQueue(nextCaps, out_fallbackCaps);
     }
 }
 
-static bool
-CreateOffscreen(GLContext* gl, const WebGLContextOptions& options,
-                const nsCOMPtr<nsIGfxInfo>& gfxInfo, WebGLContext* webgl,
-                layers::LayersBackend layersBackend,
-                layers::ISurfaceAllocator* surfAllocator)
+static gl::SurfaceCaps
+BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
 {
-    SurfaceCaps baseCaps;
+    gl::SurfaceCaps baseCaps;
 
     baseCaps.color = true;
     baseCaps.alpha = options.alpha;
     baseCaps.antialias = options.antialias;
     baseCaps.depth = options.depth;
     baseCaps.premultAlpha = options.premultipliedAlpha;
     baseCaps.preserve = options.preserveDrawingBuffer;
     baseCaps.stencil = options.stencil;
 
     if (!baseCaps.alpha)
         baseCaps.premultAlpha = true;
 
-    if (gl->IsANGLE() ||
-        (gl->GetContextType() == GLContextType::GLX &&
-         layersBackend == LayersBackend::LAYERS_OPENGL))
-    {
-        // We can't use no-alpha formats on ANGLE yet because of:
-        // https://code.google.com/p/angleproject/issues/detail?id=764
-        // GLX only supports GL_RGBA pixmaps as well. Since we can't blit from
-        // an RGB FB to GLX's RGBA FB, force RGBA when surface sharing.
-        baseCaps.alpha = true;
-    }
-
     // we should really have this behind a
     // |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
     // for now it's just behind a pref for testing/evaluation.
     baseCaps.bpp16 = Preferences::GetBool("webgl.prefer-16bpp", false);
 
 #ifdef MOZ_WIDGET_GONK
-    baseCaps.surfaceAllocator = surfAllocator;
+    do {
+        auto canvasElement = webgl->GetCanvas();
+        auto ownerDoc = canvasElement->OwnerDoc();
+        nsIWidget* docWidget = nsContentUtils::WidgetForDocument(ownerDoc);
+        if (!docWidget)
+            break;
+
+        layers::LayerManager* layerManager = docWidget->GetLayerManager();
+        if (!layerManager)
+            break;
+
+        // XXX we really want "AsSurfaceAllocator" here for generality
+        layers::ShadowLayerForwarder* forwarder = layerManager->AsShadowForwarder();
+        if (!forwarder)
+            break;
+
+        baseCaps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
+    } while (false);
 #endif
 
     // Done with baseCaps construction.
 
     bool forceAllowAA = Preferences::GetBool("webgl.msaa-force", false);
+    nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
     if (!forceAllowAA &&
         IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA))
     {
         webgl->GenerateWarning("Disallowing antialiased backbuffers due"
                                " to blacklisting.");
         baseCaps.antialias = false;
     }
 
-    std::queue<SurfaceCaps> fallbackCaps;
+    return baseCaps;
+}
+
+////////////////////////////////////////
+
+static already_AddRefed<gl::GLContext>
+CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
+                WebGLContext* webgl)
+{
+    RefPtr<GLContext> gl;
+#ifndef XP_MACOSX // Mac doesn't have GLContextProviderEGL.
+    gfx::IntSize dummySize(16, 16);
+    gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
+                                                                     flags);
+    if (!gl) {
+        webgl->GenerateWarning("Error during EGL OpenGL init.");
+        return nullptr;
+    }
+
+    if (gl->IsANGLE())
+        return nullptr;
+#endif // XP_MACOSX
+    return gl.forget();
+}
+
+static already_AddRefed<GLContext>
+CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
+                  WebGLContext* webgl)
+{
+    RefPtr<GLContext> gl;
+
+#ifdef XP_WIN
+    gfx::IntSize dummySize(16, 16);
+    gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps, flags);
+    if (!gl) {
+        webgl->GenerateWarning("Error during ANGLE OpenGL init.");
+        return nullptr;
+    }
+
+    if (!gl->IsANGLE())
+        return nullptr;
+#endif
+
+    return gl.forget();
+}
+
+static already_AddRefed<gl::GLContext>
+CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
+                    WebGLContext* webgl)
+{
+    nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+
+    if (!(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE) &&
+        IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL))
+    {
+        webgl->GenerateWarning("Refused to create native OpenGL context because of"
+                               " blacklisting.");
+        return nullptr;
+    }
+
+    gfx::IntSize dummySize(16, 16);
+    RefPtr<GLContext> gl = gl::GLContextProvider::CreateOffscreen(dummySize, caps, flags);
+    if (!gl) {
+        webgl->GenerateWarning("Error during native OpenGL init.");
+        return nullptr;
+    }
+
+    if (gl->IsANGLE())
+        return nullptr;
+
+    return gl.forget();
+}
+
+////////////////////////////////////////
+
+bool
+WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
+                                  const gl::SurfaceCaps& baseCaps,
+                                  gl::CreateContextFlags flags)
+{
+    MOZ_ASSERT(!gl);
+
+    std::queue<gl::SurfaceCaps> fallbackCaps;
     PopulateCapFallbackQueue(baseCaps, &fallbackCaps);
 
-    bool created = false;
+    gl = nullptr;
     while (!fallbackCaps.empty()) {
-        SurfaceCaps& caps = fallbackCaps.front();
+        gl::SurfaceCaps& caps = fallbackCaps.front();
 
-        created = CreateOffscreenWithCaps(gl, caps);
-        if (created)
+        gl = fnCreateGL(caps, flags, this);
+        if (gl)
             break;
 
         fallbackCaps.pop();
     }
+    if (!gl)
+        return false;
 
-    return created;
+    if (!InitAndValidateGL()) {
+        gl = nullptr;
+        return false;
+    }
+
+    return true;
 }
 
 bool
-WebGLContext::CreateOffscreenGL(bool forceEnabled)
+WebGLContext::CreateAndInitGL(bool forceEnabled)
 {
-    nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+    bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL");
+    bool disableANGLE = Preferences::GetBool("webgl.disable-angle", false);
+
+    if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"))
+        disableANGLE = true;
 
-    layers::ISurfaceAllocator* surfAllocator = nullptr;
-#ifdef MOZ_WIDGET_GONK
-    nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc());
-    if (docWidget) {
-        layers::LayerManager* layerManager = docWidget->GetLayerManager();
-        if (layerManager) {
-            // XXX we really want "AsSurfaceAllocator" here for generality
-            layers::ShadowLayerForwarder* forwarder = layerManager->AsShadowForwarder();
-            if (forwarder)
-                surfAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
-        }
-    }
-#endif
+    gl::CreateContextFlags flags = gl::CreateContextFlags::NONE;
+    if (forceEnabled) flags |= gl::CreateContextFlags::FORCE_ENABLE_HARDWARE;
+    if (!IsWebGL2())  flags |= gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE;
+
+    const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this);
+
+    MOZ_ASSERT(!gl);
 
-    CreateContextFlags flags = forceEnabled ? CreateContextFlags::FORCE_ENABLE_HARDWARE :
-                                              CreateContextFlags::NONE;
+    if (preferEGL) {
+        if (CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags))
+            return true;
+    }
 
-    gl = CreateHeadlessGL(flags, gfxInfo, this);
-
-    do {
-        if (!gl)
-            break;
+    MOZ_ASSERT(!gl);
 
-        if (!CreateOffscreen(gl, mOptions, gfxInfo, this,
-                             GetCompositorBackendType(), surfAllocator))
-            break;
+    if (!disableANGLE) {
+        if (CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags))
+            return true;
+    }
+
+    MOZ_ASSERT(!gl);
 
-        if (!InitAndValidateGL())
-            break;
-
+    if (CreateAndInitGLWith(CreateGLWithDefault, baseCaps, flags))
         return true;
-    } while (false);
 
+    MOZ_ASSERT(!gl);
     gl = nullptr;
+
     return false;
 }
 
 // Fallback for resizes:
 bool
 WebGLContext::ResizeBackbuffer(uint32_t requestedWidth,
                                uint32_t requestedHeight)
 {
@@ -936,22 +931,25 @@ WebGLContext::SetDimensions(int32_t sign
             return NS_ERROR_FAILURE;
         }
     }
 
     // Alright, now let's start trying.
     bool forceEnabled = Preferences::GetBool("webgl.force-enabled", false);
     ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
 
-    if (!CreateOffscreenGL(forceEnabled)) {
+    MOZ_ASSERT(!gl);
+    if (!CreateAndInitGL(forceEnabled)) {
         GenerateWarning("WebGL creation failed.");
         return NS_ERROR_FAILURE;
     }
     MOZ_ASSERT(gl);
 
+    MOZ_ASSERT_IF(mOptions.alpha, gl->Caps().alpha);
+
     if (!ResizeBackbuffer(width, height)) {
         GenerateWarning("Initializing WebGL backbuffer failed.");
         return NS_ERROR_FAILURE;
     }
 
 #ifdef DEBUG
     if (gl->DebugMode())
         printf_stderr("--- WebGL context created: %p\n", gl.get());
@@ -960,24 +958,30 @@ WebGLContext::SetDimensions(int32_t sign
     mResetLayer = true;
     mOptionsFrozen = true;
 
     // Update our internal stuff:
     if (gl->WorkAroundDriverBugs()) {
         if (!mOptions.alpha && gl->Caps().alpha)
             mNeedsFakeNoAlpha = true;
 
-        // ANGLE doesn't quite handle this properly.
-        if (gl->Caps().depth && !gl->Caps().stencil && gl->IsANGLE())
+        if (!mOptions.depth && gl->Caps().depth)
+            mNeedsFakeNoDepth = true;
+
+        if (!mOptions.stencil && gl->Caps().stencil)
             mNeedsFakeNoStencil = true;
     }
 
     // Update mOptions.
-    mOptions.depth = gl->Caps().depth;
-    mOptions.stencil = gl->Caps().stencil;
+    if (!gl->Caps().depth)
+        mOptions.depth = false;
+
+    if (!gl->Caps().stencil)
+        mOptions.stencil = false;
+
     mOptions.antialias = gl->Caps().antialias;
 
     MakeContextCurrent();
 
     gl->fViewport(0, 0, mWidth, mHeight);
     mViewportWidth = mWidth;
     mViewportHeight = mHeight;
 
@@ -993,20 +997,26 @@ WebGLContext::SetDimensions(int32_t sign
     // Clear immediately, because we need to present the cleared initial
     // buffer.
     mBackbufferNeedsClear = true;
     ClearBackbufferIfNeeded();
 
     mShouldPresent = true;
 
     MOZ_ASSERT(gl->Caps().color);
+
     MOZ_ASSERT_IF(!mNeedsFakeNoAlpha, gl->Caps().alpha == mOptions.alpha);
     MOZ_ASSERT_IF(mNeedsFakeNoAlpha, !mOptions.alpha && gl->Caps().alpha);
-    MOZ_ASSERT(gl->Caps().depth == mOptions.depth);
-    MOZ_ASSERT(gl->Caps().stencil == mOptions.stencil);
+
+    MOZ_ASSERT_IF(!mNeedsFakeNoDepth, gl->Caps().depth == mOptions.depth);
+    MOZ_ASSERT_IF(mNeedsFakeNoDepth, !mOptions.depth && gl->Caps().depth);
+
+    MOZ_ASSERT_IF(!mNeedsFakeNoStencil, gl->Caps().stencil == mOptions.stencil);
+    MOZ_ASSERT_IF(mNeedsFakeNoStencil, !mOptions.stencil && gl->Caps().stencil);
+
     MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias);
     MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
 
     AssertCachedBindings();
     AssertCachedState();
 
     reporter.SetSuccessful();
     return NS_OK;
@@ -1871,37 +1881,44 @@ RoundedToNextMultipleOf(CheckedUint32 x,
     return ((x + y - 1) / y) * y;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
     : mWebGL(webgl)
     , mFakeNoAlpha(ShouldFakeNoAlpha(webgl))
+    , mFakeNoDepth(ShouldFakeNoDepth(webgl))
     , mFakeNoStencil(ShouldFakeNoStencil(webgl))
 {
     if (mFakeNoAlpha) {
         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
                               mWebGL.mColorWriteMask[1],
                               mWebGL.mColorWriteMask[2],
                               false);
     }
+    if (mFakeNoDepth) {
+        mWebGL.gl->fDisable(LOCAL_GL_DEPTH_TEST);
+    }
     if (mFakeNoStencil) {
         mWebGL.gl->fDisable(LOCAL_GL_STENCIL_TEST);
     }
 }
 
 WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround()
 {
     if (mFakeNoAlpha) {
         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
                               mWebGL.mColorWriteMask[1],
                               mWebGL.mColorWriteMask[2],
                               mWebGL.mColorWriteMask[3]);
     }
+    if (mFakeNoDepth) {
+        mWebGL.gl->fEnable(LOCAL_GL_DEPTH_TEST);
+    }
     if (mFakeNoStencil) {
         mWebGL.gl->fEnable(LOCAL_GL_STENCIL_TEST);
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XPCOM goop
 
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -3,32 +3,34 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLCONTEXT_H_
 #define WEBGLCONTEXT_H_
 
 #include <stdarg.h>
 
+#include "GLContextTypes.h"
 #include "GLDefs.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "nsCycleCollectionNoteChild.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsLayoutUtils.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
+#include "SurfaceTypes.h"
 
 #ifdef XP_MACOSX
 #include "ForceDiscreteGPUHelperCGL.h"
 #endif
 
 // Local
 #include "WebGLContextUnchecked.h"
 #include "WebGLFormats.h"
@@ -807,16 +809,17 @@ public:
                              JS::MutableHandle<JS::Value> retval);
     bool IsEnabled(GLenum cap);
 
 private:
     // State tracking slots
     realGLboolean mDitherEnabled;
     realGLboolean mRasterizerDiscardEnabled;
     realGLboolean mScissorTestEnabled;
+    realGLboolean mDepthTestEnabled;
     realGLboolean mStencilTestEnabled;
 
     bool ValidateCapabilityEnum(GLenum cap, const char* info);
     realGLboolean* GetStateTrackingSlot(GLenum cap);
 
 // -----------------------------------------------------------------------------
 // Texture funcions (WebGLContextTextures.cpp)
 public:
@@ -1148,21 +1151,29 @@ protected:
     // -------------------------------------------------------------------------
     // WebGL 2 specifics (implemented in WebGL2Context.cpp)
 public:
     virtual bool IsWebGL2() const = 0;
 
 protected:
     bool InitWebGL2();
 
+    bool CreateAndInitGL(bool forceEnabled);
+    bool ResizeBackbuffer(uint32_t width, uint32_t height);
+
+    typedef already_AddRefed<gl::GLContext> FnCreateGL_T(const gl::SurfaceCaps& caps,
+                                                         gl::CreateContextFlags flags,
+                                                         WebGLContext* webgl);
+
+    bool CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps,
+                             gl::CreateContextFlags flags);
+
     // -------------------------------------------------------------------------
     // Validation functions (implemented in WebGLContextValidate.cpp)
-    bool CreateOffscreenGL(bool forceEnabled);
     bool InitAndValidateGL();
-    bool ResizeBackbuffer(uint32_t width, uint32_t height);
     bool ValidateBlendEquationEnum(GLenum cap, const char* info);
     bool ValidateBlendFuncDstEnum(GLenum mode, const char* info);
     bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info);
     bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor,
                                              const char* info);
     bool ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info);
     bool ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info);
     bool ValidateTextureTargetEnum(GLenum target, const char* info);
@@ -1438,31 +1449,40 @@ protected:
     int mMaxWarnings;
     bool mAlreadyWarnedAboutFakeVertexAttrib0;
 
     bool ShouldGenerateWarnings() const;
 
     uint64_t mLastUseIndex;
 
     bool mNeedsFakeNoAlpha;
+    bool mNeedsFakeNoDepth;
     bool mNeedsFakeNoStencil;
 
     struct ScopedMaskWorkaround {
         WebGLContext& mWebGL;
         const bool mFakeNoAlpha;
+        const bool mFakeNoDepth;
         const bool mFakeNoStencil;
 
         static bool ShouldFakeNoAlpha(WebGLContext& webgl) {
             // We should only be doing this if we're about to draw to the backbuffer, but
             // the backbuffer needs to have this fake-no-alpha workaround.
             return !webgl.mBoundDrawFramebuffer &&
                    webgl.mNeedsFakeNoAlpha &&
                    webgl.mColorWriteMask[3] != false;
         }
 
+        static bool ShouldFakeNoDepth(WebGLContext& webgl) {
+            // We should only be doing this if we're about to draw to the backbuffer.
+            return !webgl.mBoundDrawFramebuffer &&
+                   webgl.mNeedsFakeNoDepth &&
+                   webgl.mDepthTestEnabled;
+        }
+
         static bool ShouldFakeNoStencil(WebGLContext& webgl) {
             // We should only be doing this if we're about to draw to the backbuffer.
             return !webgl.mBoundDrawFramebuffer &&
                    webgl.mNeedsFakeNoStencil &&
                    webgl.mStencilTestEnabled;
         }
 
         explicit ScopedMaskWorkaround(WebGLContext& webgl);
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -355,20 +355,26 @@ WebGLContext::GetParameter(JSContext* cx
         case LOCAL_GL_SAMPLE_BUFFERS:
         case LOCAL_GL_SAMPLES:
         case LOCAL_GL_MAX_VERTEX_ATTRIBS:
         case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_RED_BITS:
         case LOCAL_GL_GREEN_BITS:
-        case LOCAL_GL_BLUE_BITS:
+        case LOCAL_GL_BLUE_BITS: {
+            GLint i = 0;
+            gl->fGetIntegerv(pname, &i);
+            return JS::Int32Value(i);
+        }
         case LOCAL_GL_DEPTH_BITS: {
             GLint i = 0;
-            gl->fGetIntegerv(pname, &i);
+            if (!mNeedsFakeNoDepth) {
+                gl->fGetIntegerv(pname, &i);
+            }
             return JS::Int32Value(i);
         }
         case LOCAL_GL_ALPHA_BITS: {
             GLint i = 0;
             if (!mNeedsFakeNoAlpha) {
                 gl->fGetIntegerv(pname, &i);
             }
             return JS::Int32Value(i);
@@ -617,16 +623,18 @@ WebGLContext::ValidateCapabilityEnum(GLe
             return false;
     }
 }
 
 realGLboolean*
 WebGLContext::GetStateTrackingSlot(GLenum cap)
 {
     switch (cap) {
+        case LOCAL_GL_DEPTH_TEST:
+            return &mDepthTestEnabled;
         case LOCAL_GL_DITHER:
             return &mDitherEnabled;
         case LOCAL_GL_RASTERIZER_DISCARD:
             return &mRasterizerDiscardEnabled;
         case LOCAL_GL_SCISSOR_TEST:
             return &mScissorTestEnabled;
         case LOCAL_GL_STENCIL_TEST:
             return &mStencilTestEnabled;
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -1170,16 +1170,17 @@ WebGLContext::AssertCachedState()
 
     // extensions
     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
         AssertUintParamCorrect(gl, LOCAL_GL_MAX_COLOR_ATTACHMENTS, mGLMaxColorAttachments);
         AssertUintParamCorrect(gl, LOCAL_GL_MAX_DRAW_BUFFERS, mGLMaxDrawBuffers);
     }
 
     // Draw state
+    MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DEPTH_TEST) == mDepthTestEnabled);
     MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled);
     MOZ_ASSERT_IF(IsWebGL2(),
                   gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled);
     MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled);
     MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_STENCIL_TEST) == mStencilTestEnabled);
 
     realGLboolean colorWriteMask[4] = {0, 0, 0, 0};
     gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -95,17 +95,17 @@ public:
       return nullptr;
     }
 
     EGLint attribs[] = {
       LOCAL_EGL_IMAGE_PRESERVED_KHR, LOCAL_EGL_TRUE,
       LOCAL_EGL_NONE, LOCAL_EGL_NONE
     };
 
-    EGLContext eglContext = static_cast<GLContextEGL*>(mGLContext.get())->GetEGLContext();
+    EGLContext eglContext = static_cast<GLContextEGL*>(mGLContext.get())->mContext;
     EGLImage eglImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext,
                                                  LOCAL_EGL_GL_TEXTURE_2D_KHR,
                                                  (EGLClientBuffer)tex, attribs);
     mGLContext->fDeleteTextures(1, &tex);
 
     return eglImage;
   }
 
--- a/dom/plugins/base/android/ANPOpenGL.cpp
+++ b/dom/plugins/base/android/ANPOpenGL.cpp
@@ -23,17 +23,17 @@ typedef nsNPAPIPluginInstance::TextureIn
 static ANPEGLContext anp_opengl_acquireContext(NPP instance) {
     nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
 
     GLContext* context = pinst->GLContext();
     if (!context)
         return nullptr;
 
     context->MakeCurrent();
-    return GLContextEGL::Cast(context)->GetEGLContext();
+    return GLContextEGL::Cast(context)->mContext;
 }
 
 static ANPTextureInfo anp_opengl_lockTexture(NPP instance) {
     nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
 
     TextureInfo pluginInfo = pinst->LockContentTexture();
 
     ANPTextureInfo info;
--- a/gfx/gl/EGLUtils.cpp
+++ b/gfx/gl/EGLUtils.cpp
@@ -18,17 +18,17 @@ DoesEGLContextSupportSharingWithEGLImage
 }
 
 EGLImage
 CreateEGLImage(GLContext* gl, GLuint tex)
 {
     MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl));
 
     EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex);
-    EGLContext eglContext = GLContextEGL::Cast(gl)->GetEGLContext();
+    EGLContext eglContext = GLContextEGL::Cast(gl)->mContext;
     EGLImage image = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
                                               eglContext,
                                               LOCAL_EGL_GL_TEXTURE_2D,
                                               clientBuffer,
                                               nullptr);
     return image;
 }
 
@@ -37,17 +37,17 @@ CreateEGLImage(GLContext* gl, GLuint tex
 
 /*static*/ EGLImageWrapper*
 EGLImageWrapper::Create(GLContext* gl, GLuint tex)
 {
     MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl));
 
     GLLibraryEGL& library = sEGLLibrary;
     EGLDisplay display = EGL_DISPLAY();
-    EGLContext eglContext = GLContextEGL::Cast(gl)->GetEGLContext();
+    EGLContext eglContext = GLContextEGL::Cast(gl)->mContext;
     EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex);
     EGLImage image = library.fCreateImage(display,
                                           eglContext,
                                           LOCAL_EGL_GL_TEXTURE_2D,
                                           clientBuffer,
                                           nullptr);
     if (!image) {
 #ifdef DEBUG
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -301,17 +301,16 @@ GLContext::GLContext(const SurfaceCaps& 
     mIsOffscreen(isOffscreen),
     mContextLost(false),
     mVersion(0),
     mProfile(ContextProfile::Unknown),
     mVendor(GLVendor::Other),
     mRenderer(GLRenderer::Other),
     mHasRobustness(false),
     mTopError(LOCAL_GL_NO_ERROR),
-    mLocalErrorScope(nullptr),
     mSharedContext(sharedContext),
     mCaps(caps),
     mScreen(nullptr),
     mLockedSurface(nullptr),
     mMaxTextureSize(0),
     mMaxCubeMapTextureSize(0),
     mMaxTextureImageSize(0),
     mMaxRenderbufferSize(0),
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2,22 +2,23 @@
 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GLCONTEXT_H_
 #define GLCONTEXT_H_
 
-#include <stdio.h>
-#include <stdint.h>
+#include <bitset>
 #include <ctype.h>
+#include <stdint.h>
+#include <stdio.h>
 #include <map>
-#include <bitset>
 #include <queue>
+#include <stack>
 
 #ifdef DEBUG
 #include <string.h>
 #endif
 
 #ifdef WIN32
 #include <windows.h>
 #endif
@@ -614,31 +615,30 @@ public:
         return err;
     }
 
     ////////////////////////////////////
     // Use this safer option.
     class LocalErrorScope;
 
 private:
-    LocalErrorScope* mLocalErrorScope;
+    std::stack<const LocalErrorScope*> mLocalErrorScopeStack;
 
 public:
     class LocalErrorScope {
         GLContext& mGL;
         GLenum mOldTop;
         bool mHasBeenChecked;
 
     public:
         explicit LocalErrorScope(GLContext& gl)
             : mGL(gl)
             , mHasBeenChecked(false)
         {
-            MOZ_ASSERT(!mGL.mLocalErrorScope);
-            mGL.mLocalErrorScope = this;
+            mGL.mLocalErrorScopeStack.push(this);
 
             mGL.FlushErrors();
 
             mOldTop = mGL.mTopError;
             mGL.mTopError = LOCAL_GL_NO_ERROR;
         }
 
         GLenum GetError() {
@@ -648,20 +648,20 @@ public:
             return mGL.fGetError();
         }
 
         ~LocalErrorScope() {
             MOZ_ASSERT(mHasBeenChecked);
 
             MOZ_ASSERT(mGL.fGetError() == LOCAL_GL_NO_ERROR);
 
+            MOZ_ASSERT(mGL.mLocalErrorScopeStack.top() == this);
+            mGL.mLocalErrorScopeStack.pop();
+
             mGL.mTopError = mOldTop;
-
-            MOZ_ASSERT(mGL.mLocalErrorScope == this);
-            mGL.mLocalErrorScope = nullptr;
         }
     };
 
     bool GetPotentialInteger(GLenum pname, GLint* param) {
         LocalErrorScope localError(*this);
 
         fGetIntegerv(pname, param);
 
@@ -733,17 +733,17 @@ private:
             GLenum err = FlushErrors();
 
             if (DebugMode() & DebugTrace) {
                 printf_stderr("[gl:%p] < %s [%s (0x%04x)]\n", this, funcName,
                               GLErrorToString(err), err);
             }
 
             if (err != LOCAL_GL_NO_ERROR &&
-                !mLocalErrorScope)
+                !mLocalErrorScopeStack.size())
             {
                 printf_stderr("[gl:%p] %s: Generated unexpected %s error."
                               " (0x%04x)\n", this, funcName,
                               GLErrorToString(err), err);
 
                 if (DebugMode() & DebugAbortOnError)
                     MOZ_CRASH("MOZ_GL_DEBUG_ABORT_ON_ERROR");
             }
--- a/gfx/gl/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -87,45 +87,46 @@ public:
     virtual bool SetupLookupFunction() override;
 
     virtual bool SwapBuffers() override;
 
     // hold a reference to the given surface
     // for the lifetime of this context.
     void HoldSurface(gfxASurface *aSurf);
 
-    EGLContext GetEGLContext() {
-        return mContext;
-    }
-
-    EGLSurface GetEGLSurface() {
+    EGLSurface GetEGLSurface() const {
         return mSurface;
     }
 
-    EGLDisplay GetEGLDisplay() {
-        return EGL_DISPLAY();
+    EGLDisplay GetEGLDisplay() const {
+        return sEGLLibrary.Display();
     }
 
     bool BindTex2DOffscreen(GLContext *aOffscreen);
     void UnbindTex2DOffscreen(GLContext *aOffscreen);
     void BindOffscreenFramebuffer();
 
     static already_AddRefed<GLContextEGL>
     CreateEGLPixmapOffscreenContext(const gfx::IntSize& size);
 
     static already_AddRefed<GLContextEGL>
-    CreateEGLPBufferOffscreenContext(const gfx::IntSize& size);
+    CreateEGLPBufferOffscreenContext(const gfx::IntSize& size,
+                                     const SurfaceCaps& minCaps);
 
 protected:
     friend class GLContextProviderEGL;
 
-    EGLConfig  mConfig;
+public:
+    const EGLConfig  mConfig;
+protected:
     EGLSurface mSurface;
+public:
+    const EGLContext mContext;
+protected:
     EGLSurface mSurfaceOverride;
-    EGLContext mContext;
     nsRefPtr<gfxASurface> mThebesSurface;
     bool mBound;
 
     bool mIsPBuffer;
     bool mIsDoubleBuffered;
     bool mCanBindToTexture;
     bool mShareWithEGLImage;
     bool mOwnsContext;
--- a/gfx/gl/GLContextProvider.h
+++ b/gfx/gl/GLContextProvider.h
@@ -4,84 +4,71 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GLCONTEXTPROVIDER_H_
 #define GLCONTEXTPROVIDER_H_
 
 #include "GLContextTypes.h"
 #include "nsAutoPtr.h"
 #include "SurfaceTypes.h"
-#include "mozilla/TypedEnumBits.h"
 
 #include "nsSize.h" // for gfx::IntSize (needed by GLContextProviderImpl.h below)
 
 class nsIWidget;
 
 namespace mozilla {
 namespace gl {
 
-enum class CreateContextFlags : int8_t {
-    NONE = 0,
-    REQUIRE_COMPAT_PROFILE = 1 << 0,
-    // Force the use of hardware backed GL, don't allow software implementations.
-    FORCE_ENABLE_HARDWARE = 1 << 1,
-    /* Don't force discrete GPU to be used (if applicable) */
-    ALLOW_OFFLINE_RENDERER =  1 << 2,
-};
-MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags)
-
 #define IN_GL_CONTEXT_PROVIDER_H
 
 // Null is always there
 #define GL_CONTEXT_PROVIDER_NAME GLContextProviderNull
 #include "GLContextProviderImpl.h"
 #undef GL_CONTEXT_PROVIDER_NAME
 
 #ifdef XP_WIN
-#define GL_CONTEXT_PROVIDER_NAME GLContextProviderWGL
-#include "GLContextProviderImpl.h"
-#undef GL_CONTEXT_PROVIDER_NAME
-#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderWGL
-#define DEFAULT_IMPL WGL
+  #define GL_CONTEXT_PROVIDER_NAME GLContextProviderWGL
+  #include "GLContextProviderImpl.h"
+  #undef GL_CONTEXT_PROVIDER_NAME
+  #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderWGL
+  #define DEFAULT_IMPL WGL
 #endif
 
 #ifdef XP_MACOSX
-#define GL_CONTEXT_PROVIDER_NAME GLContextProviderCGL
-#include "GLContextProviderImpl.h"
-#undef GL_CONTEXT_PROVIDER_NAME
-#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL
+  #define GL_CONTEXT_PROVIDER_NAME GLContextProviderCGL
+  #include "GLContextProviderImpl.h"
+  #undef GL_CONTEXT_PROVIDER_NAME
+  #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL
 #endif
 
-#if defined(ANDROID) || defined(XP_WIN)
+#if defined(MOZ_X11)
+  #define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX
+  #include "GLContextProviderImpl.h"
+  #undef GL_CONTEXT_PROVIDER_NAME
+  #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderGLX
+#endif
+
 #define GL_CONTEXT_PROVIDER_NAME GLContextProviderEGL
 #include "GLContextProviderImpl.h"
 #undef GL_CONTEXT_PROVIDER_NAME
 #ifndef GL_CONTEXT_PROVIDER_DEFAULT
-#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL
-#endif
+  #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL
 #endif
 
 #ifdef MOZ_GL_PROVIDER
-#define GL_CONTEXT_PROVIDER_NAME MOZ_GL_PROVIDER
-#include "GLContextProviderImpl.h"
-#undef GL_CONTEXT_PROVIDER_NAME
-#define GL_CONTEXT_PROVIDER_DEFAULT MOZ_GL_PROVIDER
-#endif
-
-#if defined(MOZ_X11) && !defined(GL_CONTEXT_PROVIDER_DEFAULT)
-#define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX
-#include "GLContextProviderImpl.h"
-#undef GL_CONTEXT_PROVIDER_NAME
-#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderGLX
+  #define GL_CONTEXT_PROVIDER_NAME MOZ_GL_PROVIDER
+  #include "GLContextProviderImpl.h"
+  #undef GL_CONTEXT_PROVIDER_NAME
+  #define GL_CONTEXT_PROVIDER_DEFAULT MOZ_GL_PROVIDER
 #endif
 
 #ifdef GL_CONTEXT_PROVIDER_DEFAULT
-typedef GL_CONTEXT_PROVIDER_DEFAULT GLContextProvider;
+  typedef GL_CONTEXT_PROVIDER_DEFAULT GLContextProvider;
 #else
-typedef GLContextProviderNull GLContextProvider;
+  typedef GLContextProviderNull GLContextProvider;
 #endif
 
 #undef IN_GL_CONTEXT_PROVIDER_H
 
 } // namespace gl
 } // namespace mozilla
 
 #endif
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -312,26 +312,27 @@ GLContextProviderCGL::CreateHeadless(Cre
         return nullptr;
     }
 
     return gl.forget();
 }
 
 already_AddRefed<GLContext>
 GLContextProviderCGL::CreateOffscreen(const IntSize& size,
-                                      const SurfaceCaps& caps,
+                                      const SurfaceCaps& minCaps,
                                       CreateContextFlags flags)
 {
-    nsRefPtr<GLContext> glContext = CreateHeadless(flags);
-    if (!glContext->InitOffscreen(size, caps)) {
-        NS_WARNING("Failed during InitOffscreen.");
+    RefPtr<GLContext> gl = CreateHeadless(flags);
+    if (!gl)
         return nullptr;
-    }
 
-    return glContext.forget();
+    if (!gl->InitOffscreen(size, minCaps))
+        return nullptr;
+
+    return gl.forget();
 }
 
 static nsRefPtr<GLContext> gGlobalContext;
 
 GLContext*
 GLContextProviderCGL::GetGlobalContext()
 {
     if (!sCGLLibrary.EnsureInitialized()) {
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -187,41 +187,41 @@ DestroySurface(EGLSurface oldSurface) {
         sEGLLibrary.fDestroySurface(EGL_DISPLAY(), oldSurface);
     }
 }
 
 static EGLSurface
 CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) {
     EGLSurface newSurface = EGL_NO_SURFACE;
 
-    #ifdef MOZ_WIDGET_ANDROID
+#ifdef MOZ_WIDGET_ANDROID
         mozilla::AndroidBridge::Bridge()->RegisterCompositor();
         newSurface = mozilla::AndroidBridge::Bridge()->CreateEGLSurfaceForCompositor();
         if (newSurface == EGL_NO_SURFACE) {
             return EGL_NO_SURFACE;
         }
-    #else
+#elif defined(XP_WIN)
         MOZ_ASSERT(widget != nullptr);
         newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(widget), 0);
-    #endif
+#endif
     return newSurface;
 }
 
 GLContextEGL::GLContextEGL(
                   const SurfaceCaps& caps,
                   GLContext* shareContext,
                   bool isOffscreen,
                   EGLConfig config,
                   EGLSurface surface,
                   EGLContext context)
     : GLContext(caps, shareContext, isOffscreen)
     , mConfig(config)
     , mSurface(surface)
+    , mContext(context)
     , mSurfaceOverride(EGL_NO_SURFACE)
-    , mContext(context)
     , mThebesSurface(nullptr)
     , mBound(false)
     , mIsPBuffer(false)
     , mIsDoubleBuffered(false)
     , mCanBindToTexture(false)
     , mShareWithEGLImage(false)
     , mOwnsContext(true)
 {
@@ -834,70 +834,154 @@ GLContextProviderEGL::DestroyEGLSurface(
     if (!sEGLLibrary.EnsureInitialized()) {
         MOZ_CRASH("Failed to load EGL library!\n");
     }
 
     sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
 }
 #endif // defined(ANDROID)
 
-already_AddRefed<GLContextEGL>
-GLContextEGL::CreateEGLPBufferOffscreenContext(const mozilla::gfx::IntSize& size)
+static void
+FillContextAttribs(bool alpha, bool depth, bool stencil, bool bpp16,
+                   nsTArray<EGLint>* out)
 {
-    EGLConfig config;
-    EGLSurface surface;
+    out->AppendElement(LOCAL_EGL_SURFACE_TYPE);
+    out->AppendElement(LOCAL_EGL_PBUFFER_BIT);
+
+    out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE);
+    out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT);
+
+    out->AppendElement(LOCAL_EGL_RED_SIZE);
+    if (bpp16) {
+        out->AppendElement(alpha ? 4 : 5);
+    } else {
+        out->AppendElement(8);
+    }
+
+    out->AppendElement(LOCAL_EGL_GREEN_SIZE);
+    if (bpp16) {
+        out->AppendElement(alpha ? 4 : 6);
+    } else {
+        out->AppendElement(8);
+    }
+
+    out->AppendElement(LOCAL_EGL_BLUE_SIZE);
+    if (bpp16) {
+        out->AppendElement(alpha ? 4 : 5);
+    } else {
+        out->AppendElement(8);
+    }
+
+    out->AppendElement(LOCAL_EGL_ALPHA_SIZE);
+    if (alpha) {
+        out->AppendElement(bpp16 ? 4 : 8);
+    } else {
+        out->AppendElement(0);
+    }
 
-    const EGLint numConfigs = 1; // We only need one.
-    EGLConfig configs[numConfigs];
+    out->AppendElement(LOCAL_EGL_DEPTH_SIZE);
+    out->AppendElement(depth ? 16 : 0);
+
+    out->AppendElement(LOCAL_EGL_STENCIL_SIZE);
+    out->AppendElement(stencil ? 8 : 0);
+
+    // EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
+    out->AppendElement(LOCAL_EGL_NONE);
+    out->AppendElement(0);
+
+    out->AppendElement(0);
+    out->AppendElement(0);
+}
+
+static GLint
+GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib)
+{
+    EGLint bits = 0;
+    egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits);
+    MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
+
+    return bits;
+}
+
+static EGLConfig
+ChooseConfig(GLLibraryEGL* egl, const SurfaceCaps& minCaps,
+             SurfaceCaps* const out_configCaps)
+{
+    nsTArray<EGLint> configAttribList;
+    FillContextAttribs(minCaps.alpha, minCaps.depth, minCaps.stencil, minCaps.bpp16,
+                       &configAttribList);
+
+    const EGLint* configAttribs = configAttribList.Elements();
+
+    // We're guaranteed to get at least minCaps, and the sorting dictated by the spec for
+    // eglChooseConfig reasonably assures that a reasonable 'best' config is on top.
+    const EGLint kMaxConfigs = 1;
+    EGLConfig configs[kMaxConfigs];
     EGLint foundConfigs = 0;
-    if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
-                                   kEGLConfigAttribsOffscreenPBuffer,
-                                   configs, numConfigs,
-                                   &foundConfigs)
+    if (!egl->fChooseConfig(egl->Display(), configAttribs, configs, kMaxConfigs,
+                            &foundConfigs)
         || foundConfigs == 0)
     {
-        NS_WARNING("No EGL Config for minimal PBuffer!");
+        return EGL_NO_CONFIG;
+    }
+
+    EGLConfig config = configs[0];
+
+    *out_configCaps = minCaps; // Pick up any preserve, etc.
+    out_configCaps->color = true;
+    out_configCaps->alpha   = bool(GetAttrib(egl, config, LOCAL_EGL_ALPHA_SIZE));
+    out_configCaps->depth   = bool(GetAttrib(egl, config, LOCAL_EGL_DEPTH_SIZE));
+    out_configCaps->stencil = bool(GetAttrib(egl, config, LOCAL_EGL_STENCIL_SIZE));
+    out_configCaps->bpp16 = (GetAttrib(egl, config, LOCAL_EGL_RED_SIZE) < 8);
+
+    return config;
+}
+
+/*static*/ already_AddRefed<GLContextEGL>
+GLContextEGL::CreateEGLPBufferOffscreenContext(const mozilla::gfx::IntSize& size,
+                                               const SurfaceCaps& minCaps)
+{
+    SurfaceCaps configCaps;
+    EGLConfig config = ChooseConfig(&sEGLLibrary, minCaps, &configCaps);
+    if (config == EGL_NO_CONFIG) {
+        NS_WARNING("Failed to find a compatible config.");
         return nullptr;
     }
 
-    // We absolutely don't care, so just pick the first one.
-    config = configs[0];
     if (GLContext::ShouldSpew())
         sEGLLibrary.DumpEGLConfig(config);
 
     mozilla::gfx::IntSize pbSize(size);
-    surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
-                                                                 LOCAL_EGL_NONE,
-                                                                 pbSize);
+    EGLSurface surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
+                                                                            LOCAL_EGL_NONE,
+                                                                            pbSize);
     if (!surface) {
         NS_WARNING("Failed to create PBuffer for context!");
         return nullptr;
     }
 
-    SurfaceCaps dummyCaps = SurfaceCaps::Any();
-    nsRefPtr<GLContextEGL> glContext =
-        GLContextEGL::CreateGLContext(dummyCaps,
-                                      nullptr, true,
-                                      config, surface);
-    if (!glContext) {
+
+    RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(configCaps, nullptr, true,
+                                                            config, surface);
+    if (!gl) {
         NS_WARNING("Failed to create GLContext from PBuffer");
-        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
+        sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface);
         return nullptr;
     }
 
-    if (!glContext->Init()) {
+    if (!gl->Init()) {
         NS_WARNING("Failed to initialize GLContext!");
         // GLContextEGL::dtor will destroy |surface| for us.
         return nullptr;
     }
 
-    return glContext.forget();
+    return gl.forget();
 }
 
-already_AddRefed<GLContextEGL>
+/*static*/ already_AddRefed<GLContextEGL>
 GLContextEGL::CreateEGLPixmapOffscreenContext(const mozilla::gfx::IntSize& size)
 {
     gfxASurface *thebesSurface = nullptr;
     EGLNativePixmapType pixmap = 0;
 
     if (!pixmap) {
         return nullptr;
     }
@@ -927,59 +1011,87 @@ GLContextEGL::CreateEGLPixmapOffscreenCo
         return nullptr;
     }
 
     glContext->HoldSurface(thebesSurface);
 
     return glContext.forget();
 }
 
-already_AddRefed<GLContext>
+/*static*/ already_AddRefed<GLContext>
 GLContextProviderEGL::CreateHeadless(CreateContextFlags flags)
 {
-    if (!sEGLLibrary.EnsureInitialized(bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE))) {
+    bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
+    if (!sEGLLibrary.EnsureInitialized(forceEnableHardware))
         return nullptr;
-    }
 
     mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16);
-    nsRefPtr<GLContext> glContext;
-    glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize);
-    if (!glContext)
-        return nullptr;
-
-    return glContext.forget();
+    SurfaceCaps dummyCaps = SurfaceCaps::Any();
+    return GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize, dummyCaps);
 }
 
 // Under EGL, on Android, pbuffers are supported fine, though
 // often without the ability to texture from them directly.
-already_AddRefed<GLContext>
+/*static*/ already_AddRefed<GLContext>
 GLContextProviderEGL::CreateOffscreen(const mozilla::gfx::IntSize& size,
-                                      const SurfaceCaps& caps,
+                                      const SurfaceCaps& minCaps,
                                       CreateContextFlags flags)
 {
-    nsRefPtr<GLContext> glContext = CreateHeadless(flags);
-    if (!glContext)
+    bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
+    if (!sEGLLibrary.EnsureInitialized(forceEnableHardware))
         return nullptr;
 
-    if (!glContext->InitOffscreen(size, caps))
+    bool canOffscreenUseHeadless = true;
+    if (sEGLLibrary.IsANGLE()) {
+        // ANGLE needs to use PBuffers.
+        canOffscreenUseHeadless = false;
+    }
+
+    RefPtr<GLContext> gl;
+    SurfaceCaps offscreenCaps = minCaps;
+
+    if (canOffscreenUseHeadless) {
+        gl = CreateHeadless(flags);
+        if (!gl)
+            return nullptr;
+    } else {
+        SurfaceCaps minBackbufferCaps = minCaps;
+        if (minCaps.antialias) {
+            minBackbufferCaps.antialias = false;
+            minBackbufferCaps.depth = false;
+            minBackbufferCaps.stencil = false;
+        }
+
+        gl = GLContextEGL::CreateEGLPBufferOffscreenContext(size, minBackbufferCaps);
+        if (!gl)
+            return nullptr;
+
+        offscreenCaps = gl->Caps();
+        if (minCaps.antialias) {
+            offscreenCaps.depth = minCaps.depth;
+            offscreenCaps.stencil = minCaps.stencil;
+        }
+    }
+
+    if (!gl->InitOffscreen(size, offscreenCaps))
         return nullptr;
 
-    return glContext.forget();
+    return gl.forget();
 }
 
 // Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225)
 // and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257)
 // and 3) each EGL context eats 750k on B2G (bug 813783)
-GLContext*
+/*static*/ GLContext*
 GLContextProviderEGL::GetGlobalContext()
 {
     return nullptr;
 }
 
-void
+/*static*/ void
 GLContextProviderEGL::Shutdown()
 {
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
 
 #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -1125,159 +1125,167 @@ GLContextProviderGLX::CreateForWindow(ns
                                                                      display,
                                                                      window,
                                                                      cfgs[matchIndex],
                                                                      false);
 
     return glContext.forget();
 }
 
-static already_AddRefed<GLContextGLX>
-CreateOffscreenPixmapContext(const IntSize& size)
+static bool
+ChooseConfig(GLXLibrary* glx, Display* display, int screen, const SurfaceCaps& minCaps,
+             ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
+             GLXFBConfig* const out_config, int* const out_visid)
 {
-    GLXLibrary& glx = sGLXLibrary;
-    if (!glx.EnsureInitialized()) {
-        return nullptr;
-    }
+    ScopedXFree<GLXFBConfig>& scopedConfigArr = *out_scopedConfigArr;
 
-    Display *display = DefaultXDisplay();
-    int xscreen = DefaultScreen(display);
+    if (minCaps.antialias)
+        return false;
 
     int attribs[] = {
         LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT,
         LOCAL_GLX_X_RENDERABLE, True,
+        LOCAL_GLX_RED_SIZE, 8,
+        LOCAL_GLX_GREEN_SIZE, 8,
+        LOCAL_GLX_BLUE_SIZE, 8,
+        LOCAL_GLX_ALPHA_SIZE, minCaps.alpha ? 8 : 0,
+        LOCAL_GLX_DEPTH_SIZE, minCaps.depth ? 16 : 0,
+        LOCAL_GLX_STENCIL_SIZE, minCaps.stencil ? 8 : 0,
         0
     };
+
     int numConfigs = 0;
+    scopedConfigArr = glx->xChooseFBConfig(display, screen, attribs, &numConfigs);
+    if (!scopedConfigArr || !numConfigs)
+        return false;
 
-    ScopedXFree<GLXFBConfig> cfgs;
-    cfgs = glx.xChooseFBConfig(display,
-                               xscreen,
-                               attribs,
-                               &numConfigs);
-    if (!cfgs) {
-        return nullptr;
-    }
+    // Issues with glxChooseFBConfig selection and sorting:
+    // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't request
+    //   alpha bits, we'll probably get RGBA anyways, since 32 is more than 24.
+    // * DEPTH_SIZE is sorted largest first, including for `0` inputs.
+    // * STENCIL_SIZE is smallest first, but it might return `8` even though we ask for
+    //   `0`.
 
-    MOZ_ASSERT(numConfigs > 0,
-               "glXChooseFBConfig() failed to match our requested format and "
-               "violated its spec!");
-
-    int visid = None;
-    int chosenIndex = 0;
+    // For now, we don't care about these. We *will* care when we do XPixmap sharing.
 
     for (int i = 0; i < numConfigs; ++i) {
-        int dtype;
+        GLXFBConfig curConfig = scopedConfigArr[i];
 
-        if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_DRAWABLE_TYPE, &dtype) != Success
-            || !(dtype & LOCAL_GLX_PIXMAP_BIT))
-        {
-            continue;
-        }
-        if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid) != Success
-            || visid == 0)
+        int visid;
+        if (glx->xGetFBConfigAttrib(display, curConfig, LOCAL_GLX_VISUAL_ID, &visid)
+            != Success)
         {
             continue;
         }
 
-        chosenIndex = i;
-        break;
+        if (!visid)
+            continue;
+
+        *out_config = curConfig;
+        *out_visid = visid;
+        return true;
     }
 
-    if (!visid) {
-        NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!");
+    return false;
+}
+
+static already_AddRefed<GLContextGLX>
+CreateOffscreenPixmapContext(const IntSize& size, const SurfaceCaps& minCaps)
+{
+    GLXLibrary* glx = &sGLXLibrary;
+    if (!glx->EnsureInitialized())
+        return nullptr;
+
+    Display* display = DefaultXDisplay();
+    int screen = DefaultScreen(display);
+
+    ScopedXFree<GLXFBConfig> scopedConfigArr;
+    GLXFBConfig config;
+    int visid;
+    if (!ChooseConfig(glx, display, screen, minCaps, &scopedConfigArr, &config, &visid)) {
+        NS_WARNING("Failed to find a compatible config.");
         return nullptr;
     }
 
-    Visual *visual;
+    Visual* visual;
     int depth;
     FindVisualAndDepth(display, visid, &visual, &depth);
-    ScopedXErrorHandler xErrorHandler;
-    GLXPixmap glxpixmap = 0;
-    bool error = false;
 
-    IntSize dummySize(16, 16);
-    nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
-                                                               visual,
-                                                               dummySize);
-    if (xsurface->CairoStatus() != 0) {
+    ScopedXErrorHandler xErrorHandler;
+    bool error = false;
+    // Must be declared before goto:
+    Drawable drawable;
+    GLXPixmap pixmap;
+
+    gfx::IntSize dummySize(16, 16);
+    RefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
+                                                            visual,
+                                                            dummySize);
+    if (surface->CairoStatus() != 0) {
         error = true;
         goto DONE_CREATING_PIXMAP;
     }
 
     // Handle slightly different signature between glXCreatePixmap and
     // its pre-GLX-1.3 extension equivalent (though given the ABI, we
     // might not need to).
-    if (glx.GLXVersionCheck(1, 3)) {
-        glxpixmap = glx.xCreatePixmap(display,
-                                          cfgs[chosenIndex],
-                                          xsurface->XDrawable(),
-                                          nullptr);
+    drawable = surface->XDrawable();
+    if (glx->GLXVersionCheck(1, 3)) {
+        pixmap = glx->xCreatePixmap(display, config, drawable, nullptr);
     } else {
-        glxpixmap = glx.xCreateGLXPixmapWithConfig(display,
-                                                       cfgs[chosenIndex],
-                                                       xsurface->
-                                                       XDrawable());
+        pixmap = glx->xCreateGLXPixmapWithConfig(display, config, drawable);
     }
-    if (glxpixmap == 0) {
+
+    if (pixmap == 0) {
         error = true;
     }
 
 DONE_CREATING_PIXMAP:
 
-    nsRefPtr<GLContextGLX> glContext;
     bool serverError = xErrorHandler.SyncAndGetError(display);
-
-    if (!error && // earlier recorded error
-        !serverError)
-    {
-        // We might have an alpha channel, but it doesn't matter.
-        SurfaceCaps dummyCaps = SurfaceCaps::Any();
-        GLContextGLX* shareContext = GetGlobalContextGLX();
+    if (error || serverError)
+        return nullptr;
 
-        glContext = GLContextGLX::CreateGLContext(dummyCaps,
-                                                  shareContext,
-                                                  true,
-                                                  display,
-                                                  glxpixmap,
-                                                  cfgs[chosenIndex],
-                                                  true,
-                                                  xsurface);
-    }
-
-    return glContext.forget();
+    GLContextGLX* shareContext = GetGlobalContextGLX();
+    return GLContextGLX::CreateGLContext(minCaps, shareContext, true, display, pixmap,
+                                         config, true, surface);
 }
 
-already_AddRefed<GLContext>
+/*static*/ already_AddRefed<GLContext>
 GLContextProviderGLX::CreateHeadless(CreateContextFlags)
 {
     IntSize dummySize = IntSize(16, 16);
-    nsRefPtr<GLContext> glContext = CreateOffscreenPixmapContext(dummySize);
-    if (!glContext)
-        return nullptr;
-
-    return glContext.forget();
+    SurfaceCaps dummyCaps = SurfaceCaps::Any();
+    return CreateOffscreenPixmapContext(dummySize, dummyCaps);
 }
 
-already_AddRefed<GLContext>
+/*static*/ already_AddRefed<GLContext>
 GLContextProviderGLX::CreateOffscreen(const IntSize& size,
-                                      const SurfaceCaps& caps,
+                                      const SurfaceCaps& minCaps,
                                       CreateContextFlags flags)
 {
-    nsRefPtr<GLContext> glContext = CreateHeadless(flags);
-    if (!glContext)
+    SurfaceCaps minBackbufferCaps = minCaps;
+    if (minCaps.antialias) {
+        minBackbufferCaps.antialias = false;
+        minBackbufferCaps.depth = false;
+        minBackbufferCaps.stencil = false;
+    }
+
+    RefPtr<GLContext> gl;
+    gl = CreateOffscreenPixmapContext(size, minBackbufferCaps);
+    if (!gl)
         return nullptr;
 
-    if (!glContext->InitOffscreen(size, caps))
+    if (!gl->InitOffscreen(size, minCaps))
         return nullptr;
 
-    return glContext.forget();
+    return gl.forget();
 }
 
-GLContext*
+/*static*/ GLContext*
 GLContextProviderGLX::GetGlobalContext()
 {
     static bool checkedContextSharing = false;
     static bool useContextSharing = false;
 
     if (!checkedContextSharing) {
         useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
         checkedContextSharing = true;
@@ -1288,27 +1296,29 @@ GLContextProviderGLX::GetGlobalContext()
         return nullptr;
     }
 
     static bool triedToCreateContext = false;
     if (!triedToCreateContext && !gGlobalContext) {
         triedToCreateContext = true;
 
         IntSize dummySize = IntSize(16, 16);
+        SurfaceCaps dummyCaps = SurfaceCaps::Any();
         // StaticPtr doesn't support assignments from already_AddRefed,
         // so use a temporary nsRefPtr to make the reference counting
         // fall out correctly.
-        nsRefPtr<GLContext> holder = CreateOffscreenPixmapContext(dummySize);
+        RefPtr<GLContext> holder;
+        holder = CreateOffscreenPixmapContext(dummySize, dummyCaps);
         gGlobalContext = holder;
     }
 
     return gGlobalContext;
 }
 
-void
+/*static*/ void
 GLContextProviderGLX::Shutdown()
 {
     gGlobalContext = nullptr;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
 
--- a/gfx/gl/GLContextProviderImpl.h
+++ b/gfx/gl/GLContextProviderImpl.h
@@ -49,26 +49,28 @@ public:
      *
      * The offscreen context returned by this method will always have
      * the ability to be rendered into a context created by a window.
      * It might or might not share resources with the global context;
      * query GetSharedContext() for a non-null result to check.  If
      * resource sharing can be avoided on the target platform, it will
      * be, in order to isolate the offscreen context.
      *
-     * @param size The initial size of this offscreen context.
-     * @param caps The SurfaceCaps for this offscreen context.
-     * @param flags The set of CreateContextFlags to be used for this
-     *              offscreen context.
+     * @param size    The initial size of this offscreen context.
+     * @param minCaps The required SurfaceCaps for this offscreen context. The resulting
+     *                context *may* have more/better caps than requested, but it cannot
+     *                have fewer/worse caps than requested.
+     * @param flags   The set of CreateContextFlags to be used for this
+     *                offscreen context.
      *
      * @return Context to use for offscreen rendering
      */
     static already_AddRefed<GLContext>
     CreateOffscreen(const mozilla::gfx::IntSize& size,
-                    const SurfaceCaps& caps,
+                    const SurfaceCaps& minCaps,
                     CreateContextFlags flags);
 
     // Just create a context. We'll add offscreen stuff ourselves.
     static already_AddRefed<GLContext>
     CreateHeadless(CreateContextFlags flags);
 
     /**
      * Create wrapping Gecko GLContext for external gl context.
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -601,17 +601,17 @@ CreateWindowOffscreenContext()
     SurfaceCaps caps = SurfaceCaps::ForRGBA();
     nsRefPtr<GLContextWGL> glContext = new GLContextWGL(caps,
                                                         shareContext, true,
                                                         dc, context, win);
 
     return glContext.forget();
 }
 
-already_AddRefed<GLContext>
+/*static*/ already_AddRefed<GLContext>
 GLContextProviderWGL::CreateHeadless(CreateContextFlags)
 {
     if (!sWGLLib.EnsureInitialized()) {
         return nullptr;
     }
 
     nsRefPtr<GLContextWGL> glContext;
 
@@ -634,34 +634,34 @@ GLContextProviderWGL::CreateHeadless(Cre
     {
         return nullptr;
     }
 
     nsRefPtr<GLContext> retGL = glContext.get();
     return retGL.forget();
 }
 
-already_AddRefed<GLContext>
+/*static*/ already_AddRefed<GLContext>
 GLContextProviderWGL::CreateOffscreen(const IntSize& size,
-                                      const SurfaceCaps& caps,
+                                      const SurfaceCaps& minCaps,
                                       CreateContextFlags flags)
 {
-    nsRefPtr<GLContext> glContext = CreateHeadless(flags);
-    if (!glContext)
+    RefPtr<GLContext> gl = CreateHeadless(flags);
+    if (!gl)
         return nullptr;
 
-    if (!glContext->InitOffscreen(size, caps))
+    if (!gl->InitOffscreen(size, minCaps))
         return nullptr;
 
-    return glContext.forget();
+    return gl.forget();
 }
 
 static nsRefPtr<GLContextWGL> gGlobalContext;
 
-GLContext *
+/*static*/ GLContext*
 GLContextProviderWGL::GetGlobalContext()
 {
     if (!sWGLLib.EnsureInitialized()) {
         return nullptr;
     }
 
     static bool triedToCreateContext = false;
 
@@ -679,16 +679,16 @@ GLContextProviderWGL::GetGlobalContext()
             gGlobalContext = nullptr;
             return nullptr;
         }
     }
 
     return static_cast<GLContext*>(gGlobalContext);
 }
 
-void
+/*static*/ void
 GLContextProviderWGL::Shutdown()
 {
     gGlobalContext = nullptr;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/gl/GLContextTypes.h
+++ b/gfx/gl/GLContextTypes.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GLCONTEXT_TYPES_H_
 #define GLCONTEXT_TYPES_H_
 
 #include "GLTypes.h"
+#include "mozilla/TypedEnumBits.h"
 
 namespace mozilla {
 namespace gl {
 
 class GLContext;
 
 enum class GLContextType {
     Unknown,
@@ -38,12 +39,22 @@ struct GLFormats
 
     GLenum depthStencil;
     GLenum depth;
     GLenum stencil;
 
     GLsizei samples;
 };
 
+enum class CreateContextFlags : int8_t {
+    NONE = 0,
+    REQUIRE_COMPAT_PROFILE = 1 << 0,
+    // Force the use of hardware backed GL, don't allow software implementations.
+    FORCE_ENABLE_HARDWARE = 1 << 1,
+    /* Don't force discrete GPU to be used (if applicable) */
+    ALLOW_OFFLINE_RENDERER =  1 << 2,
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags)
+
 } /* namespace gl */
 } /* namespace mozilla */
 
 #endif /* GLCONTEXT_TYPES_H_ */
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -481,19 +481,26 @@ GLScreenBuffer::Swap(const gfx::IntSize&
         !mDraw)
     {
         auto src  = mFront->Surf();
         auto dest = mBack->Surf();
 
         //uint32_t srcPixel = ReadPixel(src);
         //uint32_t destPixel = ReadPixel(dest);
         //printf_stderr("Before: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel);
+#ifdef DEBUG
+        GLContext::LocalErrorScope errorScope(*mGL);
+#endif
 
         SharedSurface::ProdCopy(src, dest, mFactory.get());
 
+#ifdef DEBUG
+        MOZ_ASSERT(!errorScope.GetError());
+#endif
+
         //srcPixel = ReadPixel(src);
         //destPixel = ReadPixel(dest);
         //printf_stderr("After: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel);
     }
 
     // XXX: We would prefer to fence earlier on platforms that don't need
     // the full ProducerAcquire/ProducerRelease semantics, so that the fence
     // doesn't include the copy operation. Unfortunately, the current API
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -36,27 +36,24 @@ CreatePBufferSurface(GLLibraryEGL* egl,
     EGLint err = egl->fGetError();
     if (err != LOCAL_EGL_SUCCESS)
         return 0;
 
     return surface;
 }
 
 /*static*/ UniquePtr<SharedSurface_ANGLEShareHandle>
-SharedSurface_ANGLEShareHandle::Create(GLContext* gl,
-                                       EGLContext context, EGLConfig config,
+SharedSurface_ANGLEShareHandle::Create(GLContext* gl, EGLConfig config,
                                        const gfx::IntSize& size, bool hasAlpha)
 {
     GLLibraryEGL* egl = &sEGLLibrary;
     MOZ_ASSERT(egl);
     MOZ_ASSERT(egl->IsExtensionSupported(
                GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle));
-
-    if (!context || !config)
-        return nullptr;
+    MOZ_ASSERT(config);
 
     EGLDisplay display = egl->Display();
     EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size);
     if (!pbuffer)
         return nullptr;
 
     // Declare everything before 'goto's.
     HANDLE shareHandle = nullptr;
@@ -77,44 +74,42 @@ SharedSurface_ANGLEShareHandle::Create(G
 
     GLuint fence = 0;
     if (gl->IsExtensionSupported(GLContext::NV_fence)) {
         gl->MakeCurrent();
         gl->fGenFences(1, &fence);
     }
 
     typedef SharedSurface_ANGLEShareHandle ptrT;
-    UniquePtr<ptrT> ret( new ptrT(gl, egl, size, hasAlpha, context,
-                                  pbuffer, shareHandle, keyedMutex, fence) );
+    UniquePtr<ptrT> ret( new ptrT(gl, egl, size, hasAlpha, pbuffer, shareHandle,
+                                  keyedMutex, fence) );
     return Move(ret);
 }
 
 EGLDisplay
 SharedSurface_ANGLEShareHandle::Display()
 {
     return mEGL->Display();
 }
 
 SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(GLContext* gl,
                                                                GLLibraryEGL* egl,
                                                                const gfx::IntSize& size,
                                                                bool hasAlpha,
-                                                               EGLContext context,
                                                                EGLSurface pbuffer,
                                                                HANDLE shareHandle,
                                                                const RefPtr<IDXGIKeyedMutex>& keyedMutex,
                                                                GLuint fence)
     : SharedSurface(SharedSurfaceType::EGLSurfaceANGLE,
                     AttachmentType::Screen,
                     gl,
                     size,
                     hasAlpha,
                     true)
     , mEGL(egl)
-    , mContext(context)
     , mPBuffer(pbuffer)
     , mShareHandle(shareHandle)
     , mKeyedMutex(keyedMutex)
     , mFence(fence)
 {
 }
 
 
@@ -276,186 +271,42 @@ SharedSurface_ANGLEShareHandle::ToSurfac
     *out_descriptor = layers::SurfaceDescriptorD3D10((WindowsHandle)mShareHandle, format,
                                                      mSize);
     return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Factory
 
-static void
-FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs,
-                          int redBits, int greenBits,
-                          int blueBits, int alphaBits,
-                          int depthBits, int stencilBits)
-{
-    aAttrs.Clear();
-
-#if defined(A1) || defined(A2)
-#error The temp-macro names we want are already defined.
-#endif
-
-#define A1(_x)      do { aAttrs.AppendElement(_x); } while (0)
-#define A2(_x,_y)   do { A1(_x); A1(_y); } while (0)
-
-    A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT);
-    A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT);
-
-    A2(LOCAL_EGL_RED_SIZE, redBits);
-    A2(LOCAL_EGL_GREEN_SIZE, greenBits);
-    A2(LOCAL_EGL_BLUE_SIZE, blueBits);
-    A2(LOCAL_EGL_ALPHA_SIZE, alphaBits);
-
-    A2(LOCAL_EGL_DEPTH_SIZE, depthBits);
-    A2(LOCAL_EGL_STENCIL_SIZE, stencilBits);
-
-    A1(LOCAL_EGL_NONE);
-#undef A1
-#undef A2
-}
-
-static void
-FillPBufferAttribs_BySizes(nsTArray<EGLint>& attribs,
-                           bool bpp16, bool hasAlpha,
-                           int depthBits, int stencilBits)
-{
-    int red = 0;
-    int green = 0;
-    int blue = 0;
-    int alpha = 0;
-
-    if (bpp16) {
-        if (hasAlpha) {
-            red = green = blue = alpha = 4;
-        } else {
-            red = 5;
-            green = 6;
-            blue = 5;
-        }
-    } else {
-        red = green = blue = 8;
-        if (hasAlpha)
-            alpha = 8;
-    }
-
-    FillPBufferAttribs_ByBits(attribs, red, green, blue, alpha, depthBits,
-                              stencilBits);
-}
-
-static bool
-DoesAttribBitsMatchCapBool(GLLibraryEGL* egl, EGLConfig config, EGLint attrib,
-                           bool capBool)
-{
-    EGLint bits = 0;
-    egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits);
-    MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
-
-    bool hasBits = !!bits;
-
-    return hasBits == capBool;
-}
-
-static EGLConfig
-ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps)
-{
-    MOZ_ASSERT(egl);
-    MOZ_ASSERT(caps.color);
-
-    // We might want 24-bit depth, but we're only (fairly) sure to get 16-bit.
-    int depthBits = caps.depth ? 16 : 0;
-    int stencilBits = caps.stencil ? 8 : 0;
-
-    // Ok, now we have everything.
-    nsTArray<EGLint> attribs(32);
-    FillPBufferAttribs_BySizes(attribs, caps.bpp16, caps.alpha, depthBits,
-                               stencilBits);
-
-    // Time to try to get this config:
-    EGLConfig configs[64];
-    int numConfigs = sizeof(configs)/sizeof(EGLConfig);
-    int foundConfigs = 0;
-
-    if (!egl->fChooseConfig(egl->Display(), attribs.Elements(), configs,
-                            numConfigs, &foundConfigs) ||
-        !foundConfigs)
-    {
-        NS_WARNING("No configs found for the requested formats.");
-        return EGL_NO_CONFIG;
-    }
-
-    // The requests passed to ChooseConfig are treated as minimums. If you ask
-    // for 0 bits of alpha, we might still get 8 bits.
-    EGLConfig config = EGL_NO_CONFIG;
-    for (int i = 0; i < foundConfigs; i++) {
-        EGLConfig cur = configs[i];
-        if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
-                                        caps.alpha) ||
-            !DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
-                                        caps.depth) ||
-            !DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE,
-                                        caps.stencil))
-        {
-            continue;
-        }
-
-        config = cur;
-        break;
-    }
-
-    if (config == EGL_NO_CONFIG) {
-        NS_WARNING("No acceptable EGLConfig found.");
-        return EGL_NO_CONFIG;
-    }
-
-    if (gl->DebugMode()) {
-        egl->DumpEGLConfig(config);
-    }
-
-    return config;
-}
-
 /*static*/ UniquePtr<SurfaceFactory_ANGLEShareHandle>
 SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, const SurfaceCaps& caps,
                                         const RefPtr<layers::ISurfaceAllocator>& allocator,
                                         const layers::TextureFlags& flags)
 {
     GLLibraryEGL* egl = &sEGLLibrary;
     if (!egl)
         return nullptr;
 
     auto ext = GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle;
     if (!egl->IsExtensionSupported(ext))
         return nullptr;
 
-    bool success;
-    typedef SurfaceFactory_ANGLEShareHandle ptrT;
-    UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, egl, &success) );
+    EGLConfig config = GLContextEGL::Cast(gl)->mConfig;
 
-    if (!success)
-        return nullptr;
-
+    typedef SurfaceFactory_ANGLEShareHandle ptrT;
+    UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, egl, config) );
     return Move(ret);
 }
 
 SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl,
                                                                  const SurfaceCaps& caps,
                                                                  const RefPtr<layers::ISurfaceAllocator>& allocator,
                                                                  const layers::TextureFlags& flags,
                                                                  GLLibraryEGL* egl,
-                                                                 bool* const out_success)
+                                                                 EGLConfig config)
     : SurfaceFactory(SharedSurfaceType::EGLSurfaceANGLE, gl, caps, allocator, flags)
     , mProdGL(gl)
     , mEGL(egl)
-{
-    MOZ_ASSERT(out_success);
-    *out_success = false;
-
-    mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext();
-    mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps);
-    if (mConfig == EGL_NO_CONFIG)
-        return;
-
-    MOZ_ASSERT(mConfig && mContext);
-    *out_success = true;
-}
+    , mConfig(config)
+{ }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/gl/SharedSurfaceANGLE.h
+++ b/gfx/gl/SharedSurfaceANGLE.h
@@ -18,45 +18,42 @@ namespace gl {
 class GLContext;
 class GLLibraryEGL;
 
 class SharedSurface_ANGLEShareHandle
     : public SharedSurface
 {
 public:
     static UniquePtr<SharedSurface_ANGLEShareHandle> Create(GLContext* gl,
-                                                            EGLContext context,
                                                             EGLConfig config,
                                                             const gfx::IntSize& size,
                                                             bool hasAlpha);
 
     static SharedSurface_ANGLEShareHandle* Cast(SharedSurface* surf) {
         MOZ_ASSERT(surf->mType == SharedSurfaceType::EGLSurfaceANGLE);
 
         return (SharedSurface_ANGLEShareHandle*)surf;
     }
 
 protected:
     GLLibraryEGL* const mEGL;
-    const EGLContext mContext;
     const EGLSurface mPBuffer;
 public:
     const HANDLE mShareHandle;
 protected:
     RefPtr<IDXGIKeyedMutex> mKeyedMutex;
     RefPtr<IDXGIKeyedMutex> mConsumerKeyedMutex;
     RefPtr<ID3D11Texture2D> mConsumerTexture;
 
     const GLuint mFence;
 
     SharedSurface_ANGLEShareHandle(GLContext* gl,
                                    GLLibraryEGL* egl,
                                    const gfx::IntSize& size,
                                    bool hasAlpha,
-                                   EGLContext context,
                                    EGLSurface pbuffer,
                                    HANDLE shareHandle,
                                    const RefPtr<IDXGIKeyedMutex>& keyedMutex,
                                    GLuint fence);
 
     EGLDisplay Display();
 
 public:
@@ -89,35 +86,32 @@ public:
 
 
 class SurfaceFactory_ANGLEShareHandle
     : public SurfaceFactory
 {
 protected:
     GLContext* const mProdGL;
     GLLibraryEGL* const mEGL;
-    EGLContext mContext;
-    EGLConfig mConfig;
+    const EGLConfig mConfig;
 
 public:
     static UniquePtr<SurfaceFactory_ANGLEShareHandle> Create(GLContext* gl,
                                                              const SurfaceCaps& caps,
                                                              const RefPtr<layers::ISurfaceAllocator>& allocator,
                                                              const layers::TextureFlags& flags);
 
 protected:
     SurfaceFactory_ANGLEShareHandle(GLContext* gl, const SurfaceCaps& caps,
                                     const RefPtr<layers::ISurfaceAllocator>& allocator,
                                     const layers::TextureFlags& flags, GLLibraryEGL* egl,
-                                    bool* const out_success);
+                                    EGLConfig config);
 
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
         bool hasAlpha = mReadCaps.alpha;
-        return SharedSurface_ANGLEShareHandle::Create(mProdGL,
-                                                      mContext, mConfig,
-                                                      size, hasAlpha);
+        return SharedSurface_ANGLEShareHandle::Create(mProdGL, mConfig, size, hasAlpha);
     }
 };
 
 } /* namespace gfx */
 } /* namespace mozilla */
 
 #endif /* SHARED_SURFACE_ANGLE_H_ */
--- a/gfx/gl/SharedSurfaceEGL.cpp
+++ b/gfx/gl/SharedSurfaceEGL.cpp
@@ -215,17 +215,17 @@ SharedSurface_EGLImage::ToSurfaceDescrip
 
 ////////////////////////////////////////////////////////////////////////
 
 /*static*/ UniquePtr<SurfaceFactory_EGLImage>
 SurfaceFactory_EGLImage::Create(GLContext* prodGL, const SurfaceCaps& caps,
                                 const RefPtr<layers::ISurfaceAllocator>& allocator,
                                 const layers::TextureFlags& flags)
 {
-    EGLContext context = GLContextEGL::Cast(prodGL)->GetEGLContext();
+    EGLContext context = GLContextEGL::Cast(prodGL)->mContext;
 
     typedef SurfaceFactory_EGLImage ptrT;
     UniquePtr<ptrT> ret;
 
     GLLibraryEGL* egl = &sEGLLibrary;
     if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) {
         ret.reset( new ptrT(prodGL, caps, allocator, flags, context) );
     }
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -66,17 +66,17 @@ if CONFIG['MOZ_X11']:
 # Win32 is a special snowflake, for ANGLE
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXPORTS += [
         'GLContextWGL.h',
         'SharedSurfaceANGLE.h', # Needs <windows.h> for `HANDLE`.
         'WGLLibrary.h',
     ]
     UNIFIED_SOURCES += [
-        'GLContextProviderEGL.cpp',
+        'GLContextProviderWGL.cpp',
         'SharedSurfaceANGLE.cpp',
     ]
 if CONFIG['MOZ_ENABLE_SKIA_GPU']:
     EXPORTS += ['SkiaGLGlue.h']
     UNIFIED_SOURCES += [
         'SkiaGLGlue.cpp',
     ]
 
@@ -108,30 +108,27 @@ elif gl_provider == 'GLX':
     # as it includes X11 headers which cause conflicts.
     SOURCES += [
         'GLContextProviderGLX.cpp',
         'SharedSurfaceGLX.cpp'
     ]
     EXPORTS += [
         'SharedSurfaceGLX.h'
     ]
-else:
-    UNIFIED_SOURCES += [
-        'GLContextProvider%s.cpp' % gl_provider,
-    ]
 
 UNIFIED_SOURCES += [
     'AndroidNativeWindow.cpp',
     'AndroidSurfaceTexture.cpp',
     'DecomposeIntoNoRepeatTriangles.cpp',
     'EGLUtils.cpp',
     'GfxTexturesReporter.cpp',
     'GLBlitHelper.cpp',
     'GLContext.cpp',
     'GLContextFeatures.cpp',
+    'GLContextProviderEGL.cpp',
     'GLContextTypes.cpp',
     'GLDebugUtils.cpp',
     'GLLibraryEGL.cpp',
     'GLLibraryLoader.cpp',
     'GLReadTexImageHelper.cpp',
     'GLScreenBuffer.cpp',
     'GLTextureImage.cpp',
     'GLUploadHelpers.cpp',