| 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> |
| 11 #include <xf86drmMode.h> | 11 #include <xf86drmMode.h> |
| 12 | 12 |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
| 15 #include "base/stl_util.h" | |
| 16 #include "base/synchronization/waitable_event.h" | |
| 17 #include "base/task_runner.h" | 15 #include "base/task_runner.h" |
| 18 #include "base/thread_task_runner_handle.h" | 16 #include "base/thread_task_runner_handle.h" |
| 19 #include "base/trace_event/trace_event.h" | 17 #include "base/trace_event/trace_event.h" |
| 20 #include "third_party/skia/include/core/SkImageInfo.h" | 18 #include "third_party/skia/include/core/SkImageInfo.h" |
| 21 #include "ui/display/types/gamma_ramp_rgb_entry.h" | 19 #include "ui/display/types/gamma_ramp_rgb_entry.h" |
| 22 #include "ui/ozone/platform/drm/common/drm_util.h" | 20 #include "ui/ozone/platform/drm/common/drm_util.h" |
| 23 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h" | 21 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h" |
| 24 | 22 |
| 25 #if defined(USE_DRM_ATOMIC) | 23 #if defined(USE_DRM_ATOMIC) |
| 26 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h" | 24 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h" |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 bool CanQueryForResources(int fd) { | 106 bool CanQueryForResources(int fd) { |
| 109 drm_mode_card_res resources; | 107 drm_mode_card_res resources; |
| 110 memset(&resources, 0, sizeof(resources)); | 108 memset(&resources, 0, sizeof(resources)); |
| 111 // If there is no error getting DRM resources then assume this is a | 109 // If there is no error getting DRM resources then assume this is a |
| 112 // modesetting device. | 110 // modesetting device. |
| 113 return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources); | 111 return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources); |
| 114 } | 112 } |
| 115 | 113 |
| 116 } // namespace | 114 } // namespace |
| 117 | 115 |
| 118 class DrmDevice::PageFlipManager | 116 class DrmDevice::PageFlipManager { |
| 119 : public base::RefCountedThreadSafe<DrmDevice::PageFlipManager> { | |
| 120 public: | 117 public: |
| 121 PageFlipManager() : next_id_(0) {} | 118 PageFlipManager() : next_id_(0) {} |
| 119 ~PageFlipManager() {} |
| 122 | 120 |
| 123 void OnPageFlip(uint32_t frame, | 121 void OnPageFlip(uint32_t frame, |
| 124 uint32_t seconds, | 122 uint32_t seconds, |
| 125 uint32_t useconds, | 123 uint32_t useconds, |
| 126 uint64_t id) { | 124 uint64_t id) { |
| 127 auto it = | 125 auto it = |
| 128 std::find_if(callbacks_.begin(), callbacks_.end(), FindCallback(id)); | 126 std::find_if(callbacks_.begin(), callbacks_.end(), FindCallback(id)); |
| 129 if (it == callbacks_.end()) { | 127 if (it == callbacks_.end()) { |
| 130 LOG(WARNING) << "Could not find callback for page flip id=" << id; | 128 LOG(WARNING) << "Could not find callback for page flip id=" << id; |
| 131 return; | 129 return; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 143 | 141 |
| 144 uint64_t GetNextId() { return next_id_++; } | 142 uint64_t GetNextId() { return next_id_++; } |
| 145 | 143 |
| 146 void RegisterCallback(uint64_t id, | 144 void RegisterCallback(uint64_t id, |
| 147 uint64_t pending_calls, | 145 uint64_t pending_calls, |
| 148 const DrmDevice::PageFlipCallback& callback) { | 146 const DrmDevice::PageFlipCallback& callback) { |
| 149 callbacks_.push_back({id, pending_calls, callback}); | 147 callbacks_.push_back({id, pending_calls, callback}); |
| 150 } | 148 } |
| 151 | 149 |
| 152 private: | 150 private: |
| 153 friend class base::RefCountedThreadSafe<DrmDevice::PageFlipManager>; | |
| 154 ~PageFlipManager() {} | |
| 155 | |
| 156 struct PageFlip { | 151 struct PageFlip { |
| 157 uint64_t id; | 152 uint64_t id; |
| 158 uint32_t pending_calls; | 153 uint32_t pending_calls; |
| 159 DrmDevice::PageFlipCallback callback; | 154 DrmDevice::PageFlipCallback callback; |
| 160 }; | 155 }; |
| 161 | 156 |
| 162 struct FindCallback { | 157 struct FindCallback { |
| 163 FindCallback(uint64_t id) : id(id) {} | 158 FindCallback(uint64_t id) : id(id) {} |
| 164 | 159 |
| 165 bool operator()(const PageFlip& flip) const { return flip.id == id; } | 160 bool operator()(const PageFlip& flip) const { return flip.id == id; } |
| 166 | 161 |
| 167 uint64_t id; | 162 uint64_t id; |
| 168 }; | 163 }; |
| 169 | 164 |
| 170 uint64_t next_id_; | 165 uint64_t next_id_; |
| 171 | 166 |
| 172 std::vector<PageFlip> callbacks_; | 167 std::vector<PageFlip> callbacks_; |
| 173 | 168 |
| 174 DISALLOW_COPY_AND_ASSIGN(PageFlipManager); | 169 DISALLOW_COPY_AND_ASSIGN(PageFlipManager); |
| 175 }; | 170 }; |
| 176 | 171 |
| 177 class DrmDevice::IOWatcher | 172 class DrmDevice::IOWatcher : public base::MessagePumpLibevent::Watcher { |
| 178 : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>, | |
| 179 public base::MessagePumpLibevent::Watcher { | |
| 180 public: | 173 public: |
| 181 IOWatcher(int fd, | 174 IOWatcher(int fd, DrmDevice::PageFlipManager* page_flip_manager) |
| 182 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, | 175 : page_flip_manager_(page_flip_manager), paused_(true), fd_(fd) {} |
| 183 const scoped_refptr<DrmDevice::PageFlipManager>& page_flip_manager) | 176 |
| 184 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 177 ~IOWatcher() override { |
| 185 io_task_runner_(io_task_runner), | 178 if (!paused_) |
| 186 page_flip_manager_(page_flip_manager), | 179 Unregister(); |
| 187 paused_(true), | 180 } |
| 188 fd_(fd) {} | |
| 189 | 181 |
| 190 void SetPaused(bool paused) { | 182 void SetPaused(bool paused) { |
| 191 if (paused_ == paused) | 183 if (paused_ == paused) |
| 192 return; | 184 return; |
| 193 | 185 |
| 194 paused_ = paused; | 186 paused_ = paused; |
| 195 base::WaitableEvent done(false, false); | 187 if (paused_) |
| 196 io_task_runner_->PostTask( | 188 Unregister(); |
| 197 FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done)); | 189 else |
| 198 done.Wait(); | 190 Register(); |
| 199 } | |
| 200 | |
| 201 void Shutdown() { | |
| 202 if (!paused_) | |
| 203 io_task_runner_->PostTask(FROM_HERE, | |
| 204 base::Bind(&IOWatcher::UnregisterOnIO, this)); | |
| 205 } | 191 } |
| 206 | 192 |
| 207 private: | 193 private: |
| 208 friend class base::RefCountedThreadSafe<IOWatcher>; | 194 void Register() { |
| 209 | |
| 210 ~IOWatcher() override {} | |
| 211 | |
| 212 void RegisterOnIO() { | |
| 213 DCHECK(base::MessageLoopForIO::IsCurrent()); | 195 DCHECK(base::MessageLoopForIO::IsCurrent()); |
| 196 TRACE_EVENT0("drm", "DrmDevice::RegisterOnIO"); |
| 214 base::MessageLoopForIO::current()->WatchFileDescriptor( | 197 base::MessageLoopForIO::current()->WatchFileDescriptor( |
| 215 fd_, true, base::MessageLoopForIO::WATCH_READ, &controller_, this); | 198 fd_, true, base::MessageLoopForIO::WATCH_READ, &controller_, this); |
| 216 } | 199 } |
| 217 | 200 |
| 218 void UnregisterOnIO() { | 201 void Unregister() { |
| 219 DCHECK(base::MessageLoopForIO::IsCurrent()); | 202 DCHECK(base::MessageLoopForIO::IsCurrent()); |
| 203 TRACE_EVENT0("drm", "DrmDevice::UnregisterOnIO"); |
| 220 controller_.StopWatchingFileDescriptor(); | 204 controller_.StopWatchingFileDescriptor(); |
| 221 } | 205 } |
| 222 | 206 |
| 223 void SetPausedOnIO(base::WaitableEvent* done) { | |
| 224 DCHECK(base::MessageLoopForIO::IsCurrent()); | |
| 225 if (paused_) | |
| 226 UnregisterOnIO(); | |
| 227 else | |
| 228 RegisterOnIO(); | |
| 229 done->Signal(); | |
| 230 } | |
| 231 | |
| 232 void OnPageFlipOnIO(uint32_t frame, | |
| 233 uint32_t seconds, | |
| 234 uint32_t useconds, | |
| 235 uint64_t id) { | |
| 236 main_task_runner_->PostTask( | |
| 237 FROM_HERE, | |
| 238 base::Bind(&DrmDevice::PageFlipManager::OnPageFlip, page_flip_manager_, | |
| 239 frame, seconds, useconds, id)); | |
| 240 } | |
| 241 | |
| 242 // base::MessagePumpLibevent::Watcher overrides: | 207 // base::MessagePumpLibevent::Watcher overrides: |
| 243 void OnFileCanReadWithoutBlocking(int fd) override { | 208 void OnFileCanReadWithoutBlocking(int fd) override { |
| 244 DCHECK(base::MessageLoopForIO::IsCurrent()); | 209 DCHECK(base::MessageLoopForIO::IsCurrent()); |
| 245 TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd); | 210 TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd); |
| 246 | 211 |
| 247 if (!ProcessDrmEvent( | 212 if (!ProcessDrmEvent(fd, base::Bind(&DrmDevice::PageFlipManager::OnPageFlip, |
| 248 fd, base::Bind(&DrmDevice::IOWatcher::OnPageFlipOnIO, this))) | 213 base::Unretained(page_flip_manager_)))) |
| 249 UnregisterOnIO(); | 214 Unregister(); |
| 250 } | 215 } |
| 251 | 216 |
| 252 void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } | 217 void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } |
| 253 | 218 |
| 254 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | 219 DrmDevice::PageFlipManager* page_flip_manager_; |
| 255 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | |
| 256 | |
| 257 scoped_refptr<DrmDevice::PageFlipManager> page_flip_manager_; | |
| 258 | 220 |
| 259 base::MessagePumpLibevent::FileDescriptorWatcher controller_; | 221 base::MessagePumpLibevent::FileDescriptorWatcher controller_; |
| 260 | 222 |
| 261 bool paused_; | 223 bool paused_; |
| 262 int fd_; | 224 int fd_; |
| 263 | 225 |
| 264 DISALLOW_COPY_AND_ASSIGN(IOWatcher); | 226 DISALLOW_COPY_AND_ASSIGN(IOWatcher); |
| 265 }; | 227 }; |
| 266 | 228 |
| 267 DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file) | 229 DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file) |
| 268 : device_path_(device_path), | 230 : device_path_(device_path), |
| 269 file_(file.Pass()), | 231 file_(file.Pass()), |
| 270 page_flip_manager_(new PageFlipManager()) { | 232 page_flip_manager_(new PageFlipManager()), |
| 271 } | 233 watcher_( |
| 234 new IOWatcher(file_.GetPlatformFile(), page_flip_manager_.get())) {} |
| 272 | 235 |
| 273 DrmDevice::~DrmDevice() { | 236 DrmDevice::~DrmDevice() {} |
| 274 if (watcher_) | |
| 275 watcher_->Shutdown(); | |
| 276 } | |
| 277 | 237 |
| 278 bool DrmDevice::Initialize(bool use_atomic) { | 238 bool DrmDevice::Initialize(bool use_atomic) { |
| 279 // Ignore devices that cannot perform modesetting. | 239 // Ignore devices that cannot perform modesetting. |
| 280 if (!CanQueryForResources(file_.GetPlatformFile())) { | 240 if (!CanQueryForResources(file_.GetPlatformFile())) { |
| 281 VLOG(2) << "Cannot query for resources for '" << device_path_.value() | 241 VLOG(2) << "Cannot query for resources for '" << device_path_.value() |
| 282 << "'"; | 242 << "'"; |
| 283 return false; | 243 return false; |
| 284 } | 244 } |
| 285 | 245 |
| 286 #if defined(USE_DRM_ATOMIC) | 246 #if defined(USE_DRM_ATOMIC) |
| 287 // Use atomic only if the build, kernel & flags all allow it. | 247 // Use atomic only if the build, kernel & flags all allow it. |
| 288 if (use_atomic && SetCapability(DRM_CLIENT_CAP_ATOMIC, 1)) | 248 if (use_atomic && SetCapability(DRM_CLIENT_CAP_ATOMIC, 1)) |
| 289 plane_manager_.reset(new HardwareDisplayPlaneManagerAtomic()); | 249 plane_manager_.reset(new HardwareDisplayPlaneManagerAtomic()); |
| 290 #endif // defined(USE_DRM_ATOMIC) | 250 #endif // defined(USE_DRM_ATOMIC) |
| 291 | 251 |
| 292 if (!plane_manager_) | 252 if (!plane_manager_) |
| 293 plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); | 253 plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); |
| 294 if (!plane_manager_->Initialize(this)) { | 254 if (!plane_manager_->Initialize(this)) { |
| 295 LOG(ERROR) << "Failed to initialize the plane manager for " | 255 LOG(ERROR) << "Failed to initialize the plane manager for " |
| 296 << device_path_.value(); | 256 << device_path_.value(); |
| 297 plane_manager_.reset(); | 257 plane_manager_.reset(); |
| 298 return false; | 258 return false; |
| 299 } | 259 } |
| 300 | 260 |
| 301 return true; | 261 return true; |
| 302 } | 262 } |
| 303 | 263 |
| 304 void DrmDevice::InitializeTaskRunner( | |
| 305 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { | |
| 306 DCHECK(!task_runner_); | |
| 307 task_runner_ = task_runner; | |
| 308 watcher_ = | |
| 309 new IOWatcher(file_.GetPlatformFile(), task_runner_, page_flip_manager_); | |
| 310 } | |
| 311 | |
| 312 ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) { | 264 ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) { |
| 313 DCHECK(file_.IsValid()); | 265 DCHECK(file_.IsValid()); |
| 314 return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id)); | 266 return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id)); |
| 315 } | 267 } |
| 316 | 268 |
| 317 bool DrmDevice::SetCrtc(uint32_t crtc_id, | 269 bool DrmDevice::SetCrtc(uint32_t crtc_id, |
| 318 uint32_t framebuffer, | 270 uint32_t framebuffer, |
| 319 std::vector<uint32_t> connectors, | 271 std::vector<uint32_t> connectors, |
| 320 drmModeModeInfo* mode) { | 272 drmModeModeInfo* mode) { |
| 321 DCHECK(file_.IsValid()); | 273 DCHECK(file_.IsValid()); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer, | 346 if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer, |
| 395 DRM_MODE_PAGE_FLIP_EVENT, reinterpret_cast<void*>(id))) { | 347 DRM_MODE_PAGE_FLIP_EVENT, reinterpret_cast<void*>(id))) { |
| 396 // If successful the payload will be removed by a PageFlip event. | 348 // If successful the payload will be removed by a PageFlip event. |
| 397 page_flip_manager_->RegisterCallback(id, 1, callback); | 349 page_flip_manager_->RegisterCallback(id, 1, callback); |
| 398 | 350 |
| 399 // If the flip was requested synchronous or if no watcher has been installed | 351 // If the flip was requested synchronous or if no watcher has been installed |
| 400 // yet, then synchronously handle the page flip events. | 352 // yet, then synchronously handle the page flip events. |
| 401 if (is_sync || !watcher_) { | 353 if (is_sync || !watcher_) { |
| 402 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); | 354 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); |
| 403 | 355 |
| 404 ProcessDrmEvent( | 356 ProcessDrmEvent(file_.GetPlatformFile(), |
| 405 file_.GetPlatformFile(), | 357 base::Bind(&PageFlipManager::OnPageFlip, |
| 406 base::Bind(&PageFlipManager::OnPageFlip, page_flip_manager_)); | 358 base::Unretained(page_flip_manager_.get()))); |
| 407 } | 359 } |
| 408 | 360 |
| 409 return true; | 361 return true; |
| 410 } | 362 } |
| 411 | 363 |
| 412 return false; | 364 return false; |
| 413 } | 365 } |
| 414 | 366 |
| 415 bool DrmDevice::PageFlipOverlay(uint32_t crtc_id, | 367 bool DrmDevice::PageFlipOverlay(uint32_t crtc_id, |
| 416 uint32_t framebuffer, | 368 uint32_t framebuffer, |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 561 page_flip_manager_->RegisterCallback(id, crtc_count, callback); | 513 page_flip_manager_->RegisterCallback(id, crtc_count, callback); |
| 562 | 514 |
| 563 if (watcher_) | 515 if (watcher_) |
| 564 watcher_->SetPaused(is_sync); | 516 watcher_->SetPaused(is_sync); |
| 565 | 517 |
| 566 // If the flip was requested synchronous or if no watcher has been installed | 518 // If the flip was requested synchronous or if no watcher has been installed |
| 567 // yet, then synchronously handle the page flip events. | 519 // yet, then synchronously handle the page flip events. |
| 568 if (is_sync || !watcher_) { | 520 if (is_sync || !watcher_) { |
| 569 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); | 521 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); |
| 570 | 522 |
| 571 ProcessDrmEvent( | 523 ProcessDrmEvent(file_.GetPlatformFile(), |
| 572 file_.GetPlatformFile(), | 524 base::Bind(&PageFlipManager::OnPageFlip, |
| 573 base::Bind(&PageFlipManager::OnPageFlip, page_flip_manager_)); | 525 base::Unretained(page_flip_manager_.get()))); |
| 574 } | 526 } |
| 575 return true; | 527 return true; |
| 576 } | 528 } |
| 577 #endif // defined(USE_DRM_ATOMIC) | 529 #endif // defined(USE_DRM_ATOMIC) |
| 578 return false; | 530 return false; |
| 579 } | 531 } |
| 580 | 532 |
| 581 bool DrmDevice::SetCapability(uint64_t capability, uint64_t value) { | 533 bool DrmDevice::SetCapability(uint64_t capability, uint64_t value) { |
| 582 DCHECK(file_.IsValid()); | 534 DCHECK(file_.IsValid()); |
| 583 return !drmSetClientCap(file_.GetPlatformFile(), capability, value); | 535 return !drmSetClientCap(file_.GetPlatformFile(), capability, value); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 b.push_back(lut[i].b); | 569 b.push_back(lut[i].b); |
| 618 } | 570 } |
| 619 | 571 |
| 620 DCHECK(file_.IsValid()); | 572 DCHECK(file_.IsValid()); |
| 621 TRACE_EVENT0("drm", "DrmDevice::SetGamma"); | 573 TRACE_EVENT0("drm", "DrmDevice::SetGamma"); |
| 622 return (drmModeCrtcSetGamma(file_.GetPlatformFile(), crtc_id, r.size(), &r[0], | 574 return (drmModeCrtcSetGamma(file_.GetPlatformFile(), crtc_id, r.size(), &r[0], |
| 623 &g[0], &b[0]) == 0); | 575 &g[0], &b[0]) == 0); |
| 624 } | 576 } |
| 625 | 577 |
| 626 } // namespace ui | 578 } // namespace ui |
| OLD | NEW |