e5490fd4d9f1438aa281d0ef93f9ddd93623bb1c
[platform/framework/web/crosswalk.git] / src / ui / gfx / ozone / dri / dri_skbitmap.cc
1 // Copyright 2013 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/gfx/ozone/dri/dri_skbitmap.h"
6
7 #include <errno.h>
8 #include <sys/mman.h>
9 #include <sys/types.h>
10 #include <xf86drm.h>
11
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "third_party/skia/include/core/SkPixelRef.h"
15
16 namespace gfx {
17
18 namespace {
19
20 void DestroyDumbBuffer(int fd, uint32_t handle) {
21   struct drm_mode_destroy_dumb destroy_request;
22   destroy_request.handle = handle;
23   drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
24 }
25
26 // Special DRM implementation of a SkPixelRef. The DRM allocator will create a
27 // SkPixelRef for the backing pixels. It will then associate the SkPixelRef with
28 // the SkBitmap. SkBitmap will access the allocated memory by locking the pixels
29 // in the SkPixelRef.
30 // At the end of its life the SkPixelRef is responsible for deallocating the
31 // pixel memory.
32 class DriSkPixelRef : public SkPixelRef {
33  public:
34   DriSkPixelRef(const SkImageInfo& info,
35                 void* pixels,
36                 SkColorTable* color_table_,
37                 size_t size,
38                 size_t row_bites,
39                 int fd,
40                 uint32_t handle);
41   virtual ~DriSkPixelRef();
42
43   virtual bool onNewLockPixels(LockRec* rec) OVERRIDE;
44   virtual void onUnlockPixels() OVERRIDE;
45
46   SK_DECLARE_UNFLATTENABLE_OBJECT()
47  private:
48   // Raw pointer to the pixel memory.
49   void* pixels_;
50
51   // Optional color table associated with the pixel memory.
52   SkColorTable* color_table_;
53
54   // Size of the allocated memory.
55   size_t size_;
56
57   // Number of bytes between subsequent rows in the bitmap (stride).
58   size_t row_bytes_;
59
60   // File descriptor to the graphics card used to allocate/deallocate the
61   // memory.
62   int fd_;
63
64   // Handle for the allocated memory.
65   uint32_t handle_;
66
67   DISALLOW_COPY_AND_ASSIGN(DriSkPixelRef);
68 };
69
70 ////////////////////////////////////////////////////////////////////////////////
71 // DriSkPixelRef implementation
72
73 DriSkPixelRef::DriSkPixelRef(
74     const SkImageInfo& info,
75     void* pixels,
76     SkColorTable* color_table,
77     size_t size,
78     size_t row_bytes,
79     int fd,
80     uint32_t handle)
81   : SkPixelRef(info),
82     pixels_(pixels),
83     color_table_(color_table),
84     size_(size),
85     row_bytes_(row_bytes),
86     fd_(fd),
87     handle_(handle) {
88 }
89
90 DriSkPixelRef::~DriSkPixelRef() {
91   munmap(pixels_, size_);
92   DestroyDumbBuffer(fd_, handle_);
93 }
94
95 bool DriSkPixelRef::onNewLockPixels(LockRec* rec) {
96   rec->fPixels = pixels_;
97   rec->fRowBytes = row_bytes_;
98   rec->fColorTable = color_table_;
99   return true;
100 }
101
102 void DriSkPixelRef::onUnlockPixels() {
103 }
104
105 }  // namespace
106
107 // Allocates pixel memory for a SkBitmap using DRM dumb buffers.
108 class DriAllocator : public SkBitmap::Allocator {
109  public:
110   DriAllocator();
111
112   virtual bool allocPixelRef(SkBitmap* bitmap,
113                              SkColorTable* color_table) OVERRIDE;
114
115  private:
116   bool AllocatePixels(DriSkBitmap* bitmap, SkColorTable* color_table);
117
118   DISALLOW_COPY_AND_ASSIGN(DriAllocator);
119 };
120
121 ////////////////////////////////////////////////////////////////////////////////
122 // DriAllocator implementation
123
124 DriAllocator::DriAllocator() {
125 }
126
127 bool DriAllocator::allocPixelRef(SkBitmap* bitmap,
128                                  SkColorTable* color_table) {
129   return AllocatePixels(static_cast<DriSkBitmap*>(bitmap), color_table);
130 }
131
132 bool DriAllocator::AllocatePixels(DriSkBitmap* bitmap,
133                                   SkColorTable* color_table) {
134   struct drm_mode_create_dumb request;
135   request.width = bitmap->width();
136   request.height = bitmap->height();
137   request.bpp = bitmap->bytesPerPixel() << 3;
138   request.flags = 0;
139
140   if (drmIoctl(bitmap->get_fd(), DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) {
141     DLOG(ERROR) << "Cannot create dumb buffer (" << errno << ") "
142                 << strerror(errno);
143     return false;
144   }
145
146   CHECK(request.size == bitmap->getSize());
147
148   bitmap->set_handle(request.handle);
149
150   struct drm_mode_map_dumb map_request;
151   map_request.handle = bitmap->get_handle();
152   if (drmIoctl(bitmap->get_fd(), DRM_IOCTL_MODE_MAP_DUMB, &map_request)) {
153     DLOG(ERROR) << "Cannot prepare dumb buffer for mapping (" << errno << ") "
154                 << strerror(errno);
155     DestroyDumbBuffer(bitmap->get_fd(), bitmap->get_handle());
156     return false;
157   }
158
159   void* pixels = mmap(0,
160                       bitmap->getSize(),
161                       PROT_READ | PROT_WRITE,
162                       MAP_SHARED,
163                       bitmap->get_fd(),
164                       map_request.offset);
165   if (pixels == MAP_FAILED) {
166     DLOG(ERROR) << "Cannot mmap dumb buffer (" << errno << ") "
167                 << strerror(errno);
168     DestroyDumbBuffer(bitmap->get_fd(), bitmap->get_handle());
169     return false;
170   }
171
172   SkImageInfo info;
173   if (!bitmap->asImageInfo(&info)) {
174     DLOG(ERROR) << "Cannot get skia image info";
175     DestroyDumbBuffer(bitmap->get_fd(), bitmap->get_handle());
176     return false;
177   }
178
179   bitmap->setPixelRef(new DriSkPixelRef(
180       info,
181       pixels,
182       color_table,
183       bitmap->getSize(),
184       bitmap->rowBytes(),
185       bitmap->get_fd(),
186       bitmap->get_handle()))->unref();
187   bitmap->lockPixels();
188
189   return true;
190 }
191
192 ////////////////////////////////////////////////////////////////////////////////
193 // DriSkBitmap implementation
194
195 DriSkBitmap::DriSkBitmap(int fd)
196   : fd_(fd),
197     handle_(0),
198     framebuffer_(0) {
199 }
200
201 DriSkBitmap::~DriSkBitmap() {
202 }
203
204 bool DriSkBitmap::Initialize() {
205   DriAllocator drm_allocator;
206   return allocPixels(&drm_allocator, NULL);
207 }
208
209 uint8_t DriSkBitmap::GetColorDepth() const {
210   switch (config()) {
211     case SkBitmap::kNo_Config:
212     case SkBitmap::kA8_Config:
213       return 0;
214     case SkBitmap::kIndex8_Config:
215       return 8;
216     case SkBitmap::kRGB_565_Config:
217       return 16;
218     case SkBitmap::kARGB_4444_Config:
219       return 12;
220     case SkBitmap::kARGB_8888_Config:
221       return 24;
222     default:
223       NOTREACHED();
224       return 0;
225   }
226 }
227
228 }  // namespace gfx