Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: ui/ozone/platform/drm/host/drm_display_host_manager.cc

Issue 1285183008: Ozone integration. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: add missing license header Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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/host/drm_display_host_manager.h"
6
7 #include <fcntl.h>
8 #include <xf86drm.h>
9
10 #include "base/files/file_enumerator.h"
11 #include "base/posix/eintr_wrapper.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/threading/worker_pool.h"
15 #include "ui/display/types/display_snapshot.h"
16 #include "ui/events/ozone/device/device_event.h"
17 #include "ui/events/ozone/device/device_manager.h"
18 #include "ui/ozone/common/display_util.h"
19 #include "ui/ozone/platform/drm/common/drm_util.h"
20 #include "ui/ozone/platform/drm/host/drm_device_handle.h"
21 #include "ui/ozone/platform/drm/host/drm_display_host.h"
22 #include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
23 #include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
24
25 namespace ui {
26
27 namespace {
28
29 typedef base::Callback<void(const base::FilePath&, scoped_ptr<DrmDeviceHandle>)>
30 OnOpenDeviceReplyCallback;
31
32 const char kDefaultGraphicsCardPattern[] = "/dev/dri/card%d";
33 const char kVgemDevDriCardPath[] = "/dev/dri/";
34 const char kVgemSysCardPath[] = "/sys/bus/platform/devices/vgem/drm/";
35
36 const char* kDisplayActionString[] = {
37 "ADD",
38 "REMOVE",
39 "CHANGE",
40 };
41
42 void OpenDeviceOnWorkerThread(
43 const base::FilePath& path,
44 const scoped_refptr<base::TaskRunner>& reply_runner,
45 const OnOpenDeviceReplyCallback& callback) {
46 scoped_ptr<DrmDeviceHandle> handle(new DrmDeviceHandle());
47 handle->Initialize(path);
48 reply_runner->PostTask(
49 FROM_HERE, base::Bind(callback, path, base::Passed(handle.Pass())));
50 }
51
52 base::FilePath GetPrimaryDisplayCardPath() {
53 struct drm_mode_card_res res;
54 for (int i = 0; /* end on first card# that does not exist */; i++) {
55 std::string card_path = base::StringPrintf(kDefaultGraphicsCardPattern, i);
56
57 if (access(card_path.c_str(), F_OK) != 0) {
58 LOG(WARNING) << "Can't access card: " << card_path;
59 break;
60 }
61
62
63 int fd = open(card_path.c_str(), O_RDWR | O_CLOEXEC);
64 if (fd < 0) {
65 VPLOG(1) << "Failed to open '" << card_path << "'";
66 continue;
67 }
68
69 memset(&res, 0, sizeof(struct drm_mode_card_res));
70 int ret = drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
71 close(fd);
72 if (ret == 0 && res.count_crtcs > 0) {
73 return base::FilePath(card_path);
74 }
75
76 VPLOG_IF(1, ret) << "Failed to get DRM resources for '" << card_path << "'";
77 }
78
79 return base::FilePath();
80 }
81
82 base::FilePath GetVgemCardPath() {
83 base::FileEnumerator file_iter(base::FilePath(kVgemSysCardPath), false,
84 base::FileEnumerator::DIRECTORIES,
85 FILE_PATH_LITERAL("card*"));
86
87 while (!file_iter.Next().empty()) {
88 // Inspect the card%d directories in the directory and extract the filename.
89 std::string vgem_card_path =
90 kVgemDevDriCardPath + file_iter.GetInfo().GetName().BaseName().value();
91 DVLOG(1) << "VGEM card path is " << vgem_card_path;
92 return base::FilePath(vgem_card_path);
93 }
94 DVLOG(1) << "Don't support VGEM";
95 return base::FilePath();
96 }
97
98 class FindDrmDisplayHostById {
99 public:
100 explicit FindDrmDisplayHostById(int64_t display_id)
101 : display_id_(display_id) {}
102
103 bool operator()(const DrmDisplayHost* display) const {
104 return display->snapshot()->display_id() == display_id_;
105 }
106
107 private:
108 int64_t display_id_;
109 };
110
111 } // namespace
112
113 DrmDisplayHostManager::DrmDisplayHostManager(
114 DrmGpuPlatformSupportHost* proxy,
115 DeviceManager* device_manager,
116 InputControllerEvdev* input_controller)
117 : proxy_(proxy),
118 device_manager_(device_manager),
119 input_controller_(input_controller),
120 primary_graphics_card_path_(GetPrimaryDisplayCardPath()),
121 weak_ptr_factory_(this) {
122 {
123 // First device needs to be treated specially. We need to open this
124 // synchronously since the GPU process will need it to initialize the
125 // graphics state.
126 primary_drm_device_handle_.reset(new DrmDeviceHandle());
127 if (!primary_drm_device_handle_->Initialize(primary_graphics_card_path_)) {
128 LOG(FATAL) << "Failed to open primary graphics card";
129 return;
130 }
131 drm_devices_.insert(primary_graphics_card_path_);
132
133 vgem_card_path_ = GetVgemCardPath();
134 if (!vgem_card_path_.empty()) {
135 int fd = HANDLE_EINTR(
136 open(vgem_card_path_.value().c_str(), O_RDWR | O_CLOEXEC));
137 if (fd < 0) {
138 PLOG(ERROR) << "Failed to open vgem: " << vgem_card_path_.value();
139 }
140 vgem_card_device_file_.reset(fd);
141 }
142 }
143
144 device_manager_->AddObserver(this);
145
146 ScopedVector<HardwareDisplayControllerInfo> display_infos =
147 GetAvailableDisplayControllerInfos(primary_drm_device_handle_->fd());
148 has_dummy_display_ = !display_infos.empty();
149 for (size_t i = 0; i < display_infos.size(); ++i) {
150 displays_.push_back(new DrmDisplayHost(
151 proxy_, CreateDisplaySnapshotParams(display_infos[i],
152 primary_drm_device_handle_->fd(), i,
153 gfx::Point()),
154 true /* is_dummy */));
155 }
156 }
157
158 DrmDisplayHostManager::~DrmDisplayHostManager() {
159 device_manager_->RemoveObserver(this);
160 }
161
162 DrmDisplayHost* DrmDisplayHostManager::GetDisplay(int64_t display_id) {
163 auto it = std::find_if(displays_.begin(), displays_.end(),
164 FindDrmDisplayHostById(display_id));
165 if (it == displays_.end())
166 return nullptr;
167
168 return *it;
169 }
170
171 void DrmDisplayHostManager::AddDelegate(DrmNativeDisplayDelegate* delegate) {
172 DCHECK(!delegate_);
173 delegate_ = delegate;
174 }
175
176 void DrmDisplayHostManager::RemoveDelegate(DrmNativeDisplayDelegate* delegate) {
177 DCHECK_EQ(delegate_, delegate);
178 delegate_ = nullptr;
179 }
180
181 void DrmDisplayHostManager::TakeDisplayControl(
182 const DisplayControlCallback& callback) {
183 if (display_control_change_pending_) {
184 LOG(ERROR) << "TakeDisplayControl called while change already pending";
185 callback.Run(false);
186 return;
187 }
188
189 if (!display_externally_controlled_) {
190 LOG(ERROR) << "TakeDisplayControl called while display already owned";
191 callback.Run(true);
192 return;
193 }
194
195 take_display_control_callback_ = callback;
196 display_control_change_pending_ = true;
197
198 if (!proxy_->TakeDisplayControl())
199 OnTakeDisplayControl(false);
200 }
201
202 void DrmDisplayHostManager::RelinquishDisplayControl(
203 const DisplayControlCallback& callback) {
204 if (display_control_change_pending_) {
205 LOG(ERROR)
206 << "RelinquishDisplayControl called while change already pending";
207 callback.Run(false);
208 return;
209 }
210
211 if (display_externally_controlled_) {
212 LOG(ERROR) << "RelinquishDisplayControl called while display not owned";
213 callback.Run(true);
214 return;
215 }
216
217 relinquish_display_control_callback_ = callback;
218 display_control_change_pending_ = true;
219
220 if (!proxy_->RelinquishDisplayControl())
221 OnRelinquishDisplayControl(false);
222 }
223
224 void DrmDisplayHostManager::UpdateDisplays(
225 const GetDisplaysCallback& callback) {
226 get_displays_callback_ = callback;
227 if (!proxy_->RefreshNativeDisplays()) {
228 get_displays_callback_.Reset();
229 RunUpdateDisplaysCallback(callback);
230 }
231 }
232
233 void DrmDisplayHostManager::OnDeviceEvent(const DeviceEvent& event) {
234 if (event.device_type() != DeviceEvent::DISPLAY)
235 return;
236
237 event_queue_.push(DisplayEvent(event.action_type(), event.path()));
238 ProcessEvent();
239 }
240
241 void DrmDisplayHostManager::ProcessEvent() {
242 while (!event_queue_.empty() && !task_pending_) {
243 DisplayEvent event = event_queue_.front();
244 event_queue_.pop();
245 VLOG(1) << "Got display event " << kDisplayActionString[event.action_type]
246 << " for " << event.path.value();
247 switch (event.action_type) {
248 case DeviceEvent::ADD:
249 if (event.path == vgem_card_path_)
250 continue;
251 if (drm_devices_.find(event.path) == drm_devices_.end()) {
252 task_pending_ = base::WorkerPool::PostTask(
253 FROM_HERE,
254 base::Bind(&OpenDeviceOnWorkerThread, event.path,
255 base::ThreadTaskRunnerHandle::Get(),
256 base::Bind(&DrmDisplayHostManager::OnAddGraphicsDevice,
257 weak_ptr_factory_.GetWeakPtr())),
258 false /* task_is_slow */);
259 }
260 break;
261 case DeviceEvent::CHANGE:
262 task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
263 FROM_HERE,
264 base::Bind(&DrmDisplayHostManager::OnUpdateGraphicsDevice,
265 weak_ptr_factory_.GetWeakPtr()));
266 break;
267 case DeviceEvent::REMOVE:
268 DCHECK(event.path != primary_graphics_card_path_)
269 << "Removing primary graphics card";
270 DCHECK(event.path != vgem_card_path_) << "Removing VGEM device";
271 auto it = drm_devices_.find(event.path);
272 if (it != drm_devices_.end()) {
273 task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
274 FROM_HERE,
275 base::Bind(&DrmDisplayHostManager::OnRemoveGraphicsDevice,
276 weak_ptr_factory_.GetWeakPtr(), event.path));
277 drm_devices_.erase(it);
278 }
279 break;
280 }
281 }
282 }
283
284 void DrmDisplayHostManager::OnAddGraphicsDevice(
285 const base::FilePath& path,
286 scoped_ptr<DrmDeviceHandle> handle) {
287 if (handle->IsValid()) {
288 drm_devices_.insert(path);
289 proxy_->AddGraphicsDevice(path, base::FileDescriptor(handle->PassFD()));
290 NotifyDisplayDelegate();
291 }
292
293 task_pending_ = false;
294 ProcessEvent();
295 }
296
297 void DrmDisplayHostManager::OnUpdateGraphicsDevice() {
298 NotifyDisplayDelegate();
299 task_pending_ = false;
300 ProcessEvent();
301 }
302
303 void DrmDisplayHostManager::OnRemoveGraphicsDevice(const base::FilePath& path) {
304 proxy_->RemoveGraphicsDevice(path);
305 NotifyDisplayDelegate();
306 task_pending_ = false;
307 ProcessEvent();
308 }
309
310 void DrmDisplayHostManager::OnChannelEstablished(int host_id) {
311 // If in the middle of a configuration, just respond with the old list of
312 // displays. This is fine, since after the DRM resources are initialized and
313 // IPC-ed to the GPU NotifyDisplayDelegate() is called to let the display
314 // delegate know that the display configuration changed and it needs to
315 // update it again.
316 if (!get_displays_callback_.is_null()) {
317 base::ThreadTaskRunnerHandle::Get()->PostTask(
318 FROM_HERE,
319 base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
320 weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
321 get_displays_callback_.Reset();
322 }
323
324 // Signal that we're taking DRM master since we're going through the
325 // initialization process again and we'll take all the available resources.
326 if (!take_display_control_callback_.is_null())
327 OnTakeDisplayControl(true);
328
329 if (!relinquish_display_control_callback_.is_null())
330 OnRelinquishDisplayControl(false);
331
332 drm_devices_.clear();
333 drm_devices_.insert(primary_graphics_card_path_);
334 scoped_ptr<DrmDeviceHandle> handle = primary_drm_device_handle_.Pass();
335 if (!handle) {
336 handle.reset(new DrmDeviceHandle());
337 if (!handle->Initialize(primary_graphics_card_path_))
338 LOG(FATAL) << "Failed to open primary graphics card";
339 }
340
341 // Send the primary device first since this is used to initialize graphics
342 // state.
343 proxy_->AddGraphicsDevice(primary_graphics_card_path_,
344 base::FileDescriptor(handle->PassFD()));
345
346 device_manager_->ScanDevices(this);
347 NotifyDisplayDelegate();
348 }
349
350 void DrmDisplayHostManager::OnChannelDestroyed(int host_id) {
351 // Do nothing.
352 }
353
354 void DrmDisplayHostManager::OnUpdateNativeDisplays(
355 const std::vector<DisplaySnapshot_Params>& params) {
356 ScopedVector<DrmDisplayHost> old_displays(displays_.Pass());
357 for (size_t i = 0; i < params.size(); ++i) {
358 auto it = std::find_if(old_displays.begin(), old_displays.end(),
359 FindDrmDisplayHostById(params[i].display_id));
360 if (it == old_displays.end()) {
361 displays_.push_back(
362 new DrmDisplayHost(proxy_, params[i], false /* is_dummy */));
363 } else {
364 (*it)->UpdateDisplaySnapshot(params[i]);
365 displays_.push_back(*it);
366 old_displays.weak_erase(it);
367 }
368 }
369
370 if (!get_displays_callback_.is_null()) {
371 base::ThreadTaskRunnerHandle::Get()->PostTask(
372 FROM_HERE,
373 base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
374 weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
375 get_displays_callback_.Reset();
376 }
377 }
378
379 void DrmDisplayHostManager::OnDisplayConfigured(int64_t display_id,
380 bool status) {
381 DrmDisplayHost* display = GetDisplay(display_id);
382 if (display)
383 display->OnDisplayConfigured(status);
384 else
385 LOG(ERROR) << "Couldn't find display with id=" << display_id;
386 }
387
388 void DrmDisplayHostManager::OnHDCPStateReceived(int64_t display_id,
389 bool status,
390 HDCPState state) {
391 DrmDisplayHost* display = GetDisplay(display_id);
392 if (display)
393 display->OnHDCPStateReceived(status, state);
394 else
395 LOG(ERROR) << "Couldn't find display with id=" << display_id;
396 }
397
398 void DrmDisplayHostManager::OnHDCPStateUpdated(int64_t display_id,
399 bool status) {
400 DrmDisplayHost* display = GetDisplay(display_id);
401 if (display)
402 display->OnHDCPStateUpdated(status);
403 else
404 LOG(ERROR) << "Couldn't find display with id=" << display_id;
405 }
406
407 void DrmDisplayHostManager::OnTakeDisplayControl(bool status) {
408 if (take_display_control_callback_.is_null()) {
409 LOG(ERROR) << "No callback for take display control";
410 return;
411 }
412
413 DCHECK(display_externally_controlled_);
414 DCHECK(display_control_change_pending_);
415
416 if (status) {
417 input_controller_->SetInputDevicesEnabled(true);
418 display_externally_controlled_ = false;
419 }
420
421 base::ThreadTaskRunnerHandle::Get()->PostTask(
422 FROM_HERE, base::Bind(take_display_control_callback_, status));
423 take_display_control_callback_.Reset();
424 display_control_change_pending_ = false;
425 }
426
427 void DrmDisplayHostManager::OnRelinquishDisplayControl(bool status) {
428 if (relinquish_display_control_callback_.is_null()) {
429 LOG(ERROR) << "No callback for relinquish display control";
430 return;
431 }
432
433 DCHECK(!display_externally_controlled_);
434 DCHECK(display_control_change_pending_);
435
436 if (status) {
437 input_controller_->SetInputDevicesEnabled(false);
438 display_externally_controlled_ = true;
439 }
440
441 base::ThreadTaskRunnerHandle::Get()->PostTask(
442 FROM_HERE, base::Bind(relinquish_display_control_callback_, status));
443 relinquish_display_control_callback_.Reset();
444 display_control_change_pending_ = false;
445 }
446
447 void DrmDisplayHostManager::RunUpdateDisplaysCallback(
448 const GetDisplaysCallback& callback) const {
449 std::vector<DisplaySnapshot*> snapshots;
450 for (auto* display : displays_)
451 snapshots.push_back(display->snapshot());
452
453 callback.Run(snapshots);
454 }
455
456 void DrmDisplayHostManager::NotifyDisplayDelegate() const {
457 if (delegate_)
458 delegate_->OnConfigurationChanged();
459 }
460
461 } // namespace ui
OLDNEW
« no previous file with comments | « ui/ozone/platform/drm/host/drm_display_host_manager.h ('k') | ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698