1 // Copyright 2015 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_proxy.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "ui/gfx/linux/gbm_wrapper.h"
12 #include "ui/ozone/platform/drm/gpu/drm_device.h"
13 #include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
14 #include "ui/ozone/platform/drm/gpu/drm_thread_message_proxy.h"
15 #include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
16 #include "ui/ozone/platform/drm/gpu/gbm_pixmap.h"
17 #include "ui/ozone/platform/drm/gpu/proxy_helpers.h"
18
19 namespace ui {
20
21 namespace {
22
OnBufferCreatedOnDrmThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner,DrmThreadProxy::CreateBufferAsyncCallback callback,std::unique_ptr<GbmBuffer> buffer,scoped_refptr<DrmFramebuffer> framebuffer)23 void OnBufferCreatedOnDrmThread(
24 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
25 DrmThreadProxy::CreateBufferAsyncCallback callback,
26 std::unique_ptr<GbmBuffer> buffer,
27 scoped_refptr<DrmFramebuffer> framebuffer) {
28 task_runner->PostTask(FROM_HERE,
29 base::BindOnce(std::move(callback), std::move(buffer),
30 std::move(framebuffer)));
31 }
32
33 class GbmDeviceGenerator : public DrmDeviceGenerator {
34 public:
GbmDeviceGenerator()35 GbmDeviceGenerator() {}
~GbmDeviceGenerator()36 ~GbmDeviceGenerator() override {}
37
38 // DrmDeviceGenerator:
CreateDevice(const base::FilePath & path,base::File file,bool is_primary_device)39 scoped_refptr<DrmDevice> CreateDevice(const base::FilePath& path,
40 base::File file,
41 bool is_primary_device) override {
42 auto gbm = CreateGbmDevice(file.GetPlatformFile());
43 if (!gbm) {
44 PLOG(ERROR) << "Unable to initialize GBM for " << path.value();
45 return nullptr;
46 }
47
48 auto drm = base::MakeRefCounted<DrmDevice>(
49 path, std::move(file), is_primary_device, std::move(gbm));
50 if (!drm->Initialize())
51 return nullptr;
52 return drm;
53 }
54
55 private:
56 DISALLOW_COPY_AND_ASSIGN(GbmDeviceGenerator);
57 };
58
59 } // namespace
60
61 DrmThreadProxy::DrmThreadProxy() = default;
62
63 DrmThreadProxy::~DrmThreadProxy() = default;
64
65 // Used only with the paramtraits implementation.
BindThreadIntoMessagingProxy(InterThreadMessagingProxy * messaging_proxy)66 void DrmThreadProxy::BindThreadIntoMessagingProxy(
67 InterThreadMessagingProxy* messaging_proxy) {
68 messaging_proxy->SetDrmThread(&drm_thread_);
69 }
70
StartDrmThread(base::OnceClosure receiver_drainer)71 void DrmThreadProxy::StartDrmThread(base::OnceClosure receiver_drainer) {
72 drm_thread_.Start(std::move(receiver_drainer),
73 std::make_unique<GbmDeviceGenerator>());
74 }
75
CreateDrmWindowProxy(gfx::AcceleratedWidget widget)76 std::unique_ptr<DrmWindowProxy> DrmThreadProxy::CreateDrmWindowProxy(
77 gfx::AcceleratedWidget widget) {
78 return std::make_unique<DrmWindowProxy>(widget, &drm_thread_);
79 }
80
CreateBuffer(gfx::AcceleratedWidget widget,const gfx::Size & size,const gfx::Size & framebuffer_size,gfx::BufferFormat format,gfx::BufferUsage usage,uint32_t flags,std::unique_ptr<GbmBuffer> * buffer,scoped_refptr<DrmFramebuffer> * framebuffer)81 void DrmThreadProxy::CreateBuffer(gfx::AcceleratedWidget widget,
82 const gfx::Size& size,
83 const gfx::Size& framebuffer_size,
84 gfx::BufferFormat format,
85 gfx::BufferUsage usage,
86 uint32_t flags,
87 std::unique_ptr<GbmBuffer>* buffer,
88 scoped_refptr<DrmFramebuffer>* framebuffer) {
89 TRACE_EVENT0("drm", "DrmThreadProxy::CreateBuffer");
90 DCHECK(drm_thread_.task_runner())
91 << "no task runner! in DrmThreadProxy::CreateBuffer";
92 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
93 base::OnceClosure task = base::BindOnce(
94 &DrmThread::CreateBuffer, base::Unretained(&drm_thread_), widget, size,
95 framebuffer_size, format, usage, flags, buffer, framebuffer);
96 PostSyncTask(
97 drm_thread_.task_runner(),
98 base::BindOnce(&DrmThread::RunTaskAfterWindowReady,
99 base::Unretained(&drm_thread_), widget, std::move(task)));
100 }
101
CreateBufferAsync(gfx::AcceleratedWidget widget,const gfx::Size & size,gfx::BufferFormat format,gfx::BufferUsage usage,uint32_t flags,CreateBufferAsyncCallback callback)102 void DrmThreadProxy::CreateBufferAsync(gfx::AcceleratedWidget widget,
103 const gfx::Size& size,
104 gfx::BufferFormat format,
105 gfx::BufferUsage usage,
106 uint32_t flags,
107 CreateBufferAsyncCallback callback) {
108 DCHECK(drm_thread_.task_runner())
109 << "no task runner! in DrmThreadProxy::CreateBufferAsync";
110 base::OnceClosure task = base::BindOnce(
111 &DrmThread::CreateBufferAsync, base::Unretained(&drm_thread_), widget,
112 size, format, usage, flags,
113 base::BindOnce(OnBufferCreatedOnDrmThread,
114 base::ThreadTaskRunnerHandle::Get(), std::move(callback)));
115 // Since browser's UI thread blocks until a buffer is returned, we shouldn't
116 // block on |widget| because a blocked UI thread cannot register |widget| and
117 // causes a deadlock. We still want to block on a graphics device, though.
118 // TODO(samans): Remove this hack once OOP-D launches.
119 gfx::AcceleratedWidget blocking_widget = gfx::kNullAcceleratedWidget;
120 drm_thread_.task_runner()->PostTask(
121 FROM_HERE, base::BindOnce(&DrmThread::RunTaskAfterWindowReady,
122 base::Unretained(&drm_thread_), blocking_widget,
123 std::move(task), nullptr));
124 }
125
CreateBufferFromHandle(gfx::AcceleratedWidget widget,const gfx::Size & size,gfx::BufferFormat format,gfx::NativePixmapHandle handle,std::unique_ptr<GbmBuffer> * buffer,scoped_refptr<DrmFramebuffer> * framebuffer)126 void DrmThreadProxy::CreateBufferFromHandle(
127 gfx::AcceleratedWidget widget,
128 const gfx::Size& size,
129 gfx::BufferFormat format,
130 gfx::NativePixmapHandle handle,
131 std::unique_ptr<GbmBuffer>* buffer,
132 scoped_refptr<DrmFramebuffer>* framebuffer) {
133 TRACE_EVENT0("drm", "DrmThreadProxy::CreateBufferFromHandle");
134 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
135 base::OnceClosure task = base::BindOnce(
136 &DrmThread::CreateBufferFromHandle, base::Unretained(&drm_thread_),
137 widget, size, format, std::move(handle), buffer, framebuffer);
138 PostSyncTask(
139 drm_thread_.task_runner(),
140 base::BindOnce(&DrmThread::RunTaskAfterWindowReady,
141 base::Unretained(&drm_thread_), widget, std::move(task)));
142 }
143
SetClearOverlayCacheCallback(base::RepeatingClosure callback)144 void DrmThreadProxy::SetClearOverlayCacheCallback(
145 base::RepeatingClosure callback) {
146 DCHECK(drm_thread_.task_runner());
147
148 drm_thread_.task_runner()->PostTask(
149 FROM_HERE,
150 base::BindOnce(&DrmThread::SetClearOverlayCacheCallback,
151 base::Unretained(&drm_thread_),
152 CreateSafeRepeatingCallback(std::move(callback))));
153 }
154
CheckOverlayCapabilities(gfx::AcceleratedWidget widget,const std::vector<OverlaySurfaceCandidate> & candidates,DrmThread::OverlayCapabilitiesCallback callback)155 void DrmThreadProxy::CheckOverlayCapabilities(
156 gfx::AcceleratedWidget widget,
157 const std::vector<OverlaySurfaceCandidate>& candidates,
158 DrmThread::OverlayCapabilitiesCallback callback) {
159 DCHECK(drm_thread_.task_runner());
160 base::OnceClosure task = base::BindOnce(
161 &DrmThread::CheckOverlayCapabilities, base::Unretained(&drm_thread_),
162 widget, candidates, CreateSafeOnceCallback(std::move(callback)));
163
164 drm_thread_.task_runner()->PostTask(
165 FROM_HERE, base::BindOnce(&DrmThread::RunTaskAfterWindowReady,
166 base::Unretained(&drm_thread_), widget,
167 std::move(task), nullptr));
168 }
169
CheckOverlayCapabilitiesSync(gfx::AcceleratedWidget widget,const std::vector<OverlaySurfaceCandidate> & candidates)170 std::vector<OverlayStatus> DrmThreadProxy::CheckOverlayCapabilitiesSync(
171 gfx::AcceleratedWidget widget,
172 const std::vector<OverlaySurfaceCandidate>& candidates) {
173 TRACE_EVENT0("drm", "DrmThreadProxy::CheckOverlayCapabilitiesSync");
174 DCHECK(drm_thread_.task_runner());
175 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
176 std::vector<OverlayStatus> result;
177 base::OnceClosure task = base::BindOnce(
178 &DrmThread::CheckOverlayCapabilitiesSync, base::Unretained(&drm_thread_),
179 widget, candidates, &result);
180 PostSyncTask(
181 drm_thread_.task_runner(),
182 base::BindOnce(&DrmThread::RunTaskAfterWindowReady,
183 base::Unretained(&drm_thread_), widget, std::move(task)));
184 return result;
185 }
186
AddDrmDeviceReceiver(mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver)187 void DrmThreadProxy::AddDrmDeviceReceiver(
188 mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver) {
189 DCHECK(drm_thread_.task_runner()) << "DrmThreadProxy::AddDrmDeviceReceiver "
190 "drm_thread_ task runner missing";
191
192 drm_thread_.task_runner()->PostTask(
193 FROM_HERE,
194 base::BindOnce(&DrmThread::AddDrmDeviceReceiver,
195 base::Unretained(&drm_thread_), std::move(receiver)));
196 }
197
198 } // namespace ui
199