Bug 749063 - Prioritise visible tiles when progressively updating. r=bgirard
authorChris Lord <chrislord.net@gmail.com>
Mon, 15 Oct 2012 09:33:48 +0100
changeset 110396 9706761f3533c2f7bff82e47a0171fc6c19eebff
parent 110395 f8114d23854fe8d7db4dcdc224dd5a1d475bd884
child 110397 1c267806256f71f05098ae66a1c772aa827c4919
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersbgirard
bugs749063
milestone19.0a1
Bug 749063 - Prioritise visible tiles when progressively updating. r=bgirard When progressively updating tiles, prioritise tiles that intersect with the current viewport before off-screen tiles. New content is still prioritised over stale content.
gfx/layers/basic/BasicTiledThebesLayer.cpp
--- a/gfx/layers/basic/BasicTiledThebesLayer.cpp
+++ b/gfx/layers/basic/BasicTiledThebesLayer.cpp
@@ -245,20 +245,21 @@ BasicTiledThebesLayer::PaintThebes(gfxCo
     NS_ASSERTION(false, "Shadow requested for painting\n");
     return;
   }
 
   if (mTiledBuffer.HasFormatChanged(this)) {
     mValidRegion = nsIntRegion();
   }
 
-  nsIntRegion regionToPaint = mVisibleRegion;
-  regionToPaint.Sub(regionToPaint, mValidRegion);
-  if (regionToPaint.IsEmpty())
+  nsIntRegion invalidRegion = mVisibleRegion;
+  invalidRegion.Sub(invalidRegion, mValidRegion);
+  if (invalidRegion.IsEmpty())
     return;
+  nsIntRegion regionToPaint = invalidRegion;
 
   gfxSize resolution(1, 1);
   for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
     const FrameMetrics& metrics = parent->GetFrameMetrics();
     resolution.width *= metrics.mResolution.width;
     resolution.height *= metrics.mResolution.height;
   }
 
@@ -272,33 +273,65 @@ BasicTiledThebesLayer::PaintThebes(gfxCo
   }
   int32_t scrollDiffX = scrollOffset.x - mLastScrollOffset.x;
   int32_t scrollDiffY = scrollOffset.y - mLastScrollOffset.y;
 
   // Only draw progressively when we're panning and the resolution is unchanged.
   if (gfxPlatform::UseProgressiveTilePainting() &&
       mTiledBuffer.GetResolution() == resolution &&
       (scrollDiffX != 0 || scrollDiffY != 0)) {
-    // Paint tiles that have no content before tiles that only have stale content.
-    nsIntRegion staleRegion = mTiledBuffer.GetValidRegion();
-    staleRegion.And(staleRegion, regionToPaint);
-    bool hasNewContent = !staleRegion.Contains(regionToPaint);
-    if (!staleRegion.IsEmpty() && hasNewContent) {
-      regionToPaint.Sub(regionToPaint, staleRegion);
-    }
+    // Find out if we have any non-stale content to update.
+    nsIntRegion freshRegion = mTiledBuffer.GetValidRegion();
+    freshRegion.And(freshRegion, invalidRegion);
+    freshRegion.Sub(invalidRegion, freshRegion);
 
     // Find out the current view transform to determine which tiles to draw
     // first, and see if we should just abort this paint. Aborting is usually
     // caused by there being an incoming, more relevant paint.
     gfx::Rect viewport;
     float scaleX, scaleY;
-    if (BasicManager()->ProgressiveUpdateCallback(hasNewContent, viewport, scaleX, scaleY)) {
+    if (BasicManager()->ProgressiveUpdateCallback(!freshRegion.IsEmpty(), viewport, scaleX, scaleY)) {
       return;
     }
 
+    // Prioritise tiles that are currently visible on the screen.
+
+    // Get the transform to the current layer.
+    gfx3DMatrix transform = GetEffectiveTransform();
+    // XXX Not sure if this code for intermediate surfaces is correct.
+    //     It rarely gets hit though, and shouldn't have terrible consequences
+    //     even if it is wrong.
+    for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
+      if (parent->UseIntermediateSurface()) {
+        transform.PreMultiply(parent->GetEffectiveTransform());
+      }
+    }
+    transform.Invert();
+
+    // Transform the screen coordinates into local layer coordinates.
+    gfxRect transformedViewport(viewport.x - (scrollOffset.x * resolution.width),
+                                viewport.y - (scrollOffset.y * resolution.height),
+                                viewport.width, viewport.height);
+    transformedViewport.Scale((scaleX / resolution.width) / resolution.width,
+                              (scaleY / resolution.height) / resolution.height);
+    transformedViewport = transform.TransformBounds(transformedViewport);
+
+    nsIntRect roundedTransformedViewport((int32_t)floor(transformedViewport.x),
+                                         (int32_t)floor(transformedViewport.y),
+                                         (int32_t)ceil(transformedViewport.width),
+                                         (int32_t)ceil(transformedViewport.height));
+
+    // Paint tiles that have no content before tiles that only have stale content.
+    if (!freshRegion.IsEmpty()) {
+      regionToPaint = freshRegion;
+    }
+    if (regionToPaint.Intersects(roundedTransformedViewport)) {
+      regionToPaint.And(regionToPaint, roundedTransformedViewport);
+    }
+
     // The following code decides what order to draw tiles in, based on the
     // current scroll direction of the primary scrollable layer.
     // XXX While this code is of a reasonable size currently, it is likely
     //     we'll want to add more comprehensive methods of deciding what
     //     tiles to draw. This is a good candidate for splitting out into a
     //     separate function.
 
     // First, decide whether to iterate on the region from the beginning or end
@@ -332,20 +365,22 @@ BasicTiledThebesLayer::PaintThebes(gfxCo
     } else {
       paintTileStartY = mTiledBuffer.RoundDownToTileEdge(rect->YMost() - 1);
     }
 
     nsIntRegion maxPaint(
       nsIntRect(paintTileStartX, paintTileStartY,
                 mTiledBuffer.GetTileLength(), mTiledBuffer.GetTileLength()));
 
-    if (!maxPaint.Contains(regionToPaint)) {
+    // Expand the paint region to tile boundaries
+    regionToPaint.And(invalidRegion, maxPaint);
+
+    if (!regionToPaint.Contains(invalidRegion)) {
       // The region needed to paint is larger then our progressive chunk size
       // therefore update what we want to paint and ask for a new paint transaction.
-      regionToPaint.And(regionToPaint, maxPaint);
       BasicManager()->SetRepeatTransaction();
 
       // Make sure that tiles that fall outside of the visible region are discarded.
       mValidRegion.And(mValidRegion, mVisibleRegion);
     } else {
       // The transaction is completed, store the last scroll offset.
       mLastScrollOffset = scrollOffset;
     }