Bug 888499 - Mark frames as dirty in a threadsafe way when imgFrame::ImageUpdated is called on them, and clear that dirty bit when we're drawing. r=seth
authorJoe Drew <joe@drew.ca>
Thu, 04 Jul 2013 14:45:57 -0400
changeset 137462 6bc751e34867b78facdf9be40bb49cfafea04229
parent 137461 a9d6d86a8090de3367904ba1fa4696c3275ca3a3
child 137463 8e2e52c72e42031c7da46fc63b96aa46190b5be2
push id30551
push userjdrew@mozilla.com
push dateThu, 04 Jul 2013 18:47:15 +0000
treeherdermozilla-inbound@77c0bebf47ed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseth
bugs888499
milestone25.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 888499 - Mark frames as dirty in a threadsafe way when imgFrame::ImageUpdated is called on them, and clear that dirty bit when we're drawing. r=seth
image/src/Decoder.cpp
image/src/RasterImage.cpp
image/src/imgFrame.cpp
image/src/imgFrame.h
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -420,14 +420,14 @@ Decoder::NeedNewFrame(uint32_t framenum,
 }
 
 void
 Decoder::MarkFrameDirty()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mCurrentFrame) {
-    mCurrentFrame->MarkImageDataDirty();
+    mCurrentFrame->ApplyDirtToSurfaces();
   }
 }
 
 } // namespace image
 } // namespace mozilla
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -2689,16 +2689,18 @@ RasterImage::DrawWithPreDownscaleIfNeede
     }
   }
 
   nsIntMargin padding(framerect.y,
                       mSize.width - framerect.XMost(),
                       mSize.height - framerect.YMost(),
                       framerect.x);
 
+  frame->ApplyDirtToSurfaces();
+
   frame->Draw(aContext, aFilter, userSpaceToImageSpace, aFill, padding, subimage,
               aFlags);
 }
 
 //******************************************************************************
 /* [noscript] void draw(in gfxContext aContext,
  *                      in gfxGraphicsFilter aFilter,
  *                      [const] in gfxMatrix aUserSpaceToImageSpace,
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -32,16 +32,17 @@ static uint32_t gTotalDDBs = 0;
 static uint32_t gTotalDDBSize = 0;
 // only use up a maximum of 64MB in DDBs
 #define kMaxDDBSize (64*1024*1024)
 // and don't let anything in that's bigger than 4MB
 #define kMaxSingleDDBSize (4*1024*1024)
 
 #endif
 
+using namespace mozilla;
 using namespace mozilla::image;
 
 // Returns true if an image of aWidth x aHeight is allowed and legal.
 static bool AllowedImageSize(int32_t aWidth, int32_t aHeight)
 {
   // reject over-wide or over-tall images
   const int32_t k64KLimit = 0x0000FFFF;
   if (MOZ_UNLIKELY(aWidth > k64KLimit || aHeight > k64KLimit )) {
@@ -101,31 +102,33 @@ static bool ShouldUseImageSurfaces()
   }
 #endif
 
   return false;
 }
 
 imgFrame::imgFrame() :
   mDecoded(0, 0, 0, 0),
+  mDirtyMutex("imgFrame::mDirty"),
   mPalettedImageData(nullptr),
   mSinglePixelColor(0),
   mTimeout(100),
   mDisposalMethod(0), /* imgIContainer::kDisposeNotSpecified */
   mLockCount(0),
   mBlendMethod(1), /* imgIContainer::kBlendOver */
   mSinglePixel(false),
   mNeverUseDeviceSurface(false),
   mFormatChanged(false),
   mCompositingFailed(false),
   mNonPremult(false),
 #ifdef USE_WIN_SURFACE
   mIsDDBSurface(false),
 #endif
-  mInformedDiscardTracker(false)
+  mInformedDiscardTracker(false),
+  mDirty(false)
 {
   static bool hasCheckedOptimize = false;
   if (!hasCheckedOptimize) {
     if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) {
       gDisableOptimize = true;
     }
     hasCheckedOptimize = true;
   }
@@ -487,26 +490,36 @@ void imgFrame::Draw(gfxContext *aContext
                                subimage, sourceRect, imageRect, fill,
                                surfaceResult.mFormat, aFilter, aImageFlags);
   }
 }
 
 // This can be called from any thread, but not simultaneously.
 nsresult imgFrame::ImageUpdated(const nsIntRect &aUpdateRect)
 {
+  MutexAutoLock lock(mDirtyMutex);
+
   mDecoded.UnionRect(mDecoded, aUpdateRect);
 
   // clamp to bounds, in case someone sends a bogus updateRect (I'm looking at
   // you, gif decoder)
   nsIntRect boundsRect(mOffset, mSize);
   mDecoded.IntersectRect(mDecoded, boundsRect);
 
+  mDirty = true;
+
   return NS_OK;
 }
 
+bool imgFrame::GetIsDirty()
+{
+  MutexAutoLock lock(mDirtyMutex);
+  return mDirty;
+}
+
 nsIntRect imgFrame::GetRect() const
 {
   return nsIntRect(mOffset, mSize);
 }
 
 gfxASurface::gfxImageFormat imgFrame::GetFormat() const
 {
   return mFormat;
@@ -685,42 +698,47 @@ nsresult imgFrame::UnlockImageData()
   // cairo_image_surface data into a CGImage, so we have to call Flush() here.
   if (mQuartzSurface)
     mQuartzSurface->Flush();
 #endif
 
   return NS_OK;
 }
 
-void imgFrame::MarkImageDataDirty()
+void imgFrame::ApplyDirtToSurfaces()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (mImageSurface)
-    mImageSurface->Flush();
+  MutexAutoLock lock(mDirtyMutex);
+  if (mDirty) {
+    if (mImageSurface)
+      mImageSurface->Flush();
 
 #ifdef USE_WIN_SURFACE
-  if (mWinSurface)
-    mWinSurface->Flush();
+    if (mWinSurface)
+      mWinSurface->Flush();
 #endif
 
-  if (mImageSurface)
-    mImageSurface->MarkDirty();
+    if (mImageSurface)
+      mImageSurface->MarkDirty();
 
 #ifdef USE_WIN_SURFACE
-  if (mWinSurface)
-    mWinSurface->MarkDirty();
+    if (mWinSurface)
+      mWinSurface->MarkDirty();
 #endif
 
 #ifdef XP_MACOSX
-  // The quartz image surface (ab)uses the flush method to get the
-  // cairo_image_surface data into a CGImage, so we have to call Flush() here.
-  if (mQuartzSurface)
-    mQuartzSurface->Flush();
+    // The quartz image surface (ab)uses the flush method to get the
+    // cairo_image_surface data into a CGImage, so we have to call Flush() here.
+    if (mQuartzSurface)
+      mQuartzSurface->Flush();
 #endif
+
+    mDirty = false;
+  }
 }
 
 int32_t imgFrame::GetTimeout() const
 {
   // Ensure a minimal time between updates so we don't throttle the UI thread.
   // consider 0 == unspecified and make it fast but not too fast.  See bug
   // 125137, bug 139677, and bug 207059.  The behavior of recent IE and Opera
   // versions seems to be:
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -3,16 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef imgFrame_h
 #define imgFrame_h
 
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Mutex.h"
 #include "nsRect.h"
 #include "nsPoint.h"
 #include "nsSize.h"
 #include "gfxTypes.h"
 #include "nsID.h"
 #include "gfxContext.h"
 #include "gfxPattern.h"
 #include "gfxDrawable.h"
@@ -35,16 +36,17 @@ public:
   nsresult Optimize();
 
   void Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter,
             const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill,
             const nsIntMargin &aPadding, const nsIntRect &aSubimage,
             uint32_t aImageFlags = imgIContainer::FLAG_NONE);
 
   nsresult ImageUpdated(const nsIntRect &aUpdateRect);
+  bool GetIsDirty();
 
   nsIntRect GetRect() const;
   gfxASurface::gfxImageFormat GetFormat() const;
   bool GetNeedsBackground() const;
   uint32_t GetImageBytesPerRow() const;
   uint32_t GetImageDataLength() const;
   bool GetIsPaletted() const;
   bool GetHasAlpha() const;
@@ -65,17 +67,17 @@ public:
   void SetHasNoAlpha();
   void SetAsNonPremult(bool aIsNonPremult);
 
   bool GetCompositingFailed() const;
   void SetCompositingFailed(bool val);
 
   nsresult LockImageData();
   nsresult UnlockImageData();
-  void MarkImageDataDirty();
+  void ApplyDirtToSurfaces();
 
   nsresult GetSurface(gfxASurface **aSurface) const
   {
     *aSurface = ThebesSurface();
     NS_IF_ADDREF(*aSurface);
     return NS_OK;
   }
 
@@ -142,16 +144,18 @@ private: // data
   nsRefPtr<gfxQuartzImageSurface> mQuartzSurface;
 #endif
 
   nsIntSize    mSize;
   nsIntPoint   mOffset;
 
   nsIntRect    mDecoded;
 
+  mozilla::Mutex mDirtyMutex;
+
   // The palette and image data for images that are paletted, since Cairo
   // doesn't support these images.
   // The paletted data comes first, then the image data itself.
   // Total length is PaletteDataLength() + GetImageDataLength().
   uint8_t*     mPalettedImageData;
 
   // Note that the data stored in gfxRGBA is *non-alpha-premultiplied*.
   gfxRGBA      mSinglePixelColor;
@@ -172,16 +176,17 @@ private: // data
   bool mNonPremult;
 
   /** Have we called DiscardTracker::InformAllocation()? */
   bool mInformedDiscardTracker;
 
 #ifdef XP_WIN
   bool mIsDDBSurface;
 #endif
+  bool mDirty;
 };
 
 namespace mozilla {
 namespace image {
   // An RAII class to ensure it's easy to balance locks and unlocks on
   // imgFrames.
   class AutoFrameLocker
   {