• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
GetColorDepth(SkColorType type)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 
DestroyDumbBuffer(int fd,uint32_t handle)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 
CreateDumbBuffer(DriWrapper * dri,const SkImageInfo & info,uint32_t * handle,uint32_t * stride,void ** pixels)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 
DriBuffer(DriWrapper * dri)94 DriBuffer::DriBuffer(DriWrapper* dri)
95     : dri_(dri), handle_(0), framebuffer_(0) {}
96 
~DriBuffer()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 
Initialize(const SkImageInfo & info)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