// Sync front/back buffers content // After executing, the new back buffer has the same (interesting) pixels as // the new front buffer, and mValidRegion et al. are correct wrt the new // back buffer (i.e. as they were for the old back buffer) void ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw) { if (mTextureClient) { DebugOnly<bool> locked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE); MOZ_ASSERT(locked); } if (mTextureClientOnWhite) { DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OpenMode::OPEN_READ_WRITE); MOZ_ASSERT(locked); } if (!mFrontAndBackBufferDiffer) { MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?"); return; } MOZ_ASSERT(mFrontClient); if (!mFrontClient) { return; } MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>", this, mFrontUpdatedRegion.GetBounds().x, mFrontUpdatedRegion.GetBounds().y, mFrontUpdatedRegion.GetBounds().width, mFrontUpdatedRegion.GetBounds().height)); mFrontAndBackBufferDiffer = false; nsIntRegion updateRegion = mFrontUpdatedRegion; if (mDidSelfCopy) { mDidSelfCopy = false; updateRegion = mBufferRect; } // No point in sync'ing what we are going to draw over anyway. And if there is // nothing to sync at all, there is nothing to do and we can go home early. updateRegion.Sub(updateRegion, aRegionToDraw); if (updateRegion.IsEmpty()) { return; } // We need to ensure that we lock these two buffers in the same // order as the compositor to prevent deadlocks. if (!mFrontClient->Lock(OpenMode::OPEN_READ_ONLY)) { return; } if (mFrontClientOnWhite && !mFrontClientOnWhite->Lock(OpenMode::OPEN_READ_ONLY)) { mFrontClient->Unlock(); return; } { // Restrict the DrawTargets and frontBuffer to a scope to make // sure there is no more external references to the DrawTargets // when we Unlock the TextureClients. RefPtr<SourceSurface> surf = mFrontClient->BorrowDrawTarget()->Snapshot(); RefPtr<SourceSurface> surfOnWhite = mFrontClientOnWhite ? mFrontClientOnWhite->BorrowDrawTarget()->Snapshot() : nullptr; SourceRotatedBuffer frontBuffer(surf, surfOnWhite, mFrontBufferRect, mFrontBufferRotation); UpdateDestinationFrom(frontBuffer, updateRegion); } mFrontClient->Unlock(); if (mFrontClientOnWhite) { mFrontClientOnWhite->Unlock(); } }
// Sync front/back buffers content // After executing, the new back buffer has the same (interesting) pixels as // the new front buffer, and mValidRegion et al. are correct wrt the new // back buffer (i.e. as they were for the old back buffer) void ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw) { if (mTextureClient) { DebugOnly<bool> locked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE); MOZ_ASSERT(locked); } if (mTextureClientOnWhite) { DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OpenMode::OPEN_READ_WRITE); MOZ_ASSERT(locked); } if (!mFrontAndBackBufferDiffer) { MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?"); return; } MOZ_ASSERT(mFrontClient); if (!mFrontClient) { return; } MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>", this, mFrontUpdatedRegion.GetBounds().x, mFrontUpdatedRegion.GetBounds().y, mFrontUpdatedRegion.GetBounds().width, mFrontUpdatedRegion.GetBounds().height)); mFrontAndBackBufferDiffer = false; nsIntRegion updateRegion = mFrontUpdatedRegion; if (mDidSelfCopy) { mDidSelfCopy = false; updateRegion = mBufferRect; } // No point in sync'ing what we are going to draw over anyway. And if there is // nothing to sync at all, there is nothing to do and we can go home early. updateRegion.Sub(updateRegion, aRegionToDraw); if (updateRegion.IsEmpty()) { return; } // We need to ensure that we lock these two buffers in the same // order as the compositor to prevent deadlocks. TextureClientAutoLock frontLock(mFrontClient, OpenMode::OPEN_READ_ONLY); if (!frontLock.Succeeded()) { return; } Maybe<TextureClientAutoLock> frontOnWhiteLock; if (mFrontClientOnWhite) { frontOnWhiteLock.emplace(mFrontClientOnWhite, OpenMode::OPEN_READ_ONLY); if (!frontOnWhiteLock->Succeeded()) { return; } } // Restrict the DrawTargets and frontBuffer to a scope to make // sure there is no more external references to the DrawTargets // when we Unlock the TextureClients. gfx::DrawTarget* dt = mFrontClient->BorrowDrawTarget(); gfx::DrawTarget* dtw = mFrontClientOnWhite ? mFrontClientOnWhite->BorrowDrawTarget() : nullptr; if (dt && dt->IsValid()) { RefPtr<SourceSurface> surf = dt->Snapshot(); RefPtr<SourceSurface> surfOnWhite = dtw ? dtw->Snapshot() : nullptr; SourceRotatedBuffer frontBuffer(surf, surfOnWhite, mFrontBufferRect, mFrontBufferRotation); UpdateDestinationFrom(frontBuffer, updateRegion); } else { // We know this can happen, but we want to track it somewhat, in case it leads // to other problems. gfxCriticalNote << "Invalid draw target(s) " << hexa(dt) << " and " << hexa(dtw); } }
void ContentClientDoubleBuffered::SyncFrontBufferToBackBuffer() { if (!mFrontAndBackBufferDiffer) { return; } MOZ_ASSERT(mFrontClient); MOZ_ASSERT(mFrontClient->GetAccessMode() == TextureClient::ACCESS_READ_ONLY); MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>", this, mFrontUpdatedRegion.GetBounds().x, mFrontUpdatedRegion.GetBounds().y, mFrontUpdatedRegion.GetBounds().width, mFrontUpdatedRegion.GetBounds().height)); nsIntRegion updateRegion = mFrontUpdatedRegion; int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x; int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y; // Figure out whether the area we want to copy wraps the edges of our buffer. bool needFullCopy = (xBoundary < updateRegion.GetBounds().XMost() && xBoundary > updateRegion.GetBounds().x) || (yBoundary < updateRegion.GetBounds().YMost() && yBoundary > updateRegion.GetBounds().y); // This is a tricky trade off, we're going to get stuff out of our // frontbuffer now, but the next PaintThebes might throw it all (or mostly) // away if the visible region has changed. This is why in reality we want // this code integrated with PaintThebes to always do the optimal thing. if (needFullCopy) { // We can't easily draw our front buffer into us, since we're going to be // copying stuff around anyway it's easiest if we just move our situation // to non-rotated while we're at it. If this situation occurs we'll have // hit a self-copy path in PaintThebes before as well anyway. mBufferRect.MoveTo(mFrontBufferRect.TopLeft()); mBufferRotation = nsIntPoint(); updateRegion = mBufferRect; } else { mBufferRect = mFrontBufferRect; mBufferRotation = mFrontBufferRotation; } AutoTextureClient autoTextureFront; if (gfxPlatform::GetPlatform()->SupportsAzureContent()) { RotatedBuffer frontBuffer(autoTextureFront.GetDrawTarget(mFrontClient), mFrontBufferRect, mFrontBufferRotation); UpdateDestinationFrom(frontBuffer, updateRegion); } else { RotatedBuffer frontBuffer(autoTextureFront.GetSurface(mFrontClient), mFrontBufferRect, mFrontBufferRotation); UpdateDestinationFrom(frontBuffer, updateRegion); } mIsNewBuffer = false; mFrontAndBackBufferDiffer = false; }
void ContentClientDoubleBuffered::SyncFrontBufferToBackBuffer() { mIsNewBuffer = false; if (!mFrontAndBackBufferDiffer) { return; } MOZ_ASSERT(mFrontClient); MOZ_ASSERT(mFrontClient->GetAccessMode() == DeprecatedTextureClient::ACCESS_READ_ONLY); MOZ_ASSERT(!mFrontClientOnWhite || mFrontClientOnWhite->GetAccessMode() == DeprecatedTextureClient::ACCESS_READ_ONLY); MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>", this, mFrontUpdatedRegion.GetBounds().x, mFrontUpdatedRegion.GetBounds().y, mFrontUpdatedRegion.GetBounds().width, mFrontUpdatedRegion.GetBounds().height)); nsIntRegion updateRegion = mFrontUpdatedRegion; // This is a tricky trade off, we're going to get stuff out of our // frontbuffer now, but the next PaintThebes might throw it all (or mostly) // away if the visible region has changed. This is why in reality we want // this code integrated with PaintThebes to always do the optimal thing. if (mDidSelfCopy) { mDidSelfCopy = false; // We can't easily draw our front buffer into us, since we're going to be // copying stuff around anyway it's easiest if we just move our situation // to non-rotated while we're at it. If this situation occurs we'll have // hit a self-copy path in PaintThebes before as well anyway. mBufferRect.MoveTo(mFrontBufferRect.TopLeft()); mBufferRotation = nsIntPoint(); updateRegion = mBufferRect; } else { mBufferRect = mFrontBufferRect; mBufferRotation = mFrontBufferRotation; } AutoDeprecatedTextureClient autoTextureFront; AutoDeprecatedTextureClient autoTextureFrontOnWhite; if (SupportsAzureContent()) { // We need to ensure that we lock these two buffers in the same // order as the compositor to prevent deadlocks. DrawTarget* dt = autoTextureFront.GetDrawTarget(mFrontClient); DrawTarget* dtOnWhite = autoTextureFrontOnWhite.GetDrawTarget(mFrontClientOnWhite); RotatedBuffer frontBuffer(dt, dtOnWhite, mFrontBufferRect, mFrontBufferRotation); UpdateDestinationFrom(frontBuffer, updateRegion); } else { gfxASurface* surf = autoTextureFront.GetSurface(mFrontClient); gfxASurface* surfOnWhite = autoTextureFrontOnWhite.GetSurface(mFrontClientOnWhite); RotatedBuffer frontBuffer(surf, surfOnWhite, mFrontBufferRect, mFrontBufferRotation); UpdateDestinationFrom(frontBuffer, updateRegion); } mFrontAndBackBufferDiffer = false; }