Bug 1382104 - Update CompositorOGL handling of offscreen GLContext default framebuffers. - r=mattwoodrow draft
authorJeff Gilbert <jgilbert@mozilla.com>
Fri, 21 Jul 2017 16:23:23 -0700
changeset 649181 28b10bf80399cc9a9e07979c33e87a4f06758533
parent 649180 bf83e8c198e5a3aff9cb83fa63713cfda13a7827
child 649182 8cf4775680ca8a507c4a80c9bfad137d9d16bc1b
push id74978
push userbmo:jgilbert@mozilla.com
push dateFri, 18 Aug 2017 19:07:35 +0000
reviewersmattwoodrow
bugs1382104
milestone57.0a1
Bug 1382104 - Update CompositorOGL handling of offscreen GLContext default framebuffers. - r=mattwoodrow MozReview-Commit-ID: BMT1zVq601z
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/layers/opengl/CompositingRenderTargetOGL.cpp
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
gfx/layers/opengl/GLBlitTextureImageHelper.cpp
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -2962,10 +2962,20 @@ GLContext::ResetSyncCallCount(const char
     if (ShouldSpew()) {
         printf_stderr("On %s, mSyncGLCallCount = %" PRIu64 "\n",
                        resetReason, mSyncGLCallCount);
     }
 
     mSyncGLCallCount = 0;
 }
 
+void
+GLContext::BindDefaultFramebuffer()
+{
+    if (mScreen) {
+        mScreen->BindAsFramebuffer();
+        return;
+    }
+    fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, GetDefaultFramebuffer());
+}
+
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -301,16 +301,18 @@ public:
 
     /**
      * Get the default framebuffer for this context.
      */
     virtual GLuint GetDefaultFramebuffer() {
         return 0;
     }
 
+    void BindDefaultFramebuffer();
+
 protected:
     bool mIsOffscreen;
     bool mContextLost;
     const bool mUseTLSIsCurrent;
 
     /**
      * mVersion store the OpenGL's version, multiplied by 100. For example, if
      * the context is an OpenGL 2.1 context, mVersion value will be 210.
--- a/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
+++ b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
@@ -40,18 +40,17 @@ CompositingRenderTargetOGL::BindRenderTa
   if (mInitParams.mStatus != InitParams::INITIALIZED) {
     InitializeImpl();
     if (mInitParams.mInit == INIT_MODE_CLEAR) {
       needsClear = true;
       mClearOnBind = false;
     }
   } else {
     MOZ_ASSERT(mInitParams.mStatus == InitParams::INITIALIZED);
-    GLuint fbo = mFBO == 0 ? mGL->GetDefaultFramebuffer() : mFBO;
-    mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fbo);
+    mCompositor->BindFramebuffer(mFBO);
     GLenum result = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
       // The main framebuffer (0) of non-offscreen contexts
       // might be backed by a EGLSurface that needs to be renewed.
       if (mFBO == 0 && !mGL->IsOffscreen()) {
         mGL->RenewSurface(mCompositor->GetWidget());
         result = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
       }
@@ -89,25 +88,21 @@ CompositingRenderTargetOGL::Dump(Composi
 }
 #endif
 
 void
 CompositingRenderTargetOGL::InitializeImpl()
 {
   MOZ_ASSERT(mInitParams.mStatus == InitParams::READY);
 
-  //TODO: call mGL->GetBackbufferFB(), use that
-  GLuint fbo = mFBO == 0 ? mGL->GetDefaultFramebuffer() : mFBO;
-  mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fbo);
-  mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
-                              LOCAL_GL_COLOR_ATTACHMENT0,
-                              mInitParams.mFBOTextureTarget,
-                              mTextureHandle,
-                              0);
-
+  mCompositor->BindFramebuffer(mFBO);
+  if (mFBO) {
+    mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
+                               mInitParams.mFBOTextureTarget, mTextureHandle, 0);
+  }
   // Making this call to fCheckFramebufferStatus prevents a crash on
   // PowerVR. See bug 695246.
   GLenum result = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
   if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
     nsAutoCString msg;
     msg.AppendPrintf("Framebuffer not complete -- error 0x%x, aFBOTextureTarget 0x%x, mFBO %d, mTextureHandle %d, aRect.width %d, aRect.height %d",
                       result, mInitParams.mFBOTextureTarget, mFBO, mTextureHandle, mInitParams.mSize.width, mInitParams.mSize.height);
     NS_ERROR(msg.get());
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -189,18 +189,16 @@ CompositorOGL::CleanupResources()
 
   for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin();
        iter != mPrograms.end();
        iter++) {
     delete iter->second;
   }
   mPrograms.clear();
 
-  ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
-
   if (mQuadVBO) {
     ctx->fDeleteBuffers(1, &mQuadVBO);
     mQuadVBO = 0;
   }
 
   if (mTriangleVBO) {
     ctx->fDeleteBuffers(1, &mTriangleVBO);
     mTriangleVBO = 0;
@@ -304,17 +302,17 @@ CompositorOGL::Initialize(nsCString* con
                               0,
                               LOCAL_GL_RGBA,
                               LOCAL_GL_UNSIGNED_BYTE,
                               nullptr);
 
       // unbind this texture, in preparation for binding it to the FBO
       mGLContext->fBindTexture(target, 0);
 
-      mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO);
+      const gl::ScopedBindFramebuffer bindFB(mGLContext, testFBO);
       mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
                                         LOCAL_GL_COLOR_ATTACHMENT0,
                                         target,
                                         testTexture,
                                         0);
 
       if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
           LOCAL_GL_FRAMEBUFFER_COMPLETE)
@@ -336,19 +334,16 @@ CompositorOGL::Initialize(nsCString* con
       *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_TEXTURE_TARGET";
       return false;
     }
   } else {
     // not trying to work around driver bugs, so TEXTURE_2D should just work
     mFBOTextureTarget = LOCAL_GL_TEXTURE_2D;
   }
 
-  // back to default framebuffer, to avoid confusion
-  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
-
   if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
     /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
      * extension -- the EXT variant does not provide support for
      * texture rectangle access inside GLSL (sampler2DRect,
      * texture2DRect).
      */
     if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)){
       *out_failureReason = "FEATURE_FAILURE_OPENGL_ARB_EXT";
@@ -710,16 +705,26 @@ CompositorOGL::CreateFBOWithTexture(cons
                                     GLuint *aFBO, GLuint *aTexture,
                                     gfx::IntSize* aAllocSize)
 {
   *aTexture = CreateTexture(aRect, aCopyFromSource, aSourceFrameBuffer,
                             aAllocSize);
   mGLContext->fGenFramebuffers(1, aFBO);
 }
 
+void
+CompositorOGL::BindFramebuffer(const GLuint aFB) const
+{
+  if (aFB) {
+    mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aFB);
+  } else {
+    mGLContext->BindDefaultFramebuffer();
+  }
+}
+
 GLuint
 CompositorOGL::CreateTexture(const IntRect& aRect, bool aCopyFromSource,
                              GLuint aSourceFrameBuffer, IntSize* aAllocSize)
 {
   // we're about to create a framebuffer backed by textures to use as an intermediate
   // surface. What to do if its size (as given by aRect) would exceed the
   // maximum texture size supported by the GL? The present code chooses the compromise
   // of just clamping the framebuffer's size to the max supported size.
@@ -734,17 +739,17 @@ CompositorOGL::CreateTexture(const IntRe
 
   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
   mGLContext->fGenTextures(1, &tex);
   mGLContext->fBindTexture(mFBOTextureTarget, tex);
 
   if (aCopyFromSource) {
     GLuint curFBO = mCurrentRenderTarget->GetFBO();
     if (curFBO != aSourceFrameBuffer) {
-      mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer);
+      BindFramebuffer(aSourceFrameBuffer);
     }
 
     // We're going to create an RGBA temporary fbo.  But to
     // CopyTexImage() from the current framebuffer, the framebuffer's
     // format has to be compatible with the new texture's.  So we
     // check the format of the framebuffer here and take a slow path
     // if it's incompatible.
     GLenum format =
@@ -1650,23 +1655,17 @@ CompositorOGL::CopyToTarget(DrawTarget* 
   GLint width = rect.Width();
   GLint height = rect.Height();
 
   if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) {
     NS_ERROR("Widget size too big - integer overflow!");
     return;
   }
 
-  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
-
-  if (!mGLContext->IsGLES()) {
-    // GLES2 promises that binding to any custom FBO will attach
-    // to GL_COLOR_ATTACHMENT0 attachment point.
-    mGLContext->fReadBuffer(LOCAL_GL_BACK);
-  }
+  mGLContext->BindDefaultFramebuffer();
 
   RefPtr<DataSourceSurface> source =
         Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
   if (NS_WARN_IF(!source)) {
     return;
   }
 
   ReadPixelsIntoDataSurface(mGLContext, source);
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -210,16 +210,18 @@ public:
   }
 
   virtual void Pause() override;
   virtual bool Resume() override;
 
   GLContext* gl() const { return mGLContext; }
   GLContext* GetGLContext() const override { return mGLContext; }
 
+  void BindFramebuffer(GLuint aFB) const;
+
   /**
    * Clear the program state. This must be called
    * before operating on the GLContext directly. */
   void ResetProgram();
 
   gfx::SurfaceFormat GetFBOFormat() const {
     return gfx::SurfaceFormat::R8G8B8A8;
   }
--- a/gfx/layers/opengl/GLBlitTextureImageHelper.cpp
+++ b/gfx/layers/opengl/GLBlitTextureImageHelper.cpp
@@ -41,18 +41,17 @@ void
 GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const gfx::IntRect& aSrcRect,
                                            TextureImage *aDst, const gfx::IntRect& aDstRect)
 {
     GLContext *gl = mCompositor->gl();
 
     if (!aSrc || !aDst || aSrcRect.IsEmpty() || aDstRect.IsEmpty())
         return;
 
-    int savedFb = 0;
-    gl->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb);
+    const ScopedBindFramebuffer saveFB(gl);
 
     ScopedGLState scopedScissorTestState(gl, LOCAL_GL_SCISSOR_TEST, false);
     ScopedGLState scopedBlendState(gl, LOCAL_GL_BLEND, false);
 
     // 2.0 means scale up by two
     float blitScaleX = float(aDstRect.Width()) / float(aSrcRect.Width());
     float blitScaleY = float(aDstRect.Height()) / float(aSrcRect.Height());
 
@@ -156,18 +155,16 @@ GLBlitTextureImageHelper::BlitTextureIma
 
             gl->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
 
         } while (aSrc->NextTile());
     } while (aDst->NextTile());
 
     // unbind the previous texture from the framebuffer
     SetBlitFramebufferForDestTexture(0);
-
-    gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb);
 }
 
 void
 GLBlitTextureImageHelper::SetBlitFramebufferForDestTexture(GLuint aTexture)
 {
     GLContext *gl = mCompositor->gl();
     if (!mBlitFramebuffer) {
         gl->fGenFramebuffers(1, &mBlitFramebuffer);