зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
cc9ba81109
Коммит
c34dc7e2af
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче