Implement buffer copying and clearing on the paint thread for single tiled layers (
bug 1422392, r=nical)
MozReview-Commit-ID: d6XPUYCz18
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -99,18 +99,18 @@ CapturedTiledPaintState::Copy::CopyBuffe
{
RefPtr<gfx::SourceSurface> source = mSource->Snapshot();
// This operation requires the destination draw target to be untranslated,
// but the destination will have a transform from being part of a tiled draw
// target. However in this case, CopySurface ignores transforms so we don't
// need to do anything.
mDestination->CopySurface(source,
- mBounds,
- mBounds.TopLeft());
+ mSourceBounds,
+ mDestinationPoint);
return true;
}
void
CapturedTiledPaintState::Clear::ClearBuffer()
{
// See the comment in CopyBuffer for why we need to temporarily reset
// the transform of the draw target.
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -115,27 +115,30 @@ typedef bool (*PrepDrawTargetForPainting
// Holds the key operations needed to update a tiled content client on the
// paint thread.
class CapturedTiledPaintState {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CapturedPaintState)
public:
struct Copy {
Copy(RefPtr<gfx::DrawTarget> aSource,
RefPtr<gfx::DrawTarget> aDestination,
- gfx::IntRect aBounds)
+ gfx::IntRect aSourceBounds,
+ gfx::IntPoint aDestinationPoint)
: mSource(aSource)
, mDestination(aDestination)
- , mBounds(aBounds)
+ , mSourceBounds(aSourceBounds)
+ , mDestinationPoint(aDestinationPoint)
{}
bool CopyBuffer();
RefPtr<gfx::DrawTarget> mSource;
RefPtr<gfx::DrawTarget> mDestination;
- gfx::IntRect mBounds;
+ gfx::IntRect mSourceBounds;
+ gfx::IntPoint mDestinationPoint;
};
struct Clear {
Clear(RefPtr<gfx::DrawTarget> aTarget,
RefPtr<gfx::DrawTarget> aTargetOnWhite,
nsIntRegion aDirtyRegion)
: mTarget(aTarget)
, mTargetOnWhite(aTargetOnWhite)
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -139,26 +139,29 @@ ClientSingleTiledLayerBuffer::PaintThebe
if (mTile.IsPlaceholderTile()) {
mTile.SetTextureAllocator(this);
}
// The dirty region relative to the top-left of the tile.
nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin);
+ std::vector<CapturedTiledPaintState::Copy> paintCopies;
+ std::vector<CapturedTiledPaintState::Clear> paintClears;
+
nsIntRegion extraPainted;
RefPtr<TextureClient> backBufferOnWhite;
RefPtr<TextureClient> backBuffer =
mTile.GetBackBuffer(mCompositableClient,
tileDirtyRegion,
content, mode,
extraPainted,
- TilePaintFlags::None,
+ aFlags,
&backBufferOnWhite,
- nullptr);
+ &paintCopies);
// Mark the area we need to paint in the back buffer as invalid in the
// front buffer as they will become out of sync.
mTile.mInvalidFront.OrWith(tileDirtyRegion);
// Add backbuffer's invalid region to the dirty region to be painted.
// This will be empty if we were able to copy from the front in to the back.
paintRegion.OrWith(mTile.mInvalidBack.MovedBy(mTilingOrigin));
@@ -177,59 +180,89 @@ ClientSingleTiledLayerBuffer::PaintThebe
RefPtr<gfx::DrawTarget> dt = backBuffer->BorrowDrawTarget();
RefPtr<gfx::DrawTarget> dtOnWhite;
if (backBufferOnWhite) {
dtOnWhite = backBufferOnWhite->BorrowDrawTarget();
}
if (mode != SurfaceMode::SURFACE_OPAQUE) {
- for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
- const gfx::IntRect& rect = iter.Get();
- if (dtOnWhite) {
- dt->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height),
- gfx::ColorPattern(gfx::Color(0.0, 0.0, 0.0, 1.0)));
- dtOnWhite->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height),
- gfx::ColorPattern(gfx::Color(1.0, 1.0, 1.0, 1.0)));
- } else {
- dt->ClearRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height));
- }
+ auto clear = CapturedTiledPaintState::Clear{
+ dt,
+ dtOnWhite,
+ tileDirtyRegion,
+ };
+
+ if (asyncPaint) {
+ paintClears.push_back(clear);
+ } else {
+ clear.ClearBuffer();
}
}
// If the old frontbuffer was discarded then attempt to copy what we
// can from it to the new backbuffer.
if (discardedFrontBuffer) {
nsIntRegion copyableRegion;
copyableRegion.And(aNewValidRegion, discardedValidRegion);
copyableRegion.SubOut(aDirtyRegion);
if (!copyableRegion.IsEmpty()) {
+ OpenMode asyncFlags = asyncPaint ? OpenMode::OPEN_ASYNC
+ : OpenMode::OPEN_NONE;
+
TextureClientAutoLock frontLock(discardedFrontBuffer,
- OpenMode::OPEN_READ);
+ OpenMode::OPEN_READ | asyncFlags);
Maybe<TextureClientAutoLock> frontOnWhiteLock;
if (discardedFrontBufferOnWhite && backBufferOnWhite) {
- frontOnWhiteLock.emplace(discardedFrontBufferOnWhite, OpenMode::OPEN_READ);
+ frontOnWhiteLock.emplace(discardedFrontBufferOnWhite, OpenMode::OPEN_READ | asyncFlags);
}
// Copy to both backBuffer and backBufferOnWhite if required, or copy to neither.
if (frontLock.Succeeded() && (!frontOnWhiteLock || frontOnWhiteLock->Succeeded())) {
- for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
- const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
- const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
- discardedFrontBuffer->CopyToTextureClient(backBuffer, &rect, &dest);
- }
+ RefPtr<gfx::DrawTarget> frontBuffer = discardedFrontBuffer->BorrowDrawTarget();
- if (frontOnWhiteLock) {
+ if (frontBuffer) {
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
- discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite,
- &rect, &dest);
+
+ auto copy = CapturedTiledPaintState::Copy{
+ frontBuffer, dt, rect, dest
+ };
+ if (asyncPaint) {
+ paintCopies.push_back(copy);
+ } else {
+ copy.CopyBuffer();
+ }
}
+
+ if (frontOnWhiteLock) {
+ RefPtr<gfx::DrawTarget> frontBufferOnWhite = discardedFrontBufferOnWhite->BorrowDrawTarget();
+
+ if (frontBufferOnWhite) {
+ for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
+ const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
+ const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
+
+ auto copy = CapturedTiledPaintState::Copy{
+ frontBufferOnWhite, dtOnWhite, rect, dest
+ };
+ if (asyncPaint) {
+ paintCopies.push_back(copy);
+ } else {
+ copy.CopyBuffer();
+ }
+ }
+ }
+ } else {
+ gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
+ }
+ } else {
+ gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
}
TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
// We don't need to repaint valid content that was just copied.
paintRegion.SubOut(copyableRegion);
}
}
@@ -259,20 +292,25 @@ ClientSingleTiledLayerBuffer::PaintThebe
// Replay on the paint thread
RefPtr<CapturedTiledPaintState> capturedState =
new CapturedTiledPaintState(dt,
captureDT);
capturedState->mClients.push_back(backBuffer);
if (backBufferOnWhite) {
capturedState->mClients.push_back(backBufferOnWhite);
}
+ capturedState->mCopies = std::move(paintCopies);
+ capturedState->mClears = std::move(paintClears);
PaintThread::Get()->PaintTiledContents(capturedState);
mManager->SetQueuedAsyncPaints();
} else {
+ MOZ_ASSERT(paintCopies.size() == 0);
+ MOZ_ASSERT(paintClears.size() == 0);
+
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
if (!ctx) {
gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(dt);
return;
}
ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -502,17 +502,17 @@ CopyFrontToBack(TextureClient* aFront,
RefPtr<gfx::DrawTarget> frontBuffer = aFront->BorrowDrawTarget();
if (!frontBuffer) {
gfxWarning() << "[Tiling:Client] Failed to aquire the front buffer's draw target";
return false;
}
auto copy = CapturedTiledPaintState::Copy{
- frontBuffer, backBuffer, aRectToCopy
+ frontBuffer, backBuffer, aRectToCopy, aRectToCopy.TopLeft()
};
if (asyncPaint && aCopies) {
aCopies->push_back(copy);
} else {
copy.CopyBuffer();
}
return true;