Bug 1125491 - Only lock the image during the initial decode. r=tn
authorSeth Fowler <seth@mozilla.com>
Sat, 24 Jan 2015 20:26:40 -0800
changeset 225602 91836c912d096b846bb3f63ab2afebb75be1f5ec
parent 225601 f6e51e022084bacb9087d2df168010042b33dc65
child 225603 e43c8f946c95d975cbdcfc5bcb99661985159b6a
push id28170
push userphilringnalda@gmail.com
push dateSun, 25 Jan 2015 19:44:07 +0000
treeherdermozilla-central@fa91879c8428 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1125491
milestone38.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 1125491 - Only lock the image during the initial decode. r=tn
image/src/Decoder.cpp
image/src/Decoder.h
image/src/RasterImage.cpp
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -31,16 +31,17 @@ Decoder::Decoder(RasterImage* aImage)
   , mDecodeFlags(0)
   , mBytesDecoded(0)
   , mSendPartialInvalidations(false)
   , mDataDone(false)
   , mDecodeDone(false)
   , mDataError(false)
   , mDecodeAborted(false)
   , mImageIsTransient(false)
+  , mImageIsLocked(false)
   , mFrameCount(0)
   , mFailCode(NS_OK)
   , mNeedsNewFrame(false)
   , mNeedsToFlushData(false)
   , mInitialized(false)
   , mSizeDecode(false)
   , mInFrame(false)
   , mIsAnimated(false)
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -184,16 +184,29 @@ public:
    * short-lived images in this case.
    */
   void SetImageIsTransient(bool aIsTransient)
   {
     MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
     mImageIsTransient = aIsTransient;
   }
 
+  /**
+   * Set whether the image is locked for the lifetime of this decoder. We lock
+   * the image during our initial decode to ensure that we don't evict any
+   * surfaces before we realize that the image is animated.
+   */
+  void SetImageIsLocked()
+  {
+    MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
+    mImageIsLocked = true;
+  }
+
+  bool ImageIsLocked() const { return mImageIsLocked; }
+
   size_t BytesDecoded() const { return mBytesDecoded; }
 
   // The amount of time we've spent inside Write() so far for this decoder.
   TimeDuration DecodeTime() const { return mDecodeTime; }
 
   // The number of times Write() has been called so far for this decoder.
   uint32_t ChunkCount() const { return mChunkCount; }
 
@@ -440,16 +453,17 @@ protected:
   uint32_t mDecodeFlags;
   size_t mBytesDecoded;
   bool mSendPartialInvalidations;
   bool mDataDone;
   bool mDecodeDone;
   bool mDataError;
   bool mDecodeAborted;
   bool mImageIsTransient;
+  bool mImageIsLocked;
 
 private:
   uint32_t mFrameCount; // Number of frames, including anything in-progress
 
   nsresult mFailCode;
 
   struct NewFrameData
   {
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -1360,16 +1360,25 @@ RasterImage::CreateDecoder(const Maybe<n
 
   MOZ_ASSERT(decoder, "Should have a decoder now");
 
   // Initialize the decoder.
   decoder->SetSizeDecode(!aSize);
   decoder->SetSendPartialInvalidations(!mHasBeenDecoded);
   decoder->SetImageIsTransient(mTransient);
   decoder->SetDecodeFlags(DecodeFlags(aFlags));
+
+  if (!mHasBeenDecoded && aSize) {
+    // Lock the image while we're decoding, so that it doesn't get evicted from
+    // the SurfaceCache before we have a chance to realize that it's animated.
+    // The corresponding unlock happens in FinalizeDecoder.
+    LockImage();
+    decoder->SetImageIsLocked();
+  }
+
   if (aSize) {
     // We already have the size; tell the decoder so it can preallocate a
     // frame.  By default, we create an ARGB frame with no offset. If decoders
     // need a different type, they need to ask for it themselves.
     // XXX(seth): Note that we call SetSize() and NeedNewFrame() with the
     // image's intrinsic size, but AllocateFrame with our target size.
     decoder->SetSize(mSize, mOrientation);
     decoder->NeedNewFrame(0, 0, 0, aSize->width, aSize->height,
@@ -1539,21 +1548,16 @@ RasterImage::Decode(DecodeStrategy aStra
   }
 
   if (aSize) {
     // This isn't a size decode (which doesn't send any early notifications), so
     // send out notifications right away.
     NotifyProgress(decoder->TakeProgress(),
                    decoder->TakeInvalidRect(),
                    decoder->GetDecodeFlags());
-
-    // Lock the image while we're decoding, so that it doesn't get evicted from
-    // the SurfaceCache before we have a chance to realize that it's animated.
-    // The corresponding unlock happens in FinalizeDecoder.
-    LockImage();
   }
 
   if (mHasSourceData) {
     // If we have all the data, we can sync decode if requested.
     if (aStrategy == DecodeStrategy::SYNC_FOR_SMALL_IMAGES) {
       PROFILER_LABEL_PRINTF("DecodePool", "SyncDecodeIfSmall",
         js::ProfileEntry::Category::GRAPHICS, "%s", GetURIString().get());
       DecodePool::Singleton()->SyncDecodeIfSmall(decoder);
@@ -2040,18 +2044,18 @@ RasterImage::FinalizeDecoder(Decoder* aD
     // Detect errors.
     if (aDecoder->HasError() && !aDecoder->WasAborted()) {
       DoError();
     } else if (wasSize && !mHasSize) {
       DoError();
     }
   }
 
-  if (!wasSize) {
-    // Unlock the image, balancing the LockImage call we made in Decode().
+  if (aDecoder->ImageIsLocked()) {
+    // Unlock the image, balancing the LockImage call we made in CreateDecoder.
     UnlockImage();
   }
 
   // If we were a size decode and a full decode was requested, now's the time.
   if (done && wasSize && mWantFullDecode) {
     mWantFullDecode = false;
     RequestDecode();
   }