Implement buffer copying and clearing on the paint thread for single tiled layers (bug 1422392, r=nical) draft
authorRyan Hunt <rhunt@eqrion.net>
Fri, 01 Dec 2017 16:35:30 -0500
changeset 708367 dc59658bb31345275ac904cc94576588999c929f
parent 708366 b2af9d7976f09178c4c74ed7254d5c4ab323e5bd
child 708368 9d391cc92ae39b81131fd4c4ee971c2f971859c9
push id92378
push userbmo:rhunt@eqrion.net
push dateWed, 06 Dec 2017 20:15:21 +0000
reviewersnical
bugs1422392
milestone59.0a1
Implement buffer copying and clearing on the paint thread for single tiled layers (bug 1422392, r=nical) MozReview-Commit-ID: d6XPUYCz18
gfx/layers/PaintThread.cpp
gfx/layers/PaintThread.h
gfx/layers/client/SingleTiledContentClient.cpp
gfx/layers/client/TiledContentClient.cpp
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -99,18 +99,18 @@ CapturedTiledPaintState::Copy::CopyBuffe
 {
   RefPtr<gfx::SourceSurface> source = mSource->Snapshot();
 
   // This operation requires the destination draw target to be untranslated,
   // but the destination will have a transform from being part of a tiled draw
   // target. However in this case, CopySurface ignores transforms so we don't
   // need to do anything.
   mDestination->CopySurface(source,
-                            mBounds,
-                            mBounds.TopLeft());
+                            mSourceBounds,
+                            mDestinationPoint);
   return true;
 }
 
 void
 CapturedTiledPaintState::Clear::ClearBuffer()
 {
   // See the comment in CopyBuffer for why we need to temporarily reset
   // the transform of the draw target.
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -115,27 +115,30 @@ typedef bool (*PrepDrawTargetForPainting
 // Holds the key operations needed to update a tiled content client on the
 // paint thread.
 class CapturedTiledPaintState {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CapturedPaintState)
 public:
   struct Copy {
     Copy(RefPtr<gfx::DrawTarget> aSource,
          RefPtr<gfx::DrawTarget> aDestination,
-         gfx::IntRect aBounds)
+         gfx::IntRect aSourceBounds,
+         gfx::IntPoint aDestinationPoint)
       : mSource(aSource)
       , mDestination(aDestination)
-      , mBounds(aBounds)
+      , mSourceBounds(aSourceBounds)
+      , mDestinationPoint(aDestinationPoint)
     {}
 
     bool CopyBuffer();
 
     RefPtr<gfx::DrawTarget> mSource;
     RefPtr<gfx::DrawTarget> mDestination;
-    gfx::IntRect mBounds;
+    gfx::IntRect mSourceBounds;
+    gfx::IntPoint mDestinationPoint;
   };
 
   struct Clear {
     Clear(RefPtr<gfx::DrawTarget> aTarget,
             RefPtr<gfx::DrawTarget> aTargetOnWhite,
             nsIntRegion aDirtyRegion)
       : mTarget(aTarget)
       , mTargetOnWhite(aTargetOnWhite)
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -139,26 +139,29 @@ 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<CapturedTiledPaintState::Copy> paintCopies;
+  std::vector<CapturedTiledPaintState::Clear> paintClears;
+
   nsIntRegion extraPainted;
   RefPtr<TextureClient> backBufferOnWhite;
   RefPtr<TextureClient> backBuffer =
     mTile.GetBackBuffer(mCompositableClient,
                         tileDirtyRegion,
                         content, mode,
                         extraPainted,
-                        TilePaintFlags::None,
+                        aFlags,
                         &backBufferOnWhite,
-                        nullptr);
+                        &paintCopies);
 
   // 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));
@@ -177,59 +180,89 @@ ClientSingleTiledLayerBuffer::PaintThebe
 
   RefPtr<gfx::DrawTarget> dt = backBuffer->BorrowDrawTarget();
   RefPtr<gfx::DrawTarget> dtOnWhite;
   if (backBufferOnWhite) {
     dtOnWhite = backBufferOnWhite->BorrowDrawTarget();
   }
 
   if (mode != SurfaceMode::SURFACE_OPAQUE) {
-    for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
-      const gfx::IntRect& rect = iter.Get();
-      if (dtOnWhite) {
-        dt->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height),
-                     gfx::ColorPattern(gfx::Color(0.0, 0.0, 0.0, 1.0)));
-        dtOnWhite->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height),
-                            gfx::ColorPattern(gfx::Color(1.0, 1.0, 1.0, 1.0)));
-      } else {
-        dt->ClearRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height));
-      }
+    auto clear = CapturedTiledPaintState::Clear{
+      dt,
+      dtOnWhite,
+      tileDirtyRegion,
+    };
+
+    if (asyncPaint) {
+      paintClears.push_back(clear);
+    } else {
+      clear.ClearBuffer();
     }
   }
 
   // If the old frontbuffer was discarded then attempt to copy what we
   // can from it to the new backbuffer.
   if (discardedFrontBuffer) {
     nsIntRegion copyableRegion;
     copyableRegion.And(aNewValidRegion, discardedValidRegion);
     copyableRegion.SubOut(aDirtyRegion);
 
     if (!copyableRegion.IsEmpty()) {
+      OpenMode asyncFlags = asyncPaint ? OpenMode::OPEN_ASYNC
+                                       : OpenMode::OPEN_NONE;
+
       TextureClientAutoLock frontLock(discardedFrontBuffer,
-                                      OpenMode::OPEN_READ);
+                                      OpenMode::OPEN_READ | asyncFlags);
       Maybe<TextureClientAutoLock> frontOnWhiteLock;
       if (discardedFrontBufferOnWhite && backBufferOnWhite) {
-        frontOnWhiteLock.emplace(discardedFrontBufferOnWhite, OpenMode::OPEN_READ);
+        frontOnWhiteLock.emplace(discardedFrontBufferOnWhite, OpenMode::OPEN_READ | asyncFlags);
       }
 
       // Copy to both backBuffer and backBufferOnWhite if required, or copy to neither.
       if (frontLock.Succeeded() && (!frontOnWhiteLock || frontOnWhiteLock->Succeeded())) {
-        for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
-          const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
-          const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
-          discardedFrontBuffer->CopyToTextureClient(backBuffer, &rect, &dest);
-        }
+        RefPtr<gfx::DrawTarget> frontBuffer = discardedFrontBuffer->BorrowDrawTarget();
 
-        if (frontOnWhiteLock) {
+        if (frontBuffer) {
           for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
             const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
             const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
-            discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite,
-                                                             &rect, &dest);
+
+            auto copy = CapturedTiledPaintState::Copy{
+              frontBuffer, dt, rect, dest
+            };
+            if (asyncPaint) {
+              paintCopies.push_back(copy);
+            } else {
+              copy.CopyBuffer();
+            }
           }
+
+          if (frontOnWhiteLock) {
+            RefPtr<gfx::DrawTarget> frontBufferOnWhite = discardedFrontBufferOnWhite->BorrowDrawTarget();
+
+            if (frontBufferOnWhite) {
+              for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
+                const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
+                const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
+
+                auto copy = CapturedTiledPaintState::Copy{
+                  frontBufferOnWhite, dtOnWhite, rect, dest
+                };
+                if (asyncPaint) {
+                  paintCopies.push_back(copy);
+                } else {
+                  copy.CopyBuffer();
+                }
+              }
+            }
+          } else {
+            gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
+          }
+        } else {
+          gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
         }
 
         TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
 
         // We don't need to repaint valid content that was just copied.
         paintRegion.SubOut(copyableRegion);
       }
     }
@@ -259,20 +292,25 @@ ClientSingleTiledLayerBuffer::PaintThebe
     // Replay on the paint thread
     RefPtr<CapturedTiledPaintState> capturedState =
       new CapturedTiledPaintState(dt,
                                   captureDT);
     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);
     mManager->SetQueuedAsyncPaints();
   } else {
+    MOZ_ASSERT(paintCopies.size() == 0);
+    MOZ_ASSERT(paintClears.size() == 0);
+
     RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
     if (!ctx) {
       gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(dt);
       return;
     }
     ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
 
     aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -502,17 +502,17 @@ CopyFrontToBack(TextureClient* aFront,
 
   RefPtr<gfx::DrawTarget> frontBuffer = aFront->BorrowDrawTarget();
   if (!frontBuffer) {
     gfxWarning() << "[Tiling:Client] Failed to aquire the front buffer's draw target";
     return false;
   }
 
   auto copy = CapturedTiledPaintState::Copy{
-    frontBuffer, backBuffer, aRectToCopy
+    frontBuffer, backBuffer, aRectToCopy, aRectToCopy.TopLeft()
   };
 
   if (asyncPaint && aCopies) {
     aCopies->push_back(copy);
   } else {
     copy.CopyBuffer();
   }
   return true;