// 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(); } }
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; }
// This is the function that creates the screen presentation, by compositing the // top-level windows on the root window. void Workspace::repaint() { // If there's no damage, update the whole display if ( mDamage == None || mInitialRepaint ) { XRectangle r = { 0, 0, width(), height() }; XserverRegion region = XFixesCreateRegion( dpy, &r, 1 ); if ( mDamage ) XFixesDestroyRegion( dpy, mDamage ); mDamage = region; mInitialRepaint = false; } // Use the damage region as the clip region for the root window XFixesSetPictureClipRegion( dpy, frontBuffer(), 0, 0, mDamage ); // Client list for clients that are either translucent, or have a shadow ClientList translucents; // Draw each opaque window top to bottom, subtracting the bounding rect of // each drawn window from the clip region. ClientList::ConstIterator end = mList.constEnd(); for ( ClientList::ConstIterator it = mList.constBegin(); it != end; ++it ) { Client *client = *it; if ( !client->isVisible() || !client->isPainted() ) continue; // Update the region containing the area the window was last rendered at. client->updateOnScreenRegion(); // Only draw the window if it's opaque if ( client->isOpaque() ) { // Set the clip region for the backbuffer to the damage region, and // subtract the clients shape from the damage region XFixesSetPictureClipRegion( dpy, backBuffer(), 0, 0, mDamage ); XFixesSubtractRegion( dpy, mDamage, mDamage, client->shape() ); XRenderComposite( dpy, PictOpSrc, client->picture(), None, backBuffer(), 0, 0, 0, 0, client->x(), client->y(), client->width() + client->borderWidth() * 2, client->height() + client->borderWidth() * 2 ); } // Save the clip region before the next client shape is subtracted from it. // We need to restore it later when we're drawing the shadow. client->setShapeClip( mDamage ); translucents.prepend( client ); } // Draw any areas of the root window not covered by windows XFixesSetPictureClipRegion( dpy, backBuffer(), 0, 0, mDamage ); XRenderComposite( dpy, PictOpSrc, rootTile(), None, backBuffer(), 0, 0, 0, 0, 0, 0, width(), height() ); // Now walk the list backwards, drawing translucent windows and shadows. // That we draw bottom to top is important now since we're drawing translucent windows. end = translucents.constEnd(); for ( ClientList::ConstIterator it = translucents.constBegin(); it != end; ++it ) { Client *client = *it; // Restore the previously saved clip region XFixesSetPictureClipRegion( dpy, backBuffer(), 0, 0, client->shapeClip() ); // Only draw the window if it's translucent // (we drew the opaque ones in the previous loop) if ( !client->isOpaque() ) XRenderComposite( dpy, PictOpOver, client->picture(), client->alphaMask(), backBuffer(), 0, 0, 0, 0, client->x() + client->borderWidth(), client->y() + client->borderWidth(), client->width(), client->height() ); // We don't need the clip region anymore client->destroyShapeClip(); } translucents.clear(); // Destroy the damage region XFixesDestroyRegion( dpy, mDamage ); mDamage = None; // Copy the back buffer contents to the root window XFixesSetPictureClipRegion( dpy, backBuffer(), 0, 0, None ); XRenderComposite( dpy, PictOpSrc, backBuffer(), None, frontBuffer(), 0, 0, 0, 0, 0, 0, width(), height() ); }
// 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() { 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; }