1 // Copyright 2012 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 "cc/layers/tiled_layer_impl.h"
6
7 #include "cc/layers/append_quads_data.h"
8 #include "cc/quads/tile_draw_quad.h"
9 #include "cc/resources/layer_tiling_data.h"
10 #include "cc/test/fake_impl_proxy.h"
11 #include "cc/test/fake_layer_tree_host_impl.h"
12 #include "cc/test/layer_test_common.h"
13 #include "cc/test/mock_quad_culler.h"
14 #include "cc/trees/single_thread_proxy.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace cc {
19 namespace {
20
21 class TiledLayerImplTest : public testing::Test {
22 public:
TiledLayerImplTest()23 TiledLayerImplTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {}
24
CreateLayerNoTiles(const gfx::Size & tile_size,const gfx::Size & layer_size,LayerTilingData::BorderTexelOption border_texels)25 scoped_ptr<TiledLayerImpl> CreateLayerNoTiles(
26 const gfx::Size& tile_size,
27 const gfx::Size& layer_size,
28 LayerTilingData::BorderTexelOption border_texels) {
29 scoped_ptr<TiledLayerImpl> layer =
30 TiledLayerImpl::Create(host_impl_.active_tree(), 1);
31 scoped_ptr<LayerTilingData> tiler =
32 LayerTilingData::Create(tile_size, border_texels);
33 tiler->SetTilingRect(gfx::Rect(layer_size));
34 layer->SetTilingData(*tiler);
35 layer->set_skips_draw(false);
36 layer->draw_properties().visible_content_rect =
37 gfx::Rect(layer_size);
38 layer->draw_properties().opacity = 1;
39 layer->SetBounds(layer_size);
40 layer->SetContentBounds(layer_size);
41 layer->CreateRenderSurface();
42 layer->draw_properties().render_target = layer.get();
43 return layer.Pass();
44 }
45
46 // Create a default tiled layer with textures for all tiles and a default
47 // visibility of the entire layer size.
CreateLayer(const gfx::Size & tile_size,const gfx::Size & layer_size,LayerTilingData::BorderTexelOption border_texels)48 scoped_ptr<TiledLayerImpl> CreateLayer(
49 const gfx::Size& tile_size,
50 const gfx::Size& layer_size,
51 LayerTilingData::BorderTexelOption border_texels) {
52 scoped_ptr<TiledLayerImpl> layer =
53 CreateLayerNoTiles(tile_size, layer_size, border_texels);
54
55 ResourceProvider::ResourceId resource_id = 1;
56 for (int i = 0; i < layer->TilingForTesting()->num_tiles_x(); ++i) {
57 for (int j = 0; j < layer->TilingForTesting()->num_tiles_y(); ++j) {
58 gfx::Rect opaque_rect(
59 layer->TilingForTesting()->tile_bounds(i, j).origin(),
60 gfx::Size(1, 1));
61 layer->PushTileProperties(i, j, resource_id++, opaque_rect, false);
62 }
63 }
64
65 return layer.Pass();
66 }
67
GetQuads(RenderPass * render_pass,const gfx::Size & tile_size,const gfx::Size & layer_size,LayerTilingData::BorderTexelOption border_texel_option,const gfx::Rect & visible_content_rect)68 void GetQuads(RenderPass* render_pass,
69 const gfx::Size& tile_size,
70 const gfx::Size& layer_size,
71 LayerTilingData::BorderTexelOption border_texel_option,
72 const gfx::Rect& visible_content_rect) {
73 scoped_ptr<TiledLayerImpl> layer =
74 CreateLayer(tile_size, layer_size, border_texel_option);
75 layer->draw_properties().visible_content_rect = visible_content_rect;
76 layer->SetBounds(layer_size);
77
78 MockOcclusionTracker<LayerImpl> occlusion_tracker;
79 MockQuadCuller quad_culler(render_pass, &occlusion_tracker);
80 AppendQuadsData data;
81 layer->AppendQuads(&quad_culler, &data);
82 }
83
84 protected:
85 FakeImplProxy proxy_;
86 TestSharedBitmapManager shared_bitmap_manager_;
87 FakeLayerTreeHostImpl host_impl_;
88 };
89
TEST_F(TiledLayerImplTest,EmptyQuadList)90 TEST_F(TiledLayerImplTest, EmptyQuadList) {
91 gfx::Size tile_size(90, 90);
92 int num_tiles_x = 8;
93 int num_tiles_y = 4;
94 gfx::Size layer_size(tile_size.width() * num_tiles_x,
95 tile_size.height() * num_tiles_y);
96
97 // Verify default layer does creates quads
98 {
99 scoped_ptr<TiledLayerImpl> layer =
100 CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
101 MockOcclusionTracker<LayerImpl> occlusion_tracker;
102 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
103 MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
104
105 AppendQuadsData data;
106 EXPECT_TRUE(layer->WillDraw(DRAW_MODE_HARDWARE, NULL));
107 layer->AppendQuads(&quad_culler, &data);
108 layer->DidDraw(NULL);
109 unsigned num_tiles = num_tiles_x * num_tiles_y;
110 EXPECT_EQ(quad_culler.quad_list().size(), num_tiles);
111 }
112
113 // Layer with empty visible layer rect produces no quads
114 {
115 scoped_ptr<TiledLayerImpl> layer =
116 CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
117 layer->draw_properties().visible_content_rect = gfx::Rect();
118
119 MockOcclusionTracker<LayerImpl> occlusion_tracker;
120 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
121 MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
122
123 EXPECT_FALSE(layer->WillDraw(DRAW_MODE_HARDWARE, NULL));
124 }
125
126 // Layer with non-intersecting visible layer rect produces no quads
127 {
128 scoped_ptr<TiledLayerImpl> layer =
129 CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
130
131 gfx::Rect outside_bounds(-100, -100, 50, 50);
132 layer->draw_properties().visible_content_rect = outside_bounds;
133
134 MockOcclusionTracker<LayerImpl> occlusion_tracker;
135 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
136 MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
137
138 AppendQuadsData data;
139 EXPECT_TRUE(layer->WillDraw(DRAW_MODE_HARDWARE, NULL));
140 layer->AppendQuads(&quad_culler, &data);
141 layer->DidDraw(NULL);
142 EXPECT_EQ(quad_culler.quad_list().size(), 0u);
143 }
144
145 // Layer with skips draw produces no quads
146 {
147 scoped_ptr<TiledLayerImpl> layer =
148 CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
149 layer->set_skips_draw(true);
150
151 MockOcclusionTracker<LayerImpl> occlusion_tracker;
152 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
153 MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
154
155 AppendQuadsData data;
156 layer->AppendQuads(&quad_culler, &data);
157 EXPECT_EQ(quad_culler.quad_list().size(), 0u);
158 }
159 }
160
TEST_F(TiledLayerImplTest,Checkerboarding)161 TEST_F(TiledLayerImplTest, Checkerboarding) {
162 gfx::Size tile_size(10, 10);
163 int num_tiles_x = 2;
164 int num_tiles_y = 2;
165 gfx::Size layer_size(tile_size.width() * num_tiles_x,
166 tile_size.height() * num_tiles_y);
167
168 scoped_ptr<TiledLayerImpl> layer =
169 CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
170
171 // No checkerboarding
172 {
173 MockOcclusionTracker<LayerImpl> occlusion_tracker;
174 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
175 MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
176
177 AppendQuadsData data;
178 layer->AppendQuads(&quad_culler, &data);
179 EXPECT_EQ(quad_culler.quad_list().size(), 4u);
180 EXPECT_EQ(0u, data.num_missing_tiles);
181
182 for (size_t i = 0; i < quad_culler.quad_list().size(); ++i)
183 EXPECT_EQ(quad_culler.quad_list()[i]->material, DrawQuad::TILED_CONTENT);
184 }
185
186 for (int i = 0; i < num_tiles_x; ++i)
187 for (int j = 0; j < num_tiles_y; ++j)
188 layer->PushTileProperties(i, j, 0, gfx::Rect(), false);
189
190 // All checkerboarding
191 {
192 MockOcclusionTracker<LayerImpl> occlusion_tracker;
193 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
194 MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
195
196 AppendQuadsData data;
197 layer->AppendQuads(&quad_culler, &data);
198 EXPECT_LT(0u, data.num_missing_tiles);
199 EXPECT_EQ(quad_culler.quad_list().size(), 4u);
200 for (size_t i = 0; i < quad_culler.quad_list().size(); ++i)
201 EXPECT_NE(quad_culler.quad_list()[i]->material, DrawQuad::TILED_CONTENT);
202 }
203 }
204
205 // Test with both border texels and without.
206 #define WITH_AND_WITHOUT_BORDER_TEST(text_fixture_name) \
207 TEST_F(TiledLayerImplBorderTest, text_fixture_name##NoBorders) { \
208 text_fixture_name(LayerTilingData::NO_BORDER_TEXELS); \
209 } \
210 TEST_F(TiledLayerImplBorderTest, text_fixture_name##HasBorders) { \
211 text_fixture_name(LayerTilingData::HAS_BORDER_TEXELS); \
212 }
213
214 class TiledLayerImplBorderTest : public TiledLayerImplTest {
215 public:
CoverageVisibleRectOnTileBoundaries(LayerTilingData::BorderTexelOption borders)216 void CoverageVisibleRectOnTileBoundaries(
217 LayerTilingData::BorderTexelOption borders) {
218 gfx::Size layer_size(1000, 1000);
219 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
220 GetQuads(render_pass.get(),
221 gfx::Size(100, 100),
222 layer_size,
223 borders,
224 gfx::Rect(layer_size));
225 LayerTestCommon::VerifyQuadsExactlyCoverRect(render_pass->quad_list,
226 gfx::Rect(layer_size));
227 }
228
CoverageVisibleRectIntersectsTiles(LayerTilingData::BorderTexelOption borders)229 void CoverageVisibleRectIntersectsTiles(
230 LayerTilingData::BorderTexelOption borders) {
231 // This rect intersects the middle 3x3 of the 5x5 tiles.
232 gfx::Point top_left(65, 73);
233 gfx::Point bottom_right(182, 198);
234 gfx::Rect visible_content_rect = gfx::BoundingRect(top_left, bottom_right);
235
236 gfx::Size layer_size(250, 250);
237 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
238 GetQuads(render_pass.get(),
239 gfx::Size(50, 50),
240 gfx::Size(250, 250),
241 LayerTilingData::NO_BORDER_TEXELS,
242 visible_content_rect);
243 LayerTestCommon::VerifyQuadsExactlyCoverRect(render_pass->quad_list,
244 visible_content_rect);
245 }
246
CoverageVisibleRectIntersectsBounds(LayerTilingData::BorderTexelOption borders)247 void CoverageVisibleRectIntersectsBounds(
248 LayerTilingData::BorderTexelOption borders) {
249 gfx::Size layer_size(220, 210);
250 gfx::Rect visible_content_rect(layer_size);
251 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
252 GetQuads(render_pass.get(),
253 gfx::Size(100, 100),
254 layer_size,
255 LayerTilingData::NO_BORDER_TEXELS,
256 visible_content_rect);
257 LayerTestCommon::VerifyQuadsExactlyCoverRect(render_pass->quad_list,
258 visible_content_rect);
259 }
260 };
261 WITH_AND_WITHOUT_BORDER_TEST(CoverageVisibleRectOnTileBoundaries);
262
263 WITH_AND_WITHOUT_BORDER_TEST(CoverageVisibleRectIntersectsTiles);
264
265 WITH_AND_WITHOUT_BORDER_TEST(CoverageVisibleRectIntersectsBounds);
266
TEST_F(TiledLayerImplTest,TextureInfoForLayerNoBorders)267 TEST_F(TiledLayerImplTest, TextureInfoForLayerNoBorders) {
268 gfx::Size tile_size(50, 50);
269 gfx::Size layer_size(250, 250);
270 scoped_ptr<RenderPass> render_pass = RenderPass::Create();
271 GetQuads(render_pass.get(),
272 tile_size,
273 layer_size,
274 LayerTilingData::NO_BORDER_TEXELS,
275 gfx::Rect(layer_size));
276
277 for (size_t i = 0; i < render_pass->quad_list.size(); ++i) {
278 const TileDrawQuad* quad =
279 TileDrawQuad::MaterialCast(render_pass->quad_list[i]);
280
281 EXPECT_NE(0u, quad->resource_id) << LayerTestCommon::quad_string << i;
282 EXPECT_EQ(gfx::RectF(gfx::PointF(), tile_size), quad->tex_coord_rect)
283 << LayerTestCommon::quad_string << i;
284 EXPECT_EQ(tile_size, quad->texture_size) << LayerTestCommon::quad_string
285 << i;
286 EXPECT_EQ(gfx::Size(1, 1).ToString(), quad->opaque_rect.size().ToString())
287 << LayerTestCommon::quad_string << i;
288 }
289 }
290
TEST_F(TiledLayerImplTest,GPUMemoryUsage)291 TEST_F(TiledLayerImplTest, GPUMemoryUsage) {
292 gfx::Size tile_size(20, 30);
293 int num_tiles_x = 12;
294 int num_tiles_y = 32;
295 gfx::Size layer_size(tile_size.width() * num_tiles_x,
296 tile_size.height() * num_tiles_y);
297
298 scoped_ptr<TiledLayerImpl> layer = CreateLayerNoTiles(
299 tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
300
301 EXPECT_EQ(layer->GPUMemoryUsageInBytes(), 0u);
302
303 ResourceProvider::ResourceId resource_id = 1;
304 layer->PushTileProperties(0, 1, resource_id++, gfx::Rect(0, 0, 1, 1), false);
305 layer->PushTileProperties(2, 3, resource_id++, gfx::Rect(0, 0, 1, 1), false);
306 layer->PushTileProperties(2, 0, resource_id++, gfx::Rect(0, 0, 1, 1), false);
307
308 EXPECT_EQ(
309 layer->GPUMemoryUsageInBytes(),
310 static_cast<size_t>(3 * 4 * tile_size.width() * tile_size.height()));
311
312 ResourceProvider::ResourceId empty_resource(0);
313 layer->PushTileProperties(0, 1, empty_resource, gfx::Rect(0, 0, 1, 1), false);
314 layer->PushTileProperties(2, 3, empty_resource, gfx::Rect(0, 0, 1, 1), false);
315 layer->PushTileProperties(2, 0, empty_resource, gfx::Rect(0, 0, 1, 1), false);
316
317 EXPECT_EQ(layer->GPUMemoryUsageInBytes(), 0u);
318 }
319
TEST_F(TiledLayerImplTest,EmptyMask)320 TEST_F(TiledLayerImplTest, EmptyMask) {
321 gfx::Size tile_size(20, 20);
322 gfx::Size layer_size(0, 0);
323 scoped_ptr<TiledLayerImpl> layer =
324 CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
325
326 EXPECT_EQ(0u, layer->ContentsResourceId());
327 EXPECT_EQ(0, layer->TilingForTesting()->num_tiles_x());
328 EXPECT_EQ(0, layer->TilingForTesting()->num_tiles_y());
329 }
330
TEST_F(TiledLayerImplTest,Occlusion)331 TEST_F(TiledLayerImplTest, Occlusion) {
332 gfx::Size tile_size(100, 100);
333 gfx::Size layer_bounds(1000, 1000);
334 gfx::Size viewport_size(1000, 1000);
335
336 LayerTestCommon::LayerImplTest impl;
337
338 TiledLayerImpl* tiled_layer = impl.AddChildToRoot<TiledLayerImpl>();
339 tiled_layer->SetBounds(layer_bounds);
340 tiled_layer->SetContentBounds(layer_bounds);
341 tiled_layer->SetDrawsContent(true);
342 tiled_layer->set_skips_draw(false);
343
344 scoped_ptr<LayerTilingData> tiler =
345 LayerTilingData::Create(tile_size, LayerTilingData::NO_BORDER_TEXELS);
346 tiler->SetTilingRect(gfx::Rect(layer_bounds));
347 tiled_layer->SetTilingData(*tiler);
348
349 ResourceProvider::ResourceId resource_id = 1;
350 for (int i = 0; i < tiled_layer->TilingForTesting()->num_tiles_x(); ++i) {
351 for (int j = 0; j < tiled_layer->TilingForTesting()->num_tiles_y(); ++j)
352 tiled_layer->PushTileProperties(i, j, resource_id++, gfx::Rect(), false);
353 }
354
355 impl.CalcDrawProps(viewport_size);
356
357 {
358 SCOPED_TRACE("No occlusion");
359 gfx::Rect occluded;
360 impl.AppendQuadsWithOcclusion(tiled_layer, occluded);
361
362 LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
363 gfx::Rect(layer_bounds));
364 EXPECT_EQ(100u, impl.quad_list().size());
365 }
366
367 {
368 SCOPED_TRACE("Full occlusion");
369 gfx::Rect occluded(tiled_layer->visible_content_rect());
370 impl.AppendQuadsWithOcclusion(tiled_layer, occluded);
371
372 LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
373 EXPECT_EQ(impl.quad_list().size(), 0u);
374 }
375
376 {
377 SCOPED_TRACE("Partial occlusion");
378 gfx::Rect occluded(150, 0, 200, 1000);
379 impl.AppendQuadsWithOcclusion(tiled_layer, occluded);
380
381 size_t partially_occluded_count = 0;
382 LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
383 impl.quad_list(),
384 gfx::Rect(layer_bounds),
385 occluded,
386 &partially_occluded_count);
387 // The layer outputs one quad, which is partially occluded.
388 EXPECT_EQ(100u - 10u, impl.quad_list().size());
389 EXPECT_EQ(10u + 10u, partially_occluded_count);
390 }
391 }
392
393 } // namespace
394 } // namespace cc
395