Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/ozone/platform/dri/dri_wrapper.h" | 5 #include "ui/ozone/platform/dri/dri_wrapper.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <sys/mman.h> | 8 #include <sys/mman.h> |
| 9 #include <unistd.h> | 9 #include <unistd.h> |
| 10 #include <xf86drm.h> | 10 #include <xf86drm.h> |
| 11 #include <xf86drmMode.h> | 11 #include <xf86drmMode.h> |
| 12 | 12 |
| 13 #include "base/debug/trace_event.h" | 13 #include "base/debug/trace_event.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/message_loop/message_loop.h" | |
| 15 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
| 17 #include "base/task_runner.h" | |
| 18 #include "base/thread_task_runner_handle.h" | |
| 16 #include "third_party/skia/include/core/SkImageInfo.h" | 19 #include "third_party/skia/include/core/SkImageInfo.h" |
| 17 #include "ui/ozone/platform/dri/dri_util.h" | 20 #include "ui/ozone/platform/dri/dri_util.h" |
| 18 #include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" | 21 #include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" |
| 19 | 22 |
| 20 namespace ui { | 23 namespace ui { |
| 21 | 24 |
| 22 namespace { | 25 namespace { |
| 23 | 26 |
| 27 struct PageFlipPayload { | |
| 28 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
| |
| 29 const DriWrapper::PageFlipCallback& callback) | |
| 30 : task_runner(task_runner), callback(callback) {} | |
| 31 | |
| 32 scoped_refptr<base::TaskRunner> task_runner; | |
| 33 DriWrapper::PageFlipCallback callback; | |
| 34 }; | |
| 35 | |
| 24 bool DrmCreateDumbBuffer(int fd, | 36 bool DrmCreateDumbBuffer(int fd, |
| 25 const SkImageInfo& info, | 37 const SkImageInfo& info, |
| 26 uint32_t* handle, | 38 uint32_t* handle, |
| 27 uint32_t* stride) { | 39 uint32_t* stride) { |
| 28 struct drm_mode_create_dumb request; | 40 struct drm_mode_create_dumb request; |
| 29 memset(&request, 0, sizeof(request)); | 41 memset(&request, 0, sizeof(request)); |
| 30 request.width = info.width(); | 42 request.width = info.width(); |
| 31 request.height = info.height(); | 43 request.height = info.height(); |
| 32 request.bpp = info.bytesPerPixel() << 3; | 44 request.bpp = info.bytesPerPixel() << 3; |
| 33 request.flags = 0; | 45 request.flags = 0; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 48 return true; | 60 return true; |
| 49 } | 61 } |
| 50 | 62 |
| 51 void DrmDestroyDumbBuffer(int fd, uint32_t handle) { | 63 void DrmDestroyDumbBuffer(int fd, uint32_t handle) { |
| 52 struct drm_mode_destroy_dumb destroy_request; | 64 struct drm_mode_destroy_dumb destroy_request; |
| 53 memset(&destroy_request, 0, sizeof(destroy_request)); | 65 memset(&destroy_request, 0, sizeof(destroy_request)); |
| 54 destroy_request.handle = handle; | 66 destroy_request.handle = handle; |
| 55 drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); | 67 drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); |
| 56 } | 68 } |
| 57 | 69 |
| 70 void HandlePageFlipEventOnIO(int fd, | |
| 71 unsigned int frame, | |
| 72 unsigned int seconds, | |
| 73 unsigned int useconds, | |
| 74 void* data) { | |
| 75 scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); | |
| 76 payload->task_runner->PostTask( | |
| 77 FROM_HERE, base::Bind(payload->callback, frame, seconds, useconds)); | |
| 78 } | |
| 79 | |
| 80 void HandlePageFlipEventOnUI(int fd, | |
| 81 unsigned int frame, | |
| 82 unsigned int seconds, | |
| 83 unsigned int useconds, | |
| 84 void* data) { | |
| 85 scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); | |
| 86 payload->callback.Run(frame, seconds, useconds); | |
| 87 } | |
| 88 | |
| 58 } // namespace | 89 } // namespace |
| 59 | 90 |
| 60 DriWrapper::DriWrapper(const char* device_path) | 91 class DriWrapper::IOWatcher |
| 61 : fd_(-1), device_path_(device_path) { | 92 : public base::RefCountedThreadSafe<DriWrapper::IOWatcher>, |
| 93 public base::MessagePumpLibevent::Watcher { | |
| 94 public: | |
| 95 IOWatcher(int fd, | |
| 96 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) | |
| 97 : io_task_runner_(io_task_runner) { | |
| 98 io_task_runner_->PostTask(FROM_HERE, | |
| 99 base::Bind(&IOWatcher::RegisterOnIO, this, fd)); | |
| 100 } | |
| 101 | |
| 102 private: | |
| 103 friend class base::RefCountedThreadSafe<IOWatcher>; | |
| 104 | |
| 105 ~IOWatcher() override { | |
| 106 io_task_runner_->PostTask(FROM_HERE, | |
| 107 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()
| |
| 108 } | |
| 109 | |
| 110 void RegisterOnIO(int fd) { | |
| 111 DCHECK(base::MessageLoopForIO::IsCurrent()); | |
| 112 base::MessageLoopForIO::current()->WatchFileDescriptor( | |
| 113 fd, true, base::MessageLoopForIO::WATCH_READ, &controller_, this); | |
| 114 } | |
| 115 | |
| 116 void UnregisterOnIO() { | |
| 117 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
| |
| 118 controller_.StopWatchingFileDescriptor(); | |
| 119 } | |
| 120 | |
| 121 // base::MessagePumpLibevent::Watcher overrides: | |
| 122 void OnFileCanReadWithoutBlocking(int fd) override { | |
| 123 DCHECK(base::MessageLoopForIO::IsCurrent()); | |
| 124 TRACE_EVENT1("dri", "OnDrmEvent", "socket", fd); | |
| 125 | |
| 126 drmEventContext event; | |
| 127 event.version = DRM_EVENT_CONTEXT_VERSION; | |
| 128 event.page_flip_handler = HandlePageFlipEventOnIO; | |
| 129 event.vblank_handler = nullptr; | |
| 130 | |
| 131 drmHandleEvent(fd, &event); | |
| 132 } | |
| 133 | |
| 134 void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } | |
| 135 | |
| 136 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | |
| 137 | |
| 138 base::MessagePumpLibevent::FileDescriptorWatcher controller_; | |
| 139 | |
| 140 DISALLOW_COPY_AND_ASSIGN(IOWatcher); | |
| 141 }; | |
| 142 | |
| 143 DriWrapper::DriWrapper(const char* device_path, bool software_mode) | |
| 144 : fd_(-1), | |
| 145 software_mode_(software_mode), | |
| 146 device_path_(device_path), | |
| 147 io_thread_("DriIOThread") { | |
| 62 plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); | 148 plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); |
| 63 } | 149 } |
| 64 | 150 |
| 65 DriWrapper::~DriWrapper() { | 151 DriWrapper::~DriWrapper() { |
| 66 if (fd_ >= 0) | 152 if (fd_ >= 0) |
| 67 close(fd_); | 153 close(fd_); |
| 68 } | 154 } |
| 69 | 155 |
| 70 void DriWrapper::Initialize() { | 156 void DriWrapper::Initialize() { |
| 71 fd_ = open(device_path_, O_RDWR | O_CLOEXEC); | 157 fd_ = open(device_path_, O_RDWR | O_CLOEXEC); |
| 72 if (fd_ < 0) | 158 if (fd_ < 0) |
| 73 PLOG(FATAL) << "open: " << device_path_; | 159 PLOG(FATAL) << "open: " << device_path_; |
| 74 if (!plane_manager_->Initialize(this)) | 160 if (!plane_manager_->Initialize(this)) |
| 75 LOG(ERROR) << "Failed to initialize the plane manager"; | 161 LOG(ERROR) << "Failed to initialize the plane manager"; |
| 76 } | 162 } |
| 77 | 163 |
| 164 void DriWrapper::InitializeIOWatcher() { | |
| 165 if (!software_mode_ && !watcher_) { | |
| 166 if (!io_thread_.StartWithOptions( | |
| 167 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) | |
| 168 LOG(FATAL) << "Failed to start the IO helper thread"; | |
| 169 | |
| 170 watcher_ = new IOWatcher(fd_, io_thread_.task_runner()); | |
| 171 } | |
| 172 } | |
| 173 | |
| 78 ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) { | 174 ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) { |
| 79 DCHECK(fd_ >= 0); | 175 DCHECK(fd_ >= 0); |
| 80 return ScopedDrmCrtcPtr(drmModeGetCrtc(fd_, crtc_id)); | 176 return ScopedDrmCrtcPtr(drmModeGetCrtc(fd_, crtc_id)); |
| 81 } | 177 } |
| 82 | 178 |
| 83 bool DriWrapper::SetCrtc(uint32_t crtc_id, | 179 bool DriWrapper::SetCrtc(uint32_t crtc_id, |
| 84 uint32_t framebuffer, | 180 uint32_t framebuffer, |
| 85 std::vector<uint32_t> connectors, | 181 std::vector<uint32_t> connectors, |
| 86 drmModeModeInfo* mode) { | 182 drmModeModeInfo* mode) { |
| 87 DCHECK(fd_ >= 0); | 183 DCHECK(fd_ >= 0); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 | 250 |
| 155 bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) { | 251 bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) { |
| 156 DCHECK(fd_ >= 0); | 252 DCHECK(fd_ >= 0); |
| 157 TRACE_EVENT1("dri", "DriWrapper::RemoveFramebuffer", | 253 TRACE_EVENT1("dri", "DriWrapper::RemoveFramebuffer", |
| 158 "framebuffer", framebuffer); | 254 "framebuffer", framebuffer); |
| 159 return !drmModeRmFB(fd_, framebuffer); | 255 return !drmModeRmFB(fd_, framebuffer); |
| 160 } | 256 } |
| 161 | 257 |
| 162 bool DriWrapper::PageFlip(uint32_t crtc_id, | 258 bool DriWrapper::PageFlip(uint32_t crtc_id, |
| 163 uint32_t framebuffer, | 259 uint32_t framebuffer, |
| 164 void* data) { | 260 const PageFlipCallback& callback) { |
| 165 DCHECK(fd_ >= 0); | 261 DCHECK(fd_ >= 0); |
| 166 TRACE_EVENT2("dri", "DriWrapper::PageFlip", | 262 TRACE_EVENT2("dri", "DriWrapper::PageFlip", |
| 167 "crtc", crtc_id, | 263 "crtc", crtc_id, |
| 168 "framebuffer", framebuffer); | 264 "framebuffer", framebuffer); |
| 169 return !drmModePageFlip(fd_, | 265 |
| 170 crtc_id, | 266 // NOTE: Calling drmModeSetCrtc will immediately update the state, though |
| 171 framebuffer, | 267 // callbacks to already scheduled page flips will be honored by the kernel. |
| 172 DRM_MODE_PAGE_FLIP_EVENT, | 268 scoped_ptr<PageFlipPayload> payload( |
| 173 data); | 269 new PageFlipPayload(base::ThreadTaskRunnerHandle::Get(), callback)); |
| 270 if (!drmModePageFlip(fd_, crtc_id, framebuffer, DRM_MODE_PAGE_FLIP_EVENT, | |
| 271 payload.get())) { | |
| 272 // If successful the payload will be removed by a PageFlip event. | |
| 273 ignore_result(payload.release()); | |
| 274 if (software_mode_) { | |
| 275 TRACE_EVENT1("dri", "OnDrmEvent", "socket", fd_); | |
| 276 | |
| 277 drmEventContext event; | |
| 278 event.version = DRM_EVENT_CONTEXT_VERSION; | |
| 279 event.page_flip_handler = HandlePageFlipEventOnUI; | |
| 280 event.vblank_handler = nullptr; | |
| 281 | |
| 282 drmHandleEvent(fd_, &event); | |
| 283 } else { | |
| 284 InitializeIOWatcher(); | |
| 285 } | |
| 286 | |
| 287 return true; | |
| 288 } | |
| 289 | |
| 290 return false; | |
| 174 } | 291 } |
| 175 | 292 |
| 176 bool DriWrapper::PageFlipOverlay(uint32_t crtc_id, | 293 bool DriWrapper::PageFlipOverlay(uint32_t crtc_id, |
| 177 uint32_t framebuffer, | 294 uint32_t framebuffer, |
| 178 const gfx::Rect& location, | 295 const gfx::Rect& location, |
| 179 const gfx::Rect& source, | 296 const gfx::Rect& source, |
| 180 int overlay_plane) { | 297 int overlay_plane) { |
| 181 DCHECK(fd_ >= 0); | 298 DCHECK(fd_ >= 0); |
| 182 TRACE_EVENT2("dri", "DriWrapper::PageFlipOverlay", | 299 TRACE_EVENT2("dri", "DriWrapper::PageFlipOverlay", |
| 183 "crtc", crtc_id, | 300 "crtc", crtc_id, |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 250 DCHECK(fd_ >= 0); | 367 DCHECK(fd_ >= 0); |
| 251 TRACE_EVENT1("dri", "DriWrapper::SetCursor", "handle", handle); | 368 TRACE_EVENT1("dri", "DriWrapper::SetCursor", "handle", handle); |
| 252 return !drmModeSetCursor(fd_, crtc_id, handle, size.width(), size.height()); | 369 return !drmModeSetCursor(fd_, crtc_id, handle, size.width(), size.height()); |
| 253 } | 370 } |
| 254 | 371 |
| 255 bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { | 372 bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { |
| 256 DCHECK(fd_ >= 0); | 373 DCHECK(fd_ >= 0); |
| 257 return !drmModeMoveCursor(fd_, crtc_id, point.x(), point.y()); | 374 return !drmModeMoveCursor(fd_, crtc_id, point.x(), point.y()); |
| 258 } | 375 } |
| 259 | 376 |
| 260 void DriWrapper::HandleEvent(drmEventContext& event) { | |
| 261 DCHECK(fd_ >= 0); | |
| 262 TRACE_EVENT0("dri", "DriWrapper::HandleEvent"); | |
| 263 drmHandleEvent(fd_, &event); | |
| 264 } | |
| 265 | |
| 266 bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info, | 377 bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info, |
| 267 uint32_t* handle, | 378 uint32_t* handle, |
| 268 uint32_t* stride, | 379 uint32_t* stride, |
| 269 void** pixels) { | 380 void** pixels) { |
| 270 DCHECK(fd_ >= 0); | 381 DCHECK(fd_ >= 0); |
| 271 | 382 |
| 272 TRACE_EVENT0("dri", "DriWrapper::CreateDumbBuffer"); | 383 TRACE_EVENT0("dri", "DriWrapper::CreateDumbBuffer"); |
| 273 if (!DrmCreateDumbBuffer(fd_, info, handle, stride)) | 384 if (!DrmCreateDumbBuffer(fd_, info, handle, stride)) |
| 274 return false; | 385 return false; |
| 275 | 386 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 295 DCHECK(fd_ >= 0); | 406 DCHECK(fd_ >= 0); |
| 296 return (drmSetMaster(fd_) == 0); | 407 return (drmSetMaster(fd_) == 0); |
| 297 } | 408 } |
| 298 | 409 |
| 299 bool DriWrapper::DropMaster() { | 410 bool DriWrapper::DropMaster() { |
| 300 DCHECK(fd_ >= 0); | 411 DCHECK(fd_ >= 0); |
| 301 return (drmDropMaster(fd_) == 0); | 412 return (drmDropMaster(fd_) == 0); |
| 302 } | 413 } |
| 303 | 414 |
| 304 } // namespace ui | 415 } // namespace ui |
| OLD | NEW |