Bug 1382104 - Remove internal-vs-user FB bindings. - r=daoshengmu draft
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 18 Jul 2017 15:19:40 -0700
changeset 649179 b9d88fce260d240bba6bf6666dbdb031b8c189e7
parent 646265 b95b1638db48fc3d450b95b98da6bcd2f9326d2f
child 649180 bf83e8c198e5a3aff9cb83fa63713cfda13a7827
push id74978
push userbmo:jgilbert@mozilla.com
push dateFri, 18 Aug 2017 19:07:35 +0000
reviewersdaoshengmu
bugs1382104
milestone57.0a1
Bug 1382104 - Remove internal-vs-user FB bindings. - r=daoshengmu MozReview-Commit-ID: 1lZouQUnaDl
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextUtils.cpp
dom/canvas/WebGLTextureUpload.cpp
gfx/gl/GLBlitHelper.cpp
gfx/gl/GLBlitHelper.h
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLScreenBuffer.cpp
gfx/gl/GLScreenBuffer.h
gfx/gl/ScopedGLHelpers.cpp
gfx/gl/SharedSurface.cpp
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -800,16 +800,18 @@ WebGLContext::ResizeBackbuffer(uint32_t 
 
       width /= 2;
       height /= 2;
     }
 
     if (!resized)
         return false;
 
+    RebindFramebuffers();
+
     mWidth = gl->OffscreenSize().width;
     mHeight = gl->OffscreenSize().height;
     MOZ_ASSERT((uint32_t)mWidth == width);
     MOZ_ASSERT((uint32_t)mHeight == height);
 
     if (width != requestedWidth ||
         height != requestedHeight)
     {
@@ -817,16 +819,36 @@ WebGLContext::ResizeBackbuffer(uint32_t 
                           " to %dx%d succeeded.",
                         requestedWidth, requestedHeight,
                         width, height);
     }
     return true;
 }
 
 void
+WebGLContext::RebindFramebuffers() const
+{
+    const auto fnBind = [&](const GLenum target, const WebGLFramebuffer* const fb) {
+        if (fb) {
+            gl->fBindFramebuffer(target, fb->mGLName);
+        } else {
+            gl->Screen()->BindAsFramebuffer(target);
+        }
+    };
+
+    if (IsWebGL2()) {
+        fnBind(LOCAL_GL_DRAW_FRAMEBUFFER, mBoundDrawFramebuffer);
+        fnBind(LOCAL_GL_READ_FRAMEBUFFER, mBoundReadFramebuffer);
+    } else {
+        MOZ_ASSERT(mBoundDrawFramebuffer == mBoundReadFramebuffer);
+        fnBind(LOCAL_GL_FRAMEBUFFER, mBoundDrawFramebuffer);
+    }
+}
+
+void
 WebGLContext::ThrowEvent_WebGLContextCreationError(const nsACString& text)
 {
     RefPtr<EventTarget> target = mCanvasElement;
     if (!target && mOffscreenCanvas) {
         target = mOffscreenCanvas;
     } else if (!target) {
         GenerateWarning("Failed to create WebGL context: %s", text.BeginReading());
         return;
@@ -1088,17 +1110,17 @@ WebGLContext::SetDimensions(int32_t sign
     MakeContextCurrent();
 
     gl->fViewport(0, 0, mWidth, mHeight);
     mViewportX = mViewportY = 0;
     mViewportWidth = mWidth;
     mViewportHeight = mHeight;
 
     gl->fScissor(0, 0, mWidth, mHeight);
-    gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+    gl->Screen()->BindAsFramebuffer();
 
     //////
     // Check everything
 
     AssertCachedBindings();
     AssertCachedGlobalState();
 
     MOZ_ASSERT(gl->Caps().color);
@@ -1477,17 +1499,18 @@ WebGLContext::MozGetUnderlyingParamStrin
 
     return NS_OK;
 }
 
 void
 WebGLContext::ClearScreen()
 {
     MakeContextCurrent();
-    ScopedBindFramebuffer autoFB(gl, 0);
+    ScopedBindFramebuffer autoFB(gl);
+    gl->Screen()->BindAsFramebuffer();
 
     const bool changeDrawBuffers = (mDefaultFB_DrawBuffer0 != LOCAL_GL_BACK);
     if (changeDrawBuffers) {
         gl->Screen()->SetDrawBuffer(LOCAL_GL_BACK);
     }
 
     GLbitfield bufferBits = LOCAL_GL_COLOR_BUFFER_BIT;
     if (mOptions.depth)
@@ -1610,16 +1633,17 @@ WebGLContext::PresentScreenBuffer()
 
     GLScreenBuffer* screen = gl->Screen();
     MOZ_ASSERT(screen);
 
     if (!screen->PublishFrame(screen->Size())) {
         ForceLoseContext();
         return false;
     }
+    RebindFramebuffers();
 
     if (!mOptions.preserveDrawingBuffer) {
         mBackbufferNeedsClear = true;
     }
 
     mShouldPresent = false;
     OnEndOfFrame();
 
@@ -1949,17 +1973,18 @@ WebGLContext::GetSurfaceSnapshot(gfxAlph
     surf = Factory::CreateDataSourceSurfaceWithStride(IntSize(mWidth, mHeight),
                                                       surfFormat,
                                                       mWidth * 4);
     if (NS_WARN_IF(!surf))
         return nullptr;
 
     gl->MakeCurrent();
     {
-        ScopedBindFramebuffer autoFB(gl, 0);
+        ScopedBindFramebuffer autoFB(gl);
+        gl->Screen()->BindAsFramebuffer();
         ClearBackbufferIfNeeded();
 
         // Save, override, then restore glReadBuffer.
         const GLenum readBufferMode = gl->Screen()->GetReadBufferMode();
 
         if (readBufferMode != LOCAL_GL_BACK) {
             gl->Screen()->SetReadBuffer(LOCAL_GL_BACK);
         }
@@ -2176,34 +2201,16 @@ ScopedUnpackReset::UnwrapImpl()
         }
 
         mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, pbo);
     }
 }
 
 ////////////////////
 
-void
-ScopedFBRebinder::UnwrapImpl()
-{
-    const auto fnName = [&](WebGLFramebuffer* fb) {
-        return fb ? fb->mGLName : 0;
-    };
-
-    if (mWebGL->IsWebGL2()) {
-        mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
-        mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fnName(mWebGL->mBoundReadFramebuffer));
-    } else {
-        MOZ_ASSERT(mWebGL->mBoundDrawFramebuffer == mWebGL->mBoundReadFramebuffer);
-        mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
-    }
-}
-
-////////////////////
-
 static GLenum
 TargetIfLazy(GLenum target)
 {
     switch (target) {
     case LOCAL_GL_PIXEL_PACK_BUFFER:
     case LOCAL_GL_PIXEL_UNPACK_BUFFER:
         return target;
 
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1887,16 +1887,18 @@ protected:
                           uint8_t bytesPerPixel, uint32_t* const out_rowStride,
                           uint32_t* const out_endOffset);
 
     GLenum mPixelStore_ColorspaceConversion;
     bool mPixelStore_FlipY;
     bool mPixelStore_PremultiplyAlpha;
     bool mPixelStore_RequireFastPath;
 
+    void RebindFramebuffers() const;
+
     ////////////////////////////////////
     class FakeBlackTexture {
     public:
         static UniquePtr<FakeBlackTexture> Create(gl::GLContext* gl,
                                                   TexTarget target,
                                                   FakeBlackType type);
         gl::GLContext* const mGL;
         const GLuint mGLName;
@@ -2159,17 +2161,19 @@ private:
 
 public:
     explicit ScopedFBRebinder(WebGLContext* webgl)
         : ScopedGLWrapper<ScopedFBRebinder>(webgl->gl)
         , mWebGL(webgl)
     { }
 
 private:
-    void UnwrapImpl();
+    void UnwrapImpl() {
+        mWebGL->RebindFramebuffers();
+    }
 };
 
 class ScopedLazyBind final
     : public gl::ScopedGLWrapper<ScopedLazyBind>
 {
     friend struct gl::ScopedGLWrapper<ScopedLazyBind>;
 
     const GLenum mTarget;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -136,20 +136,19 @@ WebGLContext::BindFramebuffer(GLenum tar
         return;
 
     if (wfb && !ValidateObject("bindFramebuffer", *wfb))
         return;
 
     MakeContextCurrent();
 
     if (!wfb) {
-        gl->fBindFramebuffer(target, 0);
+        gl->Screen()->BindAsFramebuffer(target);
     } else {
-        GLuint framebuffername = wfb->mGLName;
-        gl->fBindFramebuffer(target, framebuffername);
+        gl->fBindFramebuffer(target, wfb->mGLName);
 #ifdef ANDROID
         wfb->mIsFB = true;
 #endif
     }
 
     switch (target) {
     case LOCAL_GL_FRAMEBUFFER:
         mBoundDrawFramebuffer = wfb;
@@ -157,17 +156,17 @@ WebGLContext::BindFramebuffer(GLenum tar
         break;
     case LOCAL_GL_DRAW_FRAMEBUFFER:
         mBoundDrawFramebuffer = wfb;
         break;
     case LOCAL_GL_READ_FRAMEBUFFER:
         mBoundReadFramebuffer = wfb;
         break;
     default:
-        break;
+        MOZ_CRASH();
     }
 }
 
 void
 WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer* wrb)
 {
     if (IsContextLost())
         return;
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -747,28 +747,26 @@ WebGLContext::AssertCachedBindings()
     GetAndFlushUnderlyingGLErrors();
 
     if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
         GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
         AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
     }
 
     // Framebuffers
-    if (IsWebGL2()) {
-        GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
-                                             : 0;
-        AssertUintParamCorrect(gl, LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, bound);
-
-        bound = mBoundReadFramebuffer ? mBoundReadFramebuffer->mGLName : 0;
-        AssertUintParamCorrect(gl, LOCAL_GL_READ_FRAMEBUFFER_BINDING, bound);
+    const auto boundDrawFB = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
+                                                   : gl->Screen()->DrawFB();
+    const auto boundReadFB = mBoundReadFramebuffer ? mBoundReadFramebuffer->mGLName
+                                                   : gl->Screen()->ReadFB();
+    if (gl->IsSupported(GLFeature::split_framebuffer)) {
+        AssertUintParamCorrect(gl, LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, boundDrawFB);
+        AssertUintParamCorrect(gl, LOCAL_GL_READ_FRAMEBUFFER_BINDING, boundReadFB);
     } else {
         MOZ_ASSERT(mBoundDrawFramebuffer == mBoundReadFramebuffer);
-        GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
-                                             : 0;
-        AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
+        AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, boundDrawFB);
     }
 
     GLint stencilBits = 0;
     if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer.
         const GLuint stencilRefMask = (1 << stencilBits) - 1;
 
         AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF,      stencilRefMask, mStencilRefFront);
         AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1712,16 +1712,17 @@ ValidateCopyTexImageFormats(WebGLContext
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class ScopedCopyTexImageSource
 {
     WebGLContext* const mWebGL;
     GLuint mRB;
     GLuint mFB;
+    UniquePtr<gl::ScopedBindFramebuffer> mBindFB;
 
 public:
     ScopedCopyTexImageSource(WebGLContext* webgl, const char* funcName, uint32_t srcWidth,
                              uint32_t srcHeight, const webgl::FormatInfo* srcFormat,
                              const webgl::FormatUsageInfo* dstUsage);
     ~ScopedCopyTexImageSource();
 };
 
@@ -1814,17 +1815,17 @@ ScopedCopyTexImageSource::ScopedCopyTexI
 
     GLuint rgbaRB = 0;
     gl->fGenRenderbuffers(1, &rgbaRB);
     gl::ScopedBindRenderbuffer scopedRB(gl, rgbaRB);
     gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, sizedFormat, srcWidth, srcHeight);
 
     GLuint rgbaFB = 0;
     gl->fGenFramebuffers(1, &rgbaFB);
-    gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, rgbaFB);
+    mBindFB.reset(new gl::ScopedBindFramebuffer(gl, rgbaFB));
     gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
                                  LOCAL_GL_RENDERBUFFER, rgbaRB);
 
     const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
         MOZ_CRASH("GFX: Temp framebuffer is not complete.");
     }
 
@@ -1840,40 +1841,26 @@ ScopedCopyTexImageSource::ScopedCopyTexI
     scopedBindTex.Unwrap();
     scopedTex.Unwrap();
 
     // Leave RB and FB alive, and FB bound.
     mRB = rgbaRB;
     mFB = rgbaFB;
 }
 
-template<typename T>
-static inline GLenum
-ToGLHandle(const T& obj)
-{
-    return (obj ? obj->mGLName : 0);
-}
-
 ScopedCopyTexImageSource::~ScopedCopyTexImageSource()
 {
     if (!mFB) {
         MOZ_ASSERT(!mRB);
         return;
     }
     MOZ_ASSERT(mRB);
 
     gl::GLContext* gl = mWebGL->gl;
 
-    // If we're swizzling, it's because we're on a GL core (3.2+) profile, which has
-    // split framebuffer support.
-    gl->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER,
-                         ToGLHandle(mWebGL->mBoundDrawFramebuffer));
-    gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
-                         ToGLHandle(mWebGL->mBoundReadFramebuffer));
-
     gl->fDeleteFramebuffers(1, &mFB);
     gl->fDeleteRenderbuffers(1, &mRB);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 static bool
 GetUnsizedFormatForCopy(GLenum internalFormat, webgl::UnsizedFormat* const out)
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -548,68 +548,36 @@ GLBlitHelper::DeleteTexBlitProgram()
         mGL->fDeleteProgram(mTexNV12PlanarBlit_Program);
         mTexNV12PlanarBlit_Program = 0;
     }
 }
 
 void
 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
                                            const gfx::IntSize& srcSize,
-                                           const gfx::IntSize& destSize,
-                                           bool internalFBs)
+                                           const gfx::IntSize& destSize)
 {
     MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
     MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
 
     MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
 
     ScopedBindFramebuffer boundFB(mGL);
-    ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
+    mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcFB);
+    mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destFB);
 
-    if (internalFBs) {
-        mGL->Screen()->BindReadFB_Internal(srcFB);
-        mGL->Screen()->BindDrawFB_Internal(destFB);
-    } else {
-        mGL->BindReadFB(srcFB);
-        mGL->BindDrawFB(destFB);
-    }
+    ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
 
     mGL->fBlitFramebuffer(0, 0,  srcSize.width,  srcSize.height,
                           0, 0, destSize.width, destSize.height,
                           LOCAL_GL_COLOR_BUFFER_BIT,
                           LOCAL_GL_NEAREST);
 }
 
 void
-GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
-                                           const gfx::IntSize& srcSize,
-                                           const gfx::IntSize& destSize,
-                                           const GLFormats& srcFormats,
-                                           bool internalFBs)
-{
-    MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
-    MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
-
-    if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
-        BlitFramebufferToFramebuffer(srcFB, destFB,
-                                     srcSize, destSize,
-                                     internalFBs);
-        return;
-    }
-
-    GLuint tex = CreateTextureForOffscreen(mGL, srcFormats, srcSize);
-    MOZ_ASSERT(tex);
-
-    BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize, internalFBs);
-    BlitTextureToFramebuffer(tex, destFB, srcSize, destSize, internalFBs);
-
-    mGL->fDeleteTextures(1, &tex);
-}
-
-void
 GLBlitHelper::BindAndUploadYUVTexture(Channel which,
                                       uint32_t width,
                                       uint32_t height,
                                       void* data,
                                       bool needsAllocation)
 {
     MOZ_ASSERT(which < Channel_Max, "Invalid channel!");
     GLuint* srcTexArr[3] = {&mSrcTexY, &mSrcTexCb, &mSrcTexCr};
@@ -888,64 +856,54 @@ GLBlitHelper::BlitImageToTexture(layers:
 
     return BlitImageToFramebuffer(srcImage, destSize, autoFBForTex.FB(), destOrigin);
 }
 
 void
 GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
                                        const gfx::IntSize& srcSize,
                                        const gfx::IntSize& destSize,
-                                       GLenum srcTarget,
-                                       bool internalFBs)
+                                       GLenum srcTarget)
 {
     MOZ_ASSERT(mGL->fIsTexture(srcTex));
     MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
 
     if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
         ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
         MOZ_DIAGNOSTIC_ASSERT(srcWrapper.IsComplete());
 
-        BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB,
-                                     srcSize, destSize,
-                                     internalFBs);
+        BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB, srcSize, destSize);
         return;
     }
 
-    DrawBlitTextureToFramebuffer(srcTex, destFB, srcSize, destSize, srcTarget,
-                                 internalFBs);
+    DrawBlitTextureToFramebuffer(srcTex, destFB, srcSize, destSize, srcTarget);
 }
 
 
 void
 GLBlitHelper::DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
                                            const gfx::IntSize& srcSize,
                                            const gfx::IntSize& destSize,
-                                           GLenum srcTarget,
-                                           bool internalFBs)
+                                           GLenum srcTarget)
 {
     BlitType type;
     switch (srcTarget) {
     case LOCAL_GL_TEXTURE_2D:
         type = BlitTex2D;
         break;
     case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
         type = BlitTexRect;
         break;
     default:
         MOZ_CRASH("GFX: Fatal Error: Bad `srcTarget`.");
         break;
     }
 
     ScopedGLDrawState autoStates(mGL);
-    const ScopedBindFramebuffer bindFB(mGL);
-    if (internalFBs) {
-        mGL->Screen()->BindFB_Internal(destFB);
-    } else {
-        mGL->BindFB(destFB);
-    }
+    const ScopedBindFramebuffer bindFB(mGL, destFB);
 
     // Does destructive things to (only!) what we just saved above.
     bool good = UseTexQuadProgram(type, srcSize);
     if (!good) {
         // We're up against the wall, so bail.
         MOZ_DIAGNOSTIC_ASSERT(false,
                               "Error: Failed to prepare to blit texture->framebuffer.\n");
         mGL->fScissor(0, 0, destSize.width, destSize.height);
@@ -957,40 +915,33 @@ GLBlitHelper::DrawBlitTextureToFramebuff
     const ScopedBindTexture bindTex(mGL, srcTex, srcTarget);
     mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
 }
 
 void
 GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
                                        const gfx::IntSize& srcSize,
                                        const gfx::IntSize& destSize,
-                                       GLenum destTarget,
-                                       bool internalFBs)
+                                       GLenum destTarget)
 {
     // On the Android 4.3 emulator, IsFramebuffer may return false incorrectly.
     MOZ_ASSERT_IF(mGL->Renderer() != GLRenderer::AndroidEmulator, !srcFB || mGL->fIsFramebuffer(srcFB));
     MOZ_ASSERT(mGL->fIsTexture(destTex));
 
     if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
         ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget);
 
         BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(),
-                                     srcSize, destSize,
-                                     internalFBs);
+                                     srcSize, destSize);
         return;
     }
 
     ScopedBindTexture autoTex(mGL, destTex, destTarget);
 
-    ScopedBindFramebuffer boundFB(mGL);
-    if (internalFBs) {
-        mGL->Screen()->BindFB_Internal(srcFB);
-    } else {
-        mGL->BindFB(srcFB);
-    }
+    ScopedBindFramebuffer boundFB(mGL, srcFB);
 
     ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
     mGL->fCopyTexSubImage2D(destTarget, 0,
                        0, 0,
                        0, 0,
                        srcSize.width, srcSize.height);
 }
 
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -120,38 +120,29 @@ class GLBlitHelper final
 public:
     ~GLBlitHelper();
 
     // If you don't have |srcFormats| for the 2nd definition,
     // then you'll need the framebuffer_blit extensions to use
     // the first BlitFramebufferToFramebuffer.
     void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
                                       const gfx::IntSize& srcSize,
-                                      const gfx::IntSize& destSize,
-                                      bool internalFBs = false);
-    void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
-                                      const gfx::IntSize& srcSize,
-                                      const gfx::IntSize& destSize,
-                                      const GLFormats& srcFormats,
-                                      bool internalFBs = false);
+                                      const gfx::IntSize& destSize);
     void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
                                   const gfx::IntSize& srcSize,
                                   const gfx::IntSize& destSize,
-                                  GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
-                                  bool internalFBs = false);
+                                  GLenum srcTarget = LOCAL_GL_TEXTURE_2D);
     void DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
                                       const gfx::IntSize& srcSize,
                                       const gfx::IntSize& destSize,
-                                      GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
-                                      bool internalFBs = false);
+                                      GLenum srcTarget = LOCAL_GL_TEXTURE_2D);
     void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
                                   const gfx::IntSize& srcSize,
                                   const gfx::IntSize& destSize,
-                                  GLenum destTarget = LOCAL_GL_TEXTURE_2D,
-                                  bool internalFBs = false);
+                                  GLenum destTarget = LOCAL_GL_TEXTURE_2D);
     void BlitTextureToTexture(GLuint srcTex, GLuint destTex,
                               const gfx::IntSize& srcSize,
                               const gfx::IntSize& destSize,
                               GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
                               GLenum destTarget = LOCAL_GL_TEXTURE_2D);
     bool BlitImageToFramebuffer(layers::Image* srcImage, const gfx::IntSize& destSize,
                                 GLuint destFB, OriginPos destOrigin);
     bool BlitImageToTexture(layers::Image* srcImage, const gfx::IntSize& destSize,
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -960,17 +960,16 @@ GLContext::InitWithPrefixImpl(const char
 
     if (IsSupported(GLFeature::framebuffer_multisample)) {
         fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples);
     }
 
     ////////////////////////////////////////////////////////////////////////////
 
     // We're ready for final setup.
-    fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
 
     // TODO: Remove SurfaceCaps::any.
     if (mCaps.any) {
         mCaps.any = false;
         mCaps.color = true;
         mCaps.alpha = false;
     }
 
@@ -1960,36 +1959,36 @@ GLContext::AssembleOffscreenFBs(const GL
     ScopedBindFramebuffer autoFB(this);
 
     GLuint drawFB = 0;
     GLuint readFB = 0;
 
     if (texture) {
         readFB = 0;
         fGenFramebuffers(1, &readFB);
-        BindFB(readFB);
+        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, readFB);
         fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
                               LOCAL_GL_COLOR_ATTACHMENT0,
                               LOCAL_GL_TEXTURE_2D,
                               texture,
                               0);
     }
 
     if (colorMSRB) {
         drawFB = 0;
         fGenFramebuffers(1, &drawFB);
-        BindFB(drawFB);
+        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, drawFB);
         fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
                                  LOCAL_GL_COLOR_ATTACHMENT0,
                                  LOCAL_GL_RENDERBUFFER,
                                  colorMSRB);
     } else {
         drawFB = readFB;
     }
-    MOZ_ASSERT(GetFB() == drawFB);
+    MOZ_ASSERT(GetIntAs<GLuint>(LOCAL_GL_FRAMEBUFFER_BINDING) == drawFB);
 
     if (depthRB) {
         fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
                                  LOCAL_GL_DEPTH_ATTACHMENT,
                                  LOCAL_GL_RENDERBUFFER,
                                  depthRB);
     }
 
@@ -2358,64 +2357,43 @@ GLContext::GuaranteeResolve()
 const gfx::IntSize&
 GLContext::OffscreenSize() const
 {
     MOZ_ASSERT(IsOffscreen());
     return mScreen->Size();
 }
 
 bool
-GLContext::CreateScreenBufferImpl(const IntSize& size, const SurfaceCaps& caps)
+GLContext::CreateScreenBuffer(const IntSize& size, const SurfaceCaps& caps)
 {
+    if (!IsOffscreenSizeAllowed(size))
+        return false;
+
     UniquePtr<GLScreenBuffer> newScreen = GLScreenBuffer::Create(this, size, caps);
     if (!newScreen)
         return false;
 
     if (!newScreen->Resize(size)) {
         return false;
     }
 
-    // This will rebind to 0 (Screen) if needed when
-    // it falls out of scope.
-    ScopedBindFramebuffer autoFB(this);
-
     mScreen = Move(newScreen);
 
     return true;
 }
 
 bool
 GLContext::ResizeScreenBuffer(const IntSize& size)
 {
     if (!IsOffscreenSizeAllowed(size))
         return false;
 
     return mScreen->Resize(size);
 }
 
-void
-GLContext::ForceDirtyScreen()
-{
-    ScopedBindFramebuffer autoFB(0);
-
-    BeforeGLDrawCall();
-    // no-op; just pretend we did something
-    AfterGLDrawCall();
-}
-
-void
-GLContext::CleanDirtyScreen()
-{
-    ScopedBindFramebuffer autoFB(0);
-
-    BeforeGLReadCall();
-    // no-op; we just want to make sure the Read FBO is updated if it needs to be
-    AfterGLReadCall();
-}
-
 bool
 GLContext::IsOffscreenSizeAllowed(const IntSize& aSize) const
 {
     int32_t biggerDimension = std::max(aSize.width, aSize.height);
     int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize);
     return biggerDimension <= maxAllowed;
 }
 
@@ -2539,17 +2517,17 @@ GLContext::Readback(SharedSurface* src, 
     {
         ScopedBindFramebuffer autoFB(this);
 
         // We're consuming from the producer side, so which do we use?
         // Really, we just want a read-only lock, so ConsumerAcquire is the best match.
         src->ProducerReadAcquire();
 
         if (src->mAttachType == AttachmentType::Screen) {
-            fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+            mScreen->BindAsFramebuffer();
         } else {
             fGenFramebuffers(1, &tempFB);
             fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, tempFB);
 
             switch (src->mAttachType) {
             case AttachmentType::GLTexture:
                 fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
                                       src->ProdTextureTarget(), src->ProdTexture(), 0);
@@ -2616,47 +2594,29 @@ GLContext::AfterGLDrawCall()
     mHeavyGLCallsSinceLastFlush = true;
 }
 
 // Do whatever setup is necessary to read from our offscreen FBO, if it's
 // bound.
 void
 GLContext::BeforeGLReadCall()
 {
-    if (mScreen)
+    if (mScreen) {
         mScreen->BeforeReadCall();
+    }
 }
 
 void
 GLContext::fBindFramebuffer(GLenum target, GLuint framebuffer)
 {
-    if (!mScreen) {
-        raw_fBindFramebuffer(target, framebuffer);
-        return;
+    raw_fBindFramebuffer(target, framebuffer);
+
+    if (mScreen) {
+        mScreen->OnBindFramebuffer(target, framebuffer);
     }
-
-    switch (target) {
-        case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
-            mScreen->BindDrawFB(framebuffer);
-            return;
-
-        case LOCAL_GL_READ_FRAMEBUFFER_EXT:
-            mScreen->BindReadFB(framebuffer);
-            return;
-
-        case LOCAL_GL_FRAMEBUFFER:
-            mScreen->BindFB(framebuffer);
-            return;
-
-        default:
-            // Nothing we care about, likely an error.
-            break;
-    }
-
-    raw_fBindFramebuffer(target, framebuffer);
 }
 
 void
 GLContext::fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x,
                            GLint y, GLsizei width, GLsizei height, GLint border)
 {
     if (!IsTextureSizeSafeToPassToDriver(target, width, height)) {
         // pass wrong values to cause the GL to generate GL_INVALID_VALUE.
@@ -2680,35 +2640,16 @@ GLContext::fCopyTexImage2D(GLenum target
     }
     AfterGLReadCall();
 }
 
 void
 GLContext::fGetIntegerv(GLenum pname, GLint* params)
 {
     switch (pname) {
-        // LOCAL_GL_FRAMEBUFFER_BINDING is equal to
-        // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT,
-        // so we don't need two cases.
-        case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT:
-            if (mScreen) {
-                *params = mScreen->GetDrawFB();
-            } else {
-                raw_fGetIntegerv(pname, params);
-            }
-            break;
-
-        case LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT:
-            if (mScreen) {
-                *params = mScreen->GetReadFB();
-            } else {
-                raw_fGetIntegerv(pname, params);
-            }
-            break;
-
         case LOCAL_GL_MAX_TEXTURE_SIZE:
             MOZ_ASSERT(mMaxTextureSize>0);
             *params = mMaxTextureSize;
             break;
 
         case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
             MOZ_ASSERT(mMaxCubeMapTextureSize>0);
             *params = mMaxCubeMapTextureSize;
@@ -2786,17 +2727,17 @@ GLContext::fReadPixels(GLint x, GLint y,
 
 void
 GLContext::fDeleteFramebuffers(GLsizei n, const GLuint* names)
 {
     if (mScreen) {
         // Notify mScreen which framebuffers we're deleting.
         // Otherwise, we will get framebuffer binding mispredictions.
         for (int i = 0; i < n; i++) {
-            mScreen->DeletingFB(names[i]);
+            mScreen->OnDeleteFramebuffer(names[i]);
         }
     }
 
     // Avoid crash by flushing before glDeleteFramebuffers. See bug 1194923.
     if (mNeedsFlushBeforeDeleteFB) {
         fFlush();
     }
 
@@ -2852,67 +2793,27 @@ GLContext::fTexImage2D(GLenum target, GL
         if (!WillTextureMapSucceed(width, height, internalformat, type)) {
             return;
         }
     }
 #endif
     raw_fTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
 }
 
-GLuint
-GLContext::GetDrawFB()
-{
-    if (mScreen)
-        return mScreen->GetDrawFB();
-
-    GLuint ret = 0;
-    GetUIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret);
-    return ret;
-}
-
-GLuint
-GLContext::GetReadFB()
-{
-    if (mScreen)
-        return mScreen->GetReadFB();
-
-    GLenum bindEnum = IsSupported(GLFeature::split_framebuffer)
-                        ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
-                        : LOCAL_GL_FRAMEBUFFER_BINDING;
-
-    GLuint ret = 0;
-    GetUIntegerv(bindEnum, &ret);
-    return ret;
-}
-
-GLuint
-GLContext::GetFB()
-{
-    if (mScreen) {
-        // This has a very important extra assert that checks that we're
-        // not accidentally ignoring a situation where the draw and read
-        // FBs differ.
-        return mScreen->GetFB();
-    }
-
-    GLuint ret = 0;
-    GetUIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret);
-    return ret;
-}
-
 bool
 GLContext::InitOffscreen(const gfx::IntSize& size, const SurfaceCaps& caps)
 {
     if (!CreateScreenBuffer(size, caps))
         return false;
 
-    if (!MakeCurrent()) {
+    if (!MakeCurrent())
         return false;
-    }
-    fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+
+    mScreen->BindAsFramebuffer();
+
     fScissor(0, 0, size.width, size.height);
     fViewport(0, 0, size.width, size.height);
 
     mCaps = mScreen->mCaps;
     MOZ_ASSERT(!mCaps.any);
 
     return true;
 }
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -3335,35 +3335,16 @@ public:
 
     /*
      * Return size of this offscreen context.
      *
      * Only valid if IsOffscreen() returns true.
      */
     const gfx::IntSize& OffscreenSize() const;
 
-    void BindFB(GLuint fb) {
-        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
-        MOZ_ASSERT(!fb || fIsFramebuffer(fb));
-    }
-
-    void BindDrawFB(GLuint fb) {
-        fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb);
-    }
-
-    void BindReadFB(GLuint fb) {
-        fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb);
-    }
-
-    GLuint GetDrawFB();
-
-    GLuint GetReadFB();
-
-    GLuint GetFB();
-
 private:
     void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
         switch (precisiontype) {
             case LOCAL_GL_LOW_FLOAT:
             case LOCAL_GL_MEDIUM_FLOAT:
             case LOCAL_GL_HIGH_FLOAT:
                 // Assume IEEE 754 precision
                 range[0] = 127;
@@ -3378,20 +3359,16 @@ private:
                 range[0] = 24;
                 range[1] = 24;
                 *precision = 0;
                 break;
         }
     }
 
 public:
-
-    void ForceDirtyScreen();
-    void CleanDirtyScreen();
-
     virtual GLenum GetPreferredARGB32Format() const { return LOCAL_GL_RGBA; }
 
     virtual GLenum GetPreferredEGLImageTextureTarget() const {
         return IsExtensionSupported(OES_EGL_image_external) ?
             LOCAL_GL_TEXTURE_EXTERNAL : LOCAL_GL_TEXTURE_2D;
     }
 
     virtual bool RenewSurface(widget::CompositorWidget* aWidget) { return false; }
@@ -3453,25 +3430,17 @@ public:
 
         return thisShared == otherShared;
     }
 
     bool InitOffscreen(const gfx::IntSize& size, const SurfaceCaps& caps);
 
 protected:
     // Note that it does -not- clear the resized buffers.
-    bool CreateScreenBuffer(const gfx::IntSize& size, const SurfaceCaps& caps) {
-        if (!IsOffscreenSizeAllowed(size))
-            return false;
-
-       return CreateScreenBufferImpl(size, caps);
-    }
-
-    bool CreateScreenBufferImpl(const gfx::IntSize& size,
-                                const SurfaceCaps& caps);
+    bool CreateScreenBuffer(const gfx::IntSize& size, const SurfaceCaps& caps);
 
 public:
     bool ResizeScreenBuffer(const gfx::IntSize& size);
 
 protected:
     SurfaceCaps mCaps;
 
 public:
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -141,267 +141,121 @@ GLScreenBuffer::GLScreenBuffer(GLContext
                                const SurfaceCaps& caps,
                                UniquePtr<SurfaceFactory> factory)
     : mGL(gl)
     , mCaps(caps)
     , mFactory(Move(factory))
     , mNeedsBlit(true)
     , mUserReadBufferMode(LOCAL_GL_BACK)
     , mUserDrawBufferMode(LOCAL_GL_BACK)
-    , mUserDrawFB(0)
-    , mUserReadFB(0)
-    , mInternalDrawFB(0)
-    , mInternalReadFB(0)
-#ifdef DEBUG
-    , mInInternalMode_DrawFB(true)
-    , mInInternalMode_ReadFB(true)
-#endif
+    , mBoundDrawFB(0)
+    , mBoundReadFB(0)
 { }
 
 GLScreenBuffer::~GLScreenBuffer()
 {
     mFactory = nullptr;
     mDraw = nullptr;
     mRead = nullptr;
 
     if (!mBack)
         return;
 
     // Detach mBack cleanly.
     mBack->Surf()->ProducerRelease();
 }
 
 void
-GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
+GLScreenBuffer::BindAsFramebuffer(const GLenum target) const
 {
-    GLuint drawFB = DrawFB();
-    GLuint readFB = ReadFB();
-
-    if (!gl->IsSupported(GLFeature::split_framebuffer)) {
-        MOZ_ASSERT(drawFB == readFB);
-        gl->raw_fBindFramebuffer(target, readFB);
-        return;
-    }
+    const auto drawFB = DrawFB();
+    const auto readFB = ReadFB();
 
     switch (target) {
     case LOCAL_GL_FRAMEBUFFER:
-        gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
-        gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
+        if (drawFB == readFB) {
+            mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, readFB);
+        } else {
+            mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
+            mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
+        }
         break;
 
     case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
-        gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
+        mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
         break;
 
     case LOCAL_GL_READ_FRAMEBUFFER_EXT:
-        gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
+        mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
         break;
 
     default:
         MOZ_CRASH("GFX: Bad `target` for BindFramebuffer.");
     }
 }
 
 void
-GLScreenBuffer::BindFB(GLuint fb)
+GLScreenBuffer::OnBindFramebuffer(const GLenum target, const GLuint fb)
 {
-    GLuint drawFB = DrawFB();
-    GLuint readFB = ReadFB();
-
-    mUserDrawFB = fb;
-    mUserReadFB = fb;
-    mInternalDrawFB = (fb == 0) ? drawFB : fb;
-    mInternalReadFB = (fb == 0) ? readFB : fb;
-
-    if (mInternalDrawFB == mInternalReadFB) {
-        mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
-    } else {
-        MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
-        mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
-        mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
-    }
-
-#ifdef DEBUG
-    mInInternalMode_DrawFB = false;
-    mInInternalMode_ReadFB = false;
-#endif
-}
-
-void
-GLScreenBuffer::BindDrawFB(GLuint fb)
-{
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
-
-    GLuint drawFB = DrawFB();
-    mUserDrawFB = fb;
-    mInternalDrawFB = (fb == 0) ? drawFB : fb;
-
-    mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
-
-#ifdef DEBUG
-    mInInternalMode_DrawFB = false;
-#endif
-}
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+        mBoundDrawFB = fb;
+        mBoundReadFB = fb;
+        break;
 
-void
-GLScreenBuffer::BindReadFB(GLuint fb)
-{
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
-
-    GLuint readFB = ReadFB();
-    mUserReadFB = fb;
-    mInternalReadFB = (fb == 0) ? readFB : fb;
-
-    mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
-
-#ifdef DEBUG
-    mInInternalMode_ReadFB = false;
-#endif
-}
+    case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
+        mBoundDrawFB = fb;
+        break;
 
-void
-GLScreenBuffer::BindFB_Internal(GLuint fb)
-{
-    mInternalDrawFB = mUserDrawFB = fb;
-    mInternalReadFB = mUserReadFB = fb;
-    mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
+    case LOCAL_GL_READ_FRAMEBUFFER_EXT:
+        mBoundReadFB = fb;
+        break;
 
-#ifdef DEBUG
-    mInInternalMode_DrawFB = true;
-    mInInternalMode_ReadFB = true;
-#endif
-}
-
-void
-GLScreenBuffer::BindDrawFB_Internal(GLuint fb)
-{
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
-
-    mInternalDrawFB = mUserDrawFB = fb;
-    mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
-
-#ifdef DEBUG
-    mInInternalMode_DrawFB = true;
-#endif
+    default:
+        break;
+    }
 }
 
 void
-GLScreenBuffer::BindReadFB_Internal(GLuint fb)
-{
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
-
-    mInternalReadFB = mUserReadFB = fb;
-    mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
-
-#ifdef DEBUG
-    mInInternalMode_ReadFB = true;
-#endif
-}
-
-
-GLuint
-GLScreenBuffer::GetDrawFB() const
-{
-#ifdef DEBUG
-    MOZ_ASSERT(mGL->IsCurrent());
-    MOZ_ASSERT(!mInInternalMode_DrawFB);
-
-    // Don't need a branch here, because:
-    // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6
-    // We use raw_ here because this is debug code and we need to see what
-    // the driver thinks.
-    GLuint actual = 0;
-    mGL->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
-
-    GLuint predicted = mInternalDrawFB;
-    if (predicted != actual) {
-        printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n",
-                      predicted, actual);
-        MOZ_ASSERT(false, "Draw FB binding misprediction!");
-    }
-#endif
-
-    return mUserDrawFB;
-}
-
-GLuint
-GLScreenBuffer::GetReadFB() const
+GLScreenBuffer::OnDeleteFramebuffer(const GLuint fb)
 {
-#ifdef DEBUG
-    MOZ_ASSERT(mGL->IsCurrent());
-    MOZ_ASSERT(!mInInternalMode_ReadFB);
-
-    // We use raw_ here because this is debug code and we need to see what
-    // the driver thinks.
-    GLuint actual = 0;
-    if (mGL->IsSupported(GLFeature::split_framebuffer))
-        mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
-    else
-        mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual);
-
-    GLuint predicted = mInternalReadFB;
-    if (predicted != actual) {
-        printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n",
-                      predicted, actual);
-        MOZ_ASSERT(false, "Read FB binding misprediction!");
+    if (fb == mBoundDrawFB) {
+        mBoundDrawFB = 0;
     }
-#endif
-
-    return mUserReadFB;
-}
-
-GLuint
-GLScreenBuffer::GetFB() const
-{
-    MOZ_ASSERT(GetDrawFB() == GetReadFB());
-    return GetDrawFB();
-}
-
-
-void
-GLScreenBuffer::DeletingFB(GLuint fb)
-{
-    if (fb == mInternalDrawFB) {
-        mInternalDrawFB = 0;
-        mUserDrawFB = 0;
-    }
-    if (fb == mInternalReadFB) {
-        mInternalReadFB = 0;
-        mUserReadFB = 0;
+    if (fb == mBoundReadFB) {
+        mBoundDrawFB = 0;
     }
 }
 
 
 void
 GLScreenBuffer::AfterDrawCall()
 {
-    if (mUserDrawFB != 0)
-        return;
-
-    RequireBlit();
+    if (mBoundDrawFB == DrawFB()) {
+        RequireBlit();
+    }
 }
 
 void
 GLScreenBuffer::BeforeReadCall()
 {
-    if (mUserReadFB != 0)
-        return;
-
-    AssureBlitted();
+    if (mBoundReadFB == ReadFB()) {
+        AssureBlitted();
+    }
 }
 
 bool
 GLScreenBuffer::CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x,
                                GLint y, GLsizei width, GLsizei height, GLint border)
 {
     SharedSurface* surf;
-    if (GetReadFB() == 0) {
+    if (mBoundReadFB == ReadFB()) {
         surf = SharedSurf();
     } else {
-        surf = mGL->mFBOMapping[GetReadFB()];
+        surf = mGL->mFBOMapping[mBoundReadFB];
     }
     if (surf) {
         return surf->CopyTexImage2D(target, level, internalformat,  x, y, width, height, border);
     }
 
     return false;
 }
 
@@ -412,20 +266,20 @@ GLScreenBuffer::ReadPixels(GLint x, GLin
                            GLvoid* pixels)
 {
     // If the currently bound framebuffer is backed by a SharedSurface
     // then it might want to override how we read pixel data from it.
     // This is normally only the default framebuffer, but we can also
     // have SharedSurfaces bound to other framebuffers when doing
     // readback for BasicLayers.
     SharedSurface* surf;
-    if (GetReadFB() == 0) {
+    if (mBoundReadFB == ReadFB()) {
         surf = SharedSurf();
     } else {
-        surf = mGL->mFBOMapping[GetReadFB()];
+        surf = mGL->mFBOMapping[mBoundReadFB];
     }
     if (surf) {
         return surf->ReadPixels(x, y, width, height, format, type, pixels);
     }
 
     return false;
 }
 
@@ -437,29 +291,29 @@ GLScreenBuffer::RequireBlit()
 
 void
 GLScreenBuffer::AssureBlitted()
 {
     if (!mNeedsBlit)
         return;
 
     if (mDraw) {
-        GLuint drawFB = DrawFB();
-        GLuint readFB = ReadFB();
+        GLuint srcFB = DrawFB();
+        GLuint destFB = ReadFB();
 
-        MOZ_ASSERT(drawFB != 0);
-        MOZ_ASSERT(drawFB != readFB);
+        MOZ_ASSERT(srcFB != 0);
+        MOZ_ASSERT(srcFB != destFB);
         MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
         MOZ_ASSERT(mDraw->mSize == mRead->Size());
 
         ScopedBindFramebuffer boundFB(mGL);
         ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
 
-        BindReadFB_Internal(drawFB);
-        BindDrawFB_Internal(readFB);
+        mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcFB);
+        mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destFB);
 
         if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
             const gfx::IntSize&  srcSize = mDraw->mSize;
             const gfx::IntSize& destSize = mRead->Size();
 
             mGL->raw_fBlitFramebuffer(0, 0,  srcSize.width,  srcSize.height,
                                       0, 0, destSize.width, destSize.height,
                                       LOCAL_GL_COLOR_BUFFER_BIT,
@@ -480,18 +334,16 @@ GLScreenBuffer::Morph(UniquePtr<SurfaceF
 {
     MOZ_RELEASE_ASSERT(newFactory, "newFactory must not be null");
     mFactory = Move(newFactory);
 }
 
 bool
 GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size)
 {
-    ScopedBindFramebuffer autoFB(mGL);
-
     const bool readNeedsUnlock = (mRead && SharedSurf());
     if (readNeedsUnlock) {
         SharedSurf()->UnlockProd();
     }
 
     surf->LockProd();
 
     if (mRead &&
@@ -531,25 +383,25 @@ GLScreenBuffer::Attach(SharedSurface* su
             mDraw = Move(draw);
 
         mRead = Move(read);
     }
 
     // Check that we're all set up.
     MOZ_ASSERT(SharedSurf() == surf);
 
+    BindAsFramebuffer();
+
     // Update the ReadBuffer mode.
     if (mGL->IsSupported(gl::GLFeature::read_buffer)) {
-        BindFB(0);
         mRead->SetReadBuffer(mUserReadBufferMode);
     }
 
     // Update the DrawBuffer mode.
     if (mGL->IsSupported(gl::GLFeature::draw_buffers)) {
-        BindFB(0);
         SetDrawBuffer(mUserDrawBufferMode);
     }
 
     RequireBlit();
 
     return true;
 }
 
@@ -661,30 +513,26 @@ GLScreenBuffer::CreateRead(SharedSurface
 
     return ReadBuffer::Create(gl, caps, formats, surf);
 }
 
 void
 GLScreenBuffer::SetDrawBuffer(GLenum mode)
 {
     MOZ_ASSERT(mGL->IsSupported(gl::GLFeature::draw_buffers));
-    MOZ_ASSERT(GetDrawFB() == 0);
-
-    if (!mGL->IsSupported(GLFeature::draw_buffers))
-        return;
 
     mUserDrawBufferMode = mode;
 
-    GLuint fb = mDraw ? mDraw->mFB : mRead->mFB;
+    const auto drawFB = DrawFB();
     GLenum internalMode;
 
     switch (mode) {
     case LOCAL_GL_BACK:
-        internalMode = (fb == 0) ? LOCAL_GL_BACK
-                                 : LOCAL_GL_COLOR_ATTACHMENT0;
+        internalMode = (drawFB == 0) ? LOCAL_GL_BACK
+                                     : LOCAL_GL_COLOR_ATTACHMENT0;
         break;
 
     case LOCAL_GL_NONE:
         internalMode = LOCAL_GL_NONE;
         break;
 
     default:
         MOZ_CRASH("GFX: Bad value.");
@@ -693,17 +541,16 @@ GLScreenBuffer::SetDrawBuffer(GLenum mod
     mGL->MakeCurrent();
     mGL->fDrawBuffers(1, &internalMode);
 }
 
 void
 GLScreenBuffer::SetReadBuffer(GLenum mode)
 {
     MOZ_ASSERT(mGL->IsSupported(gl::GLFeature::read_buffer));
-    MOZ_ASSERT(GetReadFB() == 0);
 
     mUserReadBufferMode = mode;
     mRead->SetReadBuffer(mUserReadBufferMode);
 }
 
 bool
 GLScreenBuffer::IsDrawFramebufferDefault() const
 {
--- a/gfx/gl/GLScreenBuffer.h
+++ b/gfx/gl/GLScreenBuffer.h
@@ -161,25 +161,18 @@ protected:
     UniquePtr<ReadBuffer> mRead;
 
     bool mNeedsBlit;
 
     GLenum mUserReadBufferMode;
     GLenum mUserDrawBufferMode;
 
     // Below are the parts that help us pretend to be framebuffer 0:
-    GLuint mUserDrawFB;
-    GLuint mUserReadFB;
-    GLuint mInternalDrawFB;
-    GLuint mInternalReadFB;
-
-#ifdef DEBUG
-    bool mInInternalMode_DrawFB;
-    bool mInInternalMode_ReadFB;
-#endif
+    GLuint mBoundDrawFB;
+    GLuint mBoundReadFB;
 
     GLScreenBuffer(GLContext* gl,
                    const SurfaceCaps& caps,
                    UniquePtr<SurfaceFactory> factory);
 
 public:
     virtual ~GLScreenBuffer();
 
@@ -223,17 +216,20 @@ public:
     void DeletingFB(GLuint fb);
 
     const gfx::IntSize& Size() const {
         MOZ_ASSERT(mRead);
         MOZ_ASSERT(!mDraw || mDraw->mSize == mRead->Size());
         return mRead->Size();
     }
 
-    void BindAsFramebuffer(GLContext* const gl, GLenum target) const;
+    void BindAsFramebuffer(GLenum target = LOCAL_GL_FRAMEBUFFER) const;
+
+    void OnBindFramebuffer(GLenum target, GLuint fb);
+    void OnDeleteFramebuffer(GLuint fb);
 
     void RequireBlit();
     void AssureBlitted();
     void AfterDrawCall();
     void BeforeReadCall();
 
     bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x,
                         GLint y, GLsizei width, GLsizei height, GLint border);
@@ -268,34 +264,16 @@ public:
 
 protected:
     bool Attach(SharedSurface* surf, const gfx::IntSize& size);
 
     bool CreateDraw(const gfx::IntSize& size, UniquePtr<DrawBuffer>* out_buffer);
     UniquePtr<ReadBuffer> CreateRead(SharedSurface* surf);
 
 public:
-    /* `fb` in these functions is the framebuffer the GLContext is hoping to
-     * bind. When this is 0, we intercept the call and bind our own
-     * framebuffers. As a client of these functions, just bind 0 when you want
-     * to draw to the default framebuffer/'screen'.
-     */
-    void BindFB(GLuint fb);
-    void BindDrawFB(GLuint fb);
-    void BindReadFB(GLuint fb);
-    GLuint GetFB() const;
-    GLuint GetDrawFB() const;
-    GLuint GetReadFB() const;
-
-    // Here `fb` is the actual framebuffer you want bound. Binding 0 will
-    // bind the (generally useless) default framebuffer.
-    void BindFB_Internal(GLuint fb);
-    void BindDrawFB_Internal(GLuint fb);
-    void BindReadFB_Internal(GLuint fb);
-
     bool IsDrawFramebufferDefault() const;
     bool IsReadFramebufferDefault() const;
 };
 
 } // namespace gl
 } // namespace mozilla
 
 #endif  // SCREEN_BUFFER_H_
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -58,44 +58,44 @@ ScopedGLState::UnwrapImpl()
 
 
 /* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and BindUserFB. */
 
 void
 ScopedBindFramebuffer::Init()
 {
     if (mGL->IsSupported(GLFeature::split_framebuffer)) {
-        mOldReadFB = mGL->GetReadFB();
-        mOldDrawFB = mGL->GetDrawFB();
+        mOldReadFB = mGL->GetIntAs<GLuint>(LOCAL_GL_READ_FRAMEBUFFER_BINDING);
+        mOldDrawFB = mGL->GetIntAs<GLuint>(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING);
     } else {
-        mOldReadFB = mOldDrawFB = mGL->GetFB();
+        mOldReadFB = mOldDrawFB = mGL->GetIntAs<GLuint>(LOCAL_GL_FRAMEBUFFER_BINDING);
     }
 }
 
 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL)
     : ScopedGLWrapper<ScopedBindFramebuffer>(aGL)
 {
     Init();
 }
 
 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB)
     : ScopedGLWrapper<ScopedBindFramebuffer>(aGL)
 {
     Init();
-    mGL->BindFB(aNewFB);
+    mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aNewFB);
 }
 
 void
 ScopedBindFramebuffer::UnwrapImpl()
 {
     if (mOldReadFB == mOldDrawFB) {
-        mGL->BindFB(mOldDrawFB);
+        mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOldDrawFB);
     } else {
-        mGL->BindDrawFB(mOldDrawFB);
-        mGL->BindReadFB(mOldReadFB);
+        mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, mOldDrawFB);
+        mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, mOldReadFB);
     }
 }
 
 
 /* ScopedBindTextureUnit ******************************************************/
 
 ScopedBindTextureUnit::ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit)
     : ScopedGLWrapper<ScopedBindTextureUnit>(aGL)
--- a/gfx/gl/SharedSurface.cpp
+++ b/gfx/gl/SharedSurface.cpp
@@ -63,27 +63,25 @@ SharedSurface::ProdCopy(SharedSurface* s
 
         if (dest->mAttachType == AttachmentType::GLTexture) {
             GLuint destTex = dest->ProdTexture();
             GLenum destTarget = dest->ProdTextureTarget();
 
             gl->BlitHelper()->BlitFramebufferToTexture(0, destTex,
                                                        src->mSize,
                                                        dest->mSize,
-                                                       destTarget,
-                                                       true);
+                                                       destTarget);
         } else if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
             GLuint destRB = dest->ProdRenderbuffer();
             ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
 
             gl->BlitHelper()->BlitFramebufferToFramebuffer(0,
                                                            destWrapper.FB(),
                                                            src->mSize,
-                                                           dest->mSize,
-                                                           true);
+                                                           dest->mSize);
         } else {
             MOZ_CRASH("GFX: Unhandled dest->mAttachType 1.");
         }
 
         if (srcNeedsUnlock)
             src->UnlockProd();
 
         if (origNeedsRelock)
@@ -108,27 +106,25 @@ SharedSurface::ProdCopy(SharedSurface* s
 
         if (src->mAttachType == AttachmentType::GLTexture) {
             GLuint srcTex = src->ProdTexture();
             GLenum srcTarget = src->ProdTextureTarget();
 
             gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, 0,
                                                        src->mSize,
                                                        dest->mSize,
-                                                       srcTarget,
-                                                       !!gl->Screen());
+                                                       srcTarget);
         } else if (src->mAttachType == AttachmentType::GLRenderbuffer) {
             GLuint srcRB = src->ProdRenderbuffer();
             ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
 
             gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(),
                                                            0,
                                                            src->mSize,
-                                                           dest->mSize,
-                                                           true);
+                                                           dest->mSize);
         } else {
             MOZ_CRASH("GFX: Unhandled src->mAttachType 2.");
         }
 
         if (destNeedsUnlock)
             dest->UnlockProd();
 
         if (origNeedsRelock)
@@ -444,20 +440,17 @@ ScopedReadbackFB::ScopedReadbackFB(Share
                     mSurfToLock = origLocked;
                     mSurfToLock->UnlockProd();
                 }
 
                 mSurfToUnlock = src;
                 mSurfToUnlock->LockProd();
             }
 
-            // TODO: This should just be BindFB, but we don't have
-            // the patch for this yet. (bug 1045955)
-            MOZ_ASSERT(mGL->Screen());
-            mGL->Screen()->BindReadFB_Internal(0);
+            mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
             break;
         }
     default:
         MOZ_CRASH("GFX: Unhandled `mAttachType`.");
     }
 
     if (src->NeedsIndirectReads()) {
         mGL->fGenTextures(1, &mTempTex);