Bug 778453 - Limit the framebuffer rect size to prevent crash. r=BenWa, a=leo+
authorJerry Shih <hshih@mozilla.com>
Wed, 31 Jul 2013 09:33:13 -0400
changeset 119825 aff662053ee8
parent 119824 35cb56244e74
child 119826 5317a86d17a2
push id1014
push userryanvm@gmail.com
push date2013-07-31 13:34 +0000
reviewersBenWa, leo
bugs778453
milestone18.1
Bug 778453 - Limit the framebuffer rect size to prevent crash. r=BenWa, a=leo+
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -188,18 +188,29 @@ ContainerRender(Container* aContainer,
   nsIntRect cachedScissor = aContainer->gl()->ScissorRect();
   aContainer->gl()->PushScissorRect();
   aContainer->mSupportsComponentAlphaChildren = false;
 
   float opacity = aContainer->GetEffectiveOpacity();
   const gfx3DMatrix& transform = aContainer->GetEffectiveTransform();
   bool needsFramebuffer = aContainer->UseIntermediateSurface();
   if (needsFramebuffer) {
+    nsIntRect framebufferRect = visibleRect;
+    // 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 framebufferRect) 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.
+    // This gives us a lower resolution rendering of the intermediate surface (children layers).
+    // See bug 827170 for a discussion.
+    GLint maxTexSize;
+    aContainer->gl()->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTexSize);
+    framebufferRect.width = std::min(framebufferRect.width, maxTexSize);
+    framebufferRect.height = std::min(framebufferRect.height, maxTexSize);
+
     LayerManagerOGL::InitMode mode = LayerManagerOGL::InitModeClear;
-    nsIntRect framebufferRect = visibleRect;
     if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 && 
         (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
     {
       // don't need a background, we're going to paint all opaque stuff
       aContainer->mSupportsComponentAlphaChildren = true;
       mode = LayerManagerOGL::InitModeNone;
     } else {
       const gfx3DMatrix& transform3D = aContainer->GetEffectiveTransform();
@@ -217,21 +228,27 @@ ContainerRender(Container* aContainer,
         framebufferRect.y += transform.y0;
         aContainer->mSupportsComponentAlphaChildren = gfxPlatform::GetPlatform()->UsesSubpixelAATextRendering();
       }
     }
 
     aContainer->gl()->PushViewportRect();
     framebufferRect -= childOffset;
     if (!aManager->CompositingDisabled()) {
-      aManager->CreateFBOWithTexture(framebufferRect,
+      // Skip this layer when create FBO failed. Bug 867226
+      if(!aManager->CreateFBOWithTexture(framebufferRect,
                                      mode,
                                      aPreviousFrameBuffer,
                                      &frameBuffer,
-                                     &containerSurface);
+                                     &containerSurface)) {
+        aContainer->gl()->PopViewportRect();
+        aContainer->gl()->PopScissorRect();
+        aContainer->gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
+        return;
+      }
     }
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
   } else {
     frameBuffer = aPreviousFrameBuffer;
     aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
       (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
   }
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -1348,17 +1348,17 @@ GetFrameBufferInternalFormat(GLContext* 
                              nsIWidget* aWidget)
 {
   if (aCurrentFrameBuffer == 0) { // default framebuffer
     return aWidget->GetGLFrameBufferFormat();
   }
   return LOCAL_GL_RGBA;
 }
 
-void
+bool
 LayerManagerOGL::CreateFBOWithTexture(const nsIntRect& aRect, InitMode aInit,
                                       GLuint aCurrentFrameBuffer,
                                       GLuint *aFBO, GLuint *aTexture)
 {
   GLuint tex, fbo;
 
   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
   mGLContext->fGenTextures(1, &tex);
@@ -1430,40 +1430,50 @@ LayerManagerOGL::CreateFBOWithTexture(co
   mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
                                     LOCAL_GL_COLOR_ATTACHMENT0,
                                     mFBOTextureTarget,
                                     tex,
                                     0);
 
   // Making this call to fCheckFramebufferStatus prevents a crash on
   // PowerVR. See bug 695246.
+  //
+  // Return false instead of abort when create FBO failed. Bug 867226
   GLenum result = mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
   if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
     nsAutoCString msg;
     msg.Append("Framebuffer not complete -- error 0x");
     msg.AppendInt(result, 16);
     msg.Append(", mFBOTextureTarget 0x");
     msg.AppendInt(mFBOTextureTarget, 16);
     msg.Append(", aRect.width ");
     msg.AppendInt(aRect.width);
     msg.Append(", aRect.height ");
     msg.AppendInt(aRect.height);
-    NS_RUNTIMEABORT(msg.get());
+    NS_WARNING(msg.get());
+
+    mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+    mGLContext->fDeleteFramebuffers(1, &fbo);
+    mGLContext->fDeleteTextures(1, &tex);
+
+    return false;
   }
 
   SetupPipeline(aRect.width, aRect.height, DontApplyWorldTransform);
   mGLContext->fScissor(0, 0, aRect.width, aRect.height);
 
   if (aInit == InitModeClear) {
     mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
     mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
   }
 
   *aFBO = fbo;
   *aTexture = tex;
+
+  return true;
 }
 
 already_AddRefed<ShadowThebesLayer>
 LayerManagerOGL::CreateShadowThebesLayer()
 {
   if (LayerManagerOGL::mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return nullptr;
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -245,17 +245,17 @@ public:
   };
 
   /* Create a FBO backed by a texture; will leave the FBO
    * bound.  Note that the texture target type will be
    * of the type returned by FBOTextureTarget; different
    * shaders are required to sample from the different
    * texture types.
    */
-  void CreateFBOWithTexture(const nsIntRect& aRect, InitMode aInit,
+  bool CreateFBOWithTexture(const nsIntRect& aRect, InitMode aInit,
                             GLuint aCurrentFrameBuffer,
                             GLuint *aFBO, GLuint *aTexture);
 
   GLuint QuadVBO() { return mQuadVBO; }
   GLintptr QuadVBOVertexOffset() { return 0; }
   GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; }
   GLintptr QuadVBOFlippedTexCoordOffset() { return sizeof(float)*8*2; }