Replay buffer commands on paint thread when OMTP is enabled (bug 1399692 part 7, r=bas)

This commit does the work of actually dispatching the recorded buffer operations
to the paint thread, and removing some main thread asserts from TextureClient.

MozReview-Commit-ID: CN3RoQPz9fP

--HG--
extra : rebase_source : 08ae6cf8445ef0a757efc54175768c2fa9bb1685
extra : intermediate-source : 0fc2414f146d8f5d08c97e5b7eedb25c5632ab2d
extra : source : e9349ad2f1f8fec862b1d2271d0d8f25ad0814d4
This commit is contained in:
Ryan Hunt 2017-10-26 00:47:17 -04:00
Родитель cc9ba81109
Коммит c34dc7e2af
11 изменённых файлов: 172 добавлений и 19 удалений

Просмотреть файл

@ -45,6 +45,34 @@ CapturedBufferState::PrepareBuffer()
(!mBufferUnrotate || mBufferUnrotate->UnrotateBuffer());
}
void
CapturedBufferState::GetTextureClients(nsTArray<RefPtr<TextureClient>>& aTextureClients)
{
if (mBufferCopy) {
if (TextureClient* source = mBufferCopy->mSource->GetClient()) {
aTextureClients.AppendElement(source);
}
if (TextureClient* sourceOnWhite = mBufferCopy->mSource->GetClientOnWhite()) {
aTextureClients.AppendElement(sourceOnWhite);
}
if (TextureClient* destination = mBufferCopy->mDestination->GetClient()) {
aTextureClients.AppendElement(destination);
}
if (TextureClient* destinationOnWhite = mBufferCopy->mDestination->GetClientOnWhite()) {
aTextureClients.AppendElement(destinationOnWhite);
}
}
if (mBufferUnrotate) {
if (TextureClient* client = mBufferUnrotate->mBuffer->GetClient()) {
aTextureClients.AppendElement(client);
}
if (TextureClient* clientOnWhite = mBufferUnrotate->mBuffer->GetClientOnWhite()) {
aTextureClients.AppendElement(clientOnWhite);
}
}
}
StaticAutoPtr<PaintThread> PaintThread::sSingleton;
StaticRefPtr<nsIThread> PaintThread::sThread;
PlatformThreadId PaintThread::sThreadId;
@ -182,6 +210,56 @@ PaintThread::BeginLayerTransaction()
MOZ_ASSERT(!mInAsyncPaintGroup);
}
void
PaintThread::PrepareBuffer(CapturedBufferState* aState)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aState);
// If painting asynchronously, we need to acquire the compositor bridge which
// owns the underlying MessageChannel. Otherwise we leave it null and use
// synchronous dispatch.
RefPtr<CompositorBridgeChild> cbc;
if (!gfxPrefs::LayersOMTPForceSync()) {
cbc = CompositorBridgeChild::Get();
cbc->NotifyBeginAsyncPrepareBuffer(aState);
}
RefPtr<CapturedBufferState> state(aState);
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PrepareBuffer",
[self, cbc, state]() -> void
{
self->AsyncPrepareBuffer(cbc,
state);
});
if (cbc) {
sThread->Dispatch(task.forget());
} else {
SyncRunnable::DispatchToThread(sThread, task);
}
}
void
PaintThread::AsyncPrepareBuffer(CompositorBridgeChild* aBridge,
CapturedBufferState* aState)
{
MOZ_ASSERT(IsOnPaintThread());
MOZ_ASSERT(aState);
if (!mInAsyncPaintGroup) {
mInAsyncPaintGroup = true;
PROFILER_TRACING("Paint", "Rasterize", TRACING_INTERVAL_START);
}
if (!aState->PrepareBuffer()) {
gfxCriticalNote << "Failed to prepare buffers on the paint thread.";
}
aBridge->NotifyFinishedAsyncPrepareBuffer(aState);
}
void
PaintThread::PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback)

Просмотреть файл

@ -100,6 +100,7 @@ public:
* for the frame.
*/
bool PrepareBuffer();
void GetTextureClients(nsTArray<RefPtr<TextureClient>>& aTextureClients);
Maybe<Copy> mBufferCopy;
Maybe<Unrotate> mBufferUnrotate;
@ -130,6 +131,8 @@ public:
// or running while this is executing.
void BeginLayerTransaction();
void PrepareBuffer(CapturedBufferState* aState);
void PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);
@ -160,6 +163,8 @@ private:
void ShutdownOnPaintThread();
void InitOnPaintThread();
void AsyncPrepareBuffer(CompositorBridgeChild* aBridge,
CapturedBufferState* aState);
void AsyncPaintContents(CompositorBridgeChild* aBridge,
CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);

Просмотреть файл

@ -497,7 +497,7 @@ RemoteRotatedBuffer::Lock(OpenMode aMode)
mTarget = mClient->BorrowDrawTarget();
if (!mTarget || !mTarget->IsValid()) {
gfxCriticalNote << "Invalid draw target " << hexa(mTarget)
<< "in RemoteRotatedBuffer::Lock";
<< " in RemoteRotatedBuffer::Lock";
Unlock();
return false;
}
@ -507,7 +507,7 @@ RemoteRotatedBuffer::Lock(OpenMode aMode)
if (!mTargetOnWhite || !mTargetOnWhite->IsValid()) {
gfxCriticalNote << "Invalid draw target(s) " << hexa(mTarget)
<< " and " << hexa(mTargetOnWhite)
<< "in RemoteRotatedBuffer::Lock";
<< " in RemoteRotatedBuffer::Lock";
Unlock();
return false;
}

Просмотреть файл

@ -243,6 +243,13 @@ public:
virtual gfx::DrawTarget* GetDTBuffer() const = 0;
virtual gfx::DrawTarget* GetDTBufferOnWhite() const = 0;
virtual TextureClient* GetClient() const {
return nullptr;
}
virtual TextureClient* GetClientOnWhite() const {
return nullptr;
}
/**
* Creates a shallow copy of the rotated buffer with the same underlying
* texture clients and draw targets. Rotated buffers are not thread safe,
@ -338,9 +345,6 @@ public:
};
}
TextureClient* GetClient() const { return mClient; }
TextureClient* GetClientOnWhite() const { return mClientOnWhite; }
void SyncWithObject(SyncObjectClient* aSyncObject);
void Clear();

Просмотреть файл

@ -210,11 +210,17 @@ ClientPaintedLayer::PaintOffMainThread()
uint32_t flags = GetPaintFlags();
PaintState state = mContentClient->BeginPaint(this, flags | ContentClient::PAINT_ASYNC);
bool didUpdate = false;
if (state.mBufferState) {
PaintThread::Get()->PrepareBuffer(state.mBufferState);
didUpdate = true;
}
if (!UpdatePaintRegion(state)) {
return false;
}
bool didUpdate = false;
RotatedBuffer::DrawIterator iter;
// Debug Protip: Change to BorrowDrawTargetForPainting if using sync OMTP.

Просмотреть файл

@ -181,12 +181,31 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
});
}
if (bufferState->PrepareBuffer()) {
if (bufferState->mBufferUnrotate) {
newParameters.SetUnrotated();
// If we're async painting then return the buffer state to
// be dispatched to the paint thread, otherwise do it now
if (asyncPaint) {
// We cannot do a buffer unrotate if the buffer is already rotated
// and we're async painting as that may fail
if (!bufferState->mBufferUnrotate ||
mBuffer->BufferRotation() == IntPoint(0,0)) {
result.mBufferState = bufferState;
// We can then assume that preparing the buffer will always
// succeed and update our parameters unconditionally
if (bufferState->mBufferUnrotate) {
newParameters.SetUnrotated();
}
mBuffer->SetParameters(newParameters);
canReuseBuffer = true;
}
} else {
if (bufferState->PrepareBuffer()) {
if (bufferState->mBufferUnrotate) {
newParameters.SetUnrotated();
}
mBuffer->SetParameters(newParameters);
canReuseBuffer = true;
}
mBuffer->SetParameters(newParameters);
canReuseBuffer = true;
}
}
@ -242,9 +261,16 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
newBuffer->BufferRect(),
});
if (!bufferState->PrepareBuffer()) {
gfxCriticalNote << "Failed to copy front buffer to back buffer.";
return result;
// If we're async painting then return the buffer state to
// be dispatched to the paint thread, otherwise do it now
if (asyncPaint) {
MOZ_ASSERT(!result.mBufferState);
result.mBufferState = bufferState;
} else {
if (!bufferState->PrepareBuffer()) {
gfxCriticalNote << "Failed to copy front buffer to back buffer.";
return result;
}
}
if (dest.mMustRemoveFrontBuffer) {

Просмотреть файл

@ -118,6 +118,7 @@ public:
SurfaceMode mMode;
DrawRegionClip mClip;
gfxContentType mContentType;
RefPtr<CapturedBufferState> mBufferState;
};
enum {

Просмотреть файл

@ -692,10 +692,6 @@ TextureClient::BorrowDrawTarget()
return nullptr;
}
if (!NS_IsMainThread()) {
return nullptr;
}
if (!mBorrowedDrawTarget) {
mBorrowedDrawTarget = mData->BorrowDrawTarget();
#ifdef DEBUG

Просмотреть файл

@ -768,7 +768,7 @@ CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
already_AddRefed<DrawTarget>
D3D11TextureData::BorrowDrawTarget()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread());
if (!mDrawTarget && mTexture) {
// This may return a null DrawTarget

Просмотреть файл

@ -1193,6 +1193,34 @@ CompositorBridgeChild::FlushAsyncPaints()
}
}
void
CompositorBridgeChild::NotifyBeginAsyncPrepareBuffer(CapturedBufferState* aState)
{
MOZ_ASSERT(NS_IsMainThread());
MonitorAutoLock lock(mPaintLock);
// We must not be waiting for paints (or buffer copying) to complete yet. This
// would imply we started a new paint without waiting for a previous one, which
// could lead to incorrect rendering or IPDL deadlocks.
MOZ_ASSERT(!mIsDelayingForAsyncPaints);
mOutstandingAsyncPaints++;
// Mark texture clients that they are being used for async painting, and
// make sure we hold them alive on the main thread.
aState->GetTextureClients(mTextureClientsForAsyncPaint);
}
void
CompositorBridgeChild::NotifyFinishedAsyncPrepareBuffer(CapturedBufferState* aState)
{
MOZ_ASSERT(PaintThread::IsOnPaintThread());
MonitorAutoLock lock(mPaintLock);
mOutstandingAsyncPaints--;
}
void
CompositorBridgeChild::NotifyBeginAsyncPaint(CapturedPaintState* aState)
{

Просмотреть файл

@ -45,6 +45,7 @@ class CompositorManagerChild;
class CompositorOptions;
class TextureClient;
class TextureClientPool;
class CapturedBufferState;
class CapturedPaintState;
struct FrameMetrics;
@ -227,6 +228,14 @@ public:
// operation completes.
void FlushAsyncPaints();
// Must only be called from the main thread. Notifies the CompositorBridge
// that the paint thread is going to begin preparing a buffer asynchronously.
void NotifyBeginAsyncPrepareBuffer(CapturedBufferState* aState);
// Must only be called from the paint thread. Notifies the CompositorBridge
// that the paint thread has finished an asynchronous buffer prepare.
void NotifyFinishedAsyncPrepareBuffer(CapturedBufferState* aState);
// Must only be called from the main thread. Notifies the CompositorBridge
// that the paint thread is going to begin painting asynchronously.
void NotifyBeginAsyncPaint(CapturedPaintState* aState);