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