Bug 1290149 - Copy intersecting region from old frontbuffer to new backbuffer when single tile layer visible region changes; r?mstange draft
authorJamie Nicol <jnicol@mozilla.com>
Thu, 18 Aug 2016 22:50:48 +0100
changeset 426148 4b5ae3dd3ad1894e52752f6e8a1b8e1c1ff33f00
parent 426004 7c8216f48c38a8498f251fe044509b930af44de6
child 534110 bb3c53330654a5aa54d9f868f4bf14692af31cc7
push id32635
push userbmo:jnicol@mozilla.com
push dateMon, 17 Oct 2016 23:31:14 +0000
reviewersmstange
bugs1290149
milestone52.0a1
Bug 1290149 - Copy intersecting region from old frontbuffer to new backbuffer when single tile layer visible region changes; r?mstange MozReview-Commit-ID: 96AhbNyw6pg
gfx/layers/client/SingleTiledContentClient.cpp
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -106,18 +106,29 @@ ClientSingleTiledLayerBuffer::PaintThebe
                                           bool aIsProgressive)
 {
   mWasLastPaintProgressive = aIsProgressive;
 
   // Compare layer valid region size to current backbuffer size, discard if not matching.
   gfx::IntSize size = aNewValidRegion.GetBounds().Size();
   gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft();
   nsIntRegion paintRegion = aPaintRegion;
+
+  RefPtr<TextureClient> discardedFrontBuffer = nullptr;
+  RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr;
+  nsIntRegion discardedValidRegion;
+
   if (mSize != size ||
       mTilingOrigin != origin) {
+    discardedFrontBuffer = mTile.mFrontBuffer;
+    discardedFrontBufferOnWhite = mTile.mFrontBufferOnWhite;
+    discardedValidRegion = mValidRegion;
+
+    TILING_LOG("TILING %p: Single-tile valid region changed. Discarding buffers.\n", &mPaintedLayer)
+;
     ResetPaintedAndValidState();
     mSize = size;
     mTilingOrigin = origin;
     paintRegion = aNewValidRegion;
   }
 
   SurfaceMode mode;
   gfxContentType content = GetContentType(&mode);
@@ -165,16 +176,55 @@ ClientSingleTiledLayerBuffer::PaintThebe
         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));
       }
     }
   }
 
+  // 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()) {
+      TextureClientAutoLock frontLock(discardedFrontBuffer,
+                                      OpenMode::OPEN_READ);
+      if (frontLock.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);
+        }
+      }
+
+      if (discardedFrontBufferOnWhite && backBufferOnWhite) {
+        TextureClientAutoLock frontOnWhiteLock(discardedFrontBufferOnWhite,
+                                               OpenMode::OPEN_READ);
+        if (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;
+
+            discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite,
+                                                             &rect, &dest);
+          }
+        }
+      }
+
+      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);
+    }
+  }
+
   if (dtOnWhite) {
     dt = gfx::Factory::CreateDualDrawTarget(dt, dtOnWhite);
     dtOnWhite = nullptr;
   }
 
   {
     RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
     if (!ctx) {