Bug 985017 - Part 2: Cache a gfxImageSurface for the drawing path. r=seth, a=1.4+
authorMichael Wu <mwu@mozilla.com>
Wed, 02 Apr 2014 21:32:54 -0400
changeset 192548 60c9101d530466d7f108a3e52023450c910dc97b
parent 192547 1266d70f29514d9b55b9ed9b8376d311e3891346
child 192549 69078cc67a5db75728698a05dcf37c0014913614
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseth, 1
bugs985017
milestone30.0a2
Bug 985017 - Part 2: Cache a gfxImageSurface for the drawing path. r=seth, a=1.4+
image/src/imgFrame.cpp
image/src/imgFrame.h
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -304,16 +304,17 @@ nsresult imgFrame::Optimize()
         mImageSurface = nullptr;
         mOptSurface = nullptr;
 #ifdef USE_WIN_SURFACE
         mWinSurface = nullptr;
 #endif
 #ifdef XP_MACOSX
         mQuartzSurface = nullptr;
 #endif
+        mDrawSurface = nullptr;
 
         // We just dumped most of our allocated memory, so tell the discard
         // tracker that we're not using any at all.
         if (mInformedDiscardTracker) {
           DiscardTracker::InformAllocation(-4 * mSize.width * mSize.height);
           mInformedDiscardTracker = false;
         }
 
@@ -363,31 +364,33 @@ nsresult imgFrame::Optimize()
     gfxContext ctx(surf);
     ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
     ctx.SetSource(mImageSurface);
     ctx.Paint();
 
     mImageSurface = surf;
     mVBuf = buf;
     mFormat = optFormat;
+    mDrawSurface = nullptr;
   }
 #else
   if (mOptSurface == nullptr)
     mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat);
 #endif
 
   if (mOptSurface) {
     mVBuf = nullptr;
     mImageSurface = nullptr;
 #ifdef USE_WIN_SURFACE
     mWinSurface = nullptr;
 #endif
 #ifdef XP_MACOSX
     mQuartzSurface = nullptr;
 #endif
+    mDrawSurface = nullptr;
   }
 
   return NS_OK;
 }
 
 static void
 DoSingleColorFastPath(gfxContext*    aContext,
                       const gfxRGBA& aSinglePixelColor,
@@ -495,21 +498,38 @@ bool imgFrame::Draw(gfxContext *aContext
   gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(),
                     mSize.height + aPadding.TopBottom());
   gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height);
   gfxRect fill = aFill;
 
   NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(),
                "We must be allowed to sample *some* source pixels!");
 
-  nsRefPtr<gfxASurface> surf;
-  if (!mSinglePixel) {
-    surf = ThebesSurface();
-    if (!surf)
+  nsRefPtr<gfxASurface> surf = CachedThebesSurface();
+  VolatileBufferPtr<unsigned char> ref(mVBuf);
+  if (!mSinglePixel && !surf) {
+    if (ref.WasBufferPurged()) {
       return false;
+    }
+
+    surf = mDrawSurface;
+    if (!surf) {
+      long stride = gfxImageSurface::ComputeStride(mSize, mFormat);
+      nsRefPtr<gfxImageSurface> imgSurf =
+        new gfxImageSurface(ref, mSize, stride, mFormat);
+#if defined(XP_MACOSX)
+      surf = mDrawSurface = new gfxQuartzImageSurface(imgSurf);
+#else
+      surf = mDrawSurface = imgSurf;
+#endif
+    }
+    if (!surf || surf->CairoStatus()) {
+      mDrawSurface = nullptr;
+      return true;
+    }
   }
 
   bool doTile = !imageRect.Contains(sourceRect) &&
                 !(aImageFlags & imgIContainer::FLAG_CLAMP);
   SurfaceWithFormat surfaceResult =
     SurfaceForDrawing(doPadding, doPartialDecode, doTile, aPadding,
                       userSpaceToImageSpace, fill, subimage, sourceRect,
                       imageRect, surf);
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -107,45 +107,53 @@ public:
     return NS_OK;
   }
 
   bool IsSinglePixel()
   {
     return mSinglePixel;
   }
 
-  gfxASurface* ThebesSurface()
+  gfxASurface* CachedThebesSurface()
   {
     if (mOptSurface)
       return mOptSurface;
 #if defined(XP_WIN)
     if (mWinSurface)
       return mWinSurface;
 #elif defined(XP_MACOSX)
     if (mQuartzSurface)
       return mQuartzSurface;
 #endif
     if (mImageSurface)
       return mImageSurface;
+    return nullptr;
+  }
+
+  gfxASurface* ThebesSurface()
+  {
+    gfxASurface *sur = CachedThebesSurface();
+    if (sur)
+      return sur;
     if (mVBuf) {
       mozilla::VolatileBufferPtr<uint8_t> ref(mVBuf);
       if (ref.WasBufferPurged())
         return nullptr;
 
-      gfxImageSurface *sur =
+      gfxImageSurface *imgSur =
         LockedImageSurface::CreateSurface(mVBuf, mSize, mFormat);
 #if defined(XP_MACOSX)
       // Manually addref and release to make sure the cairo surface isn't lost
-      NS_ADDREF(sur);
-      gfxQuartzImageSurface *quartzSur = new gfxQuartzImageSurface(sur);
+      NS_ADDREF(imgSur);
+      gfxQuartzImageSurface *quartzSur = new gfxQuartzImageSurface(imgSur);
       // quartzSur does not hold on to the gfxImageSurface
-      NS_RELEASE(sur);
+      NS_RELEASE(imgSur);
       return quartzSur;
 #else
-      return sur;
+      return imgSur;
 #endif
     }
     // We can return null here if we're single pixel optimized
     // or a paletted image. However, one has to check for paletted
     // image data first before attempting to get a surface, so
     // this is only valid for single pixel optimized images
     MOZ_ASSERT(mSinglePixel, "No image surface and not a single pixel!");
     return nullptr;
@@ -189,16 +197,18 @@ private: // data
   nsRefPtr<gfxImageSurface> mImageSurface;
   nsRefPtr<gfxASurface> mOptSurface;
 #if defined(XP_WIN)
   nsRefPtr<gfxWindowsSurface> mWinSurface;
 #elif defined(XP_MACOSX)
   nsRefPtr<gfxQuartzImageSurface> mQuartzSurface;
 #endif
 
+  nsRefPtr<gfxASurface> mDrawSurface;
+
   nsIntSize    mSize;
   nsIntPoint   mOffset;
 
   nsIntRect    mDecoded;
 
   mutable mozilla::Mutex mDirtyMutex;
 
   // The palette and image data for images that are paletted, since Cairo