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