• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
picture_map()24   PictureMap& picture_map() { return picture_map_; }
recorded_viewport() const25   const gfx::Rect& recorded_viewport() const { return recorded_viewport_; }
26 
CanRasterLayerRect(const gfx::Rect & layer_rect)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:
~TestPicturePile()36     virtual ~TestPicturePile() {}
37 };
38 
TEST(PicturePileTest,SmallInvalidateInflated)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 
TEST(PicturePileTest,LargeInvalidateInflated)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 
TEST(PicturePileTest,InvalidateOnTileBoundaryInflated)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 
TEST(PicturePileTest,StopRecordingOffscreenInvalidations)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 
TEST_F(PicturePileTest,ClearingInvalidatesRecordedRect)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 
TEST_F(PicturePileTest,FrequentInvalidationCanRaster)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 
TEST_F(PicturePileTest,NoInvalidationValidViewport)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