Bug 735378 - Cache temporary composite surfaces - r=bgirard
☠☠ backed out by 53c21294270d ☠ ☠
authorJeff Gilbert <jgilbert@mozilla.com>
Thu, 22 Mar 2012 15:04:25 -0700
changeset 90081 636349fa2e0961e29ea2c10cce03e01a8098f097
parent 90080 8ba795535c176539ff9adeeb966a10df1b2eae23
child 90082 017f6dd98dc029ae381907ce3bfbec9502ef51d5
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbgirard
bugs735378
milestone14.0a1
Bug 735378 - Cache temporary composite surfaces - r=bgirard
gfx/layers/basic/BasicLayers.cpp
gfx/layers/d3d10/CanvasLayerD3D10.cpp
gfx/layers/d3d10/CanvasLayerD3D10.h
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/d3d9/CanvasLayerD3D9.h
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -1076,16 +1076,40 @@ protected:
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<mozilla::gl::GLContext> mGLContext;
   mozilla::RefPtr<mozilla::gfx::DrawTarget> mDrawTarget;
   
   PRUint32 mCanvasFramebuffer;
 
   bool mGLBufferIsPremultiplied;
   bool mNeedsYFlip;
+
+  nsRefPtr<gfxImageSurface> mCachedTempSurface;
+  gfxIntSize mCachedSize;
+  gfxImageFormat mCachedFormat;
+
+  gfxImageSurface* GetTempSurface(const gfxIntSize& aSize, const gfxImageFormat aFormat)
+  {
+    if (!mCachedTempSurface ||
+        aSize.width != mCachedSize.width ||
+        aSize.height != mCachedSize.height ||
+        aFormat != mCachedFormat)
+    {
+      mCachedTempSurface = new gfxImageSurface(aSize, aFormat);
+      mCachedSize = aSize;
+      mCachedFormat = aFormat;
+    }
+
+    return mCachedTempSurface;
+  }
+
+  void DiscardTempSurface()
+  {
+    mCachedTempSurface = nsnull;
+  }
 };
 
 void
 BasicCanvasLayer::Initialize(const Data& aData)
 {
   NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!");
 
   if (aData.mSurface) {
@@ -1134,34 +1158,40 @@ BasicCanvasLayer::UpdateSurface(gfxASurf
                    "Destination surface must be ImageSurface type");
       return;
     }
 
     // We need to read from the GLContext
     mGLContext->MakeCurrent();
 
 #if defined (MOZ_X11) && defined (MOZ_EGL_XRENDER_COMPOSITE)
-    mGLContext->fFinish();
+    mGLContext->GuaranteeResolve();
     gfxASurface* offscreenSurface = mGLContext->GetOffscreenPixmapSurface();
 
     // XRender can only blend premuliplied alpha, so only allow xrender
     // path if we have premultiplied alpha or opaque content.
     if (offscreenSurface && (mGLBufferIsPremultiplied || (GetContentFlags() & CONTENT_OPAQUE))) {  
         mSurface = offscreenSurface;
         mNeedsYFlip = false;
+        return;
     }
-    else
 #endif
-    {
-    nsRefPtr<gfxImageSurface> isurf = aDestSurface ?
-        static_cast<gfxImageSurface*>(aDestSurface) :
-        new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
-                            (GetContentFlags() & CONTENT_OPAQUE)
-                              ? gfxASurface::ImageFormatRGB24
-                              : gfxASurface::ImageFormatARGB32);
+    gfxImageSurface* isurf = nsnull;
+    if (aDestSurface) {
+      DiscardTempSurface();
+      isurf = static_cast<gfxImageSurface*>(aDestSurface);
+    } else {
+      nsIntSize size(mBounds.width, mBounds.height);
+      gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
+                                ? gfxASurface::ImageFormatRGB24
+                                : gfxASurface::ImageFormatARGB32;
+
+      isurf = GetTempSurface(size, format);
+    }
+
 
     if (!isurf || isurf->CairoStatus() != 0) {
       return;
     }
 
     NS_ASSERTION(isurf->Stride() == mBounds.width * 4, "gfxImageSurface stride isn't what we expect!");
 
     PRUint32 currentFramebuffer = 0;
@@ -1189,17 +1219,16 @@ BasicCanvasLayer::UpdateSurface(gfxASurf
       gfxUtils::PremultiplyImageSurface(isurf);
 
     // stick our surface into mSurface, so that the Paint() path is the same
     if (!aDestSurface) {
       mSurface = isurf;
     }
   }
 }
-}
 
 void
 BasicCanvasLayer::Paint(gfxContext* aContext)
 {
   if (IsHidden())
     return;
   UpdateSurface();
   FireDidTransactionCallback();
--- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp
@@ -167,20 +167,23 @@ CanvasLayerD3D10::UpdateSurface()
     
     HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
 
     if (FAILED(hr)) {
       NS_WARNING("Failed to map CanvasLayer texture.");
       return;
     }
 
+    const bool stridesMatch = map.RowPitch == mBounds.width * 4;
+
     PRUint8 *destination;
-    if (map.RowPitch != mBounds.width * 4) {
-      destination = new PRUint8[mBounds.width * mBounds.height * 4];
+    if (!stridesMatch) {
+      destination = GetTempBlob(mBounds.width * mBounds.height * 4);
     } else {
+      DiscardTempBlob();
       destination = (PRUint8*)map.pData;
     }
 
     mGLContext->MakeCurrent();
 
     PRUint32 currentFramebuffer = 0;
 
     mGLContext->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&currentFramebuffer);
@@ -199,23 +202,22 @@ CanvasLayerD3D10::UpdateSurface()
                                            mBounds.width, mBounds.height,
                                            tmpSurface);
     tmpSurface = nsnull;
 
     // Put back the previous framebuffer binding.
     if (currentFramebuffer != mCanvasFramebuffer)
       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, currentFramebuffer);
 
-    if (map.RowPitch != mBounds.width * 4) {
+    if (!stridesMatch) {
       for (int y = 0; y < mBounds.height; y++) {
         memcpy((PRUint8*)map.pData + map.RowPitch * y,
                destination + mBounds.width * 4 * y,
                mBounds.width * 4);
       }
-      delete [] destination;
     }
     mTexture->Unmap(0);
   } else if (mSurface) {
     RECT r;
     r.left = 0;
     r.top = 0;
     r.right = mBounds.width;
     r.bottom = mBounds.height;
--- a/gfx/layers/d3d10/CanvasLayerD3D10.h
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.h
@@ -82,13 +82,31 @@ private:
 
   PRUint32 mCanvasFramebuffer;
 
   bool mDataIsPremultiplied;
   bool mNeedsYFlip;
   bool mIsD2DTexture;
   bool mUsingSharedTexture;
   bool mHasAlpha;
+
+  nsAutoArrayPtr<PRUint8> mCachedTempBlob;
+  PRUint32 mCachedTempBlob_Size;
+
+  PRUint8* GetTempBlob(const PRUint32 aSize)
+  {
+      if (!mCachedTempBlob || aSize != mCachedTempBlob_Size) {
+          mCachedTempBlob = new PRUint8[aSize];
+          mCachedTempBlob_Size = aSize;
+      }
+
+      return mCachedTempBlob;
+  }
+
+  void DiscardTempBlob()
+  {
+      mCachedTempBlob = nsnull;
+  }
 };
 
 } /* layers */
 } /* mozilla */
 #endif /* GFX_CANVASLAYERD3D10_H */
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -108,20 +108,23 @@ CanvasLayerD3D9::UpdateSurface()
     LockTextureRectD3D9 textureLock(mTexture);
     if (!textureLock.HasLock()) {
       NS_WARNING("Failed to lock CanvasLayer texture.");
       return;
     }
 
     D3DLOCKED_RECT r = textureLock.GetLockRect();
 
+    const bool stridesMatch = r.Pitch == mBounds.width * 4;
+
     PRUint8 *destination;
-    if (r.Pitch != mBounds.width * 4) {
-      destination = new PRUint8[mBounds.width * mBounds.height * 4];
+    if (!stridesMatch) {
+      destination = GetTempBlob(mBounds.width * mBounds.height * 4);
     } else {
+      DiscardTempBlob();
       destination = (PRUint8*)r.pBits;
     }
 
     mGLContext->MakeCurrent();
 
     PRUint32 currentFramebuffer = 0;
 
     mGLContext->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&currentFramebuffer);
@@ -140,23 +143,22 @@ CanvasLayerD3D9::UpdateSurface()
                                            mBounds.width, mBounds.height,
                                            tmpSurface);
     tmpSurface = nsnull;
 
     // Put back the previous framebuffer binding.
     if (currentFramebuffer != mCanvasFramebuffer)
       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, currentFramebuffer);
 
-    if (r.Pitch != mBounds.width * 4) {
+    if (!stridesMatch) {
       for (int y = 0; y < mBounds.height; y++) {
         memcpy((PRUint8*)r.pBits + r.Pitch * y,
                destination + mBounds.width * 4 * y,
                mBounds.width * 4);
       }
-      delete [] destination;
     }
   } else {
     RECT r;
     r.left = mBounds.x;
     r.top = mBounds.y;
     r.right = mBounds.XMost();
     r.bottom = mBounds.YMost();
 
--- a/gfx/layers/d3d9/CanvasLayerD3D9.h
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.h
@@ -87,16 +87,34 @@ protected:
   nsRefPtr<IDirect3DTexture9> mTexture;
   RefPtr<gfx::DrawTarget> mDrawTarget;
 
   PRUint32 mCanvasFramebuffer;
 
   bool mDataIsPremultiplied;
   bool mNeedsYFlip;
   bool mHasAlpha;
+
+  nsAutoArrayPtr<PRUint8> mCachedTempBlob;
+  PRUint32 mCachedTempBlob_Size;
+
+  PRUint8* GetTempBlob(const PRUint32 aSize)
+  {
+      if (!mCachedTempBlob || aSize != mCachedTempBlob_Size) {
+          mCachedTempBlob = new PRUint8[aSize];
+          mCachedTempBlob_Size = aSize;
+      }
+
+      return mCachedTempBlob;
+  }
+
+  void DiscardTempBlob()
+  {
+      mCachedTempBlob = nsnull;
+  }
 };
 
 // NB: eventually we'll have separate shadow canvas2d and shadow
 // canvas3d layers, but currently they look the same from the
 // perspective of the compositor process
 class ShadowCanvasLayerD3D9 : public ShadowCanvasLayer,
                              public LayerD3D9
 {
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -173,52 +173,56 @@ CanvasLayerOGL::UpdateSurface()
   if (mPixmap) {
     return;
   }
 #endif
 
   if (mCanvasGLContext &&
       mCanvasGLContext->GetContextType() == gl()->GetContextType())
   {
+    DiscardTempSurface();
+
     // Can texture share, just make sure it's resolved first
     mCanvasGLContext->MakeCurrent();
     mCanvasGLContext->GuaranteeResolve();
 
     if (gl()->BindOffscreenNeedsTexture(mCanvasGLContext) &&
         mTexture == 0)
     {
       mOGLManager->MakeCurrent();
       MakeTexture();
     }
   } else {
     nsRefPtr<gfxASurface> updatedAreaSurface;
+
     if (mDrawTarget) {
       // TODO: This is suboptimal - We should have direct handling for the surface types instead of
       // going via a gfxASurface.
       updatedAreaSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
     } else if (mCanvasSurface) {
       updatedAreaSurface = mCanvasSurface;
     } else if (mCanvasGLContext) {
+      gfxIntSize size(mBounds.width, mBounds.height);
       nsRefPtr<gfxImageSurface> updatedAreaImageSurface =
-        new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
-                            gfxASurface::ImageFormatARGB32);
+        GetTempSurface(size, gfxASurface::ImageFormatARGB32);
+
       mCanvasGLContext->ReadPixelsIntoImageSurface(0, 0,
                                                    mBounds.width,
                                                    mBounds.height,
                                                    updatedAreaImageSurface);
+
       updatedAreaSurface = updatedAreaImageSurface;
     }
 
     mOGLManager->MakeCurrent();
-    mLayerProgram =
-      gl()->UploadSurfaceToTexture(updatedAreaSurface,
-                                   mBounds,
-                                   mTexture,
-                                   false,
-                                   nsIntPoint(0, 0));
+    mLayerProgram = gl()->UploadSurfaceToTexture(updatedAreaSurface,
+                                                 mBounds,
+                                                 mTexture,
+                                                 false,
+                                                 nsIntPoint(0, 0));
   }
 }
 
 void
 CanvasLayerOGL::RenderLayer(int aPreviousDestination,
                             const nsIntPoint& aOffset)
 {
   UpdateSurface();
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -89,16 +89,40 @@ protected:
   GLuint mTexture;
 
   bool mDelayedUpdates;
   bool mGLBufferIsPremultiplied;
   bool mNeedsYFlip;
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
   GLXPixmap mPixmap;
 #endif
+
+  nsRefPtr<gfxImageSurface> mCachedTempSurface;
+  gfxIntSize mCachedSize;
+  gfxImageFormat mCachedFormat;
+
+  gfxImageSurface* GetTempSurface(const gfxIntSize& aSize, const gfxImageFormat aFormat)
+  {
+    if (!mCachedTempSurface ||
+        aSize.width != mCachedSize.width ||
+        aSize.height != mCachedSize.height ||
+        aFormat != mCachedFormat)
+    {
+      mCachedTempSurface = new gfxImageSurface(aSize, aFormat);
+      mCachedSize = aSize;
+      mCachedFormat = aFormat;
+    }
+
+    return mCachedTempSurface;
+  }
+
+  void DiscardTempSurface()
+  {
+    mCachedTempSurface = nsnull;
+  }
 };
 
 // NB: eventually we'll have separate shadow canvas2d and shadow
 // canvas3d layers, but currently they look the same from the
 // perspective of the compositor process
 class ShadowCanvasLayerOGL : public ShadowCanvasLayer,
                              public LayerOGL
 {