Bug 1438551 - When creating a back buffer, only paint in the visible rect. r?nical draft
authorRyan Hunt <rhunt@eqrion.net>
Fri, 06 Apr 2018 14:36:39 -0500
changeset 781354 ef75615080ea4aa0bf248e4cbe8f9a1a0906f667
parent 780516 53424d957f8e77a2b7576aec1823e9b3012a4bcb
child 781355 ed41ea5568e69817a76947d986cb2f8761ebb5f3
child 781712 2e59607ef187fd9d5e2d5608c480e5da8d1d2af4
child 781717 588d6d81a8cda8b0cf8a3a64b0b8bbccad7eeb5b
push id106277
push userbmo:rhunt@eqrion.net
push dateThu, 12 Apr 2018 20:58:26 +0000
reviewersnical
bugs1438551
milestone61.0a1
Bug 1438551 - When creating a back buffer, only paint in the visible rect. r?nical When we are creating a new back buffer we mark the whole region as being invalid. This will cause us to paint extra in certain circumstances where the visible region is a subset of the tile space. MozReview-Commit-ID: BayRu0mV39O
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
@@ -137,43 +137,50 @@ ClientSingleTiledLayerBuffer::PaintThebe
   gfxContentType content = GetContentType(&mode);
   mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content);
 
   if (mTile.IsPlaceholderTile()) {
     mTile.SetTextureAllocator(this);
   }
 
   // The dirty region relative to the top-left of the tile.
+  nsIntRegion tileVisibleRegion = aNewValidRegion.MovedBy(-mTilingOrigin);
   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,
+                        tileVisibleRegion,
                         content, mode,
                         extraPainted,
                         aFlags,
                         &backBufferOnWhite,
                         &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));
-  tileDirtyRegion.OrWith(mTile.mInvalidBack);
+  nsIntRegion tileInvalidRegion = mTile.mInvalidBack;
+  tileInvalidRegion.AndWith(tileVisibleRegion);
 
+  paintRegion.OrWith(tileInvalidRegion.MovedBy(mTilingOrigin));
+  tileDirtyRegion.OrWith(tileInvalidRegion);
+
+  // Mark the region we will be painting and the region we copied from the front buffer as
+  // needing to be uploaded to the compositor
   mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
 
   extraPainted.MoveBy(mTilingOrigin);
   extraPainted.And(extraPainted, aNewValidRegion);
   mPaintedRegion.OrWith(paintRegion);
   mPaintedRegion.OrWith(extraPainted);
 
   if (!backBuffer) {
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -517,16 +517,17 @@ CopyFrontToBack(TextureClient* aFront,
   } else {
     copy.CopyBuffer();
   }
   return true;
 }
 
 void
 TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
+                                        const nsIntRegion& aVisibleRegion,
                                         nsIntRegion& aAddPaintedRegion,
                                         TilePaintFlags aFlags,
                                         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);
@@ -535,16 +536,17 @@ TileClient::ValidateBackBufferFromFront(
       // The dirty region means that we no longer need the front buffer, so
       // discard it.
       DiscardFrontBuffer();
     } else {
       // Region that needs copying.
       nsIntRegion regionToCopy = mInvalidBack;
 
       regionToCopy.Sub(regionToCopy, aDirtyRegion);
+      regionToCopy.And(regionToCopy, aVisibleRegion);
 
       aAddPaintedRegion = regionToCopy;
 
       if (regionToCopy.IsEmpty()) {
         // Just redraw it all.
         return;
       }
 
@@ -552,20 +554,20 @@ TileClient::ValidateBackBufferFromFront(
       // 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, aClients)) {
         if (mBackBufferOnWhite) {
           MOZ_ASSERT(mFrontBufferOnWhite);
           if (CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, gfxRectToCopy, aFlags, aCopies, aClients)) {
-            mInvalidBack.SetEmpty();
+            mInvalidBack.Sub(mInvalidBack, aVisibleRegion);
           }
         } else {
-          mInvalidBack.SetEmpty();
+          mInvalidBack.Sub(mInvalidBack, aVisibleRegion);
         }
       }
     }
   }
 }
 
 void
 TileClient::DiscardFrontBuffer()
@@ -648,16 +650,17 @@ CreateBackBufferTexture(TextureClient* a
   }
 
   return texture.forget();
 }
 
 TextureClient*
 TileClient::GetBackBuffer(CompositableClient& aCompositable,
                           const nsIntRegion& aDirtyRegion,
+                          const nsIntRegion& aVisibleRegion,
                           gfxContentType aContent,
                           SurfaceMode aMode,
                           nsIntRegion& aAddPaintedRegion,
                           TilePaintFlags aFlags,
                           RefPtr<TextureClient>* aBackBufferOnWhite,
                           std::vector<CapturedTiledPaintState::Copy>* aCopies,
                           std::vector<RefPtr<TextureClient>>* aClients)
 {
@@ -709,17 +712,17 @@ TileClient::GetBackBuffer(CompositableCl
       if (!mBackBufferOnWhite) {
         DiscardBackBuffer();
         DiscardFrontBuffer();
         return nullptr;
       }
       mInvalidBack = IntRect(IntPoint(), mBackBufferOnWhite->GetSize());
     }
 
-    ValidateBackBufferFromFront(aDirtyRegion, aAddPaintedRegion, aFlags, aCopies, aClients);
+    ValidateBackBufferFromFront(aDirtyRegion, aVisibleRegion, 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)";
@@ -1115,49 +1118,60 @@ ClientMultiTiledLayerBuffer::ValidateTil
   if (!aTile.mAllocator) {
     aTile.SetTextureAllocator(mManager->GetCompositorBridgeChild()->GetTexturePool(
       mManager->AsShadowForwarder(),
       gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content),
       TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD | TextureFlags::NON_BLOCKING_READ_LOCK));
     MOZ_ASSERT(aTile.mAllocator);
   }
 
-  nsIntRegion offsetScaledDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
-  offsetScaledDirtyRegion.ScaleRoundOut(mResolution, mResolution);
+  nsIntRegion tileDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
+  tileDirtyRegion.ScaleRoundOut(mResolution, mResolution);
+
+  nsIntRegion tileVisibleRegion = mNewValidRegion.MovedBy(-aTileOrigin);
+  tileVisibleRegion.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,
+                        tileDirtyRegion,
+                        tileVisibleRegion,
                         content, mode,
                         extraPainted,
                         aFlags,
                         &backBufferOnWhite,
                         &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);
+  aTile.mInvalidFront.OrWith(tileDirtyRegion);
+
+  // Add the backbuffer's invalid region intersected with the visible region to the
+  // dirty region we will be painting. This will be empty if we are able to copy
+  // from the front into the back.
+  nsIntRegion tileInvalidRegion = aTile.mInvalidBack;
+  tileInvalidRegion.AndWith(tileVisibleRegion);
 
-  // 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;
-  invalidBack.MoveBy(aTileOrigin);
-  invalidBack.ScaleInverseRoundOut(mResolution, mResolution);
-  invalidBack.AndWith(mNewValidRegion);
-  aDirtyRegion.OrWith(invalidBack);
-  offsetScaledDirtyRegion.OrWith(aTile.mInvalidBack);
+  nsIntRegion invalidRegion = tileInvalidRegion;
+  invalidRegion.MoveBy(aTileOrigin);
+  invalidRegion.ScaleInverseRoundOut(mResolution, mResolution);
 
-  aTile.mUpdateRect = offsetScaledDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
+  tileDirtyRegion.OrWith(tileInvalidRegion);
+  aDirtyRegion.OrWith(invalidRegion);
 
+  // Mark the region we will be painting and the region we copied from the front buffer as
+  // needing to be uploaded to the compositor
+  aTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
+
+  // Add the region we copied from the front buffer into the painted region
   extraPainted.MoveBy(aTileOrigin);
   extraPainted.And(extraPainted, mNewValidRegion);
   mPaintedRegion.Or(mPaintedRegion, extraPainted);
 
   if (!backBuffer) {
     return false;
   }
 
@@ -1177,17 +1191,17 @@ ClientMultiTiledLayerBuffer::ValidateTil
     drawTarget = Factory::CreateDualDrawTarget(dt, dtOnWhite);
   } else {
     drawTarget = dt;
   }
 
   auto clear = CapturedTiledPaintState::Clear{
     dt,
     dtOnWhite,
-    offsetScaledDirtyRegion
+    tileDirtyRegion
   };
 
   gfx::Tile paintTile;
   paintTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
 
   if (aFlags & TilePaintFlags::Async) {
     RefPtr<CapturedTiledPaintState> asyncPaint = new CapturedTiledPaintState();
 
@@ -1215,17 +1229,17 @@ ClientMultiTiledLayerBuffer::ValidateTil
   }
 
   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.mInvalidBack.SubOut(tileDirtyRegion);
 
   aTile.Flip();
 
   return true;
 }
 
 /**
  * This function takes the transform stored in aTransformToCompBounds
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -123,16 +123,17 @@ struct TileClient
   * If getting the back buffer required copying pixels from the front buffer
   * then the copied region is stored in aAddPaintedRegion so the host side
   * knows to upload it.
   *
   * If nullptr is returned, aTextureClientOnWhite is undefined.
   */
   TextureClient* GetBackBuffer(CompositableClient&,
                                const nsIntRegion& aDirtyRegion,
+                               const nsIntRegion& aVisibleRegion,
                                gfxContentType aContent, SurfaceMode aMode,
                                nsIntRegion& aAddPaintedRegion,
                                TilePaintFlags aFlags,
                                RefPtr<TextureClient>* aTextureClientOnWhite,
                                std::vector<CapturedTiledPaintState::Copy>* aCopies,
                                std::vector<RefPtr<TextureClient>>* aClients);
 
   void DiscardFrontBuffer();
@@ -165,16 +166,17 @@ struct TileClient
 #endif
   nsIntRegion mInvalidFront;
   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,
+                                   const nsIntRegion& aVisibleRegion,
                                    nsIntRegion& aAddPaintedRegion,
                                    TilePaintFlags aFlags,
                                    std::vector<CapturedTiledPaintState::Copy>* aCopies,
                                    std::vector<RefPtr<TextureClient>>* aClients);
 };
 
 /**
  * This struct stores all the data necessary to perform a paint so that it