| Index: ui/ozone/platform/drm/gpu/drm_device.cc
|
| diff --git a/ui/ozone/platform/drm/gpu/drm_device.cc b/ui/ozone/platform/drm/gpu/drm_device.cc
|
| index ed38a2c88a30fcf4277d598524d29a6962004e8d..49b6f5e6c83982aeebd471747b78d68837b05002 100644
|
| --- a/ui/ozone/platform/drm/gpu/drm_device.cc
|
| +++ b/ui/ozone/platform/drm/gpu/drm_device.cc
|
| @@ -29,6 +29,11 @@ namespace ui {
|
|
|
| namespace {
|
|
|
| +typedef base::Callback<void(uint32_t /* frame */,
|
| + uint32_t /* seconds */,
|
| + uint32_t /* useconds */,
|
| + uint64_t /* id */)> DrmEventHandler;
|
| +
|
| struct PageFlipPayload {
|
| PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner,
|
| const DrmDevice::PageFlipCallback& callback)
|
| @@ -73,23 +78,41 @@ bool DrmDestroyDumbBuffer(int fd, uint32_t handle) {
|
| return !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));
|
| -}
|
| +bool ProcessDrmEvent(int fd, const DrmEventHandler& callback) {
|
| + char buffer[1024];
|
| + int len = read(fd, buffer, sizeof(buffer));
|
| + if (len == 0)
|
| + return false;
|
| +
|
| + if (len < static_cast<int>(sizeof(drm_event))) {
|
| + PLOG(ERROR) << "Failed to read DRM event";
|
| + return false;
|
| + }
|
| +
|
| + int idx = 0;
|
| + while (idx < len) {
|
| + DCHECK_LE(static_cast<int>(sizeof(drm_event)), len - idx);
|
| + drm_event event;
|
| + memcpy(&event, &buffer[idx], sizeof(event));
|
| + switch (event.type) {
|
| + case DRM_EVENT_FLIP_COMPLETE: {
|
| + DCHECK_LE(static_cast<int>(sizeof(drm_event_vblank)), len - idx);
|
| + drm_event_vblank vblank;
|
| + memcpy(&vblank, &buffer[idx], sizeof(vblank));
|
| + callback.Run(vblank.sequence, vblank.tv_sec, vblank.tv_usec,
|
| + vblank.user_data);
|
| + } break;
|
| + case DRM_EVENT_VBLANK:
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| +
|
| + idx += event.length;
|
| + }
|
|
|
| -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);
|
| + return true;
|
| }
|
|
|
| bool CanQueryForResources(int fd) {
|
| @@ -102,13 +125,70 @@ bool CanQueryForResources(int fd) {
|
|
|
| } // namespace
|
|
|
| +class DrmDevice::PageFlipManager
|
| + : public base::RefCountedThreadSafe<DrmDevice::PageFlipManager> {
|
| + public:
|
| + PageFlipManager() : next_id_(0) {}
|
| +
|
| + void OnPageFlip(uint32_t frame,
|
| + uint32_t seconds,
|
| + uint32_t useconds,
|
| + uint64_t id) {
|
| + auto it =
|
| + std::find_if(callbacks_.begin(), callbacks_.end(), FindCallback(id));
|
| + if (it == callbacks_.end()) {
|
| + LOG(WARNING) << "Could not find callback for page flip id=" << id;
|
| + return;
|
| + }
|
| +
|
| + DrmDevice::PageFlipCallback callback = it->callback;
|
| + callbacks_.erase(it);
|
| + callback.Run(frame, seconds, useconds);
|
| + }
|
| +
|
| + uint64_t GetNextId() { return next_id_++; }
|
| +
|
| + void RegisterCallback(uint64_t id,
|
| + const DrmDevice::PageFlipCallback& callback) {
|
| + callbacks_.push_back({id, callback});
|
| + }
|
| +
|
| + private:
|
| + friend class base::RefCountedThreadSafe<DrmDevice::PageFlipManager>;
|
| + ~PageFlipManager() {}
|
| +
|
| + struct PageFlip {
|
| + uint64_t id;
|
| + DrmDevice::PageFlipCallback callback;
|
| + };
|
| +
|
| + struct FindCallback {
|
| + FindCallback(uint64_t id) : id(id) {}
|
| +
|
| + bool operator()(const PageFlip& flip) const { return flip.id == id; }
|
| +
|
| + uint64_t id;
|
| + };
|
| +
|
| + uint64_t next_id_;
|
| +
|
| + std::vector<PageFlip> callbacks_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PageFlipManager);
|
| +};
|
| +
|
| 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) {}
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
|
| + const scoped_refptr<DrmDevice::PageFlipManager>& page_flip_manager)
|
| + : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
| + io_task_runner_(io_task_runner),
|
| + page_flip_manager_(page_flip_manager),
|
| + paused_(true),
|
| + fd_(fd) {}
|
|
|
| void SetPaused(bool paused) {
|
| if (paused_ == paused)
|
| @@ -152,23 +232,33 @@ class DrmDevice::IOWatcher
|
| done->Signal();
|
| }
|
|
|
| + void OnPageFlipOnIO(uint32_t frame,
|
| + uint32_t seconds,
|
| + uint32_t useconds,
|
| + uint64_t id) {
|
| + main_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&DrmDevice::PageFlipManager::OnPageFlip, page_flip_manager_,
|
| + frame, seconds, useconds, id));
|
| + }
|
| +
|
| // 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);
|
| + if (!ProcessDrmEvent(
|
| + fd, base::Bind(&DrmDevice::IOWatcher::OnPageFlipOnIO, this)))
|
| + UnregisterOnIO();
|
| }
|
|
|
| void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); }
|
|
|
| + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
|
| scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
|
|
|
| + scoped_refptr<DrmDevice::PageFlipManager> page_flip_manager_;
|
| +
|
| base::MessagePumpLibevent::FileDescriptorWatcher controller_;
|
|
|
| bool paused_;
|
| @@ -181,14 +271,17 @@ 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) {
|
| + base::File::FLAG_WRITE),
|
| + page_flip_manager_(new PageFlipManager()) {
|
| 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()) {
|
| + : device_path_(device_path),
|
| + file_(file.Pass()),
|
| + page_flip_manager_(new PageFlipManager()) {
|
| }
|
|
|
| DrmDevice::~DrmDevice() {
|
| @@ -223,7 +316,8 @@ void DrmDevice::InitializeTaskRunner(
|
| const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
|
| DCHECK(!task_runner_);
|
| task_runner_ = task_runner;
|
| - watcher_ = new IOWatcher(file_.GetPlatformFile(), task_runner_);
|
| + watcher_ =
|
| + new IOWatcher(file_.GetPlatformFile(), task_runner_, page_flip_manager_);
|
| }
|
|
|
| ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) {
|
| @@ -307,24 +401,20 @@ bool DrmDevice::PageFlip(uint32_t crtc_id,
|
|
|
| // 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));
|
| + uint64_t id = page_flip_manager_->GetNextId();
|
| if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer,
|
| - DRM_MODE_PAGE_FLIP_EVENT, payload.get())) {
|
| + DRM_MODE_PAGE_FLIP_EVENT, reinterpret_cast<void*>(id))) {
|
| // If successful the payload will be removed by a PageFlip event.
|
| - ignore_result(payload.release());
|
| + page_flip_manager_->RegisterCallback(id, callback);
|
|
|
| // 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);
|
| + ProcessDrmEvent(
|
| + file_.GetPlatformFile(),
|
| + base::Bind(&PageFlipManager::OnPageFlip, page_flip_manager_));
|
| }
|
|
|
| return true;
|
|
|