Make a CaptureTiledPaintState for each tile (
bug 1425056, r=bas)
This makes it so that each tile of a paint gets a DrawTargetCapture and
its own buffer operations. Once this is done, each CaptureTiledPaintState
will be isolated from each other and able to be done in parallel.
MozReview-Commit-ID: BuBDXgjma4z
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -381,17 +381,17 @@ PaintThread::AsyncPaintTiledContents(Com
for (auto& copy : aState->mCopies) {
copy.CopyBuffer();
}
for (auto& clear : aState->mClears) {
clear.ClearBuffer();
}
- DrawTarget* target = aState->mTargetTiled;
+ DrawTarget* target = aState->mTarget;
DrawTargetCapture* capture = aState->mCapture;
// Draw all the things into the actual dest target.
target->DrawCapturedDT(capture, Matrix());
target->Flush();
if (gfxPrefs::LayersOMTPReleaseCaptureOnMainThread()) {
// This should ensure the capture drawtarget, which may hold on to UnscaledFont objects,
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -211,36 +211,38 @@ public:
void ClearBuffer();
RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTarget> mTargetOnWhite;
nsIntRegion mDirtyRegion;
};
- CapturedTiledPaintState(gfx::DrawTarget* aTargetTiled,
+ CapturedTiledPaintState()
+ {}
+ CapturedTiledPaintState(gfx::DrawTarget* aTarget,
gfx::DrawTargetCapture* aCapture)
- : mTargetTiled(aTargetTiled)
+ : mTarget(aTarget)
, mCapture(aCapture)
{}
template<typename F>
void ForEachTextureClient(F aClosure) const
{
for (auto client : mClients) {
aClosure(client);
}
}
void DropTextureClients()
{
mClients.clear();
}
- RefPtr<gfx::DrawTarget> mTargetTiled;
+ RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTargetCapture> mCapture;
std::vector<Copy> mCopies;
std::vector<Clear> mClears;
std::vector<RefPtr<TextureClient>> mClients;
protected:
virtual ~CapturedTiledPaintState() {}
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -985,18 +985,17 @@ void ClientMultiTiledLayerBuffer::Update
}
}
oldRetainedTiles.Clear();
nsIntRegion paintRegion = aPaintRegion;
nsIntRegion dirtyRegion = aDirtyRegion;
if (!paintRegion.IsEmpty()) {
- MOZ_ASSERT(mPaintClears.size() == 0);
- MOZ_ASSERT(mPaintCopies.size() == 0);
+ MOZ_ASSERT(mPaintStates.size() == 0);
for (size_t i = 0; i < newTileCount; ++i) {
const TileIntPoint tilePosition = newTiles.TilePosition(i);
IntPoint tileOffset = GetTileOffset(tilePosition);
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
tileDrawRegion.AndWith(paintRegion);
if (tileDrawRegion.IsEmpty()) {
@@ -1023,60 +1022,39 @@ void ClientMultiTiledLayerBuffer::Update
tileset.mTileCount = mPaintTiles.size();
RefPtr<DrawTarget> drawTarget = gfx::Factory::CreateTiledDrawTarget(tileset);
if (!drawTarget || !drawTarget->IsValid()) {
gfxDevCrash(LogReason::InvalidContext) << "Invalid tiled draw target";
return;
}
drawTarget->SetTransform(Matrix());
- if (aFlags & TilePaintFlags::Async) {
- // Create a capture draw target
- RefPtr<DrawTargetCapture> captureDT =
- Factory::CreateCaptureDrawTarget(drawTarget->GetBackendType(),
- drawTarget->GetSize(),
- drawTarget->GetFormat());
+ // Draw into the tiled draw target
+ RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(drawTarget);
+ MOZ_ASSERT(ctx); // already checked the draw target above
+ ctx->SetMatrix(
+ ctx->CurrentMatrix().PreScale(mResolution, mResolution).PreTranslate(-mTilingOrigin));
- // Draw into the capture target
- RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(captureDT);
- MOZ_ASSERT(ctx); // already checked the draw target above
- ctx->SetMatrix(
- ctx->CurrentMatrix().PreScale(mResolution, mResolution).PreTranslate(-mTilingOrigin));
-
- mCallback(&mPaintedLayer, ctx, paintRegion, dirtyRegion,
- DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
- ctx = nullptr;
+ mCallback(&mPaintedLayer, ctx, paintRegion, dirtyRegion,
+ DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
+ ctx = nullptr;
- // Replay on the paint thread
- RefPtr<CapturedTiledPaintState> capturedState =
- new CapturedTiledPaintState(drawTarget,
- captureDT);
- capturedState->mClients = std::move(mPaintTilesTextureClients);
- capturedState->mCopies = std::move(mPaintCopies);
- capturedState->mClears = std::move(mPaintClears);
-
- PaintThread::Get()->PaintTiledContents(capturedState);
+ if (aFlags & TilePaintFlags::Async) {
+ for (const auto& state : mPaintStates) {
+ PaintThread::Get()->PaintTiledContents(state);
+ }
mManager->SetQueuedAsyncPaints();
+ MOZ_ASSERT(mPaintStates.size() > 0);
+ mPaintStates.clear();
} else {
- MOZ_ASSERT(mPaintCopies.size() == 0);
- MOZ_ASSERT(mPaintClears.size() == 0);
-
- // Draw into the tiled draw target
- RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(drawTarget);
- MOZ_ASSERT(ctx); // already checked the draw target above
- ctx->SetMatrix(
- ctx->CurrentMatrix().PreScale(mResolution, mResolution).PreTranslate(-mTilingOrigin));
-
- mCallback(&mPaintedLayer, ctx, paintRegion, dirtyRegion,
- DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
+ MOZ_ASSERT(mPaintStates.size() == 0);
}
// Reset
mPaintTiles.clear();
- mPaintTilesTextureClients.clear();
mTilingOrigin = IntPoint(std::numeric_limits<int32_t>::max(),
std::numeric_limits<int32_t>::max());
}
bool edgePaddingEnabled = gfxPrefs::TileEdgePaddingEnabled();
for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
TileClient& tile = mRetainedTiles[i];
@@ -1141,27 +1119,30 @@ ClientMultiTiledLayerBuffer::ValidateTil
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content),
TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD));
MOZ_ASSERT(aTile.mAllocator);
}
nsIntRegion offsetScaledDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
offsetScaledDirtyRegion.ScaleRoundOut(mResolution, mResolution);
+ std::vector<CapturedTiledPaintState::Copy> asyncPaintCopies;
+ std::vector<RefPtr<TextureClient>> asyncPaintClients;
+
nsIntRegion extraPainted;
RefPtr<TextureClient> backBufferOnWhite;
RefPtr<TextureClient> backBuffer =
aTile.GetBackBuffer(mCompositableClient,
offsetScaledDirtyRegion,
content, mode,
extraPainted,
aFlags,
&backBufferOnWhite,
- &mPaintCopies,
- &mPaintTilesTextureClients);
+ &asyncPaintCopies,
+ &asyncPaintClients);
// Mark the area we need to paint in the back buffer as invalid in the
// front buffer as they will become out of sync.
aTile.mInvalidFront.OrWith(offsetScaledDirtyRegion);
// 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.
nsIntRegion invalidBack = aTile.mInvalidBack;
@@ -1176,54 +1157,74 @@ ClientMultiTiledLayerBuffer::ValidateTil
extraPainted.MoveBy(aTileOrigin);
extraPainted.And(extraPainted, mNewValidRegion);
mPaintedRegion.Or(mPaintedRegion, extraPainted);
if (!backBuffer) {
return false;
}
- gfx::Tile paintTile;
RefPtr<DrawTarget> dt = backBuffer->BorrowDrawTarget();
RefPtr<DrawTarget> dtOnWhite;
if (backBufferOnWhite) {
dtOnWhite = backBufferOnWhite->BorrowDrawTarget();
- paintTile.mDrawTarget = Factory::CreateDualDrawTarget(dt, dtOnWhite);
- } else {
- paintTile.mDrawTarget = dt;
}
- paintTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
+
if (!dt || (backBufferOnWhite && !dtOnWhite)) {
aTile.DiscardBuffers();
return false;
}
- mPaintTiles.push_back(paintTile);
- mTilingOrigin.x = std::min(mTilingOrigin.x, paintTile.mTileOrigin.x);
- mTilingOrigin.y = std::min(mTilingOrigin.y, paintTile.mTileOrigin.y);
-
- if (aFlags & TilePaintFlags::Async) {
- mPaintTilesTextureClients.push_back(backBuffer);
- if (backBufferOnWhite) {
- mPaintTilesTextureClients.push_back(backBufferOnWhite);
- }
+ RefPtr<DrawTarget> drawTarget;
+ if (dtOnWhite) {
+ drawTarget = Factory::CreateDualDrawTarget(dt, dtOnWhite);
+ } else {
+ drawTarget = dt;
}
auto clear = CapturedTiledPaintState::Clear{
dt,
dtOnWhite,
offsetScaledDirtyRegion
};
+ gfx::Tile paintTile;
+ paintTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
+
if (aFlags & TilePaintFlags::Async) {
- mPaintClears.push_back(clear);
+ RefPtr<CapturedTiledPaintState> asyncPaint = new CapturedTiledPaintState();
+
+ RefPtr<DrawTargetCapture> captureDT =
+ Factory::CreateCaptureDrawTarget(drawTarget->GetBackendType(),
+ drawTarget->GetSize(),
+ drawTarget->GetFormat());
+ paintTile.mDrawTarget = captureDT;
+ asyncPaint->mTarget = drawTarget;
+ asyncPaint->mCapture = captureDT;
+
+ asyncPaint->mCopies = std::move(asyncPaintCopies);
+ asyncPaint->mClears.push_back(clear);
+
+ asyncPaint->mClients = std::move(asyncPaintClients);
+ asyncPaint->mClients.push_back(backBuffer);
+ if (backBufferOnWhite) {
+ asyncPaint->mClients.push_back(backBufferOnWhite);
+ }
+
+ mPaintStates.push_back(asyncPaint);
} else {
+ paintTile.mDrawTarget = drawTarget;
clear.ClearBuffer();
}
+ mPaintTiles.push_back(paintTile);
+
+ mTilingOrigin.x = std::min(mTilingOrigin.x, paintTile.mTileOrigin.x);
+ mTilingOrigin.y = std::min(mTilingOrigin.y, paintTile.mTileOrigin.y);
+
// The new buffer is now validated, remove the dirty region from it.
aTile.mInvalidBack.SubOut(offsetScaledDirtyRegion);
aTile.Flip();
return true;
}
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -445,19 +445,17 @@ private:
// completed then this is identical to mValidRegion.
nsIntRegion mNewValidRegion;
SharedFrameMetricsHelper* mSharedFrameMetricsHelper;
// Parameters that are collected during Update for a paint before they
// are either executed or replayed on the paint thread.
std::vector<gfx::Tile> mPaintTiles;
- std::vector<RefPtr<TextureClient>> mPaintTilesTextureClients;
- std::vector<CapturedTiledPaintState::Copy> mPaintCopies;
- std::vector<CapturedTiledPaintState::Clear> mPaintClears;
+ std::vector<RefPtr<CapturedTiledPaintState>> mPaintStates;
/**
* While we're adding tiles, this is used to keep track of the position of
* the top-left of the top-left-most tile. When we come to wrap the tiles in
* TiledDrawTarget we subtract the value of this member from each tile's
* offset so that all the tiles have a positive offset, then add a
* translation to the TiledDrawTarget to compensate. This is important so
* that the mRect of the TiledDrawTarget is always at a positive x/y