Bug 1438551 - When creating a back buffer, only paint in the visible rect. r=nical
authorRyan Hunt <rhunt@eqrion.net>
Fri, 06 Apr 2018 14:36:39 -0500
changeset 467396 ab5ed3dd38b9f6b6a3244e13ab902b29073cb6e3
parent 467395 5c07a83643348dc9118bcd6fb408d4c41fce8266
child 467397 83a97d3d6b77b8cc8580d4e9c255f4b712fe5a4d
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1438551
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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