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/basictypes.h" | |
8 #include "cc/layers/content_layer.h" | |
9 #include "cc/layers/delegated_frame_provider.h" | |
10 #include "cc/layers/delegated_frame_resource_collection.h" | |
11 #include "cc/layers/heads_up_display_layer.h" | |
12 #include "cc/layers/io_surface_layer.h" | |
13 #include "cc/layers/layer_impl.h" | |
14 #include "cc/layers/painted_scrollbar_layer.h" | |
15 #include "cc/layers/picture_layer.h" | |
16 #include "cc/layers/texture_layer.h" | |
17 #include "cc/layers/texture_layer_impl.h" | |
18 #include "cc/output/filter_operations.h" | |
19 #include "cc/resources/single_release_callback.h" | |
20 #include "cc/test/failure_output_surface.h" | |
21 #include "cc/test/fake_content_layer.h" | |
22 #include "cc/test/fake_content_layer_client.h" | |
23 #include "cc/test/fake_content_layer_impl.h" | |
24 #include "cc/test/fake_delegated_renderer_layer.h" | |
25 #include "cc/test/fake_delegated_renderer_layer_impl.h" | |
26 #include "cc/test/fake_layer_tree_host_client.h" | |
27 #include "cc/test/fake_output_surface.h" | |
28 #include "cc/test/fake_output_surface_client.h" | |
29 #include "cc/test/fake_painted_scrollbar_layer.h" | |
30 #include "cc/test/fake_picture_layer.h" | |
31 #include "cc/test/fake_picture_layer_impl.h" | |
32 #include "cc/test/fake_scoped_ui_resource.h" | |
33 #include "cc/test/fake_scrollbar.h" | |
34 #include "cc/test/layer_tree_test.h" | |
35 #include "cc/test/render_pass_test_common.h" | |
36 #include "cc/test/test_context_provider.h" | |
37 #include "cc/test/test_shared_bitmap_manager.h" | |
38 #include "cc/test/test_web_graphics_context_3d.h" | |
39 #include "cc/trees/layer_tree_host_impl.h" | |
40 #include "cc/trees/layer_tree_impl.h" | |
41 #include "cc/trees/single_thread_proxy.h" | |
42 #include "gpu/GLES2/gl2extchromium.h" | |
43 | |
44 namespace cc { | |
45 namespace { | |
46 | |
47 // These tests deal with losing the 3d graphics context. | |
48 class LayerTreeHostContextTest : public LayerTreeTest { | |
49 public: | |
50 LayerTreeHostContextTest() | |
51 : LayerTreeTest(), | |
52 context3d_(NULL), | |
53 times_to_fail_create_(0), | |
54 times_to_lose_during_commit_(0), | |
55 times_to_lose_during_draw_(0), | |
56 times_to_fail_recreate_(0), | |
57 times_to_expect_create_failed_(0), | |
58 times_create_failed_(0), | |
59 committed_at_least_once_(false), | |
60 context_should_support_io_surface_(false), | |
61 fallback_context_works_(false), | |
62 async_output_surface_creation_(false) { | |
63 } | |
64 | |
65 void LoseContext() { | |
66 // For sanity-checking tests, they should only call this when the | |
67 // context is not lost. | |
68 CHECK(context3d_); | |
69 context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, | |
70 GL_INNOCENT_CONTEXT_RESET_ARB); | |
71 context3d_ = NULL; | |
72 } | |
73 | |
74 virtual scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() { | |
75 return TestWebGraphicsContext3D::Create(); | |
76 } | |
77 | |
78 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override { | |
79 if (times_to_fail_create_) { | |
80 --times_to_fail_create_; | |
81 ExpectCreateToFail(); | |
82 return make_scoped_ptr(new FailureOutputSurface(delegating_renderer())); | |
83 } | |
84 | |
85 scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d(); | |
86 context3d_ = context3d.get(); | |
87 | |
88 if (context_should_support_io_surface_) { | |
89 context3d_->set_have_extension_io_surface(true); | |
90 context3d_->set_have_extension_egl_image(true); | |
91 } | |
92 | |
93 if (delegating_renderer()) | |
94 return FakeOutputSurface::CreateDelegating3d(context3d.Pass()); | |
95 else | |
96 return FakeOutputSurface::Create3d(context3d.Pass()); | |
97 } | |
98 | |
99 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | |
100 LayerTreeHostImpl::FrameData* frame, | |
101 DrawResult draw_result) override { | |
102 if (draw_result == DRAW_ABORTED_MISSING_HIGH_RES_CONTENT) { | |
103 // Only valid for single-threaded impl-side painting, which activates | |
104 // immediately and will try to draw again when content has finished. | |
105 DCHECK(!host_impl->proxy()->HasImplThread()); | |
106 DCHECK(host_impl->settings().impl_side_painting); | |
107 return draw_result; | |
108 } | |
109 EXPECT_EQ(DRAW_SUCCESS, draw_result); | |
110 if (!times_to_lose_during_draw_) | |
111 return draw_result; | |
112 | |
113 --times_to_lose_during_draw_; | |
114 LoseContext(); | |
115 | |
116 times_to_fail_create_ = times_to_fail_recreate_; | |
117 times_to_fail_recreate_ = 0; | |
118 | |
119 return draw_result; | |
120 } | |
121 | |
122 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | |
123 committed_at_least_once_ = true; | |
124 | |
125 if (!times_to_lose_during_commit_) | |
126 return; | |
127 --times_to_lose_during_commit_; | |
128 LoseContext(); | |
129 | |
130 times_to_fail_create_ = times_to_fail_recreate_; | |
131 times_to_fail_recreate_ = 0; | |
132 } | |
133 | |
134 void DidFailToInitializeOutputSurface() override { ++times_create_failed_; } | |
135 | |
136 void TearDown() override { | |
137 LayerTreeTest::TearDown(); | |
138 EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_); | |
139 } | |
140 | |
141 void ExpectCreateToFail() { ++times_to_expect_create_failed_; } | |
142 | |
143 protected: | |
144 TestWebGraphicsContext3D* context3d_; | |
145 int times_to_fail_create_; | |
146 int times_to_lose_during_commit_; | |
147 int times_to_lose_during_draw_; | |
148 int times_to_fail_recreate_; | |
149 int times_to_expect_create_failed_; | |
150 int times_create_failed_; | |
151 bool committed_at_least_once_; | |
152 bool context_should_support_io_surface_; | |
153 bool fallback_context_works_; | |
154 bool async_output_surface_creation_; | |
155 }; | |
156 | |
157 class LayerTreeHostContextTestLostContextSucceeds | |
158 : public LayerTreeHostContextTest { | |
159 public: | |
160 LayerTreeHostContextTestLostContextSucceeds() | |
161 : LayerTreeHostContextTest(), | |
162 test_case_(0), | |
163 num_losses_(0), | |
164 num_losses_last_test_case_(-1), | |
165 recovered_context_(true), | |
166 first_initialized_(false) {} | |
167 | |
168 void BeginTest() override { PostSetNeedsCommitToMainThread(); } | |
169 | |
170 void RequestNewOutputSurface() override { | |
171 if (async_output_surface_creation_) { | |
172 MainThreadTaskRunner()->PostTask( | |
173 FROM_HERE, base::Bind(&LayerTreeHostContextTestLostContextSucceeds:: | |
174 CreateAndSetOutputSurface, | |
175 base::Unretained(this))); | |
176 } else { | |
177 CreateAndSetOutputSurface(); | |
178 } | |
179 } | |
180 | |
181 void CreateAndSetOutputSurface() { | |
182 scoped_ptr<OutputSurface> surface( | |
183 LayerTreeHostContextTest::CreateOutputSurface()); | |
184 CHECK(surface); | |
185 layer_tree_host()->SetOutputSurface(surface.Pass()); | |
186 } | |
187 | |
188 void DidInitializeOutputSurface() override { | |
189 if (first_initialized_) | |
190 ++num_losses_; | |
191 else | |
192 first_initialized_ = true; | |
193 | |
194 recovered_context_ = true; | |
195 } | |
196 | |
197 void AfterTest() override { EXPECT_EQ(11u, test_case_); } | |
198 | |
199 void DidCommitAndDrawFrame() override { | |
200 // If the last frame had a context loss, then we'll commit again to | |
201 // recover. | |
202 if (!recovered_context_) | |
203 return; | |
204 if (times_to_lose_during_commit_) | |
205 return; | |
206 if (times_to_lose_during_draw_) | |
207 return; | |
208 | |
209 recovered_context_ = false; | |
210 if (NextTestCase()) | |
211 InvalidateAndSetNeedsCommit(); | |
212 else | |
213 EndTest(); | |
214 } | |
215 | |
216 virtual void InvalidateAndSetNeedsCommit() { | |
217 // Cause damage so we try to draw. | |
218 layer_tree_host()->root_layer()->SetNeedsDisplay(); | |
219 layer_tree_host()->SetNeedsCommit(); | |
220 } | |
221 | |
222 bool NextTestCase() { | |
223 static const TestCase kTests[] = { | |
224 // Losing the context and failing to recreate it (or losing it again | |
225 // immediately) a small number of times should succeed. | |
226 { | |
227 1, // times_to_lose_during_commit | |
228 0, // times_to_lose_during_draw | |
229 0, // times_to_fail_recreate | |
230 false, // fallback_context_works | |
231 false, // async_output_surface_creation | |
232 }, | |
233 { | |
234 0, // times_to_lose_during_commit | |
235 1, // times_to_lose_during_draw | |
236 0, // times_to_fail_recreate | |
237 false, // fallback_context_works | |
238 false, // async_output_surface_creation | |
239 }, | |
240 { | |
241 1, // times_to_lose_during_commit | |
242 0, // times_to_lose_during_draw | |
243 3, // times_to_fail_recreate | |
244 false, // fallback_context_works | |
245 false, // async_output_surface_creation | |
246 }, | |
247 { | |
248 0, // times_to_lose_during_commit | |
249 1, // times_to_lose_during_draw | |
250 3, // times_to_fail_recreate | |
251 false, // fallback_context_works | |
252 false, // async_output_surface_creation | |
253 }, | |
254 { | |
255 0, // times_to_lose_during_commit | |
256 1, // times_to_lose_during_draw | |
257 3, // times_to_fail_recreate | |
258 false, // fallback_context_works | |
259 true, // async_output_surface_creation | |
260 }, | |
261 // Losing the context and recreating it any number of times should | |
262 // succeed. | |
263 { | |
264 10, // times_to_lose_during_commit | |
265 0, // times_to_lose_during_draw | |
266 0, // times_to_fail_recreate | |
267 false, // fallback_context_works | |
268 false, // async_output_surface_creation | |
269 }, | |
270 { | |
271 0, // times_to_lose_during_commit | |
272 10, // times_to_lose_during_draw | |
273 0, // times_to_fail_recreate | |
274 false, // fallback_context_works | |
275 false, // async_output_surface_creation | |
276 }, | |
277 { | |
278 10, // times_to_lose_during_commit | |
279 0, // times_to_lose_during_draw | |
280 0, // times_to_fail_recreate | |
281 false, // fallback_context_works | |
282 true, // async_output_surface_creation | |
283 }, | |
284 { | |
285 0, // times_to_lose_during_commit | |
286 10, // times_to_lose_during_draw | |
287 0, // times_to_fail_recreate | |
288 false, // fallback_context_works | |
289 true, // async_output_surface_creation | |
290 }, | |
291 // Losing the context, failing to reinitialize it, and making a fallback | |
292 // context should work. | |
293 { | |
294 0, // times_to_lose_during_commit | |
295 1, // times_to_lose_during_draw | |
296 0, // times_to_fail_recreate | |
297 true, // fallback_context_works | |
298 false, // async_output_surface_creation | |
299 }, | |
300 { | |
301 0, // times_to_lose_during_commit | |
302 1, // times_to_lose_during_draw | |
303 0, // times_to_fail_recreate | |
304 true, // fallback_context_works | |
305 true, // async_output_surface_creation | |
306 }, | |
307 }; | |
308 | |
309 if (test_case_ >= arraysize(kTests)) | |
310 return false; | |
311 // Make sure that we lost our context at least once in the last test run so | |
312 // the test did something. | |
313 EXPECT_GT(num_losses_, num_losses_last_test_case_); | |
314 num_losses_last_test_case_ = num_losses_; | |
315 | |
316 times_to_lose_during_commit_ = | |
317 kTests[test_case_].times_to_lose_during_commit; | |
318 times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw; | |
319 times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate; | |
320 fallback_context_works_ = kTests[test_case_].fallback_context_works; | |
321 async_output_surface_creation_ = | |
322 kTests[test_case_].async_output_surface_creation; | |
323 ++test_case_; | |
324 return true; | |
325 } | |
326 | |
327 struct TestCase { | |
328 int times_to_lose_during_commit; | |
329 int times_to_lose_during_draw; | |
330 int times_to_fail_recreate; | |
331 bool fallback_context_works; | |
332 bool async_output_surface_creation; | |
333 }; | |
334 | |
335 protected: | |
336 size_t test_case_; | |
337 int num_losses_; | |
338 int num_losses_last_test_case_; | |
339 bool recovered_context_; | |
340 bool first_initialized_; | |
341 }; | |
342 | |
343 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds); | |
344 | |
345 class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface | |
346 : public LayerTreeHostContextTest { | |
347 public: | |
348 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface() | |
349 : LayerTreeHostContextTest() {} | |
350 | |
351 void WillBeginTest() override { | |
352 // Override and do not signal SetLayerTreeHostClientReady. | |
353 } | |
354 | |
355 void BeginTest() override { | |
356 PostSetNeedsCommitToMainThread(); | |
357 EndTest(); | |
358 } | |
359 | |
360 scoped_ptr<OutputSurface> CreateOutputSurface() override { | |
361 EXPECT_TRUE(false); | |
362 return nullptr; | |
363 } | |
364 | |
365 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); } | |
366 | |
367 void AfterTest() override {} | |
368 }; | |
369 | |
370 SINGLE_AND_MULTI_THREAD_TEST_F( | |
371 LayerTreeHostClientNotReadyDoesNotCreateOutputSurface); | |
372 | |
373 class MultipleCompositeDoesNotCreateOutputSurface | |
374 : public LayerTreeHostContextTest { | |
375 public: | |
376 MultipleCompositeDoesNotCreateOutputSurface() | |
377 : LayerTreeHostContextTest(), request_count_(0) {} | |
378 | |
379 void InitializeSettings(LayerTreeSettings* settings) override { | |
380 settings->single_thread_proxy_scheduler = false; | |
381 } | |
382 | |
383 void RequestNewOutputSurface() override { | |
384 EXPECT_GE(1, ++request_count_); | |
385 EndTest(); | |
386 } | |
387 | |
388 void BeginTest() override { | |
389 layer_tree_host()->Composite(base::TimeTicks()); | |
390 layer_tree_host()->Composite(base::TimeTicks()); | |
391 } | |
392 | |
393 scoped_ptr<OutputSurface> CreateOutputSurface() override { | |
394 EXPECT_TRUE(false); | |
395 return nullptr; | |
396 } | |
397 | |
398 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); } | |
399 | |
400 void AfterTest() override {} | |
401 | |
402 int request_count_; | |
403 }; | |
404 | |
405 SINGLE_THREAD_NOIMPL_TEST_F(MultipleCompositeDoesNotCreateOutputSurface); | |
406 | |
407 // This test makes sure that once a SingleThreadProxy issues a | |
408 // DidFailToInitializeOutputSurface, that future Composite calls will not | |
409 // trigger additional requests for output surfaces. | |
410 class FailedCreateDoesNotCreateExtraOutputSurface | |
411 : public LayerTreeHostContextTest { | |
412 public: | |
413 FailedCreateDoesNotCreateExtraOutputSurface() | |
414 : LayerTreeHostContextTest(), num_requests_(0), has_failed_(false) {} | |
415 | |
416 void InitializeSettings(LayerTreeSettings* settings) override { | |
417 settings->single_thread_proxy_scheduler = false; | |
418 } | |
419 | |
420 void RequestNewOutputSurface() override { | |
421 num_requests_++; | |
422 // There should be one initial request and then one request from | |
423 // the LayerTreeTest test hooks DidFailToInitializeOutputSurface (which is | |
424 // hard to skip). This second request is just ignored and is test cruft. | |
425 EXPECT_LE(num_requests_, 2); | |
426 if (num_requests_ > 1) | |
427 return; | |
428 ExpectCreateToFail(); | |
429 layer_tree_host()->SetOutputSurface( | |
430 make_scoped_ptr(new FailureOutputSurface(false))); | |
431 } | |
432 | |
433 void BeginTest() override { | |
434 // First composite tries to create a surface. | |
435 layer_tree_host()->Composite(base::TimeTicks()); | |
436 EXPECT_EQ(num_requests_, 2); | |
437 EXPECT_TRUE(has_failed_); | |
438 | |
439 // Second composite should not request or fail. | |
440 layer_tree_host()->Composite(base::TimeTicks()); | |
441 EXPECT_EQ(num_requests_, 2); | |
442 EndTest(); | |
443 } | |
444 | |
445 void DidInitializeOutputSurface() override { EXPECT_TRUE(false); } | |
446 | |
447 void DidFailToInitializeOutputSurface() override { | |
448 LayerTreeHostContextTest::DidFailToInitializeOutputSurface(); | |
449 EXPECT_FALSE(has_failed_); | |
450 has_failed_ = true; | |
451 } | |
452 | |
453 void AfterTest() override {} | |
454 | |
455 int num_requests_; | |
456 bool has_failed_; | |
457 }; | |
458 | |
459 SINGLE_THREAD_NOIMPL_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface); | |
460 | |
461 class LayerTreeHostContextTestCommitAfterDelayedOutputSurface | |
462 : public LayerTreeHostContextTest { | |
463 public: | |
464 LayerTreeHostContextTestCommitAfterDelayedOutputSurface() | |
465 : LayerTreeHostContextTest(), creating_output_(false) {} | |
466 | |
467 void InitializeSettings(LayerTreeSettings* settings) override { | |
468 settings->single_thread_proxy_scheduler = false; | |
469 } | |
470 | |
471 void RequestNewOutputSurface() override { | |
472 MainThreadTaskRunner()->PostTask( | |
473 FROM_HERE, | |
474 base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface:: | |
475 CreateAndSetOutputSurface, | |
476 base::Unretained(this))); | |
477 } | |
478 | |
479 void CreateAndSetOutputSurface() { | |
480 creating_output_ = true; | |
481 layer_tree_host()->SetOutputSurface( | |
482 LayerTreeHostContextTest::CreateOutputSurface()); | |
483 } | |
484 | |
485 void BeginTest() override { layer_tree_host()->Composite(base::TimeTicks()); } | |
486 | |
487 void ScheduleComposite() override { | |
488 if (creating_output_) | |
489 EndTest(); | |
490 } | |
491 | |
492 void AfterTest() override {} | |
493 | |
494 bool creating_output_; | |
495 }; | |
496 | |
497 SINGLE_THREAD_NOIMPL_TEST_F( | |
498 LayerTreeHostContextTestCommitAfterDelayedOutputSurface); | |
499 | |
500 class LayerTreeHostContextTestAvoidUnnecessaryComposite | |
501 : public LayerTreeHostContextTest { | |
502 public: | |
503 LayerTreeHostContextTestAvoidUnnecessaryComposite() | |
504 : LayerTreeHostContextTest(), in_composite_(false) {} | |
505 | |
506 void InitializeSettings(LayerTreeSettings* settings) override { | |
507 settings->single_thread_proxy_scheduler = false; | |
508 } | |
509 | |
510 void RequestNewOutputSurface() override { | |
511 layer_tree_host()->SetOutputSurface( | |
512 LayerTreeHostContextTest::CreateOutputSurface()); | |
513 EndTest(); | |
514 } | |
515 | |
516 void BeginTest() override { | |
517 in_composite_ = true; | |
518 layer_tree_host()->Composite(base::TimeTicks()); | |
519 in_composite_ = false; | |
520 } | |
521 | |
522 void ScheduleComposite() override { EXPECT_FALSE(in_composite_); } | |
523 | |
524 void AfterTest() override {} | |
525 | |
526 bool in_composite_; | |
527 }; | |
528 | |
529 SINGLE_THREAD_NOIMPL_TEST_F(LayerTreeHostContextTestAvoidUnnecessaryComposite); | |
530 | |
531 class LayerTreeHostContextTestLostContextSucceedsWithContent | |
532 : public LayerTreeHostContextTestLostContextSucceeds { | |
533 public: | |
534 void SetupTree() override { | |
535 root_ = Layer::Create(); | |
536 root_->SetBounds(gfx::Size(10, 10)); | |
537 root_->SetIsDrawable(true); | |
538 | |
539 // Paint non-solid color. | |
540 SkPaint paint; | |
541 paint.setColor(SkColorSetARGB(100, 80, 200, 200)); | |
542 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint); | |
543 | |
544 if (layer_tree_host()->settings().impl_side_painting) | |
545 layer_ = FakePictureLayer::Create(&client_); | |
546 else | |
547 layer_ = FakeContentLayer::Create(&client_); | |
548 layer_->SetBounds(gfx::Size(10, 10)); | |
549 layer_->SetIsDrawable(true); | |
550 | |
551 root_->AddChild(layer_); | |
552 | |
553 layer_tree_host()->SetRootLayer(root_); | |
554 LayerTreeHostContextTest::SetupTree(); | |
555 } | |
556 | |
557 void InvalidateAndSetNeedsCommit() override { | |
558 // Invalidate the render surface so we don't try to use a cached copy of the | |
559 // surface. We want to make sure to test the drawing paths for drawing to | |
560 // a child surface. | |
561 layer_->SetNeedsDisplay(); | |
562 LayerTreeHostContextTestLostContextSucceeds::InvalidateAndSetNeedsCommit(); | |
563 } | |
564 | |
565 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | |
566 if (!host_impl->settings().impl_side_painting) { | |
567 FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>( | |
568 host_impl->active_tree()->root_layer()->children()[0]); | |
569 // Even though the context was lost, we should have a resource. The | |
570 // TestWebGraphicsContext3D ensures that this resource is created with | |
571 // the active context. | |
572 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0)); | |
573 } else { | |
574 FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>( | |
575 host_impl->active_tree()->root_layer()->children()[0]); | |
576 EXPECT_TRUE(picture_impl->HighResTiling()->TileAt(0, 0)->IsReadyToDraw()); | |
577 } | |
578 } | |
579 | |
580 protected: | |
581 FakeContentLayerClient client_; | |
582 scoped_refptr<Layer> root_; | |
583 scoped_refptr<Layer> layer_; | |
584 }; | |
585 | |
586 // This test uses TiledLayer and PictureLayer to check for a working context. | |
587 SINGLE_AND_MULTI_THREAD_TEST_F( | |
588 LayerTreeHostContextTestLostContextSucceedsWithContent); | |
589 | |
590 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce | |
591 : public LayerTreeHostContextTest { | |
592 public: | |
593 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce() | |
594 : times_to_fail_(1), times_initialized_(0) { | |
595 times_to_fail_create_ = times_to_fail_; | |
596 } | |
597 | |
598 void BeginTest() override { PostSetNeedsCommitToMainThread(); } | |
599 | |
600 void DidInitializeOutputSurface() override { times_initialized_++; } | |
601 | |
602 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { EndTest(); } | |
603 | |
604 void AfterTest() override { | |
605 EXPECT_EQ(times_to_fail_, times_create_failed_); | |
606 EXPECT_NE(0, times_initialized_); | |
607 } | |
608 | |
609 private: | |
610 int times_to_fail_; | |
611 int times_initialized_; | |
612 }; | |
613 | |
614 SINGLE_AND_MULTI_THREAD_TEST_F( | |
615 LayerTreeHostContextTestCreateOutputSurfaceFailsOnce); | |
616 | |
617 class LayerTreeHostContextTestLostContextAndEvictTextures | |
618 : public LayerTreeHostContextTest { | |
619 public: | |
620 LayerTreeHostContextTestLostContextAndEvictTextures() | |
621 : LayerTreeHostContextTest(), | |
622 impl_host_(0), | |
623 num_commits_(0), | |
624 lost_context_(false) {} | |
625 | |
626 void SetupTree() override { | |
627 // Paint non-solid color. | |
628 SkPaint paint; | |
629 paint.setColor(SkColorSetARGB(100, 80, 200, 200)); | |
630 client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint); | |
631 | |
632 if (layer_tree_host()->settings().impl_side_painting) { | |
633 picture_layer_ = FakePictureLayer::Create(&client_); | |
634 picture_layer_->SetBounds(gfx::Size(10, 20)); | |
635 layer_tree_host()->SetRootLayer(picture_layer_); | |
636 } else { | |
637 content_layer_ = FakeContentLayer::Create(&client_); | |
638 content_layer_->SetBounds(gfx::Size(10, 20)); | |
639 layer_tree_host()->SetRootLayer(content_layer_); | |
640 } | |
641 | |
642 LayerTreeHostContextTest::SetupTree(); | |
643 } | |
644 | |
645 void BeginTest() override { PostSetNeedsCommitToMainThread(); } | |
646 | |
647 void PostEvictTextures() { | |
648 if (HasImplThread()) { | |
649 ImplThreadTaskRunner()->PostTask( | |
650 FROM_HERE, | |
651 base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures:: | |
652 EvictTexturesOnImplThread, | |
653 base::Unretained(this))); | |
654 } else { | |
655 DebugScopedSetImplThread impl(proxy()); | |
656 EvictTexturesOnImplThread(); | |
657 } | |
658 } | |
659 | |
660 void EvictTexturesOnImplThread() { | |
661 impl_host_->EvictTexturesForTesting(); | |
662 | |
663 if (lose_after_evict_) { | |
664 LoseContext(); | |
665 lost_context_ = true; | |
666 } | |
667 } | |
668 | |
669 void DidCommitAndDrawFrame() override { | |
670 if (num_commits_ > 1) | |
671 return; | |
672 if (!layer_tree_host()->settings().impl_side_painting) { | |
673 EXPECT_TRUE(content_layer_->HaveBackingAt(0, 0)); | |
674 } | |
675 PostEvictTextures(); | |
676 } | |
677 | |
678 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | |
679 LayerTreeHostContextTest::CommitCompleteOnThread(impl); | |
680 if (num_commits_ > 1) | |
681 return; | |
682 ++num_commits_; | |
683 if (!lose_after_evict_) { | |
684 LoseContext(); | |
685 lost_context_ = true; | |
686 } | |
687 } | |
688 | |
689 void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | |
690 if (impl->settings().impl_side_painting) { | |
691 FakePictureLayerImpl* picture_impl = | |
692 static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer()); | |
693 EXPECT_TRUE(picture_impl->HighResTiling()->TileAt(0, 0)->IsReadyToDraw()); | |
694 } else { | |
695 FakeContentLayerImpl* content_impl = | |
696 static_cast<FakeContentLayerImpl*>(impl->active_tree()->root_layer()); | |
697 EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0)); | |
698 } | |
699 | |
700 impl_host_ = impl; | |
701 if (lost_context_) | |
702 EndTest(); | |
703 } | |
704 | |
705 void DidInitializeOutputSurface() override {} | |
706 | |
707 void AfterTest() override {} | |
708 | |
709 protected: | |
710 bool lose_after_evict_; | |
711 FakeContentLayerClient client_; | |
712 scoped_refptr<FakeContentLayer> content_layer_; | |
713 scoped_refptr<FakePictureLayer> picture_layer_; | |
714 LayerTreeHostImpl* impl_host_; | |
715 int num_commits_; | |
716 bool lost_context_; | |
717 }; | |
718 | |
719 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
720 LoseAfterEvict_SingleThread_DirectRenderer) { | |
721 lose_after_evict_ = true; | |
722 RunTest(false, false, false); | |
723 } | |
724 | |
725 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
726 LoseAfterEvict_SingleThread_DelegatingRenderer) { | |
727 lose_after_evict_ = true; | |
728 RunTest(false, true, false); | |
729 } | |
730 | |
731 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
732 LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) { | |
733 lose_after_evict_ = true; | |
734 RunTest(true, false, false); | |
735 } | |
736 | |
737 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
738 LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) { | |
739 lose_after_evict_ = true; | |
740 RunTest(true, true, false); | |
741 } | |
742 | |
743 // Flaky on all platforms, http://crbug.com/310979 | |
744 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
745 DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) { | |
746 lose_after_evict_ = true; | |
747 RunTest(true, true, true); | |
748 } | |
749 | |
750 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
751 LoseBeforeEvict_SingleThread_DirectRenderer) { | |
752 lose_after_evict_ = false; | |
753 RunTest(false, false, false); | |
754 } | |
755 | |
756 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
757 LoseBeforeEvict_SingleThread_DelegatingRenderer) { | |
758 lose_after_evict_ = false; | |
759 RunTest(false, true, false); | |
760 } | |
761 | |
762 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
763 LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) { | |
764 lose_after_evict_ = false; | |
765 RunTest(true, false, false); | |
766 } | |
767 | |
768 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
769 LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) { | |
770 lose_after_evict_ = false; | |
771 RunTest(true, false, true); | |
772 } | |
773 | |
774 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
775 LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) { | |
776 lose_after_evict_ = false; | |
777 RunTest(true, true, false); | |
778 } | |
779 | |
780 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, | |
781 LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) { | |
782 lose_after_evict_ = false; | |
783 RunTest(true, true, true); | |
784 } | |
785 | |
786 class LayerTreeHostContextTestLostContextWhileUpdatingResources | |
787 : public LayerTreeHostContextTest { | |
788 public: | |
789 LayerTreeHostContextTestLostContextWhileUpdatingResources() | |
790 : num_children_(50), times_to_lose_on_end_query_(3) {} | |
791 | |
792 scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() override { | |
793 scoped_ptr<TestWebGraphicsContext3D> context = | |
794 LayerTreeHostContextTest::CreateContext3d(); | |
795 if (times_to_lose_on_end_query_) { | |
796 --times_to_lose_on_end_query_; | |
797 context->set_times_end_query_succeeds(5); | |
798 } | |
799 return context.Pass(); | |
800 } | |
801 | |
802 void SetupTree() override { | |
803 if (layer_tree_host()->settings().impl_side_painting) | |
804 parent_ = FakePictureLayer::Create(&client_); | |
805 else | |
806 parent_ = FakeContentLayer::Create(&client_); | |
807 | |
808 parent_->SetBounds(gfx::Size(num_children_, 1)); | |
809 | |
810 for (int i = 0; i < num_children_; i++) { | |
811 scoped_refptr<Layer> child; | |
812 if (layer_tree_host()->settings().impl_side_painting) | |
813 child = FakePictureLayer::Create(&client_); | |
814 else | |
815 child = FakeContentLayer::Create(&client_); | |
816 child->SetPosition(gfx::PointF(i, 0.f)); | |
817 child->SetBounds(gfx::Size(1, 1)); | |
818 parent_->AddChild(child); | |
819 } | |
820 | |
821 layer_tree_host()->SetRootLayer(parent_); | |
822 LayerTreeHostContextTest::SetupTree(); | |
823 } | |
824 | |
825 void BeginTest() override { PostSetNeedsCommitToMainThread(); } | |
826 | |
827 void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | |
828 EXPECT_EQ(0, times_to_lose_on_end_query_); | |
829 EndTest(); | |
830 } | |
831 | |
832 void AfterTest() override { EXPECT_EQ(0, times_to_lose_on_end_query_); } | |
833 | |
834 private: | |
835 FakeContentLayerClient client_; | |
836 scoped_refptr<Layer> parent_; | |
837 int num_children_; | |
838 int times_to_lose_on_end_query_; | |
839 }; | |
840 | |
841 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F( | |
842 LayerTreeHostContextTestLostContextWhileUpdatingResources); | |
843 | |
844 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest { | |
845 public: | |
846 LayerTreeHostContextTestLayersNotified() | |
847 : LayerTreeHostContextTest(), num_commits_(0) {} | |
848 | |
849 void SetupTree() override { | |
850 if (layer_tree_host()->settings().impl_side_painting) { | |
851 root_ = FakePictureLayer::Create(&client_); | |
852 child_ = FakePictureLayer::Create(&client_); | |
853 grandchild_ = FakePictureLayer::Create(&client_); | |
854 } else { | |
855 root_ = FakeContentLayer::Create(&client_); | |
856 child_ = FakeContentLayer::Create(&client_); | |
857 grandchild_ = FakeContentLayer::Create(&client_); | |
858 } | |
859 | |
860 root_->AddChild(child_); | |
861 child_->AddChild(grandchild_); | |
862 | |
863 layer_tree_host()->SetRootLayer(root_); | |
864 LayerTreeHostContextTest::SetupTree(); | |
865 } | |
866 | |
867 void BeginTest() override { PostSetNeedsCommitToMainThread(); } | |
868 | |
869 void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | |
870 LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl); | |
871 | |
872 FakePictureLayerImpl* root_picture = NULL; | |
873 FakePictureLayerImpl* child_picture = NULL; | |
874 FakePictureLayerImpl* grandchild_picture = NULL; | |
875 FakeContentLayerImpl* root_content = NULL; | |
876 FakeContentLayerImpl* child_content = NULL; | |
877 FakeContentLayerImpl* grandchild_content = NULL; | |
878 | |
879 if (host_impl->settings().impl_side_painting) { | |
880 root_picture = static_cast<FakePictureLayerImpl*>( | |
881 host_impl->active_tree()->root_layer()); | |
882 child_picture = | |
883 static_cast<FakePictureLayerImpl*>(root_picture->children()[0]); | |
884 grandchild_picture = | |
885 static_cast<FakePictureLayerImpl*>(child_picture->children()[0]); | |
886 | |
887 } else { | |
888 root_content = static_cast<FakeContentLayerImpl*>( | |
889 host_impl->active_tree()->root_layer()); | |
890 child_content = | |
891 static_cast<FakeContentLayerImpl*>(root_content->children()[0]); | |
892 grandchild_content = | |
893 static_cast<FakeContentLayerImpl*>(child_content->children()[0]); | |
894 } | |
895 | |
896 ++num_commits_; | |
897 switch (num_commits_) { | |
898 case 1: | |
899 if (host_impl->settings().impl_side_painting) { | |
900 EXPECT_EQ(0u, root_picture->release_resources_count()); | |
901 EXPECT_EQ(0u, child_picture->release_resources_count()); | |
902 EXPECT_EQ(0u, grandchild_picture->release_resources_count()); | |
903 } else { | |
904 EXPECT_EQ(0u, root_content->lost_output_surface_count()); | |
905 EXPECT_EQ(0u, child_content->lost_output_surface_count()); | |
906 EXPECT_EQ(0u, grandchild_content->lost_output_surface_count()); | |
907 } | |
908 | |
909 // Lose the context and struggle to recreate it. | |
910 LoseContext(); | |
911 times_to_fail_create_ = 1; | |
912 break; | |
913 case 2: | |
914 if (host_impl->settings().impl_side_painting) { | |
915 EXPECT_TRUE(root_picture->release_resources_count()); | |
916 EXPECT_TRUE(child_picture->release_resources_count()); | |
917 EXPECT_TRUE(grandchild_picture->release_resources_count()); | |
918 } else { | |
919 EXPECT_TRUE(root_content->lost_output_surface_count()); | |
920 EXPECT_TRUE(child_content->lost_output_surface_count()); | |
921 EXPECT_TRUE(grandchild_content->lost_output_surface_count()); | |
922 } | |
923 | |
924 EndTest(); | |
925 break; | |
926 default: | |
927 NOTREACHED(); | |
928 } | |
929 } | |
930 | |
931 void AfterTest() override {} | |
932 | |
933 private: | |
934 int num_commits_; | |
935 | |
936 FakeContentLayerClient client_; | |
937 scoped_refptr<Layer> root_; | |
938 scoped_refptr<Layer> child_; | |
939 scoped_refptr<Layer> grandchild_; | |
940 }; | |
941 | |
942 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified); | |
943 | |
944 class LayerTreeHostContextTestDontUseLostResources | |
945 : public LayerTreeHostContextTest { | |
946 public: | |
947 LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) { | |
948 context_should_support_io_surface_ = true; | |
949 | |
950 child_output_surface_ = FakeOutputSurface::Create3d(); | |
951 child_output_surface_->BindToClient(&output_surface_client_); | |
952 shared_bitmap_manager_.reset(new TestSharedBitmapManager()); | |
953 child_resource_provider_ = | |
954 ResourceProvider::Create(child_output_surface_.get(), | |
955 shared_bitmap_manager_.get(), | |
956 NULL, | |
957 NULL, | |
958 0, | |
959 false, | |
960 1); | |
961 } | |
962 | |
963 static void EmptyReleaseCallback(unsigned sync_point, bool lost) {} | |
964 | |
965 void SetupTree() override { | |
966 gpu::gles2::GLES2Interface* gl = | |
967 child_output_surface_->context_provider()->ContextGL(); | |
968 | |
969 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); | |
970 | |
971 scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create(); | |
972 pass_for_quad->SetNew( | |
973 // AppendOneOfEveryQuadType() makes a RenderPass quad with this id. | |
974 RenderPassId(2, 1), | |
975 gfx::Rect(0, 0, 10, 10), | |
976 gfx::Rect(0, 0, 10, 10), | |
977 gfx::Transform()); | |
978 | |
979 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); | |
980 pass->SetNew(RenderPassId(1, 1), | |
981 gfx::Rect(0, 0, 10, 10), | |
982 gfx::Rect(0, 0, 10, 10), | |
983 gfx::Transform()); | |
984 pass->AppendOneOfEveryQuadType(child_resource_provider_.get(), | |
985 RenderPassId(2, 1)); | |
986 | |
987 frame_data->render_pass_list.push_back(pass_for_quad.Pass()); | |
988 frame_data->render_pass_list.push_back(pass.Pass()); | |
989 | |
990 delegated_resource_collection_ = new DelegatedFrameResourceCollection; | |
991 delegated_frame_provider_ = new DelegatedFrameProvider( | |
992 delegated_resource_collection_.get(), frame_data.Pass()); | |
993 | |
994 ResourceProvider::ResourceId resource = | |
995 child_resource_provider_->CreateResource( | |
996 gfx::Size(4, 4), GL_CLAMP_TO_EDGE, | |
997 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888); | |
998 ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(), | |
999 resource); | |
1000 | |
1001 gpu::Mailbox mailbox; | |
1002 gl->GenMailboxCHROMIUM(mailbox.name); | |
1003 GLuint sync_point = gl->InsertSyncPointCHROMIUM(); | |
1004 | |
1005 scoped_refptr<Layer> root = Layer::Create(); | |
1006 root->SetBounds(gfx::Size(10, 10)); | |
1007 root->SetIsDrawable(true); | |
1008 | |
1009 scoped_refptr<FakeDelegatedRendererLayer> delegated = | |
1010 FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get()); | |
1011 delegated->SetBounds(gfx::Size(10, 10)); | |
1012 delegated->SetIsDrawable(true); | |
1013 root->AddChild(delegated); | |
1014 | |
1015 scoped_refptr<Layer> layer; | |
1016 if (layer_tree_host()->settings().impl_side_painting) | |
1017 layer = PictureLayer::Create(&client_); | |
1018 else | |
1019 layer = ContentLayer::Create(&client_); | |
1020 layer->SetBounds(gfx::Size(10, 10)); | |
1021 layer->SetIsDrawable(true); | |
1022 root->AddChild(layer); | |
1023 | |
1024 scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL); | |
1025 texture->SetBounds(gfx::Size(10, 10)); | |
1026 texture->SetIsDrawable(true); | |
1027 texture->SetTextureMailbox( | |
1028 TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point), | |
1029 SingleReleaseCallback::Create( | |
1030 base::Bind(&LayerTreeHostContextTestDontUseLostResources:: | |
1031 EmptyReleaseCallback))); | |
1032 root->AddChild(texture); | |
1033 | |
1034 scoped_refptr<Layer> mask; | |
1035 if (layer_tree_host()->settings().impl_side_painting) | |
1036 mask = PictureLayer::Create(&client_); | |
1037 else | |
1038 mask = ContentLayer::Create(&client_); | |
1039 mask->SetBounds(gfx::Size(10, 10)); | |
1040 | |
1041 scoped_refptr<Layer> layer_with_mask; | |
1042 if (layer_tree_host()->settings().impl_side_painting) | |
1043 layer_with_mask = PictureLayer::Create(&client_); | |
1044 else | |
1045 layer_with_mask = ContentLayer::Create(&client_); | |
1046 layer_with_mask->SetBounds(gfx::Size(10, 10)); | |
1047 layer_with_mask->SetIsDrawable(true); | |
1048 layer_with_mask->SetMaskLayer(mask.get()); | |
1049 root->AddChild(layer_with_mask); | |
1050 | |
1051 if (!delegating_renderer()) { | |
1052 // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335 | |
1053 scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create(); | |
1054 io_surface->SetBounds(gfx::Size(10, 10)); | |
1055 io_surface->SetIsDrawable(true); | |
1056 io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10)); | |
1057 root->AddChild(io_surface); | |
1058 } | |
1059 | |
1060 // Enable the hud. | |
1061 LayerTreeDebugState debug_state; | |
1062 debug_state.show_property_changed_rects = true; | |
1063 layer_tree_host()->SetDebugState(debug_state); | |
1064 | |
1065 scoped_refptr<PaintedScrollbarLayer> scrollbar = | |
1066 PaintedScrollbarLayer::Create( | |
1067 scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), layer->id()); | |
1068 scrollbar->SetBounds(gfx::Size(10, 10)); | |
1069 scrollbar->SetIsDrawable(true); | |
1070 root->AddChild(scrollbar); | |
1071 | |
1072 layer_tree_host()->SetRootLayer(root); | |
1073 LayerTreeHostContextTest::SetupTree(); | |
1074 } | |
1075 | |
1076 void BeginTest() override { PostSetNeedsCommitToMainThread(); } | |
1077 | |
1078 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | |
1079 LayerTreeHostContextTest::CommitCompleteOnThread(host_impl); | |
1080 } | |
1081 | |
1082 DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | |
1083 LayerTreeHostImpl::FrameData* frame, | |
1084 DrawResult draw_result) override { | |
1085 if (host_impl->active_tree()->source_frame_number() == 2) { | |
1086 // Lose the context during draw on the second commit. This will cause | |
1087 // a third commit to recover. | |
1088 context3d_->set_times_bind_texture_succeeds(0); | |
1089 } | |
1090 return draw_result; | |
1091 } | |
1092 | |
1093 scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override { | |
1094 // This will get called twice: | |
1095 // First when we create the initial output surface... | |
1096 if (layer_tree_host()->source_frame_number() > 0) { | |
1097 // ... and then again after we forced the context to be lost. | |
1098 lost_context_ = true; | |
1099 } | |
1100 return LayerTreeHostContextTest::CreateFakeOutputSurface(); | |
1101 } | |
1102 | |
1103 void DidCommitAndDrawFrame() override { | |
1104 ASSERT_TRUE(layer_tree_host()->hud_layer()); | |
1105 // End the test once we know the 3nd frame drew. | |
1106 if (layer_tree_host()->source_frame_number() < 5) { | |
1107 layer_tree_host()->root_layer()->SetNeedsDisplay(); | |
1108 layer_tree_host()->SetNeedsCommit(); | |
1109 } else { | |
1110 EndTest(); | |
1111 } | |
1112 } | |
1113 | |
1114 void AfterTest() override { EXPECT_TRUE(lost_context_); } | |
1115 | |
1116 private: | |
1117 FakeContentLayerClient client_; | |
1118 bool lost_context_; | |
1119 | |
1120 FakeOutputSurfaceClient output_surface_client_; | |
1121 scoped_ptr<FakeOutputSurface> child_output_surface_; | |
1122 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; | |
1123 scoped_ptr<ResourceProvider> child_resource_provider_; | |
1124 | |
1125 scoped_refptr<DelegatedFrameResourceCollection> | |
1126 delegated_resource_collection_; | |
1127 scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_; | |
1128 }; | |
1129 | |
1130 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources); | |
1131 | |
1132 class ImplSidePaintingLayerTreeHostContextTest | |
1133 : public LayerTreeHostContextTest { | |
1134 public: | |
1135 void InitializeSettings(LayerTreeSettings* settings) override { | |
1136 settings->impl_side_painting = true; | |
1137 } | |
1138 }; | |
1139 | |
1140 class LayerTreeHostContextTestImplSidePainting | |
1141 : public ImplSidePaintingLayerTreeHostContextTest { | |
1142 public: | |
1143 void SetupTree() override { | |
1144 scoped_refptr<Layer> root = Layer::Create(); | |
1145 root->SetBounds(gfx::Size(10, 10)); | |
1146 root->SetIsDrawable(true); | |
1147 | |
1148 scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_); | |
1149 picture->SetBounds(gfx::Size(10, 10)); | |
1150 picture->SetIsDrawable(true); | |
1151 root->AddChild(picture); | |
1152 | |
1153 layer_tree_host()->SetRootLayer(root); | |
1154 LayerTreeHostContextTest::SetupTree(); | |
1155 } | |
1156 | |
1157 void BeginTest() override { | |
1158 times_to_lose_during_commit_ = 1; | |
1159 PostSetNeedsCommitToMainThread(); | |
1160 } | |
1161 | |
1162 void AfterTest() override {} | |
1163 | |
1164 void DidInitializeOutputSurface() override { EndTest(); } | |
1165 | |
1166 private: | |
1167 FakeContentLayerClient client_; | |
1168 }; | |
1169 | |
1170 MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting); | |
1171 | |
1172 class ScrollbarLayerLostContext : public LayerTreeHostContextTest { | |
1173 public: | |
1174 ScrollbarLayerLostContext() : commits_(0) {} | |
1175 | |
1176 void BeginTest() override { | |
1177 scoped_refptr<Layer> scroll_layer = Layer::Create(); | |
1178 scrollbar_layer_ = | |
1179 FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id()); | |
1180 scrollbar_layer_->SetBounds(gfx::Size(10, 100)); | |
1181 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_); | |
1182 layer_tree_host()->root_layer()->AddChild(scroll_layer); | |
1183 PostSetNeedsCommitToMainThread(); | |
1184 } | |
1185 | |
1186 void AfterTest() override {} | |
1187 | |
1188 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | |
1189 LayerTreeHostContextTest::CommitCompleteOnThread(impl); | |
1190 | |
1191 ++commits_; | |
1192 switch (commits_) { | |
1193 case 1: | |
1194 // First (regular) update, we should upload 2 resources (thumb, and | |
1195 // backtrack). | |
1196 EXPECT_EQ(1, scrollbar_layer_->update_count()); | |
1197 LoseContext(); | |
1198 break; | |
1199 case 2: | |
1200 // Second update, after the lost context, we should still upload 2 | |
1201 // resources even if the contents haven't changed. | |
1202 EXPECT_EQ(2, scrollbar_layer_->update_count()); | |
1203 EndTest(); | |
1204 break; | |
1205 default: | |
1206 NOTREACHED(); | |
1207 } | |
1208 } | |
1209 | |
1210 private: | |
1211 int commits_; | |
1212 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_; | |
1213 }; | |
1214 | |
1215 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext); | |
1216 | |
1217 class UIResourceLostTest : public LayerTreeHostContextTest { | |
1218 public: | |
1219 UIResourceLostTest() : time_step_(0) {} | |
1220 void InitializeSettings(LayerTreeSettings* settings) override { | |
1221 settings->renderer_settings.texture_id_allocation_chunk_size = 1; | |
1222 } | |
1223 void BeginTest() override { PostSetNeedsCommitToMainThread(); } | |
1224 void AfterTest() override {} | |
1225 | |
1226 // This is called on the main thread after each commit and | |
1227 // DidActivateTreeOnThread, with the value of time_step_ at the time | |
1228 // of the call to DidActivateTreeOnThread. Similar tests will do | |
1229 // work on the main thread in DidCommit but that is unsuitable because | |
1230 // the main thread work for these tests must happen after | |
1231 // DidActivateTreeOnThread, which happens after DidCommit with impl-side | |
1232 // painting. | |
1233 virtual void StepCompleteOnMainThread(int time_step) = 0; | |
1234 | |
1235 // Called after DidActivateTreeOnThread. If this is done during the commit, | |
1236 // the call to StepCompleteOnMainThread will not occur until after | |
1237 // the commit completes, because the main thread is blocked. | |
1238 void PostStepCompleteToMainThread() { | |
1239 proxy()->MainThreadTaskRunner()->PostTask( | |
1240 FROM_HERE, | |
1241 base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal, | |
1242 base::Unretained(this), | |
1243 time_step_)); | |
1244 } | |
1245 | |
1246 void PostLoseContextToImplThread() { | |
1247 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); | |
1248 ImplThreadTaskRunner()->PostTask( | |
1249 FROM_HERE, | |
1250 base::Bind(&LayerTreeHostContextTest::LoseContext, | |
1251 base::Unretained(this))); | |
1252 } | |
1253 | |
1254 protected: | |
1255 int time_step_; | |
1256 scoped_ptr<FakeScopedUIResource> ui_resource_; | |
1257 | |
1258 private: | |
1259 void StepCompleteOnMainThreadInternal(int step) { | |
1260 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); | |
1261 StepCompleteOnMainThread(step); | |
1262 } | |
1263 }; | |
1264 | |
1265 class UIResourceLostTestSimple : public UIResourceLostTest { | |
1266 public: | |
1267 // This is called when the commit is complete and the new layer tree has been | |
1268 // activated. | |
1269 virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0; | |
1270 | |
1271 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | |
1272 if (!impl->settings().impl_side_painting) { | |
1273 StepCompleteOnImplThread(impl); | |
1274 PostStepCompleteToMainThread(); | |
1275 ++time_step_; | |
1276 } | |
1277 } | |
1278 | |
1279 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | |
1280 if (impl->settings().impl_side_painting) { | |
1281 StepCompleteOnImplThread(impl); | |
1282 PostStepCompleteToMainThread(); | |
1283 ++time_step_; | |
1284 } | |
1285 } | |
1286 }; | |
1287 | |
1288 // Losing context after an UI resource has been created. | |
1289 class UIResourceLostAfterCommit : public UIResourceLostTestSimple { | |
1290 public: | |
1291 void StepCompleteOnMainThread(int step) override { | |
1292 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); | |
1293 switch (step) { | |
1294 case 0: | |
1295 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host()); | |
1296 // Expects a valid UIResourceId. | |
1297 EXPECT_NE(0, ui_resource_->id()); | |
1298 PostSetNeedsCommitToMainThread(); | |
1299 break; | |
1300 case 4: | |
1301 // Release resource before ending the test. | |
1302 ui_resource_ = nullptr; | |
1303 EndTest(); | |
1304 break; | |
1305 case 5: | |
1306 NOTREACHED(); | |
1307 break; | |
1308 } | |
1309 } | |
1310 | |
1311 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override { | |
1312 LayerTreeHostContextTest::CommitCompleteOnThread(impl); | |
1313 switch (time_step_) { | |
1314 case 1: | |
1315 // The resource should have been created on LTHI after the commit. | |
1316 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id())); | |
1317 PostSetNeedsCommitToMainThread(); | |
1318 break; | |
1319 case 2: | |
1320 LoseContext(); | |
1321 break; | |
1322 case 3: | |
1323 // The resources should have been recreated. The bitmap callback should | |
1324 // have been called once with the resource_lost flag set to true. | |
1325 EXPECT_EQ(1, ui_resource_->lost_resource_count); | |
1326 // Resource Id on the impl-side have been recreated as well. Note | |
1327 // that the same UIResourceId persists after the context lost. | |
1328 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id())); | |
1329 PostSetNeedsCommitToMainThread(); | |
1330 break; | |
1331 } | |
1332 } | |
1333 }; | |
1334 | |
1335 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit); | |
1336 | |
1337 // Losing context before UI resource requests can be commited. Three sequences | |
1338 // of creation/deletion are considered: | |
1339 // 1. Create one resource -> Context Lost => Expect the resource to have been | |
1340 // created. | |
1341 // 2. Delete an exisiting resource (test_id0_) -> create a second resource | |
1342 // (test_id1_) -> Context Lost => Expect the test_id0_ to be removed and | |
1343 // test_id1_ to have been created. | |
1344 // 3. Create one resource -> Delete that same resource -> Context Lost => Expect | |
1345 // the resource to not exist in the manager. | |
1346 class UIResourceLostBeforeCommit : public UIResourceLostTestSimple { | |
1347 public: | |
1348 UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {} | |
1349 | |
1350 void StepCompleteOnMainThread(int step) override { | |
1351 switch (step) { | |
1352 case 0: | |
1353 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host()); | |
1354 // Lose the context on the impl thread before the commit. | |
1355 PostLoseContextToImplThread(); | |
1356 break; | |
1357 case 2: | |
1358 // Sequence 2: | |
1359 // Currently one resource has been created. | |
1360 test_id0_ = ui_resource_->id(); | |
1361 // Delete this resource. | |
1362 ui_resource_ = nullptr; | |
1363 // Create another resource. | |
1364 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host()); | |
1365 test_id1_ = ui_resource_->id(); | |
1366 // Sanity check that two resource creations return different ids. | |
1367 EXPECT_NE(test_id0_, test_id1_); | |
1368 // Lose the context on the impl thread before the commit. | |
1369 PostLoseContextToImplThread(); | |
1370 break; | |
1371 case 3: | |
1372 // Clear the manager of resources. | |
1373 ui_resource_ = nullptr; | |
1374 PostSetNeedsCommitToMainThread(); | |
1375 break; | |
1376 case 4: | |
1377 // Sequence 3: | |
1378 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host()); | |
1379 test_id0_ = ui_resource_->id(); | |
1380 // Sanity check the UIResourceId should not be 0. | |
1381 EXPECT_NE(0, test_id0_); | |
1382 // Usually ScopedUIResource are deleted from the manager in their | |
1383 // destructor (so usually ui_resource_ = nullptr). But here we need | |
1384 // ui_resource_ for the next step, so call DeleteUIResource directly. | |
1385 layer_tree_host()->DeleteUIResource(test_id0_); | |
1386 // Delete the resouce and then lose the context. | |
1387 PostLoseContextToImplThread(); | |
1388 break; | |
1389 case 5: | |
1390 // Release resource before ending the test. | |
1391 ui_resource_ = nullptr; | |
1392 EndTest(); | |
1393 break; | |
1394 case 6: | |
1395 NOTREACHED(); | |
1396 break; | |
1397 } | |
1398 } | |
1399 | |
1400 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override { | |
1401 LayerTreeHostContextTest::CommitCompleteOnThread(impl); | |
1402 switch (time_step_) { | |
1403 case 1: | |
1404 // Sequence 1 (continued): | |
1405 // The first context lost happens before the resources were created, | |
1406 // and because it resulted in no resources being destroyed, it does not | |
1407 // trigger resource re-creation. | |
1408 EXPECT_EQ(1, ui_resource_->resource_create_count); | |
1409 EXPECT_EQ(0, ui_resource_->lost_resource_count); | |
1410 // Resource Id on the impl-side has been created. | |
1411 PostSetNeedsCommitToMainThread(); | |
1412 break; | |
1413 case 3: | |
1414 // Sequence 2 (continued): | |
1415 // The previous resource should have been deleted. | |
1416 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_)); | |
1417 // The second resource should have been created. | |
1418 EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_)); | |
1419 // The second resource called the resource callback once and since the | |
1420 // context is lost, a "resource lost" callback was also issued. | |
1421 EXPECT_EQ(2, ui_resource_->resource_create_count); | |
1422 EXPECT_EQ(1, ui_resource_->lost_resource_count); | |
1423 break; | |
1424 case 5: | |
1425 // Sequence 3 (continued): | |
1426 // Expect the resource callback to have been called once. | |
1427 EXPECT_EQ(1, ui_resource_->resource_create_count); | |
1428 // No "resource lost" callbacks. | |
1429 EXPECT_EQ(0, ui_resource_->lost_resource_count); | |
1430 // The UI resource id should not be valid | |
1431 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_)); | |
1432 break; | |
1433 } | |
1434 } | |
1435 | |
1436 private: | |
1437 UIResourceId test_id0_; | |
1438 UIResourceId test_id1_; | |
1439 }; | |
1440 | |
1441 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostBeforeCommit); | |
1442 | |
1443 // Losing UI resource before the pending trees is activated but after the | |
1444 // commit. Impl-side-painting only. | |
1445 class UIResourceLostBeforeActivateTree : public UIResourceLostTest { | |
1446 void StepCompleteOnMainThread(int step) override { | |
1447 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); | |
1448 switch (step) { | |
1449 case 0: | |
1450 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host()); | |
1451 PostSetNeedsCommitToMainThread(); | |
1452 break; | |
1453 case 3: | |
1454 test_id_ = ui_resource_->id(); | |
1455 ui_resource_ = nullptr; | |
1456 PostSetNeedsCommitToMainThread(); | |
1457 break; | |
1458 case 5: | |
1459 // Release resource before ending the test. | |
1460 ui_resource_ = nullptr; | |
1461 EndTest(); | |
1462 break; | |
1463 case 6: | |
1464 // Make sure no extra commits happened. | |
1465 NOTREACHED(); | |
1466 } | |
1467 } | |
1468 | |
1469 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | |
1470 LayerTreeHostContextTest::CommitCompleteOnThread(impl); | |
1471 switch (time_step_) { | |
1472 case 2: | |
1473 PostSetNeedsCommitToMainThread(); | |
1474 break; | |
1475 case 4: | |
1476 PostSetNeedsCommitToMainThread(); | |
1477 break; | |
1478 } | |
1479 } | |
1480 | |
1481 void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override { | |
1482 switch (time_step_) { | |
1483 case 1: | |
1484 // The resource creation callback has been called. | |
1485 EXPECT_EQ(1, ui_resource_->resource_create_count); | |
1486 // The resource is not yet lost (sanity check). | |
1487 EXPECT_EQ(0, ui_resource_->lost_resource_count); | |
1488 // The resource should not have been created yet on the impl-side. | |
1489 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id())); | |
1490 LoseContext(); | |
1491 break; | |
1492 case 3: | |
1493 LoseContext(); | |
1494 break; | |
1495 } | |
1496 } | |
1497 | |
1498 void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | |
1499 LayerTreeHostContextTest::DidActivateTreeOnThread(impl); | |
1500 switch (time_step_) { | |
1501 case 1: | |
1502 // The pending requests on the impl-side should have been processed. | |
1503 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id())); | |
1504 break; | |
1505 case 2: | |
1506 // The "lost resource" callback should have been called once. | |
1507 EXPECT_EQ(1, ui_resource_->lost_resource_count); | |
1508 break; | |
1509 case 4: | |
1510 // The resource is deleted and should not be in the manager. Use | |
1511 // test_id_ since ui_resource_ has been deleted. | |
1512 EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_)); | |
1513 break; | |
1514 } | |
1515 | |
1516 PostStepCompleteToMainThread(); | |
1517 ++time_step_; | |
1518 } | |
1519 | |
1520 private: | |
1521 UIResourceId test_id_; | |
1522 }; | |
1523 | |
1524 TEST_F(UIResourceLostBeforeActivateTree, | |
1525 RunMultiThread_DirectRenderer_ImplSidePaint) { | |
1526 RunTest(true, false, true); | |
1527 } | |
1528 | |
1529 TEST_F(UIResourceLostBeforeActivateTree, | |
1530 RunMultiThread_DelegatingRenderer_ImplSidePaint) { | |
1531 RunTest(true, true, true); | |
1532 } | |
1533 | |
1534 // Resources evicted explicitly and by visibility changes. | |
1535 class UIResourceLostEviction : public UIResourceLostTestSimple { | |
1536 public: | |
1537 void StepCompleteOnMainThread(int step) override { | |
1538 EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); | |
1539 switch (step) { | |
1540 case 0: | |
1541 ui_resource_ = FakeScopedUIResource::Create(layer_tree_host()); | |
1542 EXPECT_NE(0, ui_resource_->id()); | |
1543 PostSetNeedsCommitToMainThread(); | |
1544 break; | |
1545 case 2: | |
1546 // Make the tree not visible. | |
1547 PostSetVisibleToMainThread(false); | |
1548 break; | |
1549 case 3: | |
1550 // Release resource before ending the test. | |
1551 ui_resource_ = nullptr; | |
1552 EndTest(); | |
1553 break; | |
1554 case 4: | |
1555 NOTREACHED(); | |
1556 } | |
1557 } | |
1558 | |
1559 void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, bool visible) override { | |
1560 TestWebGraphicsContext3D* context = TestContext(); | |
1561 if (!visible) { | |
1562 // All resources should have been evicted. | |
1563 ASSERT_EQ(0u, context->NumTextures()); | |
1564 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id())); | |
1565 EXPECT_EQ(2, ui_resource_->resource_create_count); | |
1566 EXPECT_EQ(1, ui_resource_->lost_resource_count); | |
1567 // Drawing is disabled both because of the evicted resources and | |
1568 // because the renderer is not visible. | |
1569 EXPECT_FALSE(impl->CanDraw()); | |
1570 // Make the renderer visible again. | |
1571 PostSetVisibleToMainThread(true); | |
1572 } | |
1573 } | |
1574 | |
1575 void StepCompleteOnImplThread(LayerTreeHostImpl* impl) override { | |
1576 TestWebGraphicsContext3D* context = TestContext(); | |
1577 LayerTreeHostContextTest::CommitCompleteOnThread(impl); | |
1578 switch (time_step_) { | |
1579 case 1: | |
1580 // The resource should have been created on LTHI after the commit. | |
1581 ASSERT_EQ(1u, context->NumTextures()); | |
1582 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id())); | |
1583 EXPECT_EQ(1, ui_resource_->resource_create_count); | |
1584 EXPECT_EQ(0, ui_resource_->lost_resource_count); | |
1585 EXPECT_TRUE(impl->CanDraw()); | |
1586 // Evict all UI resources. This will trigger a commit. | |
1587 impl->EvictAllUIResources(); | |
1588 ASSERT_EQ(0u, context->NumTextures()); | |
1589 EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id())); | |
1590 EXPECT_EQ(1, ui_resource_->resource_create_count); | |
1591 EXPECT_EQ(0, ui_resource_->lost_resource_count); | |
1592 EXPECT_FALSE(impl->CanDraw()); | |
1593 break; | |
1594 case 2: | |
1595 // The resource should have been recreated. | |
1596 ASSERT_EQ(1u, context->NumTextures()); | |
1597 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id())); | |
1598 EXPECT_EQ(2, ui_resource_->resource_create_count); | |
1599 EXPECT_EQ(1, ui_resource_->lost_resource_count); | |
1600 EXPECT_TRUE(impl->CanDraw()); | |
1601 break; | |
1602 case 3: | |
1603 // The resource should have been recreated after visibility was | |
1604 // restored. | |
1605 ASSERT_EQ(1u, context->NumTextures()); | |
1606 EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id())); | |
1607 EXPECT_EQ(3, ui_resource_->resource_create_count); | |
1608 EXPECT_EQ(2, ui_resource_->lost_resource_count); | |
1609 EXPECT_TRUE(impl->CanDraw()); | |
1610 break; | |
1611 } | |
1612 } | |
1613 }; | |
1614 | |
1615 SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction); | |
1616 | |
1617 class LayerTreeHostContextTestSurfaceCreateCallback | |
1618 : public LayerTreeHostContextTest { | |
1619 public: | |
1620 LayerTreeHostContextTestSurfaceCreateCallback() | |
1621 : LayerTreeHostContextTest() {} | |
1622 | |
1623 void SetupTree() override { | |
1624 if (layer_tree_host()->settings().impl_side_painting) { | |
1625 picture_layer_ = FakePictureLayer::Create(&client_); | |
1626 picture_layer_->SetBounds(gfx::Size(10, 20)); | |
1627 layer_tree_host()->SetRootLayer(picture_layer_); | |
1628 } else { | |
1629 content_layer_ = FakeContentLayer::Create(&client_); | |
1630 content_layer_->SetBounds(gfx::Size(10, 20)); | |
1631 layer_tree_host()->SetRootLayer(content_layer_); | |
1632 } | |
1633 | |
1634 LayerTreeHostContextTest::SetupTree(); | |
1635 } | |
1636 | |
1637 void BeginTest() override { PostSetNeedsCommitToMainThread(); } | |
1638 | |
1639 void DidCommit() override { | |
1640 switch (layer_tree_host()->source_frame_number()) { | |
1641 case 1: | |
1642 if (layer_tree_host()->settings().impl_side_painting) | |
1643 EXPECT_EQ(1u, picture_layer_->output_surface_created_count()); | |
1644 else | |
1645 EXPECT_EQ(1u, content_layer_->output_surface_created_count()); | |
1646 layer_tree_host()->SetNeedsCommit(); | |
1647 break; | |
1648 case 2: | |
1649 if (layer_tree_host()->settings().impl_side_painting) | |
1650 EXPECT_EQ(1u, picture_layer_->output_surface_created_count()); | |
1651 else | |
1652 EXPECT_EQ(1u, content_layer_->output_surface_created_count()); | |
1653 layer_tree_host()->SetNeedsCommit(); | |
1654 break; | |
1655 case 3: | |
1656 if (layer_tree_host()->settings().impl_side_painting) | |
1657 EXPECT_EQ(1u, picture_layer_->output_surface_created_count()); | |
1658 else | |
1659 EXPECT_EQ(1u, content_layer_->output_surface_created_count()); | |
1660 break; | |
1661 case 4: | |
1662 if (layer_tree_host()->settings().impl_side_painting) | |
1663 EXPECT_EQ(2u, picture_layer_->output_surface_created_count()); | |
1664 else | |
1665 EXPECT_EQ(2u, content_layer_->output_surface_created_count()); | |
1666 layer_tree_host()->SetNeedsCommit(); | |
1667 break; | |
1668 } | |
1669 } | |
1670 | |
1671 void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | |
1672 LayerTreeHostContextTest::CommitCompleteOnThread(impl); | |
1673 switch (LastCommittedSourceFrameNumber(impl)) { | |
1674 case 0: | |
1675 break; | |
1676 case 1: | |
1677 break; | |
1678 case 2: | |
1679 LoseContext(); | |
1680 break; | |
1681 case 3: | |
1682 EndTest(); | |
1683 break; | |
1684 } | |
1685 } | |
1686 | |
1687 void AfterTest() override {} | |
1688 | |
1689 protected: | |
1690 FakeContentLayerClient client_; | |
1691 scoped_refptr<FakePictureLayer> picture_layer_; | |
1692 scoped_refptr<FakeContentLayer> content_layer_; | |
1693 }; | |
1694 | |
1695 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback); | |
1696 | |
1697 class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame | |
1698 : public LayerTreeHostContextTest { | |
1699 protected: | |
1700 void BeginTest() override { | |
1701 deferred_ = false; | |
1702 PostSetNeedsCommitToMainThread(); | |
1703 } | |
1704 | |
1705 void ScheduledActionWillSendBeginMainFrame() override { | |
1706 if (deferred_) | |
1707 return; | |
1708 deferred_ = true; | |
1709 | |
1710 // Defer commits before the BeginFrame arrives, causing it to be delayed. | |
1711 PostSetDeferCommitsToMainThread(true); | |
1712 // Meanwhile, lose the context while we are in defer commits. | |
1713 ImplThreadTaskRunner()->PostTask( | |
1714 FROM_HERE, | |
1715 base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame:: | |
1716 LoseContextOnImplThread, | |
1717 base::Unretained(this))); | |
1718 } | |
1719 | |
1720 void LoseContextOnImplThread() { | |
1721 LoseContext(); | |
1722 | |
1723 // After losing the context, stop deferring commits. | |
1724 PostSetDeferCommitsToMainThread(false); | |
1725 } | |
1726 | |
1727 void WillBeginMainFrame() override { | |
1728 // Don't begin a frame with a lost surface. | |
1729 EXPECT_FALSE(layer_tree_host()->output_surface_lost()); | |
1730 } | |
1731 | |
1732 void DidCommitAndDrawFrame() override { EndTest(); } | |
1733 | |
1734 void AfterTest() override {} | |
1735 | |
1736 bool deferred_; | |
1737 }; | |
1738 | |
1739 SINGLE_AND_MULTI_THREAD_TEST_F( | |
1740 LayerTreeHostContextTestLoseAfterSendingBeginMainFrame); | |
1741 | |
1742 } // namespace | |
1743 } // namespace cc | |
OLD | NEW |