Bug 1386966. Coalesce OMTP drawtarget flushes until finished painting a layer. r=dvander

This commit is contained in:
Mason Chang 2017-08-09 08:24:15 -07:00
parent 52ffe4157f
commit cddef9fa41
5 changed files with 74 additions and 13 deletions

View File

@ -42,21 +42,13 @@ struct MOZ_STACK_CLASS AutoCapturedPaintSetup
mTarget->SetTransform(mOldTransform);
mTarget->SetPermitSubpixelAA(mRestorePermitsSubpixelAA);
// Textureclient forces a flush once we "end paint", so
// users of this texture expect all the drawing to be complete.
// Force a flush now.
// TODO: This might be a performance bottleneck because
// main thread painting only does one flush at the end of all paints
// whereas we force a flush after each draw target paint.
mTarget->Flush();
if (mBridge) {
mBridge->NotifyFinishedAsyncPaint(mState);
}
}
RefPtr<CapturedPaintState> mState;
DrawTarget* mTarget;
RefPtr<DrawTarget> mTarget;
bool mRestorePermitsSubpixelAA;
Matrix mOldTransform;
RefPtr<CompositorBridgeChild> mBridge;
@ -169,8 +161,53 @@ PaintThread::PaintContentsAsync(CompositorBridgeChild* aBridge,
// Draw all the things into the actual dest target.
target->DrawCapturedDT(capture, Matrix());
if (!mDrawTargetsToFlush.Contains(target)) {
mDrawTargetsToFlush.AppendElement(target);
}
}
void
PaintThread::FinishedLayerBatch()
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<CompositorBridgeChild> cbc;
if (!gfxPrefs::LayersOMTPForceSync()) {
cbc = CompositorBridgeChild::Get();
}
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::EndAsyncPainting",
[self, cbc]() -> void
{
self->EndAsyncPainting(cbc);
});
if (cbc) {
sThread->Dispatch(task.forget());
} else {
SyncRunnable::DispatchToThread(sThread, task);
}
}
void
PaintThread::EndAsyncPainting(CompositorBridgeChild* aBridge)
{
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();
}
mDrawTargetsToFlush.Clear();
if (aBridge) {
aBridge->NotifyFinishedAsyncPaintLayer();
}
}
void
PaintThread::PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback)

View File

@ -70,6 +70,11 @@ public:
void PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);
// To 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 FinishedLayerBatch();
// Sync Runnables need threads to be ref counted,
// But this thread lives through the whole process.
// We're only temporarily using sync runnables so
@ -87,10 +92,15 @@ private:
void PaintContentsAsync(CompositorBridgeChild* aBridge,
CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);
void EndAsyncPainting(CompositorBridgeChild* aBridge);
static StaticAutoPtr<PaintThread> sSingleton;
static StaticRefPtr<nsIThread> sThread;
static PlatformThreadId sThreadId;
// This shouldn't be very many elements, so a list should be fine.
// Should only be accessed on the paint thread.
nsTArray<RefPtr<gfx::DrawTarget>> mDrawTargetsToFlush;
};
} // namespace layers

View File

@ -262,6 +262,8 @@ ClientPaintedLayer::PaintOffMainThread()
didUpdate = true;
}
PaintThread::Get()->FinishedLayerBatch();
mContentClient->EndPaint(nullptr);
if (didUpdate) {

View File

@ -1186,6 +1186,13 @@ CompositorBridgeChild::NotifyFinishedAsyncPaint(CapturedPaintState* aState)
aState->mTextureClientOnWhite->DropPaintThreadRef();
aState->mTextureClientOnWhite = nullptr;
}
}
void
CompositorBridgeChild::NotifyFinishedAsyncPaintLayer()
{
MOZ_ASSERT(PaintThread::IsOnPaintThread());
MonitorAutoLock lock(mPaintLock);
// 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

View File

@ -226,10 +226,6 @@ public:
// that the paint thread is going to begin painting asynchronously.
void NotifyBeginAsyncPaint(CapturedPaintState* aState);
// 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 CompoistorBridge
// that a transaction is about to be sent, and if the paint thread is
// currently painting, to begin delaying IPC messages.
@ -240,6 +236,15 @@ public:
// 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 paint thread. Notifies the CompositorBridge
// that the paint thread has finished ALL async requests from a given
// ClientPaintedLayer's batch.
void NotifyFinishedAsyncPaintLayer();
private:
// Private destructor, to discourage deletion outside of Release():
virtual ~CompositorBridgeChild();