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/drm/gpu/drm_device.h" | 5 #include "ui/ozone/platform/drm/gpu/drm_device.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> |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h" | 22 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h" |
23 | 23 |
24 #if defined(USE_DRM_ATOMIC) | 24 #if defined(USE_DRM_ATOMIC) |
25 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h" | 25 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h" |
26 #endif | 26 #endif |
27 | 27 |
28 namespace ui { | 28 namespace ui { |
29 | 29 |
30 namespace { | 30 namespace { |
31 | 31 |
| 32 typedef base::Callback<void(uint32_t /* frame */, |
| 33 uint32_t /* seconds */, |
| 34 uint32_t /* useconds */, |
| 35 uint64_t /* id */)> DrmEventHandler; |
| 36 |
32 struct PageFlipPayload { | 37 struct PageFlipPayload { |
33 PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner, | 38 PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner, |
34 const DrmDevice::PageFlipCallback& callback) | 39 const DrmDevice::PageFlipCallback& callback) |
35 : task_runner(task_runner), callback(callback) {} | 40 : task_runner(task_runner), callback(callback) {} |
36 | 41 |
37 // Task runner for the thread scheduling the page flip event. This is used to | 42 // Task runner for the thread scheduling the page flip event. This is used to |
38 // run the callback on the same thread the callback was created on. | 43 // run the callback on the same thread the callback was created on. |
39 scoped_refptr<base::TaskRunner> task_runner; | 44 scoped_refptr<base::TaskRunner> task_runner; |
40 DrmDevice::PageFlipCallback callback; | 45 DrmDevice::PageFlipCallback callback; |
41 }; | 46 }; |
(...skipping 24 matching lines...) Expand all Loading... |
66 return true; | 71 return true; |
67 } | 72 } |
68 | 73 |
69 bool DrmDestroyDumbBuffer(int fd, uint32_t handle) { | 74 bool DrmDestroyDumbBuffer(int fd, uint32_t handle) { |
70 struct drm_mode_destroy_dumb destroy_request; | 75 struct drm_mode_destroy_dumb destroy_request; |
71 memset(&destroy_request, 0, sizeof(destroy_request)); | 76 memset(&destroy_request, 0, sizeof(destroy_request)); |
72 destroy_request.handle = handle; | 77 destroy_request.handle = handle; |
73 return !drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); | 78 return !drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); |
74 } | 79 } |
75 | 80 |
76 void HandlePageFlipEventOnIO(int fd, | 81 bool ProcessDrmEvent(int fd, const DrmEventHandler& callback) { |
77 unsigned int frame, | 82 char buffer[1024]; |
78 unsigned int seconds, | 83 int len = read(fd, buffer, sizeof(buffer)); |
79 unsigned int useconds, | 84 if (len == 0) |
80 void* data) { | 85 return false; |
81 scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); | |
82 payload->task_runner->PostTask( | |
83 FROM_HERE, base::Bind(payload->callback, frame, seconds, useconds)); | |
84 } | |
85 | 86 |
86 void HandlePageFlipEventOnUI(int fd, | 87 if (len < static_cast<int>(sizeof(drm_event))) { |
87 unsigned int frame, | 88 PLOG(ERROR) << "Failed to read DRM event"; |
88 unsigned int seconds, | 89 return false; |
89 unsigned int useconds, | 90 } |
90 void* data) { | 91 |
91 scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); | 92 int idx = 0; |
92 payload->callback.Run(frame, seconds, useconds); | 93 while (idx < len) { |
| 94 DCHECK_LE(static_cast<int>(sizeof(drm_event)), len - idx); |
| 95 drm_event event; |
| 96 memcpy(&event, &buffer[idx], sizeof(event)); |
| 97 switch (event.type) { |
| 98 case DRM_EVENT_FLIP_COMPLETE: { |
| 99 DCHECK_LE(static_cast<int>(sizeof(drm_event_vblank)), len - idx); |
| 100 drm_event_vblank vblank; |
| 101 memcpy(&vblank, &buffer[idx], sizeof(vblank)); |
| 102 callback.Run(vblank.sequence, vblank.tv_sec, vblank.tv_usec, |
| 103 vblank.user_data); |
| 104 } break; |
| 105 case DRM_EVENT_VBLANK: |
| 106 break; |
| 107 default: |
| 108 NOTREACHED(); |
| 109 break; |
| 110 } |
| 111 |
| 112 idx += event.length; |
| 113 } |
| 114 |
| 115 return true; |
93 } | 116 } |
94 | 117 |
95 bool CanQueryForResources(int fd) { | 118 bool CanQueryForResources(int fd) { |
96 drm_mode_card_res resources; | 119 drm_mode_card_res resources; |
97 memset(&resources, 0, sizeof(resources)); | 120 memset(&resources, 0, sizeof(resources)); |
98 // If there is no error getting DRM resources then assume this is a | 121 // If there is no error getting DRM resources then assume this is a |
99 // modesetting device. | 122 // modesetting device. |
100 return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources); | 123 return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources); |
101 } | 124 } |
102 | 125 |
103 } // namespace | 126 } // namespace |
104 | 127 |
| 128 class DrmDevice::PageFlipManager |
| 129 : public base::RefCountedThreadSafe<DrmDevice::PageFlipManager> { |
| 130 public: |
| 131 PageFlipManager() : next_id_(0) {} |
| 132 |
| 133 void OnPageFlip(uint32_t frame, |
| 134 uint32_t seconds, |
| 135 uint32_t useconds, |
| 136 uint64_t id) { |
| 137 auto it = |
| 138 std::find_if(callbacks_.begin(), callbacks_.end(), FindCallback(id)); |
| 139 if (it == callbacks_.end()) { |
| 140 LOG(WARNING) << "Could not find callback for page flip id=" << id; |
| 141 return; |
| 142 } |
| 143 |
| 144 DrmDevice::PageFlipCallback callback = it->callback; |
| 145 callbacks_.erase(it); |
| 146 callback.Run(frame, seconds, useconds); |
| 147 } |
| 148 |
| 149 uint64_t GetNextId() { return next_id_++; } |
| 150 |
| 151 void RegisterCallback(uint64_t id, |
| 152 const DrmDevice::PageFlipCallback& callback) { |
| 153 callbacks_.push_back({id, callback}); |
| 154 } |
| 155 |
| 156 private: |
| 157 friend class base::RefCountedThreadSafe<DrmDevice::PageFlipManager>; |
| 158 ~PageFlipManager() {} |
| 159 |
| 160 struct PageFlip { |
| 161 uint64_t id; |
| 162 DrmDevice::PageFlipCallback callback; |
| 163 }; |
| 164 |
| 165 struct FindCallback { |
| 166 FindCallback(uint64_t id) : id(id) {} |
| 167 |
| 168 bool operator()(const PageFlip& flip) const { return flip.id == id; } |
| 169 |
| 170 uint64_t id; |
| 171 }; |
| 172 |
| 173 uint64_t next_id_; |
| 174 |
| 175 std::vector<PageFlip> callbacks_; |
| 176 |
| 177 DISALLOW_COPY_AND_ASSIGN(PageFlipManager); |
| 178 }; |
| 179 |
105 class DrmDevice::IOWatcher | 180 class DrmDevice::IOWatcher |
106 : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>, | 181 : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>, |
107 public base::MessagePumpLibevent::Watcher { | 182 public base::MessagePumpLibevent::Watcher { |
108 public: | 183 public: |
109 IOWatcher(int fd, | 184 IOWatcher(int fd, |
110 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) | 185 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
111 : io_task_runner_(io_task_runner), paused_(true), fd_(fd) {} | 186 const scoped_refptr<DrmDevice::PageFlipManager>& page_flip_manager) |
| 187 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 188 io_task_runner_(io_task_runner), |
| 189 page_flip_manager_(page_flip_manager), |
| 190 paused_(true), |
| 191 fd_(fd) {} |
112 | 192 |
113 void SetPaused(bool paused) { | 193 void SetPaused(bool paused) { |
114 if (paused_ == paused) | 194 if (paused_ == paused) |
115 return; | 195 return; |
116 | 196 |
117 paused_ = paused; | 197 paused_ = paused; |
118 base::WaitableEvent done(false, false); | 198 base::WaitableEvent done(false, false); |
119 io_task_runner_->PostTask( | 199 io_task_runner_->PostTask( |
120 FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done)); | 200 FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done)); |
121 done.Wait(); | 201 done.Wait(); |
(...skipping 23 matching lines...) Expand all Loading... |
145 | 225 |
146 void SetPausedOnIO(base::WaitableEvent* done) { | 226 void SetPausedOnIO(base::WaitableEvent* done) { |
147 DCHECK(base::MessageLoopForIO::IsCurrent()); | 227 DCHECK(base::MessageLoopForIO::IsCurrent()); |
148 if (paused_) | 228 if (paused_) |
149 UnregisterOnIO(); | 229 UnregisterOnIO(); |
150 else | 230 else |
151 RegisterOnIO(); | 231 RegisterOnIO(); |
152 done->Signal(); | 232 done->Signal(); |
153 } | 233 } |
154 | 234 |
| 235 void OnPageFlipOnIO(uint32_t frame, |
| 236 uint32_t seconds, |
| 237 uint32_t useconds, |
| 238 uint64_t id) { |
| 239 main_task_runner_->PostTask( |
| 240 FROM_HERE, |
| 241 base::Bind(&DrmDevice::PageFlipManager::OnPageFlip, page_flip_manager_, |
| 242 frame, seconds, useconds, id)); |
| 243 } |
| 244 |
155 // base::MessagePumpLibevent::Watcher overrides: | 245 // base::MessagePumpLibevent::Watcher overrides: |
156 void OnFileCanReadWithoutBlocking(int fd) override { | 246 void OnFileCanReadWithoutBlocking(int fd) override { |
157 DCHECK(base::MessageLoopForIO::IsCurrent()); | 247 DCHECK(base::MessageLoopForIO::IsCurrent()); |
158 TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd); | 248 TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd); |
159 | 249 |
160 drmEventContext event; | 250 if (!ProcessDrmEvent( |
161 event.version = DRM_EVENT_CONTEXT_VERSION; | 251 fd, base::Bind(&DrmDevice::IOWatcher::OnPageFlipOnIO, this))) |
162 event.page_flip_handler = HandlePageFlipEventOnIO; | 252 UnregisterOnIO(); |
163 event.vblank_handler = nullptr; | |
164 | |
165 drmHandleEvent(fd, &event); | |
166 } | 253 } |
167 | 254 |
168 void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } | 255 void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } |
169 | 256 |
| 257 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
170 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | 258 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; |
171 | 259 |
| 260 scoped_refptr<DrmDevice::PageFlipManager> page_flip_manager_; |
| 261 |
172 base::MessagePumpLibevent::FileDescriptorWatcher controller_; | 262 base::MessagePumpLibevent::FileDescriptorWatcher controller_; |
173 | 263 |
174 bool paused_; | 264 bool paused_; |
175 int fd_; | 265 int fd_; |
176 | 266 |
177 DISALLOW_COPY_AND_ASSIGN(IOWatcher); | 267 DISALLOW_COPY_AND_ASSIGN(IOWatcher); |
178 }; | 268 }; |
179 | 269 |
180 DrmDevice::DrmDevice(const base::FilePath& device_path) | 270 DrmDevice::DrmDevice(const base::FilePath& device_path) |
181 : device_path_(device_path), | 271 : device_path_(device_path), |
182 file_(device_path, | 272 file_(device_path, |
183 base::File::FLAG_OPEN | base::File::FLAG_READ | | 273 base::File::FLAG_OPEN | base::File::FLAG_READ | |
184 base::File::FLAG_WRITE) { | 274 base::File::FLAG_WRITE), |
| 275 page_flip_manager_(new PageFlipManager()) { |
185 LOG_IF(FATAL, !file_.IsValid()) | 276 LOG_IF(FATAL, !file_.IsValid()) |
186 << "Failed to open '" << device_path_.value() | 277 << "Failed to open '" << device_path_.value() |
187 << "': " << base::File::ErrorToString(file_.error_details()); | 278 << "': " << base::File::ErrorToString(file_.error_details()); |
188 } | 279 } |
189 | 280 |
190 DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file) | 281 DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file) |
191 : device_path_(device_path), file_(file.Pass()) { | 282 : device_path_(device_path), |
| 283 file_(file.Pass()), |
| 284 page_flip_manager_(new PageFlipManager()) { |
192 } | 285 } |
193 | 286 |
194 DrmDevice::~DrmDevice() { | 287 DrmDevice::~DrmDevice() { |
195 if (watcher_) | 288 if (watcher_) |
196 watcher_->Shutdown(); | 289 watcher_->Shutdown(); |
197 } | 290 } |
198 | 291 |
199 bool DrmDevice::Initialize() { | 292 bool DrmDevice::Initialize() { |
200 // Ignore devices that cannot perform modesetting. | 293 // Ignore devices that cannot perform modesetting. |
201 if (!CanQueryForResources(file_.GetPlatformFile())) { | 294 if (!CanQueryForResources(file_.GetPlatformFile())) { |
(...skipping 14 matching lines...) Expand all Loading... |
216 return false; | 309 return false; |
217 } | 310 } |
218 | 311 |
219 return true; | 312 return true; |
220 } | 313 } |
221 | 314 |
222 void DrmDevice::InitializeTaskRunner( | 315 void DrmDevice::InitializeTaskRunner( |
223 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { | 316 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { |
224 DCHECK(!task_runner_); | 317 DCHECK(!task_runner_); |
225 task_runner_ = task_runner; | 318 task_runner_ = task_runner; |
226 watcher_ = new IOWatcher(file_.GetPlatformFile(), task_runner_); | 319 watcher_ = |
| 320 new IOWatcher(file_.GetPlatformFile(), task_runner_, page_flip_manager_); |
227 } | 321 } |
228 | 322 |
229 ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) { | 323 ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) { |
230 DCHECK(file_.IsValid()); | 324 DCHECK(file_.IsValid()); |
231 return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id)); | 325 return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id)); |
232 } | 326 } |
233 | 327 |
234 bool DrmDevice::SetCrtc(uint32_t crtc_id, | 328 bool DrmDevice::SetCrtc(uint32_t crtc_id, |
235 uint32_t framebuffer, | 329 uint32_t framebuffer, |
236 std::vector<uint32_t> connectors, | 330 std::vector<uint32_t> connectors, |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 const PageFlipCallback& callback) { | 394 const PageFlipCallback& callback) { |
301 DCHECK(file_.IsValid()); | 395 DCHECK(file_.IsValid()); |
302 TRACE_EVENT2("drm", "DrmDevice::PageFlip", "crtc", crtc_id, "framebuffer", | 396 TRACE_EVENT2("drm", "DrmDevice::PageFlip", "crtc", crtc_id, "framebuffer", |
303 framebuffer); | 397 framebuffer); |
304 | 398 |
305 if (watcher_) | 399 if (watcher_) |
306 watcher_->SetPaused(is_sync); | 400 watcher_->SetPaused(is_sync); |
307 | 401 |
308 // NOTE: Calling drmModeSetCrtc will immediately update the state, though | 402 // NOTE: Calling drmModeSetCrtc will immediately update the state, though |
309 // callbacks to already scheduled page flips will be honored by the kernel. | 403 // callbacks to already scheduled page flips will be honored by the kernel. |
310 scoped_ptr<PageFlipPayload> payload( | 404 uint64_t id = page_flip_manager_->GetNextId(); |
311 new PageFlipPayload(base::ThreadTaskRunnerHandle::Get(), callback)); | |
312 if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer, | 405 if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer, |
313 DRM_MODE_PAGE_FLIP_EVENT, payload.get())) { | 406 DRM_MODE_PAGE_FLIP_EVENT, reinterpret_cast<void*>(id))) { |
314 // If successful the payload will be removed by a PageFlip event. | 407 // If successful the payload will be removed by a PageFlip event. |
315 ignore_result(payload.release()); | 408 page_flip_manager_->RegisterCallback(id, callback); |
316 | 409 |
317 // If the flip was requested synchronous or if no watcher has been installed | 410 // If the flip was requested synchronous or if no watcher has been installed |
318 // yet, then synchronously handle the page flip events. | 411 // yet, then synchronously handle the page flip events. |
319 if (is_sync || !watcher_) { | 412 if (is_sync || !watcher_) { |
320 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); | 413 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); |
321 | 414 |
322 drmEventContext event; | 415 ProcessDrmEvent( |
323 event.version = DRM_EVENT_CONTEXT_VERSION; | 416 file_.GetPlatformFile(), |
324 event.page_flip_handler = HandlePageFlipEventOnUI; | 417 base::Bind(&PageFlipManager::OnPageFlip, page_flip_manager_)); |
325 event.vblank_handler = nullptr; | |
326 | |
327 drmHandleEvent(file_.GetPlatformFile(), &event); | |
328 } | 418 } |
329 | 419 |
330 return true; | 420 return true; |
331 } | 421 } |
332 | 422 |
333 return false; | 423 return false; |
334 } | 424 } |
335 | 425 |
336 bool DrmDevice::PageFlipOverlay(uint32_t crtc_id, | 426 bool DrmDevice::PageFlipOverlay(uint32_t crtc_id, |
337 uint32_t framebuffer, | 427 uint32_t framebuffer, |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
488 DCHECK(file_.IsValid()); | 578 DCHECK(file_.IsValid()); |
489 return (drmSetMaster(file_.GetPlatformFile()) == 0); | 579 return (drmSetMaster(file_.GetPlatformFile()) == 0); |
490 } | 580 } |
491 | 581 |
492 bool DrmDevice::DropMaster() { | 582 bool DrmDevice::DropMaster() { |
493 DCHECK(file_.IsValid()); | 583 DCHECK(file_.IsValid()); |
494 return (drmDropMaster(file_.GetPlatformFile()) == 0); | 584 return (drmDropMaster(file_.GetPlatformFile()) == 0); |
495 } | 585 } |
496 | 586 |
497 } // namespace ui | 587 } // namespace ui |
OLD | NEW |