Bug 1416864 - Synchronize how snapshots detach in DrawTargetD2D1. r=bas a=gchang
authorDavid Anderson <danderson@mozilla.com>
Tue, 21 Nov 2017 10:52:38 -0500
changeset 442684 503237c7de504e66df56ec3c16e2d8e262e11122
parent 442683 43f74013ae081e9b5a84cdc6c087d4e206af068b
child 442685 84ca5dce1d6a63bc64612876eccee30fc45080f9
push id8300
push userccoroiu@mozilla.com
push dateMon, 04 Dec 2017 12:38:17 +0000
treeherdermozilla-beta@810f9fabc684 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, gchang
bugs1416864
milestone58.0
Bug 1416864 - Synchronize how snapshots detach in DrawTargetD2D1. r=bas a=gchang
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
gfx/2d/SourceSurfaceD2D1.cpp
gfx/2d/SourceSurfaceD2D1.h
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -52,16 +52,17 @@ DrawTargetD2D1::DrawTargetD2D1()
 {
 }
 
 DrawTargetD2D1::~DrawTargetD2D1()
 {
   PopAllClips();
 
   if (mSnapshot) {
+    MutexAutoLock lock(*mSnapshotLock);
     // We may hold the only reference. MarkIndependent will clear mSnapshot;
     // keep the snapshot object alive so it doesn't get destroyed while
     // MarkIndependent is running.
     RefPtr<SourceSurfaceD2D1> deathGrip = mSnapshot;
     // mSnapshot can be treated as independent of this DrawTarget since we know
     // this DrawTarget won't change again.
     deathGrip->MarkIndependent();
     // mSnapshot will be cleared now.
@@ -85,16 +86,19 @@ DrawTargetD2D1::~DrawTargetD2D1()
        iter != mDependingOnTargets.end(); iter++) {
     (*iter)->mDependentTargets.erase(this);
   }
 }
 
 already_AddRefed<SourceSurface>
 DrawTargetD2D1::Snapshot()
 {
+  if (!mSnapshotLock) {
+    mSnapshotLock = make_shared<Mutex>("DrawTargetD2D1::mSnapshotLock");
+  }
   if (mSnapshot) {
     RefPtr<SourceSurface> snapshot(mSnapshot);
     return snapshot.forget();
   }
   PopAllClips();
 
   Flush();
 
@@ -1269,16 +1273,17 @@ DrawTargetD2D1::CleanupD2D()
     mFactory = nullptr;
   }
 }
 
 void
 DrawTargetD2D1::MarkChanged()
 {
   if (mSnapshot) {
+    MutexAutoLock lock(*mSnapshotLock);
     if (mSnapshot->hasOneRef()) {
       // Just destroy it, since no-one else knows about it.
       mSnapshot = nullptr;
     } else {
       mSnapshot->DrawTargetWillChange();
       // The snapshot will no longer depend on this target.
       MOZ_ASSERT(!mSnapshot);
     }
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -275,16 +275,17 @@ private:
   PushedLayer& CurrentLayer()
   {
     return mPushedLayers.back();
   }
 
   // The latest snapshot of this surface. This needs to be told when this
   // target is modified. We keep it alive as a cache.
   RefPtr<SourceSurfaceD2D1> mSnapshot;
+  std::shared_ptr<Mutex> mSnapshotLock;
   // A list of targets we need to flush when we're modified.
   TargetSet mDependentTargets;
   // A list of targets which have this object in their mDependentTargets set
   TargetSet mDependingOnTargets;
 
   uint32_t mUsedCommandListsSincePurge;
   // When a BlendEffect has been drawn to a command list, and that command list is
   // subsequently used -again- as an input to a blend effect for a command list,
--- a/gfx/2d/SourceSurfaceD2D1.cpp
+++ b/gfx/2d/SourceSurfaceD2D1.cpp
@@ -18,16 +18,19 @@ SourceSurfaceD2D1::SourceSurfaceD2D1(ID2
   , mDC(aDC)
   , mDevice(Factory::GetD2D1Device())
   , mDrawTarget(aDT)
 {
   aImage->QueryInterface((ID2D1Bitmap1**)getter_AddRefs(mRealizedBitmap));
 
   mFormat = aFormat;
   mSize = aSize;
+  if (aDT) {
+    mSnapshotLock = aDT->mSnapshotLock;
+  }
 }
 
 SourceSurfaceD2D1::~SourceSurfaceD2D1()
 {
 }
 
 bool
 SourceSurfaceD2D1::IsValid() const
@@ -104,16 +107,19 @@ SourceSurfaceD2D1::EnsureRealizedBitmap(
   dc->EndDraw();
 
   return true;
 }
 
 void
 SourceSurfaceD2D1::DrawTargetWillChange()
 {
+  MOZ_ASSERT(mSnapshotLock);
+  mSnapshotLock->AssertCurrentThreadOwns();
+
   // At this point in time this should always be true here.
   MOZ_ASSERT(mRealizedBitmap);
 
   RefPtr<ID2D1Bitmap1> oldBitmap = mRealizedBitmap;
 
   D2D1_BITMAP_PROPERTIES1 props;
   props.dpiX = 96;
   props.dpiY = 96;
--- a/gfx/2d/SourceSurfaceD2D1.h
+++ b/gfx/2d/SourceSurfaceD2D1.h
@@ -57,16 +57,17 @@ private:
   RefPtr<ID2D1Bitmap1> mRealizedBitmap;
   RefPtr<ID2D1DeviceContext> mDC;
   // Keep this around to verify whether out image is still valid in the future.
   RefPtr<ID2D1Device> mDevice;
 
   SurfaceFormat mFormat;
   IntSize mSize;
   DrawTargetD2D1* mDrawTarget;
+  std::shared_ptr<Mutex> mSnapshotLock;
 };
 
 class DataSourceSurfaceD2D1 : public DataSourceSurface
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceD2D1)
   DataSourceSurfaceD2D1(ID2D1Bitmap1 *aMappableBitmap, SurfaceFormat aFormat);
   ~DataSourceSurfaceD2D1();