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/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 void DrmDestroyDumbBuffer(int fd, uint32_t handle) { | 74 void 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 drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); | 78 drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); |
| 74 } | 79 } |
| 75 | 80 |
| 76 void HandlePageFlipEventOnIO(int fd, | 81 void 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; |
| 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; |
| 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 drm_event* event = reinterpret_cast<drm_event*>(&buffer[idx]); | |
|
spang
2015/04/27 17:23:38
You can't cast a char* to an arbitrary struct. It'
dnicoara
2015/04/27 20:22:22
Why would it be undefined behavior to cast between
dnicoara
2015/04/28 14:42:49
Done.
| |
| 95 switch (event->type) { | |
| 96 case DRM_EVENT_FLIP_COMPLETE: { | |
| 97 drm_event_vblank* vblank = reinterpret_cast<drm_event_vblank*>(event); | |
| 98 callback.Run(vblank->sequence, vblank->tv_sec, vblank->tv_usec, | |
| 99 vblank->user_data); | |
| 100 } break; | |
| 101 case DRM_EVENT_VBLANK: | |
| 102 break; | |
| 103 default: | |
| 104 NOTREACHED(); | |
| 105 break; | |
| 106 } | |
| 107 | |
| 108 idx += event->length; | |
| 109 } | |
| 93 } | 110 } |
| 94 | 111 |
| 95 bool CanQueryForResources(int fd) { | 112 bool CanQueryForResources(int fd) { |
| 96 drm_mode_card_res resources; | 113 drm_mode_card_res resources; |
| 97 memset(&resources, 0, sizeof(resources)); | 114 memset(&resources, 0, sizeof(resources)); |
| 98 // If there is no error getting DRM resources then assume this is a | 115 // If there is no error getting DRM resources then assume this is a |
| 99 // modesetting device. | 116 // modesetting device. |
| 100 return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources); | 117 return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources); |
| 101 } | 118 } |
| 102 | 119 |
| 103 } // namespace | 120 } // namespace |
| 104 | 121 |
| 122 class DrmDevice::PageFlipManager | |
| 123 : public base::RefCountedThreadSafe<DrmDevice::PageFlipManager> { | |
| 124 public: | |
| 125 PageFlipManager() : next_id_(0) {} | |
| 126 ~PageFlipManager() {} | |
| 127 | |
| 128 void OnPageFlip(uint32_t frame, | |
| 129 uint32_t seconds, | |
| 130 uint32_t useconds, | |
| 131 uint64_t id) { | |
| 132 auto it = callback_map_.find(id); | |
| 133 if (it == callback_map_.end()) { | |
| 134 LOG(WARNING) << "Could not find callback for page flip id=" << id; | |
| 135 return; | |
| 136 } | |
| 137 | |
| 138 it->second.Run(frame, seconds, useconds); | |
| 139 callback_map_.erase(it); | |
| 140 } | |
| 141 | |
| 142 uint64_t GetNextId() { return next_id_++; } | |
| 143 | |
| 144 void RegisterCallback(uint64_t id, | |
| 145 const DrmDevice::PageFlipCallback& callback) { | |
| 146 DCHECK(callback_map_.find(id) == callback_map_.end()); | |
| 147 callback_map_.insert(std::make_pair(id, callback)); | |
| 148 } | |
| 149 | |
| 150 private: | |
| 151 uint64_t next_id_; | |
| 152 | |
| 153 std::map<uint64_t, DrmDevice::PageFlipCallback> callback_map_; | |
|
spang
2015/04/27 17:23:38
vector?
dnicoara
2015/04/27 20:22:22
Why vector? ... I suppose the number of callbacks
spang
2015/04/27 20:53:42
You'll only have 1-3 elements right? vector is a b
dnicoara
2015/04/28 14:42:48
Done.
| |
| 154 | |
| 155 DISALLOW_COPY_AND_ASSIGN(PageFlipManager); | |
| 156 }; | |
| 157 | |
| 105 class DrmDevice::IOWatcher | 158 class DrmDevice::IOWatcher |
| 106 : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>, | 159 : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>, |
| 107 public base::MessagePumpLibevent::Watcher { | 160 public base::MessagePumpLibevent::Watcher { |
| 108 public: | 161 public: |
| 109 IOWatcher(int fd, | 162 IOWatcher(int fd, |
| 110 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) | 163 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
| 111 : io_task_runner_(io_task_runner), paused_(true), fd_(fd) {} | 164 const scoped_refptr<DrmDevice::PageFlipManager>& page_flip_manager) |
| 165 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 166 io_task_runner_(io_task_runner), | |
| 167 page_flip_manager_(page_flip_manager), | |
| 168 paused_(true), | |
| 169 fd_(fd) {} | |
| 112 | 170 |
| 113 void SetPaused(bool paused) { | 171 void SetPaused(bool paused) { |
| 114 if (paused_ == paused) | 172 if (paused_ == paused) |
| 115 return; | 173 return; |
| 116 | 174 |
| 117 paused_ = paused; | 175 paused_ = paused; |
| 118 base::WaitableEvent done(false, false); | 176 base::WaitableEvent done(false, false); |
| 119 io_task_runner_->PostTask( | 177 io_task_runner_->PostTask( |
| 120 FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done)); | 178 FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done)); |
| 121 done.Wait(); | 179 done.Wait(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 145 | 203 |
| 146 void SetPausedOnIO(base::WaitableEvent* done) { | 204 void SetPausedOnIO(base::WaitableEvent* done) { |
| 147 DCHECK(base::MessageLoopForIO::IsCurrent()); | 205 DCHECK(base::MessageLoopForIO::IsCurrent()); |
| 148 if (paused_) | 206 if (paused_) |
| 149 UnregisterOnIO(); | 207 UnregisterOnIO(); |
| 150 else | 208 else |
| 151 RegisterOnIO(); | 209 RegisterOnIO(); |
| 152 done->Signal(); | 210 done->Signal(); |
| 153 } | 211 } |
| 154 | 212 |
| 213 void OnPageFlipOnIO(uint32_t frame, | |
| 214 uint32_t seconds, | |
| 215 uint32_t useconds, | |
| 216 uint64_t id) { | |
| 217 main_task_runner_->PostTask( | |
| 218 FROM_HERE, | |
| 219 base::Bind(&DrmDevice::PageFlipManager::OnPageFlip, page_flip_manager_, | |
| 220 frame, seconds, useconds, id)); | |
| 221 } | |
| 222 | |
| 155 // base::MessagePumpLibevent::Watcher overrides: | 223 // base::MessagePumpLibevent::Watcher overrides: |
| 156 void OnFileCanReadWithoutBlocking(int fd) override { | 224 void OnFileCanReadWithoutBlocking(int fd) override { |
| 157 DCHECK(base::MessageLoopForIO::IsCurrent()); | 225 DCHECK(base::MessageLoopForIO::IsCurrent()); |
| 158 TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd); | 226 TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd); |
| 159 | 227 |
| 160 drmEventContext event; | 228 ProcessDrmEvent(fd, |
| 161 event.version = DRM_EVENT_CONTEXT_VERSION; | 229 base::Bind(&DrmDevice::IOWatcher::OnPageFlipOnIO, this)); |
| 162 event.page_flip_handler = HandlePageFlipEventOnIO; | |
| 163 event.vblank_handler = nullptr; | |
| 164 | |
| 165 drmHandleEvent(fd, &event); | |
| 166 } | 230 } |
| 167 | 231 |
| 168 void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } | 232 void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } |
| 169 | 233 |
| 234 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | |
| 170 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | 235 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; |
| 171 | 236 |
| 237 scoped_refptr<DrmDevice::PageFlipManager> page_flip_manager_; | |
| 238 | |
| 172 base::MessagePumpLibevent::FileDescriptorWatcher controller_; | 239 base::MessagePumpLibevent::FileDescriptorWatcher controller_; |
| 173 | 240 |
| 174 bool paused_; | 241 bool paused_; |
| 175 int fd_; | 242 int fd_; |
| 176 | 243 |
| 177 DISALLOW_COPY_AND_ASSIGN(IOWatcher); | 244 DISALLOW_COPY_AND_ASSIGN(IOWatcher); |
| 178 }; | 245 }; |
| 179 | 246 |
| 180 DrmDevice::DrmDevice(const base::FilePath& device_path) | 247 DrmDevice::DrmDevice(const base::FilePath& device_path) |
| 181 : device_path_(device_path), | 248 : device_path_(device_path), |
| 182 file_(device_path, | 249 file_(device_path, |
| 183 base::File::FLAG_OPEN | base::File::FLAG_READ | | 250 base::File::FLAG_OPEN | base::File::FLAG_READ | |
| 184 base::File::FLAG_WRITE) { | 251 base::File::FLAG_WRITE), |
| 252 page_flip_manager_(new PageFlipManager()) { | |
| 185 LOG_IF(FATAL, !file_.IsValid()) | 253 LOG_IF(FATAL, !file_.IsValid()) |
| 186 << "Failed to open '" << device_path_.value() | 254 << "Failed to open '" << device_path_.value() |
| 187 << "': " << base::File::ErrorToString(file_.error_details()); | 255 << "': " << base::File::ErrorToString(file_.error_details()); |
| 188 } | 256 } |
| 189 | 257 |
| 190 DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file) | 258 DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file) |
| 191 : device_path_(device_path), file_(file.Pass()) { | 259 : device_path_(device_path), |
| 260 file_(file.Pass()), | |
| 261 page_flip_manager_(new PageFlipManager()) { | |
| 192 } | 262 } |
| 193 | 263 |
| 194 DrmDevice::~DrmDevice() { | 264 DrmDevice::~DrmDevice() { |
| 195 if (watcher_) | 265 if (watcher_) |
| 196 watcher_->Shutdown(); | 266 watcher_->Shutdown(); |
| 197 } | 267 } |
| 198 | 268 |
| 199 bool DrmDevice::Initialize() { | 269 bool DrmDevice::Initialize() { |
| 200 // Ignore devices that cannot perform modesetting. | 270 // Ignore devices that cannot perform modesetting. |
| 201 if (!CanQueryForResources(file_.GetPlatformFile())) { | 271 if (!CanQueryForResources(file_.GetPlatformFile())) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 216 return false; | 286 return false; |
| 217 } | 287 } |
| 218 | 288 |
| 219 return true; | 289 return true; |
| 220 } | 290 } |
| 221 | 291 |
| 222 void DrmDevice::InitializeTaskRunner( | 292 void DrmDevice::InitializeTaskRunner( |
| 223 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { | 293 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { |
| 224 DCHECK(!task_runner_); | 294 DCHECK(!task_runner_); |
| 225 task_runner_ = task_runner; | 295 task_runner_ = task_runner; |
| 226 watcher_ = new IOWatcher(file_.GetPlatformFile(), task_runner_); | 296 watcher_ = |
| 297 new IOWatcher(file_.GetPlatformFile(), task_runner_, page_flip_manager_); | |
| 227 } | 298 } |
| 228 | 299 |
| 229 ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) { | 300 ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) { |
| 230 DCHECK(file_.IsValid()); | 301 DCHECK(file_.IsValid()); |
| 231 return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id)); | 302 return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id)); |
| 232 } | 303 } |
| 233 | 304 |
| 234 bool DrmDevice::SetCrtc(uint32_t crtc_id, | 305 bool DrmDevice::SetCrtc(uint32_t crtc_id, |
| 235 uint32_t framebuffer, | 306 uint32_t framebuffer, |
| 236 std::vector<uint32_t> connectors, | 307 std::vector<uint32_t> connectors, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 300 const PageFlipCallback& callback) { | 371 const PageFlipCallback& callback) { |
| 301 DCHECK(file_.IsValid()); | 372 DCHECK(file_.IsValid()); |
| 302 TRACE_EVENT2("drm", "DrmDevice::PageFlip", "crtc", crtc_id, "framebuffer", | 373 TRACE_EVENT2("drm", "DrmDevice::PageFlip", "crtc", crtc_id, "framebuffer", |
| 303 framebuffer); | 374 framebuffer); |
| 304 | 375 |
| 305 if (watcher_) | 376 if (watcher_) |
| 306 watcher_->SetPaused(is_sync); | 377 watcher_->SetPaused(is_sync); |
| 307 | 378 |
| 308 // NOTE: Calling drmModeSetCrtc will immediately update the state, though | 379 // NOTE: Calling drmModeSetCrtc will immediately update the state, though |
| 309 // callbacks to already scheduled page flips will be honored by the kernel. | 380 // callbacks to already scheduled page flips will be honored by the kernel. |
| 310 scoped_ptr<PageFlipPayload> payload( | 381 uint64_t id = page_flip_manager_->GetNextId(); |
| 311 new PageFlipPayload(base::ThreadTaskRunnerHandle::Get(), callback)); | |
| 312 if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer, | 382 if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer, |
| 313 DRM_MODE_PAGE_FLIP_EVENT, payload.get())) { | 383 DRM_MODE_PAGE_FLIP_EVENT, reinterpret_cast<void*>(id))) { |
| 314 // If successful the payload will be removed by a PageFlip event. | 384 // If successful the payload will be removed by a PageFlip event. |
| 315 ignore_result(payload.release()); | 385 page_flip_manager_->RegisterCallback(id, callback); |
| 316 | 386 |
| 317 // If the flip was requested synchronous or if no watcher has been installed | 387 // If the flip was requested synchronous or if no watcher has been installed |
| 318 // yet, then synchronously handle the page flip events. | 388 // yet, then synchronously handle the page flip events. |
| 319 if (is_sync || !watcher_) { | 389 if (is_sync || !watcher_) { |
| 320 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); | 390 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); |
| 321 | 391 |
| 322 drmEventContext event; | 392 ProcessDrmEvent( |
| 323 event.version = DRM_EVENT_CONTEXT_VERSION; | 393 file_.GetPlatformFile(), |
| 324 event.page_flip_handler = HandlePageFlipEventOnUI; | 394 base::Bind(&PageFlipManager::OnPageFlip, page_flip_manager_)); |
| 325 event.vblank_handler = nullptr; | |
| 326 | |
| 327 drmHandleEvent(file_.GetPlatformFile(), &event); | |
| 328 } | 395 } |
| 329 | 396 |
| 330 return true; | 397 return true; |
| 331 } | 398 } |
| 332 | 399 |
| 333 return false; | 400 return false; |
| 334 } | 401 } |
| 335 | 402 |
| 336 bool DrmDevice::PageFlipOverlay(uint32_t crtc_id, | 403 bool DrmDevice::PageFlipOverlay(uint32_t crtc_id, |
| 337 uint32_t framebuffer, | 404 uint32_t framebuffer, |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 470 DCHECK(file_.IsValid()); | 537 DCHECK(file_.IsValid()); |
| 471 return (drmSetMaster(file_.GetPlatformFile()) == 0); | 538 return (drmSetMaster(file_.GetPlatformFile()) == 0); |
| 472 } | 539 } |
| 473 | 540 |
| 474 bool DrmDevice::DropMaster() { | 541 bool DrmDevice::DropMaster() { |
| 475 DCHECK(file_.IsValid()); | 542 DCHECK(file_.IsValid()); |
| 476 return (drmDropMaster(file_.GetPlatformFile()) == 0); | 543 return (drmDropMaster(file_.GetPlatformFile()) == 0); |
| 477 } | 544 } |
| 478 | 545 |
| 479 } // namespace ui | 546 } // namespace ui |
| OLD | NEW |