Bug 942492 - Move ScopedGL* RAII helpers out of GLContext.* - r=bjacob
authorDan Glastonbury <dglastonbury@mozilla.com>
Tue, 26 Nov 2013 13:25:25 +1000
changeset 162451 129bf6f1933cb4fa535b1dfd106cd731f9cf1e99
parent 162450 1b0fc4fd9a75dafdbae4344ca847a24abbb6a01a
child 162452 e6484a878eeed6df777567c9767e1dd7b8f59231
push idunknown
push userunknown
push dateunknown
reviewersbjacob
bugs942492
milestone28.0a1
Bug 942492 - Move ScopedGL* RAII helpers out of GLContext.* - r=bjacob
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLRenderbuffer.cpp
content/canvas/src/WebGLTexture.cpp
gfx/gl/GLBlitHelper.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/ScopedGLHelpers.cpp
gfx/gl/ScopedGLHelpers.h
gfx/gl/SharedSurfaceEGL.cpp
gfx/gl/SharedSurfaceGL.cpp
gfx/gl/SharedSurfaceIO.cpp
gfx/gl/moz.build
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -33,16 +33,17 @@
 #include "gfxPattern.h"
 #include "gfxUtils.h"
 
 #include "CanvasUtils.h"
 #include "nsDisplayList.h"
 
 #include "GLContextProvider.h"
 #include "GLContext.h"
+#include "ScopedGLHelpers.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #include "nsSVGEffects.h"
 
 #include "prenv.h"
 
 #include "mozilla/Preferences.h"
--- a/content/canvas/src/WebGLRenderbuffer.cpp
+++ b/content/canvas/src/WebGLRenderbuffer.cpp
@@ -3,26 +3,27 @@
  * 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/. */
 
 #include "WebGLContext.h"
 #include "WebGLRenderbuffer.h"
 #include "WebGLTexture.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "GLContext.h"
+#include "ScopedGLHelpers.h"
 
 using namespace mozilla;
 using namespace mozilla::gl;
 
 static GLenum
 DepthStencilDepthFormat(GLContext* gl) {
     // We might not be able to get 24-bit, so let's pretend!
     if (gl->IsGLES2() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
         return LOCAL_GL_DEPTH_COMPONENT16;
-    
+
     return LOCAL_GL_DEPTH_COMPONENT24;
 }
 
 static bool
 SupportsDepthStencil(GLContext* gl) {
     return gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil) ||
            gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil);
 }
@@ -122,17 +123,17 @@ WebGLRenderbuffer::MemoryUsage() const {
 
 void
 WebGLRenderbuffer::BindRenderbuffer() const {
     /* Do this explicitly here, since the meaning changes for depth-stencil emu.
      * Under normal circumstances, there's only one RB: `mPrimaryRB`.
      * `mSecondaryRB` is used when we have to pretend that the renderbuffer is
      * DEPTH_STENCIL, when it's actually one DEPTH buffer `mPrimaryRB` and one
      * STENCIL buffer `mSecondaryRB`.
-     * 
+     *
      * In the DEPTH_STENCIL emulation case, we're actually juggling two RBs, but
      * we can only bind one of them at a time. We choose to unconditionally bind
      * the depth RB. When we need to ask about the stencil buffer (say, how many
      * stencil bits we have), we temporarily bind the stencil RB, so that it
      * looks like we're just asking the question of a combined DEPTH_STENCIL
      * buffer.
      */
     mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
@@ -146,17 +147,17 @@ WebGLRenderbuffer::RenderbufferStorage(G
     GLenum secondaryFormat = 0;
 
     if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
         primaryFormat = DepthStencilDepthFormat(gl);
         secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
     }
 
     gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, primaryFormat, width, height);
-    
+
     if (!mSecondaryRB) {
         MOZ_ASSERT(!secondaryFormat);
         return;
     }
     // We can't leave the secondary RB unspecified either, since we should
     // handle the case where we attach a non-depth-stencil RB to a
     // depth-stencil attachment point, or attach this depth-stencil RB to a
     // non-depth-stencil attachment point.
--- a/content/canvas/src/WebGLTexture.cpp
+++ b/content/canvas/src/WebGLTexture.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "WebGLContext.h"
 #include "WebGLTexture.h"
 #include "GLContext.h"
+#include "ScopedGLHelpers.h"
 #include "WebGLTexelConversions.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include <algorithm>
 
 using namespace mozilla;
 
 JSObject*
 WebGLTexture::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) {
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "GLBlitHelper.h"
 #include "GLContext.h"
+#include "ScopedGLHelpers.h"
 #include "mozilla/Preferences.h"
 
 namespace mozilla {
 namespace gl {
 
 GLBlitHelper::GLBlitHelper(GLContext* gl)
     : mGL(gl)
     , mTexBlit_Buffer(0)
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -17,16 +17,17 @@
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "GLContextProvider.h"
 #include "GLTextureImage.h"
 #include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
 #include "prenv.h"
 #include "prlink.h"
+#include "ScopedGLHelpers.h"
 #include "SurfaceStream.h"
 #include "GfxTexturesReporter.h"
 #include "TextureGarbageBin.h"
 #include "gfx2DGlue.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2800,17 +2800,17 @@ public:
                                            const nsIntRegion& aDstRegion,
                                            GLuint& aTexture,
                                            bool aOverwrite = false,
                                            bool aPixelBuffer = false,
                                            GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
                                            GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
 
     /**
-     * Convenience wrapper around UploadImageDataToTexture for gfxASurfaces. 
+     * Convenience wrapper around UploadImageDataToTexture for gfxASurfaces.
      */
     SurfaceFormat UploadSurfaceToTexture(gfxASurface *aSurface,
                                          const nsIntRegion& aDstRegion,
                                          GLuint& aTexture,
                                          bool aOverwrite = false,
                                          const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
                                          bool aPixelBuffer = false,
                                          GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
@@ -3296,357 +3296,13 @@ public:
     nsTArray<NamedResource> mTrackedRenderbuffers;
     nsTArray<NamedResource> mTrackedBuffers;
     nsTArray<NamedResource> mTrackedQueries;
 #endif
 };
 
 bool DoesStringMatch(const char* aString, const char *aWantedString);
 
-//RAII via CRTP!
-template <class Derived>
-struct ScopedGLWrapper
-{
-private:
-    bool mIsUnwrapped;
-
-protected:
-    GLContext* const mGL;
-
-    ScopedGLWrapper(GLContext* gl)
-        : mIsUnwrapped(false)
-        , mGL(gl)
-    {
-        MOZ_ASSERT(&ScopedGLWrapper<Derived>::Unwrap == &Derived::Unwrap);
-        MOZ_ASSERT(&Derived::UnwrapImpl);
-        MOZ_ASSERT(mGL->IsCurrent());
-    }
-
-    virtual ~ScopedGLWrapper() {
-        if (!mIsUnwrapped)
-            Unwrap();
-    }
-
-public:
-    void Unwrap() {
-        MOZ_ASSERT(!mIsUnwrapped);
-
-        Derived* derived = static_cast<Derived*>(this);
-        derived->UnwrapImpl();
-
-        mIsUnwrapped = true;
-    }
-};
-
-// Wraps glEnable/Disable.
-struct ScopedGLState
-    : public ScopedGLWrapper<ScopedGLState>
-{
-    friend struct ScopedGLWrapper<ScopedGLState>;
-
-protected:
-    const GLenum mCapability;
-    bool mOldState;
-
-public:
-    // Use |newState = true| to enable, |false| to disable.
-    ScopedGLState(GLContext* gl, GLenum capability, bool newState)
-        : ScopedGLWrapper<ScopedGLState>(gl)
-        , mCapability(capability)
-    {
-        mOldState = mGL->fIsEnabled(mCapability);
-
-        // Early out if we're already in the right state.
-        if (newState == mOldState)
-            return;
-
-        if (newState)
-            mGL->fEnable(mCapability);
-        else
-            mGL->fDisable(mCapability);
-    }
-
-protected:
-    void UnwrapImpl() {
-        if (mOldState)
-            mGL->fEnable(mCapability);
-        else
-            mGL->fDisable(mCapability);
-    }
-};
-
-// Saves and restores with GetUserBoundFB and BindUserFB.
-struct ScopedBindFramebuffer
-    : public ScopedGLWrapper<ScopedBindFramebuffer>
-{
-    friend struct ScopedGLWrapper<ScopedBindFramebuffer>;
-
-protected:
-    GLuint mOldFB;
-
-private:
-    void Init() {
-        mOldFB = mGL->GetFB();
-    }
-
-public:
-    explicit ScopedBindFramebuffer(GLContext* gl)
-        : ScopedGLWrapper<ScopedBindFramebuffer>(gl)
-    {
-        Init();
-    }
-
-    ScopedBindFramebuffer(GLContext* gl, GLuint newFB)
-        : ScopedGLWrapper<ScopedBindFramebuffer>(gl)
-    {
-        Init();
-        mGL->BindFB(newFB);
-    }
-
-protected:
-    void UnwrapImpl() {
-        // Check that we're not falling out of scope after
-        // the current context changed.
-        MOZ_ASSERT(mGL->IsCurrent());
-
-        mGL->BindFB(mOldFB);
-    }
-};
-
-struct ScopedBindTextureUnit
-    : public ScopedGLWrapper<ScopedBindTextureUnit>
-{
-    friend struct ScopedGLWrapper<ScopedBindTextureUnit>;
-
-protected:
-    GLenum mOldTexUnit;
-
-public:
-    ScopedBindTextureUnit(GLContext* gl, GLenum texUnit)
-        : ScopedGLWrapper<ScopedBindTextureUnit>(gl)
-    {
-        MOZ_ASSERT(texUnit >= LOCAL_GL_TEXTURE0);
-        mGL->GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &mOldTexUnit);
-        mGL->fActiveTexture(texUnit);
-    }
-
-protected:
-    void UnwrapImpl() {
-        // Check that we're not falling out of scope after
-        // the current context changed.
-        MOZ_ASSERT(mGL->IsCurrent());
-
-        mGL->fActiveTexture(mOldTexUnit);
-    }
-};
-
-struct ScopedTexture
-    : public ScopedGLWrapper<ScopedTexture>
-{
-    friend struct ScopedGLWrapper<ScopedTexture>;
-
-protected:
-    GLuint mTexture;
-
-public:
-    ScopedTexture(GLContext* gl)
-        : ScopedGLWrapper<ScopedTexture>(gl)
-    {
-        mGL->fGenTextures(1, &mTexture);
-    }
-
-    GLuint Texture() { return mTexture; }
-
-protected:
-    void UnwrapImpl() {
-        // Check that we're not falling out of scope after
-        // the current context changed.
-        MOZ_ASSERT(mGL->IsCurrent());
-
-        mGL->fDeleteTextures(1, &mTexture);
-    }
-};
-
-struct ScopedBindTexture
-    : public ScopedGLWrapper<ScopedBindTexture>
-{
-    friend struct ScopedGLWrapper<ScopedBindTexture>;
-
-protected:
-    GLuint mOldTex;
-    GLenum mTarget;
-
-private:
-    void Init(GLenum target) {
-        mTarget = target;
-        mOldTex = 0;
-        GLenum bindingTarget = (target == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_BINDING_2D
-                             : (target == LOCAL_GL_TEXTURE_RECTANGLE_ARB) ? LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB
-                             : (target == LOCAL_GL_TEXTURE_CUBE_MAP) ? LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
-                             : LOCAL_GL_NONE;
-        MOZ_ASSERT(bindingTarget != LOCAL_GL_NONE);
-        mGL->GetUIntegerv(bindingTarget, &mOldTex);
-    }
-
-public:
-    ScopedBindTexture(GLContext* gl, GLuint newTex, GLenum target = LOCAL_GL_TEXTURE_2D)
-        : ScopedGLWrapper<ScopedBindTexture>(gl)
-    {
-        Init(target);
-        mGL->fBindTexture(target, newTex);
-    }
-
-protected:
-    void UnwrapImpl() {
-        // Check that we're not falling out of scope after
-        // the current context changed.
-        MOZ_ASSERT(mGL->IsCurrent());
-
-        mGL->fBindTexture(mTarget, mOldTex);
-    }
-};
-
-
-struct ScopedBindRenderbuffer
-    : public ScopedGLWrapper<ScopedBindRenderbuffer>
-{
-    friend struct ScopedGLWrapper<ScopedBindRenderbuffer>;
-
-protected:
-    GLuint mOldRB;
-
-private:
-    void Init() {
-        mOldRB = 0;
-        mGL->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &mOldRB);
-    }
-
-public:
-    explicit ScopedBindRenderbuffer(GLContext* gl)
-        : ScopedGLWrapper<ScopedBindRenderbuffer>(gl)
-    {
-        Init();
-    }
-
-    ScopedBindRenderbuffer(GLContext* gl, GLuint newRB)
-        : ScopedGLWrapper<ScopedBindRenderbuffer>(gl)
-    {
-        Init();
-        mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newRB);
-    }
-
-protected:
-    void UnwrapImpl() {
-        // Check that we're not falling out of scope after
-        // the current context changed.
-        MOZ_ASSERT(mGL->IsCurrent());
-
-        mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB);
-    }
-};
-
-struct ScopedFramebufferForTexture
-    : public ScopedGLWrapper<ScopedFramebufferForTexture>
-{
-    friend struct ScopedGLWrapper<ScopedFramebufferForTexture>;
-
-protected:
-    bool mComplete; // True if the framebuffer we create is complete.
-    GLuint mFB;
-
-public:
-    ScopedFramebufferForTexture(GLContext* gl, GLuint texture,
-                                GLenum target = LOCAL_GL_TEXTURE_2D)
-        : ScopedGLWrapper<ScopedFramebufferForTexture>(gl)
-        , mComplete(false)
-        , mFB(0)
-    {
-        mGL->fGenFramebuffers(1, &mFB);
-        ScopedBindFramebuffer autoFB(gl, mFB);
-        mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
-                                   LOCAL_GL_COLOR_ATTACHMENT0,
-                                   target,
-                                   texture,
-                                   0);
-
-        GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
-        if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
-            mComplete = true;
-        } else {
-            mGL->fDeleteFramebuffers(1, &mFB);
-            mFB = 0;
-        }
-    }
-
-protected:
-    void UnwrapImpl() {
-        if (!mFB)
-            return;
-
-        mGL->fDeleteFramebuffers(1, &mFB);
-        mFB = 0;
-    }
-
-public:
-    GLuint FB() const {
-        MOZ_ASSERT(IsComplete());
-        return mFB;
-    }
-
-    bool IsComplete() const {
-        return mComplete;
-    }
-};
-
-struct ScopedFramebufferForRenderbuffer
-    : public ScopedGLWrapper<ScopedFramebufferForRenderbuffer>
-{
-    friend struct ScopedGLWrapper<ScopedFramebufferForRenderbuffer>;
-
-protected:
-    bool mComplete; // True if the framebuffer we create is complete.
-    GLuint mFB;
-
-public:
-    ScopedFramebufferForRenderbuffer(GLContext* gl, GLuint rb)
-        : ScopedGLWrapper<ScopedFramebufferForRenderbuffer>(gl)
-        , mComplete(false)
-        , mFB(0)
-    {
-        mGL->fGenFramebuffers(1, &mFB);
-        ScopedBindFramebuffer autoFB(gl, mFB);
-        mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
-                                      LOCAL_GL_COLOR_ATTACHMENT0,
-                                      LOCAL_GL_RENDERBUFFER,
-                                      rb);
-
-        GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
-        if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
-            mComplete = true;
-        } else {
-            mGL->fDeleteFramebuffers(1, &mFB);
-            mFB = 0;
-        }
-    }
-
-protected:
-    void UnwrapImpl() {
-        if (!mFB)
-            return;
-
-        mGL->fDeleteFramebuffers(1, &mFB);
-        mFB = 0;
-    }
-
-public:
-    GLuint FB() const {
-        return mFB;
-    }
-
-    bool IsComplete() const {
-        return mComplete;
-    }
-};
 
 } /* namespace gl */
 } /* namespace mozilla */
 
 #endif /* GLCONTEXT_H_ */
new file mode 100644
--- /dev/null
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/. */
+
+#include "ScopedGLHelpers.h"
+
+namespace mozilla {
+namespace gl {
+
+/* ScopedGLState - Wraps glEnable/glDisable. **********************************/
+
+// Use |newState = true| to enable, |false| to disable.
+ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability, bool aNewState)
+    : ScopedGLWrapper<ScopedGLState>(aGL)
+    , mCapability(aCapability)
+{
+    mOldState = mGL->fIsEnabled(mCapability);
+
+    // Early out if we're already in the right state.
+    if (aNewState == mOldState)
+        return;
+
+    if (aNewState) {
+        mGL->fEnable(mCapability);
+    } else {
+        mGL->fDisable(mCapability);
+    }
+}
+
+void
+ScopedGLState::UnwrapImpl()
+{
+    if (mOldState) {
+        mGL->fEnable(mCapability);
+    } else {
+        mGL->fDisable(mCapability);
+    }
+}
+
+
+/* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and BindUserFB. */
+
+void
+ScopedBindFramebuffer::Init()
+{
+    mOldFB = mGL->GetFB();
+}
+
+ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL)
+    : ScopedGLWrapper<ScopedBindFramebuffer>(aGL)
+{
+    Init();
+}
+
+ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB)
+    : ScopedGLWrapper<ScopedBindFramebuffer>(aGL)
+{
+    Init();
+    mGL->BindFB(aNewFB);
+}
+
+void
+ScopedBindFramebuffer::UnwrapImpl()
+{
+    // Check that we're not falling out of scope after the current context changed.
+    MOZ_ASSERT(mGL->IsCurrent());
+
+    mGL->BindFB(mOldFB);
+}
+
+
+/* ScopedBindTextureUnit ******************************************************/
+
+ScopedBindTextureUnit::ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit)
+    : ScopedGLWrapper<ScopedBindTextureUnit>(aGL)
+{
+    MOZ_ASSERT(aTexUnit >= LOCAL_GL_TEXTURE0);
+    mGL->GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &mOldTexUnit);
+    mGL->fActiveTexture(aTexUnit);
+}
+
+void
+ScopedBindTextureUnit::UnwrapImpl() {
+    // Check that we're not falling out of scope after the current context changed.
+    MOZ_ASSERT(mGL->IsCurrent());
+
+    mGL->fActiveTexture(mOldTexUnit);
+}
+
+
+/* ScopedTexture **************************************************************/
+
+ScopedTexture::ScopedTexture(GLContext* aGL)
+    : ScopedGLWrapper<ScopedTexture>(aGL)
+{
+    mGL->fGenTextures(1, &mTexture);
+}
+
+void
+ScopedTexture::UnwrapImpl()
+{
+    // Check that we're not falling out of scope after
+    // the current context changed.
+    MOZ_ASSERT(mGL->IsCurrent());
+
+    mGL->fDeleteTextures(1, &mTexture);
+}
+
+/* ScopedBindTexture **********************************************************/
+void
+ScopedBindTexture::Init(GLenum aTarget)
+{
+    mTarget = aTarget;
+    mOldTex = 0;
+    GLenum bindingTarget = (aTarget == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_BINDING_2D
+                         : (aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) ? LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB
+                         : (aTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
+                         : LOCAL_GL_NONE;
+    MOZ_ASSERT(bindingTarget != LOCAL_GL_NONE);
+    mGL->GetUIntegerv(bindingTarget, &mOldTex);
+}
+
+ScopedBindTexture::ScopedBindTexture(GLContext* aGL, GLuint aNewTex, GLenum aTarget)
+        : ScopedGLWrapper<ScopedBindTexture>(aGL)
+    {
+        Init(aTarget);
+        mGL->fBindTexture(aTarget, aNewTex);
+    }
+
+void
+ScopedBindTexture::UnwrapImpl()
+{
+    // Check that we're not falling out of scope after the current context changed.
+    MOZ_ASSERT(mGL->IsCurrent());
+
+    mGL->fBindTexture(mTarget, mOldTex);
+}
+
+
+/* ScopedBindRenderbuffer *****************************************************/
+
+void
+ScopedBindRenderbuffer::Init()
+{
+    mOldRB = 0;
+    mGL->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &mOldRB);
+}
+
+ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL)
+        : ScopedGLWrapper<ScopedBindRenderbuffer>(aGL)
+{
+    Init();
+}
+
+ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL, GLuint aNewRB)
+    : ScopedGLWrapper<ScopedBindRenderbuffer>(aGL)
+{
+    Init();
+    mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, aNewRB);
+}
+
+void
+ScopedBindRenderbuffer::UnwrapImpl() {
+    // Check that we're not falling out of scope after the current context changed.
+    MOZ_ASSERT(mGL->IsCurrent());
+
+    mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB);
+}
+
+
+/* ScopedFramebufferForTexture ************************************************/
+ScopedFramebufferForTexture::ScopedFramebufferForTexture(GLContext* aGL,
+                                                         GLuint aTexture,
+                                                         GLenum aTarget)
+    : ScopedGLWrapper<ScopedFramebufferForTexture>(aGL)
+    , mComplete(false)
+    , mFB(0)
+{
+    mGL->fGenFramebuffers(1, &mFB);
+    ScopedBindFramebuffer autoFB(aGL, mFB);
+    mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
+                               LOCAL_GL_COLOR_ATTACHMENT0,
+                               aTarget,
+                               aTexture,
+                               0);
+
+    GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+    if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+        mComplete = true;
+    } else {
+        mGL->fDeleteFramebuffers(1, &mFB);
+        mFB = 0;
+    }
+}
+
+void ScopedFramebufferForTexture::UnwrapImpl()
+{
+    if (!mFB)
+        return;
+
+    mGL->fDeleteFramebuffers(1, &mFB);
+    mFB = 0;
+}
+
+
+/* ScopedFramebufferForRenderbuffer *******************************************/
+
+
+ScopedFramebufferForRenderbuffer::ScopedFramebufferForRenderbuffer(GLContext* aGL,
+                                                                   GLuint aRB)
+    : ScopedGLWrapper<ScopedFramebufferForRenderbuffer>(aGL)
+    , mComplete(false)
+    , mFB(0)
+{
+    mGL->fGenFramebuffers(1, &mFB);
+    ScopedBindFramebuffer autoFB(aGL, mFB);
+    mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
+                                  LOCAL_GL_COLOR_ATTACHMENT0,
+                                  LOCAL_GL_RENDERBUFFER,
+                                  aRB);
+
+    GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+    if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+        mComplete = true;
+    } else {
+        mGL->fDeleteFramebuffers(1, &mFB);
+        mFB = 0;
+    }
+}
+
+void
+ScopedFramebufferForRenderbuffer::UnwrapImpl()
+{
+    if (!mFB)
+        return;
+
+    mGL->fDeleteFramebuffers(1, &mFB);
+    mFB = 0;
+}
+
+} /* namespace gl */
+} /* namespace mozilla */
new file mode 100644
--- /dev/null
+++ b/gfx/gl/ScopedGLHelpers.h
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 SCOPEDGLHELPERS_H_
+#define SCOPEDGLHELPERS_H_
+
+namespace mozilla {
+namespace gl {
+//RAII via CRTP!
+template <class Derived>
+struct ScopedGLWrapper
+{
+private:
+    bool mIsUnwrapped;
+
+protected:
+    GLContext* const mGL;
+
+    ScopedGLWrapper(GLContext* gl)
+        : mIsUnwrapped(false)
+        , mGL(gl)
+    {
+        MOZ_ASSERT(&ScopedGLWrapper<Derived>::Unwrap == &Derived::Unwrap);
+        MOZ_ASSERT(&Derived::UnwrapImpl);
+        MOZ_ASSERT(mGL->IsCurrent());
+    }
+
+    virtual ~ScopedGLWrapper() {
+        if (!mIsUnwrapped)
+            Unwrap();
+    }
+
+public:
+    void Unwrap() {
+        MOZ_ASSERT(!mIsUnwrapped);
+
+        Derived* derived = static_cast<Derived*>(this);
+        derived->UnwrapImpl();
+
+        mIsUnwrapped = true;
+    }
+};
+
+// Wraps glEnable/Disable.
+struct ScopedGLState
+    : public ScopedGLWrapper<ScopedGLState>
+{
+    friend struct ScopedGLWrapper<ScopedGLState>;
+
+protected:
+    const GLenum mCapability;
+    bool mOldState;
+
+public:
+    // Use |newState = true| to enable, |false| to disable.
+    ScopedGLState(GLContext* aGL, GLenum aCapability, bool aNewState);
+
+protected:
+    void UnwrapImpl();
+};
+
+// Saves and restores with GetUserBoundFB and BindUserFB.
+struct ScopedBindFramebuffer
+    : public ScopedGLWrapper<ScopedBindFramebuffer>
+{
+    friend struct ScopedGLWrapper<ScopedBindFramebuffer>;
+
+protected:
+    GLuint mOldFB;
+
+private:
+    void Init();
+
+public:
+    explicit ScopedBindFramebuffer(GLContext* aGL);
+    ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB);
+
+protected:
+    void UnwrapImpl();
+};
+
+struct ScopedBindTextureUnit
+    : public ScopedGLWrapper<ScopedBindTextureUnit>
+{
+    friend struct ScopedGLWrapper<ScopedBindTextureUnit>;
+
+protected:
+    GLenum mOldTexUnit;
+
+public:
+    ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit);
+
+protected:
+    void UnwrapImpl();
+};
+
+
+struct ScopedTexture
+    : public ScopedGLWrapper<ScopedTexture>
+{
+    friend struct ScopedGLWrapper<ScopedTexture>;
+
+protected:
+    GLuint mTexture;
+
+public:
+    ScopedTexture(GLContext* aGL);
+    GLuint Texture() { return mTexture; }
+
+protected:
+    void UnwrapImpl();
+};
+
+
+struct ScopedBindTexture
+    : public ScopedGLWrapper<ScopedBindTexture>
+{
+    friend struct ScopedGLWrapper<ScopedBindTexture>;
+
+protected:
+    GLuint mOldTex;
+    GLenum mTarget;
+
+private:
+    void Init(GLenum aTarget);
+
+public:
+    ScopedBindTexture(GLContext* aGL, GLuint aNewTex,
+                      GLenum aTarget = LOCAL_GL_TEXTURE_2D);
+
+protected:
+    void UnwrapImpl();
+};
+
+
+struct ScopedBindRenderbuffer
+    : public ScopedGLWrapper<ScopedBindRenderbuffer>
+{
+    friend struct ScopedGLWrapper<ScopedBindRenderbuffer>;
+
+protected:
+    GLuint mOldRB;
+
+private:
+    void Init();
+
+public:
+    explicit ScopedBindRenderbuffer(GLContext* aGL);
+
+    ScopedBindRenderbuffer(GLContext* aGL, GLuint aNewRB);
+
+protected:
+    void UnwrapImpl();
+};
+
+
+struct ScopedFramebufferForTexture
+    : public ScopedGLWrapper<ScopedFramebufferForTexture>
+{
+    friend struct ScopedGLWrapper<ScopedFramebufferForTexture>;
+
+protected:
+    bool mComplete; // True if the framebuffer we create is complete.
+    GLuint mFB;
+
+public:
+    ScopedFramebufferForTexture(GLContext* aGL, GLuint aTexture,
+                                GLenum aTarget = LOCAL_GL_TEXTURE_2D);
+
+    bool IsComplete() const {
+        return mComplete;
+    }
+
+    GLuint FB() const {
+        MOZ_ASSERT(IsComplete());
+        return mFB;
+    }
+
+protected:
+    void UnwrapImpl();
+};
+
+struct ScopedFramebufferForRenderbuffer
+    : public ScopedGLWrapper<ScopedFramebufferForRenderbuffer>
+{
+    friend struct ScopedGLWrapper<ScopedFramebufferForRenderbuffer>;
+
+protected:
+    bool mComplete; // True if the framebuffer we create is complete.
+    GLuint mFB;
+
+public:
+    ScopedFramebufferForRenderbuffer(GLContext* aGL, GLuint aRB);
+
+    bool IsComplete() const {
+        return mComplete;
+    }
+
+    GLuint FB() const {
+        return mFB;
+    }
+
+protected:
+    void UnwrapImpl();
+};
+
+} /* namespace gl */
+} /* namespace mozilla */
+
+#endif /* SCOPEDGLHELPERS_H_ */
--- a/gfx/gl/SharedSurfaceEGL.cpp
+++ b/gfx/gl/SharedSurfaceEGL.cpp
@@ -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/. */
 
 #include "SharedSurfaceEGL.h"
 
 #include "GLContext.h"
 #include "GLBlitHelper.h"
+#include "ScopedGLHelpers.h"
 #include "SharedSurfaceGL.h"
 #include "SurfaceFactory.h"
 #include "GLLibraryEGL.h"
 #include "TextureGarbageBin.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
--- a/gfx/gl/SharedSurfaceGL.cpp
+++ b/gfx/gl/SharedSurfaceGL.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
 /* 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/. */
 
 #include "SharedSurfaceGL.h"
 #include "GLContext.h"
 #include "GLBlitHelper.h"
+#include "ScopedGLHelpers.h"
 #include "gfxImageSurface.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace gl {
 
 // |src| must begin and end locked, though we may
--- a/gfx/gl/SharedSurfaceIO.cpp
+++ b/gfx/gl/SharedSurfaceIO.cpp
@@ -3,16 +3,17 @@
  * 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/. */
 
 #include "SharedSurfaceIO.h"
 #include "GLContext.h"
 #include "gfxImageSurface.h"
 #include "mozilla/gfx/MacIOSurface.h"
 #include "mozilla/DebugOnly.h"
+#include "ScopedGLHelpers.h"
 
 namespace mozilla {
 namespace gl {
 
 using namespace gfx;
 
 /* static */ SharedSurface_IOSurface*
 SharedSurface_IOSurface::Create(MacIOSurface* surface, GLContext *gl, bool hasAlpha)
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -38,16 +38,17 @@ EXPORTS += [
     'GLContextTypes.h',
     'GLContextUtils.h',
     'GLDefs.h',
     'GLLibraryEGL.h',
     'GLLibraryLoader.h',
     'GLScreenBuffer.h',
     'GLTextureImage.h',
     'GLTypes.h',
+    'ScopedGLHelpers.h',
     'SharedSurface.h',
     'SharedSurfaceEGL.h',
     'SharedSurfaceGL.h',
     'SurfaceFactory.h',
     'SurfaceStream.h',
     'SurfaceTypes.h',
     'TextureGarbageBin.h',
     'VBOArena.h',
@@ -111,16 +112,17 @@ UNIFIED_SOURCES += [
     'GLContext.cpp',
     'GLContextFeatures.cpp',
     'GLContextTypes.cpp',
     'GLContextUtils.cpp',
     'GLLibraryEGL.cpp',
     'GLLibraryLoader.cpp',
     'GLScreenBuffer.cpp',
     'GLTextureImage.cpp',
+    'ScopedGLHelpers.cpp',
     'SharedSurface.cpp',
     'SharedSurfaceEGL.cpp',
     'SharedSurfaceGL.cpp',
     'SurfaceFactory.cpp',
     'SurfaceStream.cpp',
     'TextureGarbageBin.cpp',
     'TextureImageEGL.cpp',
     'VBOArena.cpp',