1 // Copyright 2017 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 "components/viz/service/gl/gpu_service_impl.h"
6 
7 #include <memory>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/macros.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/run_loop.h"
15 #include "base/single_thread_task_runner.h"
16 #include "gpu/config/gpu_info.h"
17 #include "gpu/ipc/service/display_context.h"
18 #include "gpu/ipc/service/gpu_watchdog_thread.h"
19 #include "mojo/public/cpp/bindings/pending_remote.h"
20 #include "mojo/public/cpp/bindings/remote.h"
21 #include "services/viz/public/mojom/gpu.mojom.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "ui/gl/init/gl_factory.h"
25 
26 namespace viz {
27 namespace {
28 
29 class MockDisplayContext : public gpu::DisplayContext {
30  public:
31   MockDisplayContext() = default;
32   ~MockDisplayContext() override = default;
33 
34   // gpu::DisplayContext implementation.
35   MOCK_METHOD0(MarkContextLost, void());
36 };
37 
38 }  // namespace
39 
40 class GpuServiceTest : public testing::Test {
41  public:
GpuServiceTest()42   GpuServiceTest()
43       : io_thread_("TestIOThread"),
44         wait_(base::WaitableEvent::ResetPolicy::MANUAL,
45               base::WaitableEvent::InitialState::NOT_SIGNALED) {}
~GpuServiceTest()46   ~GpuServiceTest() override {}
47 
gpu_service()48   GpuServiceImpl* gpu_service() { return gpu_service_.get(); }
49 
DestroyService()50   void DestroyService() { gpu_service_ = nullptr; }
51 
BlockIOThread()52   void BlockIOThread() {
53     wait_.Reset();
54     io_runner()->PostTask(FROM_HERE, base::BindOnce(&base::WaitableEvent::Wait,
55                                                     base::Unretained(&wait_)));
56   }
57 
UnblockIOThread()58   void UnblockIOThread() {
59     DCHECK(!wait_.IsSignaled());
60     wait_.Signal();
61   }
62 
io_runner()63   scoped_refptr<base::SingleThreadTaskRunner> io_runner() {
64     return io_thread_.task_runner();
65   }
66 
67   // testing::Test
SetUp()68   void SetUp() override {
69     ASSERT_TRUE(io_thread_.Start());
70     gpu::GPUInfo gpu_info;
71     gpu_info.in_process_gpu = false;
72     gpu_service_ = std::make_unique<GpuServiceImpl>(
73         gpu_info, /*watchdog_thread=*/nullptr, io_thread_.task_runner(),
74         gpu::GpuFeatureInfo(), gpu::GpuPreferences(), gpu::GPUInfo(),
75         gpu::GpuFeatureInfo(), gpu::GpuExtraInfo(),
76         /*device_perf_info=*/base::nullopt,
77         /*vulkan_implementation=*/nullptr,
78         /*exit_callback=*/base::DoNothing());
79   }
80 
TearDown()81   void TearDown() override {
82     DestroyService();
83     base::RunLoop runloop;
84     runloop.RunUntilIdle();
85     io_thread_.Stop();
86   }
87 
88  private:
89   base::Thread io_thread_;
90   std::unique_ptr<GpuServiceImpl> gpu_service_;
91   base::WaitableEvent wait_;
92 
93   DISALLOW_COPY_AND_ASSIGN(GpuServiceTest);
94 };
95 
96 // Tests that GpuServiceImpl can be destroyed before Bind() succeeds on the IO
97 // thread.
TEST_F(GpuServiceTest,ServiceDestroyedBeforeBind)98 TEST_F(GpuServiceTest, ServiceDestroyedBeforeBind) {
99   // Block the IO thread to make sure that the GpuServiceImpl is destroyed
100   // before the binding happens on the IO thread.
101   mojo::Remote<mojom::GpuService> gpu_service_remote;
102   BlockIOThread();
103   gpu_service()->Bind(gpu_service_remote.BindNewPipeAndPassReceiver());
104   UnblockIOThread();
105   DestroyService();
106 }
107 
108 // Tests that GpuServiceImpl can be destroyed after Bind() succeeds on the IO
109 // thread.
TEST_F(GpuServiceTest,ServiceDestroyedAfterBind)110 TEST_F(GpuServiceTest, ServiceDestroyedAfterBind) {
111   mojo::Remote<mojom::GpuService> gpu_service_remote;
112   gpu_service()->Bind(gpu_service_remote.BindNewPipeAndPassReceiver());
113   base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
114                            base::WaitableEvent::InitialState::NOT_SIGNALED);
115   io_runner()->PostTask(FROM_HERE, base::BindOnce(&base::WaitableEvent::Signal,
116                                                   base::Unretained(&wait)));
117   wait.Wait();
118   DestroyService();
119 }
120 
TEST_F(GpuServiceTest,LoseAllContexts)121 TEST_F(GpuServiceTest, LoseAllContexts) {
122   mojo::Remote<mojom::GpuService> gpu_service_remote;
123   gpu_service()->Bind(gpu_service_remote.BindNewPipeAndPassReceiver());
124 
125   // Use a disconnected mojo remote for GpuHost, we don't need to receive any
126   // messages.
127   mojo::PendingRemote<mojom::GpuHost> gpu_host_proxy;
128   ignore_result(gpu_host_proxy.InitWithNewPipeAndPassReceiver());
129   gpu_service()->InitializeWithHost(
130       std::move(gpu_host_proxy), gpu::GpuProcessActivityFlags(),
131       gl::init::CreateOffscreenGLSurface(gfx::Size()),
132       /*sync_point_manager=*/nullptr, /*shared_image_manager=*/nullptr,
133       /*shutdown_event=*/nullptr);
134   gpu_service_remote.FlushForTesting();
135 
136   MockDisplayContext display_context;
137   gpu_service()->RegisterDisplayContext(&display_context);
138 
139   // Verify that |display_context| is told to lose it's context.
140   EXPECT_CALL(display_context, MarkContextLost());
141   gpu_service()->LoseAllContexts();
142   testing::Mock::VerifyAndClearExpectations(&display_context);
143 
144   gpu_service()->MaybeExitOnContextLost();
145   EXPECT_TRUE(gpu_service()->IsExiting());
146 
147   // Verify that if GPU process is already exiting then |display_context| won't
148   // be told to lose it's context.
149   EXPECT_CALL(display_context, MarkContextLost()).Times(0);
150   gpu_service()->LoseAllContexts();
151   testing::Mock::VerifyAndClearExpectations(&display_context);
152 
153   gpu_service()->UnregisterDisplayContext(&display_context);
154 }
155 
156 }  // namespace viz
157