Bug 685516: Instead of decoding small images synchronously and large images asynchronously, always decode synchronously for some time, and post the remainder to the event loop if necessary. r=joe
authorKyle Huey <khuey@kylehuey.com>
Mon, 13 Aug 2012 11:12:15 -0700
changeset 102325 3bb125057939
parent 102324 a33215aa549c
child 102326 d3829aea9cd1
push id23279
push userkhuey@mozilla.com
push date2012-08-15 13:26 +0000
treeherdermozilla-central@a0bddf5fcb91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe
bugs685516
milestone17.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 685516: Instead of decoding small images synchronously and large images asynchronously, always decode synchronously for some time, and post the remainder to the event loop if necessary. r=joe
content/base/src/nsNodeUtils.cpp
image/src/RasterImage.cpp
image/src/RasterImage.h
modules/libpref/src/init/all.js
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -23,17 +23,16 @@
 #ifdef MOZ_XUL
 #include "nsXULElement.h"
 #endif
 #include "nsBindingManager.h"
 #include "nsGenericHTMLElement.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
-#include "nsImageLoadingContent.h"
 #include "jsgc.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsObjectLoadingContent.h"
 #include "nsDOMMutationObserver.h"
 
 using namespace mozilla::dom;
 
 // This macro expects the ownerDocument of content_ to be in scope as
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -50,27 +50,24 @@ static PRLogModuleInfo *gCompressedImage
 #endif
 
 // Tweakable progressive decoding parameters.  These are initialized to 0 here
 // because otherwise, we have to initialize them in a static initializer, which
 // makes us slower to start up.
 static bool gInitializedPrefCaches = false;
 static PRUint32 gDecodeBytesAtATime = 0;
 static PRUint32 gMaxMSBeforeYield = 0;
-static PRUint32 gMaxBytesForSyncDecode = 0;
 
 static void
 InitPrefCaches()
 {
   Preferences::AddUintVarCache(&gDecodeBytesAtATime,
                                "image.mem.decode_bytes_at_a_time", 200000);
   Preferences::AddUintVarCache(&gMaxMSBeforeYield,
                                "image.mem.max_ms_before_yield", 400);
-  Preferences::AddUintVarCache(&gMaxBytesForSyncDecode,
-                               "image.mem.max_bytes_for_sync_decode", 150000);
   gInitializedPrefCaches = true;
 }
 
 /* We define our own error checking macros here for 2 reasons:
  *
  * 1) Most of the failures we encounter here will (hopefully) be
  * the result of decoding failures (ie, bad data) and not code
  * failures. As such, we don't want to clutter up debug consoles
@@ -2457,19 +2454,23 @@ RasterImage::RequestDecode()
     rv = InitDecoder(/* aDoSizeDecode = */ false);
     CONTAINER_ENSURE_SUCCESS(rv);
   }
 
   // If we've read all the data we have, we're done
   if (mBytesDecoded == mSourceData.Length())
     return NS_OK;
 
-  // If it's a smallish image, it's not worth it to do things async
-  if (!mDecoded && !mInDecoder && mHasSourceData && (mSourceData.Length() < gMaxBytesForSyncDecode))
-    return SyncDecode();
+  // If we can do decoding now, do so.  Small images will decode completely,
+  // large images will decode a bit and post themselves to the event loop
+  // to finish decoding.
+  if (!mDecoded && !mInDecoder && mHasSourceData) {
+    DecodeWorker::Singleton()->DecodeABitOf(this);
+    return NS_OK;
+  }
 
   // If we get this far, dispatch the worker. We do this instead of starting
   // any immediate decoding to guarantee that all our decode notifications are
   // dispatched asynchronously, and to ensure we stay responsive.
   DecodeWorker::Singleton()->RequestDecode(this);
 
   return NS_OK;
 }
@@ -2892,16 +2893,35 @@ RasterImage::DecodeWorker::AddDecodeRequ
 void
 RasterImage::DecodeWorker::RequestDecode(RasterImage* aImg)
 {
   AddDecodeRequest(&aImg->mDecodeRequest);
   EnsurePendingInEventLoop();
 }
 
 void
+RasterImage::DecodeWorker::DecodeABitOf(RasterImage* aImg)
+{
+  TimeStamp eventStart = TimeStamp::Now();
+
+  do {
+    DecodeSomeOfImage(aImg);
+
+    // If we aren't yet finished decoding and we have more data in hand, add
+    // this request to the back of the priority list.
+    if (aImg->mDecoder &&
+        !aImg->mError &&
+        !aImg->IsDecodeFinished() &&
+        aImg->mSourceData.Length() > aImg->mBytesDecoded) {
+      RequestDecode(aImg);
+    }
+  } while ((TimeStamp::Now() - eventStart).ToMilliseconds() <= gMaxMSBeforeYield);
+}
+
+void
 RasterImage::DecodeWorker::EnsurePendingInEventLoop()
 {
   if (!mPendingInEventLoop) {
     mPendingInEventLoop = true;
     NS_DispatchToCurrentThread(this);
   }
 }
 
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -390,16 +390,22 @@ private:
     static DecodeWorker* Singleton();
 
     /**
      * Ask the DecodeWorker to asynchronously decode this image.
      */
     void RequestDecode(RasterImage* aImg);
 
     /**
+     * Decode aImg for a short amount of time, and post the remainder to the
+     * queue.
+     */
+    void DecodeABitOf(RasterImage* aImg);
+
+    /**
      * Give this image ASAP priority; it will be decoded before all non-ASAP
      * images.  You can call MarkAsASAP before or after you call RequestDecode
      * for the image, but if you MarkAsASAP before you call RequestDecode, you
      * still need to call RequestDecode.
      *
      * StopDecoding() resets the image's ASAP flag.
      */
     void MarkAsASAP(RasterImage* aImg);
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3504,19 +3504,16 @@ pref("image.mem.decodeondraw", true);
 pref("image.mem.min_discard_timeout_ms", 10000);
 
 // Chunk size for calls to the image decoders
 pref("image.mem.decode_bytes_at_a_time", 4096);
 
 // The longest time we can spend in an iteration of an async decode
 pref("image.mem.max_ms_before_yield", 5);
 
-// The maximum source data size for which we auto sync decode
-pref("image.mem.max_bytes_for_sync_decode", 150000);
-
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 pref("image.mem.max_decoded_image_kb", 51200);
 
 // WebGL prefs
 pref("webgl.force-enabled", false);
 pref("webgl.disabled", false);
 pref("webgl.shader_validator", true);