[chromium] Add overdraw metrics for texture uploads
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Mar 2012 17:14:30 +0000 (17:14 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Mar 2012 17:14:30 +0000 (17:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=81175

Patch by Dana Jansens <danakj@chromium.org> on 2012-03-16
Reviewed by Adrienne Walker.

Source/WebCore:

Record texture upload metrics during paint. To properly record
the amount of pixels culled, we must compute the amount of pixels we
would have uploaded for a tile. This requires knowing the dirty rect of
the tile, but the dirty rect can be changed by WebKit during a paint, so
we always store the dirtyRect in the tile's updateRect. We add an
m_updateCulled bool to the UpdatableTile structure, to identify tiles
that were not updated, and know a tile was updated if updateRect is not
empty and updateCulled is false.

Tested by all TiledLayerChromiumTests that use occlusion tracker.

* platform/graphics/chromium/TiledLayerChromium.cpp:
(UpdatableTile):
(WebCore::TiledLayerChromium::prepareToUpdateTiles):
* platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
(WebCore::CCLayerTreeHost::paintLayerContents):

Source/WebKit/chromium:

* tests/TiledLayerChromiumTest.cpp:
(WTF::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@111023 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/TiledLayerChromium.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/tests/TiledLayerChromiumTest.cpp

index 10c3797..3d27f88 100644 (file)
@@ -1,3 +1,27 @@
+2012-03-16  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Add overdraw metrics for texture uploads
+        https://bugs.webkit.org/show_bug.cgi?id=81175
+
+        Reviewed by Adrienne Walker.
+
+        Record texture upload metrics during paint. To properly record
+        the amount of pixels culled, we must compute the amount of pixels we
+        would have uploaded for a tile. This requires knowing the dirty rect of
+        the tile, but the dirty rect can be changed by WebKit during a paint, so
+        we always store the dirtyRect in the tile's updateRect. We add an
+        m_updateCulled bool to the UpdatableTile structure, to identify tiles
+        that were not updated, and know a tile was updated if updateRect is not
+        empty and updateCulled is false.
+
+        Tested by all TiledLayerChromiumTests that use occlusion tracker.
+
+        * platform/graphics/chromium/TiledLayerChromium.cpp:
+        (UpdatableTile):
+        (WebCore::TiledLayerChromium::prepareToUpdateTiles):
+        * platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
+        (WebCore::CCLayerTreeHost::paintLayerContents):
+
 2012-03-16  Jer Noble  <jer.noble@apple.com>
 
         Allow AudioContext::create() to emit an ExceptionCode.
index 853d675..f7a4008 100644 (file)
@@ -63,19 +63,18 @@ public:
     ManagedTexture* managedTexture() { return m_texture->texture(); }
 
     bool isDirty() const { return !m_dirtyRect.isEmpty(); }
-    void copyAndClearDirty()
-    {
-        m_updateRect = m_dirtyRect;
-        m_dirtyRect = IntRect();
-    }
-    bool isDirtyForCurrentFrame() { return !m_dirtyRect.isEmpty() && m_updateRect.isEmpty(); }
+    // Returns whether the layer was dirty and not updated in the current frame. For tiles that were not culled, the
+    // updateRect holds the area of the tile that was updated. Otherwise, the area that would have been updated.
+    bool isDirtyForCurrentFrame() { return !m_dirtyRect.isEmpty() && (m_updateRect.isEmpty() || m_updateCulled); }
 
     IntRect m_dirtyRect;
     IntRect m_updateRect;
     bool m_partialUpdate;
+    bool m_updateCulled;
 private:
     explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture)
         : m_partialUpdate(false)
+        , m_updateCulled(false)
         , m_texture(texture)
     {
     }
@@ -196,6 +195,9 @@ void TiledLayerChromium::updateCompositorResources(GraphicsContext3D*, CCTexture
             if (!tile)
                 CRASH();
 
+            if (tile->m_updateCulled)
+                continue;
+
             IntRect sourceRect = tile->m_updateRect;
             if (tile->m_updateRect.isEmpty())
                 continue;
@@ -412,13 +414,17 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int
             if (!tile)
                 tile = createTile(i, j);
 
-            // When not idle painting, if the visible region of the tile is occluded, don't reserve a texture or mark it for update.
-            // If any part of the tile is visible, then we need to paint it so the tile is pushed to the impl thread.
-            // This will also avoid painting the tile in the next loop, below.
+            // Save the dirty rect since WebKit can change the tile's dirty rect during painting.
+            tile->m_updateRect = tile->m_dirtyRect;
+
+            // When not idle painting, if the visible region of the tile is occluded, don't reserve a texture or update the tile.
+            // If any part of the tile is visible, then we need to update it so the tile is pushed to the impl thread.
             if (!idle && occlusion) {
                 IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleLayerRect());
-                if (occlusion->occluded(this, visibleTileRect))
+                if (occlusion->occluded(this, visibleTileRect)) {
+                    tile->m_updateCulled = true;
                     continue;
+                }
             }
 
             // FIXME: Decide if partial update should be allowed based on cost
@@ -448,7 +454,8 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int
             }
 
             dirtyLayerRect.unite(tile->m_dirtyRect);
-            tile->copyAndClearDirty();
+            // Clear the dirty rect.
+            tile->m_dirtyRect = IntRect();
         }
     }
 
@@ -479,11 +486,23 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int
 
             IntRect tileRect = m_tiler->tileBounds(i, j);
 
-            // Use m_updateRect as copyAndClearDirty above moved the existing dirty rect to m_updateRect if the tile isn't culled.
+            // Use m_updateRect as the above loop copied the dirty rect for this frame to m_updateRect.
             const IntRect& dirtyRect = tile->m_updateRect;
             if (dirtyRect.isEmpty())
                 continue;
 
+            // sourceRect starts as a full-sized tile with border texels included.
+            IntRect sourceRect = m_tiler->tileRect(tile);
+            sourceRect.intersect(dirtyRect);
+            // Paint rect not guaranteed to line up on tile boundaries, so
+            // make sure that sourceRect doesn't extend outside of it.
+            sourceRect.intersect(m_paintRect);
+
+            if (tile->m_updateCulled && occlusion) {
+                occlusion->overdrawMetrics().didCull(TransformationMatrix(), sourceRect, IntRect());
+                continue;
+            }
+
             // Save what was painted opaque in the tile. Keep the old area if the paint didn't touch it, and didn't paint some
             // other part of the tile opaque.
             IntRect tilePaintedRect = intersection(tileRect, m_paintRect);
@@ -497,18 +516,13 @@ void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int
                     tile->setOpaqueRect(tilePaintedOpaqueRect);
             }
 
-            // sourceRect starts as a full-sized tile with border texels included.
-            IntRect sourceRect = m_tiler->tileRect(tile);
-            sourceRect.intersect(dirtyRect);
-            // Paint rect not guaranteed to line up on tile boundaries, so
-            // make sure that sourceRect doesn't extend outside of it.
-            sourceRect.intersect(m_paintRect);
-
             tile->m_updateRect = sourceRect;
             if (sourceRect.isEmpty())
                 continue;
 
             tile->texture()->prepareRect(sourceRect);
+            if (occlusion)
+                occlusion->overdrawMetrics().didDraw(TransformationMatrix(), sourceRect, tile->opaqueRect());
         }
     }
 }
@@ -556,6 +570,7 @@ void TiledLayerChromium::resetUpdateState()
         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
         tile->m_updateRect = IntRect();
         tile->m_partialUpdate = false;
+        tile->m_updateCulled = false;
     }
 }
 
index 0831ccf..017820a 100644 (file)
@@ -557,6 +557,8 @@ void CCLayerTreeHost::paintLayerContents(const LayerList& renderSurfaceLayerList
         } else
             occlusionTracker.leaveToTargetRenderSurface(it.targetRenderSurfaceLayer()->renderSurface());
     }
+
+    occlusionTracker.overdrawMetrics().recordMetrics(this);
 }
 
 void CCLayerTreeHost::updateCompositorResources(GraphicsContext3D* context, CCTextureUpdater& updater)
index d7c13a6..0f1f171 100644 (file)
@@ -1,5 +1,15 @@
 2012-03-16  Dana Jansens  <danakj@chromium.org>
 
+        [chromium] Add overdraw metrics for texture uploads
+        https://bugs.webkit.org/show_bug.cgi?id=81175
+
+        Reviewed by Adrienne Walker.
+
+        * tests/TiledLayerChromiumTest.cpp:
+        (WTF::TEST):
+
+2012-03-16  Dana Jansens  <danakj@chromium.org>
+
         [chromium] Remove surface damage client from occlusion tracker
         https://bugs.webkit.org/show_bug.cgi?id=81242
 
index 07ceaae..7eebb97 100644 (file)
@@ -308,6 +308,10 @@ TEST(TiledLayerChromiumTest, pushOccludedDirtyTiles)
     layer->updateCompositorResources(0, updater);
     layer->pushPropertiesTo(layerImpl.get());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 20000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 0, 1);
+
     // We should have both tiles on the impl side.
     EXPECT_TRUE(layerImpl->hasTileAt(0, 0));
     EXPECT_TRUE(layerImpl->hasTileAt(0, 1));
@@ -322,6 +326,10 @@ TEST(TiledLayerChromiumTest, pushOccludedDirtyTiles)
     layer->updateCompositorResources(0, updater);
     layer->pushPropertiesTo(layerImpl.get());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 20000 + 2500, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 0, 1);
+
     // We should still have both tiles, as part of the top tile is still unoccluded.
     EXPECT_TRUE(layerImpl->hasTileAt(0, 0));
     EXPECT_TRUE(layerImpl->hasTileAt(0, 1));
@@ -824,6 +832,10 @@ TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusion)
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(36-3, layer->fakeLayerTextureUpdater()->prepareRectCount());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 330000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 30000, 1);
+
     layer->fakeLayerTextureUpdater()->clearPrepareRectCount();
 
     occluded.setOcclusion(IntRect(250, 200, 300, 100));
@@ -831,12 +843,20 @@ TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusion)
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(36-2, layer->fakeLayerTextureUpdater()->prepareRectCount());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 330000 + 340000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 30000 + 20000, 1);
+
     layer->fakeLayerTextureUpdater()->clearPrepareRectCount();
 
     occluded.setOcclusion(IntRect(250, 250, 300, 100));
     layer->invalidateRect(IntRect(0, 0, 600, 600));
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(36, layer->fakeLayerTextureUpdater()->prepareRectCount());
+
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 330000 + 340000 + 360000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 30000 + 20000, 1);
 }
 
 TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndVisiblityConstraints)
@@ -857,6 +877,10 @@ TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndVisiblityConstraints)
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(24-3, layer->fakeLayerTextureUpdater()->prepareRectCount());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 210000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 30000, 1);
+
     layer->fakeLayerTextureUpdater()->clearPrepareRectCount();
 
     // Now the visible region stops at the edge of the occlusion so the partly visible tiles become fully occluded.
@@ -866,6 +890,10 @@ TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndVisiblityConstraints)
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(24-6, layer->fakeLayerTextureUpdater()->prepareRectCount());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 210000 + 180000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 30000 + 60000, 1);
+
     layer->fakeLayerTextureUpdater()->clearPrepareRectCount();
 
     // Now the visible region is even smaller than the occlusion, it should have the same result.
@@ -874,6 +902,11 @@ TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndVisiblityConstraints)
     layer->invalidateRect(IntRect(0, 0, 600, 600));
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(24-6, layer->fakeLayerTextureUpdater()->prepareRectCount());
+
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 210000 + 180000 + 180000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 30000 + 60000 + 60000, 1);
+
 }
 
 TEST(TiledLayerChromiumTest, tilesNotPaintedWithoutInvalidation)
@@ -893,11 +926,19 @@ TEST(TiledLayerChromiumTest, tilesNotPaintedWithoutInvalidation)
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(36-3, layer->fakeLayerTextureUpdater()->prepareRectCount());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 330000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 30000, 1);
+
     layer->fakeLayerTextureUpdater()->clearPrepareRectCount();
 
     // Repaint without marking it dirty.
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(0, layer->fakeLayerTextureUpdater()->prepareRectCount());
+
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 330000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 30000, 1);
 }
 
 TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndTransforms)
@@ -921,6 +962,10 @@ TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndTransforms)
     layer->invalidateRect(IntRect(0, 0, 600, 600));
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(36-3, layer->fakeLayerTextureUpdater()->prepareRectCount());
+
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 330000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 30000, 1);
 }
 
 TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndScaling)
@@ -947,6 +992,10 @@ TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndScaling)
     // number of tiles 3x3.
     EXPECT_EQ(9, layer->fakeLayerTextureUpdater()->prepareRectCount());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 90000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 0, 1);
+
     layer->fakeLayerTextureUpdater()->clearPrepareRectCount();
 
     // This makes sure the painting works when the content space is scaled to
@@ -958,6 +1007,10 @@ TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndScaling)
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(9-1, layer->fakeLayerTextureUpdater()->prepareRectCount());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 90000 + 80000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 10000, 1);
+
     layer->fakeLayerTextureUpdater()->clearPrepareRectCount();
 
     // This makes sure content scaling and transforms work together.
@@ -971,12 +1024,17 @@ TEST(TiledLayerChromiumTest, tilesPaintedWithOcclusionAndScaling)
     layer->invalidateRect(IntRect(0, 0, 600, 600));
     layer->prepareToUpdate(IntRect(0, 0, 600, 600), &occluded);
     EXPECT_EQ(9-1, layer->fakeLayerTextureUpdater()->prepareRectCount());
+
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 90000 + 80000 + 80000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 10000 + 10000, 1);
 }
 
 TEST(TiledLayerChromiumTest, opaqueContentsRegion)
 {
     OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024);
     RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
+    TestCCOcclusionTracker occluded;
 
     // The tile size is 100x100, so this invalidates and then paints two tiles in various ways.
 
@@ -987,49 +1045,70 @@ TEST(TiledLayerChromiumTest, opaqueContentsRegion)
     IntRect visibleBounds = IntRect(0, 0, 100, 150);
 
     layer->setBounds(contentBounds.size());
+    layer->setDrawTransform(TransformationMatrix(1, 0, 0, 1, layer->bounds().width() / 2.0, layer->bounds().height() / 2.0));
     layer->setVisibleLayerRect(visibleBounds);
     layer->setDrawOpacity(1);
 
     // If the layer doesn't paint opaque content, then the opaqueContentsRegion should be empty.
-    layer->fakeLayerTextureUpdater()->setOpaquePaintRect(opaquePaintRect);
+    layer->fakeLayerTextureUpdater()->setOpaquePaintRect(IntRect());
     layer->invalidateRect(contentBounds);
-    layer->prepareToUpdate(contentBounds, 0);
+    layer->prepareToUpdate(contentBounds, &occluded);
     opaqueContents = layer->opaqueContentsRegion();
     EXPECT_TRUE(opaqueContents.isEmpty());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 0, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 20000, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 0, 1);
+
     // opaqueContentsRegion should match the visible part of what is painted opaque.
     opaquePaintRect = IntRect(10, 10, 90, 190);
     layer->fakeLayerTextureUpdater()->setOpaquePaintRect(opaquePaintRect);
     layer->invalidateRect(contentBounds);
-    layer->prepareToUpdate(contentBounds, 0);
+    layer->prepareToUpdate(contentBounds, &occluded);
     opaqueContents = layer->opaqueContentsRegion();
     EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), opaqueContents.bounds());
     EXPECT_EQ(1u, opaqueContents.rects().size());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 17100, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 20000 + 20000 - 17100, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 0, 1);
+
     // If we paint again without invalidating, the same stuff should be opaque.
     layer->fakeLayerTextureUpdater()->setOpaquePaintRect(IntRect());
-    layer->prepareToUpdate(contentBounds, 0);
+    layer->prepareToUpdate(contentBounds, &occluded);
     opaqueContents = layer->opaqueContentsRegion();
     EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), opaqueContents.bounds());
     EXPECT_EQ(1u, opaqueContents.rects().size());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 17100, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 20000 + 20000 - 17100, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 0, 1);
+
     // If we repaint a non-opaque part of the tile, then it shouldn't lose its opaque-ness. And other tiles should
     // not be affected.
     layer->fakeLayerTextureUpdater()->setOpaquePaintRect(IntRect());
     layer->invalidateRect(IntRect(0, 0, 1, 1));
-    layer->prepareToUpdate(contentBounds, 0);
+    layer->prepareToUpdate(contentBounds, &occluded);
     opaqueContents = layer->opaqueContentsRegion();
     EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), opaqueContents.bounds());
     EXPECT_EQ(1u, opaqueContents.rects().size());
 
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 17100, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 20000 + 20000 - 17100 + 1, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 0, 1);
+
     // If we repaint an opaque part of the tile, then it should lose its opaque-ness. But other tiles should still
     // not be affected.
     layer->fakeLayerTextureUpdater()->setOpaquePaintRect(IntRect());
     layer->invalidateRect(IntRect(10, 10, 1, 1));
-    layer->prepareToUpdate(contentBounds, 0);
+    layer->prepareToUpdate(contentBounds, &occluded);
     opaqueContents = layer->opaqueContentsRegion();
     EXPECT_EQ_RECT(intersection(IntRect(10, 100, 90, 100), visibleBounds), opaqueContents.bounds());
     EXPECT_EQ(1u, opaqueContents.rects().size());
+
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnOpaque(), 17100, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsDrawnTranslucent(), 20000 + 20000 - 17100 + 1 + 1, 1);
+    EXPECT_NEAR(occluded.overdrawMetrics().pixelsCulled(), 0, 1);
 }
 
 } // namespace