1 // Copyright 2019 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 "ui/ozone/platform/drm/gpu/drm_thread.h"
6
7 #include <utility>
8
9 #include "base/callback_helpers.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/test/task_environment.h"
12 #include "mojo/public/cpp/bindings/remote.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "ui/gfx/linux/test/mock_gbm_device.h"
15 #include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
16 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
17
18 namespace ui {
19
20 namespace {
21
22 class FakeDrmDeviceGenerator : public DrmDeviceGenerator {
23 // DrmDeviceGenerator:
CreateDevice(const base::FilePath & path,base::File file,bool is_primary_device)24 scoped_refptr<DrmDevice> CreateDevice(const base::FilePath& path,
25 base::File file,
26 bool is_primary_device) override {
27 auto gbm_device = std::make_unique<MockGbmDevice>();
28 return base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device));
29 }
30 };
31
StubTask()32 void StubTask() {}
33
StubTaskWithDoneFeedback(bool * done)34 void StubTaskWithDoneFeedback(bool* done) {
35 *done = true;
36 }
37
38 } // namespace
39
40 class DrmThreadTest : public testing::Test {
41 protected:
42 // Overridden from testing::Test
SetUp()43 void SetUp() override {
44 drm_thread_.Start(base::DoNothing(),
45 std::make_unique<FakeDrmDeviceGenerator>());
46 drm_thread_.task_runner()->PostTask(
47 FROM_HERE, base::BindOnce(&DrmThread::AddDrmDeviceReceiver,
48 base::Unretained(&drm_thread_),
49 drm_device_.BindNewPipeAndPassReceiver()));
50 drm_thread_.FlushForTesting();
51 }
52
PostStubTaskWithWaitableEvent()53 std::unique_ptr<base::WaitableEvent> PostStubTaskWithWaitableEvent() {
54 base::OnceClosure task = base::BindOnce(StubTask);
55 auto event = std::make_unique<base::WaitableEvent>(
56 base::WaitableEvent::ResetPolicy::AUTOMATIC,
57 base::WaitableEvent::InitialState::NOT_SIGNALED);
58 drm_thread_.task_runner()->PostTask(
59 FROM_HERE, base::BindOnce(&DrmThread::RunTaskAfterDeviceReady,
60 base::Unretained(&drm_thread_),
61 std::move(task), event.get()));
62 return event;
63 }
64
PostStubTask(bool * done)65 void PostStubTask(bool* done) {
66 *done = false;
67 base::OnceClosure task = base::BindOnce(StubTaskWithDoneFeedback, done);
68 drm_thread_.task_runner()->PostTask(
69 FROM_HERE, base::BindOnce(&DrmThread::RunTaskAfterDeviceReady,
70 base::Unretained(&drm_thread_),
71 std::move(task), nullptr));
72 }
73
AddGraphicsDevice()74 void AddGraphicsDevice() {
75 base::FilePath file_path("/dev/null");
76 base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_WRITE |
77 base::File::FLAG_READ);
78 drm_device_->AddGraphicsDevice(file_path, std::move(file));
79 }
80
81 base::test::TaskEnvironment env_;
82 DrmThread drm_thread_;
83 mojo::Remote<ozone::mojom::DrmDevice> drm_device_;
84 };
85
TEST_F(DrmThreadTest,RunTaskAfterDeviceReady)86 TEST_F(DrmThreadTest, RunTaskAfterDeviceReady) {
87 bool called = false;
88
89 // Post 2 tasks. One with WaitableEvent and one without. They should block on
90 // a graphics device becoming available.
91 std::unique_ptr<base::WaitableEvent> event = PostStubTaskWithWaitableEvent();
92 PostStubTask(&called);
93 drm_thread_.FlushForTesting();
94 EXPECT_FALSE(event->IsSignaled());
95 EXPECT_FALSE(called);
96
97 // Add the graphics device. The tasks should run.
98 AddGraphicsDevice();
99 drm_thread_.FlushForTesting();
100 ASSERT_TRUE(event->IsSignaled());
101 ASSERT_TRUE(called);
102
103 // Now that a graphics device is available, further tasks should execute
104 // immediately.
105 event = PostStubTaskWithWaitableEvent();
106 PostStubTask(&called);
107 drm_thread_.FlushForTesting();
108 ASSERT_TRUE(event->IsSignaled());
109 ASSERT_TRUE(called);
110 }
111
112 // Verifies that we gracefully handle the case where CheckOverlayCapabilities()
113 // is called on a destroyed window.
TEST_F(DrmThreadTest,CheckOverlayCapabilitiesDestroyedWindow)114 TEST_F(DrmThreadTest, CheckOverlayCapabilitiesDestroyedWindow) {
115 gfx::AcceleratedWidget widget = 5;
116 constexpr gfx::Rect bounds(10, 10);
117 constexpr size_t candidates_size = 9;
118 std::vector<OverlaySurfaceCandidate> candidates(candidates_size);
119 std::vector<OverlayStatus> result;
120 AddGraphicsDevice();
121 drm_device_->CreateWindow(widget, bounds);
122 drm_device_->DestroyWindow(widget);
123 drm_device_.FlushForTesting();
124 drm_thread_.task_runner()->PostTask(
125 FROM_HERE, base::BindOnce(&DrmThread::CheckOverlayCapabilitiesSync,
126 base::Unretained(&drm_thread_), widget,
127 candidates, &result));
128 drm_thread_.FlushForTesting();
129 EXPECT_EQ(candidates_size, result.size());
130 for (const auto& status : result) {
131 EXPECT_EQ(OVERLAY_STATUS_NOT, status);
132 }
133 }
134
135 } // namespace ui
136