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_buffer.h"
      6 
      7 #include <errno.h>
      8 #include <sys/mman.h>
      9 #include <sys/types.h>
     10 #include <xf86drm.h>
     11 
     12 #include "base/logging.h"
     13 #include "third_party/skia/include/core/SkCanvas.h"
     14 #include "ui/ozone/platform/dri/dri_wrapper.h"
     15 
     16 namespace ui {
     17 
     18 namespace {
     19 
     20 // Modesetting cannot happen from a buffer with transparencies. Return the size
     21 // of a pixel without alpha.
     22 uint8_t GetColorDepth(SkColorType type) {
     23   switch (type) {
     24     case kUnknown_SkColorType:
     25     case kAlpha_8_SkColorType:
     26       return 0;
     27     case kIndex_8_SkColorType:
     28       return 8;
     29     case kRGB_565_SkColorType:
     30       return 16;
     31     case kARGB_4444_SkColorType:
     32       return 12;
     33     case kPMColor_SkColorType:
     34       return 24;
     35     default:
     36       NOTREACHED();
     37       return 0;
     38   }
     39 }
     40 
     41 void DestroyDumbBuffer(int fd, uint32_t handle) {
     42   struct drm_mode_destroy_dumb destroy_request;
     43   destroy_request.handle = handle;
     44   drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
     45 }
     46 
     47 bool CreateDumbBuffer(DriWrapper* dri,
     48                       const SkImageInfo& info,
     49                       uint32_t* handle,
     50                       uint32_t* stride,
     51                       void** pixels) {
     52   struct drm_mode_create_dumb request;
     53   request.width = info.width();
     54   request.height = info.height();
     55   request.bpp = info.bytesPerPixel() << 3;
     56   request.flags = 0;
     57 
     58   if (drmIoctl(dri->get_fd(), DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) {
     59     DLOG(ERROR) << "Cannot create dumb buffer (" << errno << ") "
     60                 << strerror(errno);
     61     return false;
     62   }
     63 
     64   *handle = request.handle;
     65   *stride = request.pitch;
     66 
     67   struct drm_mode_map_dumb map_request;
     68   map_request.handle = request.handle;
     69   if (drmIoctl(dri->get_fd(), DRM_IOCTL_MODE_MAP_DUMB, &map_request)) {
     70     DLOG(ERROR) << "Cannot prepare dumb buffer for mapping (" << errno << ") "
     71                 << strerror(errno);
     72     DestroyDumbBuffer(dri->get_fd(), request.handle);
     73     return false;
     74   }
     75 
     76   *pixels = mmap(0,
     77                  request.size,
     78                  PROT_READ | PROT_WRITE,
     79                  MAP_SHARED,
     80                  dri->get_fd(),
     81                  map_request.offset);
     82   if (*pixels == MAP_FAILED) {
     83     DLOG(ERROR) << "Cannot mmap dumb buffer (" << errno << ") "
     84                 << strerror(errno);
     85     DestroyDumbBuffer(dri->get_fd(), request.handle);
     86     return false;
     87   }
     88 
     89   return true;
     90 }
     91 
     92 }  // namespace
     93 
     94 DriBuffer::DriBuffer(DriWrapper* dri)
     95     : dri_(dri), handle_(0), framebuffer_(0) {}
     96 
     97 DriBuffer::~DriBuffer() {
     98   if (!surface_)
     99     return;
    100 
    101   if (framebuffer_)
    102     dri_->RemoveFramebuffer(framebuffer_);
    103 
    104   SkImageInfo info;
    105   void* pixels = const_cast<void*>(surface_->peekPixels(&info, NULL));
    106   if (!pixels)
    107     return;
    108 
    109   munmap(pixels, info.getSafeSize(stride_));
    110   DestroyDumbBuffer(dri_->get_fd(), handle_);
    111 }
    112 
    113 bool DriBuffer::Initialize(const SkImageInfo& info) {
    114   void* pixels = NULL;
    115   if (!CreateDumbBuffer(dri_, info, &handle_, &stride_, &pixels)) {
    116     DLOG(ERROR) << "Cannot allocate drm dumb buffer";
    117     return false;
    118   }
    119 
    120   if (!dri_->AddFramebuffer(info.width(),
    121                             info.height(),
    122                             GetColorDepth(info.colorType()),
    123                             info.bytesPerPixel() << 3,
    124                             stride_,
    125                             handle_,
    126                             &framebuffer_)) {
    127     DLOG(ERROR) << "Failed to register framebuffer: " << strerror(errno);
    128     return false;
    129   }
    130 
    131   surface_ = skia::AdoptRef(SkSurface::NewRasterDirect(info, pixels, stride_));
    132   if (!surface_) {
    133     DLOG(ERROR) << "Cannot install Skia pixels for drm buffer";
    134     return false;
    135   }
    136 
    137   return true;
    138 }
    139 
    140 }  // namespace ui
    141