Bug 1116747 - Always use multithreaded image decoding. r=tn
authorSeth Fowler <seth@mozilla.com>
Thu, 08 Jan 2015 00:29:41 -0800
changeset 248561 a49774cdd1b18e45f76819a7a2cd2da45556efaa
parent 248560 25d6527235cabab1a0e25e3dd6126120e39e3dde
child 248562 c356ab8b348af6a10f7886fb75e687e511f637f9
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1116747
milestone37.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 1116747 - Always use multithreaded image decoding. r=tn
gfx/thebes/gfxPrefs.h
image/src/DecodePool.cpp
modules/libpref/init/all.js
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -240,17 +240,16 @@ private:
   DECL_GFX_PREF(Live, "image.mem.decodeondraw",                ImageMemDecodeOnDraw, bool, false);
   DECL_GFX_PREF(Live, "image.mem.discardable",                 ImageMemDiscardable, bool, false);
   DECL_GFX_PREF(Live, "image.mem.max_ms_before_yield",         ImageMemMaxMSBeforeYield, uint32_t, 400);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.discard_factor", ImageMemSurfaceCacheDiscardFactor, uint32_t, 1);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.max_size_kb",    ImageMemSurfaceCacheMaxSizeKB, uint32_t, 100 * 1024);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.min_expiration_ms", ImageMemSurfaceCacheMinExpirationMS, uint32_t, 60*1000);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.size_factor",    ImageMemSurfaceCacheSizeFactor, uint32_t, 64);
   DECL_GFX_PREF(Live, "image.mozsamplesize.enabled",           ImageMozSampleSizeEnabled, bool, false);
-  DECL_GFX_PREF(Live, "image.multithreaded_decoding.enabled",  ImageMTDecodingEnabled, bool, true);
   DECL_GFX_PREF(Live, "image.multithreaded_decoding.limit",    ImageMTDecodingLimit, int32_t, -1);
 
   DECL_GFX_PREF(Once, "layers.acceleration.disabled",          LayersAccelerationDisabled, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps",          LayersDrawFPS, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-video.enabled",            AsyncVideoEnabled, bool, true);
--- a/image/src/DecodePool.cpp
+++ b/image/src/DecodePool.cpp
@@ -70,16 +70,18 @@ class DecodeWorker : public nsRunnable
 {
 public:
   explicit DecodeWorker(RasterImage* aImage)
     : mImage(aImage)
   { }
 
   NS_IMETHOD Run() MOZ_OVERRIDE
   {
+    MOZ_ASSERT(!NS_IsMainThread());
+
     ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
 
     // If we were interrupted, we shouldn't do any work.
     if (mImage->mDecodeStatus == DecodeStatus::STOPPED) {
       NotifyProgressWorker::Dispatch(mImage);
       return NS_OK;
     }
 
@@ -88,24 +90,20 @@ public:
       NotifyProgressWorker::Dispatch(mImage);
       return NS_OK;
     }
 
     mImage->mDecodeStatus = DecodeStatus::ACTIVE;
 
     size_t oldByteCount = mImage->mDecoder->BytesDecoded();
 
-    // Multithreaded decoding can be disabled. If we've done so, we don't want
-    // to monopolize the main thread, and will allow a timeout.
-    DecodeUntil type = NS_IsMainThread() ? DecodeUntil::TIME
-                                         : DecodeUntil::DONE_BYTES;
-
     size_t maxBytes = mImage->mSourceData.Length() -
                       mImage->mDecoder->BytesDecoded();
-    DecodePool::Singleton()->DecodeSomeOfImage(mImage, type, maxBytes);
+    DecodePool::Singleton()->DecodeSomeOfImage(mImage, DecodeUntil::DONE_BYTES,
+                                               maxBytes);
 
     size_t bytesDecoded = mImage->mDecoder->BytesDecoded() - oldByteCount;
 
     mImage->mDecodeStatus = DecodeStatus::WORK_DONE;
 
     if (mImage->mDecoder &&
         !mImage->mError &&
         !mImage->mPendingError &&
@@ -121,27 +119,25 @@ public:
     }
 
     return NS_OK;
   }
 
 protected:
   virtual ~DecodeWorker()
   {
-    if (gfxPrefs::ImageMTDecodingEnabled()) {
-      // Dispatch mImage to main thread to prevent mImage from being destructed by decode thread.
-      nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-      NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
-      if (mainThread) {
-        // Handle ambiguous nsISupports inheritance
-        RasterImage* rawImg = nullptr;
-        mImage.swap(rawImg);
-        DebugOnly<nsresult> rv = NS_ProxyRelease(mainThread, NS_ISUPPORTS_CAST(ImageResource*, rawImg));
-        MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to proxy release to main thread");
-      }
+    // Dispatch mImage to main thread to prevent mImage from being destructed by decode thread.
+    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+    NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
+    if (mainThread) {
+      // Handle ambiguous nsISupports inheritance
+      RasterImage* rawImg = nullptr;
+      mImage.swap(rawImg);
+      DebugOnly<nsresult> rv = NS_ProxyRelease(mainThread, NS_ISUPPORTS_CAST(ImageResource*, rawImg));
+      MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to proxy release to main thread");
     }
   }
 
 private:
   nsRefPtr<RasterImage> mImage;
 };
 
 #ifdef MOZ_NUWA_PROCESS
@@ -203,42 +199,41 @@ DecodePool::GetEventTarget()
 {
   nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mThreadPool);
   return target.forget();
 }
 
 DecodePool::DecodePool()
   : mThreadPoolMutex("Thread Pool")
 {
-  if (gfxPrefs::ImageMTDecodingEnabled()) {
-    mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
-    if (mThreadPool) {
-      mThreadPool->SetName(NS_LITERAL_CSTRING("ImageDecoder"));
-      int32_t prefLimit = gfxPrefs::ImageMTDecodingLimit();
-      uint32_t limit;
-      if (prefLimit <= 0) {
-        limit = max(PR_GetNumberOfProcessors(), 2) - 1;
-      } else {
-        limit = static_cast<uint32_t>(prefLimit);
-      }
+  mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
+  MOZ_RELEASE_ASSERT(mThreadPool,
+                     "Should succeed in creating image decoding thread pool");
 
-      mThreadPool->SetThreadLimit(limit);
-      mThreadPool->SetIdleThreadLimit(limit);
+  mThreadPool->SetName(NS_LITERAL_CSTRING("ImageDecoder"));
+  int32_t prefLimit = gfxPrefs::ImageMTDecodingLimit();
+  uint32_t limit;
+  if (prefLimit <= 0) {
+    limit = max(PR_GetNumberOfProcessors(), 2) - 1;
+  } else {
+    limit = static_cast<uint32_t>(prefLimit);
+  }
+
+  mThreadPool->SetThreadLimit(limit);
+  mThreadPool->SetIdleThreadLimit(limit);
 
 #ifdef MOZ_NUWA_PROCESS
-      if (IsNuwaProcess()) {
-        mThreadPool->SetListener(new RIDThreadPoolListener());
-      }
+  if (IsNuwaProcess()) {
+    mThreadPool->SetListener(new RIDThreadPoolListener());
+  }
 #endif
 
-      nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
-      if (obsSvc) {
-        obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
-      }
-    }
+  nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
+  if (obsSvc) {
+    obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
   }
 }
 
 DecodePool::~DecodePool()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must shut down DecodePool on main thread!");
 }
 
@@ -273,20 +268,20 @@ DecodePool::RequestDecode(RasterImage* a
     // The image is already in our list of images to decode, or currently being
     // decoded, so we don't have to do anything else.
     return;
   }
 
   aImage->mDecodeStatus = DecodeStatus::PENDING;
   nsCOMPtr<nsIRunnable> worker = new DecodeWorker(aImage);
 
+  // Dispatch to the thread pool if it exists. If it doesn't, we're currently
+  // shutting down, so it's OK to just drop the job on the floor.
   MutexAutoLock threadPoolLock(mThreadPoolMutex);
-  if (!gfxPrefs::ImageMTDecodingEnabled() || !mThreadPool) {
-    NS_DispatchToMainThread(worker);
-  } else {
+  if (mThreadPool) {
     mThreadPool->Dispatch(worker, nsIEventTarget::DISPATCH_NORMAL);
   }
 }
 
 void
 DecodePool::DecodeABitOf(RasterImage* aImage)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3794,20 +3794,16 @@ pref("image.mem.surfacecache.size_factor
 // How much of the data in the surface cache is discarded when we get a memory
 // pressure notification, as a fraction. The discard factor is interpreted as a
 // reciprocal, so a discard factor of 1 means to discard everything in the
 // surface cache on memory pressure, a discard factor of 2 means to discard half
 // of the data, and so forth. The default should be a good balance for desktop
 // and laptop systems, where we never discard visible images.
 pref("image.mem.surfacecache.discard_factor", 1);
 
-// Whether we decode images on multiple background threads rather than the
-// foreground thread.
-pref("image.multithreaded_decoding.enabled", true);
-
 // How many threads we'll use for multithreaded decoding. If < 0, will be
 // automatically determined based on the system's number of cores.
 pref("image.multithreaded_decoding.limit", -1);
 
 // Limit for the canvas image cache. 0 means we don't limit the size of the
 // cache.
 pref("canvas.image.cache.limit", 0);