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