diff options
-rw-r--r-- | Android.mk | 42 | ||||
-rw-r--r-- | alloc_device.cpp | 312 | ||||
-rw-r--r-- | alloc_device.h | 22 | ||||
-rw-r--r-- | framebuffer_device.cpp | 452 | ||||
-rw-r--r-- | framebuffer_device.h | 25 | ||||
-rw-r--r-- | gralloc_helper.h | 29 | ||||
-rw-r--r-- | gralloc_module.cpp | 235 | ||||
-rw-r--r-- | gralloc_priv.h | 177 | ||||
-rw-r--r-- | gralloc_vsync_report.h | 42 |
9 files changed, 1336 insertions, 0 deletions
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_ */ |