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