Bug 572571 - Abort Core Animation rendering for windows that are too large. r=josh
authorBenoit Girard <b56girard@gmail.com>
Sun, 01 Aug 2010 19:15:25 -0400
changeset 71301 946a55feeb027b0b0e258c5606f5923e0f8b4a7d
parent 71300 1bc7e99950842908f127e7dc603b84492fc6107b
child 71302 d6ecab455b57148872b25b7fcd4748e68245777c
push id20527
push usermlamouri@mozilla.com
push dateMon, 20 Jun 2011 11:45:12 +0000
treeherdermozilla-central@aeed034b74d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjosh
bugs572571
milestone7.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 572571 - Abort Core Animation rendering for windows that are too large. r=josh
gfx/thebes/nsCoreAnimationSupport.h
gfx/thebes/nsCoreAnimationSupport.mm
--- a/gfx/thebes/nsCoreAnimationSupport.h
+++ b/gfx/thebes/nsCoreAnimationSupport.h
@@ -53,17 +53,18 @@ CGColorSpaceRef THEBES_API CreateSystemC
 struct _CGLPBufferObject;
 struct _CGLContextObject;
 class nsIOSurface;
 
 class THEBES_API nsCARenderer {
 public:
   nsCARenderer() : mCARenderer(nsnull), mPixelBuffer(nsnull), mOpenGLContext(nsnull),
                    mCGImage(nsnull), mCGData(nsnull), mIOSurface(nsnull), mFBO(nsnull),
-                   mIOTexture(nsnull) {}
+                   mIOTexture(nsnull), 
+                   mUnsupportedWidth(UINT32_MAX), mUnsupportedHeight(UINT32_MAX) {}
   ~nsCARenderer();
   nsresult SetupRenderer(void* aCALayer, int aWidth, int aHeight);
   nsresult Render(int aWidth, int aHeight, CGImageRef *aOutCAImage);
   bool isInit() { return mCARenderer != nsnull; }
   /*
    * Render the CALayer to an IOSurface. If no IOSurface
    * is attached then an internal pixel buffer will be
    * used.
@@ -80,16 +81,18 @@ private:
   void *mCARenderer;
   _CGLPBufferObject *mPixelBuffer;
   _CGLContextObject *mOpenGLContext;
   CGImageRef         mCGImage;
   void              *mCGData;
   nsIOSurface       *mIOSurface;
   uint32_t           mFBO;
   uint32_t           mIOTexture;
+  uint32_t           mUnsupportedWidth;
+  uint32_t           mUnsupportedHeight;
 };
 
 typedef uint32_t IOSurfaceID;
 
 class THEBES_API nsIOSurface {
 public:
   static nsIOSurface *CreateIOSurface(int aWidth, int aHeight); 
   static void ReleaseIOSurface(nsIOSurface *aIOSurface); 
--- a/gfx/thebes/nsCoreAnimationSupport.mm
+++ b/gfx/thebes/nsCoreAnimationSupport.mm
@@ -444,90 +444,109 @@ void nsCARenderer::Destroy() {
   mFBO = nsnull;
   mIOTexture = nsnull;
 }
 
 nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) {
   if (aWidth == 0 || aHeight == 0)
     return NS_ERROR_FAILURE;
 
+  if (aWidth == mUnsupportedWidth && 
+      aHeight == mUnsupportedHeight) {
+    return NS_ERROR_FAILURE;
+  }
+
   CALayer* layer = (CALayer*)aCALayer;
   CARenderer* caRenderer = nsnull;
 
   CGLPixelFormatAttribute attributes[] = {
     kCGLPFANoRecovery,
     kCGLPFAAccelerated,
     kCGLPFAPBuffer,
     kCGLPFADepthSize, (CGLPixelFormatAttribute)24,
     (CGLPixelFormatAttribute)0
   };
 
   if (!mIOSurface) {
     CGLError result = ::CGLCreatePBuffer(aWidth, aHeight,
                          GL_TEXTURE_2D, GL_RGBA, 0, &mPixelBuffer);
     if (result != kCGLNoError) {
+      mUnsupportedWidth = aWidth;
+      mUnsupportedHeight = aHeight;
       Destroy();
       return NS_ERROR_FAILURE;
     }
   }
 
   GLint screen;
   CGLPixelFormatObj format;
   if (::CGLChoosePixelFormat(attributes, &format, &screen) != kCGLNoError) {
+    mUnsupportedWidth = aWidth;
+    mUnsupportedHeight = aHeight;
     Destroy();
     return NS_ERROR_FAILURE;
   }
 
   if (::CGLCreateContext(format, nsnull, &mOpenGLContext) != kCGLNoError) {
+    mUnsupportedWidth = aWidth;
+    mUnsupportedHeight = aHeight;
     Destroy();
     return NS_ERROR_FAILURE;
   }
   ::CGLDestroyPixelFormat(format);
 
   caRenderer = [[CARenderer rendererWithCGLContext:mOpenGLContext 
                             options:nil] retain];
   mCARenderer = caRenderer;
   if (caRenderer == nil) {
+    mUnsupportedWidth = aWidth;
+    mUnsupportedHeight = aHeight;
     Destroy();
     return NS_ERROR_FAILURE;
   }
   [layer setBounds:CGRectMake(0, 0, aWidth, aHeight)];
   [layer setPosition:CGPointMake(aWidth/2.0, aHeight/2.0)];
   caRenderer.layer = layer;
   caRenderer.bounds = CGRectMake(0, 0, aWidth, aHeight);
 
   // We either target rendering to a CGImage or IOSurface.
   if (!mIOSurface) {
     mCGData = malloc(aWidth*aHeight*4);
     if (!mCGData) {
+      mUnsupportedWidth = aWidth;
+      mUnsupportedHeight = aHeight;
       Destroy();
     }
     memset(mCGData, 0, aWidth*aHeight*4);
 
     CGDataProviderRef dataProvider = nsnull;
     dataProvider = ::CGDataProviderCreateWithData(mCGData,
                                         mCGData, aHeight*aWidth*4, 
                                         cgdata_release_callback);
     if (!dataProvider) {
       cgdata_release_callback(mCGData, mCGData, aHeight*aWidth*4);
+      mUnsupportedWidth = aWidth;
+      mUnsupportedHeight = aHeight;
       Destroy();
       return NS_ERROR_FAILURE;
     }
 
     CGColorSpaceRef colorSpace = CreateSystemColorSpace();
 
     mCGImage = ::CGImageCreate(aWidth, aHeight, 8, 32, aWidth * 4, colorSpace, 
                 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
                 dataProvider, NULL, true, kCGRenderingIntentDefault);
 
     ::CGDataProviderRelease(dataProvider);
     if (colorSpace) {
       ::CGColorSpaceRelease(colorSpace);
     }
     if (!mCGImage) {
+      mUnsupportedWidth = aWidth;
+      mUnsupportedHeight = aHeight;
       Destroy();
       return NS_ERROR_FAILURE;
     }
   } else {
     CGLContextObj oldContext = ::CGLGetCurrentContext();
     ::CGLSetCurrentContext(mOpenGLContext);
 
     // Create the IOSurface mapped texture.
@@ -549,16 +568,18 @@ nsresult nsCARenderer::SetupRenderer(voi
 
     // Make sure that the Framebuffer configuration is supported on the client machine
     GLenum fboStatus;
     fboStatus = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
     if (fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT) {
       NS_ERROR("FBO not supported");
       if (oldContext)
         ::CGLSetCurrentContext(oldContext);
+      mUnsupportedWidth = aWidth;
+      mUnsupportedHeight = aHeight;
       Destroy();
       return NS_ERROR_FAILURE; 
     }
 
     if (oldContext)
       ::CGLSetCurrentContext(oldContext);
   }
 
@@ -572,16 +593,18 @@ nsresult nsCARenderer::SetupRenderer(voi
 
   // Render upside down to speed up CGContextDrawImage
   ::glTranslatef(0.0f, aHeight, 0.0);
   ::glScalef(1.0, -1.0, 1.0);
 
   GLenum result = ::glGetError();
   if (result != GL_NO_ERROR) {
     NS_ERROR("Unexpected OpenGL Error");
+    mUnsupportedWidth = aWidth;
+    mUnsupportedHeight = aHeight;
     Destroy();
     if (oldContext)
       ::CGLSetCurrentContext(oldContext);
     return NS_ERROR_FAILURE;
   }
 
   if (oldContext)
     ::CGLSetCurrentContext(oldContext);
@@ -630,16 +653,17 @@ nsresult nsCARenderer::Render(int aWidth
   if (renderer_width != aWidth || renderer_height != aHeight) {
     // XXX: This should be optimized to not rescale the buffer
     //      if we are resizing down.
     CALayer* caLayer = [caRenderer layer];
     Destroy();
     if (SetupRenderer(caLayer, aWidth, aHeight) != NS_OK) {
       return NS_ERROR_FAILURE;
     }
+
     caRenderer = (CARenderer*)mCARenderer;
   }
 
   CGLContextObj oldContext = ::CGLGetCurrentContext();
   ::CGLSetCurrentContext(mOpenGLContext);
   if (!mIOSurface) {
     ::CGLSetPBuffer(mOpenGLContext, mPixelBuffer, 0, 0, 0);
   }