Home | History | Annotate | Download | only in resources
      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