gralloc_ump: initial commit
From:
http://www.malideveloper.com/developer-resources/drivers/open-source-mali-gpus-android-gralloc-module.php
This is an Android Gralloc module which allocates memory from the
Unified Memory Profider (UMP) device driver. The Gralloc module is
used by Android's composition engine in order to allocate and manage
memory which is suitable for 2D and 3D graphics usage. The Mali driver
stack is able to use UMP memory directly, resulting in zero-copy
operations when compositing.
Signed-off-by: Angus Ainslie <angus.ainslie@linaro.org>
Signed-off-by: Zach Pfeffer <zach.pfeffer@linaro.org>
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..64cfb71
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2010 ARM Limited. All rights reserved.
+#
+# 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.
+
+ifeq ($(TARGET_BOARD_PLATFORM),origen)
+LOCAL_PATH := $(call my-dir)
+
+# HAL module implemenation, not prelinked and stored in
+# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
+include $(CLEAR_VARS)
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_SHARED_LIBRARIES := liblog libcutils libMali libGLESv1_CM libUMP
+LOCAL_CFLAGS := -fpermissive
+
+# Include the UMP header files
+LOCAL_C_INCLUDES := hardware/samsung/origen/ump/include
+
+LOCAL_SRC_FILES := \
+ gralloc_module.cpp \
+ alloc_device.cpp \
+ framebuffer_device.cpp
+
+LOCAL_MODULE := gralloc.origen
+LOCAL_MODULE_TAGS := eng
+LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc_ump\" -DGRALLOC_32_BITS -DSTANDARD_LINUX_SCREEN -fpermissive
+#LOCAL_CFLAGS+= -DMALI_VSYNC_EVENT_REPORT_ENABLE
+include $(BUILD_SHARED_LIBRARY)
+endif
\ No newline at end of file
diff --git a/alloc_device.cpp b/alloc_device.cpp
new file mode 100644
index 0000000..d46704b
--- /dev/null
+++ b/alloc_device.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2010 ARM Limited. All rights reserved.
+ *
+ * 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 <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include "alloc_device.h"
+#include "gralloc_priv.h"
+#include "gralloc_helper.h"
+#include "framebuffer_device.h"
+
+#include <ump/ump.h>
+#include <ump/ump_ref_drv.h>
+
+
+
+static int gralloc_alloc_buffer(alloc_device_t* dev, size_t size, int usage, buffer_handle_t* pHandle)
+{
+ ump_handle ump_mem_handle;
+ void *cpu_ptr;
+ ump_secure_id ump_id;
+ ump_alloc_constraints constraints;
+
+ size = round_up_to_page_size(size);
+
+ if( (usage&GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN )
+ {
+ constraints = UMP_REF_DRV_CONSTRAINT_USE_CACHE;
+ }
+ else
+ {
+ constraints = UMP_REF_DRV_CONSTRAINT_NONE;
+ }
+
+ ump_mem_handle = ump_ref_drv_allocate(size, constraints);
+ if (UMP_INVALID_MEMORY_HANDLE != ump_mem_handle)
+ {
+ cpu_ptr = ump_mapped_pointer_get(ump_mem_handle);
+ if (NULL != cpu_ptr)
+ {
+ ump_id = ump_secure_id_get(ump_mem_handle);
+ if (UMP_INVALID_SECURE_ID != ump_id)
+ {
+ private_handle_t* hnd = new private_handle_t(private_handle_t::PRIV_FLAGS_USES_UMP, size, (int)cpu_ptr,
+ private_handle_t::LOCK_STATE_MAPPED, ump_id, ump_mem_handle);
+ if (NULL != hnd)
+ {
+ *pHandle = hnd;
+ return 0;
+ }
+ else
+ {
+ LOGE("gralloc_alloc_buffer() failed to allocate handle");
+ }
+ }
+ else
+ {
+ LOGE("gralloc_alloc_buffer() failed to retrieve valid secure id");
+ }
+
+ ump_mapped_pointer_release(ump_mem_handle);
+ }
+ else
+ {
+ LOGE("gralloc_alloc_buffer() failed to map UMP memory");
+ }
+
+ ump_reference_release(ump_mem_handle);
+ }
+ else
+ {
+ LOGE("gralloc_alloc_buffer() failed to allcoate UMP memory");
+ }
+
+ return -1;
+}
+
+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 = init_frame_buffer_locked(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;
+ LOGE("fallback to single buffering");
+ return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle);
+ }
+
+ if (bufferMask >= ((1LU<<numBuffers)-1))
+ {
+ // We ran out of buffers.
+ return -ENOMEM;
+ }
+
+ int vaddr = m->framebuffer->base;
+ // find a free slot
+ for (uint32_t i=0 ; i<numBuffers ; i++)
+ {
+ if ((bufferMask & (1LU<<i)) == 0)
+ {
+ m->bufferMask |= (1LU<<i);
+ break;
+ }
+ vaddr += bufferSize;
+ }
+
+ // The entire framebuffer memory is already mapped, now create a buffer object for parts of this memory
+ private_handle_t* hnd = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, size, vaddr,
+ 0, dup(m->framebuffer->fd), vaddr - 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 alloc_device_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;
+ size_t stride;
+ if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP ||
+ format == HAL_PIXEL_FORMAT_YCbCr_422_SP ||
+ format == HAL_PIXEL_FORMAT_YV12 )
+ {
+ int vstride;
+ switch (format)
+ {
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+ stride = (w + 1) & ~1;
+ size = stride * h * 2;
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ stride = (w + 1) & ~1;
+ vstride = (h+1) & ~1;
+ size = (stride * vstride) + (w/2 * h/2) * 2;
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ stride = (w + 15) & ~15;
+ size = h * (stride + stride/2);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ else
+ {
+ int align = 8;
+ 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 alloc_device_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);
+ close(hnd->fd);
+ }
+ else if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_UMP)
+ {
+ ump_mapped_pointer_release((ump_handle)hnd->ump_mem_handle);
+ ump_reference_release((ump_handle)hnd->ump_mem_handle);
+ }
+
+ delete hnd;
+
+ return 0;
+}
+
+static int alloc_device_close(struct hw_device_t *device)
+{
+ alloc_device_t* dev = reinterpret_cast<alloc_device_t*>(device);
+ if (dev)
+ {
+ delete dev;
+ ump_close(); // Our UMP memory refs will be released automatically here...
+ }
+ return 0;
+}
+
+int alloc_device_open(hw_module_t const* module, const char* name, hw_device_t** device)
+{
+ alloc_device_t *dev;
+
+ dev = new alloc_device_t;
+ if (NULL == dev)
+ {
+ return -1;
+ }
+
+ ump_result ump_res = ump_open();
+ if (UMP_OK != ump_res)
+ {
+ LOGE("UMP open failed");
+ delete dev;
+ return -1;
+ }
+
+ /* initialize our state here */
+ memset(dev, 0, sizeof(*dev));
+
+ /* initialize the procs */
+ dev->common.tag = HARDWARE_DEVICE_TAG;
+ dev->common.version = 0;
+ dev->common.module = const_cast<hw_module_t*>(module);
+ dev->common.close = alloc_device_close;
+ dev->alloc = alloc_device_alloc;
+ dev->free = alloc_device_free;
+
+ *device = &dev->common;
+
+ return 0;
+}
diff --git a/alloc_device.h b/alloc_device.h
new file mode 100644
index 0000000..3e243e2
--- /dev/null
+++ b/alloc_device.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2010 ARM Limited. All rights reserved.
+ *
+ * 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 <hardware/hardware.h>
+
+// Create an alloc device
+int alloc_device_open(hw_module_t const* module, const char* name, hw_device_t** device);
diff --git a/framebuffer_device.cpp b/framebuffer_device.cpp
new file mode 100644
index 0000000..42578f2
--- /dev/null
+++ b/framebuffer_device.cpp
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2010 ARM Limited. All rights reserved.
+ *
+ * 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 <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include <GLES/gl.h>
+
+#ifdef MALI_VSYNC_EVENT_REPORT_ENABLE
+#include "gralloc_vsync_report.h"
+#endif
+
+#include "gralloc_priv.h"
+#include "gralloc_helper.h"
+
+// numbers of buffers for page flipping
+#define NUM_BUFFERS 2
+
+enum
+{
+ PAGE_FLIP = 0x00000001,
+};
+
+static int fb_set_swap_interval(struct framebuffer_device_t* dev, int interval)
+{
+ if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval)
+ {
+ return -EINVAL;
+ }
+
+ // Currently not implemented
+ return 0;
+}
+
+static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
+{
+ if (private_handle_t::validate(buffer) < 0)
+ {
+ return -EINVAL;
+ }
+
+ private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
+ private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);
+
+ if (m->currentBuffer)
+ {
+ m->base.unlock(&m->base, m->currentBuffer);
+ m->currentBuffer = 0;
+ }
+
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)
+ {
+ m->base.lock(&m->base, buffer, private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
+ 0, 0, m->info.xres, m->info.yres, NULL);
+
+ const size_t offset = hnd->base - m->framebuffer->base;
+ int interrupt;
+ m->info.activate = FB_ACTIVATE_VBL;
+ m->info.yoffset = offset / m->finfo.line_length;
+
+#ifdef STANDARD_LINUX_SCREEN
+#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
+#define S3CFB_SET_VSYNC_INT _IOW('F', 206, unsigned int)
+ if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) == -1)
+ {
+ LOGE("FBIOPAN_DISPLAY failed");
+ m->base.unlock(&m->base, buffer);
+ return 0;
+ }
+
+ // enable VSYNC
+ interrupt = 1;
+ if(ioctl(m->framebuffer->fd, S3CFB_SET_VSYNC_INT, &interrupt) < 0)
+ {
+ LOGE("S3CFB_SET_VSYNC_INT enable failed");
+ return 0;
+ }
+ // wait for VSYNC
+#ifdef MALI_VSYNC_EVENT_REPORT_ENABLE
+ gralloc_mali_vsync_report(MALI_VSYNC_EVENT_BEGIN_WAIT);
+#endif
+ if(ioctl(m->framebuffer->fd, FBIO_WAITFORVSYNC, 0) < 0)
+ {
+ LOGE("FBIO_WAITFORVSYNC failed");
+#ifdef MALI_VSYNC_EVENT_REPORT_ENABLE
+ gralloc_mali_vsync_report(MALI_VSYNC_EVENT_END_WAIT);
+#endif
+ return 0;
+ }
+#ifdef MALI_VSYNC_EVENT_REPORT_ENABLE
+ gralloc_mali_vsync_report(MALI_VSYNC_EVENT_END_WAIT);
+#endif
+ // disable VSYNC
+ interrupt = 0;
+ if(ioctl(m->framebuffer->fd, S3CFB_SET_VSYNC_INT, &interrupt) < 0)
+ {
+ LOGE("S3CFB_SET_VSYNC_INT disable failed");
+ return 0;
+ }
+#else
+ /*Standard Android way*/
+#ifdef MALI_VSYNC_EVENT_REPORT_ENABLE
+ gralloc_mali_vsync_report(MALI_VSYNC_EVENT_BEGIN_WAIT);
+#endif
+ if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1)
+ {
+ LOGE("FBIOPUT_VSCREENINFO failed");
+#ifdef MALI_VSYNC_EVENT_REPORT_ENABLE
+ gralloc_mali_vsync_report(MALI_VSYNC_EVENT_END_WAIT);
+#endif
+ m->base.unlock(&m->base, buffer);
+ return -errno;
+ }
+#ifdef MALI_VSYNC_EVENT_REPORT_ENABLE
+ gralloc_mali_vsync_report(MALI_VSYNC_EVENT_END_WAIT);
+#endif
+#endif
+
+ m->currentBuffer = buffer;
+ }
+ else
+ {
+ void* fb_vaddr;
+ void* buffer_vaddr;
+
+ m->base.lock(&m->base, m->framebuffer, GRALLOC_USAGE_SW_WRITE_RARELY,
+ 0, 0, m->info.xres, m->info.yres, &fb_vaddr);
+
+ m->base.lock(&m->base, buffer, GRALLOC_USAGE_SW_READ_RARELY,
+ 0, 0, m->info.xres, m->info.yres, &buffer_vaddr);
+
+ memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
+
+ m->base.unlock(&m->base, buffer);
+ m->base.unlock(&m->base, m->framebuffer);
+ }
+
+ return 0;
+}
+
+int init_frame_buffer_locked(struct private_module_t* module)
+{
+ if (module->framebuffer)
+ {
+ return 0; // Nothing to do, already initialized
+ }
+
+ char const * const device_template[] =
+ {
+ "/dev/graphics/fb%u",
+ "/dev/fb%u",
+ NULL
+ };
+
+ int fd = -1;
+ int i = 0;
+ char name[64];
+
+ while ((fd == -1) && device_template[i])
+ {
+ snprintf(name, 64, device_template[i], 0);
+ fd = open(name, O_RDWR, 0);
+ i++;
+ }
+
+ if (fd < 0)
+ {
+ return -errno;
+ }
+
+ struct fb_fix_screeninfo finfo;
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+ {
+ return -errno;
+ }
+
+ struct fb_var_screeninfo info;
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+ {
+ return -errno;
+ }
+
+ info.reserved[0] = 0;
+ info.reserved[1] = 0;
+ info.reserved[2] = 0;
+ info.xoffset = 0;
+ info.yoffset = 0;
+ info.activate = FB_ACTIVATE_NOW;
+
+#ifdef GRALLOC_16_BITS
+ /*
+ * Explicitly request 5/6/5
+ */
+ info.bits_per_pixel = 16;
+ info.red.offset = 11;
+ info.red.length = 5;
+ info.green.offset = 5;
+ info.green.length = 6;
+ info.blue.offset = 0;
+ info.blue.length = 5;
+ info.transp.offset = 0;
+ info.transp.length = 0;
+#else
+ /*
+ * Explicitly request 8/8/8
+ */
+ info.bits_per_pixel = 32;
+ info.red.offset = 16;
+ info.red.length = 8;
+ info.green.offset = 8;
+ info.green.length = 8;
+ info.blue.offset = 0;
+ info.blue.length = 8;
+ info.transp.offset = 0;
+ info.transp.length = 0;
+#endif
+
+ /*
+ * Request NUM_BUFFERS screens (at lest 2 for page flipping)
+ */
+ info.yres_virtual = info.yres * NUM_BUFFERS;
+
+ uint32_t flags = PAGE_FLIP;
+ if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1)
+ {
+ info.yres_virtual = info.yres;
+ flags &= ~PAGE_FLIP;
+ LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
+ }
+
+ if (info.yres_virtual < info.yres * 2)
+ {
+ // we need at least 2 for page-flipping
+ info.yres_virtual = info.yres;
+ flags &= ~PAGE_FLIP;
+ LOGW("page flipping not supported (yres_virtual=%d, requested=%d)", info.yres_virtual, info.yres*2);
+ }
+
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+ {
+ return -errno;
+ }
+
+ int refreshRate = 1000000000000000LLU /
+ (
+ uint64_t( info.upper_margin + info.lower_margin + info.yres )
+ * ( info.left_margin + info.right_margin + info.xres )
+ * info.pixclock
+ );
+
+ if (refreshRate == 0)
+ {
+ refreshRate = 60*1000; // 60 Hz
+ }
+
+ if (int(info.width) <= 0 || int(info.height) <= 0)
+ {
+ // the driver doesn't return that information
+ // default to 160 dpi
+ info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
+ info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
+ }
+
+ float xdpi = (info.xres * 25.4f) / info.width;
+ float ydpi = (info.yres * 25.4f) / info.height;
+ float fps = refreshRate / 1000.0f;
+
+ LOGI("using (fd=%d)\n"
+ "id = %s\n"
+ "xres = %d px\n"
+ "yres = %d px\n"
+ "xres_virtual = %d px\n"
+ "yres_virtual = %d px\n"
+ "bpp = %d\n"
+ "r = %2u:%u\n"
+ "g = %2u:%u\n"
+ "b = %2u:%u\n",
+ fd,
+ finfo.id,
+ info.xres,
+ info.yres,
+ info.xres_virtual,
+ info.yres_virtual,
+ info.bits_per_pixel,
+ info.red.offset, info.red.length,
+ info.green.offset, info.green.length,
+ info.blue.offset, info.blue.length);
+
+ LOGI("width = %d mm (%f dpi)\n"
+ "height = %d mm (%f dpi)\n"
+ "refresh rate = %.2f Hz\n",
+ info.width, xdpi,
+ info.height, ydpi,
+ fps);
+
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+ {
+ return -errno;
+ }
+
+ if (finfo.smem_len <= 0)
+ {
+ return -errno;
+ }
+
+ module->flags = flags;
+ module->info = info;
+ module->finfo = finfo;
+ module->xdpi = xdpi;
+ module->ydpi = ydpi;
+ module->fps = fps;
+
+ /*
+ * map the framebuffer
+ */
+ size_t fbSize = round_up_to_page_size(finfo.line_length * info.yres_virtual);
+ void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (vaddr == MAP_FAILED)
+ {
+ LOGE("Error mapping the framebuffer (%s)", strerror(errno));
+ return -errno;
+ }
+
+ memset(vaddr, 0, fbSize);
+
+ // Create a "fake" buffer object for the entire frame buffer memory, and store it in the module
+ module->framebuffer = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, fbSize, intptr_t(vaddr),
+ 0, dup(fd), 0);
+
+ module->numBuffers = info.yres_virtual / info.yres;
+ module->bufferMask = 0;
+
+ return 0;
+}
+
+static int init_frame_buffer(struct private_module_t* module)
+{
+ pthread_mutex_lock(&module->lock);
+ int err = init_frame_buffer_locked(module);
+ pthread_mutex_unlock(&module->lock);
+ return err;
+}
+
+static int fb_close(struct hw_device_t *device)
+{
+ framebuffer_device_t* dev = reinterpret_cast<framebuffer_device_t*>(device);
+ if (dev)
+ {
+ ump_close();
+ delete dev;
+ }
+ return 0;
+}
+
+int compositionComplete(struct framebuffer_device_t* dev)
+{
+ unsigned char pixels[4];
+ /* By doing a readpixel here we force the GL driver to start rendering
+ all the drawcalls up to this point, and to wait for the rendering to be complete.
+ Readpixel() also reads a dummy pixel, but this is not used. We only use this
+ function here to flush the render pipeline. */
+ glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ /* The rendering of the backbuffer is now completed.
+ When SurfaceFlinger later does a call to eglSwapBuffer(), the swap will be done
+ synchronously in the same thread, and not asynchronoulsy in a background thread later.
+ The SurfaceFlinger requires this behaviour since it releases the lock on all the
+ SourceBuffers (Layers) after the compositionComplete() function returns.
+ However this "bad" behaviour by SurfaceFlinger should not affect performance,
+ since the Applications that render the SourceBuffers (Layers) still get the
+ full renderpipeline using asynchronouls rendering. So they perform at maximum speed,
+ and because of their complexity compared to the Surface flinger jobs, the Surface flinger
+ is normally faster even if it does everyhing synchronous and serial.
+ */
+ return 0;
+}
+
+int framebuffer_device_open(hw_module_t const* module, const char* name, hw_device_t** device)
+{
+ int status = -EINVAL;
+
+ alloc_device_t* gralloc_device;
+ status = gralloc_open(module, &gralloc_device);
+ if (status < 0)
+ {
+ return status;
+ }
+
+ private_module_t* m = (private_module_t*)module;
+ status = init_frame_buffer(m);
+ if (status < 0)
+ {
+ gralloc_close(gralloc_device);
+ return status;
+ }
+
+ /* initialize our state here */
+ framebuffer_device_t *dev = new framebuffer_device_t;
+ memset(dev, 0, sizeof(*dev));
+
+ /* initialize the procs */
+ dev->common.tag = HARDWARE_DEVICE_TAG;
+ dev->common.version = 0;
+ dev->common.module = const_cast<hw_module_t*>(module);
+ dev->common.close = fb_close;
+ dev->setSwapInterval = fb_set_swap_interval;
+ dev->post = fb_post;
+ dev->setUpdateRect = 0;
+ dev->compositionComplete = &compositionComplete;
+
+ int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
+ const_cast<uint32_t&>(dev->flags) = 0;
+ const_cast<uint32_t&>(dev->width) = m->info.xres;
+ const_cast<uint32_t&>(dev->height) = m->info.yres;
+ const_cast<int&>(dev->stride) = stride;
+#ifdef GRALLOC_16_BITS
+ const_cast<int&>(dev->format) = HAL_PIXEL_FORMAT_RGB_565;
+#else
+ const_cast<int&>(dev->format) = HAL_PIXEL_FORMAT_BGRA_8888;
+#endif
+ const_cast<float&>(dev->xdpi) = m->xdpi;
+ const_cast<float&>(dev->ydpi) = m->ydpi;
+ const_cast<float&>(dev->fps) = m->fps;
+ const_cast<int&>(dev->minSwapInterval) = 1;
+ const_cast<int&>(dev->maxSwapInterval) = 1;
+ *device = &dev->common;
+ status = 0;
+
+ return status;
+}
diff --git a/framebuffer_device.h b/framebuffer_device.h
new file mode 100644
index 0000000..7e63d5f
--- /dev/null
+++ b/framebuffer_device.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2010 ARM Limited. All rights reserved.
+ *
+ * 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 <hardware/hardware.h>
+
+// Create a framebuffer device
+int framebuffer_device_open(hw_module_t const* module, const char* name, hw_device_t** device);
+
+// Initialize the framebuffer (must keep module lock before calling
+int init_frame_buffer_locked(struct private_module_t* module);
diff --git a/gralloc_helper.h b/gralloc_helper.h
new file mode 100644
index 0000000..277364b
--- /dev/null
+++ b/gralloc_helper.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 ARM Limited. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef GRALLOC_HELPER_H_
+#define GRALLOC_HELPER_H_
+
+#include <sys/mman.h>
+
+inline size_t round_up_to_page_size(size_t x)
+{
+ return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
+}
+
+#endif /* GRALLOC_HELPER_H_ */
diff --git a/gralloc_module.cpp b/gralloc_module.cpp
new file mode 100644
index 0000000..2f4bda2
--- /dev/null
+++ b/gralloc_module.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2010 ARM Limited. All rights reserved.
+ *
+ * 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 <errno.h>
+#include <pthread.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+#include <ump/ump_ref_drv.h>
+
+#include "gralloc_priv.h"
+#include "alloc_device.h"
+#include "framebuffer_device.h"
+
+static pthread_mutex_t s_map_lock = PTHREAD_MUTEX_INITIALIZER;
+static int s_ump_is_open = 0;
+
+static 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))
+ {
+ status = alloc_device_open(module, name, device);
+ }
+ else if (!strcmp(name, GRALLOC_HARDWARE_FB0))
+ {
+ status = framebuffer_device_open(module, name, device);
+ }
+
+ return status;
+}
+
+static int gralloc_register_buffer(gralloc_module_t const* module, buffer_handle_t handle)
+{
+ if (private_handle_t::validate(handle) < 0)
+ {
+ LOGE("Registering invalid buffer, returning error");
+ return -EINVAL;
+ }
+
+ // if this handle was created in this process, then we keep it as is.
+ private_handle_t* hnd = (private_handle_t*)handle;
+ if (hnd->pid == getpid())
+ {
+ return 0;
+ }
+
+ int retval = -EINVAL;
+
+ pthread_mutex_lock(&s_map_lock);
+
+ if (!s_ump_is_open)
+ {
+ ump_result res = ump_open();
+ if (res != UMP_OK)
+ {
+ pthread_mutex_unlock(&s_map_lock);
+ LOGE("Failed to open UMP library");
+ return retval;
+ }
+ s_ump_is_open = 1;
+ }
+
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_UMP)
+ {
+ hnd->ump_mem_handle = (int)ump_handle_create_from_secure_id(hnd->ump_id);
+ if (UMP_INVALID_MEMORY_HANDLE != (ump_handle)hnd->ump_mem_handle)
+ {
+ hnd->base = (int)ump_mapped_pointer_get((ump_handle)hnd->ump_mem_handle);
+ if (0 != hnd->base)
+ {
+ hnd->lockState = private_handle_t::LOCK_STATE_MAPPED;
+ hnd->writeOwner = 0;
+ hnd->lockState = 0;
+
+ pthread_mutex_unlock(&s_map_lock);
+ return 0;
+ }
+ else
+ {
+ LOGE("Failed to map UMP handle");
+ }
+
+ ump_reference_release((ump_handle)hnd->ump_mem_handle);
+ }
+ else
+ {
+ LOGE("Failed to create UMP handle");
+ }
+ }
+ else
+ {
+ LOGE("registering non-UMP buffer not supported");
+ }
+
+ pthread_mutex_unlock(&s_map_lock);
+ return retval;
+}
+
+static int gralloc_unregister_buffer(gralloc_module_t const* module, buffer_handle_t handle)
+{
+ if (private_handle_t::validate(handle) < 0)
+ {
+ LOGE("unregistering invalid buffer, returning error");
+ return -EINVAL;
+ }
+
+ private_handle_t* hnd = (private_handle_t*)handle;
+
+ LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK, "[unregister] handle %p still locked (state=%08x)", hnd, hnd->lockState);
+
+ // never unmap buffers that were created in this process
+ if (hnd->pid != getpid())
+ {
+ pthread_mutex_lock(&s_map_lock);
+
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_UMP)
+ {
+ ump_mapped_pointer_release((ump_handle)hnd->ump_mem_handle);
+ hnd->base = 0;
+ ump_reference_release((ump_handle)hnd->ump_mem_handle);
+ hnd->ump_mem_handle = (int)UMP_INVALID_MEMORY_HANDLE;
+ }
+ else
+ {
+ LOGE("unregistering non-UMP buffer not supported");
+ }
+
+ hnd->base = 0;
+ hnd->lockState = 0;
+ hnd->writeOwner = 0;
+
+ pthread_mutex_unlock(&s_map_lock);
+ }
+
+ return 0;
+}
+
+static int gralloc_lock(gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, void** vaddr)
+{
+ if (private_handle_t::validate(handle) < 0)
+ {
+ LOGE("Locking invalid buffer, returning error");
+ return -EINVAL;
+ }
+
+ private_handle_t* hnd = (private_handle_t*)handle;
+
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_UMP)
+ {
+ hnd->writeOwner = usage & GRALLOC_USAGE_SW_WRITE_MASK;
+ }
+
+ if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK))
+ {
+ *vaddr = (void*)hnd->base;
+ }
+ return 0;
+}
+
+static int gralloc_unlock(gralloc_module_t const* module, buffer_handle_t handle)
+{
+ if (private_handle_t::validate(handle) < 0)
+ {
+ LOGE("Unlocking invalid buffer, returning error");
+ return -EINVAL;
+ }
+
+ private_handle_t* hnd = (private_handle_t*)handle;
+ int32_t current_value;
+ int32_t new_value;
+ int retry;
+
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_UMP && hnd->writeOwner)
+ {
+ ump_cpu_msync_now((ump_handle)hnd->ump_mem_handle, UMP_MSYNC_CLEAN_AND_INVALIDATE, NULL, 0);
+ }
+ return 0;
+}
+
+// There is one global instance of the module
+
+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: "ARM Ltd.",
+ methods: &gralloc_module_methods,
+ dso: NULL,
+ reserved : {0,},
+ },
+ registerBuffer: gralloc_register_buffer,
+ unregisterBuffer: gralloc_unregister_buffer,
+ lock: gralloc_lock,
+ unlock: gralloc_unlock,
+ perform: NULL,
+ reserved_proc: {0,},
+ },
+ framebuffer: NULL,
+ flags: 0,
+ numBuffers: 0,
+ bufferMask: 0,
+ lock: PTHREAD_MUTEX_INITIALIZER,
+ currentBuffer: NULL,
+};
diff --git a/gralloc_priv.h b/gralloc_priv.h
new file mode 100644
index 0000000..2c4e492
--- /dev/null
+++ b/gralloc_priv.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2010 ARM Limited. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef GRALLOC_PRIV_H_
+#define GRALLOC_PRIV_H_
+
+#include <stdint.h>
+#include <pthread.h>
+#include <errno.h>
+#include <linux/fb.h>
+
+#include <hardware/gralloc.h>
+#include <cutils/native_handle.h>
+
+#include <ump/ump.h>
+
+#define GRALLOC_ARM_UMP_MODULE 1
+
+enum {
+ /* OEM specific HAL formats */
+ HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x100,
+};
+
+struct private_handle_t;
+
+struct private_module_t
+{
+ gralloc_module_t base;
+
+ private_handle_t* framebuffer;
+ uint32_t flags;
+ uint32_t numBuffers;
+ uint32_t bufferMask;
+ pthread_mutex_t lock;
+ buffer_handle_t currentBuffer;
+
+ struct fb_var_screeninfo info;
+ struct fb_fix_screeninfo finfo;
+ float xdpi;
+ float ydpi;
+ float fps;
+
+ enum
+ {
+ // flag to indicate we'll post this buffer
+ PRIV_USAGE_LOCKED_FOR_POST = 0x80000000
+ };
+};
+
+#ifdef __cplusplus
+struct private_handle_t : public native_handle
+{
+#else
+struct private_handle_t
+{
+ struct native_handle nativeHandle;
+#endif
+
+ enum
+ {
+ PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
+ PRIV_FLAGS_USES_UMP = 0x00000002,
+ };
+
+ enum
+ {
+ LOCK_STATE_WRITE = 1<<31,
+ LOCK_STATE_MAPPED = 1<<30,
+ LOCK_STATE_READ_MASK = 0x3FFFFFFF
+ };
+
+ // ints
+ int magic;
+ int flags;
+ int size;
+ int base;
+ int lockState;
+ int writeOwner;
+ int pid;
+
+ // Following members are for UMP memory only
+ int ump_id;
+ int ump_mem_handle;
+
+ // Following members is for framebuffer only
+ int fd;
+ int offset;
+
+
+#ifdef __cplusplus
+ static const int sNumInts = 11;
+ static const int sNumFds = 0;
+ static const int sMagic = 0x3141592;
+
+ private_handle_t(int flags, int size, int base, int lock_state, ump_secure_id secure_id, ump_handle handle):
+ magic(sMagic),
+ flags(flags),
+ size(size),
+ base(base),
+ lockState(lock_state),
+ writeOwner(0),
+ pid(getpid()),
+ ump_id((int)secure_id),
+ ump_mem_handle((int)handle),
+ fd(0),
+ offset(0)
+ {
+ version = sizeof(native_handle);
+ numFds = sNumFds;
+ numInts = sNumInts;
+ }
+
+ private_handle_t(int flags, int size, int base, int lock_state, int fb_file, int fb_offset):
+ magic(sMagic),
+ flags(flags),
+ size(size),
+ base(base),
+ lockState(lock_state),
+ writeOwner(0),
+ pid(getpid()),
+ ump_id((int)UMP_INVALID_SECURE_ID),
+ ump_mem_handle((int)UMP_INVALID_MEMORY_HANDLE),
+ fd(fb_file),
+ offset(fb_offset)
+ {
+ version = sizeof(native_handle);
+ numFds = sNumFds;
+ numInts = sNumInts;
+ }
+
+ ~private_handle_t()
+ {
+ magic = 0;
+ }
+
+ bool usesPhysicallyContiguousMemory()
+ {
+ return (flags & PRIV_FLAGS_FRAMEBUFFER) ? true : false;
+ }
+
+ static int validate(const native_handle* h)
+ {
+ const private_handle_t* hnd = (const private_handle_t*)h;
+ if (!h || h->version != sizeof(native_handle) || h->numInts != sNumInts || h->numFds != sNumFds || hnd->magic != sMagic)
+ {
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ static private_handle_t* dynamicCast(const native_handle* in)
+ {
+ if (validate(in) == 0)
+ {
+ return (private_handle_t*) in;
+ }
+ return NULL;
+ }
+#endif
+};
+
+#endif /* GRALLOC_PRIV_H_ */
diff --git a/gralloc_vsync_report.h b/gralloc_vsync_report.h
new file mode 100644
index 0000000..58c3035
--- /dev/null
+++ b/gralloc_vsync_report.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 ARM Limited. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef GRALLOC_VSYNC_REPORT_H_
+#define GRALLOC_VSYNC_REPORT_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+typedef enum mali_vsync_event
+{
+ MALI_VSYNC_EVENT_BEGIN_WAIT = 0,
+ MALI_VSYNC_EVENT_END_WAIT
+} mali_vsync_event;
+
+extern void _mali_base_arch_vsync_event_report(mali_vsync_event);
+
+inline void gralloc_mali_vsync_report(mali_vsync_event event)
+{
+ _mali_base_arch_vsync_event_report(event);
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GRALLOC_VSYNC_REPORT_H_ */