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)
{
}
if (!tile)
CRASH();
+ if (tile->m_updateCulled)
+ continue;
+
IntRect sourceRect = tile->m_updateRect;
if (tile->m_updateRect.isEmpty())
continue;
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
}
dirtyLayerRect.unite(tile->m_dirtyRect);
- tile->copyAndClearDirty();
+ // Clear the dirty rect.
+ tile->m_dirtyRect = IntRect();
}
}
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);
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());
}
}
}
UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
tile->m_updateRect = IntRect();
tile->m_partialUpdate = false;
+ tile->m_updateCulled = false;
}
}
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));
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));
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));
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)
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.
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.
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)
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)
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)
// 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
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.
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.
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