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