diff options
author | Mathias Agopian <mathias@google.com> | 2009-04-10 14:24:31 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2009-04-10 14:24:31 -0700 |
commit | a8a75166a2d3c7639a7432a67075c98796165206 (patch) | |
tree | 38811b92caa0085a823a805b1706917a8b8540f2 /modules/gralloc/gralloc.cpp | |
parent | cfce2add7e2bac420f2b720bcb5ece0339b7a86d (diff) | |
download | hardware_libhardware-a8a75166a2d3c7639a7432a67075c98796165206.zip hardware_libhardware-a8a75166a2d3c7639a7432a67075c98796165206.tar.gz hardware_libhardware-a8a75166a2d3c7639a7432a67075c98796165206.tar.bz2 |
Integrate from //sandbox/mathias/donut/...@145728
SurfaceFlinger rework for new EGL driver model support.
Diffstat (limited to 'modules/gralloc/gralloc.cpp')
-rw-r--r-- | modules/gralloc/gralloc.cpp | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/modules/gralloc/gralloc.cpp b/modules/gralloc/gralloc.cpp new file mode 100644 index 0000000..67febd8 --- /dev/null +++ b/modules/gralloc/gralloc.cpp @@ -0,0 +1,320 @@ +/* + * 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 <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <cutils/ashmem.h> +#include <cutils/log.h> + +#include <hardware/hardware.h> +#include <hardware/gralloc.h> + +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> + +#include <cutils/log.h> +#include <cutils/atomic.h> + +#include "gralloc_priv.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_map(gralloc_module_t const* module, + buffer_handle_t handle, void** vaddr); + +extern int gralloc_unmap(gralloc_module_t const* module, + buffer_handle_t handle); + +extern int gralloc_lock(gralloc_module_t const* module, + buffer_handle_t handle, int usage, + int l, int t, int w, int h); + +extern int gralloc_unlock(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 + }, + map: gralloc_map, + unmap: gralloc_unmap, + lock: gralloc_lock, + unlock: gralloc_unlock, + }, + framebuffer: 0, + flags: 0, + numBuffers: 0, + bufferMask: 0, + lock: PTHREAD_MUTEX_INITIALIZER, + currentBuffer: 0 +}; + +/*****************************************************************************/ + +/* + * This function creates a buffer_handle_t initialized with the given fd. + * the offset passed in parameter is used to mmap() this fd later at this + * offset. + */ + +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 + int err = mapFrameBufferLocked(m); + if (err < 0) { + return err; + } + } + + if (m->framebuffer->base == 0) { + void *vaddr; + m->base.map(&m->base, m->framebuffer, &vaddr); + } + + 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_USES_PMEM | + 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; + *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) +{ + size = roundUpToPageSize(size); + int flags = 0; + if (usage & GRALLOC_USAGE_HW_2D) { + flags |= private_handle_t::PRIV_FLAGS_USES_PMEM; + } + int fd; + if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) == 0) { + fd = ashmem_create_region("Buffer", size); + } else { + fd = open("/dev/pmem", O_RDWR, 0); + // Note: Currently pmem get sized when it is mmaped. + // This means that just doing the open doesn't actually allocate + // anything. We basically need to do an implicit "mmap" + // (under the hood) for pmem regions. However, the current + // code will work okay for now thanks to the reference-counting. + } + if (fd < 0) { + return -errno; + } + private_handle_t* hnd = new private_handle_t(fd, size, flags); + *pHandle = hnd; + return 0; +} + +/*****************************************************************************/ + +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; + + int align = 4; + int bpp = 0; + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + bpp = 4; + 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_t size = bpr * h; + size_t 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); + } + + if (hnd->base) { + LOGW("Freeing mapped handle %p", hnd); + gralloc_unmap((gralloc_module_t*) dev->common.module, handle); + } + + 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 + */ + + private_module_t* m = reinterpret_cast<private_module_t*>(dev->module); + pthread_mutex_lock(&m->lock); + if (m->framebuffer) { + m->base.unmap(&m->base, m->framebuffer); + } + pthread_mutex_unlock(&m->lock); + + 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; +} |