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 | ||
788e20df SK |
47 | #define ION_HEAP_EXYNOS_CONTIG_MASK (1 << 4) |
48 | #define ION_EXYNOS_VIDEO_MASK (1 << 29) | |
49 | ||
2480eccc RSZ |
50 | /*****************************************************************************/ |
51 | ||
52 | struct gralloc_context_t { | |
53 | alloc_device_t device; | |
54 | /* our private data here */ | |
55 | }; | |
56 | ||
57 | static int gralloc_alloc_buffer(alloc_device_t* dev, | |
58 | size_t size, int usage, buffer_handle_t* pHandle); | |
59 | ||
60 | /*****************************************************************************/ | |
61 | ||
62 | int fb_device_open(const hw_module_t* module, const char* name, | |
63 | hw_device_t** device); | |
64 | ||
65 | static int gralloc_device_open(const hw_module_t* module, const char* name, | |
66 | hw_device_t** device); | |
67 | ||
68 | extern int gralloc_lock(gralloc_module_t const* module, | |
69 | buffer_handle_t handle, int usage, | |
70 | int l, int t, int w, int h, | |
71 | void** vaddr); | |
72 | ||
73 | extern int gralloc_unlock(gralloc_module_t const* module, | |
74 | buffer_handle_t handle); | |
75 | ||
76 | extern int gralloc_register_buffer(gralloc_module_t const* module, | |
77 | buffer_handle_t handle); | |
78 | ||
79 | extern int gralloc_unregister_buffer(gralloc_module_t const* module, | |
80 | buffer_handle_t handle); | |
81 | ||
82 | /*****************************************************************************/ | |
83 | ||
84 | static struct hw_module_methods_t gralloc_module_methods = { | |
85 | open: gralloc_device_open | |
86 | }; | |
87 | ||
88 | struct private_module_t HAL_MODULE_INFO_SYM = { | |
89 | base: { | |
90 | common: { | |
91 | tag: HARDWARE_MODULE_TAG, | |
92 | version_major: 1, | |
93 | version_minor: 0, | |
94 | id: GRALLOC_HARDWARE_MODULE_ID, | |
95 | name: "Graphics Memory Allocator Module", | |
96 | author: "The Android Open Source Project", | |
97 | methods: &gralloc_module_methods | |
98 | }, | |
ec68ab21 RSZ |
99 | registerBuffer: gralloc_register_buffer, |
100 | unregisterBuffer: gralloc_unregister_buffer, | |
101 | lock: gralloc_lock, | |
102 | unlock: gralloc_unlock, | |
2480eccc | 103 | }, |
ec68ab21 RSZ |
104 | framebuffer: 0, |
105 | flags: 0, | |
106 | numBuffers: 0, | |
107 | bufferMask: 0, | |
108 | lock: PTHREAD_MUTEX_INITIALIZER, | |
109 | currentBuffer: 0, | |
110 | ionfd: -1, | |
2480eccc RSZ |
111 | }; |
112 | ||
113 | /*****************************************************************************/ | |
114 | ||
115 | #define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1)) | |
116 | ||
788e20df SK |
117 | static unsigned int _select_heap(int usage) |
118 | { | |
119 | unsigned int heap_mask; | |
120 | ||
121 | if (usage & GRALLOC_USAGE_PROTECTED) | |
122 | heap_mask = ION_HEAP_EXYNOS_CONTIG_MASK; | |
123 | else | |
124 | heap_mask = ION_HEAP_SYSTEM_MASK; | |
125 | ||
126 | return heap_mask; | |
127 | } | |
128 | ||
da3d8712 RSZ |
129 | static int gralloc_alloc_rgb(int ionfd, int w, int h, int format, int usage, |
130 | unsigned int ion_flags, private_handle_t **hnd, int *stride) | |
2480eccc RSZ |
131 | { |
132 | size_t size, bpr; | |
70212e56 | 133 | int bpp = 0, vstride, fd, err; |
788e20df SK |
134 | unsigned int heap_mask = _select_heap(usage); |
135 | ||
2480eccc RSZ |
136 | switch (format) { |
137 | case HAL_PIXEL_FORMAT_RGBA_8888: | |
138 | case HAL_PIXEL_FORMAT_RGBX_8888: | |
139 | case HAL_PIXEL_FORMAT_BGRA_8888: | |
140 | bpp = 4; | |
141 | break; | |
142 | case HAL_PIXEL_FORMAT_RGB_888: | |
143 | bpp = 3; | |
144 | break; | |
145 | case HAL_PIXEL_FORMAT_RGB_565: | |
146 | case HAL_PIXEL_FORMAT_RGBA_5551: | |
147 | case HAL_PIXEL_FORMAT_RGBA_4444: | |
148 | case HAL_PIXEL_FORMAT_RAW_SENSOR: | |
149 | bpp = 2; | |
150 | break; | |
151 | case HAL_PIXEL_FORMAT_BLOB: | |
152 | bpp = 1; | |
153 | break; | |
154 | default: | |
155 | return -EINVAL; | |
156 | } | |
157 | bpr = ALIGN(w*bpp, 16); | |
c41b757c GH |
158 | vstride = ALIGN(h, 16); |
159 | if (vstride == h) | |
160 | size = bpr * (vstride + 1); | |
161 | else | |
162 | size = bpr * vstride; | |
2480eccc RSZ |
163 | *stride = bpr / bpp; |
164 | size = ALIGN(size, PAGE_SIZE); | |
165 | ||
788e20df | 166 | err = ion_alloc_fd(ionfd, size, 0, heap_mask, ion_flags, |
da3d8712 RSZ |
167 | &fd); |
168 | *hnd = new private_handle_t(fd, size, usage, w, h, format, *stride, | |
169 | vstride); | |
2480eccc RSZ |
170 | |
171 | return err; | |
172 | } | |
173 | ||
55a3039b RSZ |
174 | static int gralloc_alloc_framework_yuv(int ionfd, int w, int h, int format, |
175 | int usage, unsigned int ion_flags, | |
176 | private_handle_t **hnd, int *stride) | |
177 | { | |
178 | size_t size; | |
179 | int err, fd; | |
180 | ||
181 | switch (format) { | |
182 | case HAL_PIXEL_FORMAT_YV12: | |
183 | *stride = ALIGN(w, 16); | |
184 | break; | |
185 | case HAL_PIXEL_FORMAT_YCrCb_420_SP: | |
186 | *stride = w; | |
187 | break; | |
188 | default: | |
bcf29611 RSZ |
189 | ALOGE("invalid yuv format %d\n", format); |
190 | return -EINVAL; | |
55a3039b RSZ |
191 | } |
192 | ||
193 | size = *stride * h * 3 / 2; | |
194 | err = ion_alloc_fd(ionfd, size, 0, 1 << ION_HEAP_TYPE_SYSTEM, | |
195 | ion_flags, &fd); | |
196 | if (err) | |
197 | return err; | |
198 | ||
199 | *hnd = new private_handle_t(fd, size, usage, w, h, format, *stride, h); | |
200 | return err; | |
201 | } | |
202 | ||
203 | static int gralloc_alloc_yuv(int ionfd, int w, int h, int format, | |
204 | int usage, unsigned int ion_flags, | |
205 | private_handle_t **hnd, int *stride) | |
2480eccc RSZ |
206 | { |
207 | size_t luma_size, chroma_size; | |
208 | int err, planes, fd, fd1, fd2 = 0; | |
70212e56 | 209 | size_t luma_vstride; |
788e20df SK |
210 | unsigned int heap_mask = _select_heap(usage); |
211 | ||
2480eccc RSZ |
212 | *stride = ALIGN(w, 16); |
213 | ||
214 | switch (format) { | |
c853be7b | 215 | case HAL_PIXEL_FORMAT_EXYNOS_YV12: |
bcf29611 RSZ |
216 | { |
217 | luma_vstride = ALIGN(h, 16); | |
218 | luma_size = luma_vstride * *stride; | |
219 | chroma_size = (luma_vstride / 2) * ALIGN(*stride / 2, 16); | |
220 | planes = 3; | |
221 | break; | |
222 | } | |
c853be7b | 223 | case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP: |
2480eccc RSZ |
224 | case HAL_PIXEL_FORMAT_YCbCr_420_SP: |
225 | case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: | |
bcf29611 RSZ |
226 | { |
227 | size_t chroma_vstride = ALIGN(h / 2, 32); | |
228 | luma_vstride = ALIGN(h, 32); | |
229 | luma_size = luma_vstride * *stride; | |
230 | chroma_size = chroma_vstride * *stride; | |
231 | planes = 2; | |
232 | break; | |
233 | } | |
55a3039b RSZ |
234 | case HAL_PIXEL_FORMAT_YV12: |
235 | case HAL_PIXEL_FORMAT_YCrCb_420_SP: | |
236 | return gralloc_alloc_framework_yuv(ionfd, w, h, format, usage, | |
237 | ion_flags, hnd, stride); | |
2480eccc | 238 | default: |
bcf29611 RSZ |
239 | ALOGE("invalid yuv format %d\n", format); |
240 | return -EINVAL; | |
2480eccc RSZ |
241 | } |
242 | ||
788e20df | 243 | err = ion_alloc_fd(ionfd, luma_size, 0, heap_mask, ion_flags, &fd); |
2480eccc RSZ |
244 | if (err) |
245 | return err; | |
788e20df | 246 | err = ion_alloc_fd(ionfd, chroma_size, 0, heap_mask, ion_flags, &fd1); |
2480eccc RSZ |
247 | if (err) |
248 | goto err1; | |
249 | if (planes == 3) { | |
788e20df | 250 | err = ion_alloc_fd(ionfd, chroma_size, 0, heap_mask, ion_flags, &fd2); |
2480eccc RSZ |
251 | if (err) |
252 | goto err2; | |
2480eccc | 253 | |
ec68ab21 RSZ |
254 | *hnd = new private_handle_t(fd, fd1, fd2, luma_size, usage, w, h, |
255 | format, *stride, luma_vstride); | |
256 | } else { | |
257 | *hnd = new private_handle_t(fd, fd1, luma_size, usage, w, h, format, | |
258 | *stride, luma_vstride); | |
259 | } | |
2480eccc RSZ |
260 | return err; |
261 | ||
262 | err2: | |
263 | close(fd1); | |
264 | err1: | |
265 | close(fd); | |
266 | return err; | |
267 | } | |
268 | ||
269 | static int gralloc_alloc(alloc_device_t* dev, | |
270 | int w, int h, int format, int usage, | |
271 | buffer_handle_t* pHandle, int* pStride) | |
272 | { | |
273 | int stride; | |
274 | int err; | |
da3d8712 | 275 | unsigned int ion_flags = 0; |
2480eccc RSZ |
276 | private_handle_t *hnd; |
277 | ||
278 | if (!pHandle || !pStride) | |
279 | return -EINVAL; | |
280 | ||
281 | if( (usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN ) | |
da3d8712 | 282 | ion_flags = ION_FLAG_CACHED; |
788e20df SK |
283 | if (usage & GRALLOC_USAGE_PROTECTED) |
284 | ion_flags |= ION_EXYNOS_VIDEO_MASK; | |
2480eccc RSZ |
285 | |
286 | private_module_t* m = reinterpret_cast<private_module_t*> | |
287 | (dev->common.module); | |
288 | gralloc_module_t* module = reinterpret_cast<gralloc_module_t*> | |
289 | (dev->common.module); | |
290 | ||
da3d8712 RSZ |
291 | err = gralloc_alloc_rgb(m->ionfd, w, h, format, usage, ion_flags, &hnd, |
292 | &stride); | |
2480eccc | 293 | if (err) |
da3d8712 RSZ |
294 | err = gralloc_alloc_yuv(m->ionfd, w, h, format, usage, ion_flags, |
295 | &hnd, &stride); | |
2480eccc RSZ |
296 | if (err) |
297 | return err; | |
298 | ||
299 | err = grallocMap(module, hnd); | |
300 | ||
301 | if (err != 0) | |
302 | goto err; | |
303 | ||
304 | *pHandle = hnd; | |
305 | *pStride = stride; | |
306 | return 0; | |
307 | err: | |
308 | close(hnd->fd); | |
ec68ab21 | 309 | if (hnd->fd1 >= 0) |
2480eccc | 310 | close(hnd->fd1); |
ec68ab21 | 311 | if (hnd->fd2 >= 0) |
2480eccc RSZ |
312 | close(hnd->fd2); |
313 | return err; | |
314 | } | |
315 | ||
316 | static int gralloc_free(alloc_device_t* dev, | |
317 | buffer_handle_t handle) | |
318 | { | |
319 | if (private_handle_t::validate(handle) < 0) | |
320 | return -EINVAL; | |
321 | ||
322 | private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle); | |
323 | gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>( | |
324 | dev->common.module); | |
325 | ||
326 | grallocUnmap(module, const_cast<private_handle_t*>(hnd)); | |
327 | close(hnd->fd); | |
ec68ab21 | 328 | if (hnd->fd1 >= 0) |
2480eccc | 329 | close(hnd->fd1); |
ec68ab21 | 330 | if (hnd->fd2 >= 0) |
2480eccc RSZ |
331 | close(hnd->fd2); |
332 | ||
333 | delete hnd; | |
334 | return 0; | |
335 | } | |
336 | ||
337 | /*****************************************************************************/ | |
338 | ||
339 | static int gralloc_close(struct hw_device_t *dev) | |
340 | { | |
341 | gralloc_context_t* ctx = reinterpret_cast<gralloc_context_t*>(dev); | |
342 | if (ctx) { | |
343 | /* TODO: keep a list of all buffer_handle_t created, and free them | |
344 | * all here. | |
345 | */ | |
346 | free(ctx); | |
347 | } | |
348 | return 0; | |
349 | } | |
350 | ||
351 | int gralloc_device_open(const hw_module_t* module, const char* name, | |
352 | hw_device_t** device) | |
353 | { | |
354 | int status = -EINVAL; | |
355 | if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) { | |
356 | gralloc_context_t *dev; | |
357 | dev = (gralloc_context_t*)malloc(sizeof(*dev)); | |
358 | ||
359 | /* initialize our state here */ | |
360 | memset(dev, 0, sizeof(*dev)); | |
361 | ||
362 | /* initialize the procs */ | |
363 | dev->device.common.tag = HARDWARE_DEVICE_TAG; | |
364 | dev->device.common.version = 0; | |
365 | dev->device.common.module = const_cast<hw_module_t*>(module); | |
366 | dev->device.common.close = gralloc_close; | |
367 | ||
368 | dev->device.alloc = gralloc_alloc; | |
369 | dev->device.free = gralloc_free; | |
370 | ||
371 | private_module_t *p = reinterpret_cast<private_module_t*>(dev->device.common.module); | |
372 | p->ionfd = ion_open(); | |
373 | ||
374 | *device = &dev->device.common; | |
375 | status = 0; | |
376 | } else { | |
377 | status = fb_device_open(module, name, device); | |
378 | } | |
379 | return status; | |
380 | } |