From 1202e079cf5dafbe539a22002bd5b61ab19baf5b Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Thu, 12 Nov 2009 18:46:07 -0800 Subject: [PATCH 1/2] eclair snapshot --- Android.mk | 5 + hardware.c | 66 +++-- include/hardware/copybit.h | 10 +- include/hardware/gralloc.h | 344 ++++++++++++++++++++++ include/hardware/hardware.h | 41 ++- include/hardware/lights.h | 21 ++ include/hardware/overlay.h | 28 +- include/hardware/sensors.h | 32 ++- modules/gralloc/Android.mk | 33 +++ modules/gralloc/allocator.cpp | 170 +++++++++++ modules/gralloc/allocator.h | 129 +++++++++ modules/gralloc/framebuffer.cpp | 371 ++++++++++++++++++++++++ modules/gralloc/gr.h | 63 ++++ modules/gralloc/gralloc.cpp | 489 ++++++++++++++++++++++++++++++++ modules/gralloc/gralloc_priv.h | 137 +++++++++ modules/gralloc/mapper.cpp | 282 ++++++++++++++++++ modules/overlay/overlay.cpp | 2 +- 17 files changed, 2168 insertions(+), 55 deletions(-) create mode 100644 include/hardware/gralloc.h mode change 100644 => 100755 include/hardware/lights.h create mode 100644 modules/gralloc/Android.mk create mode 100644 modules/gralloc/allocator.cpp create mode 100644 modules/gralloc/allocator.h create mode 100644 modules/gralloc/framebuffer.cpp create mode 100644 modules/gralloc/gr.h create mode 100644 modules/gralloc/gralloc.cpp create mode 100644 modules/gralloc/gralloc_priv.h create mode 100644 modules/gralloc/mapper.cpp diff --git a/Android.mk b/Android.mk index b2e9caf9..a35de91f 100644 --- a/Android.mk +++ b/Android.mk @@ -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 diff --git a/hardware.c b/hardware.c index cc68602d..3a23b1f6 100644 --- a/hardware.c +++ b/hardware.c @@ -41,7 +41,6 @@ * led.default.so */ -#define HAL_DEFAULT_VARIANT "default" static const char *variant_keys[] = { "ro.hardware", /* This goes first so that it can pick up a different file on the emulator. */ @@ -49,26 +48,22 @@ static const char *variant_keys[] = { "ro.board.platform", "ro.arch" }; -#define HAL_VARIANT_KEYS_COUNT (sizeof(variant_keys)/sizeof(variant_keys[0])) + +static const int HAL_VARIANT_KEYS_COUNT = + (sizeof(variant_keys)/sizeof(variant_keys[0])); /** - * Load the file defined by the variant and if succesfull + * Load the file defined by the variant and if successful * return the dlopen handle and the hmi. * @return 0 = success, !0 = failure. */ static int load(const char *id, - const char *variant, - const struct hw_module_t **pHmi) + const char *path, + const struct hw_module_t **pHmi) { int status; void *handle; - const struct hw_module_t *hmi; - char path[PATH_MAX]; - - /* Construct the path. */ - snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH, id, variant); - - LOGV("load: E id=%s path=%s", id, path); + struct hw_module_t *hmi; /* * load the symbols resolving undefined symbols before @@ -78,16 +73,15 @@ 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); + LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown"); 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); status = -EINVAL; goto done; @@ -100,22 +94,25 @@ static int load(const char *id, goto done; } + hmi->dso = handle; + /* success */ status = 0; -done: + done: if (status != 0) { hmi = NULL; if (handle != NULL) { dlclose(handle); handle = NULL; } + } else { + LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", + id, path, *pHmi, handle); } *pHmi = hmi; - LOGV("load: X id=%s path=%s hmi=%p handle=%p status=%d", - id, path, *pHmi, handle, status); return status; } @@ -125,6 +122,7 @@ int hw_get_module(const char *id, const struct hw_module_t **module) int i; const struct hw_module_t *hmi = NULL; char prop[PATH_MAX]; + char path[PATH_MAX]; /* * Here we rely on the fact that calling dlopen multiple times on @@ -132,26 +130,32 @@ int hw_get_module(const char *id, const struct hw_module_t **module) * a new copy of the library). * We also assume that dlopen() is thread-safe. */ - - LOGV("hal_module_info_get: Load module id=%s", id); - - status = -EINVAL; /* Loop through the configuration variants looking for a module */ - for (i = 0; (status != 0) && (i < HAL_VARIANT_KEYS_COUNT); i++) { - if (property_get(variant_keys[i], prop, NULL) == 0) { + for (i=0 ; i + +#include + +#include +#include +#include + +__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 = 0x00000000, + /* 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 = 0x00000000, + /* 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, +}; + +/*****************************************************************************/ + +typedef const native_handle* buffer_handle_t; + +enum { + /* FIXME: this only exists to work-around some issues with + * the video and camera frameworks. don't implement unless + * you know what you're doing. + */ + GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER = 0x080000001, +}; + +/** + * 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. + */ +typedef struct gralloc_module_t { + struct hw_module_t common; + + /* + * (*registerBuffer)() must be called before a buffer_handle_t that has not + * been created with (*alloc_device_t::alloc)() can be used. + * + * This is intended to be used with buffer_handle_t's that have been + * received in this process through IPC. + * + * This function checks that the handle is indeed a valid one and prepares + * it for use with (*lock)() and (*unlock)(). + * + * It is not necessary to call (*registerBuffer)() on a handle created + * with (*alloc_device_t::alloc)(). + * + * returns an error if this buffer_handle_t is not valid. + */ + int (*registerBuffer)(struct gralloc_module_t const* module, + buffer_handle_t handle); + + /* + * (*unregisterBuffer)() is called once this handle is no longer needed in + * this process. After this call, it is an error to call (*lock)(), + * (*unlock)(), or (*registerBuffer)(). + * + * This function doesn't close or free the handle itself; this is done + * by other means, usually through libcutils's native_handle_close() and + * native_handle_free(). + * + * It is an error to call (*unregisterBuffer)() on a buffer that wasn't + * explicitly registered first. + */ + int (*unregisterBuffer)(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 only 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. + * + * If usage specifies GRALLOC_USAGE_SW_*, vaddr is filled with the address + * of the buffer in virtual memory. + * + * THREADING CONSIDERATIONS: + * + * It is legal for several different threads to lock a buffer from + * read access, none of the threads are blocked. + * + * However, locking a buffer simultaneously for write or read/write is + * undefined, but: + * - shall not result in termination of the process + * - shall not block the caller + * It is acceptable to return an error or to leave the buffer's content + * into an indeterminate state. + * + * If the buffer was created with a usage mask incompatible with the + * requested usage flags here, -EINVAL is returned. + * + */ + + int (*lock)(struct gralloc_module_t const* module, + buffer_handle_t handle, int usage, + int l, int t, int w, int h, + void** vaddr); + + + /* + * 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); + + + /* reserved for future use */ + int (*perform)(struct gralloc_module_t const* module, + int operation, ... ); + + /* reserved for future use */ + void* reserved_proc[7]; +} gralloc_module_t; + +/*****************************************************************************/ + +/** + * Every device data structure must begin with hw_device_t + * followed by module specific public methods and attributes. + */ + +typedef 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); + +} alloc_device_t; + + +typedef 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); + + /* + * This hook is OPTIONAL. + * + * It is non NULL If the framebuffer driver supports "update-on-demand" + * and the given rectangle is the area of the screen that gets + * updated during (*post)(). + * + * This is useful on devices that are able to DMA only a portion of + * the screen to the display panel, upon demand -- as opposed to + * constantly refreshing the panel 60 times per second, for instance. + * + * Only the area defined by this rectangle is guaranteed to be valid, that + * is, the driver is not allowed to post anything outside of this + * rectangle. + * + * The rectangle evaluated during (*post)() and specifies which area + * of the buffer passed in (*post)() shall 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 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); + + + /* + * The (*compositionComplete)() method must be called after the + * compositor has finished issuing GL commands for client buffers. + */ + + int (*compositionComplete)(struct framebuffer_device_t* dev); + + + void* reserved_proc[8]; + +} framebuffer_device_t; + + +/** 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 53257442..ee5123d4 100644 --- a/include/hardware/hardware.h +++ b/include/hardware/hardware.h @@ -20,13 +20,18 @@ #include #include +#include + __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; @@ -37,7 +42,7 @@ struct hw_device_t; * and the fields of this data structure must begin with hw_module_t * followed by module specific information. */ -struct hw_module_t { +typedef struct hw_module_t { /** tag must be initialized to HARDWARE_MODULE_TAG */ uint32_t tag; @@ -58,22 +63,27 @@ struct hw_module_t { /** Modules methods */ struct hw_module_methods_t* methods; - - /** padding to 128 bytes, reserved for future use */ - uint32_t reserved[32-6]; -}; -struct hw_module_methods_t { + /** module's dso */ + void* dso; + + /** padding to 128 bytes, reserved for future use */ + uint32_t reserved[32-7]; + +} hw_module_t; + +typedef struct hw_module_methods_t { /** Open a specific device */ int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device); -}; + +} hw_module_methods_t; /** * Every device data structure must begin with hw_device_t * followed by module specific public methods and attributes. */ -struct hw_device_t { +typedef struct hw_device_t { /** tag must be initialized to HARDWARE_DEVICE_TAG */ uint32_t tag; @@ -88,10 +98,11 @@ struct hw_device_t { /** Close this device */ int (*close)(struct hw_device_t* device); -}; + +} hw_device_t; /** - * Name of the hal_module_info + * Name of the hal_module_info */ #define HAL_MODULE_INFO_SYM HMI @@ -113,6 +124,8 @@ int hw_get_module(const char *id, const struct hw_module_t **module); enum { HAL_PIXEL_FORMAT_RGBA_8888 = 1, + HAL_PIXEL_FORMAT_RGBX_8888 = 2, + HAL_PIXEL_FORMAT_RGB_888 = 3, HAL_PIXEL_FORMAT_RGB_565 = 4, HAL_PIXEL_FORMAT_BGRA_8888 = 5, HAL_PIXEL_FORMAT_RGBA_5551 = 6, @@ -122,7 +135,9 @@ enum { HAL_PIXEL_FORMAT_YCbCr_422_P = 0x12, HAL_PIXEL_FORMAT_YCbCr_420_P = 0x13, HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, - HAL_PIXEL_FORMAT_YCbCr_420_I = 0x15 + HAL_PIXEL_FORMAT_YCbCr_420_I = 0x15, + HAL_PIXEL_FORMAT_CbYCrY_422_I = 0x16, + HAL_PIXEL_FORMAT_CbYCrY_420_I = 0x17 }; diff --git a/include/hardware/lights.h b/include/hardware/lights.h old mode 100644 new mode 100755 index bb89c897..2cf55193 --- a/include/hardware/lights.h +++ b/include/hardware/lights.h @@ -65,6 +65,21 @@ __BEGIN_DECLS */ #define LIGHT_FLASH_TIMED 1 +/** + * To flash the light using hardware assist, set flashMode to + * the hardware mode. + */ +#define LIGHT_FLASH_HARDWARE 2 + +/** + * Light brightness is managed by a user setting. + */ +#define BRIGHTNESS_MODE_USER 0 + +/** + * Light brightness is managed by a light sensor. + */ +#define BRIGHTNESS_MODE_SENSOR 1 /** * The parameters that can be set for a given light. @@ -95,6 +110,12 @@ struct light_state_t { int flashMode; int flashOnMS; int flashOffMS; + + /** + * Policy used by the framework to manage the light's brightness. + * Currently the values are BRIGHTNESS_MODE_USER and BRIGHTNESS_MODE_SENSOR. + */ + int brightnessMode; }; struct light_device_t { diff --git a/include/hardware/overlay.h b/include/hardware/overlay.h index 92992d18..eca4d276 100644 --- a/include/hardware/overlay.h +++ b/include/hardware/overlay.h @@ -45,8 +45,14 @@ enum { OVERLAY_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, OVERLAY_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, OVERLAY_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, - OVERLAY_FORMAT_YCbCr_422_I = HAL_PIXEL_FORMAT_YCbCr_422_I, - OVERLAY_FORMAT_YCbCr_420_I = HAL_PIXEL_FORMAT_YCbCr_420_I + OVERLAY_FORMAT_YCbCr_422_SP = HAL_PIXEL_FORMAT_YCbCr_422_SP, + OVERLAY_FORMAT_YCbCr_420_SP = HAL_PIXEL_FORMAT_YCbCr_420_SP, + OVERLAY_FORMAT_YCbYCr_422_I = HAL_PIXEL_FORMAT_YCbCr_422_I, + OVERLAY_FORMAT_YCbYCr_420_I = HAL_PIXEL_FORMAT_YCbCr_420_I, + OVERLAY_FORMAT_CbYCrY_422_I = HAL_PIXEL_FORMAT_CbYCrY_422_I, + OVERLAY_FORMAT_CbYCrY_420_I = HAL_PIXEL_FORMAT_CbYCrY_420_I, + OVERLAY_FORMAT_DEFAULT = 99 // The actual color format is determined + // by the overlay }; /* values for copybit_set_parameter(OVERLAY_TRANSFORM) */ @@ -169,6 +175,9 @@ struct overlay_control_device_t { * supported. */ int (*setParameter)(struct overlay_control_device_t *dev, overlay_t* overlay, int param, int value); + + int (*stage)(struct overlay_control_device_t *dev, overlay_t* overlay); + int (*commit)(struct overlay_control_device_t *dev, overlay_t* overlay); }; @@ -179,7 +188,20 @@ struct overlay_data_device_t { * overlay data module to its control module */ int (*initialize)(struct overlay_data_device_t *dev, overlay_handle_t handle); - + + /* can be called to change the width and height of the overlay. */ + int (*resizeInput)(struct overlay_data_device_t *dev, + uint32_t w, uint32_t h); + + int (*setCrop)(struct overlay_data_device_t *dev, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) ; + + int (*getCrop)(struct overlay_data_device_t *dev, + uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) ; + + int (*setParameter)(struct overlay_data_device_t *dev, + int param, int value); + /* blocks until an overlay buffer is available and return that buffer. */ int (*dequeueBuffer)(struct overlay_data_device_t *dev, overlay_buffer_t *buf); diff --git a/include/hardware/sensors.h b/include/hardware/sensors.h index a6bee561..74d50dd1 100644 --- a/include/hardware/sensors.h +++ b/include/hardware/sensors.h @@ -173,7 +173,20 @@ __BEGIN_DECLS * * All values are in micro-Tesla (uT) and measure the ambient magnetic * field in the X, Y and Z axis. - * + * + * Proximity + * --------- + * + * The distance value is measured in centimeters. Note that some proximity + * sensors only support a binary "close" or "far" measurement. In this case, + * the sensor should report its maxRange value in the "far" state and a value + * less than maxRange in the "near" state. + * + * Light + * ----- + * + * The light sensor value is returned in SI lux units. + * */ typedef struct { union { @@ -216,6 +229,12 @@ typedef struct { /* temperature is in degrees centigrade (Celsius) */ float temperature; + + /* distance in centimeters */ + float distance; + + /* light in SI lux units */ + float light; }; /* time is in nanosecond */ @@ -287,7 +306,16 @@ struct sensors_control_device_t { * @return a native_handle_t if successful, NULL on error */ native_handle_t* (*open_data_source)(struct sensors_control_device_t *dev); - + + /** + * Releases any resources that were created by open_data_source. + * This call is optional and can be NULL if not implemented + * by the sensor HAL. + * + * @return 0 if successful, < 0 on error + */ + int (*close_data_source)(struct sensors_control_device_t *dev); + /** Activate/deactivate one sensor. * * @param handle is the handle of the sensor to change. diff --git a/modules/gralloc/Android.mk b/modules/gralloc/Android.mk new file mode 100644 index 00000000..8f044c54 --- /dev/null +++ b/modules/gralloc/Android.mk @@ -0,0 +1,33 @@ +# 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/..so +include $(CLEAR_VARS) +LOCAL_PRELINK_MODULE := false +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_SHARED_LIBRARIES := liblog libcutils + +LOCAL_SRC_FILES := \ + allocator.cpp \ + gralloc.cpp \ + framebuffer.cpp \ + mapper.cpp + +LOCAL_MODULE := gralloc.default +LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc\" +include $(BUILD_SHARED_LIBRARY) diff --git a/modules/gralloc/allocator.cpp b/modules/gralloc/allocator.cpp new file mode 100644 index 00000000..4dad6a17 --- /dev/null +++ b/modules/gralloc/allocator.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2009 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 + +#include "allocator.h" + + +// align all the memory blocks on a cache-line boundary +const int SimpleBestFitAllocator::kMemoryAlign = 32; + +SimpleBestFitAllocator::SimpleBestFitAllocator() + : mHeapSize(0) +{ +} + +SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size) + : mHeapSize(0) +{ + setSize(size); +} + +SimpleBestFitAllocator::~SimpleBestFitAllocator() +{ + while(!mList.isEmpty()) { + delete mList.remove(mList.head()); + } +} + +ssize_t SimpleBestFitAllocator::setSize(size_t size) +{ + Locker::Autolock _l(mLock); + if (mHeapSize != 0) return -EINVAL; + size_t pagesize = getpagesize(); + mHeapSize = ((size + pagesize-1) & ~(pagesize-1)); + chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign); + mList.insertHead(node); + return size; +} + + +size_t SimpleBestFitAllocator::size() const +{ + return mHeapSize; +} + +ssize_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags) +{ + Locker::Autolock _l(mLock); + if (mHeapSize == 0) return -EINVAL; + ssize_t offset = alloc(size, flags); + return offset; +} + +ssize_t SimpleBestFitAllocator::deallocate(size_t offset) +{ + Locker::Autolock _l(mLock); + if (mHeapSize == 0) return -EINVAL; + chunk_t const * const freed = dealloc(offset); + if (freed) { + return 0; + } + return -ENOENT; +} + +ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags) +{ + if (size == 0) { + return 0; + } + size = (size + kMemoryAlign-1) / kMemoryAlign; + chunk_t* free_chunk = 0; + chunk_t* cur = mList.head(); + + size_t pagesize = getpagesize(); + while (cur) { + int extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ; + + // best fit + if (cur->free && (cur->size >= (size+extra))) { + if ((!free_chunk) || (cur->size < free_chunk->size)) { + free_chunk = cur; + } + if (cur->size == size) { + break; + } + } + cur = cur->next; + } + + if (free_chunk) { + const size_t free_size = free_chunk->size; + free_chunk->free = 0; + free_chunk->size = size; + if (free_size > size) { + int extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ; + if (extra) { + chunk_t* split = new chunk_t(free_chunk->start, extra); + free_chunk->start += extra; + mList.insertBefore(free_chunk, split); + } + + LOGE_IF(((free_chunk->start*kMemoryAlign)&(pagesize-1)), + "page is not aligned!!!"); + + const ssize_t tail_free = free_size - (size+extra); + if (tail_free > 0) { + chunk_t* split = new chunk_t( + free_chunk->start + free_chunk->size, tail_free); + mList.insertAfter(free_chunk, split); + } + } + return (free_chunk->start)*kMemoryAlign; + } + return -ENOMEM; +} + +SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) +{ + start = start / kMemoryAlign; + chunk_t* cur = mList.head(); + while (cur) { + if (cur->start == start) { + LOG_FATAL_IF(cur->free, + "block at offset 0x%08lX of size 0x%08lX already freed", + cur->start*kMemoryAlign, cur->size*kMemoryAlign); + + // merge freed blocks together + chunk_t* freed = cur; + cur->free = 1; + do { + chunk_t* const p = cur->prev; + chunk_t* const n = cur->next; + if (p && (p->free || !cur->size)) { + freed = p; + p->size += cur->size; + mList.remove(cur); + delete cur; + } + cur = n; + } while (cur && cur->free); + + #ifndef NDEBUG + if (!freed->free) { + dump_l("dealloc (!freed->free)"); + } + #endif + LOG_FATAL_IF(!freed->free, + "freed block at offset 0x%08lX of size 0x%08lX is not free!", + freed->start * kMemoryAlign, freed->size * kMemoryAlign); + + return freed; + } + cur = cur->next; + } + return 0; +} diff --git a/modules/gralloc/allocator.h b/modules/gralloc/allocator.h new file mode 100644 index 00000000..b0d89e9e --- /dev/null +++ b/modules/gralloc/allocator.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2009 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_ALLOCATOR_H_ +#define GRALLOC_ALLOCATOR_H_ + +#include +#include + +#include "gr.h" + +// ---------------------------------------------------------------------------- + +/* + * A simple templatized doubly linked-list implementation + */ + +template +class LinkedList +{ + NODE* mFirst; + NODE* mLast; + +public: + LinkedList() : mFirst(0), mLast(0) { } + bool isEmpty() const { return mFirst == 0; } + NODE const* head() const { return mFirst; } + NODE* head() { return mFirst; } + NODE const* tail() const { return mLast; } + NODE* tail() { return mLast; } + + void insertAfter(NODE* node, NODE* newNode) { + newNode->prev = node; + newNode->next = node->next; + if (node->next == 0) mLast = newNode; + else node->next->prev = newNode; + node->next = newNode; + } + + void insertBefore(NODE* node, NODE* newNode) { + newNode->prev = node->prev; + newNode->next = node; + if (node->prev == 0) mFirst = newNode; + else node->prev->next = newNode; + node->prev = newNode; + } + + void insertHead(NODE* newNode) { + if (mFirst == 0) { + mFirst = mLast = newNode; + newNode->prev = newNode->next = 0; + } else { + newNode->prev = 0; + newNode->next = mFirst; + mFirst->prev = newNode; + mFirst = newNode; + } + } + + void insertTail(NODE* newNode) { + if (mLast == 0) { + insertHead(newNode); + } else { + newNode->prev = mLast; + newNode->next = 0; + mLast->next = newNode; + mLast = newNode; + } + } + + NODE* remove(NODE* node) { + if (node->prev == 0) mFirst = node->next; + else node->prev->next = node->next; + if (node->next == 0) mLast = node->prev; + else node->next->prev = node->prev; + return node; + } +}; + +class SimpleBestFitAllocator +{ +public: + + SimpleBestFitAllocator(); + SimpleBestFitAllocator(size_t size); + ~SimpleBestFitAllocator(); + + ssize_t setSize(size_t size); + + ssize_t allocate(size_t size, uint32_t flags = 0); + ssize_t deallocate(size_t offset); + size_t size() const; + +private: + struct chunk_t { + chunk_t(size_t start, size_t size) + : start(start), size(size), free(1), prev(0), next(0) { + } + size_t start; + size_t size : 28; + int free : 4; + mutable chunk_t* prev; + mutable chunk_t* next; + }; + + ssize_t alloc(size_t size, uint32_t flags); + chunk_t* dealloc(size_t start); + + static const int kMemoryAlign; + mutable Locker mLock; + LinkedList mList; + size_t mHeapSize; +}; + +#endif /* GRALLOC_ALLOCATOR_H_ */ diff --git a/modules/gralloc/framebuffer.cpp b/modules/gralloc/framebuffer.cpp new file mode 100644 index 00000000..7d2b582f --- /dev/null +++ b/modules/gralloc/framebuffer.cpp @@ -0,0 +1,371 @@ +/* + * 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 + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#if HAVE_ANDROID_OS +#include +#endif + +#include "gralloc_priv.h" +#include "gr.h" + +/*****************************************************************************/ + +// numbers of buffers for page flipping +#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( + 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(buffer); + private_module_t* m = reinterpret_cast( + 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; + 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 + + 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 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 = 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; + } + module->framebuffer->base = intptr_t(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(module); + dev->device.common.close = fb_close; + dev->device.setSwapInterval = fb_setSwapInterval; + dev->device.post = fb_post; + dev->device.setUpdateRect = 0; + + 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(dev->device.flags) = 0; + const_cast(dev->device.width) = m->info.xres; + const_cast(dev->device.height) = m->info.yres; + const_cast(dev->device.stride) = stride; + const_cast(dev->device.format) = HAL_PIXEL_FORMAT_RGB_565; + const_cast(dev->device.xdpi) = m->xdpi; + const_cast(dev->device.ydpi) = m->ydpi; + const_cast(dev->device.fps) = m->fps; + const_cast(dev->device.minSwapInterval) = 1; + const_cast(dev->device.maxSwapInterval) = 1; + *device = &dev->device.common; + } + } + return status; +} diff --git a/modules/gralloc/gr.h b/modules/gralloc/gr.h new file mode 100644 index 00000000..1775bfa7 --- /dev/null +++ b/modules/gralloc/gr.h @@ -0,0 +1,63 @@ +/* + * 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 GR_H_ +#define GR_H_ + +#include +#ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define +# include +#else +# include +#endif +#include +#include +#include +#include +#include + +#include + +/*****************************************************************************/ + +struct private_module_t; +struct private_handle_t; + +inline size_t roundUpToPageSize(size_t x) { + return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1); +} + +int mapFrameBufferLocked(struct private_module_t* module); +int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd); + +/*****************************************************************************/ + +class Locker { + pthread_mutex_t mutex; +public: + class Autolock { + Locker& locker; + public: + inline Autolock(Locker& locker) : locker(locker) { locker.lock(); } + inline ~Autolock() { locker.unlock(); } + }; + inline Locker() { pthread_mutex_init(&mutex, 0); } + inline ~Locker() { pthread_mutex_destroy(&mutex); } + inline void lock() { pthread_mutex_lock(&mutex); } + inline void unlock() { pthread_mutex_unlock(&mutex); } +}; + +#endif /* GR_H_ */ diff --git a/modules/gralloc/gralloc.cpp b/modules/gralloc/gralloc.cpp new file mode 100644 index 00000000..404d8b80 --- /dev/null +++ b/modules/gralloc/gralloc.cpp @@ -0,0 +1,489 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "gralloc_priv.h" +#include "allocator.h" + +#if HAVE_ANDROID_OS +#include +#endif + +/*****************************************************************************/ + +static SimpleBestFitAllocator sAllocator; + +/*****************************************************************************/ + +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_lock(gralloc_module_t const* module, + buffer_handle_t handle, int usage, + int l, int t, int w, int h, + void** vaddr); + +extern int gralloc_unlock(gralloc_module_t const* module, + buffer_handle_t handle); + +extern int gralloc_register_buffer(gralloc_module_t const* module, + buffer_handle_t handle); + +extern int gralloc_unregister_buffer(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 + }, + registerBuffer: gralloc_register_buffer, + unregisterBuffer: gralloc_unregister_buffer, + lock: gralloc_lock, + unlock: gralloc_unlock, + }, + framebuffer: 0, + flags: 0, + numBuffers: 0, + bufferMask: 0, + lock: PTHREAD_MUTEX_INITIALIZER, + currentBuffer: 0, + pmem_master: -1, + pmem_master_base: 0 +}; + +/*****************************************************************************/ + +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( + dev->common.module); + + // allocate the framebuffer + if (m->framebuffer == NULL) { + // initialize the framebuffer, the framebuffer is mapped once + // and forever. + int err = mapFrameBufferLocked(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; + return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle); + } + + if (bufferMask >= ((1LU<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 ; ibufferMask |= (1LU<base = vaddr; + hnd->offset = vaddr - intptr_t(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( + 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 init_pmem_area_locked(private_module_t* m) +{ + int err = 0; +#if HAVE_ANDROID_OS // should probably define HAVE_PMEM somewhere + int master_fd = open("/dev/pmem", O_RDWR, 0); + if (master_fd >= 0) { + + size_t size; + pmem_region region; + if (ioctl(master_fd, PMEM_GET_TOTAL_SIZE, ®ion) < 0) { + LOGE("PMEM_GET_TOTAL_SIZE failed, limp mode"); + size = 8<<20; // 8 MiB + } else { + size = region.len; + } + sAllocator.setSize(size); + + void* base = mmap(0, size, + PROT_READ|PROT_WRITE, MAP_SHARED, master_fd, 0); + if (base == MAP_FAILED) { + err = -errno; + base = 0; + close(master_fd); + master_fd = -1; + } + m->pmem_master = master_fd; + m->pmem_master_base = base; + } else { + err = -errno; + } + return err; +#else + return -1; +#endif +} + +static int init_pmem_area(private_module_t* m) +{ + pthread_mutex_lock(&m->lock); + int err = m->pmem_master; + if (err == -1) { + // first time, try to initialize pmem + err = init_pmem_area_locked(m); + if (err) { + m->pmem_master = err; + } + } else if (err < 0) { + // pmem couldn't be initialized, never use it + } else { + // pmem OK + err = 0; + } + 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) +{ + int err = 0; + int flags = 0; + + int fd = -1; + void* base = 0; + int offset = 0; + int lockState = 0; + + size = roundUpToPageSize(size); + +#if HAVE_ANDROID_OS // should probably define HAVE_PMEM somewhere + + if (usage & GRALLOC_USAGE_HW_TEXTURE) { + // enable pmem in that case, so our software GL can fallback to + // the copybit module. + flags |= private_handle_t::PRIV_FLAGS_USES_PMEM; + } + + if (usage & GRALLOC_USAGE_HW_2D) { + flags |= private_handle_t::PRIV_FLAGS_USES_PMEM; + } + + if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) == 0) { +try_ashmem: + fd = ashmem_create_region("gralloc-buffer", size); + if (fd < 0) { + LOGE("couldn't create ashmem (%s)", strerror(-errno)); + err = -errno; + } + } else { + private_module_t* m = reinterpret_cast( + dev->common.module); + + err = init_pmem_area(m); + if (err == 0) { + // PMEM buffers are always mmapped + base = m->pmem_master_base; + lockState |= private_handle_t::LOCK_STATE_MAPPED; + + offset = sAllocator.allocate(size); + if (offset < 0) { + // no more pmem memory + err = -ENOMEM; + } else { + struct pmem_region sub = { offset, size }; + + // now create the "sub-heap" + fd = open("/dev/pmem", O_RDWR, 0); + err = fd < 0 ? fd : 0; + + // and connect to it + if (err == 0) + err = ioctl(fd, PMEM_CONNECT, m->pmem_master); + + // and make it available to the client process + if (err == 0) + err = ioctl(fd, PMEM_MAP, &sub); + + if (err < 0) { + err = -errno; + close(fd); + sAllocator.deallocate(offset); + fd = -1; + } + //LOGD_IF(!err, "allocating pmem size=%d, offset=%d", size, offset); + memset((char*)base + offset, 0, size); + } + } else { + if ((usage & GRALLOC_USAGE_HW_2D) == 0) { + // the caller didn't request PMEM, so we can try something else + flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM; + err = 0; + goto try_ashmem; + } else { + LOGE("couldn't open pmem (%s)", strerror(-errno)); + } + } + } + +#else // HAVE_ANDROID_OS + + fd = ashmem_create_region("Buffer", size); + if (fd < 0) { + LOGE("couldn't create ashmem (%s)", strerror(-errno)); + err = -errno; + } + +#endif // HAVE_ANDROID_OS + + if (err == 0) { + private_handle_t* hnd = new private_handle_t(fd, size, flags); + hnd->offset = offset; + hnd->base = int(base)+offset; + hnd->lockState = lockState; + *pHandle = hnd; + } + + LOGE_IF(err, "gralloc failed err=%s", strerror(-err)); + + return err; +} + +/*****************************************************************************/ + +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; + + size_t size, stride; + if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP || + format == HAL_PIXEL_FORMAT_YCbCr_422_SP) + { + // FIXME: there is no way to return the vstride + int vstride; + stride = (w + 1) & ~1; + switch (format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + size = stride * h * 2; + break; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + vstride = (h+1) & ~1; + size = (stride * vstride) + (w/2 * h/2) * 2; + break; + default: + return -EINVAL; + } + } else { + int align = 4; + 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 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(handle); + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + // free this buffer + private_module_t* m = reinterpret_cast( + 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<flags & private_handle_t::PRIV_FLAGS_USES_PMEM) { + if (hnd->fd >= 0) { + struct pmem_region sub = { hnd->offset, hnd->size }; + int err = ioctl(hnd->fd, PMEM_UNMAP, &sub); + LOGE_IF(err<0, "PMEM_UNMAP failed (%s), " + "fd=%d, sub.offset=%lu, sub.size=%lu", + strerror(errno), hnd->fd, hnd->offset, hnd->size); + if (err == 0) { + // we can't deallocate the memory in case of UNMAP failure + // because it would give that process access to someone else's + // surfaces, which would be a security breach. + sAllocator.deallocate(hnd->offset); + } + } + } +#endif // HAVE_ANDROID_OS + gralloc_module_t* module = reinterpret_cast( + dev->common.module); + terminateBuffer(module, const_cast(hnd)); + } + + close(hnd->fd); + delete hnd; + return 0; +} + +/*****************************************************************************/ + +static int gralloc_close(struct hw_device_t *dev) +{ + gralloc_context_t* ctx = reinterpret_cast(dev); + if (ctx) { + /* TODO: keep a list of all buffer_handle_t created, and free them + * all here. + */ + 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(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 00000000..c3655a50 --- /dev/null +++ b/modules/gralloc/gralloc_priv.h @@ -0,0 +1,137 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#include + +/*****************************************************************************/ + +struct private_module_t; +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; + int pmem_master; + void* pmem_master_base; + + 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_PMEM = 0x00000002, + }; + + enum { + LOCK_STATE_WRITE = 1<<31, + LOCK_STATE_MAPPED = 1<<30, + LOCK_STATE_READ_MASK = 0x3FFFFFFF + }; + + // file-descriptors + int fd; + // ints + int magic; + int flags; + int size; + int offset; + + // FIXME: the attributes below should be out-of-line + int base; + int lockState; + int writeOwner; + int pid; + +#ifdef __cplusplus + static const int sNumInts = 8; + static const int sNumFds = 1; + static const int sMagic = 0x3141592; + + private_handle_t(int fd, int size, int flags) : + fd(fd), magic(sMagic), flags(flags), size(size), offset(0), + base(0), lockState(0), writeOwner(0), pid(getpid()) + { + 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) { + 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) + { + LOGE("invalid gralloc handle (at %p)", h); + 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/modules/gralloc/mapper.cpp b/modules/gralloc/mapper.cpp new file mode 100644 index 00000000..e2caf79e --- /dev/null +++ b/modules/gralloc/mapper.cpp @@ -0,0 +1,282 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include "gralloc_priv.h" + + +// we need this for now because pmem cannot mmap at an offset +#define PMEM_HACK 1 + +/* desktop Linux needs a little help with gettid() */ +#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS) +#define __KERNEL__ +# include +pid_t gettid() { return syscall(__NR_gettid);} +#undef __KERNEL__ +#endif + +/*****************************************************************************/ + +static int gralloc_map(gralloc_module_t const* module, + buffer_handle_t handle, + void** vaddr) +{ + private_handle_t* hnd = (private_handle_t*)handle; + if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { + size_t size = hnd->size; +#if PMEM_HACK + size += hnd->offset; +#endif + void* mappedAddress = mmap(0, size, + PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0); + if (mappedAddress == MAP_FAILED) { + LOGE("Could not mmap %s", strerror(errno)); + return -errno; + } + hnd->base = intptr_t(mappedAddress) + hnd->offset; + //LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p", + // hnd->fd, hnd->offset, hnd->size, mappedAddress); + } + *vaddr = (void*)hnd->base; + return 0; +} + +static int gralloc_unmap(gralloc_module_t const* module, + buffer_handle_t handle) +{ + private_handle_t* hnd = (private_handle_t*)handle; + if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { + void* base = (void*)hnd->base; + size_t size = hnd->size; +#if PMEM_HACK + base = (void*)(intptr_t(base) - hnd->offset); + size += hnd->offset; +#endif + //LOGD("unmapping from %p, size=%d", base, size); + if (munmap(base, size) < 0) { + LOGE("Could not unmap %s", strerror(errno)); + } + } + hnd->base = 0; + return 0; +} + +/*****************************************************************************/ + +static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER; + +/*****************************************************************************/ + +int gralloc_register_buffer(gralloc_module_t const* module, + buffer_handle_t handle) +{ + if (private_handle_t::validate(handle) < 0) + return -EINVAL; + + // In this implementation, we don't need to do anything here + + /* NOTE: we need to initialize the buffer as not mapped/not locked + * because it shouldn't when this function is called the first time + * in a new process. Ideally these flags shouldn't be part of the + * handle, but instead maintained in the kernel or at least + * out-of-line + */ + + // 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()) { + hnd->base = 0; + hnd->lockState = 0; + hnd->writeOwner = 0; + } + return 0; +} + +int gralloc_unregister_buffer(gralloc_module_t const* module, + buffer_handle_t handle) +{ + if (private_handle_t::validate(handle) < 0) + return -EINVAL; + + /* + * If the buffer has been mapped during a lock operation, it's time + * to un-map it. It's an error to be here with a locked buffer. + * NOTE: the framebuffer is handled differently and is never unmapped. + */ + + 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()) { + if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) { + gralloc_unmap(module, handle); + } + hnd->base = 0; + hnd->lockState = 0; + hnd->writeOwner = 0; + } + return 0; +} + +int terminateBuffer(gralloc_module_t const* module, + private_handle_t* hnd) +{ + /* + * If the buffer has been mapped during a lock operation, it's time + * to un-map it. It's an error to be here with a locked buffer. + */ + + LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK, + "[terminate] handle %p still locked (state=%08x)", + hnd, hnd->lockState); + + if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) { + // this buffer was mapped, unmap it now + if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) && + (hnd->pid == getpid())) { + // ... unless it's a "master" pmem buffer, that is a buffer + // mapped in the process it's been allocated. + // (see gralloc_alloc_buffer()) + } else { + gralloc_unmap(module, hnd); + } + } + + return 0; +} + +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) + return -EINVAL; + + int err = 0; + private_handle_t* hnd = (private_handle_t*)handle; + int32_t current_value, new_value; + int retry; + + do { + current_value = hnd->lockState; + new_value = current_value; + + if (current_value & private_handle_t::LOCK_STATE_WRITE) { + // already locked for write + LOGE("handle %p already locked for write", handle); + return -EBUSY; + } else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) { + // already locked for read + if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) { + LOGE("handle %p already locked for read", handle); + return -EBUSY; + } else { + // this is not an error + //LOGD("%p already locked for read... count = %d", + // handle, (current_value & ~(1<<31))); + } + } + + // not currently locked + if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) { + // locking for write + new_value |= private_handle_t::LOCK_STATE_WRITE; + } + new_value++; + + retry = android_atomic_cmpxchg(current_value, new_value, + (volatile int32_t*)&hnd->lockState); + } while (retry); + + if (new_value & private_handle_t::LOCK_STATE_WRITE) { + // locking for write, store the tid + hnd->writeOwner = gettid(); + } + + if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { + if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) { + // we need to map for real + pthread_mutex_t* const lock = &sMapLock; + pthread_mutex_lock(lock); + if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) { + err = gralloc_map(module, handle, vaddr); + if (err == 0) { + android_atomic_or(private_handle_t::LOCK_STATE_MAPPED, + (volatile int32_t*)&(hnd->lockState)); + } + } + pthread_mutex_unlock(lock); + } + *vaddr = (void*)hnd->base; + } + + return err; +} + +int gralloc_unlock(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; + int32_t current_value, new_value; + + do { + current_value = hnd->lockState; + new_value = current_value; + + if (current_value & private_handle_t::LOCK_STATE_WRITE) { + // locked for write + if (hnd->writeOwner == gettid()) { + hnd->writeOwner = 0; + new_value &= ~private_handle_t::LOCK_STATE_WRITE; + } + } + + if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) { + LOGE("handle %p not locked", handle); + return -EINVAL; + } + + new_value--; + + } while (android_atomic_cmpxchg(current_value, new_value, + (volatile int32_t*)&hnd->lockState)); + + return 0; +} diff --git a/modules/overlay/overlay.cpp b/modules/overlay/overlay.cpp index 0246b5bb..a91df587 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, From a6612f84427a10c2f08e1a60cd83442111b3a602 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 12 Jan 2010 15:19:04 -0800 Subject: [PATCH 2/2] android-2.1_r1 snapshot