diff options
Diffstat (limited to 'libgralloc/gralloc.cpp')
-rw-r--r-- | libgralloc/gralloc.cpp | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/libgralloc/gralloc.cpp b/libgralloc/gralloc.cpp new file mode 100644 index 0000000..dcd2e2b --- /dev/null +++ b/libgralloc/gralloc.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <cutils/ashmem.h> +#include <cutils/log.h> +#include <cutils/atomic.h> + +#include <hardware/hardware.h> +#include <hardware/gralloc.h> + +#include "gralloc_priv.h" +#include "gr.h" + +/*****************************************************************************/ + +struct gralloc_context_t { + alloc_device_t device; + /* our private data here */ +}; + +static int gralloc_alloc_buffer(alloc_device_t* dev, + size_t size, int usage, buffer_handle_t* pHandle); + +/*****************************************************************************/ + +int fb_device_open(const hw_module_t* module, const char* name, + hw_device_t** device); + +static int gralloc_device_open(const hw_module_t* module, const char* name, + hw_device_t** device); + +extern int gralloc_lock(gralloc_module_t const* module, + buffer_handle_t handle, int usage, + int l, int t, int w, int h, + void** vaddr); + +extern int gralloc_unlock(gralloc_module_t const* module, + buffer_handle_t handle); + +extern int gralloc_register_buffer(gralloc_module_t const* module, + buffer_handle_t handle); + +extern int gralloc_unregister_buffer(gralloc_module_t const* module, + buffer_handle_t handle); + +/*****************************************************************************/ + +static struct hw_module_methods_t gralloc_module_methods = { + open: gralloc_device_open +}; + +struct private_module_t HAL_MODULE_INFO_SYM = { + base: { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: GRALLOC_HARDWARE_MODULE_ID, + name: "Graphics Memory Allocator Module", + author: "The Android Open Source Project", + methods: &gralloc_module_methods + }, + registerBuffer: gralloc_register_buffer, + unregisterBuffer: gralloc_unregister_buffer, + lock: gralloc_lock, + unlock: gralloc_unlock, + }, + framebuffer: 0, + flags: 0, + numBuffers: 0, + bufferMask: 0, + lock: PTHREAD_MUTEX_INITIALIZER, + currentBuffer: 0, +}; + +/*****************************************************************************/ + +static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev, + size_t size, int usage, buffer_handle_t* pHandle) +{ + private_module_t* m = reinterpret_cast<private_module_t*>( + dev->common.module); + + // allocate the framebuffer + if (m->framebuffer == NULL) { + // initialize the framebuffer, the framebuffer is mapped once + // and forever. + int err = mapFrameBufferLocked(m); + if (err < 0) { + return err; + } + } + + const uint32_t bufferMask = m->bufferMask; + const uint32_t numBuffers = m->numBuffers; + const size_t bufferSize = m->finfo.line_length * m->info.yres; + if (numBuffers == 1) { + // If we have only one buffer, we never use page-flipping. Instead, + // we return a regular buffer which will be memcpy'ed to the main + // screen when post is called. + int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D; + return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle); + } + + if (bufferMask >= ((1LU<<numBuffers)-1)) { + // We ran out of buffers. + return -ENOMEM; + } + + // create a "fake" handles for it + intptr_t vaddr = intptr_t(m->framebuffer->base); + private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size, + private_handle_t::PRIV_FLAGS_FRAMEBUFFER); + + // find a free slot + for (uint32_t i=0 ; i<numBuffers ; i++) { + if ((bufferMask & (1LU<<i)) == 0) { + m->bufferMask |= (1LU<<i); + break; + } + vaddr += bufferSize; + } + + hnd->base = vaddr; + hnd->offset = vaddr - intptr_t(m->framebuffer->base); + *pHandle = hnd; + + return 0; +} + +static int gralloc_alloc_framebuffer(alloc_device_t* dev, + size_t size, int usage, buffer_handle_t* pHandle) +{ + private_module_t* m = reinterpret_cast<private_module_t*>( + dev->common.module); + pthread_mutex_lock(&m->lock); + int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle); + pthread_mutex_unlock(&m->lock); + return err; +} + +static int gralloc_alloc_buffer(alloc_device_t* dev, + size_t size, int usage, buffer_handle_t* pHandle) +{ + int err = 0; + int fd = -1; + + size = roundUpToPageSize(size); + + fd = ashmem_create_region("gralloc-buffer", size); + if (fd < 0) { + LOGE("couldn't create ashmem (%s)", strerror(-errno)); + err = -errno; + } + + if (err == 0) { + private_handle_t* hnd = new private_handle_t(fd, size, 0); + gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>( + dev->common.module); + err = mapBuffer(module, hnd); + if (err == 0) { + *pHandle = hnd; + } + } + + LOGE_IF(err, "gralloc failed err=%s", strerror(-err)); + + return err; +} + +/*****************************************************************************/ + +static int gralloc_alloc(alloc_device_t* dev, + int w, int h, int format, int usage, + buffer_handle_t* pHandle, int* pStride) +{ + if (!pHandle || !pStride) + return -EINVAL; + + size_t size, stride; + + int align = 4; + int bpp = 0; + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + bpp = 4; + break; + case HAL_PIXEL_FORMAT_RGB_888: + bpp = 3; + break; + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + bpp = 2; + break; + default: + return -EINVAL; + } + size_t bpr = (w*bpp + (align-1)) & ~(align-1); + size = bpr * h; + stride = bpr / bpp; + + int err; + if (usage & GRALLOC_USAGE_HW_FB) { + err = gralloc_alloc_framebuffer(dev, size, usage, pHandle); + } else { + err = gralloc_alloc_buffer(dev, size, usage, pHandle); + } + + if (err < 0) { + return err; + } + + *pStride = stride; + return 0; +} + +static int gralloc_free(alloc_device_t* dev, + buffer_handle_t handle) +{ + if (private_handle_t::validate(handle) < 0) + return -EINVAL; + + private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle); + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + // free this buffer + private_module_t* m = reinterpret_cast<private_module_t*>( + dev->common.module); + const size_t bufferSize = m->finfo.line_length * m->info.yres; + int index = (hnd->base - m->framebuffer->base) / bufferSize; + m->bufferMask &= ~(1<<index); + } else { + gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>( + dev->common.module); + terminateBuffer(module, const_cast<private_handle_t*>(hnd)); + } + + close(hnd->fd); + delete hnd; + return 0; +} + +/*****************************************************************************/ + +static int gralloc_close(struct hw_device_t *dev) +{ + gralloc_context_t* ctx = reinterpret_cast<gralloc_context_t*>(dev); + if (ctx) { + /* TODO: keep a list of all buffer_handle_t created, and free them + * all here. + */ + free(ctx); + } + return 0; +} + +int gralloc_device_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + int status = -EINVAL; + if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) { + gralloc_context_t *dev; + dev = (gralloc_context_t*)malloc(sizeof(*dev)); + + /* initialize our state here */ + memset(dev, 0, sizeof(*dev)); + + /* initialize the procs */ + dev->device.common.tag = HARDWARE_DEVICE_TAG; + dev->device.common.version = 0; + dev->device.common.module = const_cast<hw_module_t*>(module); + dev->device.common.close = gralloc_close; + + dev->device.alloc = gralloc_alloc; + dev->device.free = gralloc_free; + + *device = &dev->device.common; + status = 0; + } else { + status = fb_device_open(module, name, device); + } + return status; +} |