Bug 1521368: Forego drawing if our drawtarget is invalid, this can happen on a devicereset. r=rhunt
authorBas Schouten <bschouten@mozilla.com>
Tue, 22 Jan 2019 23:09:28 +0000
changeset 514927 9ec304cd5e28666c8d6a45e99d1a396785c72cfd
parent 514926 b8b0f4d2fa2cbc951383d18f28f72a34a77d32a1
child 514928 ee28acf1382f6df640735c8d1cb66c3c80367153
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrhunt
bugs1521368
milestone66.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 1521368: Forego drawing if our drawtarget is invalid, this can happen on a devicereset. r=rhunt Differential Revision: https://phabricator.services.mozilla.com/D17224
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
gfx/layers/PaintThread.cpp
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -82,16 +82,25 @@ DrawTargetD2D1::~DrawTargetD2D1() {
     // Our dependencies on other targets no longer matter.
     for (TargetSet::iterator iter = mDependingOnTargets.begin();
          iter != mDependingOnTargets.end(); iter++) {
       (*iter)->mDependentTargets.erase(this);
     }
   }
 }
 
+bool DrawTargetD2D1::IsValid() const {
+  if (NS_IsMainThread()) {
+    // Uninitialized DTs are considered valid.
+    return !mIsInitialized || mDC;
+  } else {
+    return const_cast<DrawTargetD2D1 *>(this)->EnsureInitialized();
+  }
+}
+
 already_AddRefed<SourceSurface> DrawTargetD2D1::Snapshot() {
   if (!EnsureInitialized()) {
     return nullptr;
   }
 
   MutexAutoLock lock(*mSnapshotLock);
   if (mSnapshot) {
     RefPtr<SourceSurface> snapshot(mSnapshot);
@@ -1302,19 +1311,22 @@ void DrawTargetD2D1::FlushInternal(bool 
        iter != mDependingOnTargets.end(); iter++) {
     (*iter)->mDependentTargets.erase(this);
   }
   mDependingOnTargets.clear();
 }
 
 bool DrawTargetD2D1::EnsureInitialized() {
   if (mIsInitialized) {
-    return true;
+    return !!mDC;
   }
 
+  // Don't retry.
+  mIsInitialized = true;
+
   HRESULT hr;
 
   RefPtr<ID2D1Device> device = Factory::GetD2D1Device(&mDeviceSeq);
   if (!device) {
     gfxCriticalNote << "[D2D1.1] Failed to obtain a device for "
                        "DrawTargetD2D1::EnsureInitialized().";
     return false;
   }
@@ -1383,18 +1395,16 @@ bool DrawTargetD2D1::EnsureInitialized()
   mDC->BeginDraw();
 
   CurrentLayer().mIsOpaque = mFormat == SurfaceFormat::B8G8R8X8;
 
   if (!mSurface) {
     mDC->Clear();
   }
 
-  mIsInitialized = true;
-
   return true;
 }
 
 void DrawTargetD2D1::MarkChanged() {
   if (mSnapshot) {
     MutexAutoLock lock(*mSnapshotLock);
     if (mSnapshot->hasOneRef()) {
       // Just destroy it, since no-one else knows about it.
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -29,16 +29,17 @@ class SourceSurfaceD2D1;
 const int32_t kLayerCacheSize1 = 5;
 
 class DrawTargetD2D1 : public DrawTarget {
  public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetD2D1, override)
   DrawTargetD2D1();
   virtual ~DrawTargetD2D1();
 
+  virtual bool IsValid() const override;
   virtual DrawTargetType GetType() const override {
     return DrawTargetType::HARDWARE_RASTER;
   }
   virtual BackendType GetBackendType() const override {
     return BackendType::DIRECT2D1_1;
   }
   virtual already_AddRefed<SourceSurface> Snapshot() override;
   virtual already_AddRefed<SourceSurface> IntoLuminanceSource(
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -191,18 +191,23 @@ void PaintThread::AsyncPaintTask(Composi
   AUTO_PROFILER_LABEL("PaintThread::AsyncPaintTask", GRAPHICS);
 
   MOZ_ASSERT(IsOnPaintWorkerThread());
   MOZ_ASSERT(aTask);
 
   gfx::DrawTargetCapture* capture = aTask->mCapture;
   gfx::DrawTarget* target = aTask->mTarget;
 
-  target->DrawCapturedDT(capture, Matrix());
-  target->Flush();
+  if (target->IsValid()) {
+    // Do not replay to invalid targets. This can happen on device resets and
+    // the browser will ensure the graphics stack is reinitialized on the main
+    // thread.
+    target->DrawCapturedDT(capture, Matrix());
+    target->Flush();
+  }
 
   if (gfxPrefs::LayersOMTPReleaseCaptureOnMainThread()) {
     // This should ensure the capture drawtarget, which may hold on to
     // UnscaledFont objects, gets destroyed on the main thread (See bug
     // 1404742). This assumes (unflushed) target DrawTargets do not themselves
     // hold on to UnscaledFonts.
     NS_ReleaseOnMainThreadSystemGroup("PaintTask::DrawTargetCapture",
                                       aTask->mCapture.forget());