Bug 1422169: Have the D3D11TextureData destructor defer releasing the last reference to its DrawTarget to the paint thread. r=dvander
authorBas Schouten <bschouten@mozilla.com>
Fri, 01 Dec 2017 17:04:46 +0100 (2017-12-01)
changeset 446376 db72cf1e6abcb9952868997598a46cdb5d664ec3
parent 446375 33ab7736c435fdf4503b2267326832fc1d598808
child 446377 43598bb5fe1ccf86d51229514db0e309a1d1aaa8
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000 (2018-01-11)
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1422169
milestone59.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 1422169: Have the D3D11TextureData destructor defer releasing the last reference to its DrawTarget to the paint thread. r=dvander MozReview-Commit-ID: Dmzu5Nnpx9g
gfx/layers/PaintThread.cpp
gfx/layers/PaintThread.h
gfx/layers/d3d11/TextureD3D11.cpp
gfx/thebes/gfxPrefs.h
modules/libpref/init/all.js
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -355,16 +355,26 @@ PaintThread::EndLayer()
 #ifndef OMTP_FORCE_SYNC
   sThread->Dispatch(task.forget());
 #else
   SyncRunnable::DispatchToThread(sThread, task);
 #endif
 }
 
 void
+PaintThread::Dispatch(RefPtr<Runnable>& aRunnable)
+{
+#ifndef OMTP_FORCE_SYNC
+  sThread->Dispatch(aRunnable.forget());
+#else
+  SyncRunnable::DispatchToThread(sThread, aRunnable);
+#endif
+}
+
+void
 PaintThread::AsyncEndLayer()
 {
   MOZ_ASSERT(IsOnPaintThread());
   // Textureclient forces a flush once we "end paint", so
   // users of this texture expect all the drawing to be complete.
   // Force a flush now.
   for (size_t i = 0; i < mDrawTargetsToFlush.Length(); i++) {
     mDrawTargetsToFlush[i]->Flush();
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -137,16 +137,19 @@ public:
   void PaintContents(CapturedPaintState* aState,
                      PrepDrawTargetForPaintingCallback aCallback);
 
   // Must be called on the main thread. Signifies that the current
   // batch of CapturedPaintStates* for PaintContents have been recorded
   // and the main thread is finished recording this layer.
   void EndLayer();
 
+  // This allows external users to run code on the paint thread.
+  void Dispatch(RefPtr<Runnable>& aRunnable);
+
   // Must be called on the main thread. Signifies that the current
   // layer tree transaction has been finished and any async paints
   // for it have been queued on the paint thread. This MUST be called
   // at the end of a layer transaction as it will be used to do an optional
   // texture sync and then unblock the main thread if it is waiting to paint
   // a new frame.
   void EndLayerTransaction(SyncObjectClient* aSyncObject);
 
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/gfx/DeviceManagerDx.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/webrender/RenderD3D11TextureHostOGL.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "mozilla/webrender/WebRenderAPI.h"
+#include "PaintThread.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 static const GUID sD3D11TextureUsage =
@@ -282,28 +283,47 @@ D3D11TextureData::D3D11TextureData(ID3D1
                                    bool aIsForOutOfBandContent)
 : DXGITextureData(aSize, aFormat, aNeedsClear, aNeedsClearWhite, aIsForOutOfBandContent)
 , mTexture(aTexture)
 {
   MOZ_ASSERT(aTexture);
   mHasSynchronization = HasKeyedMutex(aTexture);
 }
 
-D3D11TextureData::~D3D11TextureData()
+static void DestroyDrawTarget(RefPtr<DrawTarget>& aDT, RefPtr<ID3D11Texture2D>& aTexture)
 {
-#ifdef DEBUG
   // An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is
   // when it calls EndDraw. This EndDraw should not execute anything so it
   // shouldn't -really- need the lock but the debug layer chokes on this.
+#ifdef DEBUG
+  LockD3DTexture(aTexture.get());
+#endif
+  aDT = nullptr;
+#ifdef DEBUG
+  UnlockD3DTexture(aTexture.get());
+#endif
+  aTexture = nullptr;
+}
+
+D3D11TextureData::~D3D11TextureData()
+{
   if (mDrawTarget) {
-    Lock(OpenMode::OPEN_NONE);
-    mDrawTarget = nullptr;
-    Unlock();
+    if (PaintThread::Get() && gfxPrefs::Direct2DDestroyDTOnPaintThread()) {
+      RefPtr<DrawTarget> dt = mDrawTarget;
+      RefPtr<ID3D11Texture2D> tex = mTexture;
+      RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::RunFunction",
+        [dt, tex]() mutable { DestroyDrawTarget(dt, tex); });
+      PaintThread::Get()->Dispatch(task);
+    }
+#ifdef DEBUG
+    else {
+      DestroyDrawTarget(mDrawTarget, mTexture);
+    }
+#endif
   }
-#endif
 }
 
 bool
 D3D11TextureData::Lock(OpenMode aMode)
 {
   if (!LockD3DTexture(mTexture.get())) {
     return false;
   }
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -449,16 +449,17 @@ private:
   // Size in megabytes
   DECL_GFX_PREF(Once, "gfx.content.skia-font-cache-size",      SkiaContentFontCacheSize, int32_t, 10);
 
   DECL_GFX_PREF(Once, "gfx.device-reset.limit",                DeviceResetLimitCount, int32_t, 10);
   DECL_GFX_PREF(Once, "gfx.device-reset.threshold-ms",         DeviceResetThresholdMilliseconds, int32_t, -1);
 
   DECL_GFX_PREF(Once, "gfx.direct2d.disabled",                 Direct2DDisabled, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled",            Direct2DForceEnabled, bool, false);
+  DECL_GFX_PREF(Live, "gfx.direct2d.destroy-dt-on-paintthread",Direct2DDestroyDTOnPaintThread, bool, true);
   DECL_GFX_PREF(Live, "gfx.direct3d11.reuse-decoder-device",   Direct3D11ReuseDecoderDevice, int32_t, -1);
   DECL_GFX_PREF(Live, "gfx.direct3d11.allow-keyed-mutex",      Direct3D11AllowKeyedMutex, bool, true);
   DECL_GFX_PREF(Live, "gfx.direct3d11.use-double-buffering",   Direct3D11UseDoubleBuffering, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct3d11.enable-debug-layer",     Direct3D11EnableDebugLayer, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct3d11.break-on-error",         Direct3D11BreakOnError, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct3d11.sleep-on-create-device", Direct3D11SleepOnCreateDevice, int32_t, 0);
   DECL_GFX_PREF(Live, "gfx.downloadable_fonts.keep_color_bitmaps", KeepColorBitmaps, bool, false);
   DECL_GFX_PREF(Live, "gfx.downloadable_fonts.keep_variation_tables", KeepVariationTables, bool, false);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4854,16 +4854,20 @@ pref("widget.window-transforms.disabled"
 #ifdef XP_WIN
 // Whether to disable the automatic detection and use of direct2d.
 pref("gfx.direct2d.disabled", false);
 
 // Whether to attempt to enable Direct2D regardless of automatic detection or
 // blacklisting
 pref("gfx.direct2d.force-enabled", false);
 
+// Whether to defer destruction of Direct2D DrawTargets to the paint thread
+// when using OMTP.
+pref("gfx.direct2d.destroy-dt-on-paintthread", true);
+
 pref("gfx.direct3d11.enable-debug-layer", false);
 pref("gfx.direct3d11.break-on-error", false);
 
 pref("layers.prefer-opengl", false);
 #endif
 
 // Copy-on-write canvas
 pref("layers.shared-buffer-provider.enabled", true);