Bug 1390755 - Ensure PaintThread::EndTransaction runs before IPDL messages are resumed. r=mchang
authorRyan Hunt <rhunt@eqrion.net>
Wed, 16 Aug 2017 13:55:57 -0500
changeset 375360 7bd53f7a21168f28a974a92c6cb1dceaaf590cd9
parent 375359 53197932a884f014b76764e1a94fd31032a23654
child 375361 5b0eb3f25b7412e3be948bfa95c3d818410944af
push id32355
push userkwierso@gmail.com
push dateThu, 17 Aug 2017 23:17:14 +0000
treeherdermozilla-central@a6a1f5c1d971 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmchang
bugs1390755
milestone57.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 1390755 - Ensure PaintThread::EndTransaction runs before IPDL messages are resumed. r=mchang MozReview-Commit-ID: GdSKTxtqWRA
gfx/layers/PaintThread.cpp
gfx/layers/ipc/CompositorBridgeChild.cpp
gfx/layers/ipc/CompositorBridgeChild.h
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -204,16 +204,17 @@ PaintThread::EndAsyncPaintingLayer()
 void
 PaintThread::FinishedLayerTransaction(SyncObjectClient* aSyncObject)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   RefPtr<CompositorBridgeChild> cbc;
   if (!gfxPrefs::LayersOMTPForceSync()) {
     cbc = CompositorBridgeChild::Get();
+    cbc->NotifyBeginAsyncPaintEndTransaction();
   }
 
   RefPtr<SyncObjectClient> syncObject(aSyncObject);
   RefPtr<PaintThread> self = this;
   RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::EndAsyncLayerTransaction",
     [self, cbc, syncObject]() -> void
   {
     self->EndAsyncLayerTransaction(cbc, syncObject);
@@ -232,17 +233,17 @@ PaintThread::EndAsyncLayerTransaction(Co
 {
   MOZ_ASSERT(IsOnPaintThread());
 
   if (aSyncObject) {
     aSyncObject->Synchronize();
   }
 
   if (aBridge) {
-    aBridge->NotifyFinishedAsyncPaintTransaction();
+    aBridge->NotifyFinishedAsyncPaintEndTransaction();
   }
 }
 
 void
 PaintThread::PaintContents(CapturedPaintState* aState,
                            PrepDrawTargetForPaintingCallback aCallback)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -87,16 +87,17 @@ CompositorBridgeChild::CompositorBridgeC
   , mActorDestroyed(false)
   , mFwdTransactionId(0)
   , mDeviceResetSequenceNumber(0)
   , mMessageLoop(MessageLoop::current())
   , mProcessToken(0)
   , mSectionAllocator(nullptr)
   , mPaintLock("CompositorBridgeChild.mPaintLock")
   , mOutstandingAsyncPaints(0)
+  , mOutstandingAsyncEndTransaction(false)
   , mIsWaitingForPaint(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 CompositorBridgeChild::~CompositorBridgeChild()
 {
   if (mCanSend) {
@@ -1184,23 +1185,37 @@ CompositorBridgeChild::NotifyFinishedAsy
   aState->mTextureClient = nullptr;
   if (aState->mTextureClientOnWhite) {
     aState->mTextureClientOnWhite->DropPaintThreadRef();
     aState->mTextureClientOnWhite = nullptr;
   }
 }
 
 void
-CompositorBridgeChild::NotifyFinishedAsyncPaintTransaction()
+CompositorBridgeChild::NotifyBeginAsyncPaintEndTransaction()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MonitorAutoLock lock(mPaintLock);
+
+  MOZ_ASSERT(!mOutstandingAsyncEndTransaction);
+  mOutstandingAsyncEndTransaction = true;
+}
+
+void
+CompositorBridgeChild::NotifyFinishedAsyncPaintEndTransaction()
 {
   MOZ_ASSERT(PaintThread::IsOnPaintThread());
   MonitorAutoLock lock(mPaintLock);
+
   // Since this should happen after ALL paints are done and
   // at the end of a transaction, this should always be true.
   MOZ_RELEASE_ASSERT(mOutstandingAsyncPaints == 0);
+  MOZ_ASSERT(mOutstandingAsyncEndTransaction);
+
+  mOutstandingAsyncEndTransaction = false;
 
   // It's possible that we painted so fast that the main thread never reached
   // the code that starts delaying messages. If so, mIsWaitingForPaint will be
   // false, and we can safely return.
   if (mIsWaitingForPaint) {
     ResumeIPCAfterAsyncPaint();
 
     // Notify the main thread in case it's blocking. We do this unconditionally
@@ -1213,17 +1228,19 @@ void
 CompositorBridgeChild::PostponeMessagesIfAsyncPainting()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   MonitorAutoLock lock(mPaintLock);
 
   MOZ_ASSERT(!mIsWaitingForPaint);
 
-  if (mOutstandingAsyncPaints > 0) {
+  // We need to wait for async paints and the async end transaction as
+  // it will do texture synchronization
+  if (mOutstandingAsyncPaints > 0 || mOutstandingAsyncEndTransaction) {
     mIsWaitingForPaint = true;
     GetIPCChannel()->BeginPostponingSends();
   }
 }
 
 void
 CompositorBridgeChild::ResumeIPCAfterAsyncPaint()
 {
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -235,21 +235,26 @@ public:
   // previous frames have been flushed. The main thread blocks until the
   // operation completes.
   void FlushAsyncPaints();
 
   // Must only be called from the paint thread. Notifies the CompositorBridge
   // that the paint thread has finished an asynchronous paint request.
   void NotifyFinishedAsyncPaint(CapturedPaintState* aState);
 
+  // Must only be called from the main thread. Notifies the CompositorBridge
+  // that the paint thread is going to perform texture synchronization at the
+  // end of async painting, and should postpone messages if needed until
+  // finished.
+  void NotifyBeginAsyncPaintEndTransaction();
+
   // Must only be called from the paint thread. Notifies the CompositorBridge
-  // that the paint thread has finished ALL async requests from a given
-  // transaction. We can resume IPC transactions after ALL
-  // async paints are done.
-  void NotifyFinishedAsyncPaintTransaction();
+  // that the paint thread has finished all async paints and texture syncs from
+  // a given transaction and may resume sending messages.
+  void NotifyFinishedAsyncPaintEndTransaction();
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CompositorBridgeChild();
 
   // Must only be called from the paint thread. If the main thread is delaying
   // IPC messages, this forwards all such delayed IPC messages to the I/O thread
   // and resumes IPC.
@@ -368,16 +373,19 @@ private:
   // state below.
   Monitor mPaintLock;
 
   // Contains the number of outstanding asynchronous paints tied to a
   // PLayerTransaction on this bridge. This is R/W on both the main and paint
   // threads, and must be accessed within the paint lock.
   size_t mOutstandingAsyncPaints;
 
+  // Whether we are waiting for an async paint end transaction
+  bool mOutstandingAsyncEndTransaction;
+
   // True if this CompositorBridge is currently delaying its messages until the
   // paint thread completes. This is R/W on both the main and paint threads, and
   // must be accessed within the paint lock.
   bool mIsWaitingForPaint;
 };
 
 } // namespace layers
 } // namespace mozilla