Home | History | Annotate | Download | only in dri
      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