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