Chromium Code Reviews| Index: ui/ozone/platform/dri/dri_wrapper.cc |
| diff --git a/ui/ozone/platform/dri/dri_wrapper.cc b/ui/ozone/platform/dri/dri_wrapper.cc |
| index e08fbfc7374aab8e15e4c0fe80e680b741279c13..948a2ab91173442de5aa1e05704ded11efe5998b 100644 |
| --- a/ui/ozone/platform/dri/dri_wrapper.cc |
| +++ b/ui/ozone/platform/dri/dri_wrapper.cc |
| @@ -12,7 +12,10 @@ |
| #include "base/debug/trace_event.h" |
| #include "base/logging.h" |
| +#include "base/message_loop/message_loop.h" |
| #include "base/stl_util.h" |
| +#include "base/task_runner.h" |
| +#include "base/thread_task_runner_handle.h" |
| #include "third_party/skia/include/core/SkImageInfo.h" |
| #include "ui/ozone/platform/dri/dri_util.h" |
| #include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" |
| @@ -21,6 +24,15 @@ namespace ui { |
| namespace { |
| +struct PageFlipPayload { |
| + PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner, |
|
alexst (slow to review)
2015/01/09 03:55:46
You should mention which thread this task runner b
dnicoara
2015/01/09 15:08:24
Added some comments. In principle it doesn't matte
|
| + const DriWrapper::PageFlipCallback& callback) |
| + : task_runner(task_runner), callback(callback) {} |
| + |
| + scoped_refptr<base::TaskRunner> task_runner; |
| + DriWrapper::PageFlipCallback callback; |
| +}; |
| + |
| bool DrmCreateDumbBuffer(int fd, |
| const SkImageInfo& info, |
| uint32_t* handle, |
| @@ -55,10 +67,84 @@ void DrmDestroyDumbBuffer(int fd, uint32_t 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); |
| +} |
| + |
| } // namespace |
| -DriWrapper::DriWrapper(const char* device_path) |
| - : fd_(-1), device_path_(device_path) { |
| +class DriWrapper::IOWatcher |
| + : public base::RefCountedThreadSafe<DriWrapper::IOWatcher>, |
| + public base::MessagePumpLibevent::Watcher { |
| + public: |
| + IOWatcher(int fd, |
| + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) |
| + : io_task_runner_(io_task_runner) { |
| + io_task_runner_->PostTask(FROM_HERE, |
| + base::Bind(&IOWatcher::RegisterOnIO, this, fd)); |
| + } |
| + |
| + private: |
| + friend class base::RefCountedThreadSafe<IOWatcher>; |
| + |
| + ~IOWatcher() override { |
| + io_task_runner_->PostTask(FROM_HERE, |
| + base::Bind(&IOWatcher::UnregisterOnIO, this)); |
|
alexst (slow to review)
2015/01/09 03:55:46
I am pretty sure this is not safe, we are in the d
dnicoara
2015/01/09 15:08:24
Doh! You are right, move the post in a Shutdown()
|
| + } |
| + |
| + void RegisterOnIO(int fd) { |
| + DCHECK(base::MessageLoopForIO::IsCurrent()); |
| + base::MessageLoopForIO::current()->WatchFileDescriptor( |
| + fd, true, base::MessageLoopForIO::WATCH_READ, &controller_, this); |
| + } |
| + |
| + void UnregisterOnIO() { |
| + DCHECK(base::MessageLoopForIO::IsCurrent()); |
|
alexst (slow to review)
2015/01/09 03:55:46
Is this checking that an IO type thread is current
dnicoara
2015/01/09 15:08:24
Yes. It would be hard to check which IO message lo
|
| + controller_.StopWatchingFileDescriptor(); |
| + } |
| + |
| + // base::MessagePumpLibevent::Watcher overrides: |
| + void OnFileCanReadWithoutBlocking(int fd) override { |
| + DCHECK(base::MessageLoopForIO::IsCurrent()); |
| + TRACE_EVENT1("dri", "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_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(IOWatcher); |
| +}; |
| + |
| +DriWrapper::DriWrapper(const char* device_path, bool software_mode) |
| + : fd_(-1), |
| + software_mode_(software_mode), |
| + device_path_(device_path), |
| + io_thread_("DriIOThread") { |
| plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); |
| } |
| @@ -75,6 +161,16 @@ void DriWrapper::Initialize() { |
| LOG(ERROR) << "Failed to initialize the plane manager"; |
| } |
| +void DriWrapper::InitializeIOWatcher() { |
| + if (!software_mode_ && !watcher_) { |
| + if (!io_thread_.StartWithOptions( |
| + base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) |
| + LOG(FATAL) << "Failed to start the IO helper thread"; |
| + |
| + watcher_ = new IOWatcher(fd_, io_thread_.task_runner()); |
| + } |
| +} |
| + |
| ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) { |
| DCHECK(fd_ >= 0); |
| return ScopedDrmCrtcPtr(drmModeGetCrtc(fd_, crtc_id)); |
| @@ -161,16 +257,37 @@ bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) { |
| bool DriWrapper::PageFlip(uint32_t crtc_id, |
| uint32_t framebuffer, |
| - void* data) { |
| + const PageFlipCallback& callback) { |
| DCHECK(fd_ >= 0); |
| TRACE_EVENT2("dri", "DriWrapper::PageFlip", |
| "crtc", crtc_id, |
| "framebuffer", framebuffer); |
| - return !drmModePageFlip(fd_, |
| - crtc_id, |
| - framebuffer, |
| - DRM_MODE_PAGE_FLIP_EVENT, |
| - data); |
| + |
| + // 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(fd_, 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 (software_mode_) { |
| + TRACE_EVENT1("dri", "OnDrmEvent", "socket", fd_); |
| + |
| + drmEventContext event; |
| + event.version = DRM_EVENT_CONTEXT_VERSION; |
| + event.page_flip_handler = HandlePageFlipEventOnUI; |
| + event.vblank_handler = nullptr; |
| + |
| + drmHandleEvent(fd_, &event); |
| + } else { |
| + InitializeIOWatcher(); |
| + } |
| + |
| + return true; |
| + } |
| + |
| + return false; |
| } |
| bool DriWrapper::PageFlipOverlay(uint32_t crtc_id, |
| @@ -257,12 +374,6 @@ bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { |
| return !drmModeMoveCursor(fd_, crtc_id, point.x(), point.y()); |
| } |
| -void DriWrapper::HandleEvent(drmEventContext& event) { |
| - DCHECK(fd_ >= 0); |
| - TRACE_EVENT0("dri", "DriWrapper::HandleEvent"); |
| - drmHandleEvent(fd_, &event); |
| -} |
| - |
| bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info, |
| uint32_t* handle, |
| uint32_t* stride, |