gralloc.cpp revision 988b8bd553180e8d71b4028ecb721f46312efe62
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#include <limits.h>
18
19#include <sys/mman.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22
23#include <cutils/ashmem.h>
24#include <cutils/log.h>
25
26#include <hardware/hardware.h>
27#include <hardware/gralloc.h>
28
29#include <fcntl.h>
30#include <errno.h>
31#include <pthread.h>
32
33#include <cutils/log.h>
34#include <cutils/atomic.h>
35
36#include "gralloc_priv.h"
37
38/*****************************************************************************/
39
40struct gralloc_context_t {
41    alloc_device_t  device;
42    /* our private data here */
43};
44
45static int gralloc_alloc_buffer(alloc_device_t* dev,
46        size_t size, int usage, buffer_handle_t* pHandle);
47
48/*****************************************************************************/
49
50int fb_device_open(const hw_module_t* module, const char* name,
51        hw_device_t** device);
52
53static int gralloc_device_open(const hw_module_t* module, const char* name,
54        hw_device_t** device);
55
56extern int gralloc_lock(gralloc_module_t const* module,
57        buffer_handle_t handle, int usage,
58        int l, int t, int w, int h,
59        void** vaddr);
60
61extern int gralloc_unlock(gralloc_module_t const* module,
62        buffer_handle_t handle);
63
64extern int gralloc_register_buffer(gralloc_module_t const* module,
65        buffer_handle_t handle);
66
67extern int gralloc_unregister_buffer(gralloc_module_t const* module,
68        buffer_handle_t handle);
69
70/*****************************************************************************/
71
72static struct hw_module_methods_t gralloc_module_methods = {
73        open: gralloc_device_open
74};
75
76struct private_module_t HAL_MODULE_INFO_SYM = {
77    base: {
78        common: {
79            tag: HARDWARE_MODULE_TAG,
80            version_major: 1,
81            version_minor: 0,
82            id: GRALLOC_HARDWARE_MODULE_ID,
83            name: "Graphics Memory Allocator Module",
84            author: "The Android Open Source Project",
85            methods: &gralloc_module_methods
86        },
87        registerBuffer: gralloc_register_buffer,
88        unregisterBuffer: gralloc_unregister_buffer,
89        lock: gralloc_lock,
90        unlock: gralloc_unlock,
91    },
92    framebuffer: 0,
93    flags: 0,
94    numBuffers: 0,
95    bufferMask: 0,
96    lock: PTHREAD_MUTEX_INITIALIZER,
97    currentBuffer: 0
98};
99
100/*****************************************************************************/
101
102static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev,
103        size_t size, int usage, buffer_handle_t* pHandle)
104{
105    private_module_t* m = reinterpret_cast<private_module_t*>(
106            dev->common.module);
107
108    // allocate the framebuffer
109    if (m->framebuffer == NULL) {
110        // initialize the framebuffer, the framebuffer is mapped once
111        // and forever.
112        int err = mapFrameBufferLocked(m);
113        if (err < 0) {
114            return err;
115        }
116    }
117
118    const uint32_t bufferMask = m->bufferMask;
119    const uint32_t numBuffers = m->numBuffers;
120    const size_t bufferSize = m->finfo.line_length * m->info.yres;
121    if (numBuffers == 1) {
122        // If we have only one buffer, we never use page-flipping. Instead,
123        // we return a regular buffer which will be memcpy'ed to the main
124        // screen when post is called.
125        int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
126        return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle);
127    }
128
129    if (bufferMask >= ((1LU<<numBuffers)-1)) {
130        // We ran out of buffers.
131        return -ENOMEM;
132    }
133
134    // create a "fake" handles for it
135    intptr_t vaddr = intptr_t(m->framebuffer->base);
136    private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
137            private_handle_t::PRIV_FLAGS_USES_PMEM |
138            private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
139
140    // find a free slot
141    for (uint32_t i=0 ; i<numBuffers ; i++) {
142        if ((bufferMask & (1LU<<i)) == 0) {
143            m->bufferMask |= (1LU<<i);
144            break;
145        }
146        vaddr += bufferSize;
147    }
148
149    hnd->base = vaddr;
150    *pHandle = hnd;
151
152    return 0;
153}
154
155static int gralloc_alloc_framebuffer(alloc_device_t* dev,
156        size_t size, int usage, buffer_handle_t* pHandle)
157{
158    private_module_t* m = reinterpret_cast<private_module_t*>(
159            dev->common.module);
160    pthread_mutex_lock(&m->lock);
161    int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);
162    pthread_mutex_unlock(&m->lock);
163    return err;
164}
165
166
167static int gralloc_alloc_buffer(alloc_device_t* dev,
168        size_t size, int usage, buffer_handle_t* pHandle)
169{
170    size = roundUpToPageSize(size);
171    int flags = 0;
172    if (usage & GRALLOC_USAGE_HW_2D) {
173        flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
174    }
175    int fd;
176    if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) == 0) {
177        fd = ashmem_create_region("Buffer", size);
178    } else {
179        fd = open("/dev/pmem", O_RDWR, 0);
180        // Note: Currently pmem get sized when it is mmaped.
181        // This means that just doing the open doesn't actually allocate
182        // anything. We basically need to do an implicit "mmap"
183        // (under the hood) for pmem regions. However, the current
184        // code will work okay for now thanks to the reference-counting.
185    }
186    if (fd < 0) {
187        return -errno;
188    }
189    private_handle_t* hnd = new private_handle_t(fd, size, flags);
190    *pHandle = hnd;
191    return 0;
192}
193
194/*****************************************************************************/
195
196static int gralloc_alloc(alloc_device_t* dev,
197        int w, int h, int format, int usage,
198        buffer_handle_t* pHandle, int* pStride)
199{
200    if (!pHandle || !pStride)
201        return -EINVAL;
202
203    int align = 4;
204    int bpp = 0;
205    switch (format) {
206        case HAL_PIXEL_FORMAT_RGBA_8888:
207        case HAL_PIXEL_FORMAT_BGRA_8888:
208            bpp = 4;
209            break;
210        case HAL_PIXEL_FORMAT_RGB_565:
211        case HAL_PIXEL_FORMAT_RGBA_5551:
212        case HAL_PIXEL_FORMAT_RGBA_4444:
213            bpp = 2;
214            break;
215        default:
216            return -EINVAL;
217    }
218
219    size_t bpr = (w*bpp + (align-1)) & ~(align-1);
220    size_t size = bpr * h;
221    size_t stride = bpr / bpp;
222
223    int err;
224    if (usage & GRALLOC_USAGE_HW_FB) {
225        err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);
226    } else {
227        err = gralloc_alloc_buffer(dev, size, usage, pHandle);
228    }
229    if (err < 0) {
230        return err;
231    }
232
233    *pStride = stride;
234    return 0;
235}
236
237static int gralloc_free(alloc_device_t* dev,
238        buffer_handle_t handle)
239{
240    if (private_handle_t::validate(handle) < 0)
241        return -EINVAL;
242
243    private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);
244    if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
245        // free this buffer
246        private_module_t* m = reinterpret_cast<private_module_t*>(
247                dev->common.module);
248        const size_t bufferSize = m->finfo.line_length * m->info.yres;
249        int index = (hnd->base - m->framebuffer->base) / bufferSize;
250        m->bufferMask &= ~(1<<index);
251    }
252
253    gralloc_module_t* m = reinterpret_cast<gralloc_module_t*>(
254            dev->common.module);
255    gralloc_unregister_buffer(m, handle);
256
257    close(hnd->fd);
258    delete hnd;
259    return 0;
260}
261
262/*****************************************************************************/
263
264static int gralloc_close(struct hw_device_t *dev)
265{
266    gralloc_context_t* ctx = reinterpret_cast<gralloc_context_t*>(dev);
267    if (ctx) {
268        /* TODO: keep a list of all buffer_handle_t created, and free them
269         * all here.
270         */
271        free(ctx);
272    }
273    return 0;
274}
275
276int gralloc_device_open(const hw_module_t* module, const char* name,
277        hw_device_t** device)
278{
279    int status = -EINVAL;
280    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
281        gralloc_context_t *dev;
282        dev = (gralloc_context_t*)malloc(sizeof(*dev));
283
284        /* initialize our state here */
285        memset(dev, 0, sizeof(*dev));
286
287        /* initialize the procs */
288        dev->device.common.tag = HARDWARE_DEVICE_TAG;
289        dev->device.common.version = 0;
290        dev->device.common.module = const_cast<hw_module_t*>(module);
291        dev->device.common.close = gralloc_close;
292
293        dev->device.alloc   = gralloc_alloc;
294        dev->device.free    = gralloc_free;
295
296        *device = &dev->device.common;
297        status = 0;
298    } else {
299        status = fb_device_open(module, name, device);
300    }
301    return status;
302}
303