Bug 1390755 - Ensure PaintThread::EndTransaction runs before IPDL messages are resumed. r?mchang
MozReview-Commit-ID: GdSKTxtqWRA
--- 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,17 @@ void
CompositorBridgeChild::PostponeMessagesIfAsyncPainting()
{
MOZ_ASSERT(NS_IsMainThread());
MonitorAutoLock lock(mPaintLock);
MOZ_ASSERT(!mIsWaitingForPaint);
- if (mOutstandingAsyncPaints > 0) {
+ 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