diff options
-rw-r--r-- | Android.mk | 5 | ||||
-rw-r--r-- | hardware.c | 8 | ||||
-rw-r--r-- | include/hardware/gralloc.h | 284 | ||||
-rw-r--r-- | include/hardware/hardware.h | 18 | ||||
-rw-r--r-- | modules/gralloc/Android.mk | 27 | ||||
-rw-r--r-- | modules/gralloc/framebuffer.cpp | 356 | ||||
-rw-r--r-- | modules/gralloc/gralloc.cpp | 320 | ||||
-rw-r--r-- | modules/gralloc/gralloc_priv.h | 209 | ||||
-rw-r--r-- | modules/gralloc/mapper.cpp | 231 | ||||
-rw-r--r-- | modules/overlay/overlay.cpp | 2 |
10 files changed, 1451 insertions, 9 deletions
@@ -33,3 +33,8 @@ endif LOCAL_MODULE:= libhardware include $(BUILD_SHARED_LIBRARY) + +include $(addsuffix /Android.mk, $(addprefix $(LOCAL_PATH)/, \ + modules/gralloc \ + )) +
\ No newline at end of file @@ -62,7 +62,7 @@ static int load(const char *id, { int status; void *handle; - const struct hw_module_t *hmi; + struct hw_module_t *hmi; char path[PATH_MAX]; /* Construct the path. */ @@ -78,14 +78,14 @@ static int load(const char *id, handle = dlopen(path, RTLD_NOW); if (handle == NULL) { char const *err_str = dlerror(); - LOGW("load: module=%s error=%s", path, err_str); + //LOGW("load: module=%s error=%s", path, err_str); status = -EINVAL; goto done; } /* Get the address of the struct hal_module_info. */ const char *sym = HAL_MODULE_INFO_SYM_AS_STR; - hmi = (const struct hw_module_t *)dlsym(handle, sym); + hmi = (struct hw_module_t *)dlsym(handle, sym); if (hmi == NULL) { char const *err_str = dlerror(); LOGE("load: couldn't find symbol %s", sym); @@ -99,6 +99,8 @@ static int load(const char *id, status = -EINVAL; goto done; } + + hmi->dso = handle; /* success */ status = 0; diff --git a/include/hardware/gralloc.h b/include/hardware/gralloc.h new file mode 100644 index 0000000..c473de0 --- /dev/null +++ b/include/hardware/gralloc.h @@ -0,0 +1,284 @@ +/* + * 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 ANDROID_GRALLOC_INTERFACE_H +#define ANDROID_GRALLOC_INTERFACE_H + +#include <cutils/native_handle.h> + +#include <hardware/hardware.h> + +#include <stdint.h> +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/** + * The id of this module + */ +#define GRALLOC_HARDWARE_MODULE_ID "gralloc" + +/** + * Name of the graphics device to open + */ + +#define GRALLOC_HARDWARE_FB0 "fb0" +#define GRALLOC_HARDWARE_GPU0 "gpu0" + +enum { + /* buffer is never read in software */ + GRALLOC_USAGE_SW_READ_NEVER = 0x00000001, + /* buffer is rarely read in software */ + GRALLOC_USAGE_SW_READ_RARELY = 0x00000002, + /* buffer is often read in software */ + GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003, + /* mask for the software read values */ + GRALLOC_USAGE_SW_READ_MASK = 0x0000000F, + + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_NEVER = 0x00000010, + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_RARELY = 0x00000020, + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_OFTEN = 0x00000030, + /* mask for the software write values */ + GRALLOC_USAGE_SW_WRITE_MASK = 0x000000F0, + + /* buffer will be used as an OpenGL ES texture */ + GRALLOC_USAGE_HW_TEXTURE = 0x00000100, + /* buffer will be used as an OpenGL ES render target */ + GRALLOC_USAGE_HW_RENDER = 0x00000200, + /* buffer will be used by the 2D hardware blitter */ + GRALLOC_USAGE_HW_2D = 0x00000C00, + /* buffer will be used with the framebuffer device */ + GRALLOC_USAGE_HW_FB = 0x00001000, + /* mask for the software usage bit-mask */ + GRALLOC_USAGE_HW_MASK = 0x00001F00, +}; + +enum { + /* the framebuffer is mapped in memory */ + FRAMEBUFFER_RESERVED0 = 0x00000001, + FRAMEBUFFER_FLAG_MAPPED = 0x00000002, +}; + +/*****************************************************************************/ + +typedef const native_handle* buffer_handle_t; + +/** + * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM + * and the fields of this data structure must begin with hw_module_t + * followed by module specific information. + */ +struct gralloc_module_t { + struct hw_module_t common; + + /* + * The (*map)() method maps the buffer in the caller's address space + * if this operation is allowed (see below). + * Mapped buffers are reference-counted in a given process, that is, + * if a the buffer is already mapped, this function must return the + * same address and the internal reference counter is incremented. + * + * Returns 0 on success or -errno on error. + */ + + int (*map)(struct gralloc_module_t const* module, + buffer_handle_t handle, void** vaddr); + + /* + * The (*unmap)() method, unmaps the buffer from the caller's address + * space, if the buffer has been mapped more than once, + * the (*unmap)() needs to be called the same number of time before + * the buffer is actually unmapped. + * + * Returns 0 on success or -errno on error. + */ + + int (*unmap)(struct gralloc_module_t const* module, buffer_handle_t handle); + + + /* + * The (*lock)() method is called before a buffer is accessed for the + * specified usage. This call may block, for instance if the h/w needs + * to finish rendering or if CPU caches need to be synchronized. + * + * The caller promises to modify ALL PIXELS and ONLY THE PIXELS in the area + * specified by (l,t,w,h). + * + * The content of the buffer outside of the specified area is NOT modified + * by this call. + * + */ + + int (*lock)(struct gralloc_module_t const* module, + buffer_handle_t handle, int usage, + int l, int t, int w, int h); + + + /* + * The (*unlock)() method must be called after all changes to the buffer + * are completed. + */ + + int (*unlock)(struct gralloc_module_t const* module, + buffer_handle_t handle); + +}; + +/*****************************************************************************/ + +/** + * Every device data structure must begin with hw_device_t + * followed by module specific public methods and attributes. + */ + +struct alloc_device_t { + struct hw_device_t common; + + /* + * (*alloc)() Allocates a buffer in graphic memory with the requested + * parameters and returns a buffer_handle_t and the stride in pixels to + * allow the implementation to satisfy hardware constraints on the width + * of a pixmap (eg: it may have to be multiple of 8 pixels). + * The CALLER TAKES OWNERSHIP of the buffer_handle_t. + * + * Returns 0 on success or -errno on error. + */ + + int (*alloc)(struct alloc_device_t* dev, + int w, int h, int format, int usage, + buffer_handle_t* handle, int* stride); + + /* + * (*free)() Frees a previously allocated buffer. + * Behavior is undefined if the buffer is still mapped in any process, + * but shall not result in termination of the program or security breaches + * (allowing a process to get access to another process' buffers). + * THIS FUNCTION TAKES OWNERSHIP of the buffer_handle_t which becomes + * invalid after the call. + * + * Returns 0 on success or -errno on error. + */ + int (*free)(struct alloc_device_t* dev, + buffer_handle_t handle); + +}; + + +struct framebuffer_device_t { + struct hw_device_t common; + + /* flags describing some attributes of the framebuffer */ + const uint32_t flags; + + /* dimensions of the framebuffer in pixels */ + const uint32_t width; + const uint32_t height; + + /* frambuffer stride in pixels */ + const int stride; + + /* framebuffer pixel format */ + const int format; + + /* resolution of the framebuffer's display panel in pixel per inch*/ + const float xdpi; + const float ydpi; + + /* framebuffer's display panel refresh rate in frames per second */ + const float fps; + + /* min swap interval supported by this framebuffer */ + const int minSwapInterval; + + /* max swap interval supported by this framebuffer */ + const int maxSwapInterval; + + int reserved[8]; + + /* + * requests a specific swap-interval (same definition than EGL) + * + * Returns 0 on success or -errno on error. + */ + int (*setSwapInterval)(struct framebuffer_device_t* window, + int interval); + + /* + * sets a rectangle evaluated during (*post)() specifying which area + * of the buffer passed in (*post)() needs to be posted. + * + * return -EINVAL if width or height <=0, or if left or top < 0 + */ + int (*setUpdateRect)(struct framebuffer_device_t* window, + int left, int top, int width, int height); + + /* + * Post <buffer> to the display (display it on the screen) + * The buffer must have been allocated with the + * GRALLOC_USAGE_HW_FB usage flag. + * buffer must be the same width and height as the display and must NOT + * be locked. + * + * The buffer is shown during the next VSYNC. + * + * If the same buffer is posted again (possibly after some other buffer), + * post() will block until the the first post is completed. + * + * Internally, post() is expected to lock the buffer so that a + * subsequent call to gralloc_module_t::(*lock)() with USAGE_RENDER or + * USAGE_*_WRITE will block until it is safe; that is typically once this + * buffer is shown and another buffer has been posted. + * + * Returns 0 on success or -errno on error. + */ + int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer); + + void* reserved_proc[8]; +}; + + +/** convenience API for opening and closing a supported device */ + +static inline int gralloc_open(const struct hw_module_t* module, + struct alloc_device_t** device) { + return module->methods->open(module, + GRALLOC_HARDWARE_GPU0, (struct hw_device_t**)device); +} + +static inline int gralloc_close(struct alloc_device_t* device) { + return device->common.close(&device->common); +} + + +static inline int framebuffer_open(const struct hw_module_t* module, + struct framebuffer_device_t** device) { + return module->methods->open(module, + GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device); +} + +static inline int framebuffer_close(struct framebuffer_device_t* device) { + return device->common.close(&device->common); +} + + +__END_DECLS + +#endif // ANDROID_ALLOC_INTERFACE_H diff --git a/include/hardware/hardware.h b/include/hardware/hardware.h index 5325744..c8dc6f6 100644 --- a/include/hardware/hardware.h +++ b/include/hardware/hardware.h @@ -20,13 +20,18 @@ #include <stdint.h> #include <sys/cdefs.h> +#include <cutils/native_handle.h> + __BEGIN_DECLS /* * Value for the hw_module_t.tag field */ -#define HARDWARE_MODULE_TAG 'HWMT' -#define HARDWARE_DEVICE_TAG 'HWDT' + +#define MAKE_TAG_CONSTANT(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D)) + +#define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T') +#define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T') struct hw_module_t; struct hw_module_methods_t; @@ -58,9 +63,12 @@ struct hw_module_t { /** Modules methods */ struct hw_module_methods_t* methods; - + + /** module's dso */ + void* dso; + /** padding to 128 bytes, reserved for future use */ - uint32_t reserved[32-6]; + uint32_t reserved[32-7]; }; struct hw_module_methods_t { @@ -91,7 +99,7 @@ struct hw_device_t { }; /** - * Name of the hal_module_info + * Name of the hal_module_info */ #define HAL_MODULE_INFO_SYM HMI diff --git a/modules/gralloc/Android.mk b/modules/gralloc/Android.mk new file mode 100644 index 0000000..1603f2d --- /dev/null +++ b/modules/gralloc/Android.mk @@ -0,0 +1,27 @@ +# 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. + + +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 +LOCAL_SRC_FILES := gralloc.cpp mapper.cpp framebuffer.cpp +LOCAL_MODULE := gralloc.default +LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc\" +include $(BUILD_SHARED_LIBRARY) diff --git a/modules/gralloc/framebuffer.cpp b/modules/gralloc/framebuffer.cpp new file mode 100644 index 0000000..05b9418 --- /dev/null +++ b/modules/gralloc/framebuffer.cpp @@ -0,0 +1,356 @@ +/* + * 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 <sys/mman.h> + +#include <dlfcn.h> + +#include <cutils/ashmem.h> +#include <cutils/log.h> + +#include <hardware/hardware.h> +#include <hardware/gralloc.h> + +#include <fcntl.h> +#include <errno.h> + +#include <cutils/log.h> +#include <cutils/atomic.h> + +#if HAVE_ANDROID_OS +#include <linux/fb.h> +#endif + +#include "gralloc_priv.h" + +/*****************************************************************************/ + +#define NUM_BUFFERS 2 + + +enum { + PAGE_FLIP = 0x00000001, + LOCKED = 0x00000002 +}; + +struct fb_context_t { + framebuffer_device_t device; +}; + +/*****************************************************************************/ + +static int fb_setSwapInterval(struct framebuffer_device_t* dev, + int interval) +{ + fb_context_t* ctx = (fb_context_t*)dev; + if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval) + return -EINVAL; + // FIXME: implement fb_setSwapInterval + return 0; +} + +static int fb_setUpdateRect(struct framebuffer_device_t* dev, + int l, int t, int w, int h) +{ + if (((w|h) <= 0) || ((l|t)<0)) + return -EINVAL; + + fb_context_t* ctx = (fb_context_t*)dev; + private_module_t* m = reinterpret_cast<private_module_t*>( + dev->common.module); + m->info.reserved[0] = 0x54445055; // "UPDT"; + m->info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16); + m->info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16); + return 0; +} + +static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) +{ + if (private_handle_t::validate(buffer) < 0) + return -EINVAL; + + fb_context_t* ctx = (fb_context_t*)dev; + + 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); + + const size_t offset = hnd->base - m->framebuffer->base; + m->info.activate = FB_ACTIVATE_VBL; + m->info.yoffset = offset / m->finfo.line_length; + if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) { + LOGE("FBIOPUT_VSCREENINFO failed"); + m->base.unlock(&m->base, buffer); + return -errno; + } + m->currentBuffer = buffer; + + } else { + // If we can't do the page_flip, just copy the buffer to the front + // FIXME: use copybit HAL instead of memcpy + + m->base.lock(&m->base, buffer, + private_module_t::PRIV_USAGE_LOCKED_FOR_POST, + 0, 0, m->info.xres, m->info.yres); + + memcpy((void*)m->framebuffer->base, (void*)hnd->base, + m->finfo.line_length * m->info.yres); + + m->base.unlock(&m->base, buffer); + } + + return 0; +} + +/*****************************************************************************/ + +int mapFrameBufferLocked(struct private_module_t* module) +{ + // already initialized... + if (module->framebuffer) { + return 0; + } + + char const * const device_template[] = { + "/dev/graphics/fb%u", + "/dev/fb%u", + 0 }; + + 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; + + /* + * 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; + + /* + * 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) { + // bleagh, bad info from the driver + 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 + */ + + int err; + size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual); + module->framebuffer = new private_handle_t(dup(fd), fbSize, + private_handle_t::PRIV_FLAGS_USES_PMEM); + + module->numBuffers = info.yres_virtual / info.yres; + module->bufferMask = 0; + + void* vaddr; + module->base.map(&module->base, module->framebuffer, &vaddr); + memset(vaddr, 0, fbSize); + + return 0; +} + +static int mapFrameBuffer(struct private_module_t* module) +{ + pthread_mutex_lock(&module->lock); + int err = mapFrameBufferLocked(module); + pthread_mutex_unlock(&module->lock); + return err; +} + +/*****************************************************************************/ + +static int fb_close(struct hw_device_t *dev) +{ + fb_context_t* ctx = (fb_context_t*)dev; + if (ctx) { + free(ctx); + } + return 0; +} + +int fb_device_open(hw_module_t const* module, const char* name, + hw_device_t** device) +{ + int status = -EINVAL; + if (!strcmp(name, GRALLOC_HARDWARE_FB0)) { + + alloc_device_t* gralloc_device; + status = gralloc_open(module, &gralloc_device); + if (status < 0) + return status; + + /* initialize our state here */ + fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev)); + 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 = fb_close; + dev->device.setSwapInterval = fb_setSwapInterval; + dev->device.setUpdateRect = fb_setUpdateRect; + dev->device.post = fb_post; + + private_module_t* m = (private_module_t*)module; + status = mapFrameBuffer(m); + if (status >= 0) { + int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3); + const_cast<uint32_t&>(dev->device.flags) = FRAMEBUFFER_FLAG_MAPPED; + const_cast<uint32_t&>(dev->device.width) = m->info.xres; + const_cast<uint32_t&>(dev->device.height) = m->info.yres; + const_cast<int&>(dev->device.stride) = stride; + const_cast<int&>(dev->device.format) = HAL_PIXEL_FORMAT_RGB_565; + const_cast<float&>(dev->device.xdpi) = m->xdpi; + const_cast<float&>(dev->device.ydpi) = m->ydpi; + const_cast<float&>(dev->device.fps) = m->fps; + const_cast<int&>(dev->device.minSwapInterval) = 1; + const_cast<int&>(dev->device.maxSwapInterval) = 1; + + *device = &dev->device.common; + } + } + return status; +} 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; +} diff --git a/modules/gralloc/gralloc_priv.h b/modules/gralloc/gralloc_priv.h new file mode 100644 index 0000000..a6fa69a --- /dev/null +++ b/modules/gralloc/gralloc_priv.h @@ -0,0 +1,209 @@ +/* + * 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 <asm/page.h> +#include <limits.h> +#include <sys/cdefs.h> +#include <hardware/gralloc.h> +#include <pthread.h> + +#include <cutils/native_handle.h> + +#if HAVE_ANDROID_OS +#include <linux/fb.h> +#endif + +/*****************************************************************************/ + +inline size_t roundUpToPageSize(size_t x) { + return (x + (PAGESIZE-1)) & ~(PAGESIZE-1); +} + +int mapFrameBufferLocked(struct private_module_t* module); + +/*****************************************************************************/ + +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 { + PRIV_USAGE_LOCKED_FOR_POST = 0x80000000 + }; +}; + +/*****************************************************************************/ + +struct private_handle_t : public native_handle +{ + enum { + PRIV_FLAGS_FRAMEBUFFER = 0x00000001, + PRIV_FLAGS_USES_PMEM = 0x00000002 + }; + + int fd; + int magic; + int base; + int flags; + int size; + + static const int sNumInts = 5; + static const int sNumFds = 1; + static const int sMagic = 0x3141592; + + private_handle_t(int fd, int size, int flags) : + fd(fd), magic(sMagic), base(0), flags(flags), size(size) { + version = sizeof(native_handle); + numInts = sNumInts; + numFds = sNumFds; + } + + ~private_handle_t() { + magic = 0; + } + + bool usesPhysicallyContiguousMemory() { + return (flags & PRIV_FLAGS_USES_PMEM) != 0; + } + + static int validate(const native_handle* h) { + if (!h || h->version != sizeof(native_handle) || + h->numInts!=sNumInts || h->numFds!=sNumFds) { + return -EINVAL; + } + const private_handle_t* hnd = (const private_handle_t*)h; + if (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; + } +}; + +/*****************************************************************************/ + +template<typename T> +struct growable_sorted_array_t { + int size; + int count; + T* data; + + growable_sorted_array_t() : size(0), count(0), data(0) { + } + + growable_sorted_array_t(int initialSize) + : size(initialSize), count(0), data(0) + { + data = new T[initialSize]; + } + + ~growable_sorted_array_t() { + delete[] data; + } + + /** Returns true if we found an exact match. + * Argument index is set to the the first index >= key in place. + * Index will be in range 0..count inclusive. + * + */ + bool find(const T& key, int& index) { + return binarySearch(0, count-1, key, index); + } + + T* at(int index){ + if (index >= 0 && index < count) { + return data + index; + } + return 0; + } + + void insert(int index, const T& item) { + if (index >= 0 && index <= count) { + if (count + 1 > size) { + int newSize = size * 2; + if (newSize < count + 1) { + newSize = count + 1; + } + T* newData = new T[newSize]; + if (size > 0) { + memcpy(newData, data, sizeof(T) * count); + } + data = newData; + size = newSize; + } + int toMove = count - index; + if (toMove > 0) { + memmove(data + index + 1, data + index, sizeof(T) * toMove); + } + count++; + data[index] = item; + } + } + + void remove(int index) { + if (index >= 0 && index < count) { + int toMove = (count - 1) - index; + if (toMove > 0) { + memmove(data + index, data + index + 1, sizeof(T) * toMove); + } + count--; + } + } + + /** Return the first index >= key. May be in range first..last+1. */ + int binarySearch(int first, int last, const T& key, int& index) + { + while (first <= last) { + int mid = (first + last) / 2; + int cmp = compare(key, data[mid]); + if (cmp > 0) { + first = mid + 1; + } else if (cmp < 0) { + last = mid - 1; + } else { + index = mid; + return true; + } + } + index = first; + return false; + } +}; + + +#endif /* GRALLOC_PRIV_H_ */ diff --git a/modules/gralloc/mapper.cpp b/modules/gralloc/mapper.cpp new file mode 100644 index 0000000..a5f52ed --- /dev/null +++ b/modules/gralloc/mapper.cpp @@ -0,0 +1,231 @@ +/* + * 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 <errno.h> +#include <pthread.h> + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <cutils/log.h> +#include <cutils/atomic.h> + +#include <hardware/hardware.h> +#include <hardware/gralloc.h> + +#include "gralloc_priv.h" + +/*****************************************************************************/ + +struct mapped_buffer_t { + intptr_t key; + int size; + int base; + int refCount; + + int init(private_handle_t* hnd) { + size = hnd->size; + base = 0; + refCount = 0; + struct stat buf; + int result = 0; + key = intptr_t(hnd); + return result; + } +}; + +static int compare(const mapped_buffer_t& a, const mapped_buffer_t& b) { + if (a.key < b.key) { + return -1; + } + if (a.key > b.key) { + return 1; + } + return 0; +} + +struct mapped_buffers_t { + pthread_mutex_t mutex; + growable_sorted_array_t<mapped_buffer_t> records; + + int map(gralloc_module_t const* module, + buffer_handle_t handle, + void** vaddr) + { + private_handle_t* hnd = (private_handle_t*)(handle); + mapped_buffer_t key; + int result = key.init(hnd); + //printRecord(ANDROID_LOG_DEBUG, "map", &key); + if (result) { + return result; + } + mapped_buffer_t* record = 0; + pthread_mutex_lock(&mutex); + // From here to the end of the function we return by jumping to "exit" + // so that we always unlock the mutex. + + int index = -1; + if (!records.find(key, index)) { + //LOGD("New item at %d", index); + void* mappedAddress = mmap(0, hnd->size, + PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0); + if (mappedAddress == MAP_FAILED) { + result = -errno; + //LOGE("map failed %d", result); + goto exit; + } + key.base = intptr_t(mappedAddress); + records.insert(index, key); + record = records.at(index); + } else { + //LOGD("Found existing mapping at index %d", index); + record = records.at(index); + if (record->size != key.size) { + LOGE("Requested a new mapping at the same offset" + "but with a different size"); + printRecord(ANDROID_LOG_ERROR, "old", record); + printRecord(ANDROID_LOG_ERROR, "new", &key); + result = -EINVAL; + goto exit; + } + } + record->refCount += 1; + hnd->base = record->base; + *vaddr = (void*) record->base; + exit: + //print(); + pthread_mutex_unlock(&mutex); + return result; + } + + int unmap(gralloc_module_t const* module, + buffer_handle_t handle) + { + mapped_buffer_t key; + key.init((private_handle_t*) handle); + //printRecord(ANDROID_LOG_DEBUG, "unmap", &key); + int index = -1; + + int result = 0; + mapped_buffer_t* record = 0; + pthread_mutex_lock(&mutex); + // From here to the end of the function we return by jumping to "exit" + // so that we always unlock the mutex. + + if (!records.find(key, index)) { + // This handle is not currently locked. + //LOGE("Could not find existing mapping near %d", index); + result = -ENOENT; + goto exit; + } + record = records.at(index); + //printRecord(ANDROID_LOG_DEBUG, "record", record); + record->refCount -= 1; + if (record->refCount == 0) { + //LOGD("Unmapping..."); + if (munmap((void*)record->base, record->size) < 0) { + result = -errno; + //LOGE("Could not unmap %d", result); + } + records.remove(index); + ((private_handle_t*)handle)->base = 0; + } + + exit: + //print(); + pthread_mutex_unlock(&mutex); + return result; + } + + void print() { + char prefix[16]; + LOGD("Dumping records: count=%d size=%d", records.count, records.size); + for(int i=0; i<records.count ; i++) { + sprintf(prefix, "%3d", i); + printRecord(ANDROID_LOG_DEBUG, prefix, records.at(i)); + } + } + + void printRecord(int level, const char* what, mapped_buffer_t* record) { + LOG_PRI(level, LOG_TAG, + "%s: key=0x%08x, size=0x%08x, base=0x%08x refCount=%d", + what, int(record->key), record->size, + record->base, record->refCount); + } +}; + +static mapped_buffers_t sMappedBuffers = { + mutex: PTHREAD_MUTEX_INITIALIZER +}; + +/*****************************************************************************/ + +int gralloc_map(gralloc_module_t const* module, + buffer_handle_t handle, + void** vaddr) +{ + if (private_handle_t::validate(handle) < 0) + return -EINVAL; + + private_handle_t* hnd = (private_handle_t*)(handle); + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + const private_module_t* m = + reinterpret_cast<const private_module_t*>(module); + handle = m->framebuffer; + } + + int err = sMappedBuffers.map(module, handle, vaddr); + + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + *vaddr = (void*)hnd->base; + } + + return err; +} + +int gralloc_unmap(gralloc_module_t const* module, + buffer_handle_t handle) +{ + if (private_handle_t::validate(handle) < 0) + return -EINVAL; + + private_handle_t* hnd = (private_handle_t*)(handle); + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + const private_module_t* m = + reinterpret_cast<const private_module_t*>(module); + handle = m->framebuffer; + } + + return sMappedBuffers.unmap(module, handle); +} + + +int gralloc_lock(gralloc_module_t const* module, + buffer_handle_t handle, int usage, + int l, int t, int w, int h) +{ + // FIXME: gralloc_lock() needs implementation + return 0; +} + +int gralloc_unlock(gralloc_module_t const* module, + buffer_handle_t handle) +{ + // FIXME: gralloc_unlock() needs implementation + return 0; +} diff --git a/modules/overlay/overlay.cpp b/modules/overlay/overlay.cpp index 0246b5b..a91df58 100644 --- a/modules/overlay/overlay.cpp +++ b/modules/overlay/overlay.cpp @@ -44,7 +44,7 @@ static struct hw_module_methods_t overlay_module_methods = { open: overlay_device_open }; -const struct overlay_module_t HAL_MODULE_INFO_SYM = { +struct overlay_module_t HAL_MODULE_INFO_SYM = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1, |