Commit | Line | Data |
---|---|---|
2480eccc RSZ |
1 | /* |
2 | * Copyright (C) 2008 The Android Open Source Project | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define | |
18 | # include <asm/page.h> | |
19 | #else | |
20 | # include <sys/user.h> | |
21 | #endif | |
22 | #include <limits.h> | |
23 | #include <unistd.h> | |
24 | #include <fcntl.h> | |
25 | #include <errno.h> | |
26 | #include <pthread.h> | |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | ||
30 | #include <sys/mman.h> | |
31 | #include <sys/stat.h> | |
32 | #include <sys/types.h> | |
33 | #include <sys/ioctl.h> | |
34 | ||
35 | #include <ion/ion.h> | |
36 | #include <linux/ion.h> | |
37 | #include <cutils/log.h> | |
38 | #include <cutils/atomic.h> | |
39 | ||
40 | #include <hardware/hardware.h> | |
41 | #include <hardware/gralloc.h> | |
42 | ||
43 | #include "gralloc_priv.h" | |
44 | #include "exynos_format.h" | |
45 | #include "gr.h" | |
46 | ||
47 | /*****************************************************************************/ | |
48 | ||
49 | struct gralloc_context_t { | |
50 | alloc_device_t device; | |
51 | /* our private data here */ | |
52 | }; | |
53 | ||
54 | static int gralloc_alloc_buffer(alloc_device_t* dev, | |
55 | size_t size, int usage, buffer_handle_t* pHandle); | |
56 | ||
57 | /*****************************************************************************/ | |
58 | ||
59 | int fb_device_open(const hw_module_t* module, const char* name, | |
60 | hw_device_t** device); | |
61 | ||
62 | static int gralloc_device_open(const hw_module_t* module, const char* name, | |
63 | hw_device_t** device); | |
64 | ||
65 | extern int gralloc_lock(gralloc_module_t const* module, | |
66 | buffer_handle_t handle, int usage, | |
67 | int l, int t, int w, int h, | |
68 | void** vaddr); | |
69 | ||
70 | extern int gralloc_unlock(gralloc_module_t const* module, | |
71 | buffer_handle_t handle); | |
72 | ||
73 | extern int gralloc_register_buffer(gralloc_module_t const* module, | |
74 | buffer_handle_t handle); | |
75 | ||
76 | extern int gralloc_unregister_buffer(gralloc_module_t const* module, | |
77 | buffer_handle_t handle); | |
78 | ||
79 | /*****************************************************************************/ | |
80 | ||
81 | static struct hw_module_methods_t gralloc_module_methods = { | |
82 | open: gralloc_device_open | |
83 | }; | |
84 | ||
85 | struct private_module_t HAL_MODULE_INFO_SYM = { | |
86 | base: { | |
87 | common: { | |
88 | tag: HARDWARE_MODULE_TAG, | |
89 | version_major: 1, | |
90 | version_minor: 0, | |
91 | id: GRALLOC_HARDWARE_MODULE_ID, | |
92 | name: "Graphics Memory Allocator Module", | |
93 | author: "The Android Open Source Project", | |
94 | methods: &gralloc_module_methods | |
95 | }, | |
ec68ab21 RSZ |
96 | registerBuffer: gralloc_register_buffer, |
97 | unregisterBuffer: gralloc_unregister_buffer, | |
98 | lock: gralloc_lock, | |
99 | unlock: gralloc_unlock, | |
2480eccc | 100 | }, |
ec68ab21 RSZ |
101 | framebuffer: 0, |
102 | flags: 0, | |
103 | numBuffers: 0, | |
104 | bufferMask: 0, | |
105 | lock: PTHREAD_MUTEX_INITIALIZER, | |
106 | currentBuffer: 0, | |
107 | ionfd: -1, | |
2480eccc RSZ |
108 | }; |
109 | ||
110 | /*****************************************************************************/ | |
111 | ||
112 | #define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1)) | |
113 | ||
da3d8712 RSZ |
114 | static int gralloc_alloc_rgb(int ionfd, int w, int h, int format, int usage, |
115 | unsigned int ion_flags, private_handle_t **hnd, int *stride) | |
2480eccc RSZ |
116 | { |
117 | size_t size, bpr; | |
70212e56 | 118 | int bpp = 0, vstride, fd, err; |
2480eccc RSZ |
119 | switch (format) { |
120 | case HAL_PIXEL_FORMAT_RGBA_8888: | |
121 | case HAL_PIXEL_FORMAT_RGBX_8888: | |
122 | case HAL_PIXEL_FORMAT_BGRA_8888: | |
123 | bpp = 4; | |
124 | break; | |
125 | case HAL_PIXEL_FORMAT_RGB_888: | |
126 | bpp = 3; | |
127 | break; | |
128 | case HAL_PIXEL_FORMAT_RGB_565: | |
129 | case HAL_PIXEL_FORMAT_RGBA_5551: | |
130 | case HAL_PIXEL_FORMAT_RGBA_4444: | |
131 | case HAL_PIXEL_FORMAT_RAW_SENSOR: | |
132 | bpp = 2; | |
133 | break; | |
134 | case HAL_PIXEL_FORMAT_BLOB: | |
135 | bpp = 1; | |
136 | break; | |
137 | default: | |
138 | return -EINVAL; | |
139 | } | |
140 | bpr = ALIGN(w*bpp, 16); | |
70212e56 RSZ |
141 | vstride = ALIGN(h, 16); |
142 | size = bpr * vstride; | |
2480eccc RSZ |
143 | *stride = bpr / bpp; |
144 | size = ALIGN(size, PAGE_SIZE); | |
145 | ||
da3d8712 RSZ |
146 | err = ion_alloc_fd(ionfd, size, 0, 1 << ION_HEAP_TYPE_SYSTEM, ion_flags, |
147 | &fd); | |
148 | *hnd = new private_handle_t(fd, size, usage, w, h, format, *stride, | |
149 | vstride); | |
2480eccc RSZ |
150 | |
151 | return err; | |
152 | } | |
153 | ||
da3d8712 RSZ |
154 | static int gralloc_alloc_yuv(int ionfd, int w, int h, int format, int usage, |
155 | unsigned int ion_flags, private_handle_t **hnd, int *stride) | |
2480eccc RSZ |
156 | { |
157 | size_t luma_size, chroma_size; | |
158 | int err, planes, fd, fd1, fd2 = 0; | |
70212e56 | 159 | size_t luma_vstride; |
2480eccc RSZ |
160 | *stride = ALIGN(w, 16); |
161 | ||
162 | switch (format) { | |
163 | ALOGE("invalid yuv format %d\n", format); | |
c853be7b | 164 | case HAL_PIXEL_FORMAT_EXYNOS_YV12: |
2480eccc | 165 | { |
70212e56 RSZ |
166 | luma_vstride = ALIGN(h, 16); |
167 | luma_size = luma_vstride * *stride; | |
168 | chroma_size = (luma_vstride / 2) * ALIGN(*stride / 2, 16); | |
2480eccc RSZ |
169 | planes = 3; |
170 | break; | |
171 | } | |
c853be7b | 172 | case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP: |
2480eccc RSZ |
173 | case HAL_PIXEL_FORMAT_YCbCr_420_SP: |
174 | case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: | |
175 | { | |
2480eccc | 176 | size_t chroma_vstride = ALIGN(h / 2, 32); |
70212e56 | 177 | luma_vstride = ALIGN(h, 32); |
2480eccc RSZ |
178 | luma_size = luma_vstride * *stride; |
179 | chroma_size = chroma_vstride * *stride; | |
180 | planes = 2; | |
181 | break; | |
182 | } | |
183 | default: | |
184 | ALOGE("invalid yuv format %d\n", format); | |
185 | return -EINVAL; | |
186 | } | |
187 | ||
da3d8712 RSZ |
188 | err = ion_alloc_fd(ionfd, luma_size, 0, 1 << ION_HEAP_TYPE_SYSTEM, |
189 | ion_flags, &fd); | |
2480eccc RSZ |
190 | if (err) |
191 | return err; | |
da3d8712 RSZ |
192 | err = ion_alloc_fd(ionfd, chroma_size, 0, 1 << ION_HEAP_TYPE_SYSTEM, |
193 | ion_flags, | |
2480eccc RSZ |
194 | &fd1); |
195 | if (err) | |
196 | goto err1; | |
197 | if (planes == 3) { | |
198 | err = ion_alloc_fd(ionfd, chroma_size, 0, 1 << ION_HEAP_TYPE_SYSTEM, | |
da3d8712 | 199 | ion_flags, &fd2); |
2480eccc RSZ |
200 | if (err) |
201 | goto err2; | |
2480eccc | 202 | |
ec68ab21 RSZ |
203 | *hnd = new private_handle_t(fd, fd1, fd2, luma_size, usage, w, h, |
204 | format, *stride, luma_vstride); | |
205 | } else { | |
206 | *hnd = new private_handle_t(fd, fd1, luma_size, usage, w, h, format, | |
207 | *stride, luma_vstride); | |
208 | } | |
2480eccc RSZ |
209 | return err; |
210 | ||
211 | err2: | |
212 | close(fd1); | |
213 | err1: | |
214 | close(fd); | |
215 | return err; | |
216 | } | |
217 | ||
218 | static int gralloc_alloc(alloc_device_t* dev, | |
219 | int w, int h, int format, int usage, | |
220 | buffer_handle_t* pHandle, int* pStride) | |
221 | { | |
222 | int stride; | |
223 | int err; | |
da3d8712 | 224 | unsigned int ion_flags = 0; |
2480eccc RSZ |
225 | private_handle_t *hnd; |
226 | ||
227 | if (!pHandle || !pStride) | |
228 | return -EINVAL; | |
229 | ||
230 | if( (usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN ) | |
da3d8712 | 231 | ion_flags = ION_FLAG_CACHED; |
2480eccc RSZ |
232 | |
233 | private_module_t* m = reinterpret_cast<private_module_t*> | |
234 | (dev->common.module); | |
235 | gralloc_module_t* module = reinterpret_cast<gralloc_module_t*> | |
236 | (dev->common.module); | |
237 | ||
da3d8712 RSZ |
238 | err = gralloc_alloc_rgb(m->ionfd, w, h, format, usage, ion_flags, &hnd, |
239 | &stride); | |
2480eccc | 240 | if (err) |
da3d8712 RSZ |
241 | err = gralloc_alloc_yuv(m->ionfd, w, h, format, usage, ion_flags, |
242 | &hnd, &stride); | |
2480eccc RSZ |
243 | if (err) |
244 | return err; | |
245 | ||
246 | err = grallocMap(module, hnd); | |
247 | ||
248 | if (err != 0) | |
249 | goto err; | |
250 | ||
251 | *pHandle = hnd; | |
252 | *pStride = stride; | |
253 | return 0; | |
254 | err: | |
255 | close(hnd->fd); | |
ec68ab21 | 256 | if (hnd->fd1 >= 0) |
2480eccc | 257 | close(hnd->fd1); |
ec68ab21 | 258 | if (hnd->fd2 >= 0) |
2480eccc RSZ |
259 | close(hnd->fd2); |
260 | return err; | |
261 | } | |
262 | ||
263 | static int gralloc_free(alloc_device_t* dev, | |
264 | buffer_handle_t handle) | |
265 | { | |
266 | if (private_handle_t::validate(handle) < 0) | |
267 | return -EINVAL; | |
268 | ||
269 | private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle); | |
270 | gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>( | |
271 | dev->common.module); | |
272 | ||
273 | grallocUnmap(module, const_cast<private_handle_t*>(hnd)); | |
274 | close(hnd->fd); | |
ec68ab21 | 275 | if (hnd->fd1 >= 0) |
2480eccc | 276 | close(hnd->fd1); |
ec68ab21 | 277 | if (hnd->fd2 >= 0) |
2480eccc RSZ |
278 | close(hnd->fd2); |
279 | ||
280 | delete hnd; | |
281 | return 0; | |
282 | } | |
283 | ||
284 | /*****************************************************************************/ | |
285 | ||
286 | static int gralloc_close(struct hw_device_t *dev) | |
287 | { | |
288 | gralloc_context_t* ctx = reinterpret_cast<gralloc_context_t*>(dev); | |
289 | if (ctx) { | |
290 | /* TODO: keep a list of all buffer_handle_t created, and free them | |
291 | * all here. | |
292 | */ | |
293 | free(ctx); | |
294 | } | |
295 | return 0; | |
296 | } | |
297 | ||
298 | int gralloc_device_open(const hw_module_t* module, const char* name, | |
299 | hw_device_t** device) | |
300 | { | |
301 | int status = -EINVAL; | |
302 | if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) { | |
303 | gralloc_context_t *dev; | |
304 | dev = (gralloc_context_t*)malloc(sizeof(*dev)); | |
305 | ||
306 | /* initialize our state here */ | |
307 | memset(dev, 0, sizeof(*dev)); | |
308 | ||
309 | /* initialize the procs */ | |
310 | dev->device.common.tag = HARDWARE_DEVICE_TAG; | |
311 | dev->device.common.version = 0; | |
312 | dev->device.common.module = const_cast<hw_module_t*>(module); | |
313 | dev->device.common.close = gralloc_close; | |
314 | ||
315 | dev->device.alloc = gralloc_alloc; | |
316 | dev->device.free = gralloc_free; | |
317 | ||
318 | private_module_t *p = reinterpret_cast<private_module_t*>(dev->device.common.module); | |
319 | p->ionfd = ion_open(); | |
320 | ||
321 | *device = &dev->device.common; | |
322 | status = 0; | |
323 | } else { | |
324 | status = fb_device_open(module, name, device); | |
325 | } | |
326 | return status; | |
327 | } |