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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: ui/ozone/platform/drm/host/drm_display_host_manager.cc
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3fa038dd42d9aa40bd89cac460168bfdaff32125
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -0,0 +1,461 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
+
+#include <fcntl.h>
+#include <xf86drm.h>
+
+#include "base/files/file_enumerator.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/worker_pool.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/ozone/common/display_util.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/host/drm_device_handle.h"
+#include "ui/ozone/platform/drm/host/drm_display_host.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+#include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
+
+namespace ui {
+
+namespace {
+
+typedef base::Callback<void(const base::FilePath&, scoped_ptr<DrmDeviceHandle>)>
+ OnOpenDeviceReplyCallback;
+
+const char kDefaultGraphicsCardPattern[] = "/dev/dri/card%d";
+const char kVgemDevDriCardPath[] = "/dev/dri/";
+const char kVgemSysCardPath[] = "/sys/bus/platform/devices/vgem/drm/";
+
+const char* kDisplayActionString[] = {
+ "ADD",
+ "REMOVE",
+ "CHANGE",
+};
+
+void OpenDeviceOnWorkerThread(
+ const base::FilePath& path,
+ const scoped_refptr<base::TaskRunner>& reply_runner,
+ const OnOpenDeviceReplyCallback& callback) {
+ scoped_ptr<DrmDeviceHandle> handle(new DrmDeviceHandle());
+ handle->Initialize(path);
+ reply_runner->PostTask(
+ FROM_HERE, base::Bind(callback, path, base::Passed(handle.Pass())));
+}
+
+base::FilePath GetPrimaryDisplayCardPath() {
+ struct drm_mode_card_res res;
+ for (int i = 0; /* end on first card# that does not exist */; i++) {
+ std::string card_path = base::StringPrintf(kDefaultGraphicsCardPattern, i);
+
+ if (access(card_path.c_str(), F_OK) != 0) {
+ LOG(WARNING) << "Can't access card: " << card_path;
+ break;
+ }
+
+
+ int fd = open(card_path.c_str(), O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ VPLOG(1) << "Failed to open '" << card_path << "'";
+ continue;
+ }
+
+ memset(&res, 0, sizeof(struct drm_mode_card_res));
+ int ret = drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
+ close(fd);
+ if (ret == 0 && res.count_crtcs > 0) {
+ return base::FilePath(card_path);
+ }
+
+ VPLOG_IF(1, ret) << "Failed to get DRM resources for '" << card_path << "'";
+ }
+
+ return base::FilePath();
+}
+
+base::FilePath GetVgemCardPath() {
+ base::FileEnumerator file_iter(base::FilePath(kVgemSysCardPath), false,
+ base::FileEnumerator::DIRECTORIES,
+ FILE_PATH_LITERAL("card*"));
+
+ while (!file_iter.Next().empty()) {
+ // Inspect the card%d directories in the directory and extract the filename.
+ std::string vgem_card_path =
+ kVgemDevDriCardPath + file_iter.GetInfo().GetName().BaseName().value();
+ DVLOG(1) << "VGEM card path is " << vgem_card_path;
+ return base::FilePath(vgem_card_path);
+ }
+ DVLOG(1) << "Don't support VGEM";
+ return base::FilePath();
+}
+
+class FindDrmDisplayHostById {
+ public:
+ explicit FindDrmDisplayHostById(int64_t display_id)
+ : display_id_(display_id) {}
+
+ bool operator()(const DrmDisplayHost* display) const {
+ return display->snapshot()->display_id() == display_id_;
+ }
+
+ private:
+ int64_t display_id_;
+};
+
+} // namespace
+
+DrmDisplayHostManager::DrmDisplayHostManager(
+ DrmGpuPlatformSupportHost* proxy,
+ DeviceManager* device_manager,
+ InputControllerEvdev* input_controller)
+ : proxy_(proxy),
+ device_manager_(device_manager),
+ input_controller_(input_controller),
+ primary_graphics_card_path_(GetPrimaryDisplayCardPath()),
+ weak_ptr_factory_(this) {
+ {
+ // First device needs to be treated specially. We need to open this
+ // synchronously since the GPU process will need it to initialize the
+ // graphics state.
+ primary_drm_device_handle_.reset(new DrmDeviceHandle());
+ if (!primary_drm_device_handle_->Initialize(primary_graphics_card_path_)) {
+ LOG(FATAL) << "Failed to open primary graphics card";
+ return;
+ }
+ drm_devices_.insert(primary_graphics_card_path_);
+
+ vgem_card_path_ = GetVgemCardPath();
+ if (!vgem_card_path_.empty()) {
+ int fd = HANDLE_EINTR(
+ open(vgem_card_path_.value().c_str(), O_RDWR | O_CLOEXEC));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open vgem: " << vgem_card_path_.value();
+ }
+ vgem_card_device_file_.reset(fd);
+ }
+ }
+
+ device_manager_->AddObserver(this);
+
+ ScopedVector<HardwareDisplayControllerInfo> display_infos =
+ GetAvailableDisplayControllerInfos(primary_drm_device_handle_->fd());
+ has_dummy_display_ = !display_infos.empty();
+ for (size_t i = 0; i < display_infos.size(); ++i) {
+ displays_.push_back(new DrmDisplayHost(
+ proxy_, CreateDisplaySnapshotParams(display_infos[i],
+ primary_drm_device_handle_->fd(), i,
+ gfx::Point()),
+ true /* is_dummy */));
+ }
+}
+
+DrmDisplayHostManager::~DrmDisplayHostManager() {
+ device_manager_->RemoveObserver(this);
+}
+
+DrmDisplayHost* DrmDisplayHostManager::GetDisplay(int64_t display_id) {
+ auto it = std::find_if(displays_.begin(), displays_.end(),
+ FindDrmDisplayHostById(display_id));
+ if (it == displays_.end())
+ return nullptr;
+
+ return *it;
+}
+
+void DrmDisplayHostManager::AddDelegate(DrmNativeDisplayDelegate* delegate) {
+ DCHECK(!delegate_);
+ delegate_ = delegate;
+}
+
+void DrmDisplayHostManager::RemoveDelegate(DrmNativeDisplayDelegate* delegate) {
+ DCHECK_EQ(delegate_, delegate);
+ delegate_ = nullptr;
+}
+
+void DrmDisplayHostManager::TakeDisplayControl(
+ const DisplayControlCallback& callback) {
+ if (display_control_change_pending_) {
+ LOG(ERROR) << "TakeDisplayControl called while change already pending";
+ callback.Run(false);
+ return;
+ }
+
+ if (!display_externally_controlled_) {
+ LOG(ERROR) << "TakeDisplayControl called while display already owned";
+ callback.Run(true);
+ return;
+ }
+
+ take_display_control_callback_ = callback;
+ display_control_change_pending_ = true;
+
+ if (!proxy_->TakeDisplayControl())
+ OnTakeDisplayControl(false);
+}
+
+void DrmDisplayHostManager::RelinquishDisplayControl(
+ const DisplayControlCallback& callback) {
+ if (display_control_change_pending_) {
+ LOG(ERROR)
+ << "RelinquishDisplayControl called while change already pending";
+ callback.Run(false);
+ return;
+ }
+
+ if (display_externally_controlled_) {
+ LOG(ERROR) << "RelinquishDisplayControl called while display not owned";
+ callback.Run(true);
+ return;
+ }
+
+ relinquish_display_control_callback_ = callback;
+ display_control_change_pending_ = true;
+
+ if (!proxy_->RelinquishDisplayControl())
+ OnRelinquishDisplayControl(false);
+}
+
+void DrmDisplayHostManager::UpdateDisplays(
+ const GetDisplaysCallback& callback) {
+ get_displays_callback_ = callback;
+ if (!proxy_->RefreshNativeDisplays()) {
+ get_displays_callback_.Reset();
+ RunUpdateDisplaysCallback(callback);
+ }
+}
+
+void DrmDisplayHostManager::OnDeviceEvent(const DeviceEvent& event) {
+ if (event.device_type() != DeviceEvent::DISPLAY)
+ return;
+
+ event_queue_.push(DisplayEvent(event.action_type(), event.path()));
+ ProcessEvent();
+}
+
+void DrmDisplayHostManager::ProcessEvent() {
+ while (!event_queue_.empty() && !task_pending_) {
+ DisplayEvent event = event_queue_.front();
+ event_queue_.pop();
+ VLOG(1) << "Got display event " << kDisplayActionString[event.action_type]
+ << " for " << event.path.value();
+ switch (event.action_type) {
+ case DeviceEvent::ADD:
+ if (event.path == vgem_card_path_)
+ continue;
+ if (drm_devices_.find(event.path) == drm_devices_.end()) {
+ task_pending_ = base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&OpenDeviceOnWorkerThread, event.path,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&DrmDisplayHostManager::OnAddGraphicsDevice,
+ weak_ptr_factory_.GetWeakPtr())),
+ false /* task_is_slow */);
+ }
+ break;
+ case DeviceEvent::CHANGE:
+ task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DrmDisplayHostManager::OnUpdateGraphicsDevice,
+ weak_ptr_factory_.GetWeakPtr()));
+ break;
+ case DeviceEvent::REMOVE:
+ DCHECK(event.path != primary_graphics_card_path_)
+ << "Removing primary graphics card";
+ DCHECK(event.path != vgem_card_path_) << "Removing VGEM device";
+ auto it = drm_devices_.find(event.path);
+ if (it != drm_devices_.end()) {
+ task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DrmDisplayHostManager::OnRemoveGraphicsDevice,
+ weak_ptr_factory_.GetWeakPtr(), event.path));
+ drm_devices_.erase(it);
+ }
+ break;
+ }
+ }
+}
+
+void DrmDisplayHostManager::OnAddGraphicsDevice(
+ const base::FilePath& path,
+ scoped_ptr<DrmDeviceHandle> handle) {
+ if (handle->IsValid()) {
+ drm_devices_.insert(path);
+ proxy_->AddGraphicsDevice(path, base::FileDescriptor(handle->PassFD()));
+ NotifyDisplayDelegate();
+ }
+
+ task_pending_ = false;
+ ProcessEvent();
+}
+
+void DrmDisplayHostManager::OnUpdateGraphicsDevice() {
+ NotifyDisplayDelegate();
+ task_pending_ = false;
+ ProcessEvent();
+}
+
+void DrmDisplayHostManager::OnRemoveGraphicsDevice(const base::FilePath& path) {
+ proxy_->RemoveGraphicsDevice(path);
+ NotifyDisplayDelegate();
+ task_pending_ = false;
+ ProcessEvent();
+}
+
+void DrmDisplayHostManager::OnChannelEstablished(int host_id) {
+ // If in the middle of a configuration, just respond with the old list of
+ // displays. This is fine, since after the DRM resources are initialized and
+ // IPC-ed to the GPU NotifyDisplayDelegate() is called to let the display
+ // delegate know that the display configuration changed and it needs to
+ // update it again.
+ if (!get_displays_callback_.is_null()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
+ weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
+ get_displays_callback_.Reset();
+ }
+
+ // Signal that we're taking DRM master since we're going through the
+ // initialization process again and we'll take all the available resources.
+ if (!take_display_control_callback_.is_null())
+ OnTakeDisplayControl(true);
+
+ if (!relinquish_display_control_callback_.is_null())
+ OnRelinquishDisplayControl(false);
+
+ drm_devices_.clear();
+ drm_devices_.insert(primary_graphics_card_path_);
+ scoped_ptr<DrmDeviceHandle> handle = primary_drm_device_handle_.Pass();
+ if (!handle) {
+ handle.reset(new DrmDeviceHandle());
+ if (!handle->Initialize(primary_graphics_card_path_))
+ LOG(FATAL) << "Failed to open primary graphics card";
+ }
+
+ // Send the primary device first since this is used to initialize graphics
+ // state.
+ proxy_->AddGraphicsDevice(primary_graphics_card_path_,
+ base::FileDescriptor(handle->PassFD()));
+
+ device_manager_->ScanDevices(this);
+ NotifyDisplayDelegate();
+}
+
+void DrmDisplayHostManager::OnChannelDestroyed(int host_id) {
+ // Do nothing.
+}
+
+void DrmDisplayHostManager::OnUpdateNativeDisplays(
+ const std::vector<DisplaySnapshot_Params>& params) {
+ ScopedVector<DrmDisplayHost> old_displays(displays_.Pass());
+ for (size_t i = 0; i < params.size(); ++i) {
+ auto it = std::find_if(old_displays.begin(), old_displays.end(),
+ FindDrmDisplayHostById(params[i].display_id));
+ if (it == old_displays.end()) {
+ displays_.push_back(
+ new DrmDisplayHost(proxy_, params[i], false /* is_dummy */));
+ } else {
+ (*it)->UpdateDisplaySnapshot(params[i]);
+ displays_.push_back(*it);
+ old_displays.weak_erase(it);
+ }
+ }
+
+ if (!get_displays_callback_.is_null()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&DrmDisplayHostManager::RunUpdateDisplaysCallback,
+ weak_ptr_factory_.GetWeakPtr(), get_displays_callback_));
+ get_displays_callback_.Reset();
+ }
+}
+
+void DrmDisplayHostManager::OnDisplayConfigured(int64_t display_id,
+ bool status) {
+ DrmDisplayHost* display = GetDisplay(display_id);
+ if (display)
+ display->OnDisplayConfigured(status);
+ else
+ LOG(ERROR) << "Couldn't find display with id=" << display_id;
+}
+
+void DrmDisplayHostManager::OnHDCPStateReceived(int64_t display_id,
+ bool status,
+ HDCPState state) {
+ DrmDisplayHost* display = GetDisplay(display_id);
+ if (display)
+ display->OnHDCPStateReceived(status, state);
+ else
+ LOG(ERROR) << "Couldn't find display with id=" << display_id;
+}
+
+void DrmDisplayHostManager::OnHDCPStateUpdated(int64_t display_id,
+ bool status) {
+ DrmDisplayHost* display = GetDisplay(display_id);
+ if (display)
+ display->OnHDCPStateUpdated(status);
+ else
+ LOG(ERROR) << "Couldn't find display with id=" << display_id;
+}
+
+void DrmDisplayHostManager::OnTakeDisplayControl(bool status) {
+ if (take_display_control_callback_.is_null()) {
+ LOG(ERROR) << "No callback for take display control";
+ return;
+ }
+
+ DCHECK(display_externally_controlled_);
+ DCHECK(display_control_change_pending_);
+
+ if (status) {
+ input_controller_->SetInputDevicesEnabled(true);
+ display_externally_controlled_ = false;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(take_display_control_callback_, status));
+ take_display_control_callback_.Reset();
+ display_control_change_pending_ = false;
+}
+
+void DrmDisplayHostManager::OnRelinquishDisplayControl(bool status) {
+ if (relinquish_display_control_callback_.is_null()) {
+ LOG(ERROR) << "No callback for relinquish display control";
+ return;
+ }
+
+ DCHECK(!display_externally_controlled_);
+ DCHECK(display_control_change_pending_);
+
+ if (status) {
+ input_controller_->SetInputDevicesEnabled(false);
+ display_externally_controlled_ = true;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(relinquish_display_control_callback_, status));
+ relinquish_display_control_callback_.Reset();
+ display_control_change_pending_ = false;
+}
+
+void DrmDisplayHostManager::RunUpdateDisplaysCallback(
+ const GetDisplaysCallback& callback) const {
+ std::vector<DisplaySnapshot*> snapshots;
+ for (auto* display : displays_)
+ snapshots.push_back(display->snapshot());
+
+ callback.Run(snapshots);
+}
+
+void DrmDisplayHostManager::NotifyDisplayDelegate() const {
+ if (delegate_)
+ delegate_->OnConfigurationChanged();
+}
+
+} // namespace ui
« 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