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/dri_wrapper.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/debug/trace_event.h"
     14 #include "base/logging.h"
     15 #include "base/stl_util.h"
     16 #include "third_party/skia/include/core/SkImageInfo.h"
     17 #include "ui/ozone/platform/dri/dri_util.h"
     18 
     19 namespace ui {
     20 
     21 namespace {
     22 
     23 uint32_t ToFixedPoint(double v) {
     24   // This returns a number in a 16-bit.16-bit fixed point.
     25   return v * 65536.0;
     26 }
     27 
     28 bool DrmCreateDumbBuffer(int fd,
     29                          const SkImageInfo& info,
     30                          uint32_t* handle,
     31                          uint32_t* stride) {
     32   struct drm_mode_create_dumb request;
     33   memset(&request, 0, sizeof(request));
     34   request.width = info.width();
     35   request.height = info.height();
     36   request.bpp = info.bytesPerPixel() << 3;
     37   request.flags = 0;
     38 
     39   if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) {
     40     VLOG(2) << "Cannot create dumb buffer (" << errno << ") "
     41             << strerror(errno);
     42     return false;
     43   }
     44 
     45   // The driver may choose to align the last row as well. We don't care about
     46   // the last alignment bits since they aren't used for display purposes, so
     47   // just check that the expected size is <= to what the driver allocated.
     48   DCHECK_LE(info.getSafeSize(request.pitch), request.size);
     49 
     50   *handle = request.handle;
     51   *stride = request.pitch;
     52   return true;
     53 }
     54 
     55 void DrmDestroyDumbBuffer(int fd, uint32_t handle) {
     56   struct drm_mode_destroy_dumb destroy_request;
     57   memset(&destroy_request, 0, sizeof(destroy_request));
     58   destroy_request.handle = handle;
     59   drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
     60 }
     61 
     62 }  // namespace
     63 
     64 DriWrapper::DriWrapper(const char* device_path)
     65     : fd_(-1), device_path_(device_path) {
     66 }
     67 
     68 DriWrapper::~DriWrapper() {
     69   if (fd_ >= 0)
     70     close(fd_);
     71 }
     72 
     73 void DriWrapper::Initialize() {
     74   fd_ = open(device_path_, O_RDWR | O_CLOEXEC);
     75   if (fd_ < 0)
     76     PLOG(FATAL) << "open: " << device_path_;
     77 }
     78 
     79 ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) {
     80   DCHECK(fd_ >= 0);
     81   return ScopedDrmCrtcPtr(drmModeGetCrtc(fd_, crtc_id));
     82 }
     83 
     84 bool DriWrapper::SetCrtc(uint32_t crtc_id,
     85                          uint32_t framebuffer,
     86                          std::vector<uint32_t> connectors,
     87                          drmModeModeInfo* mode) {
     88   DCHECK(fd_ >= 0);
     89   DCHECK(!connectors.empty());
     90   DCHECK(mode);
     91 
     92   TRACE_EVENT2("dri",
     93                "DriWrapper::SetCrtc",
     94                "crtc",
     95                crtc_id,
     96                "size",
     97                gfx::Size(mode->hdisplay, mode->vdisplay).ToString());
     98   return !drmModeSetCrtc(fd_,
     99                          crtc_id,
    100                          framebuffer,
    101                          0,
    102                          0,
    103                          vector_as_array(&connectors),
    104                          connectors.size(), mode);
    105 }
    106 
    107 bool DriWrapper::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) {
    108   DCHECK(fd_ >= 0);
    109   // If there's no buffer then the CRTC was disabled.
    110   if (!crtc->buffer_id)
    111     return DisableCrtc(crtc->crtc_id);
    112 
    113   DCHECK(!connectors.empty());
    114 
    115   TRACE_EVENT1("dri", "DriWrapper::RestoreCrtc",
    116                "crtc", crtc->crtc_id);
    117   return !drmModeSetCrtc(fd_,
    118                          crtc->crtc_id,
    119                          crtc->buffer_id,
    120                          crtc->x,
    121                          crtc->y,
    122                          vector_as_array(&connectors),
    123                          connectors.size(),
    124                          &crtc->mode);
    125 }
    126 
    127 bool DriWrapper::DisableCrtc(uint32_t crtc_id) {
    128   DCHECK(fd_ >= 0);
    129   TRACE_EVENT1("dri", "DriWrapper::DisableCrtc",
    130                "crtc", crtc_id);
    131   return !drmModeSetCrtc(fd_, crtc_id, 0, 0, 0, NULL, 0, NULL);
    132 }
    133 
    134 ScopedDrmConnectorPtr DriWrapper::GetConnector(uint32_t connector_id) {
    135   DCHECK(fd_ >= 0);
    136   TRACE_EVENT1("dri", "DriWrapper::GetConnector", "connector", connector_id);
    137   return ScopedDrmConnectorPtr(drmModeGetConnector(fd_, connector_id));
    138 }
    139 
    140 bool DriWrapper::AddFramebuffer(uint32_t width,
    141                                 uint32_t height,
    142                                 uint8_t depth,
    143                                 uint8_t bpp,
    144                                 uint32_t stride,
    145                                 uint32_t handle,
    146                                 uint32_t* framebuffer) {
    147   DCHECK(fd_ >= 0);
    148   TRACE_EVENT1("dri", "DriWrapper::AddFramebuffer",
    149                "handle", handle);
    150   return !drmModeAddFB(fd_,
    151                        width,
    152                        height,
    153                        depth,
    154                        bpp,
    155                        stride,
    156                        handle,
    157                        framebuffer);
    158 }
    159 
    160 bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) {
    161   DCHECK(fd_ >= 0);
    162   TRACE_EVENT1("dri", "DriWrapper::RemoveFramebuffer",
    163                "framebuffer", framebuffer);
    164   return !drmModeRmFB(fd_, framebuffer);
    165 }
    166 
    167 bool DriWrapper::PageFlip(uint32_t crtc_id,
    168                           uint32_t framebuffer,
    169                           void* data) {
    170   DCHECK(fd_ >= 0);
    171   TRACE_EVENT2("dri", "DriWrapper::PageFlip",
    172                "crtc", crtc_id,
    173                "framebuffer", framebuffer);
    174   return !drmModePageFlip(fd_,
    175                           crtc_id,
    176                           framebuffer,
    177                           DRM_MODE_PAGE_FLIP_EVENT,
    178                           data);
    179 }
    180 
    181 bool DriWrapper::PageFlipOverlay(uint32_t crtc_id,
    182                                  uint32_t framebuffer,
    183                                  const gfx::Rect& location,
    184                                  const gfx::RectF& source,
    185                                  int overlay_plane) {
    186   DCHECK(fd_ >= 0);
    187   TRACE_EVENT2("dri", "DriWrapper::PageFlipOverlay",
    188                "crtc", crtc_id,
    189                "framebuffer", framebuffer);
    190   return !drmModeSetPlane(fd_,
    191                           overlay_plane,
    192                           crtc_id,
    193                           framebuffer,
    194                           0,
    195                           location.x(),
    196                           location.y(),
    197                           location.width(),
    198                           location.height(),
    199                           ToFixedPoint(source.x()),
    200                           ToFixedPoint(source.y()),
    201                           ToFixedPoint(source.width()),
    202                           ToFixedPoint(source.height()));
    203 }
    204 
    205 ScopedDrmFramebufferPtr DriWrapper::GetFramebuffer(uint32_t framebuffer) {
    206   DCHECK(fd_ >= 0);
    207   TRACE_EVENT1("dri", "DriWrapper::GetFramebuffer",
    208                "framebuffer", framebuffer);
    209   return ScopedDrmFramebufferPtr(drmModeGetFB(fd_, framebuffer));
    210 }
    211 
    212 ScopedDrmPropertyPtr DriWrapper::GetProperty(drmModeConnector* connector,
    213                                              const char* name) {
    214   TRACE_EVENT2("dri", "DriWrapper::GetProperty",
    215                "connector", connector->connector_id,
    216                "name", name);
    217   for (int i = 0; i < connector->count_props; ++i) {
    218     ScopedDrmPropertyPtr property(drmModeGetProperty(fd_, connector->props[i]));
    219     if (!property)
    220       continue;
    221 
    222     if (strcmp(property->name, name) == 0)
    223       return property.Pass();
    224   }
    225 
    226   return ScopedDrmPropertyPtr();
    227 }
    228 
    229 bool DriWrapper::SetProperty(uint32_t connector_id,
    230                              uint32_t property_id,
    231                              uint64_t value) {
    232   DCHECK(fd_ >= 0);
    233   return !drmModeConnectorSetProperty(fd_, connector_id, property_id, value);
    234 }
    235 
    236 ScopedDrmPropertyBlobPtr DriWrapper::GetPropertyBlob(
    237     drmModeConnector* connector, const char* name) {
    238   DCHECK(fd_ >= 0);
    239   TRACE_EVENT2("dri", "DriWrapper::GetPropertyBlob",
    240                "connector", connector->connector_id,
    241                "name", name);
    242   for (int i = 0; i < connector->count_props; ++i) {
    243     ScopedDrmPropertyPtr property(drmModeGetProperty(fd_, connector->props[i]));
    244     if (!property)
    245       continue;
    246 
    247     if (strcmp(property->name, name) == 0 &&
    248         property->flags & DRM_MODE_PROP_BLOB)
    249       return ScopedDrmPropertyBlobPtr(
    250           drmModeGetPropertyBlob(fd_, connector->prop_values[i]));
    251   }
    252 
    253   return ScopedDrmPropertyBlobPtr();
    254 }
    255 
    256 bool DriWrapper::SetCursor(uint32_t crtc_id,
    257                            uint32_t handle,
    258                            const gfx::Size& size) {
    259   DCHECK(fd_ >= 0);
    260   TRACE_EVENT1("dri", "DriWrapper::SetCursor", "handle", handle);
    261   return !drmModeSetCursor(fd_, crtc_id, handle, size.width(), size.height());
    262 }
    263 
    264 bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
    265   DCHECK(fd_ >= 0);
    266   return !drmModeMoveCursor(fd_, crtc_id, point.x(), point.y());
    267 }
    268 
    269 void DriWrapper::HandleEvent(drmEventContext& event) {
    270   DCHECK(fd_ >= 0);
    271   TRACE_EVENT0("dri", "DriWrapper::HandleEvent");
    272   drmHandleEvent(fd_, &event);
    273 }
    274 
    275 bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info,
    276                                   uint32_t* handle,
    277                                   uint32_t* stride,
    278                                   void** pixels) {
    279   DCHECK(fd_ >= 0);
    280 
    281   TRACE_EVENT0("dri", "DriWrapper::CreateDumbBuffer");
    282   if (!DrmCreateDumbBuffer(fd_, info, handle, stride))
    283     return false;
    284 
    285   if (!MapDumbBuffer(fd_, *handle, info.getSafeSize(*stride), pixels)) {
    286     DrmDestroyDumbBuffer(fd_, *handle);
    287     return false;
    288   }
    289 
    290   return true;
    291 }
    292 
    293 void DriWrapper::DestroyDumbBuffer(const SkImageInfo& info,
    294                                    uint32_t handle,
    295                                    uint32_t stride,
    296                                    void* pixels) {
    297   DCHECK(fd_ >= 0);
    298   TRACE_EVENT1("dri", "DriWrapper::DestroyDumbBuffer", "handle", handle);
    299   munmap(pixels, info.getSafeSize(stride));
    300   DrmDestroyDumbBuffer(fd_, handle);
    301 }
    302 
    303 
    304 }  // namespace ui
    305