Preserve front buffer texture clients for copies (bug 1422392, r=nical) draft
authorRyan Hunt <rhunt@eqrion.net>
Tue, 05 Dec 2017 16:32:47 -0500
changeset 708369 3896b86d78c01a238d6d7cedf30c0a9165af562b
parent 708368 9d391cc92ae39b81131fd4c4ee971c2f971859c9
child 708370 e7ce93e543e439df5127918eee3a3573f8db66d5
push id92378
push userbmo:rhunt@eqrion.net
push dateWed, 06 Dec 2017 20:15:21 +0000
reviewersnical
bugs1422392
milestone59.0a1
Preserve front buffer texture clients for copies (bug 1422392, r=nical) We collect the back buffer texture clients to preserve while async painting is happening, but if we do a buffer copy we should preserve front buffer clients as well. MozReview-Commit-ID: 9KbXkqjm34v
gfx/layers/client/SingleTiledContentClient.cpp
gfx/layers/client/TiledContentClient.cpp
gfx/layers/client/TiledContentClient.h
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -139,29 +139,31 @@ 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<RefPtr<TextureClient>> paintClients;
   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,
                         aFlags,
                         &backBufferOnWhite,
-                        &paintCopies);
+                        &paintCopies,
+                        &paintClients);
 
   // 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));
@@ -288,16 +290,17 @@ ClientSingleTiledLayerBuffer::PaintThebe
     ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
     aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
     ctx = nullptr;
 
     // Replay on the paint thread
     RefPtr<CapturedTiledPaintState> capturedState =
       new CapturedTiledPaintState(dt,
                                   captureDT);
+    capturedState->mClients = std::move(paintClients);
     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);
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -474,17 +474,18 @@ TileClient::Flip()
   mInvalidBack = invalidFront;
 }
 
 static bool
 CopyFrontToBack(TextureClient* aFront,
                 TextureClient* aBack,
                 const gfx::IntRect& aRectToCopy,
                 TilePaintFlags aFlags,
-                std::vector<CapturedTiledPaintState::Copy>* aCopies)
+                std::vector<CapturedTiledPaintState::Copy>* aCopies,
+                std::vector<RefPtr<TextureClient>>* aClients)
 {
   bool asyncPaint = !!(aFlags & TilePaintFlags::Async);
   OpenMode asyncFlags = asyncPaint ? OpenMode::OPEN_ASYNC : OpenMode::OPEN_NONE;
 
   TextureClientAutoLock frontLock(aFront, OpenMode::OPEN_READ | asyncFlags);
   if (!frontLock.Succeeded()) {
     return false;
   }
@@ -506,28 +507,30 @@ CopyFrontToBack(TextureClient* aFront,
     return false;
   }
 
   auto copy = CapturedTiledPaintState::Copy{
     frontBuffer, backBuffer, aRectToCopy, aRectToCopy.TopLeft()
   };
 
   if (asyncPaint && aCopies) {
+    aClients->push_back(aFront);
     aCopies->push_back(copy);
   } else {
     copy.CopyBuffer();
   }
   return true;
 }
 
 void
 TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
                                         nsIntRegion& aAddPaintedRegion,
                                         TilePaintFlags aFlags,
-                                        std::vector<CapturedTiledPaintState::Copy>* aCopies)
+                                        std::vector<CapturedTiledPaintState::Copy>* aCopies,
+                                        std::vector<RefPtr<TextureClient>>* aClients)
 {
   if (mBackBuffer && mFrontBuffer) {
     gfx::IntSize tileSize = mFrontBuffer->GetSize();
     const IntRect tileRect = IntRect(0, 0, tileSize.width, tileSize.height);
 
     if (aDirtyRegion.Contains(tileRect)) {
       // The dirty region means that we no longer need the front buffer, so
       // discard it.
@@ -545,20 +548,20 @@ TileClient::ValidateBackBufferFromFront(
         return;
       }
 
       // Copy the bounding rect of regionToCopy. As tiles are quite small, it
       // is unlikely that we'd save much by copying each individual rect of the
       // region, but we can reevaluate this if it becomes an issue.
       const IntRect rectToCopy = regionToCopy.GetBounds();
       gfx::IntRect gfxRectToCopy(rectToCopy.x, rectToCopy.y, rectToCopy.Width(), rectToCopy.Height());
-      if (CopyFrontToBack(mFrontBuffer, mBackBuffer, gfxRectToCopy, aFlags, aCopies)) {
+      if (CopyFrontToBack(mFrontBuffer, mBackBuffer, gfxRectToCopy, aFlags, aCopies, aClients)) {
         if (mBackBufferOnWhite) {
           MOZ_ASSERT(mFrontBufferOnWhite);
-          if (CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, gfxRectToCopy, aFlags, aCopies)) {
+          if (CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, gfxRectToCopy, aFlags, aCopies, aClients)) {
             mInvalidBack.SetEmpty();
           }
         }
       }
     }
   }
 }
 
@@ -650,17 +653,18 @@ CreateBackBufferTexture(TextureClient* a
 TextureClient*
 TileClient::GetBackBuffer(CompositableClient& aCompositable,
                           const nsIntRegion& aDirtyRegion,
                           gfxContentType aContent,
                           SurfaceMode aMode,
                           nsIntRegion& aAddPaintedRegion,
                           TilePaintFlags aFlags,
                           RefPtr<TextureClient>* aBackBufferOnWhite,
-                          std::vector<CapturedTiledPaintState::Copy>* aCopies)
+                          std::vector<CapturedTiledPaintState::Copy>* aCopies,
+                          std::vector<RefPtr<TextureClient>>* aClients)
 {
   if (!mAllocator) {
     gfxCriticalError() << "[TileClient] Missing TextureClientAllocator.";
     return nullptr;
   }
   if (aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA) {
     // It can happen that a component-alpha layer stops being on component alpha
     // on the next frame, just drop the buffers on white if that happens.
@@ -705,17 +709,17 @@ TileClient::GetBackBuffer(CompositableCl
       if (!mBackBufferOnWhite) {
         DiscardBackBuffer();
         DiscardFrontBuffer();
         return nullptr;
       }
       mInvalidBack = IntRect(IntPoint(), mBackBufferOnWhite->GetSize());
     }
 
-    ValidateBackBufferFromFront(aDirtyRegion, aAddPaintedRegion, aFlags, aCopies);
+    ValidateBackBufferFromFront(aDirtyRegion, aAddPaintedRegion, aFlags, aCopies, aClients);
   }
 
   OpenMode lockMode = aFlags & TilePaintFlags::Async ? OpenMode::OPEN_READ_WRITE_ASYNC
                                                      : OpenMode::OPEN_READ_WRITE;
 
   if (!mBackBuffer->IsLocked()) {
     if (!mBackBuffer->Lock(lockMode)) {
       gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (B)";
@@ -1146,17 +1150,18 @@ ClientMultiTiledLayerBuffer::ValidateTil
   RefPtr<TextureClient> backBufferOnWhite;
   RefPtr<TextureClient> backBuffer =
     aTile.GetBackBuffer(mCompositableClient,
                         offsetScaledDirtyRegion,
                         content, mode,
                         extraPainted,
                         aFlags,
                         &backBufferOnWhite,
-                        &mPaintCopies);
+                        &mPaintCopies,
+                        &mPaintTilesTextureClients);
 
   // 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;
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -127,17 +127,18 @@ struct TileClient
   * If nullptr is returned, aTextureClientOnWhite is undefined.
   */
   TextureClient* GetBackBuffer(CompositableClient&,
                                const nsIntRegion& aDirtyRegion,
                                gfxContentType aContent, SurfaceMode aMode,
                                nsIntRegion& aAddPaintedRegion,
                                TilePaintFlags aFlags,
                                RefPtr<TextureClient>* aTextureClientOnWhite,
-                               std::vector<CapturedTiledPaintState::Copy>* aCopies);
+                               std::vector<CapturedTiledPaintState::Copy>* aCopies,
+                               std::vector<RefPtr<TextureClient>>* aClients);
 
   void DiscardFrontBuffer();
 
   void DiscardBackBuffer();
 
   /* We wrap the back buffer in a class that disallows assignment
    * so that we can track when ever it changes so that we can update
    * the expiry tracker for expiring the back buffers */
@@ -166,17 +167,18 @@ struct TileClient
   nsIntRegion mInvalidBack;
   nsExpirationState mExpirationState;
 private:
   // Copies dirty pixels from the front buffer into the back buffer,
   // and records the copied region in aAddPaintedRegion.
   void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion,
                                    nsIntRegion& aAddPaintedRegion,
                                    TilePaintFlags aFlags,
-                                   std::vector<CapturedTiledPaintState::Copy>* aCopies);
+                                   std::vector<CapturedTiledPaintState::Copy>* aCopies,
+                                   std::vector<RefPtr<TextureClient>>* aClients);
 };
 
 /**
  * This struct stores all the data necessary to perform a paint so that it
  * doesn't need to be recalculated on every repeated transaction.
  */
 struct BasicTiledLayerPaintData {
   /*