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