diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk new file mode 100644 index 0000000..e32fbea --- /dev/null +++ b/liboverlay/Android.mk @@ -0,0 +1,37 @@ +# Copyright (C) 2008 The Android Open Source Project +# Copyright (c) 2009, Code Aurora Forum. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_PRELINK_MODULE := false +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) +LOCAL_SHARED_LIBRARIES := liblog libcutils +LOCAL_C_INCLUDES += hardware/msm7k/libgralloc-qsd8k +LOCAL_SRC_FILES := overlayLib.cpp +LOCAL_MODULE := liboverlay +include $(BUILD_SHARED_LIBRARY) + +# 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 liboverlay libcutils +LOCAL_C_INCLUDES += hardware/msm7k/libgralloc-qsd8k +LOCAL_SRC_FILES := overlay.cpp +LOCAL_MODULE := overlay.default +include $(BUILD_SHARED_LIBRARY) diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp new file mode 100644 index 0000000..988c18c --- /dev/null +++ b/liboverlay/overlay.cpp @@ -0,0 +1,820 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Overlay" + +#include +#include "overlayLib.h" +#include +#include +#include +#include +#include + +using android::Mutex; + +#define USE_MSM_ROTATOR +#define EVEN_OUT(x) if (x & 0x0001) {x--;} + +#define SHARED_MEMORY_REGION_NAME "overlay_shared_memory" +/*****************************************************************************/ + +using namespace overlay; + +struct overlay_control_context_t { + struct overlay_control_device_t device; + void *sharedMemBase; +}; + +struct ov_crop_rect_t { + int x; + int y; + int w; + int h; +}; + +struct overlay_data_context_t { + struct overlay_data_device_t device; + OverlayDataChannel* pobjDataChannel[2]; + int setCrop; + struct ov_crop_rect_t cropRect; + void *sharedMemBase; +}; + +static int overlay_device_open(const struct hw_module_t* module, const char* name, + struct hw_device_t** device); + +static struct hw_module_methods_t overlay_module_methods = { + open: overlay_device_open +}; + +struct private_overlay_module_t { + overlay_module_t base; + Mutex *pobjMutex; +}; + +struct private_overlay_module_t HAL_MODULE_INFO_SYM = { + base: { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: OVERLAY_HARDWARE_MODULE_ID, + name: "QCT MSM OVERLAY module", + author: "QuIC, Inc.", + methods: &overlay_module_methods, + } + }, + pobjMutex: NULL, +}; + +struct handle_t : public native_handle { + int sharedMemoryFd; + int ovid[2]; + int rotid[2]; + int size; + int w; + int h; + int format; + OverlayControlChannel *pobjControlChannel[2]; +}; + +static int handle_get_ovId(const overlay_handle_t overlay, int index = 0) { + return static_cast(overlay)->ovid[index]; +} + +static int handle_get_rotId(const overlay_handle_t overlay, int index = 0) { + return static_cast(overlay)->rotid[index]; +} + + +static int handle_get_size(const overlay_handle_t overlay) { + return static_cast(overlay)->size; +} + +static int handle_get_shared_fd(const overlay_handle_t overlay) { + return static_cast(overlay)->sharedMemoryFd; +} + +/* + * This is the overlay_t object, it is returned to the user and represents + * an overlay. + * This handles will be passed across processes and possibly given to other + * HAL modules (for instance video decode modules). + */ +class overlay_object : public overlay_t { + handle_t mHandle; + + static overlay_handle_t getHandleRef(struct overlay_t* overlay) { + /* returns a reference to the handle, caller doesn't take ownership */ + return &(static_cast(overlay)->mHandle); + } + +public: + overlay_object(int w, int h, int format, int fd) { + this->overlay_t::getHandleRef = getHandleRef; + mHandle.version = sizeof(native_handle); + mHandle.sharedMemoryFd = fd; + mHandle.numFds = 1; + mHandle.numInts = (sizeof(mHandle) - sizeof(native_handle)) / 4; + mHandle.ovid[0] = -1; + mHandle.ovid[1] = -1; + mHandle.rotid[0] = -1; + mHandle.rotid[1] = -1; + mHandle.size = -1; + mHandle.w = w; + mHandle.h = h; + mHandle.format = format; + mHandle.pobjControlChannel[0] = 0; + mHandle.pobjControlChannel[1] = 0; + } + + ~overlay_object() { + destroy_overlay(); + } + + int getHwOvId(int index = 0) { return mHandle.ovid[index]; } + int getRotSessionId(int index = 0) { return mHandle.rotid[index]; } + int getSharedMemoryFD() {return mHandle.sharedMemoryFd;} + + bool startControlChannel(int fbnum, bool norot = false) { + if (!mHandle.pobjControlChannel[fbnum]) + mHandle.pobjControlChannel[fbnum] = new OverlayControlChannel(); + else { + mHandle.pobjControlChannel[fbnum]->closeControlChannel(); + mHandle.pobjControlChannel[fbnum] = new OverlayControlChannel(); + } + bool ret = mHandle.pobjControlChannel[fbnum]->startControlChannel( + mHandle.w, mHandle.h, mHandle.format, fbnum, norot); + if (ret) { + if (!(mHandle.pobjControlChannel[fbnum]-> + getOvSessionID(mHandle.ovid[fbnum]) && + mHandle.pobjControlChannel[fbnum]-> + getRotSessionID(mHandle.rotid[fbnum]) && + mHandle.pobjControlChannel[fbnum]-> + getSize(mHandle.size))) + ret = false; + } + + if (!ret) { + closeControlChannel(fbnum); + } + + return ret; + } + + bool setPosition(int x, int y, uint32_t w, uint32_t h, int fbnum) { + if (!mHandle.pobjControlChannel[fbnum]) + return false; + return mHandle.pobjControlChannel[fbnum]->setPosition( + x, y, w, h); + } + + bool setParameter(int param, int value, int fbnum) { + if (!mHandle.pobjControlChannel[fbnum]) + return false; + return mHandle.pobjControlChannel[fbnum]->setParameter( + param, value); + } + + bool closeControlChannel(int fbnum) { + if (!mHandle.pobjControlChannel[fbnum]) + return true; + bool ret = mHandle.pobjControlChannel[fbnum]-> + closeControlChannel(); + delete mHandle.pobjControlChannel[fbnum]; + mHandle.pobjControlChannel[fbnum] = 0; + return ret; + } + + bool getPosition(int *x, int *y, uint32_t *w, uint32_t *h, int fbnum) { + if (!mHandle.pobjControlChannel[fbnum]) + return false; + return mHandle.pobjControlChannel[fbnum]->getPosition( + *x, *y, *w, *h); + } + + bool getOrientation(int *orientation, int fbnum) { + if (!mHandle.pobjControlChannel[fbnum]) + return false; + return mHandle.pobjControlChannel[fbnum]->getOrientation( + *orientation); + } + + void destroy_overlay() { + close(mHandle.sharedMemoryFd); + closeControlChannel(0); + closeControlChannel(1); + } + + int getFBWidth(int fbnum) { + if (!mHandle.pobjControlChannel[fbnum]) + return false; + return mHandle.pobjControlChannel[fbnum]->getFBWidth(); + } + + int getFBHeight(int fbnum) { + if (!mHandle.pobjControlChannel[fbnum]) + return false; + return mHandle.pobjControlChannel[fbnum]->getFBHeight(); + } +}; + +// **************************************************************************** +// Control module +// **************************************************************************** + + static int overlay_get(struct overlay_control_device_t *dev, int name) { + int result = -1; + switch (name) { + case OVERLAY_MINIFICATION_LIMIT: + result = HW_OVERLAY_MINIFICATION_LIMIT; + break; + case OVERLAY_MAGNIFICATION_LIMIT: + result = HW_OVERLAY_MAGNIFICATION_LIMIT; + break; + case OVERLAY_SCALING_FRAC_BITS: + result = 32; + break; + case OVERLAY_ROTATION_STEP_DEG: + result = 90; // 90 rotation steps (for instance) + break; + case OVERLAY_HORIZONTAL_ALIGNMENT: + result = 1; // 1-pixel alignment + break; + case OVERLAY_VERTICAL_ALIGNMENT: + result = 1; // 1-pixel alignment + break; + case OVERLAY_WIDTH_ALIGNMENT: + result = 1; // 1-pixel alignment + break; + case OVERLAY_HEIGHT_ALIGNMENT: + result = 1; // 1-pixel alignment + break; + } + return result; + } + + static overlay_t* overlay_createOverlay(struct overlay_control_device_t *dev, + uint32_t w, uint32_t h, int32_t format) { + overlay_object *overlay = NULL; + overlay_control_context_t *ctx = (overlay_control_context_t *)dev; + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + Mutex::Autolock objLock(m->pobjMutex); + + // Open shared memory to store shared data + int size = sizeof(overlay_shared_data); + void *base; + int fd = ashmem_create_region(SHARED_MEMORY_REGION_NAME, + size); + + if(fd < 0) { + LOGE("%s: create shared memory failed", __func__); + return NULL; + } + if (ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE) < 0) { + LOGE("ashmem_set_prot_region(fd=%d, failed (%s)", + fd, strerror(-errno)); + close(fd); + fd = -1; + return NULL; + } else { + base = mmap(0, size, PROT_READ | PROT_WRITE, + MAP_SHARED|MAP_POPULATE, fd, 0); + if (base == MAP_FAILED) { + LOGE("alloc mmap(fd=%d, size=%d) failed (%s)", + fd, size, strerror(-errno)); + close(fd); + fd = -1; + return NULL; + } + } + ctx->sharedMemBase = base; + memset(ctx->sharedMemBase, 0, size); + + /* number of buffer is not being used as overlay buffers are coming from client */ + overlay = new overlay_object(w, h, format, fd); + + if (overlay == NULL) { + LOGE("%s: can't create overlay object!", __FUNCTION__); + if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { + munmap(ctx->sharedMemBase, size); + ctx->sharedMemBase = MAP_FAILED; + } + if(fd > 0) + close(fd); + return NULL; + } + +#ifdef USE_MSM_ROTATOR + if (!overlay->startControlChannel(0)) { +#else + if (!overlay->startControlChannel(0, true)) { +#endif + LOGE("Failed to start control channel for framebuffer 0"); + overlay->closeControlChannel(0); + if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { + munmap(ctx->sharedMemBase, size); + ctx->sharedMemBase = MAP_FAILED; + } + if(fd > 0) + close(fd); + + delete overlay; + return NULL; + } + + char value[PROPERTY_VALUE_MAX]; + property_get("hw.hdmiON", value, "0"); + if (!atoi(value)) { + return overlay; + } + + if (!overlay->startControlChannel(1, true)) { + LOGE("Failed to start control channel for framebuffer 1"); + overlay->closeControlChannel(1); + if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { + munmap(ctx->sharedMemBase, size); + ctx->sharedMemBase = MAP_FAILED; + } + if(fd > 0) + close(fd); + + delete overlay; + return NULL; + } + else { + int width = w, height = h, x, y; + int fbWidthHDMI = overlay->getFBWidth(1); + int fbHeightHDMI = overlay->getFBHeight(1); + // width and height for YUV TILE format + int tempWidth = w, tempHeight = h; + /* Caculate the width and height if it is YUV TILE format*/ + if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { + tempWidth = w - ( (((w-1)/64 +1)*64) - w); + tempHeight = h - ((((h-1)/32 +1)*32) - h); + } + + if (width * fbHeightHDMI > + fbWidthHDMI * height) { + height = fbWidthHDMI * height / width; + EVEN_OUT(height); + width = fbWidthHDMI; + } else if (width * fbHeightHDMI < + fbWidthHDMI * height) { + width = fbHeightHDMI * width / height; + EVEN_OUT(width); + height = fbHeightHDMI; + } else { + width = fbWidthHDMI; + height = fbHeightHDMI; + } + /* Scaling of upto a max of 8 times supported */ + if(width >(tempWidth * HW_OVERLAY_MAGNIFICATION_LIMIT)){ + width = HW_OVERLAY_MAGNIFICATION_LIMIT * tempWidth; + } + if(height >(tempHeight*HW_OVERLAY_MAGNIFICATION_LIMIT)) { + height = HW_OVERLAY_MAGNIFICATION_LIMIT * tempHeight; + } + if (width > fbWidthHDMI) width = fbWidthHDMI; + if (height > fbHeightHDMI) height = fbHeightHDMI; + x = (fbWidthHDMI - width) / 2; + y = (fbHeightHDMI - height) / 2; + + if (!overlay->setPosition(x, y, width, height, 1)) + LOGE("Failed to upscale for framebuffer 1"); + } + + return overlay; + + } + + static void overlay_destroyOverlay(struct overlay_control_device_t *dev, + overlay_t* overlay) + { + overlay_control_context_t *ctx = (overlay_control_context_t *)dev; + overlay_object * obj = static_cast(overlay); + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + Mutex::Autolock objLock(m->pobjMutex); + if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { + munmap(ctx->sharedMemBase, sizeof(overlay_shared_data)); + ctx->sharedMemBase = MAP_FAILED; + } + obj->destroy_overlay(); + delete overlay; + } + + static int overlay_setPosition(struct overlay_control_device_t *dev, + overlay_t* overlay, + int x, int y, uint32_t w, uint32_t h) { + /* set this overlay's position (talk to the h/w) */ + overlay_control_context_t *ctx = (overlay_control_context_t *)dev; + overlay_object * obj = static_cast(overlay); + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + Mutex::Autolock objLock(m->pobjMutex); + + bool ret = obj->setPosition(x, y, w, h, 0); + if (!ret) + return -1; + return 0; + } + + static int overlay_commit(struct overlay_control_device_t *dev, + overlay_t* overlay) + { + overlay_control_context_t *ctx = (overlay_control_context_t *)dev; + overlay_object *obj = static_cast(overlay); + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + + Mutex::Autolock objLock(m->pobjMutex); + if (obj && (obj->getSharedMemoryFD() > 0) && + (ctx->sharedMemBase != MAP_FAILED)) { + overlay_shared_data data; + data.readyToQueue = 1; + memcpy(ctx->sharedMemBase, (void*)&data, sizeof(overlay_shared_data)); + } +return 0; + } + + static int overlay_getPosition(struct overlay_control_device_t *dev, + overlay_t* overlay, + int* x, int* y, uint32_t* w, uint32_t* h) { + + /* get this overlay's position */ + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + Mutex::Autolock objLock(m->pobjMutex); + overlay_object * obj = static_cast(overlay); + bool ret = obj->getPosition(x, y, w, h, 0); + if (!ret) + return -1; + return 0; + } + + static int overlay_setParameter(struct overlay_control_device_t *dev, + overlay_t* overlay, int param, int value) { + + overlay_control_context_t *ctx = (overlay_control_context_t *)dev; + overlay_object *obj = static_cast(overlay); + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + + Mutex::Autolock objLock(m->pobjMutex); + + if (obj && (obj->getSharedMemoryFD() > 0) && + (ctx->sharedMemBase != MAP_FAILED)) { + overlay_shared_data data; + data.readyToQueue = 0; + memcpy(ctx->sharedMemBase, (void*)&data, sizeof(data)); + } + + bool ret = obj->setParameter(param, value, 0); + if (!ret) + return -1; + + return 0; + } + + static int overlay_control_close(struct hw_device_t *dev) + { + struct overlay_control_context_t* ctx = (struct overlay_control_context_t*)dev; + if (ctx) { + /* free all resources associated with this device here + * in particular the overlay_handle_t, outstanding overlay_t, etc... + */ + free(ctx); + } + return 0; + } + +// **************************************************************************** +// Data module +// **************************************************************************** + + int overlay_initialize(struct overlay_data_device_t *dev, + overlay_handle_t handle) + { + /* + * overlay_handle_t should contain all the information to "inflate" this + * overlay. Typically it'll have a file descriptor, informations about + * how many buffers are there, etc... + * It is also the place to mmap all buffers associated with this overlay + * (see getBufferAddress). + * + * NOTE: this function doesn't take ownership of overlay_handle_t + * + */ + + struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev; + int ovid = handle_get_ovId(handle); + int rotid = handle_get_rotId(handle); + int size = handle_get_size(handle); + int sharedFd = handle_get_shared_fd(handle); + + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + Mutex::Autolock objLock(m->pobjMutex); + + ctx->sharedMemBase = MAP_FAILED; + + if(sharedFd > 0) { + void *base = mmap(0, sizeof(overlay_shared_data), PROT_READ, + MAP_SHARED|MAP_POPULATE, sharedFd, 0); + if(base == MAP_FAILED) { + LOGE("%s: map region failed %d", __func__, -errno); + return -1; + } + ctx->sharedMemBase = base; + } else { + LOGE("Received invalid shared memory fd"); + return -1; + } + + ctx->pobjDataChannel[0] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[0]->startDataChannel(ovid, rotid, + size, 0)) { + LOGE("Couldnt start data channel for framebuffer 0"); + delete ctx->pobjDataChannel[0]; + ctx->pobjDataChannel[0] = 0; + return -1; + } + + char value[PROPERTY_VALUE_MAX]; + property_get("hw.hdmiON", value, "0"); + if (!atoi(value)) { + ctx->pobjDataChannel[1] = 0; + return 0; + } + + ovid = handle_get_ovId(handle, 1); + rotid = handle_get_rotId(handle, 1); + ctx->pobjDataChannel[1] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[1]->startDataChannel(ovid, rotid, + size, 1, true)) { + LOGE("Couldnt start data channel for framebuffer 1"); + delete ctx->pobjDataChannel[1]; + ctx->pobjDataChannel[1] = 0; + } + + return 0; + } + + int overlay_dequeueBuffer(struct overlay_data_device_t *dev, + overlay_buffer_t* buf) + { + /* blocks until a buffer is available and return an opaque structure + * representing this buffer. + */ + + /* no interal overlay buffer to dequeue */ + LOGE("%s: no buffer to dequeue ...\n", __FUNCTION__); + + return 0; + } + + int overlay_queueBuffer(struct overlay_data_device_t *dev, + overlay_buffer_t buffer) + { + /* Mark this buffer for posting and recycle or free overlay_buffer_t. */ + struct overlay_data_context_t *ctx = (struct overlay_data_context_t*)dev; + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + Mutex::Autolock objLock(m->pobjMutex); + + // Check if readyToQueue is enabled. + overlay_shared_data data; + if(ctx->sharedMemBase != MAP_FAILED) + memcpy(&data, ctx->sharedMemBase, sizeof(data)); + else + return false; + + if(!data.readyToQueue) { + LOGE("Overlay is not ready to queue buffers"); + return -1; + } + if(ctx->setCrop) { + bool result = (ctx->pobjDataChannel[0] && + ctx->pobjDataChannel[0]-> + setCrop(ctx->cropRect.x,ctx->cropRect.y,ctx->cropRect.w,ctx->cropRect.h)); + ctx->setCrop = 0; + if (!result) { + LOGE("set crop failed for framebuffer 0"); + return -1; + } + } + + bool result = (ctx->pobjDataChannel[0] && + ctx->pobjDataChannel[0]-> + queueBuffer((uint32_t) buffer)); + if (!result) + LOGE("Queuebuffer failed for framebuffer 0"); + else { + char value[PROPERTY_VALUE_MAX]; + property_get("hw.hdmiON", value, "0"); + if (!atoi(value)) { + return 0; + } + result = (ctx->pobjDataChannel[1] && + ctx->pobjDataChannel[1]-> + queueBuffer((uint32_t) buffer)); + if (!result) { + LOGE("QueueBuffer failed for framebuffer 1"); + return -1; + } + } + + return -1; + } + + int overlay_setFd(struct overlay_data_device_t *dev, int fd) + { + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev; + Mutex::Autolock objLock(m->pobjMutex); + + bool ret = (ctx->pobjDataChannel[0] && + ctx->pobjDataChannel[0]->setFd(fd)); + if (!ret) { + LOGE("set fd failed for framebuffer 0"); + return -1; + } + + char value[PROPERTY_VALUE_MAX]; + property_get("hw.hdmiON", value, "0"); + if (!atoi(value)) { + return 0; + } + + ret = (ctx->pobjDataChannel[1] && + ctx->pobjDataChannel[1]->setFd(fd)); + if (!ret) { + LOGE("set fd failed for framebuffer 1"); + } + + return 0; + } + + static int overlay_setCrop(struct overlay_data_device_t *dev, uint32_t x, + uint32_t y, uint32_t w, uint32_t h) + { + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev; + Mutex::Autolock objLock(m->pobjMutex); + + //For primary set Crop + ctx->setCrop = 1; + ctx->cropRect.x = x; + ctx->cropRect.y = y; + ctx->cropRect.w = w; + ctx->cropRect.h = h; + + char value[PROPERTY_VALUE_MAX]; + property_get("hw.hdmiON", value, "0"); + if (!atoi(value)) { + return 0; + } + + bool ret = (ctx->pobjDataChannel[1] && + ctx->pobjDataChannel[1]-> + setCrop(x, y, w, h)); + if (!ret) { + LOGE("set crop failed for framebuffer 1"); + return -1; + } + return 0; + } + + void *overlay_getBufferAddress(struct overlay_data_device_t *dev, + overlay_buffer_t buffer) + { + /* overlay buffers are coming from client */ + return( NULL ); + } + + int overlay_getBufferCount(struct overlay_data_device_t *dev) + { + return( 0 ); + } + + + static int overlay_data_close(struct hw_device_t *dev) + { + struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev; + if (ctx) { + /* free all resources associated with this device here + * in particular all pending overlay_buffer_t if needed. + * + * NOTE: overlay_handle_t passed in initialize() is NOT freed and + * its file descriptors are not closed (this is the responsibility + * of the caller). + */ + + if (ctx->pobjDataChannel[0]) { + ctx->pobjDataChannel[0]->closeDataChannel(); + delete ctx->pobjDataChannel[0]; + ctx->pobjDataChannel[0] = 0; + } + + if (ctx->pobjDataChannel[1]) { + ctx->pobjDataChannel[1]->closeDataChannel(); + delete ctx->pobjDataChannel[1]; + ctx->pobjDataChannel[1] = 0; + } + + if(ctx->sharedMemBase != MAP_FAILED) { + munmap(ctx->sharedMemBase, sizeof(overlay_shared_data)); + ctx->sharedMemBase = MAP_FAILED; + } + + free(ctx); + } + return 0; + } + +/*****************************************************************************/ + + static int overlay_device_open(const struct hw_module_t* module, const char* name, + struct hw_device_t** device) + { + int status = -EINVAL; + + private_overlay_module_t* m = reinterpret_cast + (const_cast(module)); + if (!m->pobjMutex) + m->pobjMutex = new Mutex(); + + if (!strcmp(name, OVERLAY_HARDWARE_CONTROL)) { + struct overlay_control_context_t *dev; + dev = (overlay_control_context_t*)malloc(sizeof(*dev)); + + if (!dev) + return status; + + /* 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 = overlay_control_close; + + dev->device.get = overlay_get; + dev->device.createOverlay = overlay_createOverlay; + dev->device.destroyOverlay = overlay_destroyOverlay; + dev->device.setPosition = overlay_setPosition; + dev->device.getPosition = overlay_getPosition; + dev->device.setParameter = overlay_setParameter; + dev->device.commit = overlay_commit; + + *device = &dev->device.common; + status = 0; + } else if (!strcmp(name, OVERLAY_HARDWARE_DATA)) { + struct overlay_data_context_t *dev; + dev = (overlay_data_context_t*)malloc(sizeof(*dev)); + + if (!dev) + return status; + + /* 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 = overlay_data_close; + + dev->device.initialize = overlay_initialize; + dev->device.setCrop = overlay_setCrop; + dev->device.dequeueBuffer = overlay_dequeueBuffer; + dev->device.queueBuffer = overlay_queueBuffer; + dev->device.setFd = overlay_setFd; + dev->device.getBufferAddress = overlay_getBufferAddress; + dev->device.getBufferCount = overlay_getBufferCount; + + *device = &dev->device.common; + status = 0; + } + return status; + } diff --git a/liboverlay/overlayLib.cpp b/liboverlay/overlayLib.cpp new file mode 100644 index 0000000..222adb5 --- /dev/null +++ b/liboverlay/overlayLib.cpp @@ -0,0 +1,849 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "overlayLib.h" +#include "gralloc_priv.h" + +#define INTERLACE_MASK 0x80 +/* Helper functions */ + +static int get_mdp_format(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888 : + return MDP_RGBA_8888; + case HAL_PIXEL_FORMAT_BGRA_8888: + return MDP_BGRA_8888; + case HAL_PIXEL_FORMAT_RGB_565: + return MDP_RGB_565; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + return MDP_Y_CBCR_H2V1; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + return MDP_Y_CBCR_H2V2; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + return MDP_Y_CRCB_H2V2; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + return MDP_Y_CRCB_H2V2_TILE; + } + return -1; +} + +static int get_size(int format, int w, int h) { + int size, aligned_height, pitch; + + size = w * h; + switch (format) { + case MDP_RGBA_8888: + case MDP_BGRA_8888: + size *= 4; + break; + case MDP_RGB_565: + case MDP_Y_CBCR_H2V1: + size *= 2; + break; + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + size = (size * 3) / 2; + break; + case MDP_Y_CRCB_H2V2_TILE: + aligned_height = (h + 31) & ~31; + pitch = (w + 127) & ~127; + size = pitch * aligned_height; + size = (size + 8191) & ~8191; + + aligned_height = ((h >> 1) + 31) & ~31; + size += pitch * aligned_height; + size = (size + 8191) & ~8191; + break; + default: + return 0; + } + return size; +} + +#define LOG_TAG "OverlayLIB" +static void reportError(const char* message) { + LOGE( "%s", message); +} + +using namespace overlay; + +Overlay::Overlay() : mChannelUP(false) { +} + +Overlay::~Overlay() { + closeChannel(); +} + +int Overlay::getFBWidth() const { + return objOvCtrlChannel.getFBWidth(); +} + +int Overlay::getFBHeight() const { + return objOvCtrlChannel.getFBHeight(); +} + +bool Overlay::startChannel(int w, int h, int format, int fbnum, bool norot, bool uichannel) { + mChannelUP = objOvCtrlChannel.startControlChannel(w, h, format, fbnum, norot); + if (!mChannelUP) { + return mChannelUP; + } + return objOvDataChannel.startDataChannel(objOvCtrlChannel, fbnum, norot, uichannel); +} + +bool Overlay::closeChannel() { + if (!mChannelUP) + return true; + objOvCtrlChannel.closeControlChannel(); + objOvDataChannel.closeDataChannel(); + mChannelUP = false; + return true; +} + +bool Overlay::getPosition(int& x, int& y, uint32_t& w, uint32_t& h) { + return objOvCtrlChannel.getPosition(x, y, w, h); +} + +bool Overlay::getOrientation(int& orientation) const { + return objOvCtrlChannel.getOrientation(orientation); +} + +bool Overlay::setPosition(int x, int y, uint32_t w, uint32_t h) { + return objOvCtrlChannel.setPosition(x, y, w, h); +} + +bool Overlay::setSource(uint32_t w, uint32_t h, int format, int orientation) { + if (!objOvCtrlChannel.setSource(w, h, format, orientation)) { + objOvCtrlChannel.closeControlChannel(); + objOvDataChannel.closeDataChannel(); + mChannelUP = false; + return startChannel(w, h, format, 0, !orientation); + } + else + return true; +} + +bool Overlay::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { + if (!mChannelUP) + return false; + return objOvDataChannel.setCrop(x, y, w, h); +} + +bool Overlay::setParameter(int param, int value) { + return objOvCtrlChannel.setParameter(param, value); +} + +bool Overlay::setOrientation(int value) { + return objOvCtrlChannel.setParameter(OVERLAY_TRANSFORM, value); +} + +bool Overlay::setFd(int fd) { + return objOvDataChannel.setFd(fd); +} + +bool Overlay::queueBuffer(uint32_t offset) { + return objOvDataChannel.queueBuffer(offset); +} + +bool Overlay::queueBuffer(buffer_handle_t buffer) { + private_handle_t const* hnd = reinterpret_cast + (buffer); + const size_t offset = hnd->offset; + const int fd = hnd->fd; + if (setFd(fd)) { + return queueBuffer(offset); + } + return false; +} + +OverlayControlChannel::OverlayControlChannel() : mNoRot(false), mFD(-1), mRotFD(-1) { + memset(&mOVInfo, 0, sizeof(mOVInfo)); + memset(&mRotInfo, 0, sizeof(mRotInfo)); +} + + +OverlayControlChannel::~OverlayControlChannel() { + closeControlChannel(); +} + +bool OverlayControlChannel::openDevices(int fbnum) { + if (fbnum < 0) + return false; + + char const * const device_template = + "/dev/graphics/fb%u"; + char dev_name[64]; + snprintf(dev_name, 64, device_template, fbnum); + + mFD = open(dev_name, O_RDWR, 0); + if (mFD < 0) { + reportError("Cant open framebuffer "); + return false; + } + + fb_fix_screeninfo finfo; + if (ioctl(mFD, FBIOGET_FSCREENINFO, &finfo) == -1) { + reportError("FBIOGET_FSCREENINFO on fb1 failed"); + close(mFD); + mFD = -1; + return false; + } + + fb_var_screeninfo vinfo; + if (ioctl(mFD, FBIOGET_VSCREENINFO, &vinfo) == -1) { + reportError("FBIOGET_VSCREENINFO on fb1 failed"); + close(mFD); + mFD = -1; + return false; + } + mFBWidth = vinfo.xres; + mFBHeight = vinfo.yres; + mFBbpp = vinfo.bits_per_pixel; + mFBystride = finfo.line_length; + + if (!mNoRot) { + mRotFD = open("/dev/msm_rotator", O_RDWR, 0); + if (mRotFD < 0) { + reportError("Cant open rotator device"); + close(mFD); + mFD = -1; + return false; + } + } + + return true; +} + +bool OverlayControlChannel::setOverlayInformation(int w, int h, + int format, int flags) { + int origW, origH, xoff, yoff; + + mOVInfo.id = MSMFB_NEW_REQUEST; + mOVInfo.src.width = w; + mOVInfo.src.height = h; + mOVInfo.src_rect.x = 0; + mOVInfo.src_rect.y = 0; + mOVInfo.dst_rect.x = 0; + mOVInfo.dst_rect.y = 0; + mOVInfo.dst_rect.w = w; + mOVInfo.dst_rect.h = h; + if(format == MDP_Y_CRCB_H2V2_TILE) { + if (mNoRot) { + mOVInfo.src_rect.w = w - ( (((w-1)/64 +1)*64) - w); + mOVInfo.src_rect.h = h - ((((h-1)/32 +1)*32) - h); + mOVInfo.src.format = MDP_Y_CRCB_H2V2_TILE; + } else { + mOVInfo.src_rect.w = w; + mOVInfo.src_rect.h = h; + mOVInfo.src.width = (((w-1)/64 +1)*64); + mOVInfo.src.height = (((h-1)/32 +1)*32); + mOVInfo.src_rect.x = mOVInfo.src.width - w; + mOVInfo.src_rect.y = mOVInfo.src.height - h; + mOVInfo.src.format = MDP_Y_CRCB_H2V2; + } + } else { + mOVInfo.src_rect.w = w; + mOVInfo.src_rect.h = h; + mOVInfo.src.format = format; + } + + if (w > mFBWidth) + mOVInfo.dst_rect.w = mFBWidth; + if (h > mFBHeight) + mOVInfo.dst_rect.h = mFBHeight; + mOVInfo.z_order = 0; + mOVInfo.alpha = 0xff; + mOVInfo.transp_mask = 0xffffffff; + mOVInfo.flags = flags; + mOVInfo.is_fg = 0; + mSize = get_size(format, w, h); + return true; +} + +bool OverlayControlChannel::startOVRotatorSessions(int w, int h, + int format) { + bool ret = true; + if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) { + reportError("startOVRotatorSessions, Overlay set failed"); + ret = false; + } + else if (mNoRot) + return true; + + if (ret) { + mRotInfo.src.format = format; + mRotInfo.src.width = w; + mRotInfo.src.height = h; + mRotInfo.src_rect.w = w; + mRotInfo.src_rect.h = h; + mRotInfo.dst.width = w; + mRotInfo.dst.height = h; + if(format == MDP_Y_CRCB_H2V2_TILE) { + mRotInfo.src.width = (((w-1)/64 +1)*64); + mRotInfo.src.height = (((h-1)/32 +1)*32); + mRotInfo.src_rect.w = (((w-1)/64 +1)*64); + mRotInfo.src_rect.h = (((h-1)/32 +1)*32); + mRotInfo.dst.width = (((w-1)/64 +1)*64); + mRotInfo.dst.height = (((h-1)/32 +1)*32); + mRotInfo.dst.format = MDP_Y_CRCB_H2V2; + } else { + mRotInfo.dst.format = format; + } + mRotInfo.dst_x = 0; + mRotInfo.dst_y = 0; + mRotInfo.src_rect.x = 0; + mRotInfo.src_rect.y = 0; + mRotInfo.rotations = 0; + mRotInfo.enable = 0; + mRotInfo.session_id = 0; + int result = ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo); + if (result) { + reportError("Rotator session failed"); + ret = false; + } + else + return ret; + } + + closeControlChannel(); + + return ret; +} + +bool OverlayControlChannel::startControlChannel(int w, int h, + int format, int fbnum, bool norot) { + mNoRot = norot; + fb_fix_screeninfo finfo; + fb_var_screeninfo vinfo; + int hw_format; + int flags = 0; + int colorFormat = format; + if (format & INTERLACE_MASK) { + flags |= MDP_DEINTERLACE; + + // Get the actual format + colorFormat = format ^ HAL_PIXEL_FORMAT_INTERLACE; + } + hw_format = get_mdp_format(colorFormat); + if (hw_format < 0) { + reportError("Unsupported format"); + return false; + } + + if (!openDevices(fbnum)) + return false; + + if (!setOverlayInformation(w, h, hw_format, flags)) + return false; + + return startOVRotatorSessions(w, h, hw_format); +} + +bool OverlayControlChannel::closeControlChannel() { + if (!isChannelUP()) + return true; + + if (!mNoRot && mRotFD > 0) { + ioctl(mRotFD, MSM_ROTATOR_IOCTL_FINISH, &(mRotInfo.session_id)); + close(mRotFD); + mRotFD = -1; + } + + int ovid = mOVInfo.id; + int ret = ioctl(mFD, MSMFB_OVERLAY_UNSET, &ovid); + close(mFD); + memset(&mOVInfo, 0, sizeof(mOVInfo)); + memset(&mRotInfo, 0, sizeof(mRotInfo)); + mFD = -1; + + return true; +} + +bool OverlayControlChannel::setSource(uint32_t w, uint32_t h, int format, int orientation) { + format = get_mdp_format(format); + if ((orientation == mOrientation) && ((orientation == MDP_ROT_90) + || (orientation == MDP_ROT_270))) { + if (format == MDP_Y_CRCB_H2V2_TILE) { + format = MDP_Y_CRCB_H2V2; + w = (((w-1)/64 +1)*64); + h = (((h-1)/32 +1)*32); + } + int tmp = w; + w = h; + h = tmp; + } + if (w == mOVInfo.src.width && h == mOVInfo.src.height + && format == mOVInfo.src.format && orientation == mOrientation) + return true; + mOrientation = orientation; + return false; +} + +bool OverlayControlChannel::setPosition(int x, int y, uint32_t w, uint32_t h) { + + int width = w, height = h; + if (!isChannelUP() || + (x < 0) || (y < 0) || ((x + w) > mFBWidth) || + ((y + h) > mFBHeight)) { + reportError("setPosition failed"); + return false; + } + + mdp_overlay ov; + ov.id = mOVInfo.id; + if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { + reportError("setPosition, overlay GET failed"); + return false; + } + + /* Scaling of upto a max of 8 times supported */ + if(w >(ov.src_rect.w * HW_OVERLAY_MAGNIFICATION_LIMIT)){ + w = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.w; + } + if(h >(ov.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) { + h = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.h; + } + ov.dst_rect.x = x; + ov.dst_rect.y = y; + ov.dst_rect.w = w; + ov.dst_rect.h = h; + + if (ioctl(mFD, MSMFB_OVERLAY_SET, &ov)) { + reportError("setPosition, Overlay SET failed"); + return false; + } + mOVInfo = ov; + + return true; +} + +void OverlayControlChannel::swapOVRotWidthHeight() { + int tmp = mOVInfo.src.width; + mOVInfo.src.width = mOVInfo.src.height; + mOVInfo.src.height = tmp; + + tmp = mOVInfo.src_rect.h; + mOVInfo.src_rect.h = mOVInfo.src_rect.w; + mOVInfo.src_rect.w = tmp; + + tmp = mRotInfo.dst.width; + mRotInfo.dst.width = mRotInfo.dst.height; + mRotInfo.dst.height = tmp; +} + +bool OverlayControlChannel::setParameter(int param, int value) { + if (!isChannelUP()) + return false; + + mdp_overlay ov; + ov.id = mOVInfo.id; + if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { + reportError("setParameter, overlay GET failed"); + return false; + } + mOVInfo = ov; + + switch (param) { + case OVERLAY_DITHER: + break; + case OVERLAY_TRANSFORM: + { + int val = mOVInfo.user_data[0]; + if (value && mNoRot) + return true; + + switch(value) { + case 0: + { + if (val == MDP_ROT_90) { + int tmp = mOVInfo.src_rect.y; + mOVInfo.src_rect.y = mOVInfo.src.width - + (mOVInfo.src_rect.x + mOVInfo.src_rect.w); + mOVInfo.src_rect.x = tmp; + swapOVRotWidthHeight(); + } + else if (val == MDP_ROT_270) { + int tmp = mOVInfo.src_rect.x; + mOVInfo.src_rect.x = mOVInfo.src.height - ( + mOVInfo.src_rect.y + mOVInfo.src_rect.h); + mOVInfo.src_rect.y = tmp; + swapOVRotWidthHeight(); + } + mOVInfo.user_data[0] = MDP_ROT_NOP; + break; + } + case OVERLAY_TRANSFORM_ROT_90: + { + if (val == MDP_ROT_270) { + mOVInfo.src_rect.x = mOVInfo.src.width - ( + mOVInfo.src_rect.x + mOVInfo.src_rect.w); + mOVInfo.src_rect.y = mOVInfo.src.height - ( + mOVInfo.src_rect.y + mOVInfo.src_rect.h); + } + else if (val == MDP_ROT_NOP || val == MDP_ROT_180) { + int tmp = mOVInfo.src_rect.x; + mOVInfo.src_rect.x = mOVInfo.src.height - + (mOVInfo.src_rect.y + mOVInfo.src_rect.h); + mOVInfo.src_rect.y = tmp; + swapOVRotWidthHeight(); + } + mOVInfo.user_data[0] = MDP_ROT_90; + break; + } + case OVERLAY_TRANSFORM_ROT_180: + { + if (val == MDP_ROT_270) { + int tmp = mOVInfo.src_rect.y; + mOVInfo.src_rect.y = mOVInfo.src.width - + (mOVInfo.src_rect.x + mOVInfo.src_rect.w); + mOVInfo.src_rect.x = tmp; + swapOVRotWidthHeight(); + } + else if (val == MDP_ROT_90) { + int tmp = mOVInfo.src_rect.x; + mOVInfo.src_rect.x = mOVInfo.src.height - ( + mOVInfo.src_rect.y + mOVInfo.src_rect.h); + mOVInfo.src_rect.y = tmp; + swapOVRotWidthHeight(); + } + mOVInfo.user_data[0] = MDP_ROT_180; + break; + } + case OVERLAY_TRANSFORM_ROT_270: + { + if (val == MDP_ROT_90) { + mOVInfo.src_rect.y = mOVInfo.src.height - + (mOVInfo.src_rect.y + mOVInfo.src_rect.h); + mOVInfo.src_rect.x = mOVInfo.src.width - + (mOVInfo.src_rect.x + mOVInfo.src_rect.w); + } + else if (val == MDP_ROT_NOP || val == MDP_ROT_180) { + int tmp = mOVInfo.src_rect.y; + mOVInfo.src_rect.y = mOVInfo.src.width - ( + mOVInfo.src_rect.x + mOVInfo.src_rect.w); + mOVInfo.src_rect.x = tmp; + swapOVRotWidthHeight(); + } + + mOVInfo.user_data[0] = MDP_ROT_270; + break; + } + default: return false; + } + mRotInfo.rotations = mOVInfo.user_data[0]; + if (mOVInfo.user_data[0]) + mRotInfo.enable = 1; + else { + if(mRotInfo.src.format == MDP_Y_CRCB_H2V2_TILE) + mOVInfo.src.format = MDP_Y_CRCB_H2V2_TILE; + mRotInfo.enable = 0; + } + if (ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo)) { + reportError("setParameter, rotator start failed"); + return false; + } + + if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) { + reportError("setParameter, overlay set failed"); + return false; + } + break; + } + default: + reportError("Unsupproted param"); + return false; + } + + return true; +} + +bool OverlayControlChannel::getPosition(int& x, int& y, + uint32_t& w, uint32_t& h) { + if (!isChannelUP()) + return false; + + mdp_overlay ov; + ov.id = mOVInfo.id; + if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { + reportError("getPosition, overlay GET failed"); + return false; + } + mOVInfo = ov; + + x = mOVInfo.dst_rect.x; + y = mOVInfo.dst_rect.y; + w = mOVInfo.dst_rect.w; + h = mOVInfo.dst_rect.h; + + return true; +} + +bool OverlayControlChannel::getOrientation(int& orientation) const { + if (!isChannelUP()) + return false; + + mdp_overlay ov; + ov.id = mOVInfo.id; + if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { + reportError("getOrientation, overlay GET failed"); + return false; + } + orientation = ov.user_data[0]; + return true; +} +bool OverlayControlChannel::getOvSessionID(int& sessionID) const { + if (!isChannelUP()) + return false; + sessionID = mOVInfo.id; + return true; +} + +bool OverlayControlChannel::getRotSessionID(int& sessionID) const { + if (!isChannelUP()) + return false; + sessionID = mRotInfo.session_id; + return true; +} + +bool OverlayControlChannel::getSize(int& size) const { + if (!isChannelUP()) + return false; + size = mSize; + return true; +} + +OverlayDataChannel::OverlayDataChannel() : mNoRot(false), mFD(-1), mRotFD(-1), + mPmemFD(-1), mPmemAddr(0) { +} + +OverlayDataChannel::~OverlayDataChannel() { + closeDataChannel(); +} + +bool OverlayDataChannel::startDataChannel( + const OverlayControlChannel& objOvCtrlChannel, + int fbnum, bool norot, bool uichannel) { + int ovid, rotid, size; + mNoRot = norot; + memset(&mOvData, 0, sizeof(mOvData)); + memset(&mOvDataRot, 0, sizeof(mOvDataRot)); + memset(&mRotData, 0, sizeof(mRotData)); + if (objOvCtrlChannel.getOvSessionID(ovid) && + objOvCtrlChannel.getRotSessionID(rotid) && + objOvCtrlChannel.getSize(size)) { + return startDataChannel(ovid, rotid, size, fbnum, norot, uichannel); + } + else + return false; +} + +bool OverlayDataChannel::openDevices(int fbnum, bool uichannel) { + if (fbnum < 0) + return false; + char const * const device_template = + "/dev/graphics/fb%u"; + char dev_name[64]; + snprintf(dev_name, 64, device_template, fbnum); + + mFD = open(dev_name, O_RDWR, 0); + if (mFD < 0) { + reportError("Cant open framebuffer "); + return false; + } + if (!mNoRot) { + mRotFD = open("/dev/msm_rotator", O_RDWR, 0); + if (mRotFD < 0) { + reportError("Cant open rotator device"); + close(mFD); + mFD = -1; + return false; + } + + mPmemAddr = MAP_FAILED; + + if(!uichannel) { + mPmemFD = open("/dev/pmem_smipool", O_RDWR | O_SYNC); + if(mPmemFD >= 0) + mPmemAddr = (void *) mmap(NULL, mPmemOffset * 2, PROT_READ | PROT_WRITE, + MAP_SHARED, mPmemFD, 0); + } + + if (mPmemAddr == MAP_FAILED) { + mPmemFD = open("/dev/pmem_adsp", O_RDWR | O_SYNC); + if (mPmemFD < 0) { + reportError("Cant open pmem_adsp "); + close(mFD); + mFD = -1; + close(mRotFD); + mRotFD = -1; + return false; + } else { + mPmemAddr = (void *) mmap(NULL, mPmemOffset * 2, PROT_READ | PROT_WRITE, + MAP_SHARED, mPmemFD, 0); + if (mPmemAddr == MAP_FAILED) { + reportError("Cant map pmem_adsp "); + close(mFD); + mFD = -1; + close(mPmemFD); + mPmemFD = -1; + close(mRotFD); + mRotFD = -1; + return false; + } + } + } + + mOvDataRot.data.memory_id = mPmemFD; + mRotData.dst.memory_id = mPmemFD; + mRotData.dst.offset = 0; + } + + return true; +} + +bool OverlayDataChannel::startDataChannel(int ovid, int rotid, int size, + int fbnum, bool norot, bool uichannel) { + memset(&mOvData, 0, sizeof(mOvData)); + memset(&mOvDataRot, 0, sizeof(mOvDataRot)); + memset(&mRotData, 0, sizeof(mRotData)); + mNoRot = norot; + mOvData.data.memory_id = -1; + mOvData.id = ovid; + mOvDataRot = mOvData; + mPmemOffset = size; + mRotData.session_id = rotid; + + return openDevices(fbnum, uichannel); +} + +bool OverlayDataChannel::closeDataChannel() { + if (!isChannelUP()) + return true; + + if (!mNoRot && mRotFD > 0) { + munmap(mPmemAddr, mPmemOffset * 2); + close(mPmemFD); + mPmemFD = -1; + close(mRotFD); + mRotFD = -1; + } + close(mFD); + mFD = -1; + memset(&mOvData, 0, sizeof(mOvData)); + memset(&mOvDataRot, 0, sizeof(mOvDataRot)); + memset(&mRotData, 0, sizeof(mRotData)); + + return true; +} + +bool OverlayDataChannel::setFd(int fd) { + mOvData.data.memory_id = fd; + return true; +} + +bool OverlayDataChannel::queueBuffer(uint32_t offset) { + if ((!isChannelUP()) || mOvData.data.memory_id < 0) { + reportError("QueueBuffer failed, either channel is not set or no file descriptor to read from"); + return false; + } + + msmfb_overlay_data *odPtr; + mOvData.data.offset = offset; + odPtr = &mOvData; + + if (!mNoRot) { + mRotData.src.memory_id = mOvData.data.memory_id; + mRotData.src.offset = offset; + mRotData.dst.offset = (mRotData.dst.offset) ? 0 : mPmemOffset; + + int result = ioctl(mRotFD, + MSM_ROTATOR_IOCTL_ROTATE, &mRotData); + + if (!result) { + mOvDataRot.data.offset = (uint32_t) mRotData.dst.offset; + odPtr = &mOvDataRot; + } + } + + if (ioctl(mFD, MSMFB_OVERLAY_PLAY, odPtr)) { + reportError("overlay play failed."); + return false; + } + + return true; +} + +bool OverlayDataChannel::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { + if (!isChannelUP()) { + reportError("Channel not set"); + return false; + } + + mdp_overlay ov; + ov.id = mOvData.id; + if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { + reportError("setCrop, overlay GET failed"); + return false; + } + + if (ov.user_data[0] == MDP_ROT_90) { + int tmp = x; + x = ov.src.width - (y + h); + y = tmp; + + tmp = w; + w = h; + h = tmp; + } + else if (ov.user_data[0] == MDP_ROT_270) { + int tmp = y; + y = ov.src.height - (x + w); + x = tmp; + + tmp = w; + w = h; + h = tmp; + } + + if ((ov.src_rect.x == x) && + (ov.src_rect.y == y) && + (ov.src_rect.w == w) && + (ov.src_rect.h == h)) + return true; + if ( (int) x < 0 || (int) y < 0 || (int) w < 0 || (int) h < 0){ + LOGE("%s: invalid value for crop: x=%d,y=%d,w=%d,h=%d",__func__,x,y,w,h); + return false; + } + + ov.src_rect.x = x; + ov.src_rect.y = y; + ov.src_rect.w = w; + ov.src_rect.h = h; + + /* Scaling of upto a max of 8 times supported */ + if(ov.dst_rect.w >(ov.src_rect.w * HW_OVERLAY_MAGNIFICATION_LIMIT)){ + ov.dst_rect.w = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.w; + } + if(ov.dst_rect.h >(ov.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) { + ov.dst_rect.h = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.h; + } + if (ioctl(mFD, MSMFB_OVERLAY_SET, &ov)) { + reportError("setCrop, overlay set error"); + return false; + } + + return true; +} diff --git a/liboverlay/overlayLib.h b/liboverlay/overlayLib.h new file mode 100644 index 0000000..f5b4279 --- /dev/null +++ b/liboverlay/overlayLib.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_OVERLAY_LIB +#define INCLUDE_OVERLAY_LIB + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define HW_OVERLAY_MAGNIFICATION_LIMIT 8 +#define HW_OVERLAY_MINIFICATION_LIMIT HW_OVERLAY_MAGNIFICATION_LIMIT + +namespace overlay { + +class OverlayControlChannel { + + bool mNoRot; + + int mFBWidth; + int mFBHeight; + int mFBbpp; + int mFBystride; + + int mFD; + int mRotFD; + int mSize; + int mOrientation; + mdp_overlay mOVInfo; + msm_rotator_img_info mRotInfo; + bool openDevices(int fbnum = -1); + bool setOverlayInformation(int w, int h, int format, int flags); + bool startOVRotatorSessions(int w, int h, int format); + void swapOVRotWidthHeight(); + +public: + OverlayControlChannel(); + ~OverlayControlChannel(); + bool startControlChannel(int w, int h, int format, + int fbnum, bool norot = false); + bool closeControlChannel(); + bool setPosition(int x, int y, uint32_t w, uint32_t h); + bool setParameter(int param, int value); + bool getPosition(int& x, int& y, uint32_t& w, uint32_t& h); + bool getOvSessionID(int& sessionID) const; + bool getRotSessionID(int& sessionID) const; + bool getSize(int& size) const; + bool isChannelUP() const { return (mFD > 0); } + int getFBWidth() const { return mFBWidth; } + int getFBHeight() const { return mFBHeight; } + bool getOrientation(int& orientation) const; + bool setSource(uint32_t w, uint32_t h, int format, int orientation); +}; + +class OverlayDataChannel { + + bool mNoRot; + int mFD; + int mRotFD; + int mPmemFD; + void* mPmemAddr; + uint32_t mPmemOffset; + msmfb_overlay_data mOvData; + msmfb_overlay_data mOvDataRot; + msm_rotator_data_info mRotData; + + bool openDevices(int fbnum = -1, bool uichannel = false); + +public: + OverlayDataChannel(); + ~OverlayDataChannel(); + bool startDataChannel(const OverlayControlChannel& objOvCtrlChannel, + int fbnum, bool norot = false, bool uichannel = false); + bool startDataChannel(int ovid, int rotid, int size, + int fbnum, bool norot = false, bool uichannel = false); + bool closeDataChannel(); + bool setFd(int fd); + bool queueBuffer(uint32_t offset); + bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h); + bool isChannelUP() const { return (mFD > 0); } +}; + +/* + * Overlay class for single thread application + * A multiple thread/process application need to use Overlay HAL + */ +class Overlay { + + bool mChannelUP; + + OverlayControlChannel objOvCtrlChannel; + OverlayDataChannel objOvDataChannel; + +public: + Overlay(); + ~Overlay(); + + bool startChannel(int w, int h, int format, int fbnum, bool norot = false, bool uichannel = false); + bool closeChannel(); + bool setPosition(int x, int y, uint32_t w, uint32_t h); + bool setParameter(int param, int value); + bool setOrientation(int value); + bool setFd(int fd); + bool queueBuffer(uint32_t offset); + bool getPosition(int& x, int& y, uint32_t& w, uint32_t& h); + bool isChannelUP() const { return mChannelUP; } + int getFBWidth() const; + int getFBHeight() const; + bool getOrientation(int& orientation) const; + bool queueBuffer(buffer_handle_t buffer); + bool setSource(uint32_t w, uint32_t h, int format, int orientation); + bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h); +}; + +struct overlay_shared_data { + int readyToQueue; +}; + +}; +#endif