OLD | NEW |
| (Empty) |
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/trees/layer_tree_host.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/callback.h" | |
9 #include "base/location.h" | |
10 #include "base/message_loop/message_loop_proxy.h" | |
11 #include "base/time/time.h" | |
12 #include "cc/test/fake_content_layer.h" | |
13 #include "cc/test/fake_content_layer_client.h" | |
14 #include "cc/test/fake_painted_scrollbar_layer.h" | |
15 #include "cc/test/fake_picture_layer.h" | |
16 #include "cc/test/layer_tree_test.h" | |
17 #include "cc/trees/damage_tracker.h" | |
18 #include "cc/trees/layer_tree_impl.h" | |
19 | |
20 namespace cc { | |
21 namespace { | |
22 | |
23 // These tests deal with damage tracking. | |
24 class LayerTreeHostDamageTest : public LayerTreeTest {}; | |
25 | |
26 // LayerTreeHost::SetNeedsRedraw should damage the whole viewport. | |
27 class LayerTreeHostDamageTestSetNeedsRedraw | |
28 : public LayerTreeHostDamageTest { | |
29 void SetupTree() override { | |
30 // Viewport is 10x10. | |
31 scoped_refptr<FakeContentLayer> root = FakeContentLayer::Create(&client_); | |
32 root->SetBounds(gfx::Size(10, 10)); | |
33 | |
34 layer_tree_host()->SetRootLayer(root); | |
35 LayerTreeHostDamageTest::SetupTree(); | |
36 } | |
37 | |
38 void BeginTest() override { | |
39 draw_count_ = 0; | |
40 PostSetNeedsCommitToMainThread(); | |
41 } | |
42 | |
43 void DidCommitAndDrawFrame() override { | |
44 switch (layer_tree_host()->source_frame_number()) { | |
45 case 1: | |
46 layer_tree_host()->SetNeedsRedraw(); | |
47 break; | |
48 } | |
49 } | |
50 | |
51 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl, | |
52 LayerTreeHostImpl::FrameData* frame_data, | |
53 DrawResult draw_result) override { | |
54 EXPECT_EQ(DRAW_SUCCESS, draw_result); | |
55 | |
56 RenderSurfaceImpl* root_surface = | |
57 impl->active_tree()->root_layer()->render_surface(); | |
58 gfx::RectF root_damage = | |
59 root_surface->damage_tracker()->current_damage_rect(); | |
60 | |
61 switch (draw_count_) { | |
62 case 0: | |
63 // The first frame has full damage. | |
64 EXPECT_EQ(gfx::RectF(10.f, 10.f).ToString(), root_damage.ToString()); | |
65 break; | |
66 case 1: | |
67 // The second frame has full damage. | |
68 EXPECT_EQ(gfx::RectF(10.f, 10.f).ToString(), root_damage.ToString()); | |
69 EndTest(); | |
70 break; | |
71 case 2: | |
72 NOTREACHED(); | |
73 } | |
74 | |
75 ++draw_count_; | |
76 return draw_result; | |
77 } | |
78 | |
79 void AfterTest() override {} | |
80 | |
81 int draw_count_; | |
82 FakeContentLayerClient client_; | |
83 }; | |
84 | |
85 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetNeedsRedraw); | |
86 | |
87 // LayerTreeHost::SetViewportSize should damage the whole viewport. | |
88 class LayerTreeHostDamageTestSetViewportSize | |
89 : public LayerTreeHostDamageTest { | |
90 void SetupTree() override { | |
91 // Viewport is 10x10. | |
92 scoped_refptr<FakeContentLayer> root = FakeContentLayer::Create(&client_); | |
93 root->SetBounds(gfx::Size(10, 10)); | |
94 | |
95 layer_tree_host()->SetRootLayer(root); | |
96 LayerTreeHostDamageTest::SetupTree(); | |
97 } | |
98 | |
99 void BeginTest() override { | |
100 draw_count_ = 0; | |
101 PostSetNeedsCommitToMainThread(); | |
102 } | |
103 | |
104 void DidCommitAndDrawFrame() override { | |
105 switch (layer_tree_host()->source_frame_number()) { | |
106 case 1: | |
107 layer_tree_host()->SetViewportSize(gfx::Size(15, 15)); | |
108 break; | |
109 } | |
110 } | |
111 | |
112 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl, | |
113 LayerTreeHostImpl::FrameData* frame_data, | |
114 DrawResult draw_result) override { | |
115 EXPECT_EQ(DRAW_SUCCESS, draw_result); | |
116 | |
117 RenderSurfaceImpl* root_surface = | |
118 impl->active_tree()->root_layer()->render_surface(); | |
119 gfx::RectF root_damage = | |
120 root_surface->damage_tracker()->current_damage_rect(); | |
121 | |
122 switch (draw_count_) { | |
123 case 0: | |
124 // The first frame has full damage. | |
125 EXPECT_EQ(gfx::RectF(10.f, 10.f).ToString(), root_damage.ToString()); | |
126 break; | |
127 case 1: | |
128 // The second frame has full damage. | |
129 EXPECT_EQ(gfx::RectF(15.f, 15.f).ToString(), root_damage.ToString()); | |
130 EndTest(); | |
131 break; | |
132 case 2: | |
133 NOTREACHED(); | |
134 } | |
135 | |
136 ++draw_count_; | |
137 return draw_result; | |
138 } | |
139 | |
140 void AfterTest() override {} | |
141 | |
142 int draw_count_; | |
143 FakeContentLayerClient client_; | |
144 }; | |
145 | |
146 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetViewportSize); | |
147 | |
148 class LayerTreeHostDamageTestNoDamageDoesNotSwap | |
149 : public LayerTreeHostDamageTest { | |
150 void BeginTest() override { | |
151 expect_swap_and_succeed_ = 0; | |
152 did_swaps_ = 0; | |
153 did_swap_and_succeed_ = 0; | |
154 PostSetNeedsCommitToMainThread(); | |
155 } | |
156 | |
157 void SetupTree() override { | |
158 scoped_refptr<FakeContentLayer> root = FakeContentLayer::Create(&client_); | |
159 root->SetBounds(gfx::Size(10, 10)); | |
160 | |
161 // Most of the layer isn't visible. | |
162 content_ = FakeContentLayer::Create(&client_); | |
163 content_->SetBounds(gfx::Size(2000, 100)); | |
164 root->AddChild(content_); | |
165 | |
166 layer_tree_host()->SetRootLayer(root); | |
167 LayerTreeHostDamageTest::SetupTree(); | |
168 } | |
169 | |
170 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | |
171 LayerTreeHostImpl::FrameData* frame_data, | |
172 DrawResult draw_result) override { | |
173 EXPECT_EQ(DRAW_SUCCESS, draw_result); | |
174 | |
175 int source_frame = host_impl->active_tree()->source_frame_number(); | |
176 switch (source_frame) { | |
177 case 0: | |
178 // The first frame has damage, so we should draw and swap. | |
179 ++expect_swap_and_succeed_; | |
180 break; | |
181 case 1: | |
182 // The second frame has no damage, so we should not draw and swap. | |
183 break; | |
184 case 2: | |
185 // The third frame has damage again, so we should draw and swap. | |
186 ++expect_swap_and_succeed_; | |
187 break; | |
188 case 3: | |
189 // The fourth frame has no visible damage, so we should not draw and | |
190 // swap. | |
191 EndTest(); | |
192 break; | |
193 } | |
194 return draw_result; | |
195 } | |
196 | |
197 void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override { | |
198 ++did_swaps_; | |
199 if (result) | |
200 ++did_swap_and_succeed_; | |
201 EXPECT_EQ(expect_swap_and_succeed_, did_swap_and_succeed_); | |
202 } | |
203 | |
204 void DidCommit() override { | |
205 int next_frame = layer_tree_host()->source_frame_number(); | |
206 switch (next_frame) { | |
207 case 1: | |
208 layer_tree_host()->SetNeedsCommit(); | |
209 break; | |
210 case 2: | |
211 // Cause visible damage. | |
212 content_->SetNeedsDisplayRect( | |
213 gfx::Rect(layer_tree_host()->device_viewport_size())); | |
214 break; | |
215 case 3: | |
216 // Cause non-visible damage. | |
217 content_->SetNeedsDisplayRect(gfx::Rect(1990, 1990, 10, 10)); | |
218 layer_tree_host()->SetNeedsCommit(); | |
219 break; | |
220 } | |
221 } | |
222 | |
223 void AfterTest() override { | |
224 EXPECT_EQ(4, did_swaps_); | |
225 EXPECT_EQ(2, expect_swap_and_succeed_); | |
226 EXPECT_EQ(expect_swap_and_succeed_, did_swap_and_succeed_); | |
227 } | |
228 | |
229 FakeContentLayerClient client_; | |
230 scoped_refptr<FakeContentLayer> content_; | |
231 int expect_swap_and_succeed_; | |
232 int did_swaps_; | |
233 int did_swap_and_succeed_; | |
234 }; | |
235 | |
236 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F( | |
237 LayerTreeHostDamageTestNoDamageDoesNotSwap); | |
238 | |
239 class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest { | |
240 void BeginTest() override { PostSetNeedsCommitToMainThread(); } | |
241 | |
242 void SetupTree() override { | |
243 root_ = FakeContentLayer::Create(&client_); | |
244 child_ = FakeContentLayer::Create(&client_); | |
245 | |
246 root_->SetBounds(gfx::Size(500, 500)); | |
247 child_->SetPosition(gfx::Point(100, 100)); | |
248 child_->SetBounds(gfx::Size(30, 30)); | |
249 | |
250 root_->AddChild(child_); | |
251 layer_tree_host()->SetRootLayer(root_); | |
252 LayerTreeHostDamageTest::SetupTree(); | |
253 } | |
254 | |
255 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | |
256 LayerTreeHostImpl::FrameData* frame_data, | |
257 DrawResult draw_result) override { | |
258 EXPECT_EQ(DRAW_SUCCESS, draw_result); | |
259 | |
260 RenderSurfaceImpl* root_surface = | |
261 host_impl->active_tree()->root_layer()->render_surface(); | |
262 gfx::RectF root_damage = | |
263 root_surface->damage_tracker()->current_damage_rect(); | |
264 root_damage.Intersect(root_surface->content_rect()); | |
265 | |
266 int source_frame = host_impl->active_tree()->source_frame_number(); | |
267 switch (source_frame) { | |
268 case 0: | |
269 // The first frame draws and clears any damage. | |
270 EXPECT_EQ(gfx::RectF(root_surface->content_rect()).ToString(), | |
271 root_damage.ToString()); | |
272 EXPECT_FALSE(frame_data->has_no_damage); | |
273 break; | |
274 case 1: | |
275 // If we get a frame without damage then we don't draw. | |
276 EXPECT_EQ(gfx::RectF().ToString(), root_damage.ToString()); | |
277 EXPECT_TRUE(frame_data->has_no_damage); | |
278 | |
279 // Then we set full damage for the next frame. | |
280 host_impl->SetFullRootLayerDamage(); | |
281 break; | |
282 case 2: | |
283 // The whole frame should be damaged as requested. | |
284 EXPECT_EQ(gfx::RectF(root_surface->content_rect()).ToString(), | |
285 root_damage.ToString()); | |
286 EXPECT_FALSE(frame_data->has_no_damage); | |
287 | |
288 // Just a part of the next frame should be damaged. | |
289 child_damage_rect_ = gfx::Rect(10, 11, 12, 13); | |
290 break; | |
291 case 3: | |
292 // The update rect in the child should be damaged and the damaged area | |
293 // should match the invalidation. | |
294 EXPECT_EQ(gfx::RectF(100+10, 100+11, 12, 13).ToString(), | |
295 root_damage.ToString()); | |
296 | |
297 // TODO(danakj): Remove this when impl side painting is always on. | |
298 if (delegating_renderer() || | |
299 host_impl->settings().impl_side_painting) { | |
300 // When using a delegating renderer, or using impl side painting, the | |
301 // entire child is considered damaged as we need to replace its | |
302 // resources with newly created ones. The damaged area is kept as it | |
303 // is, but entire child is painted. | |
304 | |
305 // The paint rect should match the layer bounds. | |
306 gfx::RectF paint_rect = child_->LastPaintRect(); | |
307 paint_rect.set_origin(child_->position()); | |
308 EXPECT_EQ(gfx::RectF(100, 100, 30, 30).ToString(), | |
309 paint_rect.ToString()); | |
310 } | |
311 EXPECT_FALSE(frame_data->has_no_damage); | |
312 | |
313 // If we damage part of the frame, but also damage the full | |
314 // frame, then the whole frame should be damaged. | |
315 child_damage_rect_ = gfx::Rect(10, 11, 12, 13); | |
316 host_impl->SetFullRootLayerDamage(); | |
317 break; | |
318 case 4: | |
319 // The whole frame is damaged. | |
320 EXPECT_EQ(gfx::RectF(root_surface->content_rect()).ToString(), | |
321 root_damage.ToString()); | |
322 EXPECT_FALSE(frame_data->has_no_damage); | |
323 | |
324 EndTest(); | |
325 break; | |
326 } | |
327 return draw_result; | |
328 } | |
329 | |
330 void DidCommitAndDrawFrame() override { | |
331 if (!TestEnded()) | |
332 layer_tree_host()->SetNeedsCommit(); | |
333 | |
334 if (!child_damage_rect_.IsEmpty()) { | |
335 child_->SetNeedsDisplayRect(child_damage_rect_); | |
336 child_damage_rect_ = gfx::Rect(); | |
337 } | |
338 } | |
339 | |
340 void AfterTest() override {} | |
341 | |
342 FakeContentLayerClient client_; | |
343 scoped_refptr<FakeContentLayer> root_; | |
344 scoped_refptr<FakeContentLayer> child_; | |
345 gfx::Rect child_damage_rect_; | |
346 }; | |
347 | |
348 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostDamageTestForcedFullDamage); | |
349 | |
350 class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest { | |
351 void SetupTree() override { | |
352 scoped_refptr<Layer> root_layer = Layer::Create(); | |
353 root_layer->SetBounds(gfx::Size(400, 400)); | |
354 root_layer->SetMasksToBounds(true); | |
355 layer_tree_host()->SetRootLayer(root_layer); | |
356 | |
357 scoped_refptr<Layer> scroll_clip_layer = Layer::Create(); | |
358 scoped_refptr<Layer> content_layer = FakeContentLayer::Create(&client_); | |
359 content_layer->SetScrollClipLayerId(scroll_clip_layer->id()); | |
360 content_layer->SetScrollOffset(gfx::ScrollOffset(10, 20)); | |
361 content_layer->SetBounds(gfx::Size(100, 200)); | |
362 scroll_clip_layer->SetBounds( | |
363 gfx::Size(content_layer->bounds().width() - 30, | |
364 content_layer->bounds().height() - 50)); | |
365 scroll_clip_layer->AddChild(content_layer); | |
366 root_layer->AddChild(scroll_clip_layer); | |
367 | |
368 scoped_refptr<Layer> scrollbar_layer = | |
369 FakePaintedScrollbarLayer::Create(false, true, content_layer->id()); | |
370 scrollbar_layer->SetPosition(gfx::Point(300, 300)); | |
371 scrollbar_layer->SetBounds(gfx::Size(10, 100)); | |
372 scrollbar_layer->ToScrollbarLayer()->SetClipLayer(scroll_clip_layer->id()); | |
373 scrollbar_layer->ToScrollbarLayer()->SetScrollLayer(content_layer->id()); | |
374 root_layer->AddChild(scrollbar_layer); | |
375 | |
376 gfx::RectF content_rect(content_layer->position(), | |
377 content_layer->bounds()); | |
378 gfx::RectF scrollbar_rect(scrollbar_layer->position(), | |
379 scrollbar_layer->bounds()); | |
380 EXPECT_FALSE(content_rect.Intersects(scrollbar_rect)); | |
381 | |
382 LayerTreeHostDamageTest::SetupTree(); | |
383 } | |
384 | |
385 private: | |
386 FakeContentLayerClient client_; | |
387 }; | |
388 | |
389 class LayerTreeHostDamageTestScrollbarDoesDamage | |
390 : public LayerTreeHostScrollbarDamageTest { | |
391 void BeginTest() override { | |
392 did_swaps_ = 0; | |
393 PostSetNeedsCommitToMainThread(); | |
394 } | |
395 | |
396 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | |
397 LayerTreeHostImpl::FrameData* frame_data, | |
398 DrawResult draw_result) override { | |
399 EXPECT_EQ(DRAW_SUCCESS, draw_result); | |
400 RenderSurfaceImpl* root_surface = | |
401 host_impl->active_tree()->root_layer()->render_surface(); | |
402 gfx::RectF root_damage = | |
403 root_surface->damage_tracker()->current_damage_rect(); | |
404 root_damage.Intersect(root_surface->content_rect()); | |
405 switch (did_swaps_) { | |
406 case 0: | |
407 // The first frame has damage, so we should draw and swap. | |
408 break; | |
409 case 1: | |
410 // The second frame should not damage the scrollbars. | |
411 EXPECT_FALSE(root_damage.Intersects(gfx::Rect(300, 300, 10, 100))); | |
412 break; | |
413 case 2: | |
414 // The third frame should damage the scrollbars. | |
415 EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100))); | |
416 break; | |
417 case 3: | |
418 // The fourth frame should damage the scrollbars. | |
419 EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100))); | |
420 EndTest(); | |
421 break; | |
422 } | |
423 return draw_result; | |
424 } | |
425 | |
426 void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override { | |
427 ++did_swaps_; | |
428 EXPECT_TRUE(result); | |
429 LayerImpl* root = host_impl->active_tree()->root_layer(); | |
430 LayerImpl* scroll_clip_layer = root->children()[0]; | |
431 LayerImpl* scroll_layer = scroll_clip_layer->children()[0]; | |
432 switch (did_swaps_) { | |
433 case 1: | |
434 // Test that modifying the position of the content layer (not | |
435 // scrolling) won't damage the scrollbar. | |
436 scroll_layer->SetPosition(gfx::Point(1, 1)); | |
437 scroll_layer->PushScrollOffsetFromMainThread( | |
438 scroll_layer->BaseScrollOffset()); | |
439 host_impl->SetNeedsRedraw(); | |
440 break; | |
441 case 2: | |
442 scroll_layer->ScrollBy(gfx::Vector2dF(10.f, 10.f)); | |
443 host_impl->SetNeedsRedraw(); | |
444 break; | |
445 case 3: | |
446 scroll_layer->SetBounds(gfx::Size(root->bounds().width() + 60, | |
447 root->bounds().height() + 100)); | |
448 host_impl->SetNeedsRedraw(); | |
449 break; | |
450 } | |
451 } | |
452 | |
453 void AfterTest() override { EXPECT_EQ(4, did_swaps_); } | |
454 | |
455 int did_swaps_; | |
456 }; | |
457 | |
458 MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarDoesDamage); | |
459 | |
460 class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage | |
461 : public LayerTreeHostScrollbarDamageTest { | |
462 void BeginTest() override { | |
463 did_swaps_ = 0; | |
464 PostSetNeedsCommitToMainThread(); | |
465 } | |
466 | |
467 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | |
468 LayerTreeHostImpl::FrameData* frame_data, | |
469 DrawResult draw_result) override { | |
470 EXPECT_EQ(DRAW_SUCCESS, draw_result); | |
471 RenderSurfaceImpl* root_surface = | |
472 host_impl->active_tree()->root_layer()->render_surface(); | |
473 gfx::RectF root_damage = | |
474 root_surface->damage_tracker()->current_damage_rect(); | |
475 root_damage.Intersect(root_surface->content_rect()); | |
476 int frame = host_impl->active_tree()->source_frame_number(); | |
477 switch (did_swaps_) { | |
478 case 0: | |
479 // The first frame has damage, so we should draw and swap. | |
480 EXPECT_EQ(0, frame); | |
481 break; | |
482 case 1: | |
483 // The second frame has scrolled, so the scrollbar should be damaged. | |
484 EXPECT_EQ(0, frame); | |
485 EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100))); | |
486 break; | |
487 case 2: | |
488 // The third frame (after the commit) has no changes, so it shouldn't. | |
489 EXPECT_EQ(1, frame); | |
490 EXPECT_FALSE(root_damage.Intersects(gfx::Rect(300, 300, 10, 100))); | |
491 break; | |
492 default: | |
493 NOTREACHED(); | |
494 break; | |
495 } | |
496 return draw_result; | |
497 } | |
498 | |
499 void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override { | |
500 ++did_swaps_; | |
501 EXPECT_TRUE(result); | |
502 LayerImpl* root = host_impl->active_tree()->root_layer(); | |
503 LayerImpl* scroll_clip_layer = root->children()[0]; | |
504 LayerImpl* scroll_layer = scroll_clip_layer->children()[0]; | |
505 switch (did_swaps_) { | |
506 case 1: | |
507 // Scroll on the thread. This should damage the scrollbar for the | |
508 // next draw on the thread. | |
509 scroll_layer->ScrollBy(gfx::Vector2dF(10.f, 10.f)); | |
510 host_impl->SetNeedsRedraw(); | |
511 break; | |
512 case 2: | |
513 // Forcibly send the scroll to the main thread. | |
514 PostSetNeedsCommitToMainThread(); | |
515 break; | |
516 case 3: | |
517 // First swap after second commit. | |
518 EndTest(); | |
519 break; | |
520 default: | |
521 NOTREACHED(); | |
522 break; | |
523 } | |
524 } | |
525 | |
526 void AfterTest() override { EXPECT_EQ(3, did_swaps_); } | |
527 | |
528 int did_swaps_; | |
529 }; | |
530 | |
531 MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarCommitDoesNoDamage); | |
532 | |
533 } // namespace | |
534 } // namespace cc | |
OLD | NEW |