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 157997 129bf6f1933cb4fa535b1dfd106cd731f9cf1e99
parent 157996 1b0fc4fd9a75dafdbae4344ca847a24abbb6a01a
child 157998 e6484a878eeed6df777567c9767e1dd7b8f59231
push id36900
push userbjacob@mozilla.com
push dateThu, 28 Nov 2013 20:57:35 +0000
treeherdermozilla-inbound@129bf6f1933c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob
bugs942492
milestone28.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 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',