Bug 1126490 - Part 1: Recover when catastrophic circumstances cause us to lose frames in RasterImage. r=tn, a=sledru
authorSeth Fowler <seth@mozilla.com>
Tue, 03 Feb 2015 16:34:54 -0800
changeset 243693 b1db02330579
parent 243692 18d9d9422db6
child 243694 3be92206bfd0
push id4440
push userryanvm@gmail.com
push date2015-02-05 16:07 +0000
treeherdermozilla-beta@74c4e5bdde78 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, sledru
bugs1126490
milestone36.0
Bug 1126490 - Part 1: Recover when catastrophic circumstances cause us to lose frames in RasterImage. r=tn, a=sledru
image/src/RasterImage.cpp
image/src/RasterImage.h
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -791,16 +791,21 @@ RasterImage::CopyFrame(uint32_t aWhichFr
   nsIntRect intFrameRect = frameRef->GetRect();
   Rect rect(intFrameRect.x, intFrameRect.y,
             intFrameRect.width, intFrameRect.height);
   if (frameRef->IsSinglePixel()) {
     target->FillRect(rect, ColorPattern(frameRef->SinglePixelColor()),
                      DrawOptions(1.0f, CompositionOp::OP_SOURCE));
   } else {
     RefPtr<SourceSurface> srcSurf = frameRef->GetSurface();
+    if (!srcSurf) {
+      RecoverFromLossOfFrames();
+      return nullptr;
+    }
+
     Rect srcRect(0, 0, intFrameRect.width, intFrameRect.height);
     target->DrawSurface(srcSurf, srcRect, rect);
   }
 
   target->Flush();
   surf->Unmap();
 
   return surf;
@@ -2051,16 +2056,45 @@ RasterImage::SyncDecode()
   if (mDecoder) {
     DecodePool::Singleton()->RequestDecode(this);
   }
 
   // All good if no errors!
   return mError ? NS_ERROR_FAILURE : NS_OK;
 }
 
+void
+RasterImage::RecoverFromLossOfFrames()
+{
+  if (!mHasSize) {
+    return;
+  }
+
+  NS_WARNING("An imgFrame became invalid. Attempting to recover...");
+
+  // Discard all existing frames, since they're probably all now invalid.
+  mFrameBlender.reset();
+  SurfaceCache::RemoveImage(ImageKey(this));
+
+  // Flag that we no longer have decoded frames for this image.
+  mDecoded = false;
+  mHasFirstFrame = false;
+
+  // Animated images require some special handling, because we normally require
+  // that they never be discarded.
+  if (mAnim) {
+    RequestDecodeCore(SYNCHRONOUS_NOTIFY);
+    ResetAnimation();
+    return;
+  }
+
+  // For non-animated images, it's fine to recover using an async decode.
+  RequestDecodeCore(ASYNCHRONOUS);
+}
+
 bool
 RasterImage::CanScale(GraphicsFilter aFilter,
                       const nsIntSize& aSize,
                       uint32_t aFlags)
 {
 #ifndef MOZ_ENABLE_SKIA
   // The high-quality scaler requires Skia.
   return false;
@@ -2192,17 +2226,19 @@ RasterImage::DrawWithPreDownscaleIfNeede
   IntSize finalSize = frameRef->GetImageSize();
   if (ThebesIntSize(finalSize) != aSize) {
     gfx::Size scale(double(aSize.width) / finalSize.width,
                     double(aSize.height) / finalSize.height);
     aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
     region.Scale(1.0 / scale.width, 1.0 / scale.height);
   }
 
-  frameRef->Draw(aContext, region, aFilter, aFlags);
+  if (!frameRef->Draw(aContext, region, aFilter, aFlags)) {
+    RecoverFromLossOfFrames();
+  }
 }
 
 //******************************************************************************
 /* [noscript] void draw(in gfxContext aContext,
  *                      in gfxGraphicsFilter aFilter,
  *                      [const] in gfxMatrix aUserSpaceToImageSpace,
  *                      [const] in gfxRect aFill,
  *                      [const] in nsIntRect aSubimage,
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -328,16 +328,23 @@ private:
   NS_IMETHOD RequestDecodeCore(RequestDecodeType aDecodeType);
 
   // We would like to just check if we have a zero lock count, but we can't do
   // that for animated images because in EnsureAnimExists we lock the image and
   // never unlock so that animated images always have their lock count >= 1. In
   // that case we use our animation consumers count as a proxy for lock count.
   bool IsUnlocked() { return (mLockCount == 0 || (mAnim && mAnimationConsumers == 0)); }
 
+  /**
+   * In catastrophic circumstances like a GPU driver crash, we may lose our
+   * frames even if they're locked. RecoverFromLossOfFrames discards all
+   * existing frames and redecodes.
+   */
+  void RecoverFromLossOfFrames();
+
 private: // data
   nsIntSize                  mSize;
   Orientation                mOrientation;
 
   // Whether our frames were decoded using any special flags.
   // Some flags (e.g. unpremultiplied data) may not be compatible
   // with the browser's needs for displaying the image to the user.
   // As such, we may need to redecode if we're being asked for