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