Make a CaptureTiledPaintState for each tile (bug 1425056, r=bas) draft
authorRyan Hunt <rhunt@eqrion.net>
Thu, 07 Dec 2017 23:45:47 -0600
changeset 713693 3646c7c12727f777e7dd1994e8ab2f17ebeb329e
parent 713692 c856b693abc3196e3e7e771af6d6447e621d6d7c
child 713694 e7b08dc19e36ae00a59f8f27f97e4dab73ff5b71
push id93735
push userbmo:rhunt@eqrion.net
push dateWed, 20 Dec 2017 22:39:00 +0000
reviewersbas
bugs1425056
milestone59.0a1
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
gfx/layers/PaintThread.cpp
gfx/layers/PaintThread.h
gfx/layers/client/TiledContentClient.cpp
gfx/layers/client/TiledContentClient.h
--- 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