Bug 997374 - Check FB status in GLScreenBuffer. - r=bjacob
authorJeff Gilbert <jgilbert@mozilla.com>
Mon, 28 Apr 2014 18:11:14 -0700
changeset 181050 c8871dd41a1025feb43dbb4a52192781cbb81300
parent 181049 527c58711da128cbd5a5017f673a61da18c72150
child 181051 07196a58650f09d38bfb34ad56588a9878a48259
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersbjacob
bugs997374
milestone32.0a1
Bug 997374 - Check FB status in GLScreenBuffer. - r=bjacob
gfx/gl/GLScreenBuffer.cpp
gfx/gl/GLScreenBuffer.h
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -376,17 +376,17 @@ GLScreenBuffer::Morph(SurfaceFactory_GL*
         return;
 
     SurfaceStream* newStream = SurfaceStream::CreateForType(streamType, mGL, mStream);
     MOZ_ASSERT(newStream);
 
     mStream = newStream;
 }
 
-void
+bool
 GLScreenBuffer::Attach(SharedSurface* surface, const gfx::IntSize& size)
 {
     ScopedBindFramebuffer autoFB(mGL);
 
     SharedSurface_GL* surf = SharedSurface_GL::Cast(surface);
     if (mRead && SharedSurf())
         SharedSurf()->UnlockProd();
 
@@ -395,52 +395,60 @@ GLScreenBuffer::Attach(SharedSurface* su
     if (mRead &&
         surf->AttachType() == SharedSurf()->AttachType() &&
         size == Size())
     {
         // Same size, same type, ready for reuse!
         mRead->Attach(surf);
     } else {
         // Else something changed, so resize:
-        DrawBuffer* draw = CreateDraw(size);  // Can be null.
+        DrawBuffer* draw = nullptr;
+        bool drawOk = CreateDraw(size, &draw);  // Can be null.
+
         ReadBuffer* read = CreateRead(surf);
-        MOZ_ASSERT(read); // Should never fail if SwapProd succeeded.
+        bool readOk = !!read;
+
+        if (!drawOk || !readOk) {
+            delete draw;
+            delete read;
+            return false;
+        }
 
         delete mDraw;
         delete mRead;
 
         mDraw = draw;
         mRead = read;
     }
 
     // Check that we're all set up.
     MOZ_ASSERT(SharedSurf() == surf);
 
     if (!PreserveBuffer()) {
         // DiscardFramebuffer here could help perf on some mobile platforms.
     }
+
+    return true;
 }
 
 bool
 GLScreenBuffer::Swap(const gfx::IntSize& size)
 {
     SharedSurface* nextSurf = mStream->SwapProducer(mFactory, size);
     if (!nextSurf) {
         SurfaceFactory_Basic basicFactory(mGL, mFactory->Caps());
         nextSurf = mStream->SwapProducer(&basicFactory, size);
         if (!nextSurf)
           return false;
 
         NS_WARNING("SwapProd failed for sophisticated Factory type, fell back to Basic.");
     }
     MOZ_ASSERT(nextSurf);
 
-    Attach(nextSurf, size);
-
-    return true;
+    return Attach(nextSurf, size);
 }
 
 bool
 GLScreenBuffer::PublishFrame(const gfx::IntSize& size)
 {
     AssureBlitted();
 
     bool good = Swap(size);
@@ -449,28 +457,27 @@ GLScreenBuffer::PublishFrame(const gfx::
 
 bool
 GLScreenBuffer::Resize(const gfx::IntSize& size)
 {
     SharedSurface* surface = mStream->Resize(mFactory, size);
     if (!surface)
         return false;
 
-    Attach(surface, size);
-    return true;
+    return Attach(surface, size);
 }
 
-DrawBuffer*
-GLScreenBuffer::CreateDraw(const gfx::IntSize& size)
+bool
+GLScreenBuffer::CreateDraw(const gfx::IntSize& size, DrawBuffer** out_buffer)
 {
     GLContext* gl = mFactory->GL();
     const GLFormats& formats = mFactory->Formats();
     const SurfaceCaps& caps = mFactory->DrawCaps();
 
-    return DrawBuffer::Create(gl, caps, formats, size);
+    return DrawBuffer::Create(gl, caps, formats, size, out_buffer);
 }
 
 ReadBuffer*
 GLScreenBuffer::CreateRead(SharedSurface_GL* surf)
 {
     GLContext* gl = mFactory->GL();
     const GLFormats& formats = mFactory->Formats();
     const SurfaceCaps& caps = mFactory->ReadCaps();
@@ -503,27 +510,31 @@ GLScreenBuffer::Readback(SharedSurface_G
   delete buffer;
 
   if (needsSwap) {
       src->UnlockProd();
       SharedSurf()->LockProd();
   }
 }
 
-DrawBuffer*
+bool
 DrawBuffer::Create(GLContext* const gl,
                    const SurfaceCaps& caps,
                    const GLFormats& formats,
-                   const gfx::IntSize& size)
+                   const gfx::IntSize& size,
+                   DrawBuffer** out_buffer)
 {
+    MOZ_ASSERT(out_buffer);
+    *out_buffer = nullptr;
+
     if (!caps.color) {
         MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil);
 
         // Nothing is needed.
-        return nullptr;
+        return true;
     }
 
     GLuint colorMSRB = 0;
     GLuint depthRB   = 0;
     GLuint stencilRB = 0;
 
     GLuint* pColorMSRB = caps.antialias ? &colorMSRB : nullptr;
     GLuint* pDepthRB   = caps.depth     ? &depthRB   : nullptr;
@@ -547,19 +558,25 @@ DrawBuffer::Create(GLContext* const gl,
     }
 
     CreateRenderbuffersForOffscreen(gl, formats, size, caps.antialias,
                                     pColorMSRB, pDepthRB, pStencilRB);
 
     GLuint fb = 0;
     gl->fGenFramebuffers(1, &fb);
     gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb);
-    MOZ_ASSERT(gl->IsFramebufferComplete(fb));
+
+    ScopedDeletePtr<DrawBuffer> buffer;
+    buffer = new DrawBuffer(gl, size, fb, colorMSRB, depthRB, stencilRB);
 
-    return new DrawBuffer(gl, size, fb, colorMSRB, depthRB, stencilRB);
+    if (!gl->IsFramebufferComplete(fb))
+        return false;
+
+    *out_buffer = buffer.forget();
+    return true;
 }
 
 DrawBuffer::~DrawBuffer()
 {
     mGL->MakeCurrent();
 
     GLuint fb = mFB;
     GLuint rbs[] = {
@@ -619,21 +636,25 @@ ReadBuffer::Create(GLContext* gl,
     }
     MOZ_ASSERT(colorTex || colorRB);
 
     GLuint fb = 0;
     gl->fGenFramebuffers(1, &fb);
     gl->AttachBuffersToFB(colorTex, colorRB, depthRB, stencilRB, fb, target);
     gl->mFBOMapping[fb] = surf;
 
-    MOZ_ASSERT(gl->IsFramebufferComplete(fb));
 
-    return new ReadBuffer(gl,
-                          fb, depthRB, stencilRB,
-                          surf);
+    ScopedDeletePtr<ReadBuffer> buffer;
+    buffer = new ReadBuffer(gl,
+                            fb, depthRB, stencilRB,
+                            surf);
+    if (!gl->IsFramebufferComplete(fb))
+        return nullptr;
+
+    return buffer.forget();
 }
 
 ReadBuffer::~ReadBuffer()
 {
     mGL->MakeCurrent();
 
     GLuint fb = mFB;
     GLuint rbs[] = {
--- a/gfx/gl/GLScreenBuffer.h
+++ b/gfx/gl/GLScreenBuffer.h
@@ -41,21 +41,23 @@ namespace mozilla {
 namespace gl {
 
 class DrawBuffer
 {
 protected:
     typedef struct gfx::SurfaceCaps SurfaceCaps;
 
 public:
-    // Infallible, may return null if unneeded.
-    static DrawBuffer* Create(GLContext* const gl,
-                              const SurfaceCaps& caps,
-                              const GLFormats& formats,
-                              const gfx::IntSize& size);
+    // Fallible!
+    // But it may return true with *out_buffer==nullptr if unneeded.
+    static bool Create(GLContext* const gl,
+                       const SurfaceCaps& caps,
+                       const GLFormats& formats,
+                       const gfx::IntSize& size,
+                       DrawBuffer** out_buffer);
 
 protected:
     GLContext* const mGL;
     const gfx::IntSize mSize;
     const GLuint mFB;
     const GLuint mColorMSRB;
     const GLuint mDepthRB;
     const GLuint mStencilRB;
@@ -277,19 +279,19 @@ protected:
 public:
     bool PublishFrame(const gfx::IntSize& size);
 
     bool Resize(const gfx::IntSize& size);
 
     void Readback(SharedSurface_GL* src, gfx::DataSourceSurface* dest);
 
 protected:
-    void Attach(SharedSurface* surface, const gfx::IntSize& size);
+    bool Attach(SharedSurface* surface, const gfx::IntSize& size);
 
-    DrawBuffer* CreateDraw(const gfx::IntSize& size);
+    bool CreateDraw(const gfx::IntSize& size, DrawBuffer** out_buffer);
     ReadBuffer* CreateRead(SharedSurface_GL* 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'.
      */