1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <map> 6 #include <utility> 7 8 #include "cc/resources/picture_pile.h" 9 #include "cc/test/fake_content_layer_client.h" 10 #include "cc/test/fake_rendering_stats_instrumentation.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 #include "ui/gfx/rect_conversions.h" 13 #include "ui/gfx/size_conversions.h" 14 15 namespace cc { 16 namespace { 17 18 class TestPicturePile : public PicturePile { 19 public: 20 using PicturePile::buffer_pixels; 21 using PicturePile::CanRasterSlowTileCheck; 22 using PicturePile::Clear; 23 24 PictureMap& picture_map() { return picture_map_; } 25 const gfx::Rect& recorded_viewport() const { return recorded_viewport_; } 26 27 bool CanRasterLayerRect(const gfx::Rect& layer_rect) { 28 return CanRaster(1.f, layer_rect); 29 } 30 31 typedef PicturePile::PictureInfo PictureInfo; 32 typedef PicturePile::PictureMapKey PictureMapKey; 33 typedef PicturePile::PictureMap PictureMap; 34 35 protected: 36 virtual ~TestPicturePile() {} 37 }; 38 39 class PicturePileTest : public testing::Test { 40 public: 41 PicturePileTest() 42 : pile_(new TestPicturePile()), 43 background_color_(SK_ColorBLUE), 44 min_scale_(0.125), 45 frame_number_(0), 46 contents_opaque_(false) { 47 pile_->SetTilingRect(gfx::Rect(pile_->tiling().max_texture_size())); 48 pile_->SetTileGridSize(gfx::Size(1000, 1000)); 49 pile_->SetMinContentsScale(min_scale_); 50 } 51 52 gfx::Rect tiling_rect() const { return pile_->tiling_rect(); } 53 54 bool UpdateAndExpandInvalidation(Region* invalidation, 55 const gfx::Rect& visible_layer_rect) { 56 frame_number_++; 57 return pile_->UpdateAndExpandInvalidation(&client_, 58 invalidation, 59 background_color_, 60 contents_opaque_, 61 false, 62 visible_layer_rect, 63 frame_number_, 64 Picture::RECORD_NORMALLY, 65 &stats_instrumentation_); 66 } 67 68 bool UpdateWholePile() { 69 Region invalidation = tiling_rect(); 70 bool result = UpdateAndExpandInvalidation(&invalidation, tiling_rect()); 71 EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString()); 72 return result; 73 } 74 75 FakeContentLayerClient client_; 76 FakeRenderingStatsInstrumentation stats_instrumentation_; 77 scoped_refptr<TestPicturePile> pile_; 78 SkColor background_color_; 79 float min_scale_; 80 int frame_number_; 81 bool contents_opaque_; 82 }; 83 84 TEST_F(PicturePileTest, SmallInvalidateInflated) { 85 UpdateWholePile(); 86 87 // Invalidate something inside a tile. 88 Region invalidate_rect(gfx::Rect(50, 50, 1, 1)); 89 UpdateAndExpandInvalidation(&invalidate_rect, tiling_rect()); 90 EXPECT_EQ(gfx::Rect(50, 50, 1, 1).ToString(), invalidate_rect.ToString()); 91 92 EXPECT_EQ(1, pile_->tiling().num_tiles_x()); 93 EXPECT_EQ(1, pile_->tiling().num_tiles_y()); 94 95 TestPicturePile::PictureInfo& picture_info = 96 pile_->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second; 97 // We should have a picture. 98 EXPECT_TRUE(!!picture_info.GetPicture()); 99 gfx::Rect picture_rect = gfx::ScaleToEnclosedRect( 100 picture_info.GetPicture()->LayerRect(), min_scale_); 101 102 // The the picture should be large enough that scaling it never makes a rect 103 // smaller than 1 px wide or tall. 104 EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " << 105 picture_rect.ToString(); 106 } 107 108 TEST_F(PicturePileTest, LargeInvalidateInflated) { 109 UpdateWholePile(); 110 111 // Invalidate something inside a tile. 112 Region invalidate_rect(gfx::Rect(50, 50, 100, 100)); 113 UpdateAndExpandInvalidation(&invalidate_rect, tiling_rect()); 114 EXPECT_EQ(gfx::Rect(50, 50, 100, 100).ToString(), invalidate_rect.ToString()); 115 116 EXPECT_EQ(1, pile_->tiling().num_tiles_x()); 117 EXPECT_EQ(1, pile_->tiling().num_tiles_y()); 118 119 TestPicturePile::PictureInfo& picture_info = 120 pile_->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second; 121 EXPECT_TRUE(!!picture_info.GetPicture()); 122 123 int expected_inflation = pile_->buffer_pixels(); 124 125 Picture* base_picture = picture_info.GetPicture(); 126 gfx::Rect base_picture_rect = pile_->tiling_rect(); 127 base_picture_rect.Inset(-expected_inflation, -expected_inflation); 128 EXPECT_EQ(base_picture_rect.ToString(), 129 base_picture->LayerRect().ToString()); 130 } 131 132 TEST_F(PicturePileTest, InvalidateOnTileBoundaryInflated) { 133 gfx::Rect new_tiling_rect = 134 gfx::ToEnclosedRect(gfx::ScaleRect(pile_->tiling_rect(), 2.f)); 135 pile_->SetTilingRect(new_tiling_rect); 136 137 // Due to border pixels, we should have 3 tiles. 138 EXPECT_EQ(3, pile_->tiling().num_tiles_x()); 139 EXPECT_EQ(3, pile_->tiling().num_tiles_y()); 140 141 // We should have 1/.125 - 1 = 7 border pixels. 142 EXPECT_EQ(7, pile_->buffer_pixels()); 143 EXPECT_EQ(7, pile_->tiling().border_texels()); 144 145 // Update the whole layer to create initial pictures. 146 UpdateWholePile(); 147 148 // Invalidate everything again to have a non zero invalidation 149 // frequency. 150 UpdateWholePile(); 151 152 // Invalidate something just over a tile boundary by a single pixel. 153 // This will invalidate the tile (1, 1), as well as 1 row of pixels in (1, 0). 154 Region invalidate_rect( 155 gfx::Rect(pile_->tiling().TileBoundsWithBorder(0, 0).right(), 156 pile_->tiling().TileBoundsWithBorder(0, 0).bottom() - 1, 157 50, 158 50)); 159 Region expected_invalidation = invalidate_rect; 160 UpdateAndExpandInvalidation(&invalidate_rect, tiling_rect()); 161 EXPECT_EQ(expected_invalidation.ToString(), invalidate_rect.ToString()); 162 163 for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) { 164 for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) { 165 TestPicturePile::PictureInfo& picture_info = 166 pile_->picture_map() 167 .find(TestPicturePile::PictureMapKey(i, j)) 168 ->second; 169 170 // Expect (1, 1) and (1, 0) to be invalidated once more 171 // than the rest of the tiles. 172 if (i == 1 && (j == 0 || j == 1)) { 173 EXPECT_FLOAT_EQ( 174 2.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED, 175 picture_info.GetInvalidationFrequencyForTesting()); 176 } else { 177 EXPECT_FLOAT_EQ( 178 1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED, 179 picture_info.GetInvalidationFrequencyForTesting()); 180 } 181 } 182 } 183 } 184 185 TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) { 186 gfx::Rect new_tiling_rect = 187 gfx::ToEnclosedRect(gfx::ScaleRect(pile_->tiling_rect(), 4.f)); 188 pile_->SetTilingRect(new_tiling_rect); 189 190 gfx::Rect viewport( 191 tiling_rect().x(), tiling_rect().y(), tiling_rect().width(), 1); 192 193 // Update the whole pile until the invalidation frequency is high. 194 for (int frame = 0; frame < 33; ++frame) { 195 UpdateWholePile(); 196 } 197 198 // Make sure we have a high invalidation frequency. 199 for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) { 200 for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) { 201 TestPicturePile::PictureInfo& picture_info = 202 pile_->picture_map() 203 .find(TestPicturePile::PictureMapKey(i, j)) 204 ->second; 205 EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting()) 206 << "i " << i << " j " << j; 207 } 208 } 209 210 // Update once more with a small viewport. 211 Region invalidation = tiling_rect(); 212 UpdateAndExpandInvalidation(&invalidation, viewport); 213 EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString()); 214 215 for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) { 216 for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) { 217 TestPicturePile::PictureInfo& picture_info = 218 pile_->picture_map() 219 .find(TestPicturePile::PictureMapKey(i, j)) 220 ->second; 221 EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting()); 222 223 // If the y far enough away we expect to find no picture (no re-recording 224 // happened). For close y, the picture should change. 225 if (j >= 2) 226 EXPECT_FALSE(picture_info.GetPicture()) << "i " << i << " j " << j; 227 else 228 EXPECT_TRUE(picture_info.GetPicture()) << "i " << i << " j " << j; 229 } 230 } 231 232 // Update a partial tile that doesn't get recorded. We should expand the 233 // invalidation to the entire tiles that overlap it. 234 Region small_invalidation = 235 gfx::Rect(pile_->tiling().TileBounds(3, 4).x(), 236 pile_->tiling().TileBounds(3, 4).y() + 10, 237 1, 238 1); 239 UpdateAndExpandInvalidation(&small_invalidation, viewport); 240 EXPECT_TRUE(small_invalidation.Contains(gfx::UnionRects( 241 pile_->tiling().TileBounds(2, 4), pile_->tiling().TileBounds(3, 4)))) 242 << small_invalidation.ToString(); 243 244 // Now update with no invalidation and full viewport 245 Region empty_invalidation; 246 UpdateAndExpandInvalidation(&empty_invalidation, tiling_rect()); 247 EXPECT_EQ(Region().ToString(), empty_invalidation.ToString()); 248 249 for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) { 250 for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) { 251 TestPicturePile::PictureInfo& picture_info = 252 pile_->picture_map() 253 .find(TestPicturePile::PictureMapKey(i, j)) 254 ->second; 255 // Expect the invalidation frequency to be less than 1, since we just 256 // updated with no invalidations. 257 EXPECT_LT(picture_info.GetInvalidationFrequencyForTesting(), 1.f); 258 259 // We expect that there are pictures everywhere now. 260 EXPECT_TRUE(picture_info.GetPicture()) << "i " << i << " j " << j; 261 } 262 } 263 } 264 265 TEST_F(PicturePileTest, ClearingInvalidatesRecordedRect) { 266 UpdateWholePile(); 267 268 gfx::Rect rect(0, 0, 5, 5); 269 EXPECT_TRUE(pile_->CanRasterLayerRect(rect)); 270 EXPECT_TRUE(pile_->CanRasterSlowTileCheck(rect)); 271 272 pile_->Clear(); 273 274 // Make sure both the cache-aware check (using recorded region) and the normal 275 // check are both false after clearing. 276 EXPECT_FALSE(pile_->CanRasterLayerRect(rect)); 277 EXPECT_FALSE(pile_->CanRasterSlowTileCheck(rect)); 278 } 279 280 TEST_F(PicturePileTest, FrequentInvalidationCanRaster) { 281 // This test makes sure that if part of the page is frequently invalidated 282 // and doesn't get re-recorded, then CanRaster is not true for any 283 // tiles touching it, but is true for adjacent tiles, even if it 284 // overlaps on borders (edge case). 285 gfx::Rect new_tiling_rect = 286 gfx::ToEnclosedRect(gfx::ScaleRect(pile_->tiling_rect(), 4.f)); 287 pile_->SetTilingRect(new_tiling_rect); 288 289 gfx::Rect tile01_borders = pile_->tiling().TileBoundsWithBorder(0, 1); 290 gfx::Rect tile02_borders = pile_->tiling().TileBoundsWithBorder(0, 2); 291 gfx::Rect tile01_noborders = pile_->tiling().TileBounds(0, 1); 292 gfx::Rect tile02_noborders = pile_->tiling().TileBounds(0, 2); 293 294 // Sanity check these two tiles are overlapping with borders, since this is 295 // what the test is trying to repro. 296 EXPECT_TRUE(tile01_borders.Intersects(tile02_borders)); 297 EXPECT_FALSE(tile01_noborders.Intersects(tile02_noborders)); 298 UpdateWholePile(); 299 EXPECT_TRUE(pile_->CanRasterLayerRect(tile01_noborders)); 300 EXPECT_TRUE(pile_->CanRasterSlowTileCheck(tile01_noborders)); 301 EXPECT_TRUE(pile_->CanRasterLayerRect(tile02_noborders)); 302 EXPECT_TRUE(pile_->CanRasterSlowTileCheck(tile02_noborders)); 303 // Sanity check that an initial paint goes down the fast path of having 304 // a valid recorded viewport. 305 EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); 306 307 // Update the whole layer until the invalidation frequency is high. 308 for (int frame = 0; frame < 33; ++frame) { 309 UpdateWholePile(); 310 } 311 312 // Update once more with a small viewport. 313 gfx::Rect viewport(0, 0, tiling_rect().width(), 1); 314 Region invalidation(tiling_rect()); 315 UpdateAndExpandInvalidation(&invalidation, viewport); 316 EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString()); 317 318 // Sanity check some pictures exist and others don't. 319 EXPECT_TRUE(pile_->picture_map() 320 .find(TestPicturePile::PictureMapKey(0, 1)) 321 ->second.GetPicture()); 322 EXPECT_FALSE(pile_->picture_map() 323 .find(TestPicturePile::PictureMapKey(0, 2)) 324 ->second.GetPicture()); 325 326 EXPECT_TRUE(pile_->CanRasterLayerRect(tile01_noborders)); 327 EXPECT_TRUE(pile_->CanRasterSlowTileCheck(tile01_noborders)); 328 EXPECT_FALSE(pile_->CanRasterLayerRect(tile02_noborders)); 329 EXPECT_FALSE(pile_->CanRasterSlowTileCheck(tile02_noborders)); 330 } 331 332 TEST_F(PicturePileTest, NoInvalidationValidViewport) { 333 // This test validates that the recorded_viewport cache of full tiles 334 // is still valid for some use cases. If it's not, it's a performance 335 // issue because CanRaster checks will go down the slow path. 336 UpdateWholePile(); 337 EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); 338 339 // No invalidation, same viewport. 340 Region invalidation; 341 UpdateAndExpandInvalidation(&invalidation, tiling_rect()); 342 EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); 343 EXPECT_EQ(Region().ToString(), invalidation.ToString()); 344 345 // Partial invalidation, same viewport. 346 invalidation = gfx::Rect(0, 0, 1, 1); 347 UpdateAndExpandInvalidation(&invalidation, tiling_rect()); 348 EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); 349 EXPECT_EQ(gfx::Rect(0, 0, 1, 1).ToString(), invalidation.ToString()); 350 351 // No invalidation, changing viewport. 352 invalidation = Region(); 353 UpdateAndExpandInvalidation(&invalidation, gfx::Rect(5, 5, 5, 5)); 354 EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty()); 355 EXPECT_EQ(Region().ToString(), invalidation.ToString()); 356 } 357 358 TEST_F(PicturePileTest, InvalidationOutsideRecordingRect) { 359 gfx::Rect huge_layer_rect(10000000, 20000000); 360 gfx::Rect viewport(300000, 400000, 5000, 6000); 361 362 pile_->SetTilingRect(huge_layer_rect); 363 364 // Invalidation inside the recording rect does not need to be expanded. 365 Region invalidation = viewport; 366 UpdateAndExpandInvalidation(&invalidation, viewport); 367 EXPECT_EQ(viewport.ToString(), invalidation.ToString()); 368 369 // Invalidation outside the recording rect should expand to the tiles it 370 // covers. 371 gfx::Rect recorded_over_tiles = 372 pile_->tiling().ExpandRectToTileBounds(pile_->recorded_viewport()); 373 gfx::Rect invalidation_outside( 374 recorded_over_tiles.right(), recorded_over_tiles.y(), 30, 30); 375 invalidation = invalidation_outside; 376 UpdateAndExpandInvalidation(&invalidation, viewport); 377 gfx::Rect expanded_recorded_viewport = 378 pile_->tiling().ExpandRectToTileBounds(pile_->recorded_viewport()); 379 Region expected_invalidation = 380 pile_->tiling().ExpandRectToTileBounds(invalidation_outside); 381 EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); 382 } 383 384 } // namespace 385 } // namespace cc 386