OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ui/ozone/platform/drm/gpu/drm_device.h" |
| 6 |
| 7 #include <fcntl.h> |
| 8 #include <sys/mman.h> |
| 9 #include <unistd.h> |
| 10 #include <xf86drm.h> |
| 11 #include <xf86drmMode.h> |
| 12 |
| 13 #include "base/logging.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" |
| 18 #include "base/thread_task_runner_handle.h" |
| 19 #include "base/trace_event/trace_event.h" |
| 20 #include "third_party/skia/include/core/SkImageInfo.h" |
| 21 #include "ui/display/types/gamma_ramp_rgb_entry.h" |
| 22 #include "ui/ozone/platform/drm/common/drm_util.h" |
| 23 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h" |
| 24 |
| 25 #if defined(USE_DRM_ATOMIC) |
| 26 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h" |
| 27 #endif |
| 28 |
| 29 namespace ui { |
| 30 |
| 31 namespace { |
| 32 |
| 33 typedef base::Callback<void(uint32_t /* frame */, |
| 34 uint32_t /* seconds */, |
| 35 uint32_t /* useconds */, |
| 36 uint64_t /* id */)> DrmEventHandler; |
| 37 |
| 38 bool DrmCreateDumbBuffer(int fd, |
| 39 const SkImageInfo& info, |
| 40 uint32_t* handle, |
| 41 uint32_t* stride) { |
| 42 struct drm_mode_create_dumb request; |
| 43 memset(&request, 0, sizeof(request)); |
| 44 request.width = info.width(); |
| 45 request.height = info.height(); |
| 46 request.bpp = info.bytesPerPixel() << 3; |
| 47 request.flags = 0; |
| 48 |
| 49 if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) { |
| 50 VPLOG(2) << "Cannot create dumb buffer"; |
| 51 return false; |
| 52 } |
| 53 |
| 54 // The driver may choose to align the last row as well. We don't care about |
| 55 // the last alignment bits since they aren't used for display purposes, so |
| 56 // just check that the expected size is <= to what the driver allocated. |
| 57 DCHECK_LE(info.getSafeSize(request.pitch), request.size); |
| 58 |
| 59 *handle = request.handle; |
| 60 *stride = request.pitch; |
| 61 return true; |
| 62 } |
| 63 |
| 64 bool DrmDestroyDumbBuffer(int fd, uint32_t handle) { |
| 65 struct drm_mode_destroy_dumb destroy_request; |
| 66 memset(&destroy_request, 0, sizeof(destroy_request)); |
| 67 destroy_request.handle = handle; |
| 68 return !drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); |
| 69 } |
| 70 |
| 71 bool ProcessDrmEvent(int fd, const DrmEventHandler& callback) { |
| 72 char buffer[1024]; |
| 73 int len = read(fd, buffer, sizeof(buffer)); |
| 74 if (len == 0) |
| 75 return false; |
| 76 |
| 77 if (len < static_cast<int>(sizeof(drm_event))) { |
| 78 PLOG(ERROR) << "Failed to read DRM event"; |
| 79 return false; |
| 80 } |
| 81 |
| 82 int idx = 0; |
| 83 while (idx < len) { |
| 84 DCHECK_LE(static_cast<int>(sizeof(drm_event)), len - idx); |
| 85 drm_event event; |
| 86 memcpy(&event, &buffer[idx], sizeof(event)); |
| 87 switch (event.type) { |
| 88 case DRM_EVENT_FLIP_COMPLETE: { |
| 89 DCHECK_LE(static_cast<int>(sizeof(drm_event_vblank)), len - idx); |
| 90 drm_event_vblank vblank; |
| 91 memcpy(&vblank, &buffer[idx], sizeof(vblank)); |
| 92 callback.Run(vblank.sequence, vblank.tv_sec, vblank.tv_usec, |
| 93 vblank.user_data); |
| 94 } break; |
| 95 case DRM_EVENT_VBLANK: |
| 96 break; |
| 97 default: |
| 98 NOTREACHED(); |
| 99 break; |
| 100 } |
| 101 |
| 102 idx += event.length; |
| 103 } |
| 104 |
| 105 return true; |
| 106 } |
| 107 |
| 108 bool CanQueryForResources(int fd) { |
| 109 drm_mode_card_res resources; |
| 110 memset(&resources, 0, sizeof(resources)); |
| 111 // If there is no error getting DRM resources then assume this is a |
| 112 // modesetting device. |
| 113 return !drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &resources); |
| 114 } |
| 115 |
| 116 } // namespace |
| 117 |
| 118 class DrmDevice::PageFlipManager |
| 119 : public base::RefCountedThreadSafe<DrmDevice::PageFlipManager> { |
| 120 public: |
| 121 PageFlipManager() : next_id_(0) {} |
| 122 |
| 123 void OnPageFlip(uint32_t frame, |
| 124 uint32_t seconds, |
| 125 uint32_t useconds, |
| 126 uint64_t id) { |
| 127 auto it = |
| 128 std::find_if(callbacks_.begin(), callbacks_.end(), FindCallback(id)); |
| 129 if (it == callbacks_.end()) { |
| 130 LOG(WARNING) << "Could not find callback for page flip id=" << id; |
| 131 return; |
| 132 } |
| 133 |
| 134 DrmDevice::PageFlipCallback callback = it->callback; |
| 135 callbacks_.erase(it); |
| 136 callback.Run(frame, seconds, useconds); |
| 137 } |
| 138 |
| 139 uint64_t GetNextId() { return next_id_++; } |
| 140 |
| 141 void RegisterCallback(uint64_t id, |
| 142 const DrmDevice::PageFlipCallback& callback) { |
| 143 callbacks_.push_back({id, callback}); |
| 144 } |
| 145 |
| 146 private: |
| 147 friend class base::RefCountedThreadSafe<DrmDevice::PageFlipManager>; |
| 148 ~PageFlipManager() {} |
| 149 |
| 150 struct PageFlip { |
| 151 uint64_t id; |
| 152 DrmDevice::PageFlipCallback callback; |
| 153 }; |
| 154 |
| 155 struct FindCallback { |
| 156 FindCallback(uint64_t id) : id(id) {} |
| 157 |
| 158 bool operator()(const PageFlip& flip) const { return flip.id == id; } |
| 159 |
| 160 uint64_t id; |
| 161 }; |
| 162 |
| 163 uint64_t next_id_; |
| 164 |
| 165 std::vector<PageFlip> callbacks_; |
| 166 |
| 167 DISALLOW_COPY_AND_ASSIGN(PageFlipManager); |
| 168 }; |
| 169 |
| 170 class DrmDevice::IOWatcher |
| 171 : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>, |
| 172 public base::MessagePumpLibevent::Watcher { |
| 173 public: |
| 174 IOWatcher(int fd, |
| 175 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
| 176 const scoped_refptr<DrmDevice::PageFlipManager>& page_flip_manager) |
| 177 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 178 io_task_runner_(io_task_runner), |
| 179 page_flip_manager_(page_flip_manager), |
| 180 paused_(true), |
| 181 fd_(fd) {} |
| 182 |
| 183 void SetPaused(bool paused) { |
| 184 if (paused_ == paused) |
| 185 return; |
| 186 |
| 187 paused_ = paused; |
| 188 base::WaitableEvent done(false, false); |
| 189 io_task_runner_->PostTask( |
| 190 FROM_HERE, base::Bind(&IOWatcher::SetPausedOnIO, this, &done)); |
| 191 done.Wait(); |
| 192 } |
| 193 |
| 194 void Shutdown() { |
| 195 if (!paused_) |
| 196 io_task_runner_->PostTask(FROM_HERE, |
| 197 base::Bind(&IOWatcher::UnregisterOnIO, this)); |
| 198 } |
| 199 |
| 200 private: |
| 201 friend class base::RefCountedThreadSafe<IOWatcher>; |
| 202 |
| 203 ~IOWatcher() override {} |
| 204 |
| 205 void RegisterOnIO() { |
| 206 DCHECK(base::MessageLoopForIO::IsCurrent()); |
| 207 base::MessageLoopForIO::current()->WatchFileDescriptor( |
| 208 fd_, true, base::MessageLoopForIO::WATCH_READ, &controller_, this); |
| 209 } |
| 210 |
| 211 void UnregisterOnIO() { |
| 212 DCHECK(base::MessageLoopForIO::IsCurrent()); |
| 213 controller_.StopWatchingFileDescriptor(); |
| 214 } |
| 215 |
| 216 void SetPausedOnIO(base::WaitableEvent* done) { |
| 217 DCHECK(base::MessageLoopForIO::IsCurrent()); |
| 218 if (paused_) |
| 219 UnregisterOnIO(); |
| 220 else |
| 221 RegisterOnIO(); |
| 222 done->Signal(); |
| 223 } |
| 224 |
| 225 void OnPageFlipOnIO(uint32_t frame, |
| 226 uint32_t seconds, |
| 227 uint32_t useconds, |
| 228 uint64_t id) { |
| 229 main_task_runner_->PostTask( |
| 230 FROM_HERE, |
| 231 base::Bind(&DrmDevice::PageFlipManager::OnPageFlip, page_flip_manager_, |
| 232 frame, seconds, useconds, id)); |
| 233 } |
| 234 |
| 235 // base::MessagePumpLibevent::Watcher overrides: |
| 236 void OnFileCanReadWithoutBlocking(int fd) override { |
| 237 DCHECK(base::MessageLoopForIO::IsCurrent()); |
| 238 TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd); |
| 239 |
| 240 if (!ProcessDrmEvent( |
| 241 fd, base::Bind(&DrmDevice::IOWatcher::OnPageFlipOnIO, this))) |
| 242 UnregisterOnIO(); |
| 243 } |
| 244 |
| 245 void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } |
| 246 |
| 247 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
| 248 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; |
| 249 |
| 250 scoped_refptr<DrmDevice::PageFlipManager> page_flip_manager_; |
| 251 |
| 252 base::MessagePumpLibevent::FileDescriptorWatcher controller_; |
| 253 |
| 254 bool paused_; |
| 255 int fd_; |
| 256 |
| 257 DISALLOW_COPY_AND_ASSIGN(IOWatcher); |
| 258 }; |
| 259 |
| 260 DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file) |
| 261 : device_path_(device_path), |
| 262 file_(file.Pass()), |
| 263 page_flip_manager_(new PageFlipManager()) { |
| 264 } |
| 265 |
| 266 DrmDevice::~DrmDevice() { |
| 267 if (watcher_) |
| 268 watcher_->Shutdown(); |
| 269 } |
| 270 |
| 271 bool DrmDevice::Initialize(bool use_atomic) { |
| 272 // Ignore devices that cannot perform modesetting. |
| 273 if (!CanQueryForResources(file_.GetPlatformFile())) { |
| 274 VLOG(2) << "Cannot query for resources for '" << device_path_.value() |
| 275 << "'"; |
| 276 return false; |
| 277 } |
| 278 |
| 279 #if defined(USE_DRM_ATOMIC) |
| 280 // Use atomic only if the build, kernel & flags all allow it. |
| 281 if (use_atomic && SetCapability(DRM_CLIENT_CAP_ATOMIC, 1)) |
| 282 plane_manager_.reset(new HardwareDisplayPlaneManagerAtomic()); |
| 283 #endif // defined(USE_DRM_ATOMIC) |
| 284 |
| 285 if (!plane_manager_) |
| 286 plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); |
| 287 if (!plane_manager_->Initialize(this)) { |
| 288 LOG(ERROR) << "Failed to initialize the plane manager for " |
| 289 << device_path_.value(); |
| 290 plane_manager_.reset(); |
| 291 return false; |
| 292 } |
| 293 |
| 294 return true; |
| 295 } |
| 296 |
| 297 void DrmDevice::InitializeTaskRunner( |
| 298 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { |
| 299 DCHECK(!task_runner_); |
| 300 task_runner_ = task_runner; |
| 301 watcher_ = |
| 302 new IOWatcher(file_.GetPlatformFile(), task_runner_, page_flip_manager_); |
| 303 } |
| 304 |
| 305 ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) { |
| 306 DCHECK(file_.IsValid()); |
| 307 return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id)); |
| 308 } |
| 309 |
| 310 bool DrmDevice::SetCrtc(uint32_t crtc_id, |
| 311 uint32_t framebuffer, |
| 312 std::vector<uint32_t> connectors, |
| 313 drmModeModeInfo* mode) { |
| 314 DCHECK(file_.IsValid()); |
| 315 DCHECK(!connectors.empty()); |
| 316 DCHECK(mode); |
| 317 |
| 318 TRACE_EVENT2("drm", "DrmDevice::SetCrtc", "crtc", crtc_id, "size", |
| 319 gfx::Size(mode->hdisplay, mode->vdisplay).ToString()); |
| 320 return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0, |
| 321 vector_as_array(&connectors), connectors.size(), mode); |
| 322 } |
| 323 |
| 324 bool DrmDevice::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) { |
| 325 DCHECK(file_.IsValid()); |
| 326 // If there's no buffer then the CRTC was disabled. |
| 327 if (!crtc->buffer_id) |
| 328 return DisableCrtc(crtc->crtc_id); |
| 329 |
| 330 DCHECK(!connectors.empty()); |
| 331 |
| 332 TRACE_EVENT1("drm", "DrmDevice::RestoreCrtc", "crtc", crtc->crtc_id); |
| 333 return !drmModeSetCrtc(file_.GetPlatformFile(), crtc->crtc_id, |
| 334 crtc->buffer_id, crtc->x, crtc->y, |
| 335 vector_as_array(&connectors), connectors.size(), |
| 336 &crtc->mode); |
| 337 } |
| 338 |
| 339 bool DrmDevice::DisableCrtc(uint32_t crtc_id) { |
| 340 DCHECK(file_.IsValid()); |
| 341 TRACE_EVENT1("drm", "DrmDevice::DisableCrtc", "crtc", crtc_id); |
| 342 return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, 0, 0, 0, NULL, 0, |
| 343 NULL); |
| 344 } |
| 345 |
| 346 ScopedDrmConnectorPtr DrmDevice::GetConnector(uint32_t connector_id) { |
| 347 DCHECK(file_.IsValid()); |
| 348 TRACE_EVENT1("drm", "DrmDevice::GetConnector", "connector", connector_id); |
| 349 return ScopedDrmConnectorPtr( |
| 350 drmModeGetConnector(file_.GetPlatformFile(), connector_id)); |
| 351 } |
| 352 |
| 353 bool DrmDevice::AddFramebuffer(uint32_t width, |
| 354 uint32_t height, |
| 355 uint8_t depth, |
| 356 uint8_t bpp, |
| 357 uint32_t stride, |
| 358 uint32_t handle, |
| 359 uint32_t* framebuffer) { |
| 360 DCHECK(file_.IsValid()); |
| 361 TRACE_EVENT1("drm", "DrmDevice::AddFramebuffer", "handle", handle); |
| 362 return !drmModeAddFB(file_.GetPlatformFile(), width, height, depth, bpp, |
| 363 stride, handle, framebuffer); |
| 364 } |
| 365 |
| 366 bool DrmDevice::RemoveFramebuffer(uint32_t framebuffer) { |
| 367 DCHECK(file_.IsValid()); |
| 368 TRACE_EVENT1("drm", "DrmDevice::RemoveFramebuffer", "framebuffer", |
| 369 framebuffer); |
| 370 return !drmModeRmFB(file_.GetPlatformFile(), framebuffer); |
| 371 } |
| 372 |
| 373 bool DrmDevice::PageFlip(uint32_t crtc_id, |
| 374 uint32_t framebuffer, |
| 375 bool is_sync, |
| 376 const PageFlipCallback& callback) { |
| 377 DCHECK(file_.IsValid()); |
| 378 TRACE_EVENT2("drm", "DrmDevice::PageFlip", "crtc", crtc_id, "framebuffer", |
| 379 framebuffer); |
| 380 |
| 381 if (watcher_) |
| 382 watcher_->SetPaused(is_sync); |
| 383 |
| 384 // NOTE: Calling drmModeSetCrtc will immediately update the state, though |
| 385 // callbacks to already scheduled page flips will be honored by the kernel. |
| 386 uint64_t id = page_flip_manager_->GetNextId(); |
| 387 if (!drmModePageFlip(file_.GetPlatformFile(), crtc_id, framebuffer, |
| 388 DRM_MODE_PAGE_FLIP_EVENT, reinterpret_cast<void*>(id))) { |
| 389 // If successful the payload will be removed by a PageFlip event. |
| 390 page_flip_manager_->RegisterCallback(id, callback); |
| 391 |
| 392 // If the flip was requested synchronous or if no watcher has been installed |
| 393 // yet, then synchronously handle the page flip events. |
| 394 if (is_sync || !watcher_) { |
| 395 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); |
| 396 |
| 397 ProcessDrmEvent( |
| 398 file_.GetPlatformFile(), |
| 399 base::Bind(&PageFlipManager::OnPageFlip, page_flip_manager_)); |
| 400 } |
| 401 |
| 402 return true; |
| 403 } |
| 404 |
| 405 return false; |
| 406 } |
| 407 |
| 408 bool DrmDevice::PageFlipOverlay(uint32_t crtc_id, |
| 409 uint32_t framebuffer, |
| 410 const gfx::Rect& location, |
| 411 const gfx::Rect& source, |
| 412 int overlay_plane) { |
| 413 DCHECK(file_.IsValid()); |
| 414 TRACE_EVENT2("drm", "DrmDevice::PageFlipOverlay", "crtc", crtc_id, |
| 415 "framebuffer", framebuffer); |
| 416 return !drmModeSetPlane(file_.GetPlatformFile(), overlay_plane, crtc_id, |
| 417 framebuffer, 0, location.x(), location.y(), |
| 418 location.width(), location.height(), source.x(), |
| 419 source.y(), source.width(), source.height()); |
| 420 } |
| 421 |
| 422 ScopedDrmFramebufferPtr DrmDevice::GetFramebuffer(uint32_t framebuffer) { |
| 423 DCHECK(file_.IsValid()); |
| 424 TRACE_EVENT1("drm", "DrmDevice::GetFramebuffer", "framebuffer", framebuffer); |
| 425 return ScopedDrmFramebufferPtr( |
| 426 drmModeGetFB(file_.GetPlatformFile(), framebuffer)); |
| 427 } |
| 428 |
| 429 ScopedDrmPropertyPtr DrmDevice::GetProperty(drmModeConnector* connector, |
| 430 const char* name) { |
| 431 TRACE_EVENT2("drm", "DrmDevice::GetProperty", "connector", |
| 432 connector->connector_id, "name", name); |
| 433 for (int i = 0; i < connector->count_props; ++i) { |
| 434 ScopedDrmPropertyPtr property( |
| 435 drmModeGetProperty(file_.GetPlatformFile(), connector->props[i])); |
| 436 if (!property) |
| 437 continue; |
| 438 |
| 439 if (strcmp(property->name, name) == 0) |
| 440 return property.Pass(); |
| 441 } |
| 442 |
| 443 return ScopedDrmPropertyPtr(); |
| 444 } |
| 445 |
| 446 bool DrmDevice::SetProperty(uint32_t connector_id, |
| 447 uint32_t property_id, |
| 448 uint64_t value) { |
| 449 DCHECK(file_.IsValid()); |
| 450 return !drmModeConnectorSetProperty(file_.GetPlatformFile(), connector_id, |
| 451 property_id, value); |
| 452 } |
| 453 |
| 454 bool DrmDevice::GetCapability(uint64_t capability, uint64_t* value) { |
| 455 DCHECK(file_.IsValid()); |
| 456 return !drmGetCap(file_.GetPlatformFile(), capability, value); |
| 457 } |
| 458 |
| 459 ScopedDrmPropertyBlobPtr DrmDevice::GetPropertyBlob(drmModeConnector* connector, |
| 460 const char* name) { |
| 461 DCHECK(file_.IsValid()); |
| 462 TRACE_EVENT2("drm", "DrmDevice::GetPropertyBlob", "connector", |
| 463 connector->connector_id, "name", name); |
| 464 for (int i = 0; i < connector->count_props; ++i) { |
| 465 ScopedDrmPropertyPtr property( |
| 466 drmModeGetProperty(file_.GetPlatformFile(), connector->props[i])); |
| 467 if (!property) |
| 468 continue; |
| 469 |
| 470 if (strcmp(property->name, name) == 0 && |
| 471 property->flags & DRM_MODE_PROP_BLOB) |
| 472 return ScopedDrmPropertyBlobPtr(drmModeGetPropertyBlob( |
| 473 file_.GetPlatformFile(), connector->prop_values[i])); |
| 474 } |
| 475 |
| 476 return ScopedDrmPropertyBlobPtr(); |
| 477 } |
| 478 |
| 479 bool DrmDevice::SetCursor(uint32_t crtc_id, |
| 480 uint32_t handle, |
| 481 const gfx::Size& size) { |
| 482 DCHECK(file_.IsValid()); |
| 483 TRACE_EVENT1("drm", "DrmDevice::SetCursor", "handle", handle); |
| 484 return !drmModeSetCursor(file_.GetPlatformFile(), crtc_id, handle, |
| 485 size.width(), size.height()); |
| 486 } |
| 487 |
| 488 bool DrmDevice::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { |
| 489 DCHECK(file_.IsValid()); |
| 490 return !drmModeMoveCursor(file_.GetPlatformFile(), crtc_id, point.x(), |
| 491 point.y()); |
| 492 } |
| 493 |
| 494 bool DrmDevice::CreateDumbBuffer(const SkImageInfo& info, |
| 495 uint32_t* handle, |
| 496 uint32_t* stride) { |
| 497 DCHECK(file_.IsValid()); |
| 498 |
| 499 TRACE_EVENT0("drm", "DrmDevice::CreateDumbBuffer"); |
| 500 return DrmCreateDumbBuffer(file_.GetPlatformFile(), info, handle, stride); |
| 501 } |
| 502 |
| 503 bool DrmDevice::DestroyDumbBuffer(uint32_t handle) { |
| 504 DCHECK(file_.IsValid()); |
| 505 TRACE_EVENT1("drm", "DrmDevice::DestroyDumbBuffer", "handle", handle); |
| 506 return DrmDestroyDumbBuffer(file_.GetPlatformFile(), handle); |
| 507 } |
| 508 |
| 509 bool DrmDevice::MapDumbBuffer(uint32_t handle, size_t size, void** pixels) { |
| 510 struct drm_mode_map_dumb map_request; |
| 511 memset(&map_request, 0, sizeof(map_request)); |
| 512 map_request.handle = handle; |
| 513 if (drmIoctl(file_.GetPlatformFile(), DRM_IOCTL_MODE_MAP_DUMB, |
| 514 &map_request)) { |
| 515 PLOG(ERROR) << "Cannot prepare dumb buffer for mapping"; |
| 516 return false; |
| 517 } |
| 518 |
| 519 *pixels = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, |
| 520 file_.GetPlatformFile(), map_request.offset); |
| 521 if (*pixels == MAP_FAILED) { |
| 522 PLOG(ERROR) << "Cannot mmap dumb buffer"; |
| 523 return false; |
| 524 } |
| 525 |
| 526 return true; |
| 527 } |
| 528 |
| 529 bool DrmDevice::UnmapDumbBuffer(void* pixels, size_t size) { |
| 530 return !munmap(pixels, size); |
| 531 } |
| 532 |
| 533 bool DrmDevice::CloseBufferHandle(uint32_t handle) { |
| 534 struct drm_gem_close close_request; |
| 535 memset(&close_request, 0, sizeof(close_request)); |
| 536 close_request.handle = handle; |
| 537 return !drmIoctl(file_.GetPlatformFile(), DRM_IOCTL_GEM_CLOSE, |
| 538 &close_request); |
| 539 } |
| 540 |
| 541 bool DrmDevice::CommitProperties(drmModePropertySet* properties, |
| 542 uint32_t flags, |
| 543 bool is_sync, |
| 544 bool test_only, |
| 545 const PageFlipCallback& callback) { |
| 546 #if defined(USE_DRM_ATOMIC) |
| 547 if (test_only) |
| 548 flags |= DRM_MODE_ATOMIC_TEST_ONLY; |
| 549 else |
| 550 flags |= DRM_MODE_PAGE_FLIP_EVENT; |
| 551 uint64_t id = page_flip_manager_->GetNextId(); |
| 552 if (!drmModePropertySetCommit(file_.GetPlatformFile(), flags, |
| 553 reinterpret_cast<void*>(id), properties)) { |
| 554 if (test_only) |
| 555 return true; |
| 556 page_flip_manager_->RegisterCallback(id, callback); |
| 557 |
| 558 // If the flip was requested synchronous or if no watcher has been installed |
| 559 // yet, then synchronously handle the page flip events. |
| 560 if (is_sync || !watcher_) { |
| 561 TRACE_EVENT1("drm", "OnDrmEvent", "socket", file_.GetPlatformFile()); |
| 562 |
| 563 ProcessDrmEvent( |
| 564 file_.GetPlatformFile(), |
| 565 base::Bind(&PageFlipManager::OnPageFlip, page_flip_manager_)); |
| 566 } |
| 567 return true; |
| 568 } |
| 569 #endif // defined(USE_DRM_ATOMIC) |
| 570 return false; |
| 571 } |
| 572 |
| 573 bool DrmDevice::SetCapability(uint64_t capability, uint64_t value) { |
| 574 DCHECK(file_.IsValid()); |
| 575 return !drmSetClientCap(file_.GetPlatformFile(), capability, value); |
| 576 } |
| 577 |
| 578 bool DrmDevice::SetMaster() { |
| 579 TRACE_EVENT1("drm", "DrmDevice::SetMaster", "path", device_path_.value()); |
| 580 DCHECK(file_.IsValid()); |
| 581 return (drmSetMaster(file_.GetPlatformFile()) == 0); |
| 582 } |
| 583 |
| 584 bool DrmDevice::DropMaster() { |
| 585 TRACE_EVENT1("drm", "DrmDevice::DropMaster", "path", device_path_.value()); |
| 586 DCHECK(file_.IsValid()); |
| 587 return (drmDropMaster(file_.GetPlatformFile()) == 0); |
| 588 } |
| 589 |
| 590 bool DrmDevice::SetGammaRamp(uint32_t crtc_id, |
| 591 const std::vector<GammaRampRGBEntry>& lut) { |
| 592 ScopedDrmCrtcPtr crtc = GetCrtc(crtc_id); |
| 593 |
| 594 // TODO(robert.bradford) resample the incoming ramp to match what the kernel |
| 595 // expects. |
| 596 if (static_cast<size_t>(crtc->gamma_size) != lut.size()) { |
| 597 LOG(ERROR) << "Gamma table size mismatch: supplied " << lut.size() |
| 598 << " expected " << crtc->gamma_size; |
| 599 } |
| 600 |
| 601 std::vector<uint16_t> r, g, b; |
| 602 r.reserve(lut.size()); |
| 603 g.reserve(lut.size()); |
| 604 b.reserve(lut.size()); |
| 605 |
| 606 for (size_t i = 0; i < lut.size(); ++i) { |
| 607 r.push_back(lut[i].r); |
| 608 g.push_back(lut[i].g); |
| 609 b.push_back(lut[i].b); |
| 610 } |
| 611 |
| 612 DCHECK(file_.IsValid()); |
| 613 TRACE_EVENT0("drm", "DrmDevice::SetGamma"); |
| 614 return (drmModeCrtcSetGamma(file_.GetPlatformFile(), crtc_id, r.size(), &r[0], |
| 615 &g[0], &b[0]) == 0); |
| 616 } |
| 617 |
| 618 } // namespace ui |
OLD | NEW |