summaryrefslogtreecommitdiffstats
path: root/ui/ozone/platform/drm/gpu/drm_device.cc
diff options
context:
space:
mode:
authordnicoara <dnicoara@chromium.org>2015-03-05 12:46:18 -0800
committerCommit bot <commit-bot@chromium.org>2015-03-05 20:47:08 +0000
commit171d8c892da1b2e38f90c17b62896ba82f0719e3 (patch)
tree9fe2810948b2d8dfd73cd7a5afa002dcf79c0547 /ui/ozone/platform/drm/gpu/drm_device.cc
parentf36607f2398cb4aa9b50449b1221bbc72e3f3453 (diff)
downloadchromium_src-171d8c892da1b2e38f90c17b62896ba82f0719e3.zip
chromium_src-171d8c892da1b2e38f90c17b62896ba82f0719e3.tar.gz
chromium_src-171d8c892da1b2e38f90c17b62896ba82f0719e3.tar.bz2
[Ozone] Rename and split the DRI platform for clarity
This CL does the following: - Moves the files in ui/ozone/platform/dri to ui/ozone/platform/drm since the platform name should really be DRM rather than DRI. Note, that the platform is still refered to as "dri" in GYP/GN since CrOS builds are still using the 'dri' name. - Rename all files with a "_dri*" suffix to a "drm_" prefix. Also rename all files with a "dri_" prefix to a "drm_" prefix. - Rename NativeDisplayDelegateDri to DrmDisplayDelegateManager since it is no longer dependent on the NativeDisplayDelegate interface and the new name better describes its intent. - Split the files in the platform into 2 sub-folders ("host" and "gpu"). Depending on the intended use place of the objects (Browser (host) process or GPU process) the files in the platform are split accordingly in the 2 sub-folders. BUG=none TBR=jam@chromium.org Review URL: https://codereview.chromium.org/975063002 Cr-Commit-Position: refs/heads/master@{#319320}
Diffstat (limited to 'ui/ozone/platform/drm/gpu/drm_device.cc')
-rw-r--r--ui/ozone/platform/drm/gpu/drm_device.cc453
1 files changed, 453 insertions, 0 deletions
diff --git a/ui/ozone/platform/drm/gpu/drm_device.cc b/ui/ozone/platform/drm/gpu/drm_device.cc
new file mode 100644
index 0000000..0a4952f
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -0,0 +1,453 @@
+// 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/gpu/drm_device.h"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/ozone/platform/drm/gpu/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
+
+namespace ui {
+
+namespace {
+
+struct PageFlipPayload {
+ PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner,
+ const DrmDevice::PageFlipCallback& callback)
+ : task_runner(task_runner), callback(callback) {}
+
+ // Task runner for the thread scheduling the page flip event. This is used to
+ // run the callback on the same thread the callback was created on.
+ scoped_refptr<base::TaskRunner> task_runner;
+ DrmDevice::PageFlipCallback callback;
+};
+
+bool DrmCreateDumbBuffer(int fd,
+ const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride) {
+ struct drm_mode_create_dumb request;
+ memset(&request, 0, sizeof(request));
+ request.width = info.width();
+ request.height = info.height();
+ request.bpp = info.bytesPerPixel() << 3;
+ request.flags = 0;
+
+ if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) {
+ VLOG(2) << "Cannot create dumb buffer (" << errno << ") "
+ << strerror(errno);
+ return false;
+ }
+
+ // The driver may choose to align the last row as well. We don't care about
+ // the last alignment bits since they aren't used for display purposes, so
+ // just check that the expected size is <= to what the driver allocated.
+ DCHECK_LE(info.getSafeSize(request.pitch), request.size);
+
+ *handle = request.handle;
+ *stride = request.pitch;
+ return true;
+}
+
+void DrmDestroyDumbBuffer(int fd, uint32_t handle) {
+ struct drm_mode_destroy_dumb destroy_request;
+ memset(&destroy_request, 0, sizeof(destroy_request));
+ destroy_request.handle = handle;
+ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
+}
+
+void HandlePageFlipEventOnIO(int fd,
+ unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds,
+ void* data) {
+ scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data));
+ payload->task_runner->PostTask(
+ FROM_HERE, base::Bind(payload->callback, frame, seconds, useconds));
+}
+
+void HandlePageFlipEventOnUI(int fd,
+ unsigned int frame,
+ unsigned int seconds,
+ unsigned int useconds,
+ void* data) {
+ scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data));
+ payload->callback.Run(frame, seconds, useconds);
+}
+
+bool CanQueryForResources(int fd) {
+ drm_mode_card_res resources;
+ memset(&resources, 0, sizeof(resources));
+ // If there is no error getting DRM resources then assume this is a
+ // modesetting device.
+ return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources);
+}
+
+} // namespace
+
+class DrmDevice::IOWatcher
+ : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>,
+ public base::MessagePumpLibevent::Watcher {
+ public:
+ IOWatcher(int fd,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
+ : io_task_runner_(io_task_runner), paused_(true), fd_(fd) {}
+
+ void SetPaused(bool paused) {
+ if (paused_ == paused)
+ return;
+
+ paused_ = paused;
+ base::WaitableEvent done(false, false);
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done));
+ }
+
+ void Shutdown() {
+ if (!paused_)
+ io_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&IOWatcher::UnregisterOnIO, this));
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<IOWatcher>;
+
+ ~IOWatcher() override { SetPaused(true); }
+
+ void RegisterOnIO() {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ base::MessageLoopForIO::current()->WatchFileDescriptor(
+ fd_, true, base::MessageLoopForIO::WATCH_READ, &controller_, this);
+ }
+
+ void UnregisterOnIO() {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ controller_.StopWatchingFileDescriptor();
+ }
+
+ void SetPausedOnIO(base::WaitableEvent* done) {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ if (paused_)
+ UnregisterOnIO();
+ else
+ RegisterOnIO();
+ done->Signal();
+ }
+
+ // base::MessagePumpLibevent::Watcher overrides:
+ void OnFileCanReadWithoutBlocking(int fd) override {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd);
+
+ drmEventContext event;
+ event.version = DRM_EVENT_CONTEXT_VERSION;
+ event.page_flip_handler = HandlePageFlipEventOnIO;
+ event.vblank_handler = nullptr;
+
+ drmHandleEvent(fd, &event);
+ }
+
+ void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); }
+
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+
+ bool paused_;
+ int fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(IOWatcher);
+};
+
+DrmDevice::DrmDevice(const base::FilePath& device_path)
+ : device_path_(device_path),
+ file_(device_path,
+ base::File::FLAG_OPEN | base::File::FLAG_READ |
+ base::File::FLAG_WRITE) {
+ LOG_IF(FATAL, !file_.IsValid())
+ << "Failed to open '" << device_path_.value()
+ << "': " << base::File::ErrorToString(file_.error_details());
+}
+
+DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file)
+ : device_path_(device_path), file_(file.Pass()) {
+}
+
+DrmDevice::~DrmDevice() {
+ if (watcher_)
+ watcher_->Shutdown();
+}
+
+bool DrmDevice::Initialize() {
+ // Ignore devices that cannot perform modesetting.
+ if (!CanQueryForResources(file_.GetPlatformFile())) {
+ VLOG(2) << "Cannot query for resources for '" << device_path_.value()
+ << "'";
+ return false;
+ }
+
+ plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy());
+ if (!plane_manager_->Initialize(this)) {
+ LOG(ERROR) << "Failed to initialize the plane manager for "
+ << device_path_.value();
+ plane_manager_.reset();
+ return false;
+ }
+
+ return true;
+}
+
+void DrmDevice::InitializeTaskRunner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+ DCHECK(!task_runner_);
+ task_runner_ = task_runner;
+ watcher_ = new IOWatcher(file_.GetPlatformFile(), task_runner_);
+}
+
+ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) {
+ DCHECK(file_.IsValid());
+ return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id));
+}
+
+bool DrmDevice::SetCrtc(uint32_t crtc_id,
+ uint32_t framebuffer,
+ std::vector<uint32_t> connectors,
+ drmModeModeInfo* mode) {
+ DCHECK(file_.IsValid());
+ DCHECK(!connectors.empty());
+ DCHECK(mode);
+
+ TRACE_EVENT2("drm", "DrmDevice::SetCrtc", "crtc", crtc_id, "size",
+ gfx::Size(mode->hdisplay, mode->vdisplay).ToString());
+ return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0,
+ vector_as_array(&connectors), connectors.size(), mode);
+}
+
+bool DrmDevice::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) {
+ DCHECK(file_.IsValid());
+ // If there's no buffer then the CRTC was disabled.
+ if (!crtc->buffer_id)
+ return DisableCrtc(crtc->crtc_id);
+
+ DCHECK(!connectors.empty());
+
+ TRACE_EVENT1("drm", "DrmDevice::RestoreCrtc", "crtc", crtc->crtc_id);
+ return !drmModeSetCrtc(file_.GetPlatformFile(), crtc->crtc_id,
+ crtc->buffer_id, crtc->x, crtc->y,
+ vector_as_array(&connectors), connectors.size(),
+ &crtc->mode);
+}
+
+bool DrmDevice::DisableCrtc(uint32_t crtc_id) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::DisableCrtc", "crtc", crtc_id);
+ return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, 0, 0, 0, NULL, 0,
+ NULL);
+}
+
+ScopedDrmConnectorPtr DrmDevice::GetConnector(uint32_t connector_id) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::GetConnector", "connector", connector_id);
+ return ScopedDrmConnectorPtr(
+ drmModeGetConnector(file_.GetPlatformFile(), connector_id));
+}
+
+bool DrmDevice::AddFramebuffer(uint32_t width,
+ uint32_t height,
+ uint8_t depth,
+ uint8_t bpp,
+ uint32_t stride,
+ uint32_t handle,
+ uint32_t* framebuffer) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::AddFramebuffer", "handle", handle);
+ return !drmModeAddFB(file_.GetPlatformFile(), width, height, depth, bpp,
+ stride, handle, framebuffer);
+}
+
+bool DrmDevice::RemoveFramebuffer(uint32_t framebuffer) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::RemoveFramebuffer", "framebuffer",
+ framebuffer);
+ return !drmModeRmFB(file_.GetPlatformFile(), framebuffer);
+}
+
+bool DrmDevice::PageFlip(uint32_t crtc_id,
+ uint32_t framebuffer,
+ bool is_sync,
+ const PageFlipCallback& callback) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT2("drm", "DrmDevice::PageFlip", "crtc", crtc_id, "framebuffer",
+ framebuffer);
+
+ if (watcher_)
+ watcher_->SetPaused(is_sync);
+
+ // NOTE: Calling drmModeSetCrtc will immediately update the state, though
+ // callbacks to already scheduled page flips will be honored by the kernel.
+ scoped_ptr<PageFlipPayload> payload(
+ new PageFlipPayload(base::ThreadTaskRunnerHandle::Get(), callback));
+ if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer,
+ DRM_MODE_PAGE_FLIP_EVENT, payload.get())) {
+ // If successful the payload will be removed by a PageFlip event.
+ ignore_result(payload.release());
+
+ // If the flip was requested synchronous or if no watcher has been installed
+ // yet, then synchronously handle the page flip events.
+ if (is_sync || !watcher_) {
+ TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile());
+
+ drmEventContext event;
+ event.version = DRM_EVENT_CONTEXT_VERSION;
+ event.page_flip_handler = HandlePageFlipEventOnUI;
+ event.vblank_handler = nullptr;
+
+ drmHandleEvent(file_.GetPlatformFile(), &event);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool DrmDevice::PageFlipOverlay(uint32_t crtc_id,
+ uint32_t framebuffer,
+ const gfx::Rect& location,
+ const gfx::Rect& source,
+ int overlay_plane) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT2("drm", "DrmDevice::PageFlipOverlay", "crtc", crtc_id,
+ "framebuffer", framebuffer);
+ return !drmModeSetPlane(file_.GetPlatformFile(), overlay_plane, crtc_id,
+ framebuffer, 0, location.x(), location.y(),
+ location.width(), location.height(), source.x(),
+ source.y(), source.width(), source.height());
+}
+
+ScopedDrmFramebufferPtr DrmDevice::GetFramebuffer(uint32_t framebuffer) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::GetFramebuffer", "framebuffer", framebuffer);
+ return ScopedDrmFramebufferPtr(
+ drmModeGetFB(file_.GetPlatformFile(), framebuffer));
+}
+
+ScopedDrmPropertyPtr DrmDevice::GetProperty(drmModeConnector* connector,
+ const char* name) {
+ TRACE_EVENT2("drm", "DrmDevice::GetProperty", "connector",
+ connector->connector_id, "name", name);
+ for (int i = 0; i < connector->count_props; ++i) {
+ ScopedDrmPropertyPtr property(
+ drmModeGetProperty(file_.GetPlatformFile(), connector->props[i]));
+ if (!property)
+ continue;
+
+ if (strcmp(property->name, name) == 0)
+ return property.Pass();
+ }
+
+ return ScopedDrmPropertyPtr();
+}
+
+bool DrmDevice::SetProperty(uint32_t connector_id,
+ uint32_t property_id,
+ uint64_t value) {
+ DCHECK(file_.IsValid());
+ return !drmModeConnectorSetProperty(file_.GetPlatformFile(), connector_id,
+ property_id, value);
+}
+
+bool DrmDevice::GetCapability(uint64_t capability, uint64_t* value) {
+ DCHECK(file_.IsValid());
+ return !drmGetCap(file_.GetPlatformFile(), capability, value);
+}
+
+ScopedDrmPropertyBlobPtr DrmDevice::GetPropertyBlob(drmModeConnector* connector,
+ const char* name) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT2("drm", "DrmDevice::GetPropertyBlob", "connector",
+ connector->connector_id, "name", name);
+ for (int i = 0; i < connector->count_props; ++i) {
+ ScopedDrmPropertyPtr property(
+ drmModeGetProperty(file_.GetPlatformFile(), connector->props[i]));
+ if (!property)
+ continue;
+
+ if (strcmp(property->name, name) == 0 &&
+ property->flags & DRM_MODE_PROP_BLOB)
+ return ScopedDrmPropertyBlobPtr(drmModeGetPropertyBlob(
+ file_.GetPlatformFile(), connector->prop_values[i]));
+ }
+
+ return ScopedDrmPropertyBlobPtr();
+}
+
+bool DrmDevice::SetCursor(uint32_t crtc_id,
+ uint32_t handle,
+ const gfx::Size& size) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::SetCursor", "handle", handle);
+ return !drmModeSetCursor(file_.GetPlatformFile(), crtc_id, handle,
+ size.width(), size.height());
+}
+
+bool DrmDevice::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
+ DCHECK(file_.IsValid());
+ return !drmModeMoveCursor(file_.GetPlatformFile(), crtc_id, point.x(),
+ point.y());
+}
+
+bool DrmDevice::CreateDumbBuffer(const SkImageInfo& info,
+ uint32_t* handle,
+ uint32_t* stride,
+ void** pixels) {
+ DCHECK(file_.IsValid());
+
+ TRACE_EVENT0("drm", "DrmDevice::CreateDumbBuffer");
+ if (!DrmCreateDumbBuffer(file_.GetPlatformFile(), info, handle, stride))
+ return false;
+
+ if (!MapDumbBuffer(file_.GetPlatformFile(), *handle,
+ info.getSafeSize(*stride), pixels)) {
+ DrmDestroyDumbBuffer(file_.GetPlatformFile(), *handle);
+ return false;
+ }
+
+ return true;
+}
+
+void DrmDevice::DestroyDumbBuffer(const SkImageInfo& info,
+ uint32_t handle,
+ uint32_t stride,
+ void* pixels) {
+ DCHECK(file_.IsValid());
+ TRACE_EVENT1("drm", "DrmDevice::DestroyDumbBuffer", "handle", handle);
+ munmap(pixels, info.getSafeSize(stride));
+ DrmDestroyDumbBuffer(file_.GetPlatformFile(), handle);
+}
+
+bool DrmDevice::SetMaster() {
+ DCHECK(file_.IsValid());
+ return (drmSetMaster(file_.GetPlatformFile()) == 0);
+}
+
+bool DrmDevice::DropMaster() {
+ DCHECK(file_.IsValid());
+ return (drmDropMaster(file_.GetPlatformFile()) == 0);
+}
+
+} // namespace ui