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/dri/hardware_display_controller.h" 6 7 #include <drm.h> 8 #include <errno.h> 9 #include <string.h> 10 #include <xf86drm.h> 11 12 #include "base/basictypes.h" 13 #include "base/debug/trace_event.h" 14 #include "base/logging.h" 15 #include "base/time/time.h" 16 #include "third_party/skia/include/core/SkCanvas.h" 17 #include "ui/gfx/geometry/point.h" 18 #include "ui/gfx/geometry/size.h" 19 #include "ui/ozone/platform/dri/dri_buffer.h" 20 #include "ui/ozone/platform/dri/dri_wrapper.h" 21 #include "ui/ozone/platform/dri/scanout_surface.h" 22 23 namespace ui { 24 25 namespace { 26 27 // DRM callback on page flip events. This callback is triggered after the 28 // page flip has happened and the backbuffer is now the new frontbuffer 29 // The old frontbuffer is no longer used by the hardware and can be used for 30 // future draw operations. 31 // 32 // |device| will contain a reference to the |ScanoutSurface| object which 33 // the event belongs to. 34 // 35 // TODO(dnicoara) When we have a FD handler for the DRM calls in the message 36 // loop, we can move this function in the handler. 37 void HandlePageFlipEvent(int fd, 38 unsigned int frame, 39 unsigned int seconds, 40 unsigned int useconds, 41 void* controller) { 42 TRACE_EVENT0("dri", "HandlePageFlipEvent"); 43 static_cast<HardwareDisplayController*>(controller) 44 ->OnPageFlipEvent(frame, seconds, useconds); 45 } 46 47 } // namespace 48 49 HardwareDisplayController::HardwareDisplayController( 50 DriWrapper* drm, 51 uint32_t connector_id, 52 uint32_t crtc_id) 53 : drm_(drm), 54 connector_id_(connector_id), 55 crtc_id_(crtc_id), 56 surface_(), 57 time_of_last_flip_(0), 58 is_disabled_(true) {} 59 60 HardwareDisplayController::~HardwareDisplayController() { 61 // Reset the cursor. 62 UnsetCursor(); 63 UnbindSurfaceFromController(); 64 } 65 66 bool 67 HardwareDisplayController::BindSurfaceToController( 68 scoped_ptr<ScanoutSurface> surface, drmModeModeInfo mode) { 69 CHECK(surface); 70 71 if (!drm_->SetCrtc(crtc_id_, 72 surface->GetFramebufferId(), 73 &connector_id_, 74 &mode)) { 75 LOG(ERROR) << "Failed to modeset: error='" << strerror(errno) 76 << "' crtc=" << crtc_id_ << " connector=" << connector_id_ 77 << " framebuffer_id=" << surface->GetFramebufferId() 78 << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@" 79 << mode.vrefresh; 80 return false; 81 } 82 83 surface_.reset(surface.release()); 84 mode_ = mode; 85 is_disabled_ = false; 86 return true; 87 } 88 89 void HardwareDisplayController::UnbindSurfaceFromController() { 90 drm_->SetCrtc(crtc_id_, 0, 0, NULL); 91 surface_.reset(); 92 memset(&mode_, 0, sizeof(mode_)); 93 is_disabled_ = true; 94 } 95 96 bool HardwareDisplayController::Enable() { 97 CHECK(surface_); 98 if (is_disabled_) { 99 scoped_ptr<ScanoutSurface> surface(surface_.release()); 100 return BindSurfaceToController(surface.Pass(), mode_); 101 } 102 103 return true; 104 } 105 106 void HardwareDisplayController::Disable() { 107 drm_->SetCrtc(crtc_id_, 0, 0, NULL); 108 is_disabled_ = true; 109 } 110 111 bool HardwareDisplayController::SchedulePageFlip() { 112 CHECK(surface_); 113 if (!is_disabled_ && !drm_->PageFlip(crtc_id_, 114 surface_->GetFramebufferId(), 115 this)) { 116 LOG(ERROR) << "Cannot page flip: " << strerror(errno); 117 return false; 118 } 119 120 return true; 121 } 122 123 void HardwareDisplayController::WaitForPageFlipEvent() { 124 TRACE_EVENT0("dri", "WaitForPageFlipEvent"); 125 126 if (is_disabled_) 127 return; 128 129 drmEventContext drm_event; 130 drm_event.version = DRM_EVENT_CONTEXT_VERSION; 131 drm_event.page_flip_handler = HandlePageFlipEvent; 132 drm_event.vblank_handler = NULL; 133 134 // Wait for the page-flip to complete. 135 drm_->HandleEvent(drm_event); 136 } 137 138 void HardwareDisplayController::OnPageFlipEvent(unsigned int frame, 139 unsigned int seconds, 140 unsigned int useconds) { 141 time_of_last_flip_ = 142 static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond + 143 useconds; 144 145 surface_->SwapBuffers(); 146 } 147 148 bool HardwareDisplayController::SetCursor(ScanoutSurface* surface) { 149 bool ret = drm_->SetCursor(crtc_id_, 150 surface->GetHandle(), 151 surface->Size().width(), 152 surface->Size().height()); 153 surface->SwapBuffers(); 154 return ret; 155 } 156 157 bool HardwareDisplayController::UnsetCursor() { 158 return drm_->SetCursor(crtc_id_, 0, 0, 0); 159 } 160 161 bool HardwareDisplayController::MoveCursor(const gfx::Point& location) { 162 if (is_disabled_) 163 return true; 164 165 return drm_->MoveCursor(crtc_id_, location.x(), location.y()); 166 } 167 168 } // namespace ui 169