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 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