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..faf10e231bb97413e722d3a230edef3bfd688834 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,17 @@ namespace ui { |
namespace { |
+struct PageFlipPayload { |
+ PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner, |
+ const DriWrapper::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; |
+ DriWrapper::PageFlipCallback callback; |
+}; |
+ |
bool DrmCreateDumbBuffer(int fd, |
const SkImageInfo& info, |
uint32_t* handle, |
@@ -55,16 +69,95 @@ 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)); |
+ } |
+ |
+ void Shutdown() { |
+ io_task_runner_->PostTask(FROM_HERE, |
+ base::Bind(&IOWatcher::UnregisterOnIO, this)); |
+ } |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<IOWatcher>; |
+ |
+ ~IOWatcher() override {} |
+ |
+ 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()); |
+ 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()); |
} |
DriWrapper::~DriWrapper() { |
if (fd_ >= 0) |
close(fd_); |
+ |
+ if (watcher_) |
+ watcher_->Shutdown(); |
} |
void DriWrapper::Initialize() { |
@@ -75,6 +168,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 +264,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 +381,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, |