summaryrefslogtreecommitdiffstats
path: root/modules/gralloc/gralloc.cpp
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2009-04-10 14:24:31 -0700
committerMathias Agopian <mathias@google.com>2009-04-10 14:24:31 -0700
commita8a75166a2d3c7639a7432a67075c98796165206 (patch)
tree38811b92caa0085a823a805b1706917a8b8540f2 /modules/gralloc/gralloc.cpp
parentcfce2add7e2bac420f2b720bcb5ece0339b7a86d (diff)
downloadhardware_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.cpp320
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;
+}