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