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