diff --git a/Android.mk b/Android.mk index d497619..838af1e 100644 --- a/Android.mk +++ b/Android.mk @@ -1,70 +1,7 @@ -# 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. +# Build only new gralloc + ifeq ($(TARGET_USES_ION),true) -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 libGLESv1_CM libutils - -LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include -LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr -LOCAL_SRC_FILES := \ - allocator.cpp \ - framebuffer.cpp \ - gpu.cpp \ - gralloc.cpp \ - mapper.cpp \ - pmemalloc.cpp - -LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM) -LOCAL_MODULE_TAGS := optional -LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" -DHOST -DDEBUG_CALC_FPS - -ifeq ($(call is-board-platform,msm7627_surf msm7627_6x),true) -LOCAL_CFLAGS += -DTARGET_MSM7x27 + display-hals := libgralloc + include $(call all-named-subdir-makefiles,$(display-hals)) endif -ifeq ($(TARGET_HAVE_HDMI_OUT),true) -LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY -LOCAL_C_INCLUDES += $(LOCAL_PATH)/../liboverlay -LOCAL_SHARED_LIBRARIES += liboverlay -endif - -ifeq ($(TARGET_USES_SF_BYPASS),true) -LOCAL_CFLAGS += -DSF_BYPASS -endif - -ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true) -LOCAL_CFLAGS += -DUSE_ASHMEM -endif -include $(BUILD_SHARED_LIBRARY) - - -# Build a host library for testing -ifeq ($(HOST_OS),linux) -include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - gpu.cpp \ - pmemalloc.cpp - -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE := libgralloc_qsd8k_host -LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc-qsd8k\" -include $(BUILD_HOST_STATIC_LIBRARY) -endif -endif diff --git a/gpu.cpp b/gpu.cpp deleted file mode 100644 index e3d7a6c..0000000 --- a/gpu.cpp +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (C) 2010 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 - -#ifdef HOST -#include -#endif - -#include "gr.h" -#include "gpu.h" - -gpu_context_t::gpu_context_t(Deps& deps, PmemAllocator& pmemAllocator, - PmemAllocator& pmemAdspAllocator, const private_module_t* module) : - deps(deps), - pmemAllocator(pmemAllocator), - pmemAdspAllocator(pmemAdspAllocator), - isMDPComposition(false) -{ - // Zero out the alloc_device_t - memset(static_cast(this), 0, sizeof(alloc_device_t)); - - // Initialize the procs - common.tag = HARDWARE_DEVICE_TAG; - common.version = 0; - common.module = const_cast(&module->base.common); - common.close = gralloc_close; - alloc = gralloc_alloc; - free = gralloc_free; - - char property[PROPERTY_VALUE_MAX]; - if((property_get("debug.composition.type", property, NULL) > 0) && - (strncmp(property, "mdp", 3) == 0)) - isMDPComposition = true; -} - -int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage, - buffer_handle_t* pHandle) -{ - private_module_t* m = reinterpret_cast(common.module); - - // we don't support allocations with both the FB and PMEM_ADSP flags - if (usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) { - return -EINVAL; - } - - // allocate the framebuffer - if (m->framebuffer == NULL) { - // initialize the framebuffer, the framebuffer is mapped once - // and forever. - int err = deps.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(bufferSize, newUsage, pHandle); - } - - if (bufferMask >= ((1LU<framebuffer->base); - private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), bufferSize, - 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; -} - - -int gpu_context_t::gralloc_alloc_framebuffer(size_t size, int usage, - buffer_handle_t* pHandle) -{ - private_module_t* m = reinterpret_cast(common.module); - pthread_mutex_lock(&m->lock); - int err = gralloc_alloc_framebuffer_locked(size, usage, pHandle); - pthread_mutex_unlock(&m->lock); - return err; -} - -int gpu_context_t::alloc_ashmem_buffer(size_t size, unsigned int postfix, void** pBase, - int* pOffset, int* pFd) -{ - int err = 0; - int fd = -1; - void* base = 0; - int offset = 0; - - char name[ASHMEM_NAME_LEN]; - snprintf(name, ASHMEM_NAME_LEN, "gralloc-buffer-%x", postfix); - int prot = PROT_READ | PROT_WRITE; - fd = ashmem_create_region(name, size); - if (fd < 0) { - LOGE("couldn't create ashmem (%s)", strerror(errno)); - err = -errno; - } else { - if (ashmem_set_prot_region(fd, prot) < 0) { - LOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)", - fd, prot, strerror(errno)); - close(fd); - err = -errno; - } else { - base = mmap(0, size, prot, MAP_SHARED|MAP_POPULATE|MAP_LOCKED, fd, 0); - if (base == MAP_FAILED) { - LOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)", - fd, size, prot, strerror(errno)); - close(fd); - err = -errno; - } else { - memset((char*)base + offset, 0, size); - } - } - } - if(err == 0) { - *pFd = fd; - *pBase = base; - *pOffset = offset; -#ifdef HOST - if (ioctl(fd, ASHMEM_CACHE_INV_RANGE, NULL)) { - LOGE("ASHMEM_CACHE_INV_RANGE failed fd = %d", fd); - } -#endif - } - return err; -} - -int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* pHandle) -{ - int err = 0; - int flags = 0; - - int fd = -1; - void* base = 0; // XXX JMG: This should change to just get an address from - // the PmemAllocator rather than getting the base & offset separately - int offset = 0; - int lockState = 0; - - size = roundUpToPageSize(size); -#ifndef USE_ASHMEM - 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; - } -#else - if (usage & GRALLOC_USAGE_PRIVATE_EBI_HEAP){ - flags |= private_handle_t::PRIV_FLAGS_USES_PMEM; - } - - // Enable use of PMEM only when MDP composition is used (and other conditions apply). - // Else fall back on using ASHMEM - if (isMDPComposition && - ((usage & GRALLOC_USAGE_HW_TEXTURE) || (usage & GRALLOC_USAGE_HW_2D)) ) { - flags |= private_handle_t::PRIV_FLAGS_USES_PMEM; - } -#endif - if (usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) { - flags |= private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP; - flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM; - } - - private_module_t* m = reinterpret_cast(common.module); - if((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) == 0 && - (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) == 0) { - flags |= private_handle_t::PRIV_FLAGS_USES_ASHMEM; - err = alloc_ashmem_buffer(size, (unsigned int)pHandle, &base, &offset, &fd); - if(err >= 0) - lockState |= private_handle_t::LOCK_STATE_MAPPED; - } - else if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0 || - (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0) { - - PmemAllocator* pma = 0; - - if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0) { - if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0) { - LOGE("attempting to allocate a gralloc buffer with both the " - "USES_PMEM and USES_PMEM_ADSP flags. Unsetting the " - "USES_PMEM_ADSP flag."); - flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP; - } - pma = &pmemAllocator; - } else { // (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0 - pma = &pmemAdspAllocator; - } - - // PMEM buffers are always mmapped - lockState |= private_handle_t::LOCK_STATE_MAPPED; - - // Allocate the buffer from pmem - err = pma->alloc_pmem_buffer(size, usage, &base, &offset, &fd); - if (err < 0) { - if (((usage & GRALLOC_USAGE_PRIVATE_EBI_HEAP) == 0) && - ((usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) == 0) && - !isMDPComposition) { - // the caller didn't request PMEM, so we can try something else - flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM; - err = 0; - LOGE("Pmem allocation failed. Trying ashmem"); - goto try_ashmem; - } else { - LOGE("couldn't open pmem (%s)", strerror(errno)); - } - } - } else { -try_ashmem: - err = alloc_ashmem_buffer(size, (unsigned int)pHandle, &base, &offset, &fd); - if (err >= 0) { - lockState |= private_handle_t::LOCK_STATE_MAPPED; - flags |= private_handle_t::PRIV_FLAGS_USES_ASHMEM; - } else { - LOGE("Ashmem fallback failed"); - } - } - - 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 inline size_t ALIGN(size_t x, size_t align) { - return (x + align-1) & ~(align-1); -} - -int gpu_context_t::alloc_impl(int w, int h, int format, int usage, - buffer_handle_t* pHandle, int* pStride) { - if (!pHandle || !pStride) - return -EINVAL; - - size_t size, alignedw, alignedh; - - alignedw = ALIGN(w, 32); - alignedh = ALIGN(h, 32); - switch (format) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - case HAL_PIXEL_FORMAT_BGRA_8888: - size = alignedw * alignedh * 4; - break; - case HAL_PIXEL_FORMAT_RGB_888: - size = alignedw * alignedh * 3; - break; - case HAL_PIXEL_FORMAT_RGB_565: - case HAL_PIXEL_FORMAT_RGBA_5551: - case HAL_PIXEL_FORMAT_RGBA_4444: - size = alignedw * alignedh * 2; - break; - - // adreno formats - case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: // NV21 - size = ALIGN(alignedw*alignedh, 4096); - size += ALIGN(2 * ALIGN(w/2, 32) * ALIGN(h/2, 32), 4096); - break; - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: // NV12 - // The chroma plane is subsampled, - // but the pitch in bytes is unchanged - // The GPU needs 4K alignment, but the video decoder needs 8K - alignedw = ALIGN(w, 128); - size = ALIGN( alignedw * alignedh, 8192); - size += ALIGN( alignedw * ALIGN(h/2, 32), 4096); - break; - - case HAL_PIXEL_FORMAT_YV12: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - if ((w&1) || (h&1)) { - LOGE("w or h is odd for HAL_PIXEL_FORMAT_YV12"); - return -EINVAL; - } - alignedw = ALIGN(w, 16); - alignedh = h; - size = alignedw*alignedh + - (ALIGN(alignedw/2, 16) * (alignedh/2))*2; - break; - - default: - LOGE("unrecognized pixel format: %d", format); - return -EINVAL; - } - - if ((ssize_t)size <= 0) - return -EINVAL; - - int err; - if (usage & GRALLOC_USAGE_HW_FB) { - err = gralloc_alloc_framebuffer(size, usage, pHandle); - } else { - err = gralloc_alloc_buffer(size, usage, pHandle); - } - - if (err < 0) { - return err; - } - - *pStride = alignedw; - return 0; -} - -int gpu_context_t::free_impl(private_handle_t const* hnd) { - private_module_t* m = reinterpret_cast(common.module); - if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { - // free this buffer - 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) { - pmem_allocator = &pmemAllocator; - } else if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) { - pmem_allocator = &pmemAdspAllocator; - } else if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) { - // free ashmem - if (hnd->fd >= 0) { - if (hnd->base) { - int err = munmap((void*)hnd->base, hnd->size); - LOGE_IF(err<0, "ASHMEM_UNMAP failed (%s), " - "fd=%d, sub.offset=%d, sub.size=%d", - strerror(errno), hnd->fd, hnd->offset, hnd->size); - } - } - } - if (pmem_allocator) { - pmem_allocator->free_pmem_buffer(hnd->size, (void*)hnd->base, - hnd->offset, hnd->fd); - } - deps.terminateBuffer(&m->base, const_cast(hnd)); - } - - deps.close(hnd->fd); - delete hnd; // XXX JMG: move this to the deps - return 0; -} - -/****************************************************************************** - * Static functions - *****************************************************************************/ - -int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format, - int usage, buffer_handle_t* pHandle, int* pStride) -{ - if (!dev) { - return -EINVAL; - } - gpu_context_t* gpu = reinterpret_cast(dev); - return gpu->alloc_impl(w, h, format, usage, pHandle, pStride); -} - -int gpu_context_t::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); - gpu_context_t* gpu = reinterpret_cast(dev); - return gpu->free_impl(hnd); -} - -/*****************************************************************************/ - -int gpu_context_t::gralloc_close(struct hw_device_t *dev) -{ - gpu_context_t* ctx = reinterpret_cast(dev); - if (ctx) { - /* TODO: keep a list of all buffer_handle_t created, and free them - * all here. - */ - delete ctx; - } - return 0; -} - - -gpu_context_t::Deps::~Deps() {} diff --git a/gpu.h b/gpu.h deleted file mode 100644 index 9833d60..0000000 --- a/gpu.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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_QSD8K_GPU_H_ -#define GRALLOC_QSD8K_GPU_H_ - -#include -#include -#include -#include - -#include -#include - -#include "gralloc_priv.h" -#include "pmemalloc.h" - - -class gpu_context_t : public alloc_device_t { - public: - - class Deps { - public: - - virtual ~Deps(); - - // ashmem - virtual int ashmem_create_region(const char *name, size_t size) = 0; - - // POSIX - virtual int close(int fd) = 0; - - // Framebuffer (locally defined) - virtual int mapFrameBufferLocked(struct private_module_t* module) = 0; - virtual int terminateBuffer(gralloc_module_t const* module, - private_handle_t* hnd) = 0; - }; - - gpu_context_t(Deps& deps, PmemAllocator& pmemAllocator, - PmemAllocator& pmemAdspAllocator, const private_module_t* module); - - int gralloc_alloc_framebuffer_locked(size_t size, int usage, - buffer_handle_t* pHandle); - int gralloc_alloc_framebuffer(size_t size, int usage, - buffer_handle_t* pHandle); - int gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* pHandle); - int free_impl(private_handle_t const* hnd); - int alloc_impl(int w, int h, int format, int usage, - buffer_handle_t* pHandle, int* pStride); - - static int gralloc_alloc(alloc_device_t* dev, int w, int h, int format, - int usage, buffer_handle_t* pHandle, int* pStride); - static int gralloc_free(alloc_device_t* dev, buffer_handle_t handle); - static int gralloc_close(struct hw_device_t *dev); - - private: - - Deps& deps; - PmemAllocator& pmemAllocator; - PmemAllocator& pmemAdspAllocator; - bool isMDPComposition; - int alloc_ashmem_buffer(size_t size, unsigned int postfix, void** pBase, - int* pOffset, int* pFd); -}; - -#endif // GRALLOC_QSD8K_GPU_H diff --git a/gralloc.cpp b/gralloc.cpp deleted file mode 100644 index 0d1ac2f..0000000 --- a/gralloc.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * 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 "allocator.h" -#include "gr.h" -#include "gpu.h" - -/*****************************************************************************/ - -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); - -extern int gralloc_perform(struct gralloc_module_t const* module, - int operation, ... ); - -/*****************************************************************************/ - -/* On-device dependency implementation */ -class PmemAllocatorDepsDeviceImpl : public PmemUserspaceAllocator::Deps, - public PmemKernelAllocator::Deps { - - const private_module_t* module; - - virtual size_t getPmemTotalSize(int fd, size_t* size) { - int err = 0; -#ifndef TARGET_MSM7x27 - pmem_region region; - err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®ion); - if (err == 0) { - *size = region.len; - } -#else -#ifdef USE_ASHMEM - char property[PROPERTY_VALUE_MAX]; - bool isMDPComposition = false; - if((property_get("debug.composition.type", property, NULL) > 0) && - (strncmp(property, "mdp", 3) == 0)) - isMDPComposition = true; - - if (isMDPComposition) { - *size = 23<<20; //23MB for 7x27 - } else { - if(module != NULL) - *size = module->info.xres * module->info.yres * 2 * 2; - else - return -ENOMEM; - } -#else - *size = 23<<20; //23MB for 7x27 -#endif -#endif - return err; - } - - virtual int connectPmem(int fd, int master_fd) { - return ioctl(fd, PMEM_CONNECT, master_fd); - } - - virtual int mapPmem(int fd, int offset, size_t size) { - struct pmem_region sub = { offset, size }; - return ioctl(fd, PMEM_MAP, &sub); - } - - virtual int unmapPmem(int fd, int offset, size_t size) { - struct pmem_region sub = { offset, size }; - return ioctl(fd, PMEM_UNMAP, &sub); - } - - virtual int cleanPmem(int fd, unsigned long base, int offset, size_t size) { - struct pmem_addr pmem_addr; - pmem_addr.vaddr = base; - pmem_addr.offset = offset; - pmem_addr.length = size; - return ioctl(fd, PMEM_CLEAN_INV_CACHES, &pmem_addr); - } - - virtual int getErrno() { - return errno; - } - - virtual void* mmap(void* start, size_t length, int prot, int flags, int fd, - off_t offset) { - return ::mmap(start, length, prot, flags, fd, offset); - } - - virtual int munmap(void* start, size_t length) { - return ::munmap(start, length); - } - - virtual int open(const char* pathname, int flags, int mode) { - return ::open(pathname, flags, mode); - } - - virtual int close(int fd) { - return ::close(fd); - } - -public: - void setModule(const private_module_t* m) { - module = m; - } - -}; - -class GpuContextDepsDeviceImpl : public gpu_context_t::Deps { - - public: - - virtual int ashmem_create_region(const char *name, size_t size) { - return ::ashmem_create_region(name, size); - } - - virtual int mapFrameBufferLocked(struct private_module_t* module) { - return ::mapFrameBufferLocked(module); - } - - virtual int terminateBuffer(gralloc_module_t const* module, - private_handle_t* hnd) { - return ::terminateBuffer(module, hnd); - } - - virtual int close(int fd) { - return ::close(fd); - } -}; - -static PmemAllocatorDepsDeviceImpl pmemAllocatorDeviceDepsImpl; -static GpuContextDepsDeviceImpl gpuContextDeviceDepsImpl; - -/*****************************************************************************/ - -static SimpleBestFitAllocator pmemAllocMgr; -static PmemUserspaceAllocator pmemAllocator(pmemAllocatorDeviceDepsImpl, pmemAllocMgr, - "/dev/pmem"); - -static PmemKernelAllocator pmemAdspAllocator(pmemAllocatorDeviceDepsImpl, - "/dev/pmem_adsp"); - -/*****************************************************************************/ - -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, - perform: gralloc_perform, - }, - framebuffer: 0, - fbFormat: 0, - flags: 0, - numBuffers: 0, - bufferMask: 0, - lock: PTHREAD_MUTEX_INITIALIZER, - currentBuffer: 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)) { - const private_module_t* m = reinterpret_cast( - module); - pmemAllocatorDeviceDepsImpl.setModule(m); - gpu_context_t *dev; - dev = new gpu_context_t(gpuContextDeviceDepsImpl, pmemAllocator, - pmemAdspAllocator, m); - *device = &dev->common; - status = 0; - } else { - status = fb_device_open(module, name, device); - } - return status; -} diff --git a/libcopybit/Android.mk b/libcopybit/Android.mk new file mode 100644 index 0000000..9e425e0 --- /dev/null +++ b/libcopybit/Android.mk @@ -0,0 +1,73 @@ +# 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 + +ifeq ($(TARGET_USES_C2D_COMPOSITION),true) + include $(CLEAR_VARS) + LOCAL_PRELINK_MODULE := false + LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + LOCAL_SHARED_LIBRARIES := liblog libdl + LOCAL_SRC_FILES := copybit_c2d.cpp + LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM) + LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + LOCAL_C_INCLUDES += hardware/msm7k/libgralloc-qsd8k + LOCAL_CFLAGS += -DCOPYBIT_Z180=1 -DC2D_SUPPORT_DISPLAY=1 + include $(BUILD_SHARED_LIBRARY) +else + ifneq "$(findstring msm7630,$(TARGET_PRODUCT))" "msm7630" + ifeq ($(TARGET_BOARD_PLATFORM),msm7k) + include $(CLEAR_VARS) + ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true) + LOCAL_CFLAGS += -DUSE_ASHMEM + ifeq "$(findstring msm7627,$(TARGET_PRODUCT))" "msm7627" + LOCAL_CFLAGS += -DTARGET_7x27 + endif + endif + + LOCAL_PRELINK_MODULE := false + LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + LOCAL_SHARED_LIBRARIES := liblog + LOCAL_SRC_FILES := copybit.cpp + LOCAL_MODULE := copybit.msm7k + LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + LOCAL_C_INCLUDES += hardware/msm7k/libgralloc-qsd8k + LOCAL_CFLAGS += -DCOPYBIT_MSM7K=1 + include $(BUILD_SHARED_LIBRARY) + endif + + ifeq ($(TARGET_BOARD_PLATFORM),qsd8k) + include $(CLEAR_VARS) + ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true) + LOCAL_CFLAGS += -DUSE_ASHMEM + endif + + LOCAL_PRELINK_MODULE := false + LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + LOCAL_SHARED_LIBRARIES := liblog + LOCAL_SRC_FILES := copybit.cpp + LOCAL_MODULE := copybit.qsd8k + LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + LOCAL_C_INCLUDES += hardware/msm7k/libgralloc-qsd8k + LOCAL_CFLAGS += -DCOPYBIT_QSD8K=1 + include $(BUILD_SHARED_LIBRARY) + endif + endif +endif diff --git a/MODULE_LICENSE_APACHE2 b/libcopybit/MODULE_LICENSE_APACHE2 similarity index 100% rename from MODULE_LICENSE_APACHE2 rename to libcopybit/MODULE_LICENSE_APACHE2 diff --git a/libcopybit/NOTICE b/libcopybit/NOTICE new file mode 100644 index 0000000..7340b9e --- /dev/null +++ b/libcopybit/NOTICE @@ -0,0 +1,190 @@ + + 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/libcopybit/c2d2.h b/libcopybit/c2d2.h new file mode 100644 index 0000000..10c94be --- /dev/null +++ b/libcopybit/c2d2.h @@ -0,0 +1,618 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __c2d2_h_ +#define __c2d2_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include /* for EGL surfaces */ + +#ifndef C2D_API +#define C2D_API /* define API export as needed */ +#endif +#ifndef int32 +typedef int int32; +#endif +#ifndef uint32 +typedef unsigned int uint32; +#endif + +/*****************************************************************************/ +/*********************** Blit definitions *****************************/ +/*****************************************************************************/ + +/* Status codes, returned by any blit function */ +typedef enum { + C2D_STATUS_OK = 0, + C2D_STATUS_NOT_SUPPORTED = 1, + C2D_STATUS_OUT_OF_MEMORY = 2, + C2D_STATUS_INVALID_PARAM = 3, + C2D_STATUS_SURFACE_IN_USE = 4, +} C2D_STATUS; + + +/* Definitions of color format modes, used together with color formats */ +typedef enum { + C2D_FORMAT_PACK_INTO_32BIT = (1 << 8), /* pack into dword if set */ + C2D_FORMAT_SWAP_ENDIANNESS = (1 << 9), /* swaps the order */ + C2D_FORMAT_LINEAR_SPACE = (1 << 10), /* linear color space */ + C2D_FORMAT_PREMULTIPLIED = (1 << 11), /* alpha premultiplied */ + C2D_FORMAT_INVERT_ALPHA = (1 << 12), /* inverts alpha */ + C2D_FORMAT_DISABLE_ALPHA = (1 << 13), /* disables alpha */ + C2D_FORMAT_INTERLACED = (1 << 14), /* YUV line-interlaced */ + C2D_FORMAT_TRANSPARENT = (1 << 15), /* YUV 1-bit alpha in Y */ + C2D_FORMAT_MACROTILED = (1 << 16), /* tiled in macro level */ + C2D_FORMAT_TILED_4x4 = (1 << 17), /* 4x4 tiled format */ + C2D_FORMAT_SWAP_RB = (1 << 18), /* Swap R & B color components */ +} C2D_FORMAT_MODE; + +/* Definitions of supported RGB formats, used in C2D_RGB_SURFACE_DEF. + * The bits of each color channel are packed into a machine word + * representing a single pixel from left to right (MSB to LSB) in the + * order indicated by format name. For the sub-byte formats the pixels + * are packed into bytes from left to right (MSbit to LSBit). + * If the C2D_FORMAT_PACK_INTO_32BIT bit is set, the minimal + * machine word used for pixel storage is 32-bit and the whole word + * is reversed if endianness is swapped. + * If the C2D_FORMAT_SWAP_ENDIANNESS bit is set, the order within a + * minimal machine word representing a pixel + * is reversed for both sub-byte and multi-byte formats. + * If the C2D_FORMAT_LINEAR_SPACE bit is set, the color space of + * the formats below is considered linear, if applicable. + * If the C2D_FORMAT_PREMULTIPLIED bit is set, the color channels + * are premultiplied with the alpha, if applicable. + * If the C2D_FORMAT_INVERT_ALPHA bit is set, the alpha interpretation + * is inverted: 0 - opaque, 1 - transparent, if applicable. + * If the C2D_FORMAT_DISABLE_ALPHA bit is set, the alpha channel serves + * as a placeholder and is ignored during blit, if applicable. + * If the COMP_FORMAT_MACROTILED bit is set, the surface is in the + * tiled format : 64x32 for 8bpp, 32x32 for 16bpp formats */ +typedef enum { + C2D_COLOR_FORMAT_1 = 0, /* 1-bit alpha/color expansion */ + + C2D_COLOR_FORMAT_2_PALETTE = 1, /* 2-bit indices for palette */ + C2D_COLOR_FORMAT_4_PALETTE = 2, /* 4-bit indices for palette */ + C2D_COLOR_FORMAT_8_PALETTE = 3, /* 8-bit indices for palette */ + + C2D_COLOR_FORMAT_2_L = 4, /* 2-bit grayscale */ + C2D_COLOR_FORMAT_4_L = 5, /* 4-bit grayscale */ + C2D_COLOR_FORMAT_8_L = 6, /* 8-bit grayscale */ + + C2D_COLOR_FORMAT_2_A = 7, /* 2-bit alpha only */ + C2D_COLOR_FORMAT_4_A = 8, /* 4-bit alpha only */ + C2D_COLOR_FORMAT_8_A = 9, /* 8-bit alpha only */ + + C2D_COLOR_FORMAT_444_RGB = 10, /* 12-bit colors */ + C2D_COLOR_FORMAT_565_RGB = 11, /* 16-bit colors */ + C2D_COLOR_FORMAT_888_RGB = 12, /* 24-bit colors */ + + C2D_COLOR_FORMAT_1555_ARGB = 13, /* 16-bit colors (1-bit alpha) */ + C2D_COLOR_FORMAT_4444_ARGB = 14, /* 16-bit colors (4-bit alpha) */ + C2D_COLOR_FORMAT_8565_ARGB = 15, /* 24-bit colors (8-bit alpha) */ + C2D_COLOR_FORMAT_8888_ARGB = 16, /* 32-bit colors (8-bit alpha) */ + + C2D_COLOR_FORMAT_5551_RGBA = 17, /* 16-bit colors (1-bit alpha) */ + C2D_COLOR_FORMAT_4444_RGBA = 18, /* 16-bit colors (4-bit alpha) */ + C2D_COLOR_FORMAT_5658_RGBA = 19, /* 24-bit colors (8-bit alpha) */ + C2D_COLOR_FORMAT_8888_RGBA = 20, /* 32-bit colors (8-bit alpha) */ + + /* derived RGB color formats (base format + mode bits) */ + +} C2D_RGB_FORMAT; + +/* Definitions of supported YUV formats, used in C2D_YUV_SURFACE_DEF. + * Each of Y,U,V channels usually takes 1 byte and therefore is + * individually addressable. The definitions below show how Y,U,V + * channels are packed into macropixels for each particular format. + * The order is from left (smaller byte addresses) to right (larger + * byte addresses). The first three digits (4xx) denote the chroma + * subsampling in standard YUV notation. The digits in the macropixel + * denote that the whole block (from the previous digit or from the + * beginning) has to be repeated the number of times. Underscores + * between Y,U,V channels are used to describe separate planes for + * planar YUV formats. Formats are mapped to numbers so that future + * versions with various YUV permutations are easy to add. + * If the C2D_FORMAT_INTERLACED bit is set, the line order is + * interlaced: 0,2,4,...1,3,5... if applicable. + * If the C2D_FORMAT_TRANSPARENT bit is set, the least significant + * bit of Y channel serves as alpha: 0 - transparent, 1 - opaque. */ +typedef enum { + C2D_COLOR_FORMAT_411_YYUYYV = 110, /* packed, 12-bit */ + C2D_COLOR_FORMAT_411_YUYYVY = 111, /* packed, 12-bit */ + C2D_COLOR_FORMAT_411_UYYVYY = 112, /* packed, 12-bit, "Y411" */ + C2D_COLOR_FORMAT_411_YUYV2Y4 = 116, /* packed, 12-bit */ + C2D_COLOR_FORMAT_411_UYVY2Y4 = 117, /* packed, 12-bit, "Y41P" */ + + C2D_COLOR_FORMAT_422_YUYV = 120, /* packed, 16-bit, "YUY2" */ + C2D_COLOR_FORMAT_422_UYVY = 121, /* packed, 16-bit, "UYVY" */ + C2D_COLOR_FORMAT_422_YVYU = 122, /* packed, 16-bit, "YVYU" */ + C2D_COLOR_FORMAT_422_VYUY = 123, /* packed, 16-bit */ + + C2D_COLOR_FORMAT_444_YUV = 130, /* packed, 24-bit */ + C2D_COLOR_FORMAT_444_UYV = 131, /* packed, 24-bit, "IYU2" */ + C2D_COLOR_FORMAT_444_AYUV = 136, /* packed, 24-bit, "AYUV" */ + + C2D_COLOR_FORMAT_410_Y_UV = 150, /* planar, Y + interleaved UV */ + C2D_COLOR_FORMAT_411_Y_UV = 151, /* planar, Y + interleaved UV */ + C2D_COLOR_FORMAT_420_Y_UV = 152, /* planar, Y + interleaved UV */ + C2D_COLOR_FORMAT_422_Y_UV = 153, /* planar, Y + interleaved UV */ + C2D_COLOR_FORMAT_444_Y_UV = 154, /* planar, Y + interleaved UV */ + + C2D_COLOR_FORMAT_410_Y_VU = 160, /* planar, Y + interleaved VU */ + C2D_COLOR_FORMAT_411_Y_VU = 161, /* planar, Y + interleaved VU */ + C2D_COLOR_FORMAT_420_Y_VU = 162, /* planar, Y + interleaved VU */ + C2D_COLOR_FORMAT_422_Y_VU = 163, /* planar, Y + interleaved VU */ + C2D_COLOR_FORMAT_444_Y_VU = 164, /* planar, Y + interleaved VU */ + + C2D_COLOR_FORMAT_410_Y_U_V = 170, /* planar, Y + U + V separate */ + C2D_COLOR_FORMAT_411_Y_U_V = 171, /* planar, Y + U + V separate */ + C2D_COLOR_FORMAT_420_Y_V_U = 172, /* planar, Y + V + U separate */ + C2D_COLOR_FORMAT_420_Y_U_V = 173, /* planar, Y + U + V separate */ + C2D_COLOR_FORMAT_422_Y_U_V = 174, /* planar, Y + U + V separate */ + C2D_COLOR_FORMAT_444_Y_U_V = 175, /* planar, Y + U + V separate */ + + C2D_COLOR_FORMAT_800_Y = 190, /* planar, Y only, grayscale */ + + /* derived YUV color formats (base format + mode bits), FOURCC */ + + C2D_COLOR_FORMAT_411_Y411 = 112, + C2D_COLOR_FORMAT_411_Y41P = 117, + C2D_COLOR_FORMAT_411_IY41 = 117 | (1 << 14), + C2D_COLOR_FORMAT_411_Y41T = 117 | (1 << 15), + + C2D_COLOR_FORMAT_422_YUY2 = 120, + C2D_COLOR_FORMAT_422_IUYV = 121 | (1 << 14), + C2D_COLOR_FORMAT_422_Y42T = 121 | (1 << 15), + C2D_COLOR_FORMAT_444_IYU2 = 131, + + C2D_COLOR_FORMAT_420_NV12 = 152, + C2D_COLOR_FORMAT_420_NV21 = 162, + + C2D_COLOR_FORMAT_410_YUV9 = 170, + C2D_COLOR_FORMAT_410_YVU9 = 170, + C2D_COLOR_FORMAT_411_Y41B = 171, + C2D_COLOR_FORMAT_420_YV12 = 172, + C2D_COLOR_FORMAT_420_IYUV = 173, + C2D_COLOR_FORMAT_420_I420 = 173, + C2D_COLOR_FORMAT_422_YV16 = 174, + C2D_COLOR_FORMAT_422_Y42B = 174, + + C2D_COLOR_FORMAT_800_Y800 = 190, + +} C2D_YUV_FORMAT; + + +/* Configuration bits, used in the config_mask field of C2D_OBJECT struct */ +typedef enum { + C2D_SOURCE_RECT_BIT = (1 << 0), /* enables source_rect field */ + C2D_MIRROR_H_BIT = (1 << 1), /* enables horizontal flipping */ + C2D_MIRROR_V_BIT = (1 << 2), /* enables vertical flipping */ + C2D_SOURCE_TILE_BIT = (1 << 3), /* enables source surface tiling */ + C2D_TARGET_RECT_BIT = (1 << 4), /* enables target_rect field */ + C2D_ROTATE_BIT = (1 << 5), /* enables all rotation fields */ + C2D_SCISSOR_RECT_BIT = (1 << 6), /* enables scissor_rect field */ + C2D_MASK_SURFACE_BIT = (1 << 7), /* enables mask_surface_id field */ + C2D_MASK_ALIGN_BIT = (1 << 8), /* aligns mask to source_rect */ + C2D_MASK_SCALE_BIT = (1 << 9), /* enables mask surface scaling */ + C2D_MASK_TILE_BIT = (1 << 10), /* enables mask surface tiling */ + C2D_GLOBAL_ALPHA_BIT = (1 << 11), /* enables global_alpha field */ + C2D_COLOR_KEY_BIT = (1 << 12), /* enables color_key field */ + C2D_NO_PIXEL_ALPHA_BIT = (1 << 13), /* disables source alpha channel */ + C2D_NO_BILINEAR_BIT = (1 << 14), /* disables bilinear on scaling */ + C2D_NO_ANTIALIASING_BIT = (1 << 15), /* disables antialiasing on edges */ + C2D_DRAW_LINE_BIT = (1 << 16), /* enables line drawing with source rectangle */ + C2D_DRAW_LINE_NOLAST = (1 << 17), /* disable last pixel draw for line */ +} C2D_SOURCE_CONFIG; + +/* Target configuration bits, defines rotation + mirroring. + * Mirror is applied prior to rotation if enabled. */ +typedef enum { + C2D_TARGET_MIRROR_H = (1 << 0), /* horizontal flip */ + C2D_TARGET_MIRROR_V = (1 << 1), /* vertical flip */ + C2D_TARGET_ROTATE_0 = (0 << 2), /* no rotation */ + C2D_TARGET_ROTATE_90 = (1 << 2), /* 90 degree rotation */ + C2D_TARGET_ROTATE_180 = (2 << 2), /* 180 degree rotation */ + C2D_TARGET_ROTATE_270 = (3 << 2), /* 270 degree rotation, 90 + 180 */ + C2D_TARGET_MASK_ALIGN = (1 << 4), /* aligns mask to target scissor */ + C2D_TARGET_MASK_SCALE = (1 << 5), /* enables mask scaling */ + C2D_TARGET_MASK_TILE = (1 << 6), /* enables mask tiling */ + C2D_TARGET_COLOR_KEY = (1 << 7), /* enables target_color_key */ + C2D_TARGET_NO_PIXEL_ALPHA = (1 << 8), /* disables target alpha channel */ +} C2D_TARGET_CONFIG; + +#define C2D_TARGET_ROTATION_MASK (C2D_TARGET_ROTATE_90*3) + +/* Additional blend modes, can be used with both source and target configs. + If none of the below is set, the default "SRC over DST" is applied. */ +typedef enum { + C2D_ALPHA_BLEND_SRC_OVER = (0 << 20), /* Default, Porter-Duff "SRC over DST" */ + C2D_ALPHA_BLEND_SRC = (1 << 20), /* Porter-Duff "SRC" */ + C2D_ALPHA_BLEND_SRC_IN = (2 << 20), /* Porter-Duff "SRC in DST" */ + C2D_ALPHA_BLEND_DST_IN = (3 << 20), /* Porter-Duff "DST in SRC" */ + C2D_ALPHA_BLEND_SRC_OUT = (4 << 20), /* Porter-Duff "SRC out DST" */ + C2D_ALPHA_BLEND_DST_OUT = (5 << 20), /* Porter-Duff "DST out SRC" */ + C2D_ALPHA_BLEND_DST_OVER = (6 << 20), /* Porter-Duff "DST over SRC" */ + C2D_ALPHA_BLEND_SRC_ATOP = (7 << 20), /* Porter-Duff "SRC ATOP" */ + C2D_ALPHA_BLEND_DST_ATOP = (8 << 20), /* Porter-Duff "DST ATOP" */ + C2D_ALPHA_BLEND_XOR = (9 << 20), /* Xor */ + C2D_ALPHA_BLEND_MULTIPLY = (10 << 20), /* OpenVG "MULTIPLY" */ + C2D_ALPHA_BLEND_SCREEN = (11 << 20), /* OpenVG "SCREEN" */ + C2D_ALPHA_BLEND_DARKEN = (12 << 20), /* OpenVG "DARKEN" */ + C2D_ALPHA_BLEND_LIGHTEN = (13 << 20), /* OpenVG "LIGHTEN" */ + C2D_ALPHA_BLEND_ADDITIVE = (14 << 20), /* OpenVG "ADDITIVE" */ + C2D_ALPHA_BLEND_DIRECT = (15 << 20), /* Direct alpha blitting */ + C2D_ALPHA_BLEND_INVERTC = (16 << 20), /* Invert color */ + C2D_ALPHA_BLEND_NONE = (1 << 25), /* disables alpha blending */ +} C2D_ALPHA_BLEND_MODE; + + +/* Surface caps enumeration */ +typedef enum { + C2D_SOURCE = (1 << 0), /* allows to use as a source */ + C2D_TARGET = (1 << 1), /* allows to use as a target */ + C2D_MASK = (1 << 2), /* allows to use as a mask */ + C2D_PALETTE = (1 << 3), /* allows to use as a palette */ +} C2D_SURFACE_BITS; + +/* Surface type enumeration */ +typedef enum { + C2D_SURFACE_EGL = 0, /* Arbitrary EGL surface */ + C2D_SURFACE_RGB_HOST = 1, /* Host memory RGB surface */ + C2D_SURFACE_RGB_EXT = 2, /* External memory RGB surface */ + C2D_SURFACE_YUV_HOST = 3, /* Host memory YUV surface */ + C2D_SURFACE_YUV_EXT = 4, /* External memory YUV surface */ + C2D_SURFACE_WITH_PHYS = (1<<3), /* physical address allready mapped */ + /* this bit is valid with HOST types */ +} C2D_SURFACE_TYPE; + +/* Structure for registering an EGL surface as a blit surface */ +typedef struct { + EGLDisplay display; /* EGL display */ + EGLContext context; /* EGL context, reserved - pass EGL_NO_CONTEXT */ + EGLSurface surface; /* EGL surface */ +} C2D_EGL_SURFACE_DEF; + +/* Structure for registering a RGB buffer as a blit surface */ +typedef struct { + uint32 format; /* RGB color format plus additional mode bits */ + uint32 width; /* defines width in pixels */ + uint32 height; /* defines height in pixels */ + void *buffer; /* pointer to the RGB buffer */ + void *phys; /* physical address */ + int32 stride; /* defines stride in bytes, negative stride is allowed */ +} C2D_RGB_SURFACE_DEF; + +/* Structure for registering a YUV plane(s) as a blit surface */ +typedef struct { + uint32 format; /* YUV color format plus additional mode bits */ + uint32 width; /* defines width in pixels */ + uint32 height; /* defines height in pixels */ + void *plane0; /* holds the whole buffer if YUV format is not planar */ + void *phys0; /* physical address */ + int32 stride0; /* stride in bytes if YUV format is not planar */ + void *plane1; /* holds UV or VU plane for planar interleaved */ + void *phys1; /* physical address */ + int32 stride1; /* stride for UV or VU plane for planar interleaved */ + void *plane2; /* holds the 3. plane, ignored if YUV format is not planar */ + void *phys2; /* physical address */ + int32 stride2; /* stride for the 3. plane, ignored if YUV format is not planar */ +} C2D_YUV_SURFACE_DEF; + + +/* Rectangle definition */ +typedef struct { + int32 x; /* upper-left x */ + int32 y; /* upper-left y */ + int32 width; /* width */ + int32 height; /* height */ +} C2D_RECT; + +/* C2D_OBJECT encapsulates the blit parameters for a source surface. + * The fg_color defines color in target format for bits equal to 1 + * in the source C2D_COLOR_FORMAT_1 format. It also defines rendering + * color for all alpha-only source formats. If the surface_id is 0 + * the fg_color defines a constant fill color used instead of the surface. + * The bg_color defines color in target format for bits equal to 0 + * in the source C2D_COLOR_FORMAT_1 format, otherwise both are ignored. + * The palette_id is used for all palette source formats, otherwise ignored. + + * The source_rect first defines the content of the source surface, + * it is then horizontally/vertically flipped if C2D_MIRROR_*_BIT is set, + * then scaled with bilinear interpolation to exactly fit target_rect + * or repeated across target_rect if C2D_SOURCE_TILE_BIT is set, + * target_rect is then rotated clockwise by an arbitrary angle in degrees + * around the rot_orig_x/y, defined relative to target_rect's top left point, + * and then clipped to scissor_rect defined in target coordinate system. + + * Finally alpha blending is applied before pixels get written into the target. + * Surface's pixel alpha is combined with mask alpha and with global alpha. + * Mask surface follows all transformations applied to the source surface. + * Source color key defines transparent color, applied together with alpha. */ +typedef struct C2D_OBJECT_STR { + uint32 surface_id; /* source surface */ + + uint32 fg_color; /* foreground color */ + uint32 bg_color; /* background color */ + uint32 palette_id; /* one-dimensional horizontal palette surface */ + + uint32 config_mask; /* defines which fields below are enabled */ + + C2D_RECT source_rect; /* region of the source surface, 16.16 fp */ + C2D_RECT target_rect; /* position and scaling in target, 16.16 fp */ + + int32 rot_orig_x; /* rotation origin relative to target_rect's... */ + int32 rot_orig_y; /* ...top left point, both are 16.16 fp */ + int32 rotation; /* clock-wise rotation in degrees, 16.16 fp */ + + C2D_RECT scissor_rect; /* defines the clip rectangle in target surface */ + + uint32 mask_surface_id; /* source alpha-mask surface */ + uint32 global_alpha; /* 0 = fully transparent, 255 = fully opaque */ + uint32 color_key; /* transparent color for the source surface */ + + struct C2D_OBJECT_STR *next; /* pointer to the next object or NULL */ +} C2D_OBJECT; + + +/*****************************************************************************/ +/**************************** C2D API 2.0 ********************************/ +/*****************************************************************************/ + +/****************************************************************************** + * Functions to create/destroy surfaces */ + +/* Creates a generic blit surface according to its type. + * Pass a combination of desired surface bits according to planned usage. + * Accepted values for surface_bits may include bits from C2D_SURFACE_BITS, + * and also from C2D_DISPLAY for compatibility with HW display controller. + * For host memory types the memory is preallocated outside the API + * and should remain valid until surface is destroyed. + * For external memory types the memory is allocated within API. + * On success, the non-zero surface identifier is returned. + * All numbers greater that 0 are valid surface identifiers, 0 is invalid. + + * arbitrary EGL surface (including proprietary Command List Surface): + * surface_type = C2D_SURFACE_EGL + * surface_definition = C2D_EGL_SURFACE_DEF + * all fields in definition structure should be set + * context field is reserved and can be ignored + + * Host memory RGB surface: + * surface_type = C2D_SURFACE_RGB_HOST + * surface_definition = C2D_RGB_SURFACE_DEF + * all fields in definition structure should be set + + * External memory RGB surface: + * surface_type = C2D_SURFACE_RGB_EXT + * surface_definition = C2D_RGB_SURFACE_DEF + * buffer field in definition structure is ignored + + * Host memory YUV surface: + * surface_type = C2D_SURFACE_YUV_HOST + * surface_definition = C2D_YUV_SURFACE_DEF + * one or all plane and stride fields in definition structure + * should be set depending on whether the format is planar or not + + * External memory YUV surface: + * surface_type = C2D_SURFACE_YUV_EXT + * surface_definition = C2D_YUV_SURFACE_DEF + * all plane and stride fields in definition structure are ignored */ +C2D_API C2D_STATUS c2dCreateSurface( uint32 *surface_id, + uint32 surface_bits, + C2D_SURFACE_TYPE surface_type, + void *surface_definition ); + +/* Requests properties of the specified surface. */ +C2D_API C2D_STATUS c2dQuerySurface( uint32 surface_id, + uint32 *surface_bits, + C2D_SURFACE_TYPE *surface_type, + uint32 *width, uint32 *height, + uint32 *format ); + +/* Destroys a generic blit surface. + * For external memory surfaces also deallocates the memory. + * It is safe to free any external resources associated with a given + * surface on c2dCreateSurface call after this function returns. */ +C2D_API C2D_STATUS c2dDestroySurface( uint32 surface_id ); + + +/****************************************************************************** + * Functions to modify/exchange surface data */ + +/* The format of fill_color is the same as color format being used + * for specified surface. If fill_rect is NULL the whole surface is filled. + * Alpha-blending is not performed while filling. + * The operation is complete when function returns. */ +C2D_API C2D_STATUS c2dFillSurface( uint32 surface_id, + uint32 fill_color, + C2D_RECT *fill_rect ); + +/* Writes data located in host memory into the specified surface. + * The chunk of host memory is identified with surface_type and + * surface_definition, no surface registration needed in this case. + * Only C2D_SURFACE_RGB_HOST, C2D_SURFACE_YUV_HOST are accepted. + * If only part of the host memory buffer should be loaded, it should + * be configured in surface_definition using width, height and stride. + * The x and y are defined in target surface coordinate space. + * Color conversion has to be done, if color formats differ. + * Alpha-blending is not performed while writing. + * The operation is complete when function returns. */ +C2D_API C2D_STATUS c2dWriteSurface( uint32 surface_id, + C2D_SURFACE_TYPE surface_type, + void *surface_definition, + int32 x, int32 y ); + +/* Reads data from the specified surface into the host memory. + * The chunk of host memory is identified with surface_type and + * surface_definition, no surface registration needed in this case. + * Only C2D_SURFACE_RGB_HOST, C2D_SURFACE_YUV_HOST are accepted. + * If only part of the surface should be read, it should + * be configured in surface_definition using width, height and stride. + * The x and y are defined in source surface coordinate space. + * Color conversion has to be done, if color formats differ. + * Alpha-blending is not performed while reading. + * The operation is complete when function returns. */ +C2D_API C2D_STATUS c2dReadSurface( uint32 surface_id, + C2D_SURFACE_TYPE surface_type, + void *surface_definition, + int32 x, int32 y ); + +/* Notifies c2d imlementation that surface has been updated from outside the API, + * if updated_rect is NULL then the whole surface has been updated. */ +C2D_API C2D_STATUS c2dSurfaceUpdated( uint32 surface_id, + C2D_RECT *updated_rect ); + +/* Updates surface information. + * Could be called only for host surfaces set with parameter "C2D_SURFACE_WITH_PHYS". + * Count for surface planes have to be same than for already allocated surface */ +C2D_API C2D_STATUS c2dUpdateSurface( uint32 surface_id, + uint32 surface_bits, + C2D_SURFACE_TYPE surface_type, + void *surface_definition ); + +/****************************************************************************** + * Functions to do actual blit */ + +/* Draw a list of blit objects into the given target. + * The target_config is a bitwise OR of values from C2D_TARGET_CONFIG. + * The target transformation creates the effect that target surface + * is transformed before the blit and then transformed back + * after blit, however no physical target transform is performed. + * The objects_list is a linked list of blit objects, no more + * than num_objects is drawn from the given list. + * If num_objects is 0, the whole list is drawn. + * The blit is not guaranteed to complete after function returns. */ +C2D_API C2D_STATUS c2dDraw( uint32 target_id, + uint32 target_config, C2D_RECT *target_scissor, + uint32 target_mask_id, uint32 target_color_key, + C2D_OBJECT *objects_list, uint32 num_objects ); + + +/* timstamp set in the blit commands flush */ +typedef void* c2d_ts_handle; + +/* Forces any pending blit to complete for a given target. + * Non-blocking. All input surfaces for this target except those + * which are shared with other targets are expected to be immediately + * writable after client has been waiting returned timestamp with + * c2dWaitTimestamp funtion or c2dFinish has been called for same target */ +C2D_API C2D_STATUS c2dFlush( uint32 target_id, c2d_ts_handle *timestamp); + + +/* Waits the pending timestamp */ +C2D_API C2D_STATUS c2dWaitTimestamp( c2d_ts_handle timestamp ); + + +/* Forces any pending blit to complete for a given target. + * Blocking version, returns when blit is done. + * All input surfaces for this target except those which are shared with + * other targets are expected to be immediately + * writable after this function returns. */ +C2D_API C2D_STATUS c2dFinish( uint32 target_id ); + + +/*****************************************************************************/ +/****************************** Display API **********************************/ +/*****************************************************************************/ + + +/* Display input enumeration */ +typedef enum { + C2D_DISPLAY_INPUT_0 = 0, /*!< default input */ + C2D_DISPLAY_INPUT_1 = (1<<16), /*!< Overlay 1 */ + C2D_DISPLAY_INPUT_2 = (1<<17), /*!< Overlay 2... */ +} C2D_DISPLAY_INPUT; + + +/****************************************************************************** + * Functions for display output. */ + +/* Functionality described in this section is optional and is + * provided only for the cases when blit HW + * is tightly bound to the display controller. */ + +/* Display enumeration, may also be used in surface caps */ +typedef enum { + C2D_DISPLAY_MAIN = (1 << 10), /* main display */ + C2D_DISPLAY_SECONDARY = (1 << 11), /* secondary display */ + C2D_DISPLAY_TV_OUT = (1 << 12), /* tv-out */ +} C2D_DISPLAY; + +/* Display window enumeration */ +typedef enum { + C2D_DISPLAY_OVERLAY = C2D_DISPLAY_INPUT_1, /*!< Overlay window bit. This defines display input. + When defined the surface is set on the overlay window + otherwise the surface is set on the background window. */ +} C2D_DISPLAY_WINDOW; /*!< Window bit set with display parameter */ + + +/* Display update modes */ +typedef enum { + C2D_DISPLAY_MODE_TEAR_SYNC = (1 << 0), /* enables tearing sync */ + C2D_DISPLAY_MODE_SURF_REMOVE = (1 << 1), /* Remove surface from given display + input */ +} C2D_DISPLAY_MODE; + + +/* Sets the given surface as a current display front buffer. + * Several displays can be specified as an output if supported. + * Still only one input can be specified at a time fro display/displays. + * The surface remains shown until it gets replaced with another one. */ +C2D_API C2D_STATUS c2dDisplaySetSurface( uint32 display, + uint32 surface_id, uint32 mode ); + +/* Returns the current surface for a particular display. + * Only one display can be specified at a time. + * The latest surface set with compDisplaySetSurface or + * the default pre-allocated surface is returned. */ +C2D_API C2D_STATUS c2dDisplayGetSurface( uint32 display, + uint32 *surface_id ); + +/* Returns the properties for a particular display. + * Only one display can be specified at a time. */ +C2D_API C2D_STATUS c2dDisplayGetProperties( uint32 display, + uint32 *width, uint32 *height, + uint32 *format ); + +/* Sets the properties for a particular display input. + * Only one display + input can be specified at a time. + * C2D_OBJECT used to set input rect(target rect), + * blending operations, rotation...etc for display source */ +C2D_API C2D_STATUS c2dDisplaySetObject( uint32 display, + uint32 target_config, uint32 target_color_key, + C2D_OBJECT * c2dObject, uint32 mode); + +/*****************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* __c2d2_h_ */ diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp new file mode 100644 index 0000000..6f6fca5 --- /dev/null +++ b/libcopybit/copybit.cpp @@ -0,0 +1,498 @@ +/* + * 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. + */ + + +#define LOG_TAG "copybit" + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "gralloc_priv.h" + +#define DEBUG_MDP_ERRORS 1 + +/******************************************************************************/ + +#if defined(COPYBIT_MSM7K) +#define MAX_SCALE_FACTOR (4) +#define MAX_DIMENSION (4096) +#elif defined(COPYBIT_QSD8K) +#define MAX_SCALE_FACTOR (8) +#define MAX_DIMENSION (2048) +#else +#error "Unsupported MDP version" +#endif + +/******************************************************************************/ + +/** State information for each device instance */ +struct copybit_context_t { + struct copybit_device_t device; + int mFD; + uint8_t mAlpha; + uint8_t mFlags; +}; + +/** + * Common hardware methods + */ + +static int open_copybit(const struct hw_module_t* module, const char* name, + struct hw_device_t** device); + +static struct hw_module_methods_t copybit_module_methods = { + open: open_copybit +}; + +/* + * The COPYBIT Module + */ +struct copybit_module_t HAL_MODULE_INFO_SYM = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: COPYBIT_HARDWARE_MODULE_ID, + name: "QCT MSM7K COPYBIT Module", + author: "Google, Inc.", + methods: ©bit_module_methods + } +}; + +/******************************************************************************/ + +/** min of int a, b */ +static inline int min(int a, int b) { + return (ab) ? a : b; +} + +/** scale each parameter by mul/div. Assume div isn't 0 */ +static inline void MULDIV(uint32_t *a, uint32_t *b, int mul, int div) { + if (mul != div) { + *a = (mul * *a) / div; + *b = (mul * *b) / div; + } +} + +/** Determine the intersection of lhs & rhs store in out */ +static void intersect(struct copybit_rect_t *out, + const struct copybit_rect_t *lhs, + const struct copybit_rect_t *rhs) { + out->l = max(lhs->l, rhs->l); + out->t = max(lhs->t, rhs->t); + out->r = min(lhs->r, rhs->r); + out->b = min(lhs->b, rhs->b); +} + +/** convert COPYBIT_FORMAT to MDP format */ +static int get_format(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_RGB_565: return MDP_RGB_565; + case HAL_PIXEL_FORMAT_RGBX_8888: return MDP_RGBX_8888; + case HAL_PIXEL_FORMAT_RGB_888: return MDP_RGB_888; + case HAL_PIXEL_FORMAT_RGBA_8888: return MDP_RGBA_8888; + case HAL_PIXEL_FORMAT_BGRA_8888: return MDP_BGRA_8888; + case HAL_PIXEL_FORMAT_YCrCb_422_SP: return MDP_Y_CBCR_H2V1; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: return MDP_Y_CBCR_H2V2; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: return MDP_Y_CRCB_H2V1; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: return MDP_Y_CRCB_H2V2; + } + return -1; +} + +/** convert from copybit image to mdp image structure */ +static void set_image(struct mdp_img *img, const struct copybit_image_t *rhs) +{ + private_handle_t* hnd = (private_handle_t*)rhs->handle; + img->width = rhs->w; + img->height = rhs->h; + img->format = get_format(rhs->format); + img->offset = hnd->offset; + #if defined(COPYBIT_MSM7K) + #if defined(USE_ASHMEM) && (TARGET_7x27) + img->memory_id = hnd->fd; + #else //USE_ASHMEM not defined + img->memory_id = hnd->fd; + #endif //end USE_ASHMEM + #else + img->memory_id = hnd->fd; + #endif +} +/** setup rectangles */ +static void set_rects(struct copybit_context_t *dev, + struct mdp_blit_req *e, + const struct copybit_rect_t *dst, + const struct copybit_rect_t *src, + const struct copybit_rect_t *scissor, + uint32_t horiz_padding, + uint32_t vert_padding) { + struct copybit_rect_t clip; + intersect(&clip, scissor, dst); + + e->dst_rect.x = clip.l; + e->dst_rect.y = clip.t; + e->dst_rect.w = clip.r - clip.l; + e->dst_rect.h = clip.b - clip.t; + + uint32_t W, H; + if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) { + e->src_rect.x = (clip.t - dst->t) + src->t; + e->src_rect.y = (dst->r - clip.r) + src->l; + e->src_rect.w = (clip.b - clip.t); + e->src_rect.h = (clip.r - clip.l); + W = dst->b - dst->t; + H = dst->r - dst->l; + } else { + e->src_rect.x = (clip.l - dst->l) + src->l; + e->src_rect.y = (clip.t - dst->t) + src->t; + e->src_rect.w = (clip.r - clip.l); + e->src_rect.h = (clip.b - clip.t); + W = dst->r - dst->l; + H = dst->b - dst->t; + } + MULDIV(&e->src_rect.x, &e->src_rect.w, src->r - src->l, W); + MULDIV(&e->src_rect.y, &e->src_rect.h, src->b - src->t, H); + + if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_V) { + if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) { + e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w) - horiz_padding; + }else{ + e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h) - vert_padding; + } + } + + if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_H) { + if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) { + e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h) - vert_padding; + }else{ + e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w) - horiz_padding; + } + } +} + +/** setup mdp request */ +static void set_infos(struct copybit_context_t *dev, struct mdp_blit_req *req, int flags) { + req->alpha = dev->mAlpha; + req->transp_mask = MDP_TRANSP_NOP; + req->flags = dev->mFlags | flags; +#if defined(COPYBIT_QSD8K) + req->flags |= MDP_BLEND_FG_PREMULT; +#endif +} + +/** copy the bits */ +static int msm_copybit(struct copybit_context_t *dev, void const *list) +{ + int err = ioctl(dev->mFD, MSMFB_BLIT, + (struct mdp_blit_req_list const*)list); + LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno)); + if (err == 0) { + return 0; + } else { +#if DEBUG_MDP_ERRORS + struct mdp_blit_req_list const* l = (struct mdp_blit_req_list const*)list; + for (int i=0 ; icount ; i++) { + LOGD("%d: src={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n" + " dst={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n" + " flags=%08lx" + , + i, + l->req[i].src.width, + l->req[i].src.height, + l->req[i].src.format, + l->req[i].src_rect.x, + l->req[i].src_rect.y, + l->req[i].src_rect.w, + l->req[i].src_rect.h, + l->req[i].dst.width, + l->req[i].dst.height, + l->req[i].dst.format, + l->req[i].dst_rect.x, + l->req[i].dst_rect.y, + l->req[i].dst_rect.w, + l->req[i].dst_rect.h, + l->req[i].flags + ); + } +#endif + return -errno; + } +} + +/*****************************************************************************/ + +/** Set a parameter to value */ +static int set_parameter_copybit( + struct copybit_device_t *dev, + int name, + int value) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int status = 0; + if (ctx) { + switch(name) { + case COPYBIT_ROTATION_DEG: + switch (value) { + case 0: + ctx->mFlags &= ~0x7; + break; + case 90: + ctx->mFlags &= ~0x7; + ctx->mFlags |= MDP_ROT_90; + break; + case 180: + ctx->mFlags &= ~0x7; + ctx->mFlags |= MDP_ROT_180; + break; + case 270: + ctx->mFlags &= ~0x7; + ctx->mFlags |= MDP_ROT_270; + break; + default: + LOGE("Invalid value for COPYBIT_ROTATION_DEG"); + status = -EINVAL; + break; + } + break; + case COPYBIT_PLANE_ALPHA: + if (value < 0) value = 0; + if (value >= 256) value = 255; + ctx->mAlpha = value; + break; + case COPYBIT_DITHER: + if (value == COPYBIT_ENABLE) { + ctx->mFlags |= MDP_DITHER; + } else if (value == COPYBIT_DISABLE) { + ctx->mFlags &= ~MDP_DITHER; + } + break; + case COPYBIT_BLUR: + if (value == COPYBIT_ENABLE) { + ctx->mFlags |= MDP_BLUR; + } else if (value == COPYBIT_DISABLE) { + ctx->mFlags &= ~MDP_BLUR; + } + break; + case COPYBIT_TRANSFORM: + ctx->mFlags &= ~0x7; + ctx->mFlags |= value & 0x7; + break; + default: + status = -EINVAL; + break; + } + } else { + status = -EINVAL; + } + return status; +} + +/** Get a static info value */ +static int get(struct copybit_device_t *dev, int name) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int value; + if (ctx) { + switch(name) { + case COPYBIT_MINIFICATION_LIMIT: + value = MAX_SCALE_FACTOR; + break; + case COPYBIT_MAGNIFICATION_LIMIT: + value = MAX_SCALE_FACTOR; + break; + case COPYBIT_SCALING_FRAC_BITS: + value = 32; + break; + case COPYBIT_ROTATION_STEP_DEG: + value = 90; + break; + default: + value = -EINVAL; + } + } else { + value = -EINVAL; + } + return value; +} + +/** do a stretch blit type operation */ +static int stretch_copybit( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_rect_t const *dst_rect, + struct copybit_rect_t const *src_rect, + struct copybit_region_t const *region) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int status = 0; + if (ctx) { + struct { + uint32_t count; + struct mdp_blit_req req[12]; + } list; + + if (ctx->mAlpha < 255) { + switch (src->format) { + // we don't support plane alpha with RGBA formats + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + return -EINVAL; + } + } + + if (src_rect->l < 0 || src_rect->r > src->w || + src_rect->t < 0 || src_rect->b > src->h) { + // this is always invalid + return -EINVAL; + } + + if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION) + return -EINVAL; + + if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) + return -EINVAL; + + const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]); + const struct copybit_rect_t bounds = { 0, 0, dst->w, dst->h }; + struct copybit_rect_t clip; + list.count = 0; + status = 0; + while ((status == 0) && region->next(region, &clip)) { + intersect(&clip, &bounds, &clip); + mdp_blit_req* req = &list.req[list.count]; + int flags = 0; + + set_infos(ctx, req, flags); + set_image(&req->dst, dst); + set_image(&req->src, src); + set_rects(ctx, req, dst_rect, src_rect, &clip, src->horiz_padding, src->vert_padding); + + if (req->src_rect.w<=0 || req->src_rect.h<=0) + continue; + + if (req->dst_rect.w<=0 || req->dst_rect.h<=0) + continue; + + if (++list.count == maxCount) { + status = msm_copybit(ctx, &list); + list.count = 0; + } + } + if ((status == 0) && list.count) { + status = msm_copybit(ctx, &list); + } + } else { + status = -EINVAL; + } + return status; +} + +/** Perform a blit type operation */ +static int blit_copybit( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_region_t const *region) +{ + struct copybit_rect_t dr = { 0, 0, dst->w, dst->h }; + struct copybit_rect_t sr = { 0, 0, src->w, src->h }; + return stretch_copybit(dev, dst, src, &dr, &sr, region); +} + +/*****************************************************************************/ + +/** Close the copybit device */ +static int close_copybit(struct hw_device_t *dev) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + if (ctx) { + close(ctx->mFD); + free(ctx); + } + return 0; +} + +/** Open a new instance of a copybit device using name */ +static int open_copybit(const struct hw_module_t* module, const char* name, + struct hw_device_t** device) +{ + int status = -EINVAL; + copybit_context_t *ctx; + ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t)); + memset(ctx, 0, sizeof(*ctx)); + + ctx->device.common.tag = HARDWARE_DEVICE_TAG; + ctx->device.common.version = 1; + ctx->device.common.module = const_cast(module); + ctx->device.common.close = close_copybit; + ctx->device.set_parameter = set_parameter_copybit; + ctx->device.get = get; + ctx->device.blit = blit_copybit; + ctx->device.stretch = stretch_copybit; + ctx->mAlpha = MDP_ALPHA_NOP; + ctx->mFlags = 0; + ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0); + + if (ctx->mFD < 0) { + status = errno; + LOGE("Error opening frame buffer errno=%d (%s)", + status, strerror(status)); + status = -status; + } else { + struct fb_fix_screeninfo finfo; + if (ioctl(ctx->mFD, FBIOGET_FSCREENINFO, &finfo) == 0) { + if (strncmp(finfo.id, "msmfb", 5) == 0) { + /* Success */ + status = 0; + } else { + LOGE("Error not msm frame buffer"); + status = -EINVAL; + } + } else { + LOGE("Error executing ioctl for screen info"); + status = -errno; + } + } + + if (status == 0) { + *device = &ctx->device.common; + } else { + close_copybit(&ctx->device.common); + } + return status; +} diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp new file mode 100644 index 0000000..0995345 --- /dev/null +++ b/libcopybit/copybit_c2d.cpp @@ -0,0 +1,1036 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2010-2011, 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 "copybit_c2d" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "c2d2.h" + +#include +C2D_STATUS (*LINK_c2dCreateSurface)( uint32 *surface_id, + uint32 surface_bits, + C2D_SURFACE_TYPE surface_type, + void *surface_definition ); + +C2D_STATUS (*LINK_c2dUpdateSurface)( uint32 surface_id, + uint32 surface_bits, + C2D_SURFACE_TYPE surface_type, + void *surface_definition ); + +C2D_STATUS (*LINK_c2dReadSurface)( uint32 surface_id, + C2D_SURFACE_TYPE surface_type, + void *surface_definition, + int32 x, int32 y ); + +C2D_STATUS (*LINK_c2dDraw)( uint32 target_id, + uint32 target_config, C2D_RECT *target_scissor, + uint32 target_mask_id, uint32 target_color_key, + C2D_OBJECT *objects_list, uint32 num_objects ); + +C2D_STATUS (*LINK_c2dFinish)( uint32 target_id); + +C2D_STATUS (*LINK_c2dFlush)( uint32 target_id, c2d_ts_handle *timestamp); + +C2D_STATUS (*LINK_c2dWaitTimestamp)( c2d_ts_handle timestamp ); + +C2D_STATUS (*LINK_c2dDestroySurface)( uint32 surface_id ); + + +/******************************************************************************/ + +#if defined(COPYBIT_Z180) +#define MAX_SCALE_FACTOR (4096) +#define MAX_DIMENSION (4096) +#else +#error "Unsupported HW version" +#endif + +#define G12_DEVICE_NAME "/dev/kgsl-2d0" + +#define COPYBIT_SUCCESS 0 +#define COPYBIT_FAILURE -1 + +#define RGB_SURFACE 0 +#define YUV_SURFACE 1 +#define NUM_SRC_SURFACES 2 +#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) +/******************************************************************************/ + +/** State information for each device instance */ +struct copybit_context_t { + struct copybit_device_t device; + unsigned int src[NUM_SRC_SURFACES]; + unsigned int dst; /* dst surface */ + unsigned int trg_transform; /* target transform */ + C2D_OBJECT blitState; + void *libc2d2; + int g12_device_fd; + int fb_width; + int fb_height; + bool isPremultipliedAlpha; +}; + +struct blitlist{ + uint32_t count; + C2D_OBJECT blitObjects[12]; +}; + +/** + * Common hardware methods + */ + +static int open_copybit(const struct hw_module_t* module, const char* name, + struct hw_device_t** device); + +static struct hw_module_methods_t copybit_module_methods = { + open: open_copybit +}; + +/* + * The COPYBIT Module + */ +struct copybit_module_t HAL_MODULE_INFO_SYM = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: COPYBIT_HARDWARE_MODULE_ID, + name: "QCT COPYBIT C2D 2.0 Module", + author: "Qualcomm", + methods: ©bit_module_methods + } +}; + + +/* convert COPYBIT_FORMAT to C2D format */ +static int get_format(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_RGB_565: return C2D_COLOR_FORMAT_565_RGB; + case HAL_PIXEL_FORMAT_RGBX_8888: return C2D_COLOR_FORMAT_8888_ARGB | C2D_FORMAT_SWAP_RB | C2D_FORMAT_DISABLE_ALPHA; + case HAL_PIXEL_FORMAT_RGBA_8888: return C2D_COLOR_FORMAT_8888_ARGB | C2D_FORMAT_SWAP_RB; + case HAL_PIXEL_FORMAT_BGRA_8888: return C2D_COLOR_FORMAT_8888_ARGB; + case HAL_PIXEL_FORMAT_RGBA_5551: return C2D_COLOR_FORMAT_5551_RGBA; + case HAL_PIXEL_FORMAT_RGBA_4444: return C2D_COLOR_FORMAT_4444_RGBA; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: return C2D_COLOR_FORMAT_420_NV12; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: return C2D_COLOR_FORMAT_420_NV21; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: return C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_MACROTILED; + default: return -EINVAL; + } + return -EINVAL; +} + +/* ------------------------------------------------------------------- *//*! + * \internal + * \brief Get the bpp for a particular color format + * \param color format + * \return bits per pixel +*//* ------------------------------------------------------------------- */ +int c2diGetBpp(int32 colorformat) +{ + + int c2dBpp = 0; + + switch(colorformat&0xFF) + { + case C2D_COLOR_FORMAT_4444_RGBA: + case C2D_COLOR_FORMAT_4444_ARGB: + case C2D_COLOR_FORMAT_1555_ARGB: + case C2D_COLOR_FORMAT_565_RGB: + case C2D_COLOR_FORMAT_5551_RGBA: + c2dBpp = 16; + break; + case C2D_COLOR_FORMAT_8888_RGBA: + case C2D_COLOR_FORMAT_8888_ARGB: + c2dBpp = 32; + break; + case C2D_COLOR_FORMAT_8_L: + case C2D_COLOR_FORMAT_8_A: + c2dBpp = 8; + break; + case C2D_COLOR_FORMAT_4_A: + c2dBpp = 4; + break; + case C2D_COLOR_FORMAT_1: + c2dBpp = 1; + break; + default: + LOGE("%s ERROR", __func__); + break; + } + return c2dBpp; +} + +static uint32 c2d_get_gpuaddr(int device_fd, struct private_handle_t *handle) +{ + if(!handle) + return 0; + + struct kgsl_map_user_mem param; + memset(¶m, 0, sizeof(param)); + param.fd = handle->fd; + param.len = handle->size; + param.offset = handle->offset; + param.hostptr = handle->base; + + if (handle->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM | + private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)) + param.memtype = KGSL_USER_MEM_TYPE_PMEM; + else if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) + param.memtype = KGSL_USER_MEM_TYPE_ASHMEM; + else if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ION) + param.memtype = KGSL_USER_MEM_TYPE_ION; + else { + LOGE("Invalid handle flags: 0x%x", handle->flags); + return 0; + } + + if (!ioctl(device_fd, IOCTL_KGSL_MAP_USER_MEM, (void *)¶m, sizeof(param))) { + return param.gpuaddr; + } + + return 0; +} + +static uint32 c2d_unmap_gpuaddr(int device_fd, unsigned int gpuaddr) +{ + struct kgsl_sharedmem_free param; + + memset(¶m, 0, sizeof(param)); + param.gpuaddr = gpuaddr; + + ioctl(device_fd, IOCTL_KGSL_SHAREDMEM_FREE, (void *)¶m, sizeof(param)); + return COPYBIT_SUCCESS; +} + +static int is_supported_rgb_format(int format) +{ + switch(format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: { + return COPYBIT_SUCCESS; + } + default: + return COPYBIT_FAILURE; + } +} + +static int is_supported_yuv_format(int format) +{ + switch(format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { + return COPYBIT_SUCCESS; + } + default: + return COPYBIT_FAILURE; + } +} + +static int calculate_yuv_offset_and_stride(int format, int width, int height, int *offset, int *yStride, int *uvStride) +{ + int aligned_height = 0; + int aligned_width = 0, size = 0; + + switch (format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { + /* NV12 Tile buffers have their luma height aligned to 32bytes and width + * aligned to 128 bytes. The chroma offset starts at an 8K boundary + */ + aligned_height = ALIGN(height, 32); + aligned_width = ALIGN(width, 128); + size = aligned_width * aligned_height; + *offset = ALIGN(size,8192); + *yStride = aligned_width; + *uvStride = aligned_width; + break; + } + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: { + aligned_width = ALIGN(width, 32); + *offset = aligned_width * height; + *yStride = aligned_width; + *uvStride = aligned_width; + break; + } + default: { + return COPYBIT_FAILURE; + } + } + return COPYBIT_SUCCESS; +} + +/** create C2D surface from copybit image */ +static int set_image(int device_fd, uint32 surfaceId, const struct copybit_image_t *rhs, int *cformat, uint32_t *mapped, + const bool isPremultipliedAlpha) +{ + struct private_handle_t* handle = (struct private_handle_t*)rhs->handle; + C2D_SURFACE_TYPE surfaceType; + int status = COPYBIT_SUCCESS; + + *cformat = get_format(rhs->format); + if(*cformat == -EINVAL) { + LOGE("%s: invalid format", __func__); + return -EINVAL; + } + + if(handle == NULL) { + LOGE("%s: invalid handle", __func__); + return -EINVAL; + } + + if (handle->gpuaddr == 0) { + handle->gpuaddr = c2d_get_gpuaddr(device_fd, handle); + if(!handle->gpuaddr) { + return COPYBIT_FAILURE; + } + *mapped = 1; + } + + /* create C2D surface */ + if(is_supported_rgb_format(rhs->format) == COPYBIT_SUCCESS) { + /* RGB */ + C2D_RGB_SURFACE_DEF surfaceDef; + + surfaceType = (C2D_SURFACE_TYPE) (C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS); + + surfaceDef.phys = (void*) handle->gpuaddr; + surfaceDef.buffer = (void*) (handle->base); + + surfaceDef.format = *cformat | (isPremultipliedAlpha ? C2D_FORMAT_PREMULTIPLIED : 0); + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32); + + if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType, &surfaceDef)) { + LOGE("%s: RGB Surface c2dUpdateSurface ERROR", __func__); + goto error; + status = COPYBIT_FAILURE; + } + } else if (is_supported_yuv_format(rhs->format) == COPYBIT_SUCCESS) { + C2D_YUV_SURFACE_DEF surfaceDef; + int offset = 0; + int yStride = 0; + int uvStride = 0; + memset(&surfaceDef, 0, sizeof(surfaceDef)); + surfaceType = (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS); + surfaceDef.format = *cformat; + + status = calculate_yuv_offset_and_stride(rhs->format, rhs->w, rhs->h, &offset, &yStride, &uvStride); + if(status != COPYBIT_SUCCESS) { + LOGE("calculate_yuv_offset_and_stride error"); + goto error; + } + + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + surfaceDef.plane0 = (void*) (handle->base); + surfaceDef.phys0 = (void*) (handle->gpuaddr); + surfaceDef.stride0 = yStride; + + surfaceDef.plane1 = (void*) (handle->base + offset); + surfaceDef.phys1 = (void*) (handle->gpuaddr + offset); + surfaceDef.stride1 = uvStride; + + if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType, &surfaceDef)) { + LOGE("%s: YUV Surface c2dUpdateSurface ERROR", __func__); + goto error; + status = COPYBIT_FAILURE; + } + } else { + LOGE("%s: invalid format %x", __func__, rhs->format); + goto error; + status = COPYBIT_FAILURE; + } + + return status; + +error: + if(*mapped == 1) { + c2d_unmap_gpuaddr(device_fd, handle->gpuaddr); + handle->gpuaddr = 0; + *mapped = 0; + } + return status; +} + +static int set_src_image(int device_fd, uint32 *surfaceId, const struct copybit_image_t *rhs, int *cformat, uint32 *mapped) +{ + struct private_handle_t* handle = (struct private_handle_t*)rhs->handle; + *cformat = get_format(rhs->format); + C2D_SURFACE_TYPE surfaceType; + uint32 gpuaddr = (uint32)handle->gpuaddr; + int status = COPYBIT_SUCCESS; + + if (handle->gpuaddr == 0) + { + handle->gpuaddr = c2d_get_gpuaddr(device_fd, handle); + if(!handle->gpuaddr) + return COPYBIT_FAILURE; + + *mapped = 1; + } + + /* create C2D surface */ + if(is_supported_rgb_format(rhs->format) == COPYBIT_SUCCESS) { + /* RGB */ + C2D_RGB_SURFACE_DEF surfaceDef; + surfaceType = (C2D_SURFACE_TYPE) (C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS); + + surfaceDef.phys = (void*) handle->gpuaddr; + surfaceDef.buffer = (void*) (handle->base); + surfaceDef.buffer = (void*) (handle->base + handle->offset); + + surfaceDef.format = get_format(rhs->format); + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32); + + if(LINK_c2dCreateSurface( surfaceId, C2D_TARGET, surfaceType,(void*)&surfaceDef)) { + LOGE("%s: LINK_c2dCreateSurface error", __func__); + status = COPYBIT_FAILURE; + goto error; + } + } else if(is_supported_yuv_format(rhs->format) == COPYBIT_SUCCESS) { + /* YUV */ + C2D_YUV_SURFACE_DEF surfaceDef; + int offset = 0; + int yStride = 0; + int uvStride = 0; + memset(&surfaceDef, 0, sizeof(surfaceDef)); + + surfaceType = (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS); + surfaceDef.format = get_format(rhs->format); + status = calculate_yuv_offset_and_stride(rhs->format, rhs->w, rhs->h, &offset, &yStride, &uvStride); + if(status != COPYBIT_SUCCESS) { + LOGE("calculate_yuv_offset_and_stride error"); + goto error; + } + + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + surfaceDef.plane0 = (void*) (handle->base); + surfaceDef.phys0 = (void*) handle->gpuaddr; + surfaceDef.stride0 = yStride; + + surfaceDef.plane1 = (void*) (handle->base + offset); + surfaceDef.phys1 = (void*) (handle->gpuaddr + offset); + surfaceDef.stride1 = uvStride; + + if(LINK_c2dCreateSurface( surfaceId, C2D_TARGET | C2D_SOURCE, surfaceType, (void*)&surfaceDef)) { + LOGE("%s: YUV surface LINK_c2dCreateSurface error", __func__); + status = COPYBIT_FAILURE; + goto error; + } + } else { + LOGE("%s: Invalid format %x", __func__, rhs->format); + status = COPYBIT_FAILURE; + } + + return COPYBIT_SUCCESS; + +error: + if(*mapped == 1) { + c2d_unmap_gpuaddr(device_fd, handle->gpuaddr); + handle->gpuaddr = 0; + *mapped = 0; + } + return status; +} + +void unset_image(int device_fd, uint32 surfaceId, const struct copybit_image_t *rhs, uint32 mmapped) +{ + struct private_handle_t* handle = (struct private_handle_t*)rhs->handle; + + if (mmapped && handle->gpuaddr) { + // Unmap this gpuaddr + c2d_unmap_gpuaddr(device_fd, handle->gpuaddr); + handle->gpuaddr = 0; + } +} + +static int blit_to_target(int device_fd, uint32 surfaceId, const struct copybit_image_t *rhs) +{ + struct private_handle_t* handle = (struct private_handle_t*)rhs->handle; + uint32 cformat = get_format(rhs->format); + C2D_SURFACE_TYPE surfaceType; + uint32 memoryMapped = 0; + int status = COPYBIT_SUCCESS; + + if (!handle->gpuaddr) { + handle->gpuaddr = c2d_get_gpuaddr(device_fd,handle); + if(!handle->gpuaddr) + return COPYBIT_FAILURE; + + memoryMapped = 1; + } + + /* create C2D surface */ + + if(cformat) { + /* RGB */ + C2D_RGB_SURFACE_DEF surfaceDef; + memset(&surfaceDef, 0, sizeof(surfaceDef)); + + surfaceDef.buffer = (void*) handle->base; + surfaceDef.phys = (void*) handle->gpuaddr; + + surfaceType = C2D_SURFACE_RGB_HOST; + surfaceDef.format = get_format(rhs->format); + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32); + + if(LINK_c2dReadSurface(surfaceId, surfaceType, (void*)&surfaceDef, 0, 0)) { + LOGE("%s: LINK_c2dReadSurface ERROR", __func__); + status = COPYBIT_FAILURE; + goto done; + } + } + else { + /* YUV */ + /* TODO */ + } + +done: + if (memoryMapped) { + c2d_unmap_gpuaddr(device_fd, handle->gpuaddr); + handle->gpuaddr = 0; + } + return status; +} + +/** setup rectangles */ +static void set_rects(struct copybit_context_t *ctx, + C2D_OBJECT *c2dObject, + const struct copybit_rect_t *dst, + const struct copybit_rect_t *src, + const struct copybit_rect_t *scissor) +{ + + if((ctx->trg_transform & C2D_TARGET_ROTATE_90) && + (ctx->trg_transform & C2D_TARGET_ROTATE_180)) { + /* target rotation is 270 */ + c2dObject->target_rect.x = (dst->t)<<16; + c2dObject->target_rect.y = (ALIGN(ctx->fb_width,32) - (dst->r))<<16; + c2dObject->target_rect.height = ((dst->r) - (dst->l))<<16; + c2dObject->target_rect.width = ((dst->b) - (dst->t))<<16; + } else if(ctx->trg_transform & C2D_TARGET_ROTATE_90) { + c2dObject->target_rect.x = (ctx->fb_height - dst->b)<<16; + c2dObject->target_rect.y = (dst->l)<<16; + c2dObject->target_rect.height = ((dst->r) - (dst->l))<<16; + c2dObject->target_rect.width = ((dst->b) - (dst->t))<<16; + } else if(ctx->trg_transform & C2D_TARGET_ROTATE_180) { + c2dObject->target_rect.y = (ctx->fb_height - dst->b)<<16; + c2dObject->target_rect.x = (ALIGN(ctx->fb_width,32) - dst->r)<<16; + c2dObject->target_rect.height = ((dst->b) - (dst->t))<<16; + c2dObject->target_rect.width = ((dst->r) - (dst->l))<<16; + } else { + c2dObject->target_rect.x = (dst->l)<<16; + c2dObject->target_rect.y = (dst->t)<<16; + c2dObject->target_rect.height = ((dst->b) - (dst->t))<<16; + c2dObject->target_rect.width = ((dst->r) - (dst->l))<<16; + } + c2dObject->config_mask |= C2D_TARGET_RECT_BIT; + + c2dObject->source_rect.x = (src->l)<<16; + c2dObject->source_rect.y = (src->t)<<16; + c2dObject->source_rect.height = ((src->b) - (src->t))<<16; + c2dObject->source_rect.width = ((src->r) - (src->l))<<16; + c2dObject->config_mask |= C2D_SOURCE_RECT_BIT; + + c2dObject->scissor_rect.x = scissor->l; + c2dObject->scissor_rect.y = scissor->t; + c2dObject->scissor_rect.height = (scissor->b) - (scissor->t); + c2dObject->scissor_rect.width = (scissor->r) - (scissor->l); + + c2dObject->config_mask |= C2D_SCISSOR_RECT_BIT; +} + +/** copy the bits */ +static int msm_copybit(struct copybit_context_t *dev, blitlist *list, uint32 target) +{ + int objects; + + for(objects = 0; objects < list->count; objects++) { + list->blitObjects[objects].next = &(list->blitObjects[objects+1]); + } + + if(LINK_c2dDraw(target,dev->trg_transform, 0x0, 0, 0, list->blitObjects, + list->count)) { + LOGE("%s: LINK_c2dDraw ERROR"); + return COPYBIT_FAILURE; + } + + return COPYBIT_SUCCESS; +} + +/*****************************************************************************/ + +/** Set a parameter to value */ +static int set_parameter_copybit( + struct copybit_device_t *dev, + int name, + int value) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + if (!ctx) { + LOGE("%s: null context", __func__); + return -EINVAL; + } + + switch(name) { + case COPYBIT_ROTATION_DEG: + ctx->blitState.rotation = value<<16; + /* SRC rotation */ + if(!value) + ctx->blitState.config_mask &=~C2D_ROTATE_BIT;; + break; + case COPYBIT_PLANE_ALPHA: + if (value < 0) value = 0; + if (value >= 256) value = 255; + + ctx->blitState.global_alpha = value; + + if(ctx->blitState.global_alpha<255) + ctx->blitState.config_mask |= C2D_GLOBAL_ALPHA_BIT; + else + ctx->blitState.config_mask &=~C2D_GLOBAL_ALPHA_BIT; + break; + case COPYBIT_DITHER: + /* TODO */ + break; + case COPYBIT_BLUR: + /* TODO */ + break; + case COPYBIT_TRANSFORM: + ctx->blitState.config_mask &=~C2D_ROTATE_BIT; + ctx->blitState.config_mask &=~C2D_MIRROR_H_BIT; + ctx->blitState.config_mask &=~C2D_MIRROR_V_BIT; + ctx->trg_transform = C2D_TARGET_ROTATE_0; + + if((value&0x7) == COPYBIT_TRANSFORM_ROT_180) + ctx->trg_transform = C2D_TARGET_ROTATE_180; + else if((value&0x7) == COPYBIT_TRANSFORM_ROT_270) + ctx->trg_transform = C2D_TARGET_ROTATE_90; + else { + if(value©BIT_TRANSFORM_FLIP_H) + ctx->blitState.config_mask |= C2D_MIRROR_H_BIT; + if(value©BIT_TRANSFORM_FLIP_V) + ctx->blitState.config_mask |= C2D_MIRROR_V_BIT; + if(value©BIT_TRANSFORM_ROT_90) + ctx->trg_transform = C2D_TARGET_ROTATE_270; + } + break; + case COPYBIT_PREMULTIPLIED_ALPHA: + (value == COPYBIT_ENABLE) ? ctx->isPremultipliedAlpha = true : + ctx->isPremultipliedAlpha = false; + break; + default: + LOGE("%s: default case", __func__); + return -EINVAL; + break; + } + + return COPYBIT_SUCCESS; +} + +/** Get a static info value */ +static int get(struct copybit_device_t *dev, int name) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int value; + + if (!ctx) { + LOGE("%s: null context error", __func__); + return -EINVAL; + } + + switch(name) { + case COPYBIT_MINIFICATION_LIMIT: + value = MAX_SCALE_FACTOR; + break; + case COPYBIT_MAGNIFICATION_LIMIT: + value = MAX_SCALE_FACTOR; + break; + case COPYBIT_SCALING_FRAC_BITS: + value = 32; + break; + case COPYBIT_ROTATION_STEP_DEG: + value = 1; + break; + default: + LOGE("%s: default case", __func__); + value = -EINVAL; + } + return value; +} + +static int is_alpha(int cformat) +{ + int alpha = 0; + switch (cformat & 0xFF) { + case C2D_COLOR_FORMAT_8888_ARGB: + case C2D_COLOR_FORMAT_8888_RGBA: + case C2D_COLOR_FORMAT_5551_RGBA: + case C2D_COLOR_FORMAT_4444_ARGB: + alpha = 1; + break; + default: + alpha = 0; + break; + } + + if(alpha && (cformat&C2D_FORMAT_DISABLE_ALPHA)) + alpha = 0; + + return alpha; +} + +/** do a stretch blit type operation */ +static int stretch_copybit_internal( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_rect_t const *dst_rect, + struct copybit_rect_t const *src_rect, + struct copybit_region_t const *region, + bool enableBlend) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int status = COPYBIT_SUCCESS; + uint32 maxCount; + uint32 src_mapped = 0, trg_mapped = 0; + blitlist list; + C2D_OBJECT *req; + memset(&list, 0, sizeof(list)); + int cformat; + c2d_ts_handle timestamp; + uint32 surface_index = 0; + + if (!ctx) { + LOGE("%s: null context error", __func__); + return -EINVAL; + } + + if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION) { + LOGE("%s: src dimension error", __func__); + return -EINVAL; + } + + if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) { + LOGE("%s : dst dimension error dst w %d h %d", __func__, dst->w, dst->h); + return -EINVAL; + } + + maxCount = sizeof(list.blitObjects)/sizeof(C2D_OBJECT); + + struct copybit_rect_t clip; + list.count = 0; + + status = set_image(ctx->g12_device_fd, ctx->dst, dst, &cformat, &trg_mapped, ctx->isPremultipliedAlpha); + if(status) { + LOGE("%s: set_image error", __func__); + return COPYBIT_FAILURE; + } + + if(is_supported_rgb_format(src->format) == COPYBIT_SUCCESS) { + surface_index = RGB_SURFACE; + } else if (is_supported_yuv_format(src->format) == COPYBIT_SUCCESS) { + surface_index = YUV_SURFACE; + } else { + LOGE("%s: Invalid source surface format %x", __func__, src->format); + return -EINVAL; + } + + status = set_image(ctx->g12_device_fd, ctx->src[surface_index], src, &cformat, &src_mapped, ctx->isPremultipliedAlpha); + if(status) { + LOGE("%s: set_src_image error", __func__); + return COPYBIT_FAILURE; + } + + if (enableBlend) { + if(ctx->blitState.config_mask & C2D_GLOBAL_ALPHA_BIT) { + ctx->blitState.config_mask &= ~C2D_ALPHA_BLEND_NONE; + if(!(ctx->blitState.global_alpha)) { + // src alpha is zero + unset_image(ctx->g12_device_fd, ctx->src[surface_index], src, src_mapped); + unset_image(ctx->g12_device_fd, ctx->dst, dst, trg_mapped); + return status; + } + } else { + if(is_alpha(cformat)) + ctx->blitState.config_mask &= ~C2D_ALPHA_BLEND_NONE; + else + ctx->blitState.config_mask |= C2D_ALPHA_BLEND_NONE; + } + } else { + ctx->blitState.config_mask |= C2D_ALPHA_BLEND_NONE; + } + + ctx->blitState.surface_id = ctx->src[surface_index]; + + while ((status == 0) && region->next(region, &clip)) { + req = &(list.blitObjects[list.count]); + memcpy(req,&ctx->blitState,sizeof(C2D_OBJECT)); + + set_rects(ctx, req, dst_rect, src_rect, &clip); + + if (++list.count == maxCount) { + status = msm_copybit(ctx, &list, ctx->dst); + list.count = 0; + } + } + if ((status == 0) && list.count) { + status = msm_copybit(ctx, &list, ctx->dst); + } + + if(LINK_c2dFinish(ctx->dst)) { + LOGE("%s: LINK_c2dFinish ERROR", __func__); + } + + + unset_image(ctx->g12_device_fd, ctx->src[surface_index], src, src_mapped); + unset_image(ctx->g12_device_fd, ctx->dst, dst, trg_mapped); + ctx->isPremultipliedAlpha = false; + return status; +} + +static int stretch_copybit( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_rect_t const *dst_rect, + struct copybit_rect_t const *src_rect, + struct copybit_region_t const *region) +{ + return stretch_copybit_internal(dev, dst, src, dst_rect, src_rect, region, true); +} + +/** Perform a blit type operation */ +static int blit_copybit( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_region_t const *region) +{ + struct copybit_rect_t dr = { 0, 0, dst->w, dst->h }; + struct copybit_rect_t sr = { 0, 0, src->w, src->h }; + return stretch_copybit_internal(dev, dst, src, &dr, &sr, region, false); +} + +/*****************************************************************************/ + +/** Close the copybit device */ +static int close_copybit(struct hw_device_t *dev) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + if (ctx) { + LINK_c2dDestroySurface(ctx->dst); + for(int i = 0; i src[i]); + } + + if (ctx->libc2d2) { + ::dlclose(ctx->libc2d2); + LOGV("dlclose(libc2d2)"); + } + + if(ctx->g12_device_fd) + close(ctx->g12_device_fd); + free(ctx); + } + + return 0; +} + +/** Open a new instance of a copybit device using name */ +static int open_copybit(const struct hw_module_t* module, const char* name, + struct hw_device_t** device) +{ + int status = COPYBIT_SUCCESS; + C2D_RGB_SURFACE_DEF surfDefinition = {0}; + C2D_YUV_SURFACE_DEF yuvSurfaceDef = {0} ; + struct copybit_context_t *ctx; + char const * const device_template[] = { + "/dev/graphics/fb%u", + "/dev/fb%u", + 0 }; + + int fd = -1; + int i=0; + char fbName[64]; + + ctx = (struct copybit_context_t *)malloc(sizeof(struct copybit_context_t)); + if(!ctx) { + LOGE("%s: malloc failed", __func__); + return COPYBIT_FAILURE; + } + + /* initialize drawstate */ + memset(ctx, 0, sizeof(*ctx)); + + ctx->libc2d2 = ::dlopen("libC2D2.so", RTLD_NOW); + if (!ctx->libc2d2) { + LOGE("FATAL ERROR: could not dlopen libc2d2.so: %s", dlerror()); + goto error; + } + *(void **)&LINK_c2dCreateSurface = ::dlsym(ctx->libc2d2, + "c2dCreateSurface"); + *(void **)&LINK_c2dUpdateSurface = ::dlsym(ctx->libc2d2, + "c2dUpdateSurface"); + *(void **)&LINK_c2dReadSurface = ::dlsym(ctx->libc2d2, + "c2dReadSurface"); + *(void **)&LINK_c2dDraw = ::dlsym(ctx->libc2d2, "c2dDraw"); + *(void **)&LINK_c2dFlush = ::dlsym(ctx->libc2d2, "c2dFlush"); + *(void **)&LINK_c2dFinish = ::dlsym(ctx->libc2d2, "c2dFinish"); + *(void **)&LINK_c2dWaitTimestamp = ::dlsym(ctx->libc2d2, + "c2dWaitTimestamp"); + *(void **)&LINK_c2dDestroySurface = ::dlsym(ctx->libc2d2, + "c2dDestroySurface"); + + if(!LINK_c2dCreateSurface || !LINK_c2dUpdateSurface || !LINK_c2dReadSurface + || !LINK_c2dDraw || !LINK_c2dFlush || !LINK_c2dWaitTimestamp || !LINK_c2dFinish + || !LINK_c2dDestroySurface) { + LOGE("%s: dlsym ERROR", __func__); + goto error1; + } + + ctx->device.common.tag = HARDWARE_DEVICE_TAG; + ctx->device.common.version = 1; + ctx->device.common.module = (hw_module_t*)(module); + ctx->device.common.close = close_copybit; + ctx->device.set_parameter = set_parameter_copybit; + ctx->device.get = get; + ctx->device.blit = blit_copybit; + ctx->device.stretch = stretch_copybit; + ctx->blitState.config_mask = C2D_NO_BILINEAR_BIT | C2D_NO_ANTIALIASING_BIT; + ctx->trg_transform = C2D_TARGET_ROTATE_0; + ctx->g12_device_fd = open(G12_DEVICE_NAME, O_RDWR | O_SYNC); + if(ctx->g12_device_fd < 0) { + LOGE("%s: g12_device_fd open failed", __func__); + goto error1; + } + + /* Create RGB Surface */ + surfDefinition.buffer = (void*)0xdddddddd; + surfDefinition.phys = (void*)0xdddddddd; + surfDefinition.stride = 1 * 4; + surfDefinition.width = 1; + surfDefinition.height = 1; + surfDefinition.format = C2D_COLOR_FORMAT_8888_ARGB; + + if(LINK_c2dCreateSurface(&ctx->dst,C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | + C2D_SURFACE_WITH_PHYS), &surfDefinition)) { + LOGE("%s: create ctx->dst failed", __func__); + goto error2; + } + + if(LINK_c2dCreateSurface(&(ctx->src[RGB_SURFACE]), C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | + C2D_SURFACE_WITH_PHYS), &surfDefinition)) { + LOGE("%s: create ctx->src[RGB_SURFACE] failed", __func__); + goto error3; + } + + /* Create YUV source surface */ + yuvSurfaceDef.format = C2D_COLOR_FORMAT_420_NV12; + + yuvSurfaceDef.width = 4; + yuvSurfaceDef.height = 4; + yuvSurfaceDef.plane0 = (void*)0xaaaaaaaa; + yuvSurfaceDef.phys0 = (void*) 0xaaaaaaaa; + yuvSurfaceDef.stride0 = 4; + + yuvSurfaceDef.plane1 = (void*)0xaaaaaaaa; + yuvSurfaceDef.phys1 = (void*) 0xaaaaaaaa; + yuvSurfaceDef.stride1 = 4; + + if(LINK_c2dCreateSurface(&(ctx->src[YUV_SURFACE]),C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS), + &yuvSurfaceDef)) { + LOGE("%s: create ctx->src[YUV_SURFACE] failed", __func__); + goto error4; + } + + *device = &ctx->device.common; + + while ((fd==-1) && device_template[i]) { + snprintf(fbName, 64, device_template[i], 0); + fd = open(fbName, O_RDWR, 0); + i++; + } + if (fd < 0) + goto error5; + + struct fb_var_screeninfo info; + if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) + goto error6; + + ctx->fb_width = info.xres; + ctx->fb_height = info.yres; + close(fd); + ctx->isPremultipliedAlpha = false; + return status; + +error6: + close(fd); + fd = -1; +error5: + LINK_c2dDestroySurface(ctx->src[YUV_SURFACE]); +error4: + LINK_c2dDestroySurface(ctx->src[RGB_SURFACE]); +error3: + LINK_c2dDestroySurface(ctx->dst); +error2: + close(ctx->g12_device_fd); +error1: + ::dlclose(ctx->libc2d2); +error: + free(ctx); + status = COPYBIT_FAILURE; + *device = NULL; + + return status; +} diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk new file mode 100644 index 0000000..bd8c3e8 --- /dev/null +++ b/libgralloc/Android.mk @@ -0,0 +1,70 @@ +# 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. + +# Use this flag until pmem/ashmem is implemented in the new gralloc +ifeq ($(TARGET_USES_ION),true) +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 libGLESv1_CM libutils libmemalloc + +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +LOCAL_SRC_FILES := framebuffer.cpp \ + gpu.cpp \ + gralloc.cpp \ + mapper.cpp \ + pmemalloc.cpp \ + pmem_bestfit_alloc.cpp + +LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM) +LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" -DHOST -DDEBUG_CALC_FPS -DUSE_ION + +ifeq ($(call is-board-platform,msm7627_surf msm7627_6x),true) + LOCAL_CFLAGS += -DTARGET_MSM7x27 +endif + +ifeq ($(TARGET_HAVE_HDMI_OUT),true) + LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY + LOCAL_C_INCLUDES += hardware/msm7k/liboverlay + LOCAL_SHARED_LIBRARIES += liboverlay +endif + +ifeq ($(TARGET_USES_SF_BYPASS),true) + LOCAL_CFLAGS += -DSF_BYPASS +endif + +ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true) + LOCAL_CFLAGS += -DUSE_ASHMEM +endif +include $(BUILD_SHARED_LIBRARY) + +#MemAlloc Library +include $(CLEAR_VARS) +LOCAL_PRELINK_MODULE := false +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +LOCAL_SHARED_LIBRARIES := liblog libcutils libutils +LOCAL_SRC_FILES := ionalloc.cpp \ + ashmemalloc.cpp \ + alloc_controller.cpp +LOCAL_CFLAGS:= -DLOG_TAG=\"memalloc\" -DLOG_NDDEBUG=0 -DUSE_ION +LOCAL_MODULE := libmemalloc +include $(BUILD_SHARED_LIBRARY) +endif #TARGET_USES_ION diff --git a/libgralloc/MODULE_LICENSE_APACHE2 b/libgralloc/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 diff --git a/NOTICE b/libgralloc/NOTICE similarity index 100% rename from NOTICE rename to libgralloc/NOTICE diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp new file mode 100644 index 0000000..5cd07d3 --- /dev/null +++ b/libgralloc/alloc_controller.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "gralloc_priv.h" +#include "alloc_controller.h" +#include "memalloc.h" +#include "ionalloc.h" + +using namespace gralloc; +using android::sp; + +sp IAllocController::sController = NULL; +sp IAllocController::getInstance(void) +{ + if(sController == NULL) { +#ifdef USE_ION + sController = new IonController(); +#else + // XXX: Return pmem/ashmem controller when completed +#endif + } + return sController; +} + +IonController::IonController() +{ + mIonAlloc = new IonAlloc(); +} + +static bool canFallback(int compositionType, int usage, int flags) +{ + // Fallback to system heap when alloc fails unless + // 1. Composition type is MDP + // 2. Earlier alloc attempt was from system heap + // 3. Contiguous heap requsted explicitly + + if(compositionType == MDP_COMPOSITION) + return false; + if(flags & ION_HEAP_SYSTEM_ID) + return false; + if(usage &(GRALLOC_USAGE_PRIVATE_ADSP_HEAP| + GRALLOC_USAGE_PRIVATE_EBI_HEAP | + GRALLOC_USAGE_PRIVATE_SMI_HEAP)) + return false; + //Return true by default + return true; +} + +int IonController::allocate(alloc_data& data, int usage, + int compositionType) +{ + int ionFlags = 0; + int ret; + + //System heap cannot be uncached + if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED && + !(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP)) + data.uncached = true; + else + data.uncached = false; + + if(usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) + ionFlags |= 1 << ION_HEAP_ADSP_ID; + + if(usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP) + ionFlags |= 1 << ION_HEAP_SMI_ID; + + if(usage & GRALLOC_USAGE_PRIVATE_EBI_HEAP) + ionFlags |= 1 << ION_HEAP_EBI_ID; + + if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP) + ionFlags |= 1 << ION_HEAP_SYSTEM_ID; + + // if no flags are set, default to + // EBI heap, so that bypass can work + // we can fall back to system heap if + // we run out. + if(!ionFlags) + ionFlags = 1 << ION_HEAP_EBI_ID; + + data.flags = ionFlags; + ret = mIonAlloc->alloc_buffer(data); + + // Fallback + if(ret < 0 && canFallback(compositionType, usage, ionFlags)) { + LOGW("Falling back to system heap"); + data.flags = 1 << ION_HEAP_SYSTEM_ID; + ret = mIonAlloc->alloc_buffer(data); + } + + if(ret >= 0 ) + data.allocType = private_handle_t::PRIV_FLAGS_USES_ION; + + return ret; +} + +sp IonController::getAllocator(int flags) +{ + sp memalloc; + if (flags & private_handle_t::PRIV_FLAGS_USES_ION) { + memalloc = mIonAlloc; + } else { + LOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags); + } + + return memalloc; +} + +int PmemAshmemController::allocate(alloc_data& data, int usage, + int compositionType) +{ + //XXX PMEM with ashmem fallback strategy + return 0; +} + +sp PmemAshmemController::getAllocator(int flags) +{ + sp memalloc; + if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM) { + // XXX Return right allocator based on flags + memalloc = NULL; + } else { + LOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags); + memalloc = NULL; + } + + return memalloc; +} + + diff --git a/libgralloc/alloc_controller.h b/libgralloc/alloc_controller.h new file mode 100644 index 0000000..fbdd401 --- /dev/null +++ b/libgralloc/alloc_controller.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef GRALLOC_ALLOCCONTROLLER_H +#define GRALLOC_ALLOCCONTROLLER_H + +#include + +namespace gralloc { + + struct alloc_data; + class IMemAlloc; + class IonAlloc; + + class IAllocController : public android::RefBase { + + public: + /* Allocate using a suitable method + * Returns the type of buffer allocated + */ + virtual int allocate(alloc_data& data, int usage, + int compositionType) = 0; + + virtual android::sp getAllocator(int flags) = 0; + + virtual ~IAllocController() {}; + + static android::sp getInstance(void); + + private: + static android::sp sController; + + }; + + class IonController : public IAllocController { + + public: + virtual int allocate(alloc_data& data, int usage, + int compositionType); + + virtual android::sp getAllocator(int flags); + + IonController(); + + private: + android::sp mIonAlloc; + + }; + + class PmemAshmemController : public IAllocController { + + public: + virtual int allocate(alloc_data& data, int usage, + int compositionType); + + virtual android::sp getAllocator(int flags); + // XXX: Pmem and ashmem alloc objects + + }; + +} //end namespace gralloc +#endif // GRALLOC_ALLOCCONTROLLER_H diff --git a/libgralloc/ashmemalloc.cpp b/libgralloc/ashmemalloc.cpp new file mode 100644 index 0000000..e60137b --- /dev/null +++ b/libgralloc/ashmemalloc.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ashmemalloc.h" + +using gralloc::AshmemAlloc; +int AshmemAlloc::alloc_buffer(alloc_data& data) +{ + int err = 0; + int fd = -1; + void* base = 0; + int offset = 0; + char name[ASHMEM_NAME_LEN]; + snprintf(name, ASHMEM_NAME_LEN, "gralloc-buffer-%x", data.pHandle); + int prot = PROT_READ | PROT_WRITE; + fd = ashmem_create_region(name, data.size); + if (fd < 0) { + LOGE("couldn't create ashmem (%s)", strerror(errno)); + err = -errno; + } else { + if (ashmem_set_prot_region(fd, prot) < 0) { + LOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)", + fd, prot, strerror(errno)); + close(fd); + err = -errno; + } else { + base = mmap(0, data.size, prot, MAP_SHARED|MAP_POPULATE|MAP_LOCKED, fd, 0); + if (base == MAP_FAILED) { + LOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)", + fd, data.size, prot, strerror(errno)); + close(fd); + err = -errno; + } else { + memset((char*)base + offset, 0, data.size); + } + } + } + if(err == 0) { + data.fd = fd; + data.base = base; + data.offset = offset; + clean_buffer(base, data.size, offset, fd); + } + return err; + +} + +int AshmemAlloc::free_buffer(void* base, size_t size, int offset, int fd) +{ + LOGD("%s:Freeing buffer size=%d base=%p fd=%d PID=%d", + __FUNCTION__, size, base, fd, getpid()); + int err = 0; + + if(!base) { + LOGE("Invalid free"); + return -EINVAL; + } + err = unmap_buffer(base, size, offset); + close(fd); + return err; +} + +int AshmemAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) +{ + LOGD("%s: Mapping buffer fd=%d size=%d PID=%d", __FUNCTION__, + fd, size, getpid()); + int err = 0; + void *base = 0; + if (err) + return err; + + base = mmap(0, size, PROT_READ| PROT_WRITE, + MAP_SHARED, fd, 0); + *pBase = base; + if(base == MAP_FAILED) { + LOGD("%s: Failed to map memory in the client: %s", + __FUNCTION__, strerror(errno)); + err = -errno; + } else { + LOGD("%s: Successfully mapped %d bytes", __FUNCTION__, size); + } + return err; +} + +int AshmemAlloc::unmap_buffer(void *base, size_t size, int offset) +{ + LOGD("%s: Unmapping buffer at address %p", __FUNCTION__, base); + int err = munmap(base, size); + if(err) { + LOGE("%s: Failed to unmap memory at %p: %s", + __FUNCTION__, base, strerror(errno)); + } + return err; + +} +int AshmemAlloc::clean_buffer(void *base, size_t size, int offset, int fd) +{ + // LOGD("%s: Clean buffer fd=%d base = %p size=%d PID=%d", __FUNCTION__, + // fd, base, size, getpid()); + int err = 0; + if (ioctl(fd, ASHMEM_CACHE_INV_RANGE, NULL)) { + LOGE("ASHMEM_CACHE_INV_RANGE failed fd = %d", fd); + } + + return err; +} + diff --git a/libgralloc/ashmemalloc.h b/libgralloc/ashmemalloc.h new file mode 100644 index 0000000..051dcd1 --- /dev/null +++ b/libgralloc/ashmemalloc.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GRALLOC_ASHMEMALLOC_H +#define GRALLOC_ASHMEMALLOC_H + +#include "memalloc.h" +#include + +namespace gralloc { + class AshmemAlloc : public IMemAlloc { + + public: + virtual int alloc_buffer(alloc_data& data); + + virtual int free_buffer(void *base, size_t size, + int offset, int fd); + + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd); + + virtual int unmap_buffer(void *base, size_t size, + int offset); + + virtual int clean_buffer(void*base, size_t size, + int offset, int fd); + + }; +} +#endif /* GRALLOC_ASHMEMALLOC_H */ diff --git a/framebuffer.cpp b/libgralloc/framebuffer.cpp similarity index 72% rename from framebuffer.cpp rename to libgralloc/framebuffer.cpp index 1532ec1..8259f96 100644 --- a/framebuffer.cpp +++ b/libgralloc/framebuffer.cpp @@ -63,7 +63,6 @@ #define HEIGHT_480P 480 #define EVEN_OUT(x) if (x & 0x0001) {x--;} using overlay::Overlay; -using overlay::ActionSafe; /** min of int a, b */ static inline int min(int a, int b) { return (a( dev->common.module); @@ -177,9 +189,21 @@ static void populate_debug_fps_metadata(void) { char prop[PROPERTY_VALUE_MAX]; + /*defaults calculation of fps to based on number of frames*/ + property_get("debug.gr.calcfps.type", prop, "0"); + debug_fps_metadata.type = (debug_fps_metadata_t::DfmType) atoi(prop); + + /*defaults to 1000ms*/ + property_get("debug.gr.calcfps.timeperiod", prop, "1000"); + debug_fps_metadata.time_period = atoi(prop); + property_get("debug.gr.calcfps.period", prop, "10"); debug_fps_metadata.period = atoi(prop); + if (debug_fps_metadata.period > MAX_FPS_CALC_PERIOD_IN_FRAMES) { + debug_fps_metadata.period = MAX_FPS_CALC_PERIOD_IN_FRAMES; + } + /* default ignorethresh_us: 500 milli seconds */ property_get("debug.gr.calcfps.ignorethresh_us", prop, "500000"); debug_fps_metadata.ignorethresh_us = atoi(prop); @@ -203,6 +227,41 @@ static void populate_debug_fps_metadata(void) LOGE("ignorethresh_us: %lld", debug_fps_metadata.ignorethresh_us); } +static void print_fps(float fps) +{ + if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type) + LOGE("FPS for last %d frames: %3.2f", debug_fps_metadata.period, fps); + else + LOGE("FPS for last (%f ms, %d frames): %3.2f", + debug_fps_metadata.time_elapsed, + debug_fps_metadata.curr_frame, fps); + + debug_fps_metadata.curr_frame = 0; + debug_fps_metadata.time_elapsed = 0.0; + + if (debug_fps_level > 1) { + LOGE("Frame Arrival Distribution:"); + for (unsigned int i = 0; + i < ((debug_fps_metadata.framearrival_steps / 6) + 1); + i++) { + LOGE("%lld %lld %lld %lld %lld %lld", + debug_fps_metadata.accum_framearrivals[i*6], + debug_fps_metadata.accum_framearrivals[i*6+1], + debug_fps_metadata.accum_framearrivals[i*6+2], + debug_fps_metadata.accum_framearrivals[i*6+3], + debug_fps_metadata.accum_framearrivals[i*6+4], + debug_fps_metadata.accum_framearrivals[i*6+5]); + } + + /* We are done with displaying, now clear the stats */ + for (unsigned int i = 0; + i < debug_fps_metadata.framearrival_steps; + i++) + debug_fps_metadata.accum_framearrivals[i] = 0; + } + return; +} + static void calc_fps(nsecs_t currtime_us) { static nsecs_t oldtime_us = 0; @@ -211,41 +270,15 @@ static void calc_fps(nsecs_t currtime_us) oldtime_us = currtime_us; - if (diff > debug_fps_metadata.ignorethresh_us) { + if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type && + diff > debug_fps_metadata.ignorethresh_us) { return; } - if (debug_fps_metadata.curr_frame == debug_fps_metadata.period) { - /* time to calculate and display FPS */ - nsecs_t sum = 0; - for (unsigned int i = 0; i < debug_fps_metadata.period; i++) - sum += debug_fps_metadata.framearrivals[i]; - LOGE("FPS for last %d frames: %3.2f", debug_fps_metadata.period, - (debug_fps_metadata.period * float(1000000))/float(sum)); - - debug_fps_metadata.curr_frame = 0; - if (debug_fps_level > 1) { - LOGE("Frame Arrival Distribution:"); - for (unsigned int i = 0; - i < ((debug_fps_metadata.framearrival_steps / 6) + 1); - i++) { - LOGE("%lld %lld %lld %lld %lld %lld", - debug_fps_metadata.accum_framearrivals[i*6], - debug_fps_metadata.accum_framearrivals[i*6+1], - debug_fps_metadata.accum_framearrivals[i*6+2], - debug_fps_metadata.accum_framearrivals[i*6+3], - debug_fps_metadata.accum_framearrivals[i*6+4], - debug_fps_metadata.accum_framearrivals[i*6+5]); - } - - /* We are done with displaying, now clear the stats */ - for (unsigned int i = 0; i < debug_fps_metadata.framearrival_steps; i++) - debug_fps_metadata.accum_framearrivals[i] = 0; - } + if (debug_fps_metadata.curr_frame < MAX_FPS_CALC_PERIOD_IN_FRAMES) { + debug_fps_metadata.framearrivals[debug_fps_metadata.curr_frame++] = diff; } - debug_fps_metadata.framearrivals[debug_fps_metadata.curr_frame++] = diff; - if (debug_fps_level > 1) { unsigned int currstep = (diff + debug_fps_metadata.margin_us) / 16666; @@ -253,6 +286,25 @@ static void calc_fps(nsecs_t currtime_us) debug_fps_metadata.accum_framearrivals[currstep-1]++; } } + + if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type) { + if (debug_fps_metadata.curr_frame == debug_fps_metadata.period) { + /* time to calculate and display FPS */ + nsecs_t sum = 0; + for (unsigned int i = 0; i < debug_fps_metadata.period; i++) + sum += debug_fps_metadata.framearrivals[i]; + print_fps((debug_fps_metadata.period * float(1000000))/float(sum)); + } + } + else if (debug_fps_metadata_t::DFM_TIME == debug_fps_metadata.type) { + debug_fps_metadata.time_elapsed += ((float)diff/1000.0); + if (debug_fps_metadata.time_elapsed >= debug_fps_metadata.time_period) { + float fps = (1000.0 * debug_fps_metadata.curr_frame)/ + (float)debug_fps_metadata.time_elapsed; + print_fps(fps); + } + } + return; } #endif // DEBUG_CALC_FPS @@ -299,23 +351,6 @@ static void *disp_loop(void *ptr) if (debug_fps_level > 0) calc_fps(ns2us(systemTime())); #endif -#if defined(SF_BYPASS) - /* - * Comp. bypass sepcific. - * Close the bypass channel if PENDING_CLOSE. - * We require this code here because - - * disp_loop can only guarantee push of FB - */ - pthread_mutex_lock(&m->overlayui_lock); - if (m->bypassChannelState == BYPASS_OV_CHANNEL_PENDING_CLOSE) { - if (m->pobjOverlayUI) { - m->pobjOverlayUI->closeChannel(); - } - m->bypassChannelState = BYPASS_OV_CHANNEL_CLOSED; - } - pthread_mutex_unlock(&m->overlayui_lock); -#endif - if (cur_buf == -1) { int nxtAvail = ((nxtBuf.idx + 1) % m->numBuffers); pthread_mutex_lock(&(m->avail[nxtBuf.idx].lock)); @@ -350,16 +385,11 @@ static void *disp_loop(void *ptr) } #if defined(HDMI_DUAL_DISPLAY) -static int postOrigResHDMI(private_module_t *); static void *hdmi_ui_loop(void *ptr) { private_module_t* m = reinterpret_cast( ptr); while (1) { - if(m->isOrigResStarted) { - postOrigResHDMI(m); - continue; - } pthread_mutex_lock(&m->overlayLock); while(!(m->hdmiStateChanged)) pthread_cond_wait(&(m->overlayPost), &(m->overlayLock)); @@ -368,19 +398,27 @@ static void *hdmi_ui_loop(void *ptr) pthread_mutex_unlock(&m->overlayLock); return NULL; } - float asWidthRatio = ActionSafe::getWidthRatio() / 100.0f; - float asHeightRatio = ActionSafe::getHeightRatio() / 100.0f; + float asWidthRatio = m->actionsafeWidthRatio/100.0f; + float asHeightRatio = m->actionsafeHeightRatio/100.0f; if (m->pobjOverlay) { Overlay* pTemp = m->pobjOverlay; if (!m->enableHDMIOutput) pTemp->closeChannel(); - else if (m->enableHDMIOutput && !m->videoOverlay && - !(m->isOrigResStarted)) { + else if (m->enableHDMIOutput && !m->videoOverlay) { if (!pTemp->isChannelUP()) { - int alignedW = ALIGN(m->info.xres, 32); - if (pTemp->startChannel(alignedW, m->info.yres, - m->fbFormat, 1, false, true, 0, VG0_PIPE, true)) { + int alignedW = ALIGN(m->info.xres, 32); + + private_handle_t const* hnd = + reinterpret_cast(m->framebuffer); + overlay_buffer_info info; + info.width = alignedW; + info.height = hnd->height; + info.format = hnd->format; + info.size = hnd->size; + + if (pTemp->startChannel(info, 1, + false, true, 0, VG0_PIPE, true)) { pTemp->setFd(m->framebuffer->fd); pTemp->setCrop(0, 0, m->info.xres, m->info.yres); } else @@ -523,18 +561,34 @@ static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int enable) dev->common.module); pthread_mutex_lock(&m->overlayLock); Overlay* pTemp = m->pobjOverlay; - m->enableHDMIOutput = enable; - if(m->isOrigResStarted) { - m->ts.isHDMIExitPending = !enable; - } else if (!enable && pTemp) { + if (!enable && pTemp) pTemp->closeChannel(); - } + m->enableHDMIOutput = enable; m->hdmiStateChanged = true; pthread_cond_signal(&(m->overlayPost)); pthread_mutex_unlock(&m->overlayLock); return 0; } +static int fb_setActionSafeWidthRatio(struct framebuffer_device_t* dev, float asWidthRatio) +{ + private_module_t* m = reinterpret_cast( + dev->common.module); + pthread_mutex_lock(&m->overlayLock); + m->actionsafeWidthRatio = asWidthRatio; + pthread_mutex_unlock(&m->overlayLock); + return 0; +} + +static int fb_setActionSafeHeightRatio(struct framebuffer_device_t* dev, float asHeightRatio) +{ + private_module_t* m = reinterpret_cast( + dev->common.module); + pthread_mutex_lock(&m->overlayLock); + m->actionsafeHeightRatio = asHeightRatio; + pthread_mutex_unlock(&m->overlayLock); + return 0; +} static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientation) { private_module_t* m = reinterpret_cast( @@ -544,215 +598,6 @@ static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientati pthread_mutex_unlock(&m->overlayLock); return 0; } - -/* Posts buffers in their original resolution to secondary. - */ -static int postOrigResHDMI(private_module_t* m) { - int w, h, format; - buffer_handle_t buffer; - int ret = NO_ERROR; - - //Wait for new buffer call and read values - pthread_mutex_lock(&m->ts.newBufferMutex); - while(m->ts.isNewBuffer == false) { - pthread_cond_wait(&m->ts.newBufferCond, &m->ts.newBufferMutex); - } - m->ts.get(w,h,format,buffer); - m->ts.isNewBuffer = false; - pthread_mutex_unlock(&m->ts.newBufferMutex); - - //Post them to secondary - if(m->enableHDMIOutput) { - const int orientation = 0; - ret = m->pOrigResTV->setSource(w, h, format, orientation); - if(ret == NO_ERROR) { - m->pOrigResTV->setPosition(); - ret = m->pOrigResTV->queueBuffer(buffer); - } - if(ret != NO_ERROR) - LOGE("Posting original resolution surface to secondary failed"); - } - //Signal that we posted the buffer - pthread_mutex_lock(&m->ts.bufferPostedMutex); - m->ts.isBufferPosted = true; - pthread_cond_signal(&m->ts.bufferPostedCond); - pthread_mutex_unlock(&m->ts.bufferPostedMutex); - if(m->ts.isExitPending || m->ts.isHDMIExitPending) { - m->pOrigResTV->closeChannel(); - } - return ret; -} - - -/* Posts buffers in their original resolution to primary. - */ -static int fb_postOrigResBuffer(struct framebuffer_device_t* dev, - buffer_handle_t buffer, int w, - int h, int format, int orientation) { - private_module_t* m = reinterpret_cast( - dev->common.module); - int ret = NO_ERROR; - if (m->isOrigResStarted) { - //Share new values - pthread_mutex_lock(&m->ts.newBufferMutex); - m->ts.set(w,h,format,buffer); - m->ts.isNewBuffer = true; - pthread_cond_signal(&m->ts.newBufferCond); - pthread_mutex_unlock(&m->ts.newBufferMutex); - - ret = m->pOrigResPanel->setSource(w, h, format, orientation); - if(ret == NO_ERROR) { - ret = m->pOrigResPanel->queueBuffer(buffer); - } - if(ret != NO_ERROR) - LOGE("Posting original resolution surface to primary failed"); - - //Wait for HDMI to post buffers - pthread_mutex_lock(&m->ts.bufferPostedMutex); - while(m->ts.isBufferPosted == false) { - pthread_cond_wait(&m->ts.bufferPostedCond, - &m->ts.bufferPostedMutex); - } - m->ts.isBufferPosted = false; - pthread_mutex_unlock(&m->ts.bufferPostedMutex); - } - if(m->ts.isExitPending) { - m->pOrigResPanel->closeChannel(); - } - return ret; -} - -static int fb_startOrigResDisplay(struct framebuffer_device_t* dev) { - private_module_t* m = reinterpret_cast( - dev->common.module); - int ret = NO_ERROR; - dev->videoOverlayStarted(dev, true); - m->ts.clear(); - m->isOrigResStarted = true; - return ret; -} - -static int fb_stopOrigResDisplay(struct framebuffer_device_t* dev) { - private_module_t* m = reinterpret_cast( - dev->common.module); - int ret = NO_ERROR; - m->isOrigResStarted = false; - m->ts.isExitPending = true; - //Free the threads - m->ts.isNewBuffer = true; - m->ts.isBufferPosted = true; - pthread_cond_signal(&m->ts.newBufferCond); - pthread_cond_signal(&m->ts.bufferPostedCond); - m->pOrigResPanel->closeChannel(); - m->pOrigResTV->closeChannel(); - dev->videoOverlayStarted(dev, false); - return ret; -} - -#endif - -#if defined(SF_BYPASS) -/* - * function: fb_postBypassBuffer - * Input: framebuffer device pointer, buffer handle, width - * height, format, orientation and HPD state - * Return Value: Result of posting the bypass buffer. - * NO_ERROR - Success in pushing the buffer - * Works as following: - * Currently, if HPD is on, bypass feature is disabled. - * If Bypass channel state is PENDING CLOSE, dont push the buffer - * Else, push the buffer with following two steps - * 1) Set the source geometery - * 2) queue the buffer - * Set the bypass channel state as OPEN if we try to push the buffer - */ -static int fb_postBypassBuffer(struct framebuffer_device_t* dev, - buffer_handle_t buffer, int w, - int h, int format, int orientation, int isHPDON) -{ - if (isHPDON) - return -EINVAL; - - private_module_t* m = reinterpret_cast( - dev->common.module); - if (m->pobjOverlayUI) { - - pthread_mutex_lock(&m->overlayui_lock); - if (m->bypassChannelState == BYPASS_OV_CHANNEL_PENDING_CLOSE) { - pthread_mutex_unlock(&m->overlayui_lock); - return NO_INIT; - } - - pthread_mutex_unlock(&m->overlayui_lock); - - OverlayUI* pobjOverlay = m->pobjOverlayUI; - if (buffer == NULL) - return -EINVAL; - - bool useVGPipe = false; - - status_t ret = pobjOverlay->setSource(w, h, format, orientation, useVGPipe); - if (ret != NO_ERROR) - return ret; - - ret = pobjOverlay->queueBuffer(buffer); - - if (ret != NO_ERROR) - LOGE("error in queue.. "); - m->bypassChannelState = BYPASS_OV_CHANNEL_OPEN; - return ret; - } - return NO_INIT; -} - -/* - * function: fb_closeBypass - * Input: Framebuffer device pointer - * Its only job is to set the bypassChannelState to PENDING_CLOSE. - * so that disp_loop could close the channel when a post happens - */ - -static int fb_closeBypass(struct framebuffer_device_t* dev) -{ - private_module_t* m = reinterpret_cast( - dev->common.module); - if (m->pobjOverlayUI) { - pthread_mutex_lock(&m->overlayui_lock); - m->bypassChannelState = BYPASS_OV_CHANNEL_PENDING_CLOSE; - pthread_mutex_unlock(&m->overlayui_lock); - } - - return NO_ERROR; -} - -/* - * function: fb_copyBypassBuffer - * Input: Framebuffer device pointer - * This function is to copy the bypass buffer. - * This function is required because: - * Before closing the bypass channel - * MDP read buffer pointer need to be changed - * so that application buffer could be released - * It calls on to OverlayUI::copyBuffer for the same - */ - -static int fb_copyBypassBuffer(struct framebuffer_device_t* dev) -{ - private_module_t* m = reinterpret_cast( - dev->common.module); - status_t ret = NO_ERROR; - if (m->pobjOverlayUI) { - pthread_mutex_lock(&m->overlayui_lock); - if (m->bypassChannelState != BYPASS_OV_CHANNEL_PENDING_CLOSE) { - OverlayUI* pobjOverlay = m->pobjOverlayUI; - ret = pobjOverlay->copyBuffer(); - } - pthread_mutex_unlock(&m->overlayui_lock); - } - - return ret; -} - #endif static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) @@ -817,26 +662,11 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) pthread_cond_signal(&(m->qpost)); pthread_mutex_unlock(&(m->qlock)); - // LCDC: after new buffer grabbed by MDP can unlock previous - // (current) buffer - if (m->currentBuffer) { - if (m->swapInterval != 0) { - pthread_mutex_lock(&(m->avail[futureIdx].lock)); - //while (! m->avail[futureIdx].is_avail) { - while (m->avail[futureIdx].state != AVL) { - pthread_cond_wait(&(m->avail[futureIdx].cond), - &(m->avail[futureIdx].lock)); - //m->avail[futureIdx].is_avail = true; - } - pthread_mutex_unlock(&(m->avail[futureIdx].lock)); - } + if (m->currentBuffer) m->base.unlock(&m->base, m->currentBuffer); - } + m->currentBuffer = buffer; m->currentIdx = nxtIdx; - if (m->avail[futureIdx].state != AVL) { - LOGE_IF(m->swapInterval != 0, "[%d] != AVL!", futureIdx); - } } else { if (m->currentBuffer) m->base.unlock(&m->base, m->currentBuffer); @@ -849,14 +679,13 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) } else { void* fb_vaddr; void* buffer_vaddr; - - m->base.lock(&m->base, m->framebuffer, - GRALLOC_USAGE_SW_WRITE_RARELY, + 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, + m->base.lock(&m->base, buffer, + GRALLOC_USAGE_SW_READ_RARELY, 0, 0, m->info.xres, m->info.yres, &buffer_vaddr); @@ -868,8 +697,8 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) m->info.xoffset, m->info.yoffset, m->info.width, m->info.height); - m->base.unlock(&m->base, buffer); - m->base.unlock(&m->base, m->framebuffer); + m->base.unlock(&m->base, buffer); + m->base.unlock(&m->base, m->framebuffer); } LOGD_IF(FB_DEBUG, "Framebuffer state: [0] = %c [1] = %c [2] = %c", @@ -887,7 +716,7 @@ static int fb_compositionComplete(struct framebuffer_device_t* dev) return 0; } -static int fb_dequeueBuffer(struct framebuffer_device_t* dev, int index) +static int fb_lockBuffer(struct framebuffer_device_t* dev, int index) { private_module_t* m = reinterpret_cast( dev->common.module); @@ -914,7 +743,6 @@ int mapFrameBufferLocked(struct private_module_t* module) if (module->framebuffer) { return 0; } - char const * const device_template[] = { "/dev/graphics/fb%u", "/dev/fb%u", @@ -956,42 +784,42 @@ int mapFrameBufferLocked(struct private_module_t* module) */ if(info.bits_per_pixel == 32) { - /* - * Explicitly request RGBA_8888 - */ - info.bits_per_pixel = 32; - info.red.offset = 24; - info.red.length = 8; - info.green.offset = 16; - info.green.length = 8; - info.blue.offset = 8; - info.blue.length = 8; - info.transp.offset = 0; - info.transp.length = 8; + /* + * Explicitly request RGBA_8888 + */ + info.bits_per_pixel = 32; + info.red.offset = 24; + info.red.length = 8; + info.green.offset = 16; + info.green.length = 8; + info.blue.offset = 8; + info.blue.length = 8; + info.transp.offset = 0; + info.transp.length = 8; - /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do - * not use the MDP for composition (i.e. hw composition == 0), ask for - * RGBA instead of RGBX. */ - if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0) - module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; - else if(property_get("debug.composition.type", property, NULL) > 0 && (strncmp(property, "mdp", 3) == 0)) - module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; - else - module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888; + /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do + * not use the MDP for composition (i.e. hw composition == 0), ask for + * RGBA instead of RGBX. */ + if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0) + module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; + else if(property_get("debug.composition.type", property, NULL) > 0 && (strncmp(property, "mdp", 3) == 0)) + module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; + else + module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888; } else { - /* - * 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; - module->fbFormat = HAL_PIXEL_FORMAT_RGB_565; + /* + * 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; + module->fbFormat = HAL_PIXEL_FORMAT_RGB_565; } /* * Request NUM_BUFFERS screens (at lest 2 for page flipping) @@ -1125,7 +953,7 @@ int mapFrameBufferLocked(struct private_module_t* module) pthread_cond_init(&(module->avail[i].cond), NULL); module->avail[i].is_avail = true; module->avail[i].state = AVL; - } + } /* create display update thread */ pthread_t thread1; @@ -1139,8 +967,8 @@ int mapFrameBufferLocked(struct private_module_t* module) int err; size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual); - module->framebuffer = new private_handle_t(fd, fbSize, - private_handle_t::PRIV_FLAGS_USES_PMEM); + module->framebuffer = new private_handle_t(dup(fd), fbSize, + private_handle_t::PRIV_FLAGS_USES_PMEM, BUFFER_TYPE_UI, module->fbFormat, info.xres, info.yres); module->numBuffers = info.yres_virtual / info.yres; module->bufferMask = 0; @@ -1163,16 +991,6 @@ int mapFrameBufferLocked(struct private_module_t* module) module->hdmiStateChanged = false; pthread_t hdmiUIThread; pthread_create(&hdmiUIThread, NULL, &hdmi_ui_loop, (void *) module); - module->pOrigResPanel = new OverlayOrigRes(); - module->pOrigResTV = new OverlayOrigRes(); - module->isOrigResStarted = false; - -#endif - -#if defined(SF_BYPASS) - module->pobjOverlayUI = new OverlayUI(); - module->bypassChannelState = BYPASS_OV_CHANNEL_CLOSED; - pthread_mutex_init(&(module->overlayui_lock), NULL); #endif return 0; @@ -1198,13 +1016,6 @@ static int fb_close(struct hw_device_t *dev) m->exitHDMIUILoop = true; pthread_cond_signal(&(m->overlayPost)); pthread_mutex_unlock(&m->overlayLock); - delete m->pOrigResPanel; - delete m->pOrigResTV; -#endif - -#if defined(SF_BYPASS) - delete m->pobjOverlayUI; - m->pobjOverlayUI = 0; #endif if (ctx) { free(ctx); @@ -1235,20 +1046,13 @@ int fb_device_open(hw_module_t const* module, const char* name, dev->device.post = fb_post; dev->device.setUpdateRect = 0; dev->device.compositionComplete = fb_compositionComplete; - dev->device.dequeueBuffer = fb_dequeueBuffer; + dev->device.lockBuffer = fb_lockBuffer; #if defined(HDMI_DUAL_DISPLAY) dev->device.orientationChanged = fb_orientationChanged; dev->device.videoOverlayStarted = fb_videoOverlayStarted; dev->device.enableHDMIOutput = fb_enableHDMIOutput; - dev->device.postOrigResBuffer = fb_postOrigResBuffer; - dev->device.startOrigResDisplay = fb_startOrigResDisplay; - dev->device.stopOrigResDisplay = fb_stopOrigResDisplay; -#endif - -#if defined(SF_BYPASS) - dev->device.postBypassBuffer = fb_postBypassBuffer; - dev->device.closeBypass = fb_closeBypass; - dev->device.copyBypassBuffer = fb_copyBypassBuffer; + dev->device.setActionSafeWidthRatio = fb_setActionSafeWidthRatio; + dev->device.setActionSafeHeightRatio = fb_setActionSafeHeightRatio; #endif private_module_t* m = (private_module_t*)module; @@ -1310,7 +1114,7 @@ msm_copy_buffer(buffer_handle_t handle, int fd, blit.req.dst.width = width; blit.req.dst.height = height; blit.req.dst.offset = 0; - blit.req.dst.memory_id = fd; + blit.req.dst.memory_id = fd; blit.req.dst.format = format; blit.req.src_rect.x = blit.req.dst_rect.x = x; diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp new file mode 100644 index 0000000..135d84f --- /dev/null +++ b/libgralloc/gpu.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (c) 2011 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 +#include +#include +#include +#include + +#include "gr.h" +#include "gpu.h" +#include "memalloc.h" +#include "alloc_controller.h" + +static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; +static const int QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03; +static const int QOMX_INTERLACE_FLAG = 0x49283654; +static const int QOMX_3D_VIDEO_FLAG = 0x23784238; + +using namespace gralloc; +using android::sp; + +gpu_context_t::gpu_context_t(const private_module_t* module, + sp alloc_ctrl ) : + mAllocCtrl(alloc_ctrl) +{ + // Zero out the alloc_device_t + memset(static_cast(this), 0, sizeof(alloc_device_t)); + + char property[PROPERTY_VALUE_MAX]; + if (property_get("debug.sf.hw", property, NULL) > 0) { + if(atoi(property) == 0) { + //debug.sf.hw = 0 + compositionType = CPU_COMPOSITION; + } else { //debug.sf.hw = 1 + // Get the composition type + property_get("debug.composition.type", property, NULL); + if (property == NULL) { + compositionType = GPU_COMPOSITION; + } else if ((strncmp(property, "mdp", 3)) == 0) { + compositionType = MDP_COMPOSITION; + } else if ((strncmp(property, "c2d", 3)) == 0) { + compositionType = C2D_COMPOSITION; + } else { + compositionType = GPU_COMPOSITION; + } + } + } else { //debug.sf.hw is not set. Use cpu composition + compositionType = CPU_COMPOSITION; + } + + // Initialize the procs + common.tag = HARDWARE_DEVICE_TAG; + common.version = 0; + common.module = const_cast(&module->base.common); + common.close = gralloc_close; + alloc = gralloc_alloc; + allocSize = gralloc_alloc_size; + free = gralloc_free; + +} + +int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage, + buffer_handle_t* pHandle) +{ + private_module_t* m = reinterpret_cast(common.module); + + // we don't support allocations with both the FB and PMEM_ADSP flags + if (usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) { + return -EINVAL; + } + + if (m->framebuffer == NULL) { + LOGE("%s: Invalid framebuffer", __FUNCTION__); + return -EINVAL; + } + + 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(bufferSize, newUsage, pHandle, BUFFER_TYPE_UI, + m->fbFormat, m->info.xres, m->info.yres); + } + + if (bufferMask >= ((1LU<framebuffer->base); + private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), bufferSize, + private_handle_t::PRIV_FLAGS_USES_PMEM | + private_handle_t::PRIV_FLAGS_FRAMEBUFFER, + BUFFER_TYPE_UI, m->fbFormat, m->info.xres, + m->info.yres); + + // 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; +} + + +int gpu_context_t::gralloc_alloc_framebuffer(size_t size, int usage, + buffer_handle_t* pHandle) +{ + private_module_t* m = reinterpret_cast(common.module); + pthread_mutex_lock(&m->lock); + int err = gralloc_alloc_framebuffer_locked(size, usage, pHandle); + pthread_mutex_unlock(&m->lock); + return err; +} + +int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, + buffer_handle_t* pHandle, int bufferType, + int format, int width, int height) +{ + int err = 0; + int flags = 0; + size = roundUpToPageSize(size); + alloc_data data; + data.offset = 0; + data.fd = -1; + data.base = 0; + data.size = size; + if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) + data.align = 8192; + else + data.align = getpagesize(); + data.pHandle = (unsigned int) pHandle; + data.bufferType = bufferType; + err = mAllocCtrl->allocate(data, usage, compositionType); + + if (err == 0) { + flags |= data.allocType; + private_handle_t* hnd = new private_handle_t(data.fd, size, flags, + bufferType, format, width, height); + + hnd->offset = data.offset; + hnd->base = int(data.base) + data.offset; + hnd->lockState = private_handle_t::LOCK_STATE_MAPPED; + *pHandle = hnd; + } + + LOGE_IF(err, "gralloc failed err=%s", strerror(-err)); + return err; +} + +static inline size_t ALIGN(size_t x, size_t align) { + return (x + align-1) & ~(align-1); +} + +void gpu_context_t::getGrallocInformationFromFormat(int inputFormat, + int *colorFormat, + int *bufferType) +{ + *bufferType = BUFFER_TYPE_VIDEO; + *colorFormat = inputFormat; + + if (inputFormat == HAL_PIXEL_FORMAT_YV12) { + *bufferType = BUFFER_TYPE_VIDEO; + } else if (inputFormat & S3D_FORMAT_MASK) { + // S3D format + *colorFormat = COLOR_FORMAT(inputFormat); + } else if (inputFormat & INTERLACE_MASK) { + // Interlaced + *colorFormat = inputFormat ^ HAL_PIXEL_FORMAT_INTERLACE; + } else if (inputFormat < 0x7) { + // RGB formats + *colorFormat = inputFormat; + *bufferType = BUFFER_TYPE_UI; + } else if ((inputFormat == HAL_PIXEL_FORMAT_R_8) || + (inputFormat == HAL_PIXEL_FORMAT_RG_88)) { + *colorFormat = inputFormat; + *bufferType = BUFFER_TYPE_UI; + } +} + +int gpu_context_t::alloc_impl(int w, int h, int format, int usage, + buffer_handle_t* pHandle, int* pStride, size_t bufferSize) { + if (!pHandle || !pStride) + return -EINVAL; + + size_t size, alignedw, alignedh; + + alignedw = ALIGN(w, 32); + alignedh = ALIGN(h, 32); + int colorFormat, bufferType; + getGrallocInformationFromFormat(format, &colorFormat, &bufferType); + switch (colorFormat) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + size = alignedw * alignedh * 4; + break; + case HAL_PIXEL_FORMAT_RGB_888: + size = alignedw * alignedh * 3; + break; + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + size = alignedw * alignedh * 2; + break; + + // adreno formats + case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: // NV21 + size = ALIGN(alignedw*alignedh, 4096); + size += ALIGN(2 * ALIGN(w/2, 32) * ALIGN(h/2, 32), 4096); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: // NV12 + // The chroma plane is subsampled, + // but the pitch in bytes is unchanged + // The GPU needs 4K alignment, but the video decoder needs 8K + alignedw = ALIGN(w, 128); + size = ALIGN( alignedw * alignedh, 8192); + size += ALIGN( alignedw * ALIGN(h/2, 32), 8192); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YV12: + if ((w&1) || (h&1)) { + LOGE("w or h is odd for the YUV format"); + return -EINVAL; + } + alignedw = ALIGN(w, 16); + alignedh = h; + size = alignedw*alignedh + + (ALIGN(alignedw/2, 16) * (alignedh/2))*2; + size = ALIGN(size, 4096); + break; + + default: + LOGE("unrecognized pixel format: %d", format); + return -EINVAL; + } + + if ((ssize_t)size <= 0) + return -EINVAL; + + size = (bufferSize >= size)? bufferSize : size; + + // All buffers marked as protected or for external + // display need to go to overlay + if ((usage & GRALLOC_USAGE_EXTERNAL_DISP) || + (usage & GRALLOC_USAGE_PROTECTED)) { + bufferType = BUFFER_TYPE_VIDEO; + } + int err; + if (usage & GRALLOC_USAGE_HW_FB) { + err = gralloc_alloc_framebuffer(size, usage, pHandle); + } else { + err = gralloc_alloc_buffer(size, usage, pHandle, bufferType, + format, alignedw, alignedh); + } + + if (err < 0) { + return err; + } + + *pStride = alignedw; + return 0; +} + +int gpu_context_t::free_impl(private_handle_t const* hnd) { + private_module_t* m = reinterpret_cast(common.module); + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + // free this buffer + const size_t bufferSize = m->finfo.line_length * m->info.yres; + int index = (hnd->base - m->framebuffer->base) / bufferSize; + m->bufferMask &= ~(1< memalloc = mAllocCtrl->getAllocator(hnd->flags); + int err = memalloc->free_buffer((void*)hnd->base, (size_t) hnd->size, + hnd->offset, hnd->fd); + if(err) + return err; + } + // XXX any additional cleanup. + delete hnd; + return 0; +} + +int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format, + int usage, buffer_handle_t* pHandle, int* pStride) +{ + if (!dev) { + return -EINVAL; + } + gpu_context_t* gpu = reinterpret_cast(dev); + return gpu->alloc_impl(w, h, format, usage, pHandle, pStride, 0); +} +int gpu_context_t::gralloc_alloc_size(alloc_device_t* dev, int w, int h, int format, + int usage, buffer_handle_t* pHandle, int* pStride, int bufferSize) +{ + if (!dev) { + return -EINVAL; + } + gpu_context_t* gpu = reinterpret_cast(dev); + return gpu->alloc_impl(w, h, format, usage, pHandle, pStride, bufferSize); +} + + +int gpu_context_t::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); + gpu_context_t* gpu = reinterpret_cast(dev); + return gpu->free_impl(hnd); +} + +/*****************************************************************************/ + +int gpu_context_t::gralloc_close(struct hw_device_t *dev) +{ + gpu_context_t* ctx = reinterpret_cast(dev); + if (ctx) { + /* TODO: keep a list of all buffer_handle_t created, and free them + * all here. + */ + delete ctx; + } + return 0; +} + diff --git a/libgralloc/gpu.h b/libgralloc/gpu.h new file mode 100644 index 0000000..301c411 --- /dev/null +++ b/libgralloc/gpu.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2011 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 GRALLOC_GPU_H_ +#define GRALLOC_GPU_H_ + +#include +#include +#include +#include + +#include +#include +#include + +#include "gralloc_priv.h" + +namespace gralloc { + class IAllocController; + class gpu_context_t : public alloc_device_t { + public: + gpu_context_t(const private_module_t* module, + android::spalloc_ctrl); + + int gralloc_alloc_framebuffer_locked(size_t size, int usage, + buffer_handle_t* pHandle); + + int gralloc_alloc_framebuffer(size_t size, int usage, + buffer_handle_t* pHandle); + + int gralloc_alloc_buffer(size_t size, int usage, + buffer_handle_t* pHandle, + int bufferType, int format, + int width, int height); + + int free_impl(private_handle_t const* hnd); + + int alloc_impl(int w, int h, int format, int usage, + buffer_handle_t* pHandle, int* pStride, + size_t bufferSize = 0); + + static int gralloc_alloc(alloc_device_t* dev, int w, int h, + int format, int usage, + buffer_handle_t* pHandle, + int* pStride); + + static int gralloc_free(alloc_device_t* dev, buffer_handle_t handle); + + static int gralloc_alloc_size(alloc_device_t* dev, + int w, int h, int format, + int usage, buffer_handle_t* pHandle, + int* pStride, int bufferSize); + + static int gralloc_close(struct hw_device_t *dev); + + int get_composition_type() const { return compositionType; } + + + private: + android::sp mAllocCtrl; + int compositionType; + void getGrallocInformationFromFormat(int inputFormat, + int *colorFormat, + int *bufferType); + }; +} +#endif // GRALLOC_GPU_H diff --git a/gr.h b/libgralloc/gr.h similarity index 97% rename from gr.h rename to libgralloc/gr.h index 49a0513..034a546 100644 --- a/gr.h +++ b/libgralloc/gr.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2011 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. diff --git a/libgralloc/gralloc.cpp b/libgralloc/gralloc.cpp new file mode 100644 index 0000000..640b255 --- /dev/null +++ b/libgralloc/gralloc.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2008, The Android Open Source Project + * Copyright (c) 2011, 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 +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "gr.h" +#include "gpu.h" +#include "memalloc.h" +#include "alloc_controller.h" + +using namespace gralloc; +using android::sp; + +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); + +extern int gralloc_perform(struct gralloc_module_t const* module, + int operation, ... ); + +// HAL module methods +static struct hw_module_methods_t gralloc_module_methods = { + open: gralloc_device_open +}; + +// HAL module initialize +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, + dso: 0, + reserved: {0}, + }, + registerBuffer: gralloc_register_buffer, + unregisterBuffer: gralloc_unregister_buffer, + lock: gralloc_lock, + unlock: gralloc_unlock, + perform: gralloc_perform, + reserved_proc: {0}, + }, + framebuffer: 0, + fbFormat: 0, + flags: 0, + numBuffers: 0, + bufferMask: 0, + lock: PTHREAD_MUTEX_INITIALIZER, + currentBuffer: 0, +}; + +// Open Gralloc device +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)) { + const private_module_t* m = reinterpret_cast( + module); + gpu_context_t *dev; + sp alloc_ctrl = IAllocController::getInstance(); + dev = new gpu_context_t(m, alloc_ctrl); + *device = &dev->common; + status = 0; + } else { + status = fb_device_open(module, name, device); + } + return status; +} diff --git a/gralloc_priv.h b/libgralloc/gralloc_priv.h similarity index 74% rename from gralloc_priv.h rename to libgralloc/gralloc_priv.h index 8e79568..9f305cc 100644 --- a/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011, 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. @@ -32,24 +32,31 @@ #if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY) #include "overlayLib.h" -#include "overlayLibUI.h" using namespace overlay; -/* - * BYPASS_OV_CHANNEL_OPEN - bypass channel is open - * BYPASS_OV_CHANNEL_PENDING_CLOSE - disp_loop to close bypass channel - * BYPASS_OV_CHANNEL_CLOSED - bypass channel is closed - */ -enum { BYPASS_OV_CHANNEL_OPEN, - BYPASS_OV_CHANNEL_PENDING_CLOSE, BYPASS_OV_CHANNEL_CLOSED }; #endif enum { - /* gralloc usage bit indicating the type + /* gralloc usage bits indicating the type * of allocation that should be used */ GRALLOC_USAGE_PRIVATE_ADSP_HEAP = GRALLOC_USAGE_PRIVATE_0, GRALLOC_USAGE_PRIVATE_EBI_HEAP = GRALLOC_USAGE_PRIVATE_1, GRALLOC_USAGE_PRIVATE_SMI_HEAP = GRALLOC_USAGE_PRIVATE_2, GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP = GRALLOC_USAGE_PRIVATE_3, + /* Set this for allocating uncached memory (using O_DSYNC) + * cannot be used with the system heap */ + GRALLOC_USAGE_PRIVATE_UNCACHED = 0x00010000, + /* This flag needs to be set when using a system heap + * from ION. If not set, the system heap is assumed + * to be coming from ashmem + */ + GRALLOC_USAGE_PRIVATE_ION = 0x00020000, +}; + +enum { + GPU_COMPOSITION, + C2D_COMPOSITION, + MDP_COMPOSITION, + CPU_COMPOSITION, }; /* numbers of max buffers for page flipping */ @@ -60,8 +67,14 @@ enum { #define NUM_DEF_FRAME_BUFFERS 2 #define NO_SURFACEFLINGER_SWAPINTERVAL #define INTERLACE_MASK 0x80 +#define S3D_FORMAT_MASK 0xFF000 +#define COLOR_FORMAT(x) (x & 0xFFF) // Max range for colorFormats is 0 - FFF +#define DEVICE_PMEM_ADSP "/dev/pmem_adsp" +#define DEVICE_PMEM_SMIPOOL "/dev/pmem_smipool" /*****************************************************************************/ #ifdef __cplusplus + +//XXX: Remove framebuffer specific classes and defines to a different header template struct Node { @@ -172,6 +185,10 @@ enum { HAL_3D_OUT_MONOSCOPIC = 0x8000 }; +enum { + BUFFER_TYPE_UI = 0, + BUFFER_TYPE_VIDEO +}; /*****************************************************************************/ struct private_module_t; @@ -198,57 +215,6 @@ struct avail_t { #endif }; - -#ifdef __cplusplus -/* Store for shared data and synchronization */ -struct ThreadShared { - int w; - int h; - int format; - buffer_handle_t buffer; - bool isNewBuffer; - bool isBufferPosted; - bool isExitPending; //Feature close - bool isHDMIExitPending; //Only HDMI close - //New buffer arrival condition - pthread_mutex_t newBufferMutex; - pthread_cond_t newBufferCond; - //Buffer posted to display condition, used instead of barrier - pthread_mutex_t bufferPostedMutex; - pthread_cond_t bufferPostedCond; - - ThreadShared():w(0),h(0),format(0),buffer(0),isNewBuffer(false), - isBufferPosted(false), isExitPending(false), - isHDMIExitPending(false) { - pthread_mutex_init(&newBufferMutex, NULL); - pthread_mutex_init(&bufferPostedMutex, NULL); - pthread_cond_init(&newBufferCond, NULL); - pthread_cond_init(&bufferPostedCond, NULL); - } - - void set(int w, int h, int format, buffer_handle_t buffer) { - this->w = w; - this->h = h; - this->format = format; - this->buffer = buffer; - } - - void get(int& w, int& h, int& format, buffer_handle_t& buffer) { - w = this->w; - h = this->h; - format = this->format; - buffer = this->buffer; - } - - void clear() { - w = h = format = 0; - buffer = 0; - isNewBuffer = isBufferPosted = isExitPending = \ - isHDMIExitPending = false; - } -}; -#endif - struct private_module_t { gralloc_module_t base; @@ -267,7 +233,7 @@ struct private_module_t { float fps; int swapInterval; #ifdef __cplusplus - Queue disp; // non-empty when buffer is ready for display + Queue disp; // non-empty when buffer is ready for display #endif int currentIdx; struct avail_t avail[NUM_FRAMEBUFFERS_MAX]; @@ -287,30 +253,11 @@ struct private_module_t { uint32_t currentOffset; bool enableHDMIOutput; bool exitHDMIUILoop; + float actionsafeWidthRatio; + float actionsafeHeightRatio; bool hdmiStateChanged; pthread_mutex_t overlayLock; pthread_cond_t overlayPost; - OverlayOrigRes* pOrigResPanel; - OverlayOrigRes* pOrigResTV; - bool isOrigResStarted; - ThreadShared ts; -#endif - -#if defined(__cplusplus) && defined(SF_BYPASS) - /* - * Comp. bypass specific variables - * pobjOverlayUI - UI overlay channel for comp. bypass. - * overlayui_lock - mutex lock for synchronization between - * disp_loop and main thread to modify - * bypassChannelState - * bypassChannelState - Current Channel State - * - OPEN - bypass channel is open - * - PENDING_CLOSE - close channel pending - * - CLOSED - bypass channel is closed - */ - OverlayUI* pobjOverlayUI; - pthread_mutex_t overlayui_lock; - int bypassChannelState; #endif }; @@ -322,7 +269,6 @@ struct private_handle_t : public native_handle { struct private_handle_t { native_handle_t nativeHandle; #endif - enum { PRIV_FLAGS_FRAMEBUFFER = 0x00000001, PRIV_FLAGS_USES_PMEM = 0x00000002, @@ -346,7 +292,7 @@ struct private_handle_t { int flags; int size; int offset; - int gpu_fd; // stored as an int, b/c we don't want it marshalled + int bufferType; // FIXME: the attributes below should be out-of-line int base; @@ -354,15 +300,19 @@ struct private_handle_t { int writeOwner; int gpuaddr; // The gpu address mapped into the mmu. If using ashmem, set to 0 They don't care int pid; + int format; + int width; + int height; #ifdef __cplusplus - static const int sNumInts = 10; + static const int sNumInts = 13; static const int sNumFds = 1; static const int sMagic = 'gmsm'; - private_handle_t(int fd, int size, int flags) : - fd(fd), magic(sMagic), flags(flags), size(size), offset(0), gpu_fd(-1), - base(0), lockState(0), writeOwner(0), gpuaddr(0), pid(getpid()) + private_handle_t(int fd, int size, int flags, int bufferType, int format, int width, int height) : + fd(fd), magic(sMagic), flags(flags), size(size), offset(0), bufferType(bufferType), + base(0), lockState(0), writeOwner(0), gpuaddr(0), pid(getpid()), format(format), width(width), + height(height) { version = sizeof(native_handle); numInts = sNumInts; @@ -380,7 +330,7 @@ struct private_handle_t { 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) + hnd->magic != sMagic) { LOGE("invalid gralloc handle (at %p)", h); return -EINVAL; diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp new file mode 100644 index 0000000..d92dedc --- /dev/null +++ b/libgralloc/ionalloc.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include +#include +#include +#include +#include +#include "ionalloc.h" + +using gralloc::IonAlloc; + +#define ION_DEVICE "/dev/ion" + +int IonAlloc::open_device() +{ + if(mIonFd == FD_INIT) + mIonFd = open(ION_DEVICE, O_RDONLY); + + if(mIonFd < 0 ) { + LOGE("%s: Failed to open ion device - %s", + __FUNCTION__, strerror(errno)); + mIonFd = FD_INIT; + return -errno; + } + return 0; +} + +void IonAlloc::close_device() +{ + if(mIonFd > 0) + close(mIonFd); + mIonFd = FD_INIT; +} + +int IonAlloc::alloc_buffer(alloc_data& data) +{ + int err = 0; + int ionSyncFd = FD_INIT; + int iFd = FD_INIT; + struct ion_handle_data handle_data; + struct ion_fd_data fd_data; + struct ion_allocation_data ionAllocData; + + void *base = 0; + + ionAllocData.len = data.size; + ionAllocData.align = data.align; + ionAllocData.flags = data.flags; + + err = open_device(); + if (err) + return err; + + if(data.uncached) { + // Use the sync FD to alloc and map + // when we need uncached memory + ionSyncFd = open(ION_DEVICE, O_RDONLY|O_DSYNC); + if(ionSyncFd < 0) { + LOGE("%s: Failed to open ion device - %s", + __FUNCTION__, strerror(errno)); + close_device(); + return -errno; + } + iFd = ionSyncFd; + } else { + iFd = mIonFd; + } + + err = ioctl(iFd, ION_IOC_ALLOC, &ionAllocData); + if(err) { + LOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno)); + close_device(); + if(ionSyncFd >= 0) + close(ionSyncFd); + ionSyncFd = FD_INIT; + return err; + } + + fd_data.handle = ionAllocData.handle; + handle_data.handle = ionAllocData.handle; + LOGD("%s: Trying ION_IOC_MAP pid=%d handle=%p size=%d mIonFd=%d flags=%x", + __FUNCTION__, getpid(), ionAllocData.handle, + ionAllocData.len, mIonFd, ionAllocData.flags); + + err = ioctl(iFd, ION_IOC_MAP, &fd_data); + if(err) { + LOGE("%s: ION_IOC_MAP failed with error - %s", + __FUNCTION__, strerror(errno)); + ioctl(mIonFd, ION_IOC_FREE, &handle_data); + close_device(); + if(ionSyncFd >= 0) + close(ionSyncFd); + ionSyncFd = FD_INIT; + return err; + } + + base = mmap(0, ionAllocData.len, PROT_READ|PROT_WRITE, + MAP_SHARED, fd_data.fd, 0); + if(base == MAP_FAILED) { + LOGD("%s: Failed to map the allocated memory: %s", + __FUNCTION__, strerror(errno)); + err = -errno; + ioctl(mIonFd, ION_IOC_FREE, &handle_data); + close_device(); + ionSyncFd = FD_INIT; + return err; + } + //Close the uncached FD since we no longer need it; + if(ionSyncFd >= 0) + close(ionSyncFd); + ionSyncFd = FD_INIT; + + // Not doing memset for ION, uncomment if needed + // memset(base, 0, ionAllocData.len); + // Clean cache after memset + // clean_buffer(base, data.size, data.offset, fd_data.fd); + data.base = base; + data.fd = fd_data.fd; + ioctl(mIonFd, ION_IOC_FREE, &handle_data); + LOGD("%s: ION alloc succeeded - mIonFd=%d, SharedFD=%d PID=%d size=%d" + " ionHandle=%p", __FUNCTION__, mIonFd, fd_data.fd, getpid(), + ionAllocData.len, ionAllocData.handle); + return err; +} + + +int IonAlloc::free_buffer(void* base, size_t size, int offset, int fd) +{ + LOGD("%s:Freeing buffer size=%d base=%p mIonFd=%d fd=%d PID=%d", + __FUNCTION__, size, base, mIonFd, fd, getpid()); + int err = 0; + err = open_device(); + if (err) + return err; + + if(!base) { + LOGE("Invalid free"); + return -EINVAL; + } + err = unmap_buffer(base, size, offset); + close(fd); + return err; +} + +int IonAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) +{ + LOGD("%s: Mapping buffer fd=%d size=%d PID=%d", __FUNCTION__, + fd, size, getpid()); + int err = 0; + void *base = 0; + // It is a (quirky) requirement of ION to have opened the + // ion fd in the process that is doing the mapping + err = open_device(); + if (err) + return err; + + base = mmap(0, size, PROT_READ| PROT_WRITE, + MAP_SHARED, fd, 0); + *pBase = base; + if(base == MAP_FAILED) { + LOGD("%s: Failed to map memory in the client: %s", + __FUNCTION__, strerror(errno)); + err = -errno; + } else { + LOGD("%s: Successfully mapped %d bytes", __FUNCTION__, size); + } + return err; +} + +int IonAlloc::unmap_buffer(void *base, size_t size, int offset) +{ + LOGD("%s: Unmapping buffer at address %p", __FUNCTION__, base); + int err = munmap(base, size); + if(err) { + LOGE("%s: Failed to unmap memory at %p: %s", + __FUNCTION__, base, strerror(errno)); + } + return err; + +} +int IonAlloc::clean_buffer(void *base, size_t size, int offset, int fd) +{ + // LOGD("%s: Clean buffer fd=%d base = %p size=%d PID=%d", __FUNCTION__, + // fd, base, size, getpid()); + struct ion_flush_data flush_data; + struct ion_fd_data fd_data; + struct ion_handle_data handle_data; + struct ion_handle* handle; + int err = 0; + + err = open_device(); + if (err) + return err; + + fd_data.fd = fd; + err = ioctl(mIonFd, ION_IOC_IMPORT, &fd_data); + if(err) { + LOGE("%s: ION_IOC_IMPORT failed with error - %s", + __FUNCTION__, strerror(errno)); + close_device(); + return err; + } + + handle_data.handle = fd_data.handle; + flush_data.handle = fd_data.handle; + flush_data.vaddr = base; + flush_data.offset = offset; + flush_data.length = size; + err = ioctl(mIonFd, ION_IOC_CLEAN_INV_CACHES, &flush_data); + if(err) { + LOGE("%s: ION_IOC_CLEAN_INV_CACHES failed with error - %s", + __FUNCTION__, strerror(errno)); + ioctl(mIonFd, ION_IOC_FREE, &handle_data); + close_device(); + return err; + } + ioctl(mIonFd, ION_IOC_FREE, &handle_data); + return err; +} + diff --git a/libgralloc/ionalloc.h b/libgralloc/ionalloc.h new file mode 100644 index 0000000..91a1d65 --- /dev/null +++ b/libgralloc/ionalloc.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GRALLOC_IONALLOC_H +#define GRALLOC_IONALLOC_H + +#include "memalloc.h" +#include + +namespace gralloc { + + class IonAlloc : public IMemAlloc { + + public: + virtual int alloc_buffer(alloc_data& data); + + virtual int free_buffer(void *base, size_t size, + int offset, int fd); + + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd); + + virtual int unmap_buffer(void *base, size_t size, + int offset); + + virtual int clean_buffer(void*base, size_t size, + int offset, int fd); + + IonAlloc() { mIonFd = FD_INIT; } + + ~IonAlloc() { close_device(); } + + private: + int mIonFd; + + int open_device(); + + void close_device(); + + }; + +} + +#endif /* GRALLOC_IONALLOC_H */ + diff --git a/mapper.cpp b/libgralloc/mapper.cpp similarity index 54% rename from mapper.cpp rename to libgralloc/mapper.cpp index 7699e4c..e2ec899 100644 --- a/mapper.cpp +++ b/libgralloc/mapper.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2011 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. @@ -38,20 +39,31 @@ #include "gralloc_priv.h" #include "gr.h" +#include "ionalloc.h" +#include "ashmemalloc.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 - +using gralloc::IMemAlloc; +using gralloc::IonAlloc; +using gralloc::AshmemAlloc; +using android::sp; /*****************************************************************************/ +// Return the type of allocator - +// these are used for mapping/unmapping +static sp getAllocator(int flags) +{ + sp memalloc; + if (flags & private_handle_t::PRIV_FLAGS_USES_ION) { + memalloc = new IonAlloc(); + } + if (flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) { + memalloc = new AshmemAlloc(); + } + + // XXX Return allocator for pmem + return memalloc; +} + static int gralloc_map(gralloc_module_t const* module, buffer_handle_t handle, void** vaddr) @@ -60,16 +72,16 @@ static int gralloc_map(gralloc_module_t const* module, void *mappedAddress; if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { size_t size = hnd->size; -#if PMEM_HACK - size += hnd->offset; -#endif - if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) { - mappedAddress = mmap(0, size, - PROT_READ|PROT_WRITE, MAP_SHARED | MAP_POPULATE, hnd->fd, 0); - } else { - mappedAddress = mmap(0, size, - PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0); + sp memalloc = getAllocator(hnd->flags) ; + int err = memalloc->map_buffer(&mappedAddress, size, + hnd->offset, hnd->fd); + if(err) { + LOGE("Could not mmap handle %p, fd=%d (%s)", + handle, hnd->fd, strerror(errno)); + hnd->base = 0; + return -errno; } + if (mappedAddress == MAP_FAILED) { LOGE("Could not mmap handle %p, fd=%d (%s)", handle, hnd->fd, strerror(errno)); @@ -77,7 +89,7 @@ static int gralloc_map(gralloc_module_t const* module, return -errno; } hnd->base = intptr_t(mappedAddress) + hnd->offset; - //LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p", + //LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p", // hnd->fd, hnd->offset, hnd->size, mappedAddress); } *vaddr = (void*)hnd->base; @@ -89,15 +101,14 @@ static int gralloc_unmap(gralloc_module_t const* module, { private_handle_t* hnd = (private_handle_t*)handle; if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { + int err = -EINVAL; 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)); + sp memalloc = getAllocator(hnd->flags) ; + if(memalloc != NULL) + err = memalloc->unmap_buffer(base, size, hnd->offset); + if (err) { + LOGE("Could not unmap memory at address %p", base); } } hnd->base = 0; @@ -106,7 +117,7 @@ static int gralloc_unmap(gralloc_module_t const* module, /*****************************************************************************/ -static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER; /*****************************************************************************/ @@ -121,9 +132,9 @@ int gralloc_register_buffer(gralloc_module_t const* module, /* 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 + * 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; @@ -148,7 +159,7 @@ int gralloc_unregister_buffer(gralloc_module_t const* module, */ 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); @@ -179,8 +190,9 @@ int terminateBuffer(gralloc_module_t const* module, 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->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) { + if (hnd->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM | + private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP | + private_handle_t::PRIV_FLAGS_USES_ASHMEM)) { if (hnd->pid != getpid()) { // ... unless it's a "master" pmem buffer, that is a buffer // mapped in the process it's been allocated. @@ -188,6 +200,7 @@ int terminateBuffer(gralloc_module_t const* module, gralloc_unmap(module, hnd); } } else { + LOGE("terminateBuffer: unmapping a non pmem/ashmem buffer flags = 0x%x", hnd->flags); gralloc_unmap(module, hnd); } } @@ -213,7 +226,7 @@ int gralloc_lock(gralloc_module_t const* module, new_value = current_value; if (current_value & private_handle_t::LOCK_STATE_WRITE) { - // already locked for 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) { @@ -223,7 +236,7 @@ int gralloc_lock(gralloc_module_t const* module, return -EBUSY; } else { // this is not an error - //LOGD("%p already locked for read... count = %d", + //LOGD("%p already locked for read... count = %d", // handle, (current_value & ~(1<<31))); } } @@ -235,7 +248,7 @@ int gralloc_lock(gralloc_module_t const* module, } new_value++; - retry = android_atomic_cmpxchg(current_value, new_value, + retry = android_atomic_cmpxchg(current_value, new_value, (volatile int32_t*)&hnd->lockState); } while (retry); @@ -272,7 +285,7 @@ int gralloc_lock(gralloc_module_t const* module, return err; } -int gralloc_unlock(gralloc_module_t const* module, +int gralloc_unlock(gralloc_module_t const* module, buffer_handle_t handle) { if (private_handle_t::validate(handle) < 0) @@ -283,17 +296,9 @@ int gralloc_unlock(gralloc_module_t const* module, if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) { int err; - if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) { - struct pmem_addr pmem_addr; - pmem_addr.vaddr = hnd->base; - pmem_addr.offset = hnd->offset; - pmem_addr.length = hnd->size; - err = ioctl( hnd->fd, PMEM_CLEAN_CACHES, &pmem_addr); - } else if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM)) { - unsigned long addr = hnd->base + hnd->offset; - err = ioctl(hnd->fd, ASHMEM_CACHE_FLUSH_RANGE, NULL); - } - + sp memalloc = getAllocator(hnd->flags) ; + err = memalloc->clean_buffer((void*)hnd->base, + hnd->size, hnd->offset, hnd->fd); LOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x, flags = 0x%x) err=%s\n", hnd, hnd->offset, hnd->size, hnd->flags, strerror(errno)); hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; @@ -318,8 +323,8 @@ int gralloc_unlock(gralloc_module_t const* module, new_value--; - } while (android_atomic_cmpxchg(current_value, new_value, - (volatile int32_t*)&hnd->lockState)); + } while (android_atomic_cmpxchg(current_value, new_value, + (volatile int32_t*)&hnd->lockState)); return 0; } @@ -334,158 +339,66 @@ int gralloc_perform(struct gralloc_module_t const* module, va_start(args, operation); switch (operation) { - case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER: { - int fd = va_arg(args, int); - size_t size = va_arg(args, size_t); - size_t offset = va_arg(args, size_t); - void* base = va_arg(args, void*); + case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER: + { + int fd = va_arg(args, int); + size_t size = va_arg(args, size_t); + size_t offset = va_arg(args, size_t); + void* base = va_arg(args, void*); - native_handle_t** handle = va_arg(args, native_handle_t**); - int memoryFlags = va_arg(args, int); - if (memoryFlags == GRALLOC_USAGE_PRIVATE_EBI_HEAP) { - // validate that it's indeed a pmem buffer - pmem_region region; - if (ioctl(fd, PMEM_GET_SIZE, ®ion) < 0) { - break; + native_handle_t** handle = va_arg(args, native_handle_t**); + int memoryFlags = va_arg(args, int); + private_handle_t* hnd = (private_handle_t*)native_handle_create( + private_handle_t::sNumFds, private_handle_t::sNumInts); + hnd->magic = private_handle_t::sMagic; + hnd->fd = fd; + unsigned int contigFlags = GRALLOC_USAGE_PRIVATE_ADSP_HEAP | + GRALLOC_USAGE_PRIVATE_EBI_HEAP | + GRALLOC_USAGE_PRIVATE_SMI_HEAP; + + if (memoryFlags & contigFlags) { + // check if the buffer is a pmem buffer + pmem_region region; + if (ioctl(fd, PMEM_GET_SIZE, ®ion) < 0) + hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION; + else + hnd->flags = private_handle_t::PRIV_FLAGS_USES_PMEM | + private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH; + } else { + if (memoryFlags & GRALLOC_USAGE_PRIVATE_ION) + hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION; + else + hnd->flags = private_handle_t::PRIV_FLAGS_USES_ASHMEM; } + + hnd->size = size; + hnd->offset = offset; + hnd->base = intptr_t(base) + offset; + hnd->lockState = private_handle_t::LOCK_STATE_MAPPED; + hnd->gpuaddr = 0; + *handle = (native_handle_t *)hnd; + res = 0; + break; + } - private_handle_t* hnd = (private_handle_t*)native_handle_create( - private_handle_t::sNumFds, private_handle_t::sNumInts); - hnd->magic = private_handle_t::sMagic; - hnd->fd = fd; - hnd->flags = (memoryFlags == GRALLOC_USAGE_PRIVATE_EBI_HEAP) ? - private_handle_t::PRIV_FLAGS_USES_PMEM | - private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH: - private_handle_t::PRIV_FLAGS_USES_ASHMEM; - hnd->size = size; - hnd->offset = offset; - hnd->base = intptr_t(base) + offset; - hnd->lockState = private_handle_t::LOCK_STATE_MAPPED; - hnd->gpuaddr = 0; - *handle = (native_handle_t *)hnd; - res = 0; + case GRALLOC_MODULE_PERFORM_UPDATE_BUFFER_HANDLE: + { + native_handle_t* handle = va_arg(args, native_handle_t*); + int w = va_arg(args, int); + int h = va_arg(args, int); + int f = va_arg(args, int); + private_handle_t* hnd = (private_handle_t*)handle; + hnd->width = w; + hnd->height = h; + if (hnd->format != f) { + hnd->format = f; + } + break; + } + default: break; - } - case GRALLOC_MODULE_PERFORM_DECIDE_PUSH_BUFFER_HANDLING: { - int format = va_arg(args, int); - int width = va_arg(args, int); - int height = va_arg(args, int); - char *compositionUsed = va_arg(args, char*); - int hasBlitEngine = va_arg(args, int); - int *needConversion = va_arg(args, int*); - int *useBufferDirectly = va_arg(args, int*); - size_t *size = va_arg(args, size_t*); - *size = calculateBufferSize(width, height, format); - int conversion = 0; - int direct = 0; - res = decideBufferHandlingMechanism(format, compositionUsed, hasBlitEngine, - needConversion, useBufferDirectly); - break; - } - default: - break; } va_end(args); return res; } - -int decideBufferHandlingMechanism(int format, const char *compositionUsed, int hasBlitEngine, - int *needConversion, int *useBufferDirectly) -{ - *needConversion = FALSE; - *useBufferDirectly = FALSE; - if(compositionUsed == NULL) { - LOGE("null pointer"); - return -1; - } - - if(format == HAL_PIXEL_FORMAT_RGB_565) { - // Software video renderer gives the output in RGB565 format. - // This can be handled by all compositors - *needConversion = FALSE; - *useBufferDirectly = TRUE; - } else if(strncmp(compositionUsed, "cpu", 3) == 0){ - *needConversion = FALSE; - *useBufferDirectly = FALSE; - } else if(strncmp(compositionUsed, "gpu", 3) == 0) { - if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED || - format == HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO || - format == HAL_PIXEL_FORMAT_YV12) { - *needConversion = FALSE; - *useBufferDirectly = TRUE; - } else if(hasBlitEngine) { - *needConversion = TRUE; - *useBufferDirectly = FALSE; - } - } else if ((strncmp(compositionUsed, "mdp", 3) == 0) || - (strncmp(compositionUsed, "c2d", 3) == 0)){ - if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP || - format == HAL_PIXEL_FORMAT_YCrCb_420_SP || - format == HAL_PIXEL_FORMAT_YV12) { - *needConversion = FALSE; - *useBufferDirectly = TRUE; - } else if((strncmp(compositionUsed, "c2d", 3) == 0) && - format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { - *needConversion = FALSE; - *useBufferDirectly = TRUE; - } else if(hasBlitEngine) { - *needConversion = TRUE; - *useBufferDirectly = FALSE; - } - } else { - LOGE("Invalid composition type %s", compositionUsed); - return -1; - } - return 0; -} - -size_t calculateBufferSize(int width, int height, int format) -{ - if(!width || !height) - return 0; - - size_t size = 0; - - switch (format) - { - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { - int aligned_height = (height + 31) & ~31; - int pitch = (width + 127) & ~127; - size = pitch * aligned_height; - size = (size + 8191) & ~8191; - int secondPlaneOffset = size; - - aligned_height = ((height >> 1) + 31) & ~31; - size += pitch * aligned_height; - size = (size + 8191) & ~8191; - break; - } - case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: { - int aligned_height = (height + 31) & ~31; - int pitch = (width + 31) & ~31; - size = pitch * aligned_height; - size = (size + 4095) & ~4095; - int secondPlaneOffset = size; - - pitch = 2 * (((width >> 1) + 31) & ~31); - aligned_height = ((height >> 1) + 31) & ~31; - size += pitch * aligned_height; - size = (size + 4095) & ~4095; - break; - } - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_420_SP: - case HAL_PIXEL_FORMAT_YV12: { - /* Camera and video YUV 420 semi-planar buffers are allocated with - size equal to w * h * 1.5 */ - int aligned_width = (width + 15) & ~15; - int aligned_chroma_width = ((width/2) + 15) & ~15; - size = (aligned_width * height) + ((aligned_chroma_width * height/2) *2); - break; - } - default: - break; - } - return size; -} diff --git a/libgralloc/memalloc.h b/libgralloc/memalloc.h new file mode 100644 index 0000000..7b76d06 --- /dev/null +++ b/libgralloc/memalloc.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GRALLOC_MEMALLOC_H +#define GRALLOC_MEMALLOC_H + +#include +#include + +namespace gralloc { + + struct alloc_data { + void *base; + int fd; + int offset; + size_t size; + size_t align; + unsigned int pHandle; + bool uncached; + unsigned int flags; + int bufferType; + int allocType; + }; + + class IMemAlloc : public android::RefBase { + + public: + // Allocate buffer - fill in the alloc_data + // structure and pass it in. Mapped address + // and fd are returned in the alloc_data struct + virtual int alloc_buffer(alloc_data& data) = 0; + + // Free buffer + virtual int free_buffer(void *base, size_t size, + int offset, int fd) = 0; + + // Map buffer + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd) = 0; + + // Unmap buffer + virtual int unmap_buffer(void *base, size_t size, + int offset) = 0; + + // Clean and invalidate + virtual int clean_buffer(void *base, size_t size, + int offset, int fd) = 0; + + // Destructor + virtual ~IMemAlloc() {}; + + enum { + FD_INIT = -1, + }; + + }; + +} // end gralloc namespace +#endif // GRALLOC_MEMALLOC_H diff --git a/allocator.cpp b/libgralloc/pmem_bestfit_alloc.cpp similarity index 98% rename from allocator.cpp rename to libgralloc/pmem_bestfit_alloc.cpp index e7645b1..d13317e 100644 --- a/allocator.cpp +++ b/libgralloc/pmem_bestfit_alloc.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project + * Copyright (c) 2011 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. @@ -16,7 +17,7 @@ #include -#include "allocator.h" +#include "pmem_bestfit_alloc.h" // align all the memory blocks on a cache-line boundary @@ -50,8 +51,7 @@ ssize_t SimpleBestFitAllocator::setSize(size_t size) mList.insertHead(node); return size; } - - + size_t SimpleBestFitAllocator::size() const { return mHeapSize; diff --git a/allocator.h b/libgralloc/pmem_bestfit_alloc.h similarity index 97% rename from allocator.h rename to libgralloc/pmem_bestfit_alloc.h index dc81f51..16ff58a 100644 --- a/allocator.h +++ b/libgralloc/pmem_bestfit_alloc.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project + * Copyright (c) 2011 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. @@ -71,7 +72,7 @@ public: mFirst = newNode; } } - + void insertTail(NODE* newNode) { if (mLast == 0) { insertHead(newNode); @@ -108,7 +109,7 @@ public: private: struct chunk_t { - chunk_t(size_t start, size_t size) + chunk_t(size_t start, size_t size) : start(start), size(size), free(1), prev(0), next(0) { } size_t start; diff --git a/pmemalloc.cpp b/libgralloc/pmemalloc.cpp similarity index 82% rename from pmemalloc.cpp rename to libgralloc/pmemalloc.cpp index d3a45ea..010734b 100644 --- a/pmemalloc.cpp +++ b/libgralloc/pmemalloc.cpp @@ -54,7 +54,8 @@ PmemAllocator::~PmemAllocator() } -PmemUserspaceAllocator::PmemUserspaceAllocator(Deps& deps, Deps::Allocator& allocator, const char* pmemdev): +PmemUserspaceAllocator::PmemUserspaceAllocator(Deps& deps, + Deps::Allocator& allocator, const char* pmemdev): deps(deps), allocator(allocator), pmemdev(pmemdev), @@ -143,7 +144,7 @@ int PmemUserspaceAllocator::init_pmem_area() int PmemUserspaceAllocator::alloc_pmem_buffer(size_t size, int usage, - void** pBase, int* pOffset, int* pFd) + void** pBase, int* pOffset, int* pFd, int format) { BEGIN_FUNC; int err = init_pmem_area(); @@ -201,7 +202,8 @@ int PmemUserspaceAllocator::alloc_pmem_buffer(size_t size, int usage, } -int PmemUserspaceAllocator::free_pmem_buffer(size_t size, void* base, int offset, int fd) +int PmemUserspaceAllocator::free_pmem_buffer(size_t size, void* base, + int offset, int fd) { BEGIN_FUNC; int err = 0; @@ -232,9 +234,8 @@ PmemUserspaceAllocator::Deps::~Deps() END_FUNC; } -PmemKernelAllocator::PmemKernelAllocator(Deps& deps, const char* pmemdev): - deps(deps), - pmemdev(pmemdev) +PmemKernelAllocator::PmemKernelAllocator(Deps& deps): + deps(deps) { BEGIN_FUNC; END_FUNC; @@ -267,7 +268,7 @@ static unsigned clp2(unsigned x) { int PmemKernelAllocator::alloc_pmem_buffer(size_t size, int usage, - void** pBase,int* pOffset, int* pFd) + void** pBase,int* pOffset, int* pFd, int format) { BEGIN_FUNC; @@ -275,28 +276,55 @@ int PmemKernelAllocator::alloc_pmem_buffer(size_t size, int usage, *pOffset = 0; *pFd = -1; - int err; + int err, offset = 0; int openFlags = get_open_flags(usage); - int fd = deps.open(pmemdev, openFlags, 0); + const char *device; + if (usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) { + device = DEVICE_PMEM_ADSP; + } else if (usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP) { + device = DEVICE_PMEM_SMIPOOL; + } else if ((usage & GRALLOC_USAGE_EXTERNAL_DISP) || + (usage & GRALLOC_USAGE_PROTECTED)) { + int tempFd = deps.open(DEVICE_PMEM_SMIPOOL, openFlags, 0); + if (tempFd < 0) { + device = DEVICE_PMEM_ADSP; + } else { + close(tempFd); + device = DEVICE_PMEM_SMIPOOL; + } + } else { + LOGE("Invalid device"); + return -EINVAL; + } + + int fd = deps.open(device, openFlags, 0); if (fd < 0) { err = -deps.getErrno(); END_FUNC; + LOGE("Error opening %s", device); return err; } // The size should already be page aligned, now round it up to a power of 2. - size = clp2(size); + //size = clp2(size); + + if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { + // Tile format buffers need physical alignment to 8K + err = deps.alignPmem(fd, size, 8192); + if (err < 0) { + LOGE("alignPmem failed"); + } + } void* base = deps.mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (base == MAP_FAILED) { - LOGE("%s: failed to map pmem fd: %s", pmemdev, + LOGE("%s: failed to map pmem fd: %s", device, strerror(deps.getErrno())); err = -deps.getErrno(); deps.close(fd); END_FUNC; return err; } - memset(base, 0, size); *pBase = base; @@ -308,19 +336,22 @@ int PmemKernelAllocator::alloc_pmem_buffer(size_t size, int usage, } -int PmemKernelAllocator::free_pmem_buffer(size_t size, void* base, int offset, int fd) +int PmemKernelAllocator::free_pmem_buffer(size_t size, void* base, + int offset, int fd) { BEGIN_FUNC; - // The size should already be page aligned, now round it up to a power of 2 + // The size should already be page aligned, + // now round it up to a power of 2 // like we did when allocating. - size = clp2(size); + //size = clp2(size); int err = deps.munmap(base, size); if (err < 0) { err = deps.getErrno(); - LOGW("%s: error unmapping pmem fd: %s", pmemdev, strerror(err)); + LOGW("error unmapping pmem fd: %s", strerror(err)); return -err; } + END_FUNC; return 0; } diff --git a/pmemalloc.h b/libgralloc/pmemalloc.h similarity index 94% rename from pmemalloc.h rename to libgralloc/pmemalloc.h index a27cb41..2a1c6fd 100644 --- a/pmemalloc.h +++ b/libgralloc/pmemalloc.h @@ -36,7 +36,7 @@ class PmemAllocator { virtual void* get_base_address() = 0; virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase, - int* pOffset, int* pFd) = 0; + int* pOffset, int* pFd, int format) = 0; virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd) = 0; }; @@ -90,7 +90,7 @@ class PmemUserspaceAllocator: public PmemAllocator { virtual int init_pmem_area_locked(); virtual int init_pmem_area(); virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase, - int* pOffset, int* pFd); + int* pOffset, int* pFd, int format); virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd); #ifndef ANDROID_OS @@ -140,23 +140,22 @@ class PmemKernelAllocator: public PmemAllocator { virtual int munmap(void* start, size_t length) = 0; virtual int open(const char* pathname, int flags, int mode) = 0; virtual int close(int fd) = 0; + virtual int alignPmem(int fd, size_t size, int align) = 0; }; - PmemKernelAllocator(Deps& deps, const char* pmemdev); + PmemKernelAllocator(Deps& deps); virtual ~PmemKernelAllocator(); // Only valid after init_pmem_area() has completed successfully. virtual void* get_base_address(); virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase, - int* pOffset, int* pFd); + int* pOffset, int* pFd, int format); virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd); private: Deps& deps; - - const char* pmemdev; }; #endif // GRALLOC_QSD8K_PMEMALLOC_H diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk new file mode 100644 index 0000000..ffc30bd --- /dev/null +++ b/libhwcomposer/Android.mk @@ -0,0 +1,28 @@ +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 libEGL libhardware libutils liboverlay + +LOCAL_SRC_FILES := \ + hwcomposer.cpp + +LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM) +LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).hwcomposer\" +LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc +LOCAL_C_INCLUDES += hardware/msm7k/liboverlay +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +ifeq ($(TARGET_HAVE_HDMI_OUT),true) +LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY +endif +ifeq ($(TARGET_HAVE_BYPASS),true) +LOCAL_CFLAGS += -DCOMPOSITION_BYPASS +endif +ifeq ($(TARGET_USE_HDMI_AS_PRIMARY),true) +LOCAL_CFLAGS += -DHDMI_AS_PRIMARY +endif +include $(BUILD_SHARED_LIBRARY) diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp new file mode 100644 index 0000000..034d74d --- /dev/null +++ b/libhwcomposer/hwcomposer.cpp @@ -0,0 +1,1162 @@ +/* + * Copyright (C) 2010 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 +#include +#include +#include + +/*****************************************************************************/ +#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +// Enum containing the supported composition types +enum { + COMPOSITION_TYPE_GPU = 0, + COMPOSITION_TYPE_MDP = 0x1, + COMPOSITION_TYPE_C2D = 0x2, + COMPOSITION_TYPE_CPU = 0x4, + COMPOSITION_TYPE_DYN = 0x8 +}; + +enum HWCCompositionType { + HWC_USE_GPU = HWC_FRAMEBUFFER, // This layer is to be handled by Surfaceflinger + HWC_USE_OVERLAY = HWC_OVERLAY, // This layer is to be handled by the overlay + HWC_USE_COPYBIT // This layer is to be handled by copybit +}; + +enum HWCPrivateFlags { + HWC_USE_ORIGINAL_RESOLUTION = HWC_FLAGS_PRIVATE_0, // This layer is to be drawn using overlays + HWC_DO_NOT_USE_OVERLAY = HWC_FLAGS_PRIVATE_1, // Do not use overlays to draw this layer + HWC_COMP_BYPASS = HWC_FLAGS_PRIVATE_3, // Layer "might" use or have used bypass +}; + +enum HWCLayerType{ + HWC_SINGLE_VIDEO = 0x1, + HWC_ORIG_RESOLUTION = 0x2, + HWC_S3D_LAYER = 0x4, + HWC_STOP_UI_MIRRORING_MASK = 0xF +}; + +#ifdef COMPOSITION_BYPASS +enum BypassState { + BYPASS_ON, + BYPASS_OFF, + BYPASS_OFF_PENDING, +}; + +enum { + MAX_BYPASS_LAYERS = 2, + ANIM_FRAME_COUNT = 30, +}; +#endif + +enum eHWCOverlayStatus { + HWC_OVERLAY_OPEN, + HWC_OVERLAY_PREPARE_TO_CLOSE, + HWC_OVERLAY_CLOSED +}; + +struct hwc_context_t { + hwc_composer_device_t device; + /* our private state goes below here */ + overlay::Overlay* mOverlayLibObject; +#ifdef COMPOSITION_BYPASS + overlay::OverlayUI* mOvUI[MAX_BYPASS_LAYERS]; + int animCount; + BypassState bypassState; +#endif +#if defined HDMI_DUAL_DISPLAY + bool mHDMIEnabled; + bool pendingHDMI; +#endif + int previousLayerCount; + eHWCOverlayStatus hwcOverlayStatus; +}; + +static int hwc_device_open(const struct hw_module_t* module, const char* name, + struct hw_device_t** device); + +static struct hw_module_methods_t hwc_module_methods = { + open: hwc_device_open +}; + + +struct private_hwc_module_t { + hwc_module_t base; + overlay_control_device_t *overlayEngine; + copybit_device_t *copybitEngine; + framebuffer_device_t *fbDevice; + int compositionType; + bool isBypassEnabled; //from build.prop debug.compbypass.enable +}; + +struct private_hwc_module_t HAL_MODULE_INFO_SYM = { + base: { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: HWC_HARDWARE_MODULE_ID, + name: "Hardware Composer Module", + author: "The Android Open Source Project", + methods: &hwc_module_methods, + } + }, + overlayEngine: NULL, + copybitEngine: NULL, + fbDevice: NULL, + compositionType: 0, + isBypassEnabled: false, +}; + +/*****************************************************************************/ + +static void dump_layer(hwc_layer_t const* l) { + LOGD("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}, {%d,%d,%d,%d}", + l->compositionType, l->flags, l->handle, l->transform, l->blending, + l->sourceCrop.left, + l->sourceCrop.top, + l->sourceCrop.right, + l->sourceCrop.bottom, + l->displayFrame.left, + l->displayFrame.top, + l->displayFrame.right, + l->displayFrame.bottom); +} + +static inline int min(const int& a, const int& b) { + return (a < b) ? a : b; +} + +static inline int max(const int& a, const int& b) { + return (a > b) ? a : b; +} + +static int setVideoOverlayStatusInGralloc(hwc_context_t* ctx, const bool enable) { +#if defined HDMI_DUAL_DISPLAY + private_hwc_module_t* hwcModule = reinterpret_cast( + ctx->device.common.module); + if(!hwcModule) { + LOGE("%s: invalid params", __FUNCTION__); + return -1; + } + + framebuffer_device_t *fbDev = hwcModule->fbDevice; + if (!fbDev) { + LOGE("%s: fbDev is NULL", __FUNCTION__); + return -1; + } + + // Inform the gralloc to stop or start UI mirroring + fbDev->videoOverlayStarted(fbDev, enable); +#endif + return 0; +} + +static void setHWCOverlayStatus(hwc_context_t *ctx, bool isVideoPresent) { + + switch (ctx->hwcOverlayStatus) { + case HWC_OVERLAY_OPEN: + ctx->hwcOverlayStatus = + isVideoPresent ? HWC_OVERLAY_OPEN : HWC_OVERLAY_PREPARE_TO_CLOSE; + break; + case HWC_OVERLAY_PREPARE_TO_CLOSE: + ctx->hwcOverlayStatus = + isVideoPresent ? HWC_OVERLAY_OPEN : HWC_OVERLAY_CLOSED; + break; + case HWC_OVERLAY_CLOSED: + ctx->hwcOverlayStatus = + isVideoPresent ? HWC_OVERLAY_OPEN : HWC_OVERLAY_CLOSED; + break; + default: + LOGE("%s: Invalid hwcOverlayStatus (status =%d)", __FUNCTION__, + ctx->hwcOverlayStatus); + break; + } +} + +static int hwc_closeOverlayChannels(hwc_context_t* ctx) { + overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; + if(!ovLibObject) { + LOGE("%s: invalid params", __FUNCTION__); + return -1; + } + + if (HWC_OVERLAY_PREPARE_TO_CLOSE == ctx->hwcOverlayStatus) { + // Video mirroring is going on, and we do not have any layers to + // mirror directly. Close the current video channel and inform the + // gralloc to start UI mirroring + ovLibObject->closeChannel(); + // Inform the gralloc that video overlay has stopped. + setVideoOverlayStatusInGralloc(ctx, false); + } + return 0; +} + +/* + * Configures mdp pipes + */ +static int prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer, const bool waitForVsync) { + int ret = 0; + if (LIKELY(ctx && ctx->mOverlayLibObject)) { + private_hwc_module_t* hwcModule = + reinterpret_cast(ctx->device.common.module); + if (UNLIKELY(!hwcModule)) { + LOGE("prepareOverlay null module "); + return -1; + } + + private_handle_t *hnd = (private_handle_t *)layer->handle; + overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; + overlay_buffer_info info; + info.width = hnd->width; + info.height = hnd->height; + info.format = hnd->format; + info.size = hnd->size; + + ret = ovLibObject->setSource(info, layer->transform, + (ovLibObject->getHDMIStatus()?true:false), waitForVsync); + if (!ret) { + LOGE("prepareOverlay setSource failed"); + return -1; + } + + ret = ovLibObject->setParameter(OVERLAY_TRANSFORM, layer->transform); + if (!ret) { + LOGE("prepareOverlay setParameter failed transform %x", + layer->transform); + return -1; + } + + hwc_rect_t sourceCrop = layer->sourceCrop; + ret = ovLibObject->setCrop(sourceCrop.left, sourceCrop.top, + (sourceCrop.right - sourceCrop.left), + (sourceCrop.bottom - sourceCrop.top)); + if (!ret) { + LOGE("prepareOverlay setCrop failed"); + return -1; + } + + if (layer->flags == HWC_USE_ORIGINAL_RESOLUTION) { + framebuffer_device_t* fbDev = hwcModule->fbDevice; + ret = ovLibObject->setPosition(0, 0, + fbDev->width, fbDev->height); + } else { + hwc_rect_t displayFrame = layer->displayFrame; + ret = ovLibObject->setPosition(displayFrame.left, displayFrame.top, + (displayFrame.right - displayFrame.left), + (displayFrame.bottom - displayFrame.top)); + } + if (!ret) { + LOGE("prepareOverlay setPosition failed"); + return -1; + } + } + return 0; +} + +bool canSkipComposition(hwc_context_t* ctx, int yuvBufferCount, int currentLayerCount, + int numLayersNotUpdating) +{ + if (!ctx) { + LOGE("canSkipComposition invalid context"); + return false; + } + + bool compCountChanged = false; + if (yuvBufferCount == 1) { + if (currentLayerCount != ctx->previousLayerCount) { + compCountChanged = true; + ctx->previousLayerCount = currentLayerCount; + } + + if (!compCountChanged) { + if ((currentLayerCount == 1) || + ((currentLayerCount-1) == numLayersNotUpdating)) { + // We either have only one overlay layer or we have + // all the non-UI layers not updating. In this case + // we can skip the composition of the UI layers. + return true; + } + } + } else { + ctx->previousLayerCount = -1; + } + return false; +} + +static bool isFullScreenUpdate(const framebuffer_device_t* fbDev, const hwc_layer_list_t* list) { + + if(!fbDev) { + LOGE("ERROR: %s : fb device is invalid",__func__); + return false; + } + + int fb_w = fbDev->width; + int fb_h = fbDev->height; + + /* + * We have full screen condition when + * 1. We have 1 layer to compose + * a. layers dest rect equals display resolution. + * 2. We have 2 layers to compose + * a. Sum of their dest rects equals display resolution. + */ + + if(list->numHwLayers == 1) + { + hwc_rect_t rect = list->hwLayers[0].displayFrame; + + int w = rect.right - rect.left; + int h = rect.bottom - rect.top; + + int transform = list->hwLayers[0].transform; + + if(transform & (HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_ROT_270)) + return ((fb_w == h) && (fb_h == w)); + else + return ((fb_h == h) && (fb_w == w)); + } + + if(list->numHwLayers == 2) { + + hwc_rect_t rect_1 = list->hwLayers[0].displayFrame; + hwc_rect_t rect_2 = list->hwLayers[1].displayFrame; + + int transform_1 = list->hwLayers[0].transform; + int transform_2 = list->hwLayers[1].transform; + + int w1 = rect_1.right - rect_1.left; + int h1 = rect_1.bottom - rect_1.top; + int w2 = rect_2.right - rect_2.left; + int h2 = rect_2.bottom - rect_2.top; + + if(transform_1 == transform_2) { + if(transform_1 & (HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_ROT_270)) { + if((fb_w == (w1 + w2)) && (fb_h == h1) && (fb_h == h2)) + return true; + } else { + if((fb_w == w1) && (fb_w == w2) && (fb_h == (h1 + h2))) + return true; + } + } + } + return false; +} + +#ifdef COMPOSITION_BYPASS +/* + * Configures pipe(s) for composition bypass + */ +static int prepareBypass(hwc_context_t *ctx, hwc_layer_t *layer, int index, + int lastLayerIndex) { + if (ctx && ctx->mOvUI[index]) { + private_hwc_module_t* hwcModule = reinterpret_cast< + private_hwc_module_t*>(ctx->device.common.module); + if (!hwcModule) { + LOGE("prepareBypass null module "); + return -1; + } + private_handle_t *hnd = (private_handle_t *)layer->handle; + if(!hnd) { + LOGE("prepareBypass handle null"); + return -1; + } + hwc_rect_t sourceCrop = layer->sourceCrop; + if((sourceCrop.right - sourceCrop.left) > hwcModule->fbDevice->width || + (sourceCrop.bottom - sourceCrop.top) > hwcModule->fbDevice->height) { + ctx->animCount = ANIM_FRAME_COUNT; + return -1; + } + overlay::OverlayUI *ovUI = ctx->mOvUI[index]; + int ret = 0; + int orientation = layer->transform; + overlay_buffer_info info; + info.width = sourceCrop.right - sourceCrop.left; + info.height = sourceCrop.bottom - sourceCrop.top; + info.format = hnd->format; + info.size = hnd->size; + const bool useVGPipe = true; + //only last layer should wait for vsync + const bool waitForVsync = (index == lastLayerIndex); + const int fbnum = 0; + //Just to differentiate zorders for different layers + const int zorder = index; + ret = ovUI->setSource(info, orientation, useVGPipe, waitForVsync, + fbnum, zorder); + if (ret) { + LOGE("prepareBypass setSource failed"); + return -1; + } + + hwc_rect_t displayFrame = layer->displayFrame; + ret = ovUI->setPosition(displayFrame.left, displayFrame.top, + (displayFrame.right - displayFrame.left), + (displayFrame.bottom - displayFrame.top)); + if (ret) { + LOGE("prepareBypass setPosition failed"); + return -1; + } + } + return 0; +} + +static int drawLayerUsingBypass(hwc_context_t *ctx, hwc_layer_t *layer, + int index) { + if (ctx && ctx->mOvUI[index]) { + overlay::OverlayUI *ovUI = ctx->mOvUI[index]; + int ret = 0; + private_handle_t *hnd = (private_handle_t *)layer->handle; + ret = ovUI->queueBuffer(hnd); + if (ret) { + LOGE("drawLayerUsingBypass queueBuffer failed"); + return -1; + } + } + return 0; +} + +/* Checks if 2 layers intersect */ +static bool isIntersect(const hwc_rect_t& one, const hwc_rect_t& two) { + hwc_rect_t result; + result.left = max(one.left, two.left); + result.top = max(one.top, two.top); + result.right = min(one.right, two.right); + result.bottom = min(one.bottom, two.bottom); + const int width = result.right - result.left; + const int height = result.bottom - result.top; + const bool isEmpty = width <= 0 || height <= 0; + return !isEmpty; +} + +/* Check if layers are disjoint */ +static bool isDisjoint(const hwc_layer_list_t* list) { + //Validate supported layer range + if(list->numHwLayers <= 0 || list->numHwLayers > MAX_BYPASS_LAYERS) { + return false; + } + for(int i = 0; i < (list->numHwLayers) - 1; i++) { + for(int j = i + 1; j < list->numHwLayers; j++) { + if(isIntersect(list->hwLayers[i].displayFrame, + list->hwLayers[j].displayFrame)) { + return false; + } + } + } + return true; +} + +/* + * Checks if doing comp. bypass is possible. If video is not on and there + * are 2 layers then its doable. + */ +inline static bool isBypassDoable(hwc_composer_device_t *dev, const int yuvCount, + const hwc_layer_list_t* list) { + hwc_context_t* ctx = (hwc_context_t*)(dev); + private_hwc_module_t* hwcModule = reinterpret_cast( + dev->common.module); + //Check if enabled in build.prop + if(hwcModule->isBypassEnabled == false) { + return false; + } + //Disable bypass during animation + if(UNLIKELY(ctx->animCount)) { + --(ctx->animCount); + return false; + } +#if defined HDMI_DUAL_DISPLAY + //Disable bypass when HDMI is enabled + if(ctx->mHDMIEnabled || ctx->pendingHDMI) { + return false; + } +#endif + return (yuvCount == 0) && isDisjoint(list); +} + +/* + * Bypass is not efficient if area is greater than 1280x720 + * AND rotation is necessary, since the rotator consumes + * time greater than 1 Vsync and is sequential. + */ +inline static bool isBypassEfficient(const framebuffer_device_t* fbDev, + const hwc_layer_list_t* list, hwc_context_t* ctx) { + bool rotationNeeded = false; + for(int i = 0; i < list->numHwLayers; ++i) { + if(list->hwLayers[i].transform) { + rotationNeeded = true; + break; + } + } + return !(rotationNeeded); +} + +bool setupBypass(hwc_context_t* ctx, hwc_layer_list_t* list) { + for (int index = 0 ; index < list->numHwLayers; index++) { + if(prepareBypass(ctx, &(list->hwLayers[index]), index, + list->numHwLayers - 1) != 0) { + return false; + } + } + return true; +} + +void setBypassLayerFlags(hwc_context_t* ctx, hwc_layer_list_t* list) { + for (int index = 0 ; index < list->numHwLayers; index++) { + list->hwLayers[index].flags = HWC_COMP_BYPASS; + list->hwLayers[index].compositionType = HWC_USE_OVERLAY; + #ifdef DEBUG + LOGE("%s: layer = %d", __FUNCTION__, index); + #endif + } +} + +void unsetBypassLayerFlags(hwc_layer_list_t* list) { + for (int index = 0 ; index < list->numHwLayers; index++) { + if(list->hwLayers[index].flags == HWC_COMP_BYPASS) { + list->hwLayers[index].flags = 0; + } + } +} + +void closeBypass(hwc_context_t* ctx) { + for (int index = 0 ; index < MAX_BYPASS_LAYERS; index++) { + ctx->mOvUI[index]->closeChannel(); + #ifdef DEBUG + LOGE("%s", __FUNCTION__); + #endif + } +} +#endif //COMPOSITION_BYPASS + + +static void handleHDMIStateChange(hwc_composer_device_t *dev) { +#if defined HDMI_DUAL_DISPLAY + hwc_context_t* ctx = (hwc_context_t*)(dev); + private_hwc_module_t* hwcModule = reinterpret_cast( + dev->common.module); + framebuffer_device_t *fbDev = hwcModule->fbDevice; + if (fbDev) { + fbDev->enableHDMIOutput(fbDev, ctx->mHDMIEnabled); + } + + if(ctx && ctx->mOverlayLibObject) { + overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; + ovLibObject->setHDMIStatus(ctx->mHDMIEnabled); + if (!(ctx->mHDMIEnabled)) { + // Close the overlay channels if HDMI is disconnected + ovLibObject->closeChannel(); + } + } +#endif +} + + +/* Just mark flags and do stuff after eglSwapBuffers */ +static void hwc_enableHDMIOutput(hwc_composer_device_t *dev, bool enable) { +#if defined HDMI_DUAL_DISPLAY + hwc_context_t* ctx = (hwc_context_t*)(dev); + ctx->mHDMIEnabled = enable; + if(enable) { //On connect, allow bypass to draw once to FB + ctx->pendingHDMI = true; + } else { //On disconnect, close immediately (there will be no bypass) + handleHDMIStateChange(dev); + } +#endif +} + +static bool isValidDestination(const framebuffer_device_t* fbDev, const hwc_rect_t& rect) +{ + if (!fbDev) { + LOGE("%s: fbDev is null", __FUNCTION__); + return false; + } + + int dest_width = (rect.right - rect.left); + int dest_height = (rect.bottom - rect.top); + + if (rect.left < 0 || rect.right < 0 || rect.top < 0 || rect.bottom < 0 + || dest_width <= 0 || dest_height <= 0) { + LOGE("%s: destination: left=%d right=%d top=%d bottom=%d width=%d" + "height=%d", __FUNCTION__, rect.left, rect.right, rect.top, + rect.bottom, dest_width, dest_height); + return false; + } + + if ((rect.left+dest_width) > fbDev->width || (rect.top+dest_height) > fbDev->height) { + LOGE("%s: destination out of bound params", __FUNCTION__); + return false; + } + + return true; +} + +static int getYUVBufferCount (const hwc_layer_list_t* list) { + int yuvBufferCount = 0; + if (list) { + for (size_t i=0 ; inumHwLayers; i++) { + private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; + if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && + !(list->hwLayers[i].flags & HWC_DO_NOT_USE_OVERLAY)) { + yuvBufferCount++; + if (yuvBufferCount > 1) { + break; + } + } + } + } + return yuvBufferCount; +} + +static int getS3DVideoFormat (const hwc_layer_list_t* list) { + int s3dFormat = 0; + if (list) { + for (size_t i=0; inumHwLayers; i++) { + private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; + if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO)) + s3dFormat = FORMAT_3D_INPUT(hnd->format); + if (s3dFormat) + break; + } + } + return s3dFormat; +} + +static bool isS3DCompositionRequired() { +#ifdef HDMI_AS_PRIMARY + return overlay::is3DTV(); +#endif + return false; +} + +static void markUILayerForS3DComposition (hwc_layer_t &layer, int s3dVideoFormat) { +#ifdef HDMI_AS_PRIMARY + layer.compositionType = HWC_FRAMEBUFFER; + switch(s3dVideoFormat) { + case HAL_3D_IN_SIDE_BY_SIDE_L_R: + case HAL_3D_IN_SIDE_BY_SIDE_R_L: + layer.hints |= HWC_HINT_DRAW_S3D_SIDE_BY_SIDE; + break; + case HAL_3D_IN_TOP_BOTTOM: + layer.hints |= HWC_HINT_DRAW_S3D_TOP_BOTTOM; + break; + default: + LOGE("%s: Unknown S3D input format 0x%x", __FUNCTION__, s3dVideoFormat); + break; + } +#endif + return; +} + +static int getLayersNotUpdatingCount(const hwc_layer_list_t* list) { + int numLayersNotUpdating = 0; + if (list) { + for (size_t i=0 ; inumHwLayers; i++) { + private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; + if (hnd && (hnd->bufferType != BUFFER_TYPE_VIDEO) && + list->hwLayers[i].flags & HWC_LAYER_NOT_UPDATING) + numLayersNotUpdating++; + } + } + return numLayersNotUpdating; +} + +static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { + + hwc_context_t* ctx = (hwc_context_t*)(dev); + + if(!ctx || !list) { + LOGE("hwc_prepare invalid context or list"); + return -1; + } + + private_hwc_module_t* hwcModule = reinterpret_cast( + dev->common.module); + if(!hwcModule) { + LOGE("hwc_prepare null module "); + return -1; + } + + int yuvBufferCount = 0; + int layerType = 0; + bool isS3DCompositionNeeded = false; + int s3dVideoFormat = 0; + int numLayersNotUpdating = 0; + bool fullscreen = false; + + if (list) { + fullscreen = isFullScreenUpdate(hwcModule->fbDevice, list); + yuvBufferCount = getYUVBufferCount(list); + + bool skipComposition = false; + if (yuvBufferCount == 1) { + numLayersNotUpdating = getLayersNotUpdatingCount(list); + skipComposition = canSkipComposition(ctx, yuvBufferCount, + list->numHwLayers, numLayersNotUpdating); + s3dVideoFormat = getS3DVideoFormat(list); + if (s3dVideoFormat) + isS3DCompositionNeeded = isS3DCompositionRequired(); + } + + if (list->flags & HWC_GEOMETRY_CHANGED) { + if (yuvBufferCount == 1) { + // Inform the gralloc of the current video overlay status + setVideoOverlayStatusInGralloc(ctx, true); + } + } + + for (size_t i=0 ; inumHwLayers ; i++) { + private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; + // If there is a single Fullscreen layer, we can bypass it - TBD + // If there is only one video/camera buffer, we can bypass itn + if (list->hwLayers[i].flags & HWC_SKIP_LAYER) { + // During the animaton UI layers are marked as SKIP + // need to still mark the layer for S3D composition + if (isS3DCompositionNeeded) + markUILayerForS3DComposition(list->hwLayers[i], s3dVideoFormat); + continue; + } + if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && (yuvBufferCount == 1)) { + bool waitForVsync = skipComposition ? true:false; + if (!isValidDestination(hwcModule->fbDevice, list->hwLayers[i].displayFrame)) { + list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + skipComposition = false; + } else if(prepareOverlay(ctx, &(list->hwLayers[i]), waitForVsync) == 0) { + list->hwLayers[i].compositionType = HWC_USE_OVERLAY; + list->hwLayers[i].hints |= HWC_HINT_CLEAR_FB; + // We've opened the channel. Set the state to open. + ctx->hwcOverlayStatus = HWC_OVERLAY_OPEN; + } else if (hwcModule->compositionType & (COMPOSITION_TYPE_C2D)) { + //Fail safe path: If drawing with overlay fails, + + //Use C2D if available. + list->hwLayers[i].compositionType = HWC_USE_COPYBIT; + skipComposition = false; + } else { + //If C2D is not enabled fall back to GPU. + list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + skipComposition = false; + } + } else if (isS3DCompositionNeeded) { + markUILayerForS3DComposition(list->hwLayers[i], s3dVideoFormat); + } else if (list->hwLayers[i].flags == HWC_USE_ORIGINAL_RESOLUTION) { + list->hwLayers[i].compositionType = HWC_USE_OVERLAY; + list->hwLayers[i].hints |= HWC_HINT_CLEAR_FB; + layerType |= HWC_ORIG_RESOLUTION; + } else if (hnd && (hwcModule->compositionType & + (COMPOSITION_TYPE_C2D|COMPOSITION_TYPE_MDP))) { + list->hwLayers[i].compositionType = HWC_USE_COPYBIT; + } else if ((hwcModule->compositionType == COMPOSITION_TYPE_DYN) + && fullscreen) { + list->hwLayers[i].compositionType = HWC_USE_COPYBIT; + } else { + list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + } + } + + if (skipComposition) { + list->flags |= HWC_SKIP_COMPOSITION; + } else { + list->flags &= ~HWC_SKIP_COMPOSITION; + } + +#ifdef COMPOSITION_BYPASS + //Check if bypass is feasible + if(isBypassDoable(dev, yuvBufferCount, list) && + isBypassEfficient(hwcModule->fbDevice, list, ctx)) { + //Setup bypass + if(setupBypass(ctx, list)) { + //Overwrite layer flags only if setup succeeds. + setBypassLayerFlags(ctx, list); + list->flags |= HWC_SKIP_COMPOSITION; + ctx->bypassState = BYPASS_ON; + } + } else { + unsetBypassLayerFlags(list); + if(ctx->bypassState == BYPASS_ON) { + ctx->bypassState = BYPASS_OFF_PENDING; + } + } +#endif + } + + return 0; +} +// --------------------------------------------------------------------------- +struct range { + int current; + int end; +}; +struct region_iterator : public copybit_region_t { + + region_iterator(hwc_region_t region) { + mRegion = region; + r.end = region.numRects; + r.current = 0; + this->next = iterate; + } + +private: + static int iterate(copybit_region_t const * self, copybit_rect_t* rect) { + if (!self || !rect) { + LOGE("iterate invalid parameters"); + return 0; + } + + region_iterator const* me = static_cast(self); + if (me->r.current != me->r.end) { + rect->l = me->mRegion.rects[me->r.current].left; + rect->t = me->mRegion.rects[me->r.current].top; + rect->r = me->mRegion.rects[me->r.current].right; + rect->b = me->mRegion.rects[me->r.current].bottom; + me->r.current++; + return 1; + } + return 0; + } + + hwc_region_t mRegion; + mutable range r; +}; + + +static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer, EGLDisplay dpy, + EGLSurface surface) +{ + hwc_context_t* ctx = (hwc_context_t*)(dev); + if(!ctx) { + LOGE("drawLayerUsingCopybit null context "); + return -1; + } + + private_hwc_module_t* hwcModule = reinterpret_cast(dev->common.module); + if(!hwcModule) { + LOGE("drawLayerUsingCopybit null module "); + return -1; + } + + private_handle_t *hnd = (private_handle_t *)layer->handle; + if(!hnd) { + LOGE("drawLayerUsingCopybit invalid handle"); + return -1; + } + + // Set the copybit source: + copybit_image_t src; + src.w = ALIGN(hnd->width, 32); + src.h = hnd->height; + src.format = hnd->format; + src.base = (void *)hnd->base; + src.handle = (native_handle_t *)layer->handle; + + // Copybit source rect + hwc_rect_t sourceCrop = layer->sourceCrop; + copybit_rect_t srcRect = {sourceCrop.left, sourceCrop.top, + sourceCrop.right, + sourceCrop.bottom}; + + // Copybit destination rect + hwc_rect_t displayFrame = layer->displayFrame; + copybit_rect_t dstRect = {displayFrame.left, displayFrame.top, + displayFrame.right, + displayFrame.bottom}; + + // Copybit dst + copybit_image_t dst; + android_native_buffer_t *renderBuffer = (android_native_buffer_t *)eglGetRenderBufferANDROID(dpy, surface); + if (!renderBuffer) { + LOGE("eglGetRenderBufferANDROID returned NULL buffer"); + return -1; + } + private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle; + if(!fbHandle) { + LOGE("Framebuffer handle is NULL"); + return -1; + } + dst.w = ALIGN(fbHandle->width,32); + dst.h = fbHandle->height; + dst.format = fbHandle->format; + dst.base = (void *)fbHandle->base; + dst.handle = (native_handle_t *)renderBuffer->handle; + + // Copybit region + hwc_region_t region = layer->visibleRegionScreen; + region_iterator copybitRegion(region); + + copybit_device_t *copybit = hwcModule->copybitEngine; + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, layer->transform); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, + (layer->blending == HWC_BLENDING_NONE) ? 0xFF : layer->alpha); + copybit->set_parameter(copybit, COPYBIT_PREMULTIPLIED_ALPHA, + (layer->blending == HWC_BLENDING_PREMULT)? COPYBIT_ENABLE : COPYBIT_DISABLE); + int err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, ©bitRegion); + + if(err < 0) + LOGE("copybit stretch failed"); + + return err; +} + +static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer) +{ + if (ctx && ctx->mOverlayLibObject) { + private_hwc_module_t* hwcModule = reinterpret_cast(ctx->device.common.module); + if (!hwcModule) { + LOGE("drawLayerUsingLayer null module "); + return -1; + } + private_handle_t *hnd = (private_handle_t *)layer->handle; + overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; + int ret = 0; + + ret = ovLibObject->queueBuffer(hnd); + if (!ret) { + LOGE("drawLayerUsingOverlay queueBuffer failed"); + return -1; + } + } + return 0; +} + +static int hwc_set(hwc_composer_device_t *dev, + hwc_display_t dpy, + hwc_surface_t sur, + hwc_layer_list_t* list) +{ + hwc_context_t* ctx = (hwc_context_t*)(dev); + if(!ctx || !list) { + LOGE("hwc_set invalid context or list"); + return -1; + } + + private_hwc_module_t* hwcModule = reinterpret_cast( + dev->common.module); + if(!hwcModule) { + LOGE("hwc_set null module "); + return -1; + } + + int ret = 0; + for (size_t i=0; inumHwLayers; i++) { + if (list->hwLayers[i].flags == HWC_SKIP_LAYER) { + continue; +#ifdef COMPOSITION_BYPASS + } else if (list->hwLayers[i].flags == HWC_COMP_BYPASS) { + drawLayerUsingBypass(ctx, &(list->hwLayers[i]), i); +#endif + } else if (list->hwLayers[i].compositionType == HWC_USE_OVERLAY) { + drawLayerUsingOverlay(ctx, &(list->hwLayers[i])); + } else if (list->flags & HWC_SKIP_COMPOSITION) { + break; + } else if (list->hwLayers[i].compositionType == HWC_USE_COPYBIT) { + drawLayerUsingCopybit(dev, &(list->hwLayers[i]), (EGLDisplay)dpy, (EGLSurface)sur); + } + } + + // Do not call eglSwapBuffers if we the skip composition flag is set on the list. + if (!(list->flags & HWC_SKIP_COMPOSITION)) { + EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); + if (!sucess) { + ret = HWC_EGL_ERROR; + } + } +#ifdef COMPOSITION_BYPASS + if(ctx->bypassState == BYPASS_OFF_PENDING) { + closeBypass(ctx); + ctx->bypassState = BYPASS_OFF; + } +#endif +#if defined HDMI_DUAL_DISPLAY + if(ctx->pendingHDMI) { + handleHDMIStateChange(dev); + ctx->pendingHDMI = false; + } +#endif + + hwc_closeOverlayChannels(ctx); + int yuvBufferCount = getYUVBufferCount(list); + setHWCOverlayStatus(ctx, yuvBufferCount); + return ret; +} + +static int hwc_device_close(struct hw_device_t *dev) +{ + if(!dev) { + LOGE("hwc_device_close null device pointer"); + return -1; + } + + struct hwc_context_t* ctx = (struct hwc_context_t*)dev; + + private_hwc_module_t* hwcModule = reinterpret_cast( + ctx->device.common.module); + + // Close the overlay and copybit modules + if(hwcModule->copybitEngine) { + copybit_close(hwcModule->copybitEngine); + hwcModule->copybitEngine = NULL; + } + if(hwcModule->overlayEngine) { + overlay_control_close(hwcModule->overlayEngine); + hwcModule->overlayEngine = NULL; + } + if(hwcModule->fbDevice) { + framebuffer_close(hwcModule->fbDevice); + hwcModule->fbDevice = NULL; + } + + if (ctx) { + delete ctx->mOverlayLibObject; + ctx->mOverlayLibObject = NULL; +#ifdef COMPOSITION_BYPASS + for(int i = 0; i < MAX_BYPASS_LAYERS; i++) { + delete ctx->mOvUI[i]; + } +#endif + free(ctx); + } + return 0; +} + +/*****************************************************************************/ +static int hwc_module_initialize(struct private_hwc_module_t* hwcModule) +{ + + // Open the overlay and copybit modules + hw_module_t const *module; + + if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { + copybit_open(module, &(hwcModule->copybitEngine)); + } + if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) { + overlay_control_open(module, &(hwcModule->overlayEngine)); + } + if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { + framebuffer_open(module, &(hwcModule->fbDevice)); + } + + // get the current composition type + char property[PROPERTY_VALUE_MAX]; + if (property_get("debug.sf.hw", property, NULL) > 0) { + if(atoi(property) == 0) { + //debug.sf.hw = 0 + hwcModule->compositionType = COMPOSITION_TYPE_CPU; + } else { //debug.sf.hw = 1 + // Get the composition type + property_get("debug.composition.type", property, NULL); + if (property == NULL) { + hwcModule->compositionType = COMPOSITION_TYPE_GPU; + } else if ((strncmp(property, "mdp", 3)) == 0) { + hwcModule->compositionType = COMPOSITION_TYPE_MDP; + } else if ((strncmp(property, "c2d", 3)) == 0) { + hwcModule->compositionType = COMPOSITION_TYPE_C2D; + } else if ((strncmp(property, "dyn", 3)) == 0) { + hwcModule->compositionType = COMPOSITION_TYPE_DYN; + } else { + hwcModule->compositionType = COMPOSITION_TYPE_GPU; + } + + if(!hwcModule->copybitEngine) + hwcModule->compositionType = COMPOSITION_TYPE_GPU; + } + } else { //debug.sf.hw is not set. Use cpu composition + hwcModule->compositionType = COMPOSITION_TYPE_CPU; + } + + //Check if composition bypass is enabled + if(property_get("debug.compbypass.enable", property, NULL) > 0) { + if(atoi(property) == 1) { + hwcModule->isBypassEnabled = true; + } + } + + return 0; +} + + +static int hwc_device_open(const struct hw_module_t* module, const char* name, + struct hw_device_t** device) +{ + int status = -EINVAL; + if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { + private_hwc_module_t* hwcModule = reinterpret_cast + (const_cast(module)); + + hwc_module_initialize(hwcModule); + struct hwc_context_t *dev; + dev = (hwc_context_t*)malloc(sizeof(*dev)); + + /* initialize our state here */ + memset(dev, 0, sizeof(*dev)); + if(hwcModule->overlayEngine) { + dev->mOverlayLibObject = new overlay::Overlay(); +#ifdef COMPOSITION_BYPASS + for(int i = 0; i < MAX_BYPASS_LAYERS; i++) { + dev->mOvUI[i] = new overlay::OverlayUI(); + } + dev->animCount = 0; + dev->bypassState = BYPASS_OFF; +#endif + } else { + dev->mOverlayLibObject = NULL; +#ifdef COMPOSITION_BYPASS + for(int i = 0; i < MAX_BYPASS_LAYERS; i++) { + dev->mOvUI[i] = NULL; + } +#endif + } +#if defined HDMI_DUAL_DISPLAY + dev->mHDMIEnabled = false; + dev->pendingHDMI = false; +#endif + dev->hwcOverlayStatus = HWC_OVERLAY_CLOSED; + /* 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 = hwc_device_close; + + dev->device.prepare = hwc_prepare; + dev->device.set = hwc_set; + dev->device.enableHDMIOutput = hwc_enableHDMIOutput; + *device = &dev->device.common; + + status = 0; + } + return status; +} diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk new file mode 100644 index 0000000..0f3512c --- /dev/null +++ b/liboverlay/Android.mk @@ -0,0 +1,53 @@ +# Copyright (C) 2008 The Android Open Source Project +# Copyright (c) 2011, 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 libutils +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc +LOCAL_SRC_FILES := \ + overlayLib.cpp \ + overlayLibUI.cpp \ +LOCAL_CFLAGS:= -DLOG_TAG=\"OverlayLib\" + +ifeq ($(TARGET_USES_ION),true) + LOCAL_CFLAGS += -DUSE_ION + LOCAL_SHARED_LIBRARIES += libmemalloc +endif + +ifeq ($(TARGET_USE_HDMI_AS_PRIMARY),true) +LOCAL_CFLAGS += -DHDMI_AS_PRIMARY +endif +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 += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc +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..aa2828b --- /dev/null +++ b/liboverlay/overlay.cpp @@ -0,0 +1,1197 @@ +/* + * 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" + +#define OVERLAY_HDMI_ENABLE 8 + +/*****************************************************************************/ + + +using namespace overlay; + +struct overlay_control_context_t { + struct overlay_control_device_t device; + void *sharedMemBase; + unsigned int format3D; //input and output 3D format, zero means no 3D + unsigned int state; + unsigned int orientation; + overlay_rect posPanel; +}; + +struct overlay_data_context_t { + struct overlay_data_device_t device; + OverlayDataChannel* pobjDataChannel[2]; + unsigned int format3D; + unsigned int state; + bool setCrop; + overlay_rect cropRect; + int srcFD; //store the FD as it will needed for fb1 + int size; //size of the overlay created + void *sharedMemBase; +}; + +/////////////////////////////////////////////////////////////////////////////////// + +/* Overlay State func FIXME move to a separate module */ +class overlay_object; +int setParameterHandleState(overlay_control_context_t *ctx, + overlay_object *obj, + int param, int value); +int createOverlayHandleState(overlay_control_context_t *ctx, bool noRot, + overlay_object* overlay, int fd); +int setPositionHandleState(overlay_control_context_t *ctx, + overlay_object *obj, overlay_rect& rect, + int x, int y, uint32_t w, uint32_t h); +int configPipes_OV_2D_VIDEO_ON_PANEL(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect); + +int configPipes_OV_3D_VIDEO_2D_PANEL(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect); + +int configPipes_OV_3D_VIDEO_3D_PANEL(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect); + +int configPipes_OV_2D_VIDEO_ON_TV(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect); + +int configPipes_OV_3D_VIDEO_2D_TV(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect); + +int configPipes_OV_3D_VIDEO_3D_TV(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect); + +/* queue buffer */ +int queueBuffer_OV_2D_VIDEO_ON_PANEL(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot); + +int queueBuffer_OV_3D_VIDEO_2D_PANEL(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot); + + +int queueBuffer_OV_3D_VIDEO_3D_PANEL(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot); + +int queueBuffer_OV_2D_VIDEO_ON_TV(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot); + +int queueBuffer_OV_3D_VIDEO_2D_TV(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot); + +int queueBuffer_OV_3D_VIDEO_3D_TV(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot); + +/////////////////////////////////////////////////////////////////////////////////// + + +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; + unsigned int format3D; + 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_width(const overlay_handle_t overlay) { + return static_cast(overlay)->w; +} + +static int handle_get_height(const overlay_handle_t overlay) { + return static_cast(overlay)->h; +} + +static int handle_get_shared_fd(const overlay_handle_t overlay) { + return static_cast(overlay)->sharedMemoryFd; +} + +static int handle_get_format3D(const overlay_handle_t overlay) { + return static_cast(overlay)->format3D; +} + +/* + * 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, unsigned int format3D = 0) { + this->overlay_t::getHandleRef = getHandleRef; + this->overlay_t::w = w; + this->overlay_t::h = h; + 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.format3D = format3D; + 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, int zorder = 0) { + int index = fbnum; + if (mHandle.format3D) + index = zorder; + if (!mHandle.pobjControlChannel[index]) + mHandle.pobjControlChannel[index] = new OverlayControlChannel(); + else { + mHandle.pobjControlChannel[index]->closeControlChannel(); + mHandle.pobjControlChannel[index] = new OverlayControlChannel(); + } + bool ret = mHandle.pobjControlChannel[index]->startControlChannel( + mHandle.w, mHandle.h, mHandle.format, fbnum, norot, false, + mHandle.format3D, zorder, true); + if (ret) { + if (!(mHandle.pobjControlChannel[index]-> + getOvSessionID(mHandle.ovid[index]) && + mHandle.pobjControlChannel[index]-> + getRotSessionID(mHandle.rotid[index]) && + mHandle.pobjControlChannel[index]-> + getSize(mHandle.size))) + ret = false; + } + + if (!ret) { + closeControlChannel(index); + } + + return ret; + } + + bool setPosition(int x, int y, uint32_t w, uint32_t h, int channel) { + if (!mHandle.pobjControlChannel[channel]) + return false; + return mHandle.pobjControlChannel[channel]->setPosition( + x, y, w, h); + } + + bool getAspectRatioPosition(overlay_rect *rect, int channel) { + if (!mHandle.pobjControlChannel[channel]) + return false; + return mHandle.pobjControlChannel[channel]->getAspectRatioPosition(mHandle.w, + mHandle.h, rect); + } + + bool setParameter(int param, int value, int channel) { + if (!mHandle.pobjControlChannel[channel]) + return false; + return mHandle.pobjControlChannel[channel]->setParameter( + param, value); + } + + bool closeControlChannel(int channel) { + if (!mHandle.pobjControlChannel[channel]) + return true; + bool ret = mHandle.pobjControlChannel[channel]-> + closeControlChannel(); + delete mHandle.pobjControlChannel[channel]; + mHandle.pobjControlChannel[channel] = 0; + return ret; + } + + bool getPositionS3D(overlay_rect *rect, int channel, bool useVFB = false) { + if (!mHandle.pobjControlChannel[channel]) { + LOGE("%s:Failed got channel %d", __func__, channel); + return false; + } + int format = useVFB ? HAL_3D_OUT_SIDE_BY_SIDE_MASK : mHandle.format3D; + return mHandle.pobjControlChannel[channel]->getPositionS3D( + channel, format, rect); + } + + bool getPosition(int *x, int *y, uint32_t *w, uint32_t *h, int channel) { + if (!mHandle.pobjControlChannel[channel]) + return false; + return mHandle.pobjControlChannel[channel]->getPosition( + *x, *y, *w, *h); + } + + bool getOrientation(int *orientation, int channel) { + if (!mHandle.pobjControlChannel[channel]) + return false; + return mHandle.pobjControlChannel[channel]->getOrientation( + *orientation); + } + + void destroy_overlay() { + close(mHandle.sharedMemoryFd); + closeControlChannel(VG1_PIPE); + closeControlChannel(VG0_PIPE); + if(mHandle.format3D) { + send3DInfoPacket (0); + enableBarrier(0); + } + } + + int getFBWidth(int channel) { + if (!mHandle.pobjControlChannel[channel]) + return false; + return mHandle.pobjControlChannel[channel]->getFBWidth(); + } + + int getFBHeight(int channel) { + if (!mHandle.pobjControlChannel[channel]) + return false; + return mHandle.pobjControlChannel[channel]->getFBHeight(); + } + + inline void setFormat3D(unsigned int format3D) { + mHandle.format3D = format3D; + } + + inline bool useVirtualFB(int channel) { + if (!mHandle.pobjControlChannel[channel]) + return false; + return mHandle.pobjControlChannel[channel]->useVirtualFB(); + } +}; + +// **************************************************************************** +// 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 void error_cleanup_control(overlay_control_context_t *ctx, overlay_object *overlay, int fd, int index) { + LOGE("Failed to start control channel %d", index); + for (int i = 0; i < index; i++) + overlay->closeControlChannel(i); + if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { + munmap(ctx->sharedMemBase, sizeof(overlay_shared_data)); + ctx->sharedMemBase = MAP_FAILED; + } + if(fd > 0) + close(fd); + delete overlay; +} + +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; + } + } + + // Separate the color format from the 3D format. + // If there is 3D content; the effective format passed by the client is: + // effectiveFormat = 3D_IN | 3D_OUT | ColorFormat + unsigned int format3D = FORMAT_3D(format); + format = COLOR_FORMAT(format); + int fIn3D = FORMAT_3D_INPUT(format3D); // MSB 2 bytes are input format + int fOut3D = FORMAT_3D_OUTPUT(format3D); // LSB 2 bytes are output format + format3D = fIn3D | fOut3D; + // Use the same in/out format if not mentioned + if (!fIn3D) { + format3D |= fOut3D << SHIFT_3D; //Set the input format + } + if(!fOut3D) { + switch (fIn3D) { + case HAL_3D_IN_SIDE_BY_SIDE_L_R: + case HAL_3D_IN_SIDE_BY_SIDE_R_L: + // For all side by side formats, set the output + // format as Side-by-Side i.e 0x1 + format3D |= HAL_3D_IN_SIDE_BY_SIDE_L_R >> SHIFT_3D; + break; + default: + format3D |= fIn3D >> SHIFT_3D; //Set the output format + break; + } + } + unsigned int curState = overlay::getOverlayConfig(format3D); + if (curState == OV_3D_VIDEO_2D_PANEL || curState == OV_3D_VIDEO_2D_TV) { + LOGI("3D content on 2D display: set the output format as monoscopic"); + format3D = FORMAT_3D_INPUT(format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + } + LOGW("createOverlay: creating overlay with format3D: 0x%x, curState: %d", format3D, curState); + ctx->sharedMemBase = base; + ctx->format3D = format3D; + ctx->state = curState; + 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, format3D); + 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; + } + bool noRot; +#ifdef USE_MSM_ROTATOR + noRot = false; +#else + noRot = true; +#endif + if(-1 == createOverlayHandleState(ctx, noRot, overlay, fd)) + return 0;// NULL + overlay_shared_data* data = static_cast(ctx->sharedMemBase); + data->state = ctx->state; + for (int i=0; iovid[i] = overlay->getHwOvId(i); + data->rotid[i] = overlay->getRotSessionId(i); + } + 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; + } + // ~overlay_object calls destroy_overlay + delete obj; +} + +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; + overlay_rect rect; + // saving the position for the disconnection event + ctx->posPanel.x = x; + ctx->posPanel.y = y; + ctx->posPanel.w = w; + ctx->posPanel.h = h; + + if(-1 == setPositionHandleState(ctx, obj, rect, x, y, w, h)) + 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 = static_cast(ctx->sharedMemBase); + data->isControlSetup = true; + } + 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); + return obj->getPosition(x, y, w, h, 0) ? 0 : -1; +} + +static bool overlay_configPipes(overlay_control_context_t *ctx, + overlay_object *obj, int enable, + unsigned int newState) { + bool noRot = true; + overlay_rect rect; +#ifdef USE_MSM_ROTATOR + noRot = false; +#else + noRot = true; +#endif + switch (ctx->state) + { + case OV_2D_VIDEO_ON_PANEL: + if(-1 == configPipes_OV_2D_VIDEO_ON_PANEL(ctx, + obj, + newState, + enable, noRot, rect)) + return false; + break; + case OV_3D_VIDEO_2D_PANEL: + if(-1 == configPipes_OV_3D_VIDEO_2D_PANEL(ctx, + obj, + newState, + enable, noRot, rect)) + return false; + break; + case OV_3D_VIDEO_3D_PANEL: + if(-1 == configPipes_OV_3D_VIDEO_3D_PANEL(ctx, + obj, + newState, + enable, noRot, rect)) + return false; + break; + case OV_2D_VIDEO_ON_TV: + if(-1 == configPipes_OV_2D_VIDEO_ON_TV(ctx, + obj, + newState, + enable, noRot, rect)) + return false; + break; + case OV_3D_VIDEO_2D_TV: + if(-1 == configPipes_OV_3D_VIDEO_2D_TV(ctx, + obj, + newState, + enable, noRot, rect)) + return false; + break; + case OV_3D_VIDEO_3D_TV: + if(-1 == configPipes_OV_3D_VIDEO_3D_TV(ctx, + obj, + newState, + enable, noRot, rect)) + return false; + break; + default: + LOGE("Unknown state in configPipes"); + abort(); + } + //update the context's state + ctx->state = newState; + return true; +} + +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 = static_cast(ctx->sharedMemBase); + data->isControlSetup = false; + /* SF will inform Overlay HAL the HDMI cable connection. + This avoids polling on the system property hw.hdmiON */ + if(param == OVERLAY_HDMI_ENABLE) { + unsigned int curState = getOverlayConfig(ctx->format3D, false, value); + if(ctx->state != curState) { + LOGI("Overlay Configured for : %d Current state: %d", ctx->state, curState); + if(!overlay_configPipes(ctx, obj, value, curState)) { + LOGE("In overlay_setParameter: reconfiguring of Overlay failed !!"); + return -1; + } + else { + data->state = ctx->state; + for (int i=0; iovid[i] = obj->getHwOvId(i); + data->rotid[i] = obj->getRotSessionId(i); + } + } + } + } + } + if(param != OVERLAY_HDMI_ENABLE) { + //Save the panel orientation + if (param == OVERLAY_TRANSFORM) { + ctx->orientation = value; + if(ctx->state == OV_3D_VIDEO_3D_PANEL) { + int barrier = 0; + switch(ctx->orientation) { + case HAL_TRANSFORM_ROT_90: + case HAL_TRANSFORM_ROT_270: + barrier = BARRIER_LANDSCAPE; + break; + default: + barrier = BARRIER_PORTRAIT; + break; + } + if(!enableBarrier(barrier)) + LOGE("%s:failed to enable barriers for 3D video", __func__); + } + } + if (-1 == setParameterHandleState(ctx, obj, param, value)) + 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 +// **************************************************************************** + +static void error_cleanup_data(struct overlay_data_context_t* ctx, int index) +{ + LOGE("Couldn't start data channel %d", index); + for (int i = 0; ipobjDataChannel[i]; + ctx->pobjDataChannel[i] = NULL; + } +} + +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); + unsigned int format3D = handle_get_format3D(handle); + private_overlay_module_t* m = reinterpret_cast( + dev->common.module); + Mutex::Autolock objLock(m->pobjMutex); + bool noRot = true; +#ifdef USE_MSM_ROTATOR + noRot = false; +#else + noRot = true; +#endif + //default: set crop info to src size. + ctx->cropRect.x = 0; + ctx->cropRect.y = 0; + ctx->cropRect.w = handle_get_width(handle); + ctx->cropRect.h = handle_get_height(handle); + + ctx->sharedMemBase = MAP_FAILED; + ctx->format3D = format3D; + //Store the size, needed for HDMI mirroring + ctx->size = size; + + 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; + } + overlay_shared_data* data = static_cast + (ctx->sharedMemBase); + if (data == NULL){ + LOGE("%s:Shared data is NULL!!", __func__); + return -1; + } + ctx->state = data->state; + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + ctx->pobjDataChannel[VG0_PIPE] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[VG0_PIPE]->startDataChannel(ovid, rotid, size, FRAMEBUFFER_0, noRot)) { + error_cleanup_data(ctx, VG0_PIPE); + return -1; + } + break; + case OV_3D_VIDEO_3D_PANEL: + overlay_rect rect; + for (int i = 0; i < NUM_CHANNELS; i++) { + ovid = handle_get_ovId(handle, i); + rotid = handle_get_rotId(handle, i); + ctx->pobjDataChannel[i] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[i]->startDataChannel(ovid, rotid, size, FRAMEBUFFER_0, noRot)) { + error_cleanup_data(ctx, i); + return -1; + } + } + break; + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + for (int i = 0; i < NUM_CHANNELS; i++) { + ovid = handle_get_ovId(handle, i); + rotid = handle_get_rotId(handle, i); + ctx->pobjDataChannel[i] = new OverlayDataChannel(); + if (FRAMEBUFFER_1 == i) + noRot = true; + if (!ctx->pobjDataChannel[i]->startDataChannel(ovid, rotid, size, i, noRot)) { + error_cleanup_data(ctx, i); + return -1; + } + } + break; + case OV_3D_VIDEO_3D_TV: + for (int i = 0; i < NUM_CHANNELS; i++) { + ovid = handle_get_ovId(handle, i); + rotid = handle_get_rotId(handle, i); + ctx->pobjDataChannel[i] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[i]->startDataChannel(ovid, rotid, size, FRAMEBUFFER_1, true)) { + error_cleanup_data(ctx, i); + return -1; + } + } + if(!send3DInfoPacket(ctx->format3D & OUTPUT_MASK_3D)) + LOGI("%s:Error setting the 3D mode for TV", __func__); + break; + default: + break; + } + 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 internal overlay buffer to dequeue */ + LOGE("%s: no buffer to dequeue ...\n", __FUNCTION__); + + return 0; +} + +//Called with Mutex::Autolock objLock(m->pobjMutex); already held +int overlay_queueBufferCheckStateChange(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; + overlay_shared_data* data = 0; + if(ctx->sharedMemBase != MAP_FAILED) { + data = static_cast(ctx->sharedMemBase); + if(0 == data){ + LOGE("ctx->sharedMemBase is NULL"); + return false; + } + } + else{ + LOGE("ctx->sharedMemBase == MAP_FAILED"); + return false; + } + + bool noRot = true; +#ifdef USE_MSM_ROTATOR + noRot = false; +#else + noRot = true; +#endif + + unsigned int newState = data->state; + + switch (ctx->state) + { + case OV_2D_VIDEO_ON_PANEL: + if(-1 == queueBuffer_OV_2D_VIDEO_ON_PANEL(ctx, data, + newState, + noRot)) + return -1; + break; + case OV_3D_VIDEO_2D_PANEL: + if(-1 == queueBuffer_OV_3D_VIDEO_2D_PANEL(ctx, data, + newState, + noRot)) + return -1; + break; + case OV_3D_VIDEO_3D_PANEL: + if(-1 == queueBuffer_OV_3D_VIDEO_3D_PANEL(ctx, data, + newState, + noRot)) + return -1; + break; + case OV_2D_VIDEO_ON_TV: + if(-1 == queueBuffer_OV_2D_VIDEO_ON_TV(ctx, data, + newState, + noRot)) + return -1; + break; + case OV_3D_VIDEO_2D_TV: + if(-1 == queueBuffer_OV_3D_VIDEO_2D_TV(ctx, data, + newState, + noRot)) + return -1; + break; + case OV_3D_VIDEO_3D_TV: + if(-1 == queueBuffer_OV_3D_VIDEO_3D_TV(ctx, data, + newState, + noRot)) + return -1; + break; + default: + LOGE("Unknown state in configPipes"); + abort(); + } + //update the context's state + ctx->state = newState; + return 0; +} + +int overlay_queueBuffer(struct overlay_data_device_t *dev, + overlay_buffer_t buffer) +{ + 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 control channel is setup. + overlay_shared_data* data = NULL; + if(ctx->sharedMemBase != MAP_FAILED) { + data = static_cast(ctx->sharedMemBase); + if(data == NULL) + return false; + } + else + return false; + + if(false == data->isControlSetup) { + LOGE("Overlay Control Channel is not fully setup yet"); + return -1; + } + + // check any state-changing related events + if(-1 == overlay_queueBufferCheckStateChange(dev, buffer)){ + return -1; + } + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + if (ctx->setCrop) { + if(!ctx->pobjDataChannel[VG0_PIPE]->setCrop(ctx->cropRect.x, ctx->cropRect.y, ctx->cropRect.w, ctx->cropRect.h)) { + LOGE("%s: failed for pipe 0", __func__); + } + ctx->setCrop = false; + } + if(!ctx->pobjDataChannel[VG0_PIPE]->queueBuffer((uint32_t) buffer)) { + LOGE("%s: failed for VG pipe 0", __func__); + return -1; + } + break; + case OV_3D_VIDEO_2D_PANEL: + if (ctx->setCrop) { + overlay_rect rect; + ctx->pobjDataChannel[VG0_PIPE]->getCropS3D(&ctx->cropRect, VG0_PIPE, ctx->format3D, &rect); + if(!ctx->pobjDataChannel[VG0_PIPE]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: failed for pipe 0", __func__); + } + ctx->setCrop = false; + } + if(!ctx->pobjDataChannel[VG0_PIPE]->queueBuffer((uint32_t) buffer)) { + LOGE("%s: failed for VG pipe 0", __func__); + return -1; + } + break; + case OV_3D_VIDEO_3D_PANEL: + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i=0; ipobjDataChannel[i]->queueBuffer((uint32_t) buffer)) { + LOGE("%s: failed for VG pipe %d", __func__, i); + return -1; + } + } + break; + default: + break; + } + return 0; +} + +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); + ctx->srcFD = fd; + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + if(!ctx->pobjDataChannel[VG0_PIPE]->setFd(fd)) { + LOGE("%s: failed for VG pipe 0", __func__); + return -1; + } + break; + case OV_3D_VIDEO_3D_PANEL: + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i=0; ipobjDataChannel[i]->setFd(fd)) { + LOGE("%s: failed for pipe %d", __func__, i); + return -1; + } + } + break; + default: + break; + } + 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; + overlay_shared_data* data = static_cast(ctx->sharedMemBase); + //Yield processor until control channel is fully set up i.e commit happens. + while(false == data->isControlSetup) { + sched_yield(); + } + Mutex::Autolock objLock(m->pobjMutex); + overlay_rect rect; + ctx->cropRect.x = x; + ctx->cropRect.y = y; + ctx->cropRect.w = w; + ctx->cropRect.h = h; + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + ctx->setCrop = true; + break; + case OV_2D_VIDEO_ON_TV: + for (int i=0; ipobjDataChannel[i]->setCrop(x, y, w, h)) { + LOGE("%s: failed for pipe %d", __func__, i); + return -1; + } + } + break; + case OV_3D_VIDEO_3D_PANEL: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i=0; ipobjDataChannel[i]->getCropS3D(&ctx->cropRect, i, ctx->format3D, &rect); + if(!ctx->pobjDataChannel[i]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: failed for pipe %d", __func__, i); + return -1; + } + } + break; + default: + break; + } + 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; +} + +#include "overlayState.cpp" diff --git a/liboverlay/overlayLib.cpp b/liboverlay/overlayLib.cpp new file mode 100644 index 0000000..f0db551 --- /dev/null +++ b/liboverlay/overlayLib.cpp @@ -0,0 +1,1799 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2010-2011, 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 +#define DEBUG_OVERLAY true +/* Helper functions */ +static inline size_t ALIGN(size_t x, size_t align) { + return (x + align-1) & ~(align-1); +} + +using namespace overlay; +using android::sp; +using gralloc::IMemAlloc; +using gralloc::IonController; +using gralloc::alloc_data; + +#ifdef HDMI_AS_PRIMARY +bool Overlay::sHDMIAsPrimary = true; +#else +bool Overlay::sHDMIAsPrimary = false; +#endif + +int overlay::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_RGBX_8888: + return MDP_RGBX_8888; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + return MDP_Y_CBCR_H2V1; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + return MDP_Y_CRCB_H2V2; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + return MDP_Y_CBCR_H2V2; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + return MDP_Y_CRCB_H2V2_TILE; + case HAL_PIXEL_FORMAT_YV12: + return MDP_Y_CR_CB_GH2V2; + default: + LOGE("%s: unknown color format [0x%x]", __FUNCTION__, format); + return -1; + } + return -1; +} + +int overlay::get_mdp_orientation(int value) { + switch(value) { + case 0: return 0; + case HAL_TRANSFORM_FLIP_V: return MDP_FLIP_UD; + case HAL_TRANSFORM_FLIP_H: return MDP_FLIP_LR; + case HAL_TRANSFORM_ROT_90: return MDP_ROT_90; + case HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V: + return MDP_ROT_90|MDP_FLIP_LR; + case HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H: + return MDP_ROT_90|MDP_FLIP_UD; + case HAL_TRANSFORM_ROT_180: return MDP_ROT_180; + case HAL_TRANSFORM_ROT_270: return MDP_ROT_270; + default: + LOGE("%s: invalid rotation value (value = 0x%x", + __FUNCTION__, value); + return -1; + } + return -1; +} + +// Rotator - input to output mapping +int overlay::get_rot_output_format(int format) { + switch (format) { + case MDP_Y_CRCB_H2V2_TILE: + return MDP_Y_CRCB_H2V2; + case MDP_Y_CB_CR_H2V2: + case MDP_Y_CR_CB_GH2V2: + return MDP_Y_CBCR_H2V2; + default: + return format; + } + return -1; +} + +// This function normalizes the crop values to be all even +void overlay::normalize_crop(uint32_t& xy, uint32_t& wh) { + + if (xy & 0x0001) { + // x or y is odd, increment it's value + xy += 1; + // Since we've incremented x(y), we need to decrement + // w(h) accordingly + if (wh & 0x0001) { + // w or h is odd, decrement it by 1, to make it even + EVEN_OUT(wh); + } else { + // w(h) is already even, hence we decrement by 2 + wh -=2; + } + } else { + EVEN_OUT(wh); + } +} + +#define LOG_TAG "OverlayLIB" +static void reportError(const char* message) { + LOGE( "%s", message); +} + +void overlay::dump(mdp_overlay& mOVInfo) { + if (!DEBUG_OVERLAY) + return; + LOGE("mOVInfo:"); + LOGE("src: width %d height %d format %s user_data[0] %d", mOVInfo.src.width, + mOVInfo.src.height, getFormatString(mOVInfo.src.format), + mOVInfo.user_data[0]); + LOGE("src_rect: x %d y %d w %d h %d", mOVInfo.src_rect.x, + mOVInfo.src_rect.y, mOVInfo.src_rect.w, mOVInfo.src_rect.h); + LOGE("dst_rect: x %d y %d w %d h %d", mOVInfo.dst_rect.x, + mOVInfo.dst_rect.y, mOVInfo.dst_rect.w, mOVInfo.dst_rect.h); + LOGE("z_order %d is_fg %d alpha %d transp_mask %d flags %x id %d", + mOVInfo.z_order, mOVInfo.is_fg, mOVInfo.alpha, mOVInfo.transp_mask, + mOVInfo.flags, mOVInfo.id); +} + +void overlay::dump(msm_rotator_img_info& mRotInfo) { + if (!DEBUG_OVERLAY) + return; + LOGE("mRotInfo:"); + LOGE("session_id %d dst_x %d dst_y %d rotations %d enable %d", + mRotInfo.session_id, mRotInfo.dst_x, mRotInfo.dst_y, + mRotInfo.rotations, mRotInfo.enable); + LOGE("src: width %d height %d format %s", mRotInfo.src.width, + mRotInfo.src.height, getFormatString(mRotInfo.src.format)); + LOGE("dst: width %d height %d format %s", mRotInfo.dst.width, + mRotInfo.dst.height, getFormatString(mRotInfo.src.format)); + LOGE("src_rect: x %d y %d w %d h %d", mRotInfo.src_rect.x, + mRotInfo.src_rect.y, mRotInfo.src_rect.w, mRotInfo.src_rect.h); +} + +const char* overlay::getFormatString(int format){ + static const char* formats[] = { + "MDP_RGB_565", + "MDP_XRGB_8888", + "MDP_Y_CBCR_H2V2", + "MDP_ARGB_8888", + "MDP_RGB_888", + "MDP_Y_CRCB_H2V2", + "MDP_YCRYCB_H2V1", + "MDP_Y_CRCB_H2V1", + "MDP_Y_CBCR_H2V1", + "MDP_RGBA_8888", + "MDP_BGRA_8888", + "MDP_RGBX_8888", + "MDP_Y_CRCB_H2V2_TILE", + "MDP_Y_CBCR_H2V2_TILE", + "MDP_Y_CR_CB_H2V2", + "MDP_Y_CR_CB_GH2V2", + "MDP_Y_CB_CR_H2V2", + "MDP_Y_CRCB_H1V1", + "MDP_Y_CBCR_H1V1", + "MDP_IMGTYPE_LIMIT", + "MDP_BGR_565", + "MDP_FB_FORMAT", + "MDP_IMGTYPE_LIMIT2" + }; + return formats[format]; +} + +bool overlay::isHDMIConnected () { + char value[PROPERTY_VALUE_MAX]; + property_get("hw.hdmiON", value, "0"); + int isHDMI = atoi(value); + return isHDMI ? true : false; +} + +bool overlay::is3DTV() { + char is3DTV = '0'; + FILE *fp = fopen(EDID_3D_INFO_FILE, "r"); + if (fp) { + fread(&is3DTV, 1, 1, fp); + fclose(fp); + } + LOGI("3DTV EDID flag: %c", is3DTV); + return (is3DTV == '0') ? false : true; +} + +bool overlay::isPanel3D() { + int fd = open("/dev/graphics/fb0", O_RDWR, 0); + if (fd < 0) { + reportError("Can't open framebuffer 0"); + return false; + } + fb_fix_screeninfo finfo; + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) { + reportError("FBIOGET_FSCREENINFO on fb0 failed"); + close(fd); + fd = -1; + return false; + } + close(fd); + return (FB_TYPE_3D_PANEL == finfo.type) ? true : false; +} + +bool overlay::usePanel3D() { + if (Overlay::sHDMIAsPrimary) + return is3DTV(); + + if(!isPanel3D()) + return false; + char value[PROPERTY_VALUE_MAX]; + property_get("persist.user.panel3D", value, "0"); + int usePanel3D = atoi(value); + return usePanel3D ? true : false; +} + +bool overlay::send3DInfoPacket (unsigned int format3D) { + FILE *fp = fopen(FORMAT_3D_FILE, "wb"); + if (fp) { + fprintf(fp, "%d", format3D); + fclose(fp); + fp = NULL; + return true; + } + LOGE("%s:no sysfs entry for setting 3d mode!", __FUNCTION__); + return false; +} + +bool overlay::enableBarrier (unsigned int orientation) { + FILE *fp = fopen(BARRIER_FILE, "wb"); + if (fp) { + fprintf(fp, "%d", orientation); + fclose(fp); + fp = NULL; + return true; + } + LOGE("%s:no sysfs entry for enabling barriers on 3D panel!", __FUNCTION__); + return false; +} + +int overlay::getColorFormat(int format) +{ + return (format == HAL_PIXEL_FORMAT_YV12) ? + format : COLOR_FORMAT(format); +} + +unsigned int overlay::getOverlayConfig (unsigned int format3D, bool poll, + bool isHDMI) { + bool isTV3D = false; + unsigned int curState = 0; + if (poll) + isHDMI = isHDMIConnected(); + if (isHDMI) { + LOGD("%s: HDMI connected... checking the TV type", __FUNCTION__); + if (format3D) { + if (is3DTV()) + curState = OV_3D_VIDEO_3D_TV; + else + curState = OV_3D_VIDEO_2D_TV; + } else + curState = OV_2D_VIDEO_ON_TV; + } else { + LOGD("%s: HDMI not connected...", __FUNCTION__); + if(format3D) { + if (usePanel3D()) + curState = OV_3D_VIDEO_3D_PANEL; + else + curState = OV_3D_VIDEO_2D_PANEL; + } + else + curState = OV_2D_VIDEO_ON_PANEL; + } + return curState; +} + +Overlay::Overlay() : mChannelUP(false), mHDMIConnected(false), + mS3DFormat(0), mCroppedSrcWidth(0), + mCroppedSrcHeight(0), mState(-1) { + mOVBufferInfo.width = mOVBufferInfo.height = 0; + mOVBufferInfo.format = mOVBufferInfo.size = 0; +} + +Overlay::~Overlay() { + closeChannel(); +} + +int Overlay::getFBWidth(int channel) const { + return objOvCtrlChannel[channel].getFBWidth(); +} + +int Overlay::getFBHeight(int channel) const { + return objOvCtrlChannel[channel].getFBHeight(); +} + +bool Overlay::startChannel(const overlay_buffer_info& info, int fbnum, + bool norot, bool uichannel, + unsigned int format3D, int channel, + bool ignoreFB, int num_buffers) { + int zorder = 0; + int format = getColorFormat(info.format); + mCroppedSrcWidth = info.width; + mCroppedSrcHeight = info.height; + if (format3D) + zorder = channel; + if (mState == -1) + mState = OV_UI_MIRROR_TV; + + mChannelUP = objOvCtrlChannel[channel].startControlChannel(info.width, + info.height, format, fbnum, + norot, uichannel, + format3D, zorder, ignoreFB); + if (!mChannelUP) { + LOGE("startChannel for fb%d failed", fbnum); + return mChannelUP; + } + objOvCtrlChannel[channel].setSize(info.size); + return objOvDataChannel[channel].startDataChannel(objOvCtrlChannel[channel], fbnum, + norot, uichannel, num_buffers); +} + +bool Overlay::closeChannel() { + + if (!mChannelUP) + return true; + + if(mS3DFormat) { + if (mHDMIConnected) + overlay::send3DInfoPacket(0); + else if (mState == OV_3D_VIDEO_3D_PANEL) { + if (sHDMIAsPrimary) + overlay::send3DInfoPacket(0); + else + enableBarrier(0); + } + } + for (int i = 0; i < NUM_CHANNELS; i++) { + objOvCtrlChannel[i].closeControlChannel(); + objOvDataChannel[i].closeDataChannel(); + } + mChannelUP = false; + mS3DFormat = 0; + mOVBufferInfo.width = 0; + mOVBufferInfo.height = 0; + mOVBufferInfo.format = 0; + mOVBufferInfo.size = 0; + mState = -1; + return true; +} + +bool Overlay::getPosition(int& x, int& y, uint32_t& w, uint32_t& h, int channel) { + return objOvCtrlChannel[channel].getPosition(x, y, w, h); +} + +bool Overlay::getOrientation(int& orientation, int channel) const { + return objOvCtrlChannel[channel].getOrientation(orientation); +} + +bool Overlay::setPosition(int x, int y, uint32_t w, uint32_t h) { + bool ret = false; + overlay_rect rect; + switch (mState) { + case OV_UI_MIRROR_TV: + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + return setChannelPosition(x, y, w, h, VG0_PIPE); + break; + case OV_2D_VIDEO_ON_TV: + objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition(mCroppedSrcWidth, + mCroppedSrcHeight, &rect); + setChannelPosition(rect.x, rect.y, rect.w, rect.h, VG1_PIPE); + return setChannelPosition(x, y, w, h, VG0_PIPE); + break; + case OV_3D_VIDEO_3D_PANEL: + for (int i = 0; i < NUM_CHANNELS; i++) { + if (sHDMIAsPrimary) + objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, &rect); + else { + if (!objOvCtrlChannel[i].useVirtualFB()) { + LOGE("%s: failed virtual fb for channel %d", __FUNCTION__, i); + return false; + } + objOvCtrlChannel[i].getPositionS3D(i, 0x1, &rect); + } + if(!setChannelPosition(rect.x, rect.y, rect.w, rect.h, i)) { + LOGE("%s: failed for channel %d", __FUNCTION__, i); + return false; + } + } + break; + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i = 0; i < NUM_CHANNELS; i++) { + ret = objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, &rect); + if (!ret) + ret = setChannelPosition(x, y, w, h, i); + else + ret = setChannelPosition(rect.x, rect.y, rect.w, rect.h, i); + if (!ret) { + LOGE("%s: failed for channel %d", __FUNCTION__, i); + return ret; + } + } + break; + default: + LOGE("%s:Unknown state %d", __FUNCTION__, mState); + break; + } + return true; +} + +bool Overlay::setChannelPosition(int x, int y, uint32_t w, uint32_t h, int channel) { + return objOvCtrlChannel[channel].setPosition(x, y, w, h); +} + +bool Overlay::updateOverlaySource(const overlay_buffer_info& info, int orientation, + bool waitForVsync) { + bool ret = false; + int currentFlags = 0; + if (objOvCtrlChannel[0].isChannelUP()) { + currentFlags = objOvCtrlChannel[0].getOverlayFlags(); + } + + bool needUpdateFlags = false; + if (waitForVsync) { + if (currentFlags & MDP_OV_PLAY_NOWAIT) { + needUpdateFlags = true; + } + } else { + if (!(currentFlags & MDP_OV_PLAY_NOWAIT)) { + needUpdateFlags = true; + } + } + + bool geometryChanged = true; + if (info.width == mOVBufferInfo.width && + info.height == mOVBufferInfo.height && + info.format == mOVBufferInfo.format) { + geometryChanged = false; + } + + if (sHDMIAsPrimary) + needUpdateFlags = false; + + if ((false == needUpdateFlags) && (false == geometryChanged)) { + objOvDataChannel[0].updateDataChannel(0, 0); + return true; + } + + // Disable rotation for the HDMI channels + int orientHdmi = 0; + int orientPrimary = sHDMIAsPrimary ? 0 : orientation; + int orient[2] = {orientPrimary, orientHdmi}; + // enable waitForVsync on HDMI + bool waitForHDMI = true; + bool waitForPrimary = sHDMIAsPrimary ? true : waitForVsync; + bool waitCond[2] = {waitForPrimary, waitForHDMI}; + + switch(mState) { + case OV_3D_VIDEO_3D_PANEL: + orient[1] = sHDMIAsPrimary ? 0 : orientation; + break; + case OV_3D_VIDEO_3D_TV: + orient[0] = 0; + break; + default: + break; + } + + int numChannelsToUpdate = NUM_CHANNELS; + if (!geometryChanged) { + // Only update the primary channel - we only need to update the + // wait/no-wait flags + if (objOvCtrlChannel[0].isChannelUP()) { + return objOvCtrlChannel[0].updateWaitForVsyncFlags(waitForVsync); + } + } + + // Set the overlay source info + for (int i = 0; i < NUM_CHANNELS; i++) { + if (objOvCtrlChannel[i].isChannelUP()) { + ret = objOvCtrlChannel[i].updateOverlaySource(info, orient[i], waitCond[i]); + if (!ret) { + LOGE("objOvCtrlChannel[%d].updateOverlaySource failed", i); + return false; + } + objOvCtrlChannel[i].setSize(info.size); + int updateDataChannel = orientation ? 1:0; + ret = objOvDataChannel[i].updateDataChannel(updateDataChannel, info.size); + } + } + if (ret) { + mOVBufferInfo = info; + } else + LOGE("update failed"); + return ret; +} + +int Overlay::getS3DFormat(int format) { + // The S3D is part of the HAL_PIXEL_FORMAT_YV12 value. Add + // an explicit check for the format + if (format == HAL_PIXEL_FORMAT_YV12) { + return 0; + } + int format3D = FORMAT_3D(format); + int fIn3D = FORMAT_3D_INPUT(format3D); // MSB 2 bytes are input format + int fOut3D = FORMAT_3D_OUTPUT(format3D); // LSB 2 bytes are output format + format3D = fIn3D | fOut3D; + if (!fIn3D) { + format3D |= fOut3D << SHIFT_3D; //Set the input format + } + if (!fOut3D) { + format3D |= fIn3D >> SHIFT_3D; //Set the output format + } + return format3D; +} + +bool Overlay::setSource(const overlay_buffer_info& info, int orientation, + bool hdmiConnected, bool waitForVsync, int num_buffers) { + // Separate the color format from the 3D format. + // If there is 3D content; the effective format passed by the client is: + // effectiveFormat = 3D_IN | 3D_OUT | ColorFormat + int newState = mState; + bool stateChange = false, ret = false; + unsigned int format3D = getS3DFormat(info.format); + int colorFormat = getColorFormat(info.format); + if (-1 == mState) { + newState = getOverlayConfig (format3D, false, hdmiConnected); + stateChange = (mState == newState) ? false : true; + } + + if (stateChange) { + closeChannel(); + mHDMIConnected = hdmiConnected; + mState = newState; + mS3DFormat = format3D; + if (mState == OV_3D_VIDEO_2D_PANEL || mState == OV_3D_VIDEO_2D_TV) { + LOGI("3D content on 2D display: set the output format as monoscopic"); + mS3DFormat = FORMAT_3D_INPUT(format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + } + // We always enable the rotator for the primary. + bool noRot = false; + bool uiChannel = false; + switch(mState) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + return startChannel(info, FRAMEBUFFER_0, noRot, false, + mS3DFormat, VG0_PIPE, waitForVsync, num_buffers); + break; + case OV_3D_VIDEO_3D_PANEL: + if (sHDMIAsPrimary) { + noRot = true; + waitForVsync = true; + send3DInfoPacket(mS3DFormat & OUTPUT_MASK_3D); + } + for (int i=0; i(buffer); + if (!hnd) { + LOGE("Overlay::queueBuffer invalid handle"); + return false; + } + const size_t offset = hnd->offset; + const int fd = hnd->fd; + switch (mState) { + case OV_UI_MIRROR_TV: + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + if(!queueBuffer(fd, offset, VG0_PIPE)) { + LOGE("%s:failed for channel 0", __FUNCTION__); + return false; + } + break; + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_3D_PANEL: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i=0; i fbWidth * height) { + height = fbWidth * height / width; + EVEN_OUT(height); + width = fbWidth; + } else if (width * fbHeight < fbWidth * height) { + width = fbHeight * width / height; + EVEN_OUT(width); + height = fbHeight; + } else { + width = fbWidth; + height = fbHeight; + } + /* 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 > fbWidth) width = fbWidth; + if (height > fbHeight) height = fbHeight; + x = (fbWidth - width) / 2; + y = (fbHeight - height) / 2; + rect->x = x; + rect->y = y; + rect->w = width; + rect->h = height; + return true; +} + +bool OverlayControlChannel::getPositionS3D(int channel, int format, overlay_rect *rect) { + int wDisp = getFBWidth(); + int hDisp = getFBHeight(); + switch (format & OUTPUT_MASK_3D) { + case HAL_3D_OUT_SIDE_BY_SIDE_MASK: + if (channel == VG0_PIPE) { + rect->x = 0; + rect->y = 0; + rect->w = wDisp/2; + rect->h = hDisp; + } else { + rect->x = wDisp/2; + rect->y = 0; + rect->w = wDisp/2; + rect->h = hDisp; + } + break; + case HAL_3D_OUT_TOP_BOTTOM_MASK: + if (channel == VG0_PIPE) { + rect->x = 0; + rect->y = 0; + rect->w = wDisp; + rect->h = hDisp/2; + } else { + rect->x = 0; + rect->y = hDisp/2; + rect->w = wDisp; + rect->h = hDisp/2; + } + break; + case HAL_3D_OUT_MONOSCOPIC_MASK: + if (channel == VG1_PIPE) { + rect->x = 0; + rect->y = 0; + rect->w = wDisp; + rect->h = hDisp; + } + else + return false; + break; + case HAL_3D_OUT_INTERLEAVE_MASK: + break; + default: + reportError("Unsupported 3D output format"); + break; + } + return true; +} + +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(const overlay_buffer_info& info, + int flags, int orientation, int zorder, + bool ignoreFB, int requestType) { + int w = info.width; + int h = info.height; + int format = info.format; + + 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 (!orientation) { + mOVInfo.src_rect.w = w - ((((w-1)/64 +1)*64) - w); + mOVInfo.src_rect.h = h - ((((h-1)/32 +1)*32) - h); + } 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; + } + } 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.user_data[0] = 0; + if (requestType == NEW_REQUEST) { + mOVInfo.id = MSMFB_NEW_REQUEST; + mOVInfo.z_order = zorder; + mOVInfo.alpha = 0xff; + mOVInfo.transp_mask = 0xffffffff; + mOVInfo.flags = flags; + } + if (!ignoreFB) + mOVInfo.flags |= MDP_OV_PLAY_NOWAIT; + else + mOVInfo.flags &= ~MDP_OV_PLAY_NOWAIT; + + return true; +} + +bool OverlayControlChannel::startOVRotatorSessions( + const overlay_buffer_info& info, + int orientation, int requestType) { + bool ret = true; + int w = info.width; + int h = info.height; + int format = info.format; + + if (orientation) { + 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; + } + mRotInfo.dst.format = get_rot_output_format(format); + mRotInfo.dst_x = 0; + mRotInfo.dst_y = 0; + mRotInfo.src_rect.x = 0; + mRotInfo.src_rect.y = 0; + mRotInfo.rotations = 0; + + if (requestType == NEW_REQUEST) { + mRotInfo.enable = 0; + if(mUIChannel) + mRotInfo.enable = 1; + mRotInfo.session_id = 0; + } else + mRotInfo.enable = 1; + + int result = ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo); + if (result) { + reportError("Rotator session failed"); + dump(mRotInfo); + ret = false; + } + } + + if (ret && ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) { + reportError("startOVRotatorSessions, Overlay set failed"); + dump(mOVInfo); + ret = false; + } + + if (!ret) + closeControlChannel(); + else + mIsChannelUpdated = true; + return ret; +} + +bool OverlayControlChannel::updateOverlaySource(const overlay_buffer_info& info, + int orientation, bool waitForVsync) +{ + int colorFormat = getColorFormat(info.format); + int hw_format = get_mdp_format(colorFormat); + overlay_buffer_info ovBufInfo; + ovBufInfo.width = info.width; + ovBufInfo.height = info.height; + ovBufInfo.format = hw_format; + + if (!setOverlayInformation(ovBufInfo, 0, orientation, 0, waitForVsync, UPDATE_REQUEST)) + return false; + + return startOVRotatorSessions(ovBufInfo, orientation, UPDATE_REQUEST); +} + +bool OverlayControlChannel::startControlChannel(int w, int h, + int format, int fbnum, bool norot, + bool uichannel, + unsigned int format3D, int zorder, + bool ignoreFB) { + mNoRot = norot; + mFormat = format; + mUIChannel = uichannel; + fb_fix_screeninfo finfo; + fb_var_screeninfo vinfo; + int hw_format; + int flags = 0; + int colorFormat = format; + // The interlace mask is part of the HAL_PIXEL_FORMAT_YV12 value. Add + // an explicit check for the format + if ((format != HAL_PIXEL_FORMAT_YV12) && (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; + } + + mFormat3D = format3D; + if ( !mFormat3D || (mFormat3D & HAL_3D_OUT_MONOSCOPIC_MASK) ) { + // Set the share bit for sharing the VG pipe + flags |= MDP_OV_PIPE_SHARE; + } + if (!openDevices(fbnum)) + return false; + + int orientation = mNoRot ? 0: 1; + overlay_buffer_info ovBufInfo; + ovBufInfo.width = w; + ovBufInfo.height = h; + ovBufInfo.format = hw_format; + if (!setOverlayInformation(ovBufInfo, flags, orientation, zorder, ignoreFB, NEW_REQUEST)) + return false; + + return startOVRotatorSessions(ovBufInfo, orientation, NEW_REQUEST); +} + +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; + ioctl(mFD, MSMFB_OVERLAY_UNSET, &ovid); + if (m3DOVInfo.is_3d) { + m3DOVInfo.is_3d = 0; + ioctl(mFD, MSMFB_OVERLAY_3D, &m3DOVInfo); + } + + close(mFD); + memset(&mOVInfo, 0, sizeof(mOVInfo)); + memset(&mRotInfo, 0, sizeof(mRotInfo)); + memset(&m3DOVInfo, 0, sizeof(m3DOVInfo)); + mFD = -1; + + return true; +} + +bool OverlayControlChannel::updateWaitForVsyncFlags(bool waitForVsync) { + if (!waitForVsync) + mOVInfo.flags |= MDP_OV_PLAY_NOWAIT; + else + mOVInfo.flags &= ~MDP_OV_PLAY_NOWAIT; + + if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) { + LOGE("%s: OVERLAY_SET failed", __FUNCTION__); + dump(mOVInfo); + return false; + } + return true; +} + +bool OverlayControlChannel::setPosition(int x, int y, uint32_t w, uint32_t h) { + + if (!isChannelUP() || + (x < 0) || (y < 0) || ((x + w) > mFBWidth) || + ((y + h) > mFBHeight)) { + reportError("setPosition failed"); + LOGW("x %d y %d (x+w) %d (y+h) %d FBWidth %d FBHeight %d", x, y, x+w, y+h, + mFBWidth,mFBHeight); + return false; + } + if( x != mOVInfo.dst_rect.x || y != mOVInfo.dst_rect.y || + w != mOVInfo.dst_rect.w || h != mOVInfo.dst_rect.h ) { + 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; + x = (mFBWidth - w) / 2; + } + if(h >(ov.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) { + h = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.h; + y = (mFBHeight - h) / 2; + } + 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"); + dump(ov); + 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::useVirtualFB() { + if(!m3DOVInfo.is_3d) { + m3DOVInfo.is_3d = 1; + mFBWidth *= 2; + mFBHeight /= 2; + m3DOVInfo.width = mFBWidth; + m3DOVInfo.height = mFBHeight; + return ioctl(mFD, MSMFB_OVERLAY_3D, &m3DOVInfo) ? false : true; + } + return true; +} + +bool OverlayControlChannel::setParameter(int param, int value, bool fetch) { + if (!isChannelUP()) { + LOGE("%s: channel is not up", __FUNCTION__); + return false; + } + + mdp_overlay ov = mOVInfo; + if (fetch && ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { + reportError("setParameter, overlay GET failed"); + return false; + } + mOVInfo = ov; + if (!mIsChannelUpdated && (OVERLAY_TRANSFORM == param)) { + int orientation = get_mdp_orientation(value); + if (orientation == mOVInfo.user_data[0]) { + return true; + } + } + mIsChannelUpdated = false; + + switch (param) { + case OVERLAY_DITHER: + break; + case OVERLAY_TRANSFORM: + { + int val = mOVInfo.user_data[0]; + if (mNoRot) + return true; + + int rot = value; + + switch(rot) { + case 0: + case HAL_TRANSFORM_FLIP_H: + case HAL_TRANSFORM_FLIP_V: + { + 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(); + } + break; + } + case HAL_TRANSFORM_ROT_90: + case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H): + case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V): + { + 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(); + } + break; + } + case HAL_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(); + } + break; + } + case HAL_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(); + } + break; + } + default: return false; + } + int mdp_rotation = get_mdp_orientation(rot); + if (mdp_rotation == -1) + return false; + + mOVInfo.user_data[0] = mdp_rotation; + mRotInfo.rotations = mOVInfo.user_data[0]; + + /* Rotator always outputs non-tiled formats. + If rotator is used, set Overlay input to non-tiled + Else, overlay input remains tiled */ + + if (mOVInfo.user_data[0]) { + if (mRotInfo.src.format == MDP_Y_CRCB_H2V2_TILE) + mOVInfo.src.format = MDP_Y_CRCB_H2V2; + 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(mUIChannel) + mRotInfo.enable = 1; + } + if (ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo)) { + reportError("setParameter, rotator start failed"); + return false; + } + + if ((mOVInfo.user_data[0] == MDP_ROT_90) || + (mOVInfo.user_data[0] == MDP_ROT_270)) + mOVInfo.flags |= MDP_SOURCE_ROTATED_90; + else + mOVInfo.flags &= ~MDP_SOURCE_ROTATED_90; + + if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) { + reportError("setParameter, overlay set failed"); + dump(mOVInfo); + 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; + //mOVInfo has the current Overlay Position + 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; + // mOVInfo has the current orientation + orientation = mOVInfo.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), mUpdateDataChannel(0) +{ +#ifdef USE_ION + mAlloc = gralloc::IAllocController::getInstance(); +#endif +} + +OverlayDataChannel::~OverlayDataChannel() { + closeDataChannel(); +} + +bool OverlayDataChannel::startDataChannel( + const OverlayControlChannel& objOvCtrlChannel, + int fbnum, bool norot, bool uichannel, int num_buffers) { + 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, num_buffers); + } + else + return false; +} + +bool OverlayDataChannel::openDevices(int fbnum, bool uichannel, int num_buffers) { + 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; + } + + return mapRotatorMemory(num_buffers, uichannel, NEW_REQUEST); + } + return true; +} + +bool OverlayDataChannel::mapRotatorMemory(int num_buffers, bool uiChannel, int requestType) +{ + mPmemAddr = MAP_FAILED; + +#ifdef USE_ION + alloc_data data; + data.base = 0; + data.fd = -1; + data.offset = 0; + data.size = mPmemOffset * num_buffers; + data.align = getpagesize(); + data.uncached = true; + + int err = mAlloc->allocate(data, GRALLOC_USAGE_PRIVATE_ADSP_HEAP| + GRALLOC_USAGE_PRIVATE_SMI_HEAP, 0); + if(err) { + reportError("Cant allocate from ION"); + close(mFD); + mFD = -1; + close(mRotFD); + mRotFD = -1; + return false; + } + mPmemFD = data.fd; + mPmemAddr = data.base; + mBufferType = data.allocType; +#else + + if((requestType == NEW_REQUEST) && !uiChannel) { + mPmemFD = open("/dev/pmem_smipool", O_RDWR | O_SYNC); + if(mPmemFD >= 0) + mPmemAddr = (void *) mmap(NULL, mPmemOffset * num_buffers, 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 * num_buffers, 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; + } + } + } +#endif + // Set this flag if source memory is fb + if(uiChannel) + mRotData.src.flags |= MDP_MEMORY_ID_TYPE_FB; + + mOvDataRot.data.memory_id = mPmemFD; + mRotData.dst.memory_id = mPmemFD; + mRotData.dst.offset = 0; + mNumBuffers = num_buffers; + mCurrentItem = 0; + for (int i = 0; i < num_buffers; i++) + mRotOffset[i] = i * mPmemOffset; + + return true; +} + +bool OverlayDataChannel::updateDataChannel(int updateStatus, int size) { + mUpdateDataChannel = updateStatus; + mNewPmemOffset = size; + return true; +} + +bool OverlayDataChannel::startDataChannel(int ovid, int rotid, int size, + int fbnum, bool norot, + bool uichannel, int num_buffers) { + 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; + mNumBuffers = 0; + mCurrentItem = 0; + + return openDevices(fbnum, uichannel, num_buffers); +} + +bool OverlayDataChannel::closeDataChannel() { + if (!isChannelUP()) + return true; + + if (!mNoRot && mRotFD > 0) { +#ifdef USE_ION + sp memalloc = mAlloc->getAllocator(mBufferType); + memalloc->free_buffer(mPmemAddr, mPmemOffset * mNumBuffers, 0, mPmemFD); +#else + munmap(mPmemAddr, mPmemOffset * mNumBuffers); + close(mPmemFD); +#endif + 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)); + + mNumBuffers = 0; + mCurrentItem = 0; + + 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; + } + + int oldPmemFD = -1; + void* oldPmemAddr = MAP_FAILED; + uint32_t oldPmemOffset = -1; + bool result; + if (!mNoRot) { + if (mUpdateDataChannel) { + oldPmemFD = mPmemFD; + oldPmemAddr = mPmemAddr; + oldPmemOffset = mPmemOffset; + mPmemOffset = mNewPmemOffset; + mNewPmemOffset = -1; + // Map the new PMEM memory + result = mapRotatorMemory(mNumBuffers, 0, UPDATE_REQUEST); + if (!result) { + LOGE("queueBuffer: mapRotatorMemory failed"); + return false; + } + } + } + + result = queue(offset); + + // Unmap the old PMEM memory after the queueBuffer has returned + if (oldPmemFD != -1 && oldPmemAddr != MAP_FAILED) { +#ifdef USE_ION + sp memalloc = mAlloc->getAllocator(mBufferType); + memalloc->free_buffer(oldPmemAddr, oldPmemOffset * mNumBuffers, 0, oldPmemFD); +#else + munmap(oldPmemAddr, oldPmemOffset * mNumBuffers); + close(oldPmemFD); +#endif + + oldPmemFD = -1; + } + return result; +} + +bool OverlayDataChannel::queue(uint32_t offset) { + 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; + mRotData.dst.offset = mRotOffset[mCurrentItem]; + mCurrentItem = (mCurrentItem + 1) % mNumBuffers; + + 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::getCropS3D(overlay_rect *inRect, int channel, int format, + overlay_rect *rect) { + // for the 3D usecase extract channels from a frame + switch (format & INPUT_MASK_3D) { + case HAL_3D_IN_SIDE_BY_SIDE_L_R: + if(channel == 0) { + rect->x = 0; + rect->y = 0; + rect->w = inRect->w/2; + rect->h = inRect->h; + } else { + rect->x = inRect->w/2; + rect->y = 0; + rect->w = inRect->w/2; + rect->h = inRect->h; + } + break; + case HAL_3D_IN_SIDE_BY_SIDE_R_L: + if(channel == 1) { + rect->x = 0; + rect->y = 0; + rect->w = inRect->w/2; + rect->h = inRect->h; + } else { + rect->x = inRect->w/2; + rect->y = 0; + rect->w = inRect->w/2; + rect->h = inRect->h; + } + break; + case HAL_3D_IN_TOP_BOTTOM: + if(channel == 0) { + rect->x = 0; + rect->y = 0; + rect->w = inRect->w; + rect->h = inRect->h/2; + } else { + rect->x = 0; + rect->y = inRect->h/2; + rect->w = inRect->w; + rect->h = inRect->h/2; + } + break; + case HAL_3D_IN_INTERLEAVE: + break; + default: + reportError("Unsupported 3D format..."); + break; + } + 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) || + (ov.user_data[0] == (MDP_ROT_90 | MDP_FLIP_UD)) || + (ov.user_data[0] == (MDP_ROT_90 | MDP_FLIP_LR))){ + if (ov.src.width < (y + h)) + return false; + + uint32_t 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) { + if (ov.src.height < (x + w)) + return false; + + uint32_t tmp = y; + y = ov.src.height - (x + w); + x = tmp; + + tmp = w; + w = h; + h = tmp; + } + else if(ov.user_data[0] == MDP_ROT_180) { + if ((ov.src.height < (y + h)) || (ov.src.width < ( x + w))) + return false; + + x = ov.src.width - (x + w); + y = ov.src.height - (y + h); + } + + + if ((ov.src_rect.x == x) && + (ov.src_rect.y == y) && + (ov.src_rect.w == w) && + (ov.src_rect.h == h)) + return true; + + normalize_crop(x, w); + normalize_crop(y, h); + + 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..0ad92ce --- /dev/null +++ b/liboverlay/overlayLib.h @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2010-2011, 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 +#include +#include +#include + +#define HW_OVERLAY_MAGNIFICATION_LIMIT 8 +#define HW_OVERLAY_MINIFICATION_LIMIT HW_OVERLAY_MAGNIFICATION_LIMIT + +#define EVEN_OUT(x) if (x & 0x0001) {x--;} +#define VG0_PIPE 0 +#define VG1_PIPE 1 +#define NUM_CHANNELS 2 +#define FRAMEBUFFER_0 0 +#define FRAMEBUFFER_1 1 + +enum { + HDMI_OFF, + HDMI_ON +}; + +enum { + OVERLAY_CHANNEL_DOWN, + OVERLAY_CHANNEL_UP +}; + +enum { + NEW_REQUEST, + UPDATE_REQUEST +}; +/* ------------------------------- 3D defines ---------------------------------------*/ +// The compound format passed to the overlay is +// ABCCC where A is the input 3D format, +// B is the output 3D format +// CCC is the color format e.g YCbCr420SP YCrCb420SP etc. +#define FORMAT_3D(x) (x & 0xFF000) +#define COLOR_FORMAT(x) (x & 0xFFF) +// in the final 3D format, the MSB 2Bytes are the input format and the +// LSB 2bytes are the output format. Shift the output byte 12 bits. +#define SHIFT_OUTPUT_3D 12 +#define FORMAT_3D_OUTPUT(x) ((x & 0xF000) >> SHIFT_OUTPUT_3D) +#define FORMAT_3D_INPUT(x) (x & 0xF0000) +#define INPUT_MASK_3D 0xFFFF0000 +#define OUTPUT_MASK_3D 0x0000FFFF +#define SHIFT_3D 16 +// The output format is the 2MSB bytes. Shift the format by 12 to reflect this +#define HAL_3D_OUT_SIDE_BY_SIDE_MASK (HAL_3D_OUT_SIDE_BY_SIDE >> SHIFT_OUTPUT_3D) +#define HAL_3D_OUT_TOP_BOTTOM_MASK (HAL_3D_OUT_TOP_BOTTOM >> SHIFT_OUTPUT_3D) +#define HAL_3D_OUT_INTERLEAVE_MASK (HAL_3D_OUT_INTERLEAVE >> SHIFT_OUTPUT_3D) +#define HAL_3D_OUT_MONOSCOPIC_MASK (HAL_3D_OUT_MONOSCOPIC >> SHIFT_OUTPUT_3D) + +// 3D panel barrier orientation +#define BARRIER_LANDSCAPE 1 +#define BARRIER_PORTRAIT 2 + +#ifdef HDMI_AS_PRIMARY +#define FORMAT_3D_FILE "/sys/class/graphics/fb0/format_3d" +#define EDID_3D_INFO_FILE "/sys/class/graphics/fb0/3d_present" +#else +#define FORMAT_3D_FILE "/sys/class/graphics/fb1/format_3d" +#define EDID_3D_INFO_FILE "/sys/class/graphics/fb1/3d_present" +#endif +#define BARRIER_FILE "/sys/devices/platform/mipi_novatek.0/enable_3d_barrier" +/* -------------------------- end 3D defines ----------------------------------------*/ + +// Struct to hold the buffer info: geometry and size +struct overlay_buffer_info { + int width; + int height; + int format; + int size; +}; + +namespace overlay { + +enum { + OV_UI_MIRROR_TV = 0, + OV_2D_VIDEO_ON_PANEL, + OV_2D_VIDEO_ON_TV, + OV_3D_VIDEO_2D_PANEL, + OV_3D_VIDEO_2D_TV, + OV_3D_VIDEO_3D_PANEL, + OV_3D_VIDEO_3D_TV +}; +bool isHDMIConnected(); +bool is3DTV(); +bool isPanel3D(); +bool usePanel3D(); +bool send3DInfoPacket(unsigned int format3D); +bool enableBarrier(unsigned int orientation); +unsigned int getOverlayConfig (unsigned int format3D, bool poll = true, + bool isHDMI = false); +int getColorFormat(int format); +int get_mdp_format(int format); +int get_size(int format, int w, int h); +int get_rot_output_format(int format); +int get_mdp_orientation(int value); +void normalize_crop(uint32_t& xy, uint32_t& wh); + +/* Print values being sent to driver in case of ioctl failures + These logs are enabled only if DEBUG_OVERLAY is true */ +void dump(msm_rotator_img_info& mRotInfo); +void dump(mdp_overlay& mOvInfo); +const char* getFormatString(int format); + +const int max_num_buffers = 3; +typedef struct mdp_rect overlay_rect; + +class OverlayControlChannel { + + bool mNoRot; + + int mFBWidth; + int mFBHeight; + int mFBbpp; + int mFBystride; + int mFormat; + int mFD; + int mRotFD; + int mSize; + int mOrientation; + unsigned int mFormat3D; + bool mUIChannel; + mdp_overlay mOVInfo; + msm_rotator_img_info mRotInfo; + msmfb_overlay_3d m3DOVInfo; + bool mIsChannelUpdated; + bool openDevices(int fbnum = -1); + bool setOverlayInformation(const overlay_buffer_info& info, + int flags, int orientation, int zorder = 0, bool ignoreFB = false, + int requestType = NEW_REQUEST); + bool startOVRotatorSessions(const overlay_buffer_info& info, int orientation, int requestType); + void swapOVRotWidthHeight(); + +public: + OverlayControlChannel(); + ~OverlayControlChannel(); + bool startControlChannel(int w, int h, int format, + int fbnum, bool norot = false, + bool uichannel = false, + unsigned int format3D = 0, int zorder = 0, + bool ignoreFB = false); + bool closeControlChannel(); + bool setPosition(int x, int y, uint32_t w, uint32_t h); + bool setParameter(int param, int value, bool fetch = true); + void setSize (int size) { mSize = size; } + 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; } + int getFormat3D() const { return mFormat3D; } + bool getOrientation(int& orientation) const; + bool updateWaitForVsyncFlags(bool waitForVsync); + bool getAspectRatioPosition(int w, int h, overlay_rect *rect); + bool getPositionS3D(int channel, int format, overlay_rect *rect); + bool updateOverlaySource(const overlay_buffer_info& info, int orientation, bool waitForVsync); + bool getFormat() const { return mFormat; } + bool useVirtualFB (); + int getOverlayFlags() const { return mOVInfo.flags; } +}; + +class OverlayDataChannel { + + bool mNoRot; + int mFD; + int mRotFD; + int mPmemFD; + void* mPmemAddr; + uint32_t mPmemOffset; + uint32_t mNewPmemOffset; + msmfb_overlay_data mOvData; + msmfb_overlay_data mOvDataRot; + msm_rotator_data_info mRotData; + int mRotOffset[max_num_buffers]; + int mCurrentItem; + int mNumBuffers; + int mUpdateDataChannel; + android::sp mAlloc; + int mBufferType; + + bool openDevices(int fbnum = -1, bool uichannel = false, int num_buffers = 2); + bool mapRotatorMemory(int num_buffers, bool uiChannel, int requestType); + bool queue(uint32_t offset); + +public: + OverlayDataChannel(); + ~OverlayDataChannel(); + bool startDataChannel(const OverlayControlChannel& objOvCtrlChannel, + int fbnum, bool norot = false, + bool uichannel = false, int num_buffers = 2); + bool startDataChannel(int ovid, int rotid, int size, + int fbnum, bool norot = false, bool uichannel = false, + int num_buffers = 2); + 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 getCropS3D(overlay_rect *inRect, int channel, int format, overlay_rect *rect); + bool isChannelUP() const { return (mFD > 0); } + bool updateDataChannel(int updateStatus, int size); +}; + +/* + * Overlay class for single thread application + * A multiple thread/process application need to use Overlay HAL + */ +class Overlay { + + bool mChannelUP; + bool mHDMIConnected; + unsigned int mS3DFormat; + //Actual cropped source width and height of overlay + int mCroppedSrcWidth; + int mCroppedSrcHeight; + overlay_buffer_info mOVBufferInfo; + int mState; + OverlayControlChannel objOvCtrlChannel[2]; + OverlayDataChannel objOvDataChannel[2]; + +public: + Overlay(); + ~Overlay(); + + static bool sHDMIAsPrimary; + bool startChannel(const overlay_buffer_info& info, int fbnum, bool norot = false, + bool uichannel = false, unsigned int format3D = 0, + int channel = 0, bool ignoreFB = false, + int num_buffers = 2); + bool closeChannel(); + bool setPosition(int x, int y, uint32_t w, uint32_t h); + bool setParameter(int param, int value); + bool setOrientation(int value, int channel = 0); + bool setFd(int fd, int channel = 0); + bool queueBuffer(uint32_t offset, int channel = 0); + bool getPosition(int& x, int& y, uint32_t& w, uint32_t& h, int channel = 0); + bool isChannelUP() const { return mChannelUP; } + int getFBWidth(int channel = 0) const; + int getFBHeight(int channel = 0) const; + bool getOrientation(int& orientation, int channel = 0) const; + bool queueBuffer(buffer_handle_t buffer); + bool setSource(const overlay_buffer_info& info, int orientation, bool hdmiConnected, + bool ignoreFB = false, int numBuffers = 2); + bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h); + int getChannelStatus() const { return (mChannelUP ? OVERLAY_CHANNEL_UP: OVERLAY_CHANNEL_DOWN); } + void setHDMIStatus (bool isHDMIConnected) { mHDMIConnected = isHDMIConnected; mState = -1; } + int getHDMIStatus() const {return (mHDMIConnected ? HDMI_ON : HDMI_OFF); } + +private: + bool setChannelPosition(int x, int y, uint32_t w, uint32_t h, int channel = 0); + bool setChannelCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h, int channel); + bool queueBuffer(int fd, uint32_t offset, int channel); + bool updateOverlaySource(const overlay_buffer_info& info, int orientation, bool waitForVsync); + int getS3DFormat(int format); +}; + +struct overlay_shared_data { + volatile bool isControlSetup; + unsigned int state; + int rotid[2]; + int ovid[2]; +}; +}; +#endif diff --git a/liboverlay/overlayLibUI.cpp b/liboverlay/overlayLibUI.cpp new file mode 100644 index 0000000..dd19cd9 --- /dev/null +++ b/liboverlay/overlayLibUI.cpp @@ -0,0 +1,524 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2011, 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 "overlayLibUI.h" +#include "gralloc_priv.h" +#define LOG_TAG "OverlayUI" + +using android::sp; +using gralloc::IMemAlloc; +using gralloc::alloc_data; + +namespace { +/* helper functions */ +bool checkOVState(int w, int h, int format, int orientation, + int zorder, const mdp_overlay& ov) { + switch(orientation) { + case OVERLAY_TRANSFORM_ROT_90: + case OVERLAY_TRANSFORM_ROT_270: { + int tmp = w; + w = h; + h = tmp; + break; + } + default: + break; + } + + int srcw = (w + 31) & ~31; + int srch = (h + 31) & ~31; + bool displayAttrsCheck = ((srcw == ov.src.width) && (srch == ov.src.height) && + (format == ov.src.format)); + bool zOrderCheck = (ov.z_order == zorder); + + if (displayAttrsCheck && zorder == overlay::NO_INIT) + return true; + + if (displayAttrsCheck && zorder != overlay::NO_INIT + && ov.z_order == zorder) + return true; + return false; +} + +void swapOVRotWidthHeight(msm_rotator_img_info& rotInfo, + mdp_overlay& ovInfo) { + int srcWidth = ovInfo.src.width; + ovInfo.src.width = ovInfo.src.height; + ovInfo.src.height = srcWidth; + + int srcRectWidth = ovInfo.src_rect.w; + ovInfo.src_rect.w = ovInfo.src_rect.h; + ovInfo.src_rect.h = srcRectWidth; + + int dstWidth = rotInfo.dst.width; + rotInfo.dst.width = rotInfo.dst.height; + rotInfo.dst.height = dstWidth; +} + +void setupOvRotInfo(int w, int h, int format, int orientation, + mdp_overlay& ovInfo, msm_rotator_img_info& rotInfo) { + memset(&ovInfo, 0, sizeof(ovInfo)); + memset(&rotInfo, 0, sizeof(rotInfo)); + ovInfo.id = MSMFB_NEW_REQUEST; + int srcw = (w + 31) & ~31; + int srch = (h + 31) & ~31; + ovInfo.src.width = srcw; + ovInfo.src.height = srch; + ovInfo.src.format = format; + ovInfo.src_rect.w = w; + ovInfo.src_rect.h = h; + ovInfo.alpha = 0xff; + ovInfo.transp_mask = 0xffffffff; + rotInfo.src.format = format; + rotInfo.dst.format = format; + rotInfo.src.width = srcw; + rotInfo.src.height = srch; + rotInfo.src_rect.w = srcw; + rotInfo.src_rect.h = srch; + rotInfo.dst.width = srcw; + rotInfo.dst.height = srch; + + int rot = orientation; + switch(rot) { + case 0: + case HAL_TRANSFORM_FLIP_H: + case HAL_TRANSFORM_FLIP_V: + rot = 0; + break; + case HAL_TRANSFORM_ROT_90: + case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H): + case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V): { + int tmp = ovInfo.src_rect.x; + ovInfo.src_rect.x = ovInfo.src.height - + (ovInfo.src_rect.y + ovInfo.src_rect.h); + ovInfo.src_rect.y = tmp; + swapOVRotWidthHeight(rotInfo, ovInfo); + rot = HAL_TRANSFORM_ROT_90; + break; + } + case HAL_TRANSFORM_ROT_180: + break; + case HAL_TRANSFORM_ROT_270: { + int tmp = ovInfo.src_rect.y; + ovInfo.src_rect.y = ovInfo.src.width - + (ovInfo.src_rect.x + ovInfo.src_rect.w); + ovInfo.src_rect.x = tmp; + swapOVRotWidthHeight(rotInfo, ovInfo); + break; + } + default: + break; + } + + int mdp_rotation = overlay::get_mdp_orientation(rot); + if (mdp_rotation < 0) + mdp_rotation = 0; + ovInfo.user_data[0] = mdp_rotation; + rotInfo.rotations = ovInfo.user_data[0]; + if (mdp_rotation) + rotInfo.enable = 1; + ovInfo.dst_rect.w = ovInfo.src_rect.w; + ovInfo.dst_rect.h = ovInfo.src_rect.h; +} + +bool isRGBType(int format) { + bool ret = false; + switch(format) { + case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: + case MDP_RGB_565: + ret = true; + break; + default: + ret = false; + break; + } + return ret; +} + +int getRGBBpp(int format) { + int ret = -1; + switch(format) { + case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: + ret = 4; + break; + case MDP_RGB_565: + ret = 2; + break; + default: + ret = -1; + break; + } + + return ret; +} + +bool turnOFFVSync() { + static int swapIntervalPropVal = -1; + if (swapIntervalPropVal == -1) { + char pval[PROPERTY_VALUE_MAX]; + property_get("debug.gr.swapinterval", pval, "1"); + swapIntervalPropVal = atoi(pval); + } + return (swapIntervalPropVal == 0); +} + +}; + +namespace overlay { + +status_t Display::openDisplay(int fbnum) { + if (mFD != NO_INIT) + return ALREADY_EXISTS; + + status_t ret = NO_INIT; + 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) { + LOGE("Failed to open FB %d", fbnum); + return ret; + } + + fb_var_screeninfo vinfo; + if (ioctl(mFD, FBIOGET_VSCREENINFO, &vinfo)) { + LOGE("FBIOGET_VSCREENINFO on failed on FB %d", fbnum); + close(mFD); + mFD = NO_INIT; + return ret; + } + + mFBWidth = vinfo.xres; + mFBHeight = vinfo.yres; + mFBBpp = vinfo.bits_per_pixel; + ret = NO_ERROR; + + return ret; +} + +status_t OVHelper::startOVSession(mdp_overlay& ovInfo, int fbnum) { + status_t ret = NO_INIT; + + if (mSessionID == NO_INIT) { + ret = mobjDisplay.openDisplay(fbnum); + if (ret != NO_ERROR) + return ret; + + if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_SET, &ovInfo)) { + LOGE("OVerlay set failed.."); + mobjDisplay.closeDisplay(); + ret = BAD_VALUE; + } + else { + mSessionID = ovInfo.id; + mOVInfo = ovInfo; + ret = NO_ERROR; + } + } + else + ret = ALREADY_EXISTS; + + return ret; +} + +status_t OVHelper::queueBuffer(msmfb_overlay_data ovData) { + if (mSessionID == NO_INIT) + return NO_INIT; + + ovData.id = mSessionID; + if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_PLAY, &ovData)) + return BAD_VALUE; + + return NO_ERROR; +} + +status_t OVHelper::closeOVSession() { + if (mSessionID != NO_INIT) { + ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_UNSET, &mSessionID); + mobjDisplay.closeDisplay(); + } + + mSessionID = NO_INIT; + + return NO_ERROR; +} + +status_t OVHelper::setPosition(int x, int y, int w, int h) { + status_t ret = BAD_VALUE; + if (mSessionID != NO_INIT) { + int fd = mobjDisplay.getFD(); + if (x < 0 || y < 0 || ((x + w) > getFBWidth())) { + LOGE("set position failed, invalid argument"); + return ret; + } + + mdp_overlay ov; + ov.id = mSessionID; + if (!ioctl(fd, MSMFB_OVERLAY_GET, &ov)) { + if (x != ov.dst_rect.x || y != ov.dst_rect.y || + w != ov.dst_rect.w || h != ov.dst_rect.h) { + ov.dst_rect.x = x; + ov.dst_rect.y = y; + ov.dst_rect.w = w; + ov.dst_rect.h = h; + if (ioctl(fd, MSMFB_OVERLAY_SET, &ov)) { + LOGE("set position failed"); + return ret; + } + } + mOVInfo = ov; + return NO_ERROR; + } + return ret; + } + + return NO_INIT; +} + +status_t OVHelper::getOVInfo(mdp_overlay& ovInfo) { + if (mSessionID == NO_INIT) + return NO_INIT; + ovInfo = mOVInfo; + return NO_ERROR; +} + +status_t Rotator::startRotSession(msm_rotator_img_info& rotInfo, + int size, int numBuffers) { + status_t ret = ALREADY_EXISTS; + if (mSessionID == NO_INIT && mFD == NO_INIT) { + mNumBuffers = numBuffers; + mFD = open("/dev/msm_rotator", O_RDWR, 0); + if (mFD < 0) { + LOGE("Couldnt open rotator device"); + return NO_INIT; + } + + if (int check = ioctl(mFD, MSM_ROTATOR_IOCTL_START, &rotInfo)) { + close(mFD); + mFD = NO_INIT; + return NO_INIT; + } + +#ifdef USE_ION + alloc_data data; + data.base = 0; + data.fd = -1; + data.offset = 0; + data.size = mSize * mNumBuffers; + data.align = getpagesize(); + data.uncached = true; + + int err = mAlloc->allocate(data, GRALLOC_USAGE_PRIVATE_ADSP_HEAP| + GRALLOC_USAGE_PRIVATE_SMI_HEAP, 0); + + if(err) { + LOGE("Cant allocate from ION"); + closeRotSession(); + return NO_INIT; + } + mPmemFD = data.fd; + mPmemAddr = data.base; + mBufferType = data.allocType; +#else + mSessionID = rotInfo.session_id; + mPmemFD = open("/dev/pmem_adsp", O_RDWR | O_SYNC); + if (mPmemFD < 0) { + closeRotSession(); + return NO_INIT; + } + + mSize = size; + mPmemAddr = (void *) mmap(NULL, mSize* mNumBuffers, PROT_READ | PROT_WRITE, + MAP_SHARED, mPmemFD, 0); + if (mPmemAddr == MAP_FAILED) { + closeRotSession(); + return NO_INIT; + } +#endif + + mCurrentItem = 0; + for (int i = 0; i < mNumBuffers; i++) + mRotOffset[i] = i * mSize; + ret = NO_ERROR; + } + + return ret; +} + +status_t Rotator::closeRotSession() { + if (mSessionID != NO_INIT && mFD != NO_INIT) { + ioctl(mFD, MSM_ROTATOR_IOCTL_FINISH, &mSessionID); + close(mFD); +#ifdef USE_ION + sp memalloc = mAlloc->getAllocator(mBufferType); + memalloc->free_buffer(mPmemAddr, mSize * mNumBuffers, 0, mPmemFD); +#else + munmap(mPmemAddr, mSize * mNumBuffers); + close(mPmemFD); +#endif + close(mPmemFD); + } + + mFD = NO_INIT; + mSessionID = NO_INIT; + mPmemFD = NO_INIT; + mPmemAddr = MAP_FAILED; + + return NO_ERROR; +} + +status_t Rotator::rotateBuffer(msm_rotator_data_info& rotData) { + status_t ret = NO_INIT; + if (mSessionID != NO_INIT) { + rotData.dst.memory_id = mPmemFD; + rotData.dst.offset = mRotOffset[mCurrentItem]; + rotData.session_id = mSessionID; + mCurrentItem = (mCurrentItem + 1) % mNumBuffers; + if (ioctl(mFD, MSM_ROTATOR_IOCTL_ROTATE, &rotData)) { + LOGE("Rotator failed to rotate"); + return BAD_VALUE; + } + return NO_ERROR; + } + + return ret; +} + +status_t OverlayUI::closeChannel() { + mobjOVHelper.closeOVSession(); + mobjRotator.closeRotSession(); + mChannelState = CLOSED; + return NO_ERROR; +} + +status_t OverlayUI::setSource(const overlay_buffer_info& info, int orientation, + bool useVGPipe, bool ignoreFB, + int fbnum, int zorder) { + status_t ret = NO_INIT; + + int format3D = FORMAT_3D(info.format); + int colorFormat = COLOR_FORMAT(info.format); + int format = get_mdp_format(colorFormat); + + if (format3D || !isRGBType(format)) + return ret; + + if (mChannelState == PENDING_CLOSE) + closeChannel(); + + if (mChannelState == UP) { + mdp_overlay ov; + if (mobjOVHelper.getOVInfo(ov) == NO_ERROR) { + if (mOrientation == orientation && + mFBNum == fbnum && + checkOVState(info.width, info.height, format, orientation, zorder, ov)) + return NO_ERROR; + else + mChannelState = PENDING_CLOSE; + } + else + mChannelState = PENDING_CLOSE; + return ret; + } + + mOrientation = orientation; + mdp_overlay ovInfo; + msm_rotator_img_info rotInfo; + setupOvRotInfo(info.width, info.height, format, orientation, ovInfo, rotInfo); + + int flags = 0; + if (ignoreFB) + ovInfo.is_fg = 1; + else + flags |= MDP_OV_PLAY_NOWAIT; + + if (turnOFFVSync()) + flags |= MDP_OV_PLAY_NOWAIT; + + if (useVGPipe || + (fbnum == FB0 && getRGBBpp(format) != mobjOVHelper.getFBBpp())) + flags |= MDP_OV_PIPE_SHARE; + + ovInfo.flags = flags; + if (zorder != NO_INIT) + ovInfo.z_order = zorder; + + ret = startChannel(fbnum, ovInfo, rotInfo, info.size); + return ret; +} + +status_t OverlayUI::startChannel(int fbnum, mdp_overlay& ovInfo, + msm_rotator_img_info& rotInfo, int size) { + status_t ret = BAD_VALUE; + if (mChannelState == UP) + return ret; + + ret = mobjOVHelper.startOVSession(ovInfo, fbnum); + if (ret == NO_ERROR && mOrientation) { + ret = mobjRotator.startRotSession(rotInfo, size); + } + + if (ret == NO_ERROR) { + mChannelState = UP; + mFBNum = fbnum; + } + else + LOGE("start channel failed."); + + return ret; +} + +status_t OverlayUI::queueBuffer(buffer_handle_t buffer) { + status_t ret = NO_INIT; + + if (mChannelState != UP) + return ret; + + msmfb_overlay_data ovData; + memset(&ovData, 0, sizeof(ovData)); + + private_handle_t const* hnd = reinterpret_cast + (buffer); + ovData.data.memory_id = hnd->fd; + ovData.data.offset = hnd->offset; + if (mOrientation) { + msm_rotator_data_info rotData; + memset(&rotData, 0, sizeof(rotData)); + rotData.src.memory_id = hnd->fd; + rotData.src.offset = hnd->offset; + if (mobjRotator.rotateBuffer(rotData) != NO_ERROR) { + LOGE("Rotator failed.. "); + return BAD_VALUE; + } + ovData.data.memory_id = rotData.dst.memory_id; + ovData.data.offset = rotData.dst.offset; + } + + ret = mobjOVHelper.queueBuffer(ovData); + if (ret != NO_ERROR) + LOGE("Queuebuffer failed "); + + return ret; +} + +}; diff --git a/liboverlay/overlayLibUI.h b/liboverlay/overlayLibUI.h new file mode 100644 index 0000000..2cb1ffe --- /dev/null +++ b/liboverlay/overlayLibUI.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2011, 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_UI +#define INCLUDE_OVERLAY_LIB_UI + +#include + +#include "overlayLib.h" + +namespace overlay { + +enum channel_state_t { UP, CLOSED, PENDING_CLOSE }; +enum status_t { + NO_ERROR, + INVALID_OPERATION = -ENOSYS, + BAD_VALUE = -EINVAL, + NO_INIT = -ENODEV, + ALREADY_EXISTS = -EEXIST + }; + +/* + * Display class provides following services + * Open FB + * FB information (Width, Height and Bpp) + */ + +class Display { + int mFD; + int mFBWidth; + int mFBHeight; + int mFBBpp; + Display(const Display& objDisplay); + Display& operator=(const Display& objDisplay); + +public: + explicit Display() : mFD(NO_INIT) { }; + ~Display() { close(mFD); }; + int getFD() const { return mFD; }; + int getFBWidth() const { return mFBWidth; }; + int getFBHeight() const { return mFBHeight; }; + int getFBBpp() const { return mFBBpp; }; + status_t openDisplay(int fbnum); + void closeDisplay() { close(mFD); mFD = NO_INIT; }; +}; + +/* + * OVHelper class, provides apis related to Overlay + * It communicates with MDP driver, provides following services + * Start overlay session + * Set position of the destination on to display + */ + +class OVHelper { + int mSessionID; + Display mobjDisplay; + mdp_overlay mOVInfo; + OVHelper(const OVHelper& objOVHelper); + OVHelper& operator=(const OVHelper& objOVHelper); + +public: + explicit OVHelper() : mSessionID(NO_INIT) { }; + ~OVHelper() { closeOVSession(); }; + status_t startOVSession(mdp_overlay& ovInfo, int fbnum); + status_t closeOVSession(); + status_t queueBuffer(msmfb_overlay_data ovData); + int getFBWidth() const { return mobjDisplay.getFBWidth(); }; + int getFBHeight() const { return mobjDisplay.getFBHeight(); }; + int getFBBpp() const { return mobjDisplay.getFBBpp(); }; + status_t setPosition(int x, int y, int w, int h); + status_t getOVInfo(mdp_overlay& ovInfo); +}; + +/* + * Rotator class, manages rotation of the buffers + * It communicates with Rotator driver, provides following services + * Start rotator session + * Rotate buffer + */ + +class Rotator { + int mFD; + int mSessionID; + int mPmemFD; + void* mPmemAddr; + int mRotOffset[max_num_buffers]; + int mCurrentItem; + int mNumBuffers; + int mSize; + android::sp mAlloc; + int mBufferType; + Rotator(const Rotator& objROtator); + Rotator& operator=(const Rotator& objRotator); + +public: + explicit Rotator() : mFD(NO_INIT), mSessionID(NO_INIT), mPmemFD(-1) + { +#ifdef USE_ION + mAlloc = gralloc::IAllocController::getInstance(); +#endif + } + ~Rotator() { closeRotSession(); } + status_t startRotSession(msm_rotator_img_info& rotInfo, int size, + int numBuffers = max_num_buffers); + status_t closeRotSession(); + status_t rotateBuffer(msm_rotator_data_info& rotData); +}; + +/* + * Overlay class for Comp. Bypass + * We merge control and data channel classes. + */ + +class OverlayUI { + channel_state_t mChannelState; + int mOrientation; + int mFBNum; + OVHelper mobjOVHelper; + Rotator mobjRotator; + + OverlayUI(const OverlayUI& objOverlay); + OverlayUI& operator=(const OverlayUI& objOverlay); + + status_t startChannel(int fbnum, mdp_overlay& ovInfo, + msm_rotator_img_info& rotInfo, int size); +public: + + enum fbnum_t { FB0, FB1 }; + + explicit OverlayUI() : mChannelState(CLOSED), mOrientation(NO_INIT), mFBNum(NO_INIT) { }; + ~OverlayUI() { closeChannel(); }; + status_t setSource(const overlay_buffer_info& info, int orientation, + bool useVGPipe = false, bool ignoreFB = true, + int fbnum = FB0, int zorder = NO_INIT); + status_t setPosition(int x, int y, int w, int h) { + return mobjOVHelper.setPosition(x, y, w, h); + }; + status_t closeChannel(); + channel_state_t isChannelUP() const { return mChannelState; }; + int getFBWidth() const { return mobjOVHelper.getFBWidth(); }; + int getFBHeight() const { return mobjOVHelper.getFBHeight(); }; + status_t queueBuffer(buffer_handle_t buffer); +}; + +}; +#endif diff --git a/liboverlay/overlayState.cpp b/liboverlay/overlayState.cpp new file mode 100644 index 0000000..f4398d4 --- /dev/null +++ b/liboverlay/overlayState.cpp @@ -0,0 +1,1109 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2009 - 2011, 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. + */ + +int setParameterHandleState(overlay_control_context_t *ctx, + overlay_object *obj, + int param, int value) +{ + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + if(!obj->setParameter(param, value, VG0_PIPE)) { + LOGE("%s: Failed for channel 0", __func__); + return -1; + } + break; + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + case OV_3D_VIDEO_3D_PANEL: + for (int i=0; isetParameter(param, value, i)) { + LOGE("%s: Failed for channel %d", __func__, i); + return -1; + } + } + break; + default: + LOGE("Unknown state in setParameter"); + abort(); + break; + } + return 0; +} + +int createOverlayHandleState(overlay_control_context_t *ctx, bool noRot, + overlay_object* overlay, int fd) +{ + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + if (!overlay->startControlChannel(FRAMEBUFFER_0, noRot)) { + error_cleanup_control(ctx, overlay, fd, FRAMEBUFFER_0); + return -1; + } + break; + case OV_3D_VIDEO_3D_PANEL: + for (int i=0; istartControlChannel(FRAMEBUFFER_0, noRot, i)) { + error_cleanup_control(ctx, overlay, fd, i); + return -1; + } + } + break; + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + if (!overlay->startControlChannel(FRAMEBUFFER_0, noRot, VG0_PIPE)) { + error_cleanup_control(ctx, overlay, fd, VG0_PIPE); + return -1; + } + if (!overlay->startControlChannel(FRAMEBUFFER_1, true, VG1_PIPE)) { + error_cleanup_control(ctx, overlay, fd, VG1_PIPE); + return -1; + } + break; + case OV_3D_VIDEO_3D_TV: + for (int i=0; istartControlChannel(FRAMEBUFFER_1, true, i)) { + error_cleanup_control(ctx, overlay, fd, i); + return -1; + } + } + break; + default: + break; + } + return 0; +} + +int setPositionHandleState(overlay_control_context_t *ctx, + overlay_object *obj, overlay_rect& rect, + int x, int y, uint32_t w, uint32_t h) +{ + int ret = 0; + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + if(!obj->setPosition(x, y, w, h, VG0_PIPE)) { + LOGE("%s:Failed for channel 0", __func__); + return -1; + } + break; + case OV_3D_VIDEO_3D_PANEL: + for (int i = 0; i < NUM_CHANNELS; i++) { + if (!obj->useVirtualFB(i)) { + LOGE("can't use the virtual fb for line interleaving!"); + } + obj->getPositionS3D(&rect, i, true); + if(!obj->setPosition(rect.x, rect.y, rect.w, rect.h, i)) { + LOGE("%s:Failed for channel %d", __func__, i); + return -1; + } + } + break; + case OV_2D_VIDEO_ON_TV: + obj->getAspectRatioPosition(&rect, VG1_PIPE); + if(!obj->setPosition(rect.x, rect.y, rect.w, rect.h, VG1_PIPE)) { + LOGE("%s:Failed for channel 1", __func__); + } + if(!obj->setPosition(x, y, w, h, VG0_PIPE)) { + LOGE("%s:Failed for channel 0", __func__); + return -1; + } + break; + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i = 0; i < NUM_CHANNELS; i++) { + if (!obj->getPositionS3D(&rect, i)) + ret = obj->setPosition(x, y, w, h, i); + else + ret = obj->setPosition(rect.x, rect.y, rect.w, rect.h, i); + if (!ret) { + LOGE("%s:Failed for channel %d", __func__, i); + return -1; + } + } + break; + default: + break; + } + return ret; +} + +//////////////////////// configPipes /////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////////// + +bool TV2Dconn(overlay_control_context_t *ctx, + overlay_object *obj, bool noRot, + overlay_rect& rect) +{ + LOGI("2D TV connected, Open a new control channel for TV."); + //Start a new channel for mirroring on HDMI + if (!obj->startControlChannel(FRAMEBUFFER_1, true, VG1_PIPE)) { + obj->closeControlChannel(VG1_PIPE); + return false; + } + if (ctx->format3D) + obj->getPositionS3D(&rect, FRAMEBUFFER_1); + else + obj->getAspectRatioPosition(&rect, FRAMEBUFFER_1); + if(!obj->setPosition(rect.x, rect.y, rect.w, rect.h, FRAMEBUFFER_1)) { + LOGE("%s:Failed to set position for framebuffer 1", __func__); + return false; + } + return true; +} + +bool TV3Dconn(overlay_control_context_t *ctx, + overlay_object *obj, bool noRot, + overlay_rect& rect) +{ + LOGI("3D TV connected, close old ctl channel and open two ctl channels for 3DTV."); + //close the channel 0 as it is configured for panel + obj->closeControlChannel(VG0_PIPE); + //update the output from monoscopic to stereoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | ctx->format3D >> SHIFT_3D; + obj->setFormat3D(ctx->format3D); + LOGI("Control: new S3D format : 0x%x", ctx->format3D); + //now open both the channels + for (int i = 0; i < NUM_CHANNELS; i++) { + if (!obj->startControlChannel(FRAMEBUFFER_1, true, i)) { + LOGE("%s:Failed to open control channel for pipe %d", __func__, i); + return false; + } + obj->getPositionS3D(&rect, i); + if(!obj->setPosition(rect.x, rect.y, rect.w, rect.h, i)) { + LOGE("%s: failed for channel %d", __func__, i); + return false; + } + } + return true; +} + +bool TV3DSetup(overlay_control_context_t *ctx, overlay_object *obj, int i, + int fbnum, overlay_rect& rect) +{ + bool noRot = fbnum ? true : false; + if (!obj->startControlChannel(fbnum, noRot, i)) { + LOGE("%s:Failed to open control channel for pipe %d", __func__, i); + return false; + } + bool ret=true; + if (!obj->getPositionS3D(&rect, i)) + ret = obj->setPosition(ctx->posPanel.x, ctx->posPanel.y, + ctx->posPanel.w, ctx->posPanel.h, i); + else + ret = obj->setPosition(rect.x, rect.y, rect.w, rect.h, i); + if(!ret) { + LOGE("%s: failed for channel %d", __func__, i); + return false; + } + return true; +} + +int configPipes_OV_2D_VIDEO_ON_PANEL_to_OV_2D_VIDEO_ON_TV (overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + if(enable) // HDMI connected + { + if(!TV2Dconn(ctx, obj, noRot, rect)) + return -1; + return 0; + } + LOGE("%s Error cannot disconnect HDMI in that state", __func__); + abort(); + return -1; +} + +int configPipes_OV_3D_VIDEO_2D_PANEL_to_OV_3D_VIDEO_2D_TV (overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + // same as OV_2D_VIDEO_ON_PANEL_to_OV_2D_VIDEO_ON_TV + return configPipes_OV_2D_VIDEO_ON_PANEL_to_OV_2D_VIDEO_ON_TV(ctx, + obj, + newState, + enable, noRot, rect); +} + +int configPipes_OV_3D_VIDEO_2D_PANEL_to_OV_3D_VIDEO_3D_TV (overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + if(enable) // HDMI connected + { + if(!TV3Dconn(ctx, obj, noRot, rect)) + return -1; + return 0; + } + // HDMI disconnected + LOGE("%s Error cannot disconnect HDMI in that state", __func__); + abort(); + return -1; +} + +int configPipes_OV_3D_VIDEO_3D_PANEL_to_OV_3D_VIDEO_2D_TV (overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + if(!enable){ // HDMI disconnect + LOGE("%s Error cannot disconnect HDMI in that state", __func__); + abort(); + return -1; + } + obj->closeControlChannel(VG1_PIPE); + obj->closeControlChannel(VG0_PIPE); + //disable the panel barriers + enableBarrier(0); + //now open both the channels + //update the output from stereoscopic to monoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + obj->setFormat3D(ctx->format3D); + LOGI("Control: new S3D format : 0x%x", ctx->format3D); + int fbnum = 0; + bool ret = true; + //now open both the channels + for (int i = 0; i < NUM_CHANNELS; i++) { + fbnum = i; + if(!TV3DSetup(ctx, obj, i, fbnum, rect)) + return -1; + } + return 0; +} + +int configPipes_OV_3D_VIDEO_3D_PANEL_to_OV_3D_VIDEO_3D_TV (overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + if(!enable){ // HDMI disconnect + LOGE("%s Error cannot disconnect HDMI in that state", __func__); + abort(); + return -1; + } + obj->closeControlChannel(VG1_PIPE); + obj->closeControlChannel(VG0_PIPE); + //disable the panel barrier + enableBarrier(0); + //now open both the channels + for (int i = 0; i < NUM_CHANNELS; i++) { + if(!TV3DSetup(ctx, obj, i, FRAMEBUFFER_1, rect)) + return -1; + } + return 0; +} + + +///// HDMI Disconnect //// +int configPipes_OV_2D_VIDEO_ON_TV_to_OV_2D_VIDEO_ON_PANEL (overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + if(enable) // HDMI connected + { + LOGE("%s Error cannot connect HDMI in that state", __func__); + abort(); + return -1; + } + LOGI("2D TV disconnected, close the control channel."); + obj->closeControlChannel(VG1_PIPE); + return 0; +} + +int configPipes_OV_3D_VIDEO_2D_TV_to_OV_3D_VIDEO_2D_PANEL (overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + // same as OV_2D_VIDEO_ON_TV_to_OV_2D_VIDEO_ON_PANEL + return configPipes_OV_2D_VIDEO_ON_TV_to_OV_2D_VIDEO_ON_PANEL(ctx, + obj, + newState, + enable, noRot, rect); +} + +int configPipes_OV_3D_VIDEO_3D_TV_to_OV_3D_VIDEO_2D_PANEL(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + if(enable) // HDMI connected + { + LOGE("%s Error cannot connect HDMI in that state", __func__); + abort(); + return -1; + } + LOGI("3D TV disconnected, close the control channels & open one for panel."); + // Close both the pipes' control channel + obj->closeControlChannel(VG1_PIPE); + obj->closeControlChannel(VG0_PIPE); + //update the format3D as monoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + obj->setFormat3D(ctx->format3D); + LOGI("Control: New format3D: 0x%x", ctx->format3D); + //now open the channel 0 + if (!obj->startControlChannel(FRAMEBUFFER_0, noRot)) { + LOGE("%s:Failed to open control channel for pipe 0", __func__); + return false; + } + if(!obj->setPosition(ctx->posPanel.x, ctx->posPanel.y, + ctx->posPanel.w, ctx->posPanel.h, FRAMEBUFFER_0)) { + LOGE("%s:Failed to set position for framebuffer 0", __func__); + return false; + } + if (!obj->setParameter(OVERLAY_TRANSFORM, ctx->orientation, VG0_PIPE)) { + LOGE("%s: Failed to set orientation for channel 0", __func__); + return -1; + } + return 0; +} + +int TVto3DPanel(overlay_control_context_t *ctx, overlay_object *obj, + bool noRot, overlay_rect& rect) +{ + for (int i = 0; i < NUM_CHANNELS; i++) { + if (!obj->startControlChannel(FRAMEBUFFER_0, noRot, i)) { + LOGE("%s:Failed to open control channel for pipe %d", __func__, i); + return false; + } + if (!obj->useVirtualFB(i)) { + LOGE("can't use the virtual fb for line interleaving!"); + } + obj->getPositionS3D(&rect, i); + if(!obj->setPosition(rect.x, rect.y, rect.w, rect.h, i)) { + LOGE("%s:Failed for channel %d", __func__, i); + return -1; + } + if (!obj->setParameter(OVERLAY_TRANSFORM, ctx->orientation, i)) { + LOGE("%s: Failed to set orientation for channel 0", __func__); + return -1; + } + } + return 0; +} + +int configPipes_OV_3D_VIDEO_2D_TV_to_OV_3D_VIDEO_3D_PANEL(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + if(enable) { // HDMI connect + LOGE("%s Error cannot connect HDMI in that state", __func__); + abort(); + return -1; + } + // disconnect TV + // Close both the pipes' control channel + obj->closeControlChannel(VG0_PIPE); + obj->closeControlChannel(VG1_PIPE); + //update the output from monoscopic to stereoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | ctx->format3D >> SHIFT_3D; + obj->setFormat3D(ctx->format3D); + LOGI("Control: new S3D format : 0x%x", ctx->format3D); + return TVto3DPanel(ctx, obj, noRot, rect); +} + +int configPipes_OV_3D_VIDEO_3D_TV_to_OV_3D_VIDEO_3D_PANEL(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + if(enable) { // HDMI connect + LOGE("%s Error cannot connect HDMI in that state", __func__); + abort(); + return -1; + } + + // disconnect TV + // Close both the pipes' control channel + obj->closeControlChannel(VG0_PIPE); + obj->closeControlChannel(VG1_PIPE); + return TVto3DPanel(ctx, obj, noRot, rect); +} + + +//// On Panel //// + +int configPipes_OV_2D_VIDEO_ON_PANEL(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + switch(newState){ + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + case OV_3D_VIDEO_3D_PANEL: + case OV_3D_VIDEO_3D_TV: + case OV_3D_VIDEO_2D_TV: + LOGE("ctl: Error in handling OV_2D_VIDEO_ON_PANEL newstate=%d", newState); + abort(); + return -1; + break; + case OV_2D_VIDEO_ON_TV: + LOGI("TV connected: open a new VG control channel"); + if(-1 == configPipes_OV_2D_VIDEO_ON_PANEL_to_OV_2D_VIDEO_ON_TV(ctx, + obj, + newState, + enable, noRot, rect)) + return -1; + break; + default: + LOGE("%s Unknown state in configPipes %d", __func__, newState); + abort(); + break; + } + return 0; +} + +int configPipes_OV_3D_VIDEO_2D_PANEL(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + switch(newState){ + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + case OV_3D_VIDEO_3D_PANEL: + case OV_2D_VIDEO_ON_TV: + LOGE("Error in handling OV_3D_VIDEO_2D_PANEL newstate=%d", newState); + abort(); + return -1; + case OV_3D_VIDEO_2D_TV: + if(-1 == configPipes_OV_3D_VIDEO_2D_PANEL_to_OV_3D_VIDEO_2D_TV(ctx, + obj, + newState, + enable, noRot, rect)) + return -1; + break; + case OV_3D_VIDEO_3D_TV: + if(-1 == configPipes_OV_3D_VIDEO_2D_PANEL_to_OV_3D_VIDEO_3D_TV(ctx, + obj, + newState, + enable, noRot, rect)) + return -1; + break; + default: + LOGE("%s Unknown state in configPipes %d", __func__, newState); + abort(); + } + return 0; +} + +int configPipes_OV_3D_VIDEO_3D_PANEL(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + switch(newState){ + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + case OV_3D_VIDEO_3D_PANEL: + case OV_2D_VIDEO_ON_TV: + LOGE("Error in handling OV_3D_VIDEO_3D_PANEL newstate=%d", newState); + abort(); + return -1; + case OV_3D_VIDEO_2D_TV: + if(-1 == configPipes_OV_3D_VIDEO_3D_PANEL_to_OV_3D_VIDEO_2D_TV(ctx, + obj, + newState, + enable, noRot, rect)) + return -1; + break; + case OV_3D_VIDEO_3D_TV: + if(-1 == configPipes_OV_3D_VIDEO_3D_PANEL_to_OV_3D_VIDEO_3D_TV(ctx, + obj, + newState, + enable, noRot, rect)) + return -1; + break; + default: + LOGE("%s Unknown state in configPipes %d", __func__, newState); + abort(); + } + return 0; +} + +/// OV on TV //// + +int configPipes_OV_2D_VIDEO_ON_TV(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + switch(newState){ + case OV_2D_VIDEO_ON_PANEL: + if(-1 == configPipes_OV_2D_VIDEO_ON_TV_to_OV_2D_VIDEO_ON_PANEL(ctx, + obj, + newState, + enable, noRot, rect)) + return -1; + break; + case OV_3D_VIDEO_3D_PANEL: + case OV_3D_VIDEO_2D_PANEL: + case OV_3D_VIDEO_3D_TV: + case OV_3D_VIDEO_2D_TV: + case OV_2D_VIDEO_ON_TV: + LOGE("Error in handling OV_2D_VIDEO_ON_TV newstate=%d", newState); + abort(); + return -1; + default: + LOGE("%s Unknown state in configPipes %d", __func__, newState); + abort(); + } + return 0; +} + +int configPipes_OV_3D_VIDEO_2D_TV(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + switch(newState){ + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_3D_TV: + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + LOGE("Error in handling OV_3D_VIDEO_2D_TV newstate=%d", newState); + abort(); + return -1; + case OV_3D_VIDEO_3D_PANEL: + if(-1 == configPipes_OV_3D_VIDEO_2D_TV_to_OV_3D_VIDEO_3D_PANEL(ctx, + obj, + newState, + enable, noRot, rect)) + break; + case OV_3D_VIDEO_2D_PANEL: + if(-1 == configPipes_OV_3D_VIDEO_2D_TV_to_OV_3D_VIDEO_2D_PANEL(ctx, + obj, + newState, + enable, noRot, rect)) + return -1; + break; + default: + LOGE("%s Unknown state in configPipes %d", __func__, newState); + abort(); + } + return 0; +} + +int configPipes_OV_3D_VIDEO_3D_TV(overlay_control_context_t *ctx, + overlay_object *obj, + unsigned int newState, + int enable, bool noRot, + overlay_rect& rect) +{ + switch(newState){ + case OV_3D_VIDEO_2D_PANEL: + if(-1 == configPipes_OV_3D_VIDEO_3D_TV_to_OV_3D_VIDEO_2D_PANEL(ctx, + obj, + newState, + enable, noRot, rect)) + return -1; + break; + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_3D_TV: + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + LOGE("Error in handling OV_3D_VIDEO_2D_TV newstate=%d", newState); + abort(); + return -1; + case OV_3D_VIDEO_3D_PANEL: + if(-1 == configPipes_OV_3D_VIDEO_3D_TV_to_OV_3D_VIDEO_3D_PANEL(ctx, + obj, + newState, + enable, noRot, rect)) + return -1; + break; + default: + LOGE("%s Unknown state in configPipes %d", __func__, newState); + abort(); + } + return 0; +} + + +//////////////////////////////////// Queue Buffer /////////////////////////////////// + +///////////////////////// Helper func /////////////////////////////// + +int queueBuffer_OV_2D_VIDEO_ON_PANEL_to_OV_2D_VIDEO_ON_TV(overlay_data_context_t *ctx, + overlay_shared_data* data) +{ + LOGI("2D TV connected, Open a new data channel for TV."); + //Start a new channel for mirroring on HDMI + ctx->pobjDataChannel[VG1_PIPE] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[VG1_PIPE]->startDataChannel( + data->ovid[VG1_PIPE], data->rotid[VG1_PIPE], ctx->size, + FRAMEBUFFER_1, true)) { + delete ctx->pobjDataChannel[VG1_PIPE]; + ctx->pobjDataChannel[VG1_PIPE] = NULL; + return -1; + } + if(!ctx->pobjDataChannel[VG1_PIPE]->setCrop( + ctx->cropRect.x,ctx->cropRect.y, + ctx->cropRect.w,ctx->cropRect.h)) { + LOGE("%s:failed to crop pipe 1", __func__); + } + //setting the srcFD + if (!ctx->pobjDataChannel[VG1_PIPE]->setFd(ctx->srcFD)) { + LOGE("%s: Failed to set fd for pipe 1", __func__); + return -1; + } + return 0; +} + +int queueBuffer_OV_3D_VIDEO_2D_PANEL_to_OV_3D_VIDEO_2D_TV(overlay_data_context_t *ctx, + overlay_shared_data* data) +{ + LOGI("2D TV connected, Open a new data channel for TV."); + //Start a new channel for mirroring on HDMI + ctx->pobjDataChannel[VG1_PIPE] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[VG1_PIPE]->startDataChannel( + data->ovid[VG1_PIPE], data->rotid[VG1_PIPE], ctx->size, + FRAMEBUFFER_1, true)) { + delete ctx->pobjDataChannel[VG1_PIPE]; + ctx->pobjDataChannel[VG1_PIPE] = NULL; + return -1; + } + overlay_rect rect; + ctx->pobjDataChannel[VG1_PIPE]->getCropS3D(&ctx->cropRect, VG1_PIPE, ctx->format3D, &rect); + if (!ctx->pobjDataChannel[VG1_PIPE]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: Failed to crop pipe 1", __func__); + return -1; + } + //setting the srcFD + if (!ctx->pobjDataChannel[VG1_PIPE]->setFd(ctx->srcFD)) { + LOGE("%s: Failed to set fd for pipe 1", __func__); + return -1; + } + return 0; +} + +int queueBuffer_OV_3D_VIDEO_2D_PANEL_to_OV_3D_VIDEO_3D_TV(overlay_data_context_t *ctx, + overlay_shared_data* data) +{ + //close the channel 0 as it is configured for panel + ctx->pobjDataChannel[VG0_PIPE]->closeDataChannel(); + delete ctx->pobjDataChannel[VG0_PIPE]; + ctx->pobjDataChannel[VG0_PIPE] = NULL; + //update the output from monoscopic to stereoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | ctx->format3D >> SHIFT_3D; + LOGI("Data: New S3D format : 0x%x", ctx->format3D); + //now open both the channels + overlay_rect rect; + for (int i = 0; i < NUM_CHANNELS; i++) { + ctx->pobjDataChannel[i] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[i]->startDataChannel( + data->ovid[i], data->rotid[i], ctx->size, + FRAMEBUFFER_1, true)) { + error_cleanup_data(ctx, i); + return -1; + } + ctx->pobjDataChannel[i]->getCropS3D(&ctx->cropRect, i, ctx->format3D, &rect); + if (!ctx->pobjDataChannel[i]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: Failed to crop pipe %d", __func__, i); + return -1; + } + if (!ctx->pobjDataChannel[i]->setFd(ctx->srcFD)) { + LOGE("%s: Failed to set fd for pipe %d", __func__, i); + return -1; + } + } + send3DInfoPacket(ctx->format3D & OUTPUT_MASK_3D); + return 0; +} +int queueBuffer_3D_to_2D_TV_common(overlay_data_context_t *ctx, + overlay_shared_data* data, + overlay_rect& rect, + int i, int fbnum) +{ + bool noRot = fbnum ? true : false; + ctx->pobjDataChannel[i] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[i]->startDataChannel( + data->ovid[i], data->rotid[i], ctx->size, fbnum, noRot)) { + error_cleanup_data(ctx, i); + return -1; + } + ctx->pobjDataChannel[i]->getCropS3D(&ctx->cropRect, i, ctx->format3D, &rect); + if (!ctx->pobjDataChannel[i]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: Failed to crop pipe %d", __func__, i); + return -1; + } + if (!ctx->pobjDataChannel[i]->setFd(ctx->srcFD)) { + LOGE("%s: Failed to set fd for pipe %d", __func__, i); + return -1; + } + return 0; +} + +int queueBuffer_OV_3D_VIDEO_3D_PANEL_to_OV_3D_VIDEO_2D_TV(overlay_data_context_t *ctx, + overlay_shared_data* data) +{ + // Close both the pipes' data channel + for (int i = 0; i < NUM_CHANNELS; i++) { + ctx->pobjDataChannel[i]->closeDataChannel(); + delete ctx->pobjDataChannel[i]; + ctx->pobjDataChannel[i] = NULL; + } + //now open both the channels + overlay_rect rect; + for (int i = 0; i < NUM_CHANNELS; i++) { + int fbnum = i; + //update the output from stereoscopic to monoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + LOGI("Data: New S3D format : 0x%x", ctx->format3D); + if(-1 == queueBuffer_3D_to_2D_TV_common(ctx, data, rect, i, fbnum)) + return -1; + } + return 0; +} + +int queueBuffer_OV_3D_VIDEO_3D_PANEL_to_OV_3D_VIDEO_3D_TV(overlay_data_context_t *ctx, + overlay_shared_data* data) +{ + // Close both the pipes' data channel + for (int i = 0; i < NUM_CHANNELS; i++) { + ctx->pobjDataChannel[i]->closeDataChannel(); + delete ctx->pobjDataChannel[i]; + ctx->pobjDataChannel[i] = NULL; + } + //now open both the channels + overlay_rect rect; + int fbnum = 1; + for (int i = 0; i < NUM_CHANNELS; i++) { + if(-1 == queueBuffer_3D_to_2D_TV_common(ctx, data, rect, i, fbnum)) + return -1; + } + send3DInfoPacket(ctx->format3D & OUTPUT_MASK_3D); + return 0; +} + +void queueBuffer_OV_2D_VIDEO_ON_TV_to_OV_2D_VIDEO_ON_PANEL(overlay_data_context_t *ctx) +{ + LOGI("2D TV disconnected, close the data channel for TV."); + ctx->pobjDataChannel[VG1_PIPE]->closeDataChannel(); + delete ctx->pobjDataChannel[VG1_PIPE]; + ctx->pobjDataChannel[VG1_PIPE] = NULL; +} + +void queueBuffer_OV_3D_VIDEO_2D_TV_to_OV_3D_VIDEO_2D_PANEL(overlay_data_context_t *ctx) +{ + // same as queueBuffer_OV_2D_VIDEO_ON_TV_to_OV_2D_VIDEO_ON_PANEL + queueBuffer_OV_2D_VIDEO_ON_TV_to_OV_2D_VIDEO_ON_PANEL(ctx); +} + +int queueBuffer_OV_3D_VIDEO_3D_TV_to_OV_3D_VIDEO_2D_PANEL(overlay_data_context_t *ctx, + overlay_shared_data* data, bool noRot) +{ + LOGI("3D TV disconnected, close the data channels for 3DTV and open one for panel."); + // Close both the pipes' data channel + for (int i = 0; i < NUM_CHANNELS; i++) { + ctx->pobjDataChannel[i]->closeDataChannel(); + delete ctx->pobjDataChannel[i]; + ctx->pobjDataChannel[i] = NULL; + } + send3DInfoPacket(0); + //update the format3D as monoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + //now open the channel 0 + ctx->pobjDataChannel[VG0_PIPE] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[VG0_PIPE]->startDataChannel( + data->ovid[VG0_PIPE], data->rotid[VG0_PIPE], ctx->size, + FRAMEBUFFER_0, noRot)) { + error_cleanup_data(ctx, VG0_PIPE); + return -1; + } + overlay_rect rect; + ctx->pobjDataChannel[VG0_PIPE]->getCropS3D(&ctx->cropRect, VG0_PIPE, + ctx->format3D, &rect); + //setting the crop value + if(!ctx->pobjDataChannel[VG0_PIPE]->setCrop( rect.x, rect.y,rect.w, rect.h)) { + LOGE("%s:failed to crop pipe 0", __func__); + } + //setting the srcFD + if (!ctx->pobjDataChannel[VG0_PIPE]->setFd(ctx->srcFD)) { + LOGE("%s: Failed set fd for pipe 0", __func__); + return -1; + } + return 0; +} + +void queueBuffer_3D_Panel_common_pre(overlay_data_context_t *ctx) +{ + // Close both the pipes' data channel + for (int i = 0; i < NUM_CHANNELS; i++) { + ctx->pobjDataChannel[i]->closeDataChannel(); + delete ctx->pobjDataChannel[i]; + ctx->pobjDataChannel[i] = NULL; + } + send3DInfoPacket(0); +} + + +int queueBuffer_3D_Panel_common_post(overlay_data_context_t *ctx, + overlay_shared_data* data, + bool noRot) +{ + overlay_rect rect; + for (int i = 0; i < NUM_CHANNELS; i++) { + ctx->pobjDataChannel[i] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[i]->startDataChannel( + data->ovid[i], data->rotid[i], ctx->size, FRAMEBUFFER_0, noRot)) { + error_cleanup_data(ctx, i); + return -1; + } + ctx->pobjDataChannel[i]->getCropS3D(&ctx->cropRect, i, + ctx->format3D, &rect); + if (!ctx->pobjDataChannel[i]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: Failed to crop pipe %d", __func__, i); + return -1; + } + if (!ctx->pobjDataChannel[i]->setFd(ctx->srcFD)) { + LOGE("%s: Failed to set fd for pipe %d", __func__, i); + return -1; + } + } + return 0; +} + +int queueBuffer_OV_3D_VIDEO_3D_TV_to_OV_3D_VIDEO_3D_PANEL(overlay_data_context_t *ctx, + overlay_shared_data* data, + bool noRot) +{ + queueBuffer_3D_Panel_common_pre(ctx); + + if(-1 == queueBuffer_3D_Panel_common_post(ctx, data, noRot)) + return -1; + + return 0; +} + +int queueBuffer_OV_3D_VIDEO_2D_TV_to_OV_3D_VIDEO_3D_PANEL(overlay_data_context_t *ctx, + overlay_shared_data* data, + bool noRot) +{ + queueBuffer_3D_Panel_common_pre(ctx); + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | + ctx->format3D >> SHIFT_3D; + if(-1 == queueBuffer_3D_Panel_common_post(ctx, data, noRot)) + return -1; + + return 0; +} + +////////////////// Queue buffer state machine handling ///////////////////// + +int queueBuffer_OV_2D_VIDEO_ON_PANEL(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot) +{ + switch(newState){ + case OV_2D_VIDEO_ON_PANEL: + // nothing to do here + break; + case OV_2D_VIDEO_ON_TV: + LOGI("TV connected, open a new data channel"); + if(-1 == queueBuffer_OV_2D_VIDEO_ON_PANEL_to_OV_2D_VIDEO_ON_TV(ctx, data)) + return -1; + break; + case OV_3D_VIDEO_2D_PANEL: + case OV_3D_VIDEO_3D_PANEL: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + LOGE("data: Error in handling OV_2D_VIDEO_ON_PANEL newstate=%d", newState); + abort(); + return -1; + default: + LOGE("%s Unknown state in queueBuffer %d", __func__, newState); + abort(); + } + + return 0; +} + +int queueBuffer_OV_3D_VIDEO_2D_PANEL(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot) +{ + switch(newState){ + case OV_3D_VIDEO_2D_PANEL: + // nothing to do here + break; + case OV_3D_VIDEO_2D_TV: + if(-1 == queueBuffer_OV_3D_VIDEO_2D_PANEL_to_OV_3D_VIDEO_2D_TV(ctx, data)) + return -1; + break; + case OV_3D_VIDEO_3D_TV: + if(-1 == queueBuffer_OV_3D_VIDEO_2D_PANEL_to_OV_3D_VIDEO_3D_TV(ctx, data)) + return -1; + break; + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_3D_PANEL: + case OV_2D_VIDEO_ON_TV: + LOGE("Error in handling OV_3D_VIDEO_2D_PANEL newstate=%d", newState); + abort(); + return -1; + default: + LOGE("%s Unknown state in queueBuffer %d", __func__, newState); + abort(); + } + + return 0; +} + +int queueBuffer_OV_3D_VIDEO_3D_PANEL(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot) +{ + switch(newState){ + case OV_3D_VIDEO_3D_PANEL: + // nothing to do here + break; + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + case OV_2D_VIDEO_ON_TV: + LOGE("Error in handling OV_3D_VIDEO_3D_PANEL newstate=%d", newState); + abort(); + return -1; + case OV_3D_VIDEO_2D_TV: + if(-1 == queueBuffer_OV_3D_VIDEO_3D_PANEL_to_OV_3D_VIDEO_2D_TV(ctx, data)) + return -1; + break; + case OV_3D_VIDEO_3D_TV: + if(-1 == queueBuffer_OV_3D_VIDEO_3D_PANEL_to_OV_3D_VIDEO_3D_TV(ctx, data)) + return -1; + break; + default: + LOGE("%s Unknown state in queueBuffer %d", __func__, newState); + abort(); + } + + return 0; +} + +int queueBuffer_OV_2D_VIDEO_ON_TV(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot) +{ + switch(newState){ + case OV_2D_VIDEO_ON_TV: + // nothing to see here + break; + case OV_2D_VIDEO_ON_PANEL: + queueBuffer_OV_2D_VIDEO_ON_TV_to_OV_2D_VIDEO_ON_PANEL(ctx); + break; + case OV_3D_VIDEO_2D_PANEL: + case OV_3D_VIDEO_3D_PANEL: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + LOGE("Error in handling OV_2D_VIDEO_ON_TV newstate=%d", newState); + abort(); + return -1; + default: + LOGE("%s Unknown state in queueBuffer %d", __func__, newState); + abort(); + } + + return 0; +} + +int queueBuffer_OV_3D_VIDEO_2D_TV(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot) +{ + switch(newState){ + case OV_3D_VIDEO_2D_TV: + // nothing to see here + break; + case OV_3D_VIDEO_2D_PANEL: + queueBuffer_OV_3D_VIDEO_2D_TV_to_OV_3D_VIDEO_2D_PANEL(ctx); + break; + case OV_3D_VIDEO_3D_PANEL: + if(-1 == queueBuffer_OV_3D_VIDEO_2D_TV_to_OV_3D_VIDEO_3D_PANEL(ctx, data, noRot)) + return -1; + break; + case OV_2D_VIDEO_ON_PANEL: + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_3D_TV: + LOGE("Error in handling OV_3D_VIDEO_2D_TV newstate=%d", newState); + abort(); + return -1; + default: + LOGE("%s Unknown state in queueBuffer %d", __func__, newState); + abort(); + } + + return 0; +} + +int queueBuffer_OV_3D_VIDEO_3D_TV(overlay_data_context_t *ctx, + overlay_shared_data* data, + unsigned int newState, bool noRot) +{ + switch(newState){ + case OV_3D_VIDEO_3D_TV: + // nothing to see here + break; + case OV_3D_VIDEO_2D_PANEL: + if(-1 == queueBuffer_OV_3D_VIDEO_3D_TV_to_OV_3D_VIDEO_2D_PANEL(ctx, data, noRot)) + return -1; + break; + case OV_3D_VIDEO_3D_PANEL: + if(-1 == queueBuffer_OV_3D_VIDEO_3D_TV_to_OV_3D_VIDEO_3D_PANEL(ctx, data, noRot)) + return -1; + break; + case OV_2D_VIDEO_ON_PANEL: + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + LOGE("Error in handling OV_3D_VIDEO_3D_TV newstate=%d", newState); + abort(); + return -1; + default: + LOGE("%s Unknown state in queueBuffer %d", __func__, newState); + abort(); + } + + return 0; +} + + +///////////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////////// + diff --git a/tests/Android.mk b/tests/Android.mk deleted file mode 100644 index b9a7459..0000000 --- a/tests/Android.mk +++ /dev/null @@ -1,55 +0,0 @@ -# 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) - -# you can use EXTRA_CFLAGS to indicate additional CFLAGS to use -# in the build. The variables will be cleaned on exit -# -# - -libgralloc_test_includes:= \ - bionic/libstdc++/include \ - external/astl/include \ - external/gtest/include \ - $(LOCAL_PATH)/.. - -libgralloc_test_static_libs := \ - libgralloc_qsd8k_host \ - libgtest_main_host \ - libgtest_host \ - libastl_host \ - liblog - -define host-test - $(foreach file,$(1), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_CPP_EXTENSION := .cpp) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_C_INCLUDES := $(libgralloc_test_includes)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \ - $(eval LOCAL_LDLIBS += $(EXTRA_LDLIBS)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(libgralloc_test_static_libs)) \ - $(eval LOCAL_MODULE_TAGS := eng tests) \ - $(eval include $(BUILD_HOST_EXECUTABLE)) \ - ) \ - $(eval EXTRA_CFLAGS :=) \ - $(eval EXTRA_LDLIBS :=) -endef - -TEST_SRC_FILES := \ - pmemalloc_test.cpp - -$(call host-test, $(TEST_SRC_FILES)) diff --git a/tests/pmemalloc_test.cpp b/tests/pmemalloc_test.cpp deleted file mode 100644 index 94e86bf..0000000 --- a/tests/pmemalloc_test.cpp +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (C) 2010 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 "pmemalloc.h" - -class DepsStub : public PmemUserspaceAllocator::Deps, public PmemKernelAllocator::Deps { - - public: - - virtual size_t getPmemTotalSize(int fd, size_t* size) { - return 0; - } - - virtual int connectPmem(int fd, int master_fd) { - return 0; - } - - virtual int mapPmem(int fd, int offset, size_t size) { - return 0; - } - - virtual int unmapPmem(int fd, int offset, size_t size) { - return 0; - } - - virtual int getErrno() { - return 0; - } - - virtual void* mmap(void* start, size_t length, int prot, int flags, int fd, - off_t offset) { - return 0; - } - - virtual int munmap(void* start, size_t length) { - return 0; - } - - virtual int open(const char* pathname, int flags, int mode) { - return 0; - } - - virtual int close(int fd) { - return 0; - } -}; - -/******************************************************************************/ - -class AllocatorStub : public PmemUserspaceAllocator::Deps::Allocator { - virtual ssize_t setSize(size_t size) { - return 0; - } - - virtual size_t size() const { - return 0; - } - - virtual ssize_t allocate(size_t size, uint32_t flags = 0) { - return 0; - } - - virtual ssize_t deallocate(size_t offset) { - return 0; - } -}; - -/******************************************************************************/ - -static const char* fakePmemDev = "/foo/bar"; - -/******************************************************************************/ - -struct Deps_InitPmemAreaLockedWithSuccessfulCompletion : public DepsStub { - - virtual int open(const char* pathname, int flags, int mode) { - EXPECT_EQ(fakePmemDev, pathname); - EXPECT_EQ(O_RDWR, flags); - EXPECT_EQ(0, mode); - return 1234; - } - - virtual size_t getPmemTotalSize(int fd, size_t* size) { - EXPECT_EQ(1234, fd); - *size = 16 << 20; - return 0; - } - - virtual void* mmap(void* start, size_t length, int prot, int flags, int fd, - off_t offset) { - EXPECT_EQ(1234, fd); - return (void*)0x87654321; - } - -}; - -struct Allocator_InitPmemAreaLockedWithSuccessfulCompletion : public AllocatorStub { - - virtual ssize_t setSize(size_t size) { - EXPECT_EQ(size_t(16 << 20), size); - return 0; - } -}; - -TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithSuccessfulCompletion) { - Deps_InitPmemAreaLockedWithSuccessfulCompletion depsMock; - Allocator_InitPmemAreaLockedWithSuccessfulCompletion allocMock; - PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev); - - int result = pma.init_pmem_area_locked(); - ASSERT_EQ(0, result); -} - -/******************************************************************************/ - -struct Deps_InitPmemAreaLockedWithEnomemOnMmap : public DepsStub { - - virtual int open(const char* pathname, int flags, int mode) { - EXPECT_EQ(fakePmemDev, pathname); - EXPECT_EQ(O_RDWR, flags); - EXPECT_EQ(0, mode); - return 1234; - } - - virtual size_t getPmemTotalSize(int fd, size_t* size) { - EXPECT_EQ(1234, fd); - *size = 16 << 20; - return 0; - } - - virtual int getErrno() { - return ENOMEM; - } - - virtual void* mmap(void* start, size_t length, int prot, int flags, int fd, - off_t offset) { - return (void*)MAP_FAILED; - } - -}; - -struct Allocator_InitPmemAreaLockedWithEnomemOnMmap : public AllocatorStub { - - virtual ssize_t setSize(size_t size) { - EXPECT_EQ(size_t(16 << 20), size); - return 0; - } -}; - -TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEnomemOnMmap) { - Deps_InitPmemAreaLockedWithEnomemOnMmap depsMock; - Allocator_InitPmemAreaLockedWithEnomemOnMmap allocMock; - PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev); - - int result = pma.init_pmem_area_locked(); - ASSERT_EQ(-ENOMEM, result); -} - -/******************************************************************************/ - -struct Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize : public DepsStub { - - virtual int open(const char* pathname, int flags, int mode) { - EXPECT_EQ(fakePmemDev, pathname); - EXPECT_EQ(O_RDWR, flags); - EXPECT_EQ(0, mode); - return 1234; - } - - virtual size_t getPmemTotalSize(int fd, size_t* size) { - EXPECT_EQ(1234, fd); - return -EACCES; - } -}; - -TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEaccesOnGetPmemTotalSize) { - Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize depsMock; - AllocatorStub allocStub; - PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev); - - int result = pma.init_pmem_area_locked(); - ASSERT_EQ(-EACCES, result); -} - -/******************************************************************************/ - -struct Deps_InitPmemAreaLockedWithEaccesOnOpen : public DepsStub { - - virtual int getErrno() { - return EACCES; - } - - virtual int open(const char* pathname, int flags, int mode) { - EXPECT_EQ(fakePmemDev, pathname); - EXPECT_EQ(O_RDWR, flags); - EXPECT_EQ(0, mode); - return -1; - } -}; - -TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithEaccesOnOpenMaster) { - Deps_InitPmemAreaLockedWithEaccesOnOpen depsMock; - AllocatorStub allocStub; - PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev); - - int result = pma.init_pmem_area_locked(); - ASSERT_EQ(-EACCES, result); -} - -/******************************************************************************/ - -typedef Deps_InitPmemAreaLockedWithSuccessfulCompletion Deps_InitPmemAreaWithSuccessfulInitialCompletion; - -TEST(test_pmem_userspace_allocator, testInitPmemAreaWithSuccessfulInitialCompletion) { - Deps_InitPmemAreaWithSuccessfulInitialCompletion depsMock; - AllocatorStub allocStub; - PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev); - - int result = pma.init_pmem_area(); - ASSERT_EQ(0, result); -} - -/******************************************************************************/ - -typedef Deps_InitPmemAreaLockedWithEaccesOnOpen Deps_InitPmemAreaWithEaccesOnInitLocked; - -TEST(test_pmem_userspace_allocator, testInitPmemAreaWithEaccesOnInitLocked) { - Deps_InitPmemAreaWithEaccesOnInitLocked depsMock; - AllocatorStub allocStub; - PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev); - - int result = pma.init_pmem_area(); - ASSERT_EQ(-EACCES, result); -} - -/******************************************************************************/ - -TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterSuccessfulInitialCompletion) { - DepsStub depsStub; - AllocatorStub allocStub; - PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev); - - pma.set_master_values(1234, 0); // Indicate that the pma has been successfully init'd - - int result = pma.init_pmem_area(); - ASSERT_EQ(0, result); - //XXX JMG: Add this back in maybe? ASSERT_EQ(1234, pmi.master); // Make sure the master fd wasn't changed -} - -/******************************************************************************/ - -TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterFailedInit) { - DepsStub depsStub; - AllocatorStub allocStub; - PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev); - - pma.set_master_values(-EACCES, 0); // Indicate that the pma has failed init - - int result = pma.init_pmem_area(); - ASSERT_EQ(-EACCES, result); -} - -/******************************************************************************/ - -struct Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags : public DepsStub { - - virtual int open(const char* pathname, int flags, int mode) { - EXPECT_EQ(fakePmemDev, pathname); - EXPECT_EQ(O_RDWR, flags & O_RDWR); - EXPECT_EQ(0, mode); - return 5678; - } - - virtual int connectPmem(int fd, int master_fd) { - EXPECT_EQ(5678, fd); - EXPECT_EQ(1234, master_fd); - return 0; - } - - virtual int mapPmem(int fd, int offset, size_t size) { - EXPECT_EQ(5678, fd); - EXPECT_EQ(0x300, offset); - EXPECT_EQ(size_t(0x100), size); - return 0; - } -}; - - -struct Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags : public AllocatorStub { - - virtual ssize_t allocate(size_t size, uint32_t flags = 0) { - EXPECT_EQ(size_t(0x100), size); - EXPECT_EQ(uint32_t(0x0), flags); - return 0x300; - } -}; - -TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) { - Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags depsMock; - Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags allocMock; - PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev); - - uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd - pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd - - void* base = 0; - int offset = -9182, fd = -9182; - int size = 0x100; - int flags = 0; - int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd); - ASSERT_EQ(0, result); - ASSERT_EQ(0x300, offset); - ASSERT_EQ(5678, fd); - for (int i = 0x300; i < 0x400; ++i) { - ASSERT_EQ(uint8_t(0), buf[i]); - } -} - -/******************************************************************************/ - -typedef Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags; - -typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags; - -TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) { - Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags depsMock; - Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags allocMock; - PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev); - - uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd - pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd - - void* base = 0; - int offset = -9182, fd = -9182; - int size = 0x100; - int flags = ~0; - int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd); - ASSERT_EQ(0, result); - ASSERT_EQ(0x300, offset); - ASSERT_EQ(5678, fd); - for (int i = 0x300; i < 0x400; ++i) { - ASSERT_EQ(0, buf[i]); - } -} - -/******************************************************************************/ - -struct Deps_InitPmemAreaLockedWithEnodevOnOpen : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags { - - virtual int getErrno() { - return ENODEV; - } - - virtual int open(const char* pathname, int flags, int mode) { - EXPECT_EQ(fakePmemDev, pathname); - EXPECT_EQ(O_RDWR, flags & O_RDWR); - EXPECT_EQ(0, mode); - return -1; - } -}; - -typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnodevOnOpen; - -TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnodevOnOpen) { - Deps_InitPmemAreaLockedWithEnodevOnOpen depsMock; - Allocator_AllocPmemBufferWithEnodevOnOpen allocMock; - PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev); - - uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd - pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd - - void* base = 0; - int offset = -9182, fd = -9182; - int size = 0x100; - int flags = ~0; - int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd); - ASSERT_EQ(-ENODEV, result); -} - -/******************************************************************************/ - -struct Deps_InitPmemAreaLockedWithEnomemOnConnectPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags { - - virtual int getErrno() { - return ENOMEM; - } - - virtual int connectPmem(int fd, int master_fd) { - EXPECT_EQ(5678, fd); - EXPECT_EQ(1234, master_fd); - return -1; - } -}; - -typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnConnectPmem; - -TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnomemOnConnectPmem) { - Deps_InitPmemAreaLockedWithEnomemOnConnectPmem depsMock; - Allocator_AllocPmemBufferWithEnomemOnConnectPmem allocMock; - PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev); - - uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd - pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd - - void* base = 0; - int offset = -9182, fd = -9182; - int size = 0x100; - int flags = ~0; - int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd); - ASSERT_EQ(-ENOMEM, result); -} - -/******************************************************************************/ - -struct Deps_InitPmemAreaLockedWithEnomemOnMapPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags { - - virtual int getErrno() { - return ENOMEM; - } - - virtual int mapPmem(int fd, int offset, size_t size) { - EXPECT_EQ(5678, fd); - EXPECT_EQ(0x300, offset); - EXPECT_EQ(size_t(0x100), size); - return -1; - } -}; - -typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnMapPmem; - -TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithEnomemOnMapPmem) { - Deps_InitPmemAreaLockedWithEnomemOnMapPmem depsMock; - Allocator_AllocPmemBufferWithEnomemOnMapPmem allocMock; - PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev); - - uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd - pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd - - void* base = 0; - int offset = -9182, fd = -9182; - int size = 0x100; - int flags = ~0; - int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd); - ASSERT_EQ(-ENOMEM, result); -} - -/******************************************************************************/ - -struct Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags : public DepsStub { - - void* mmapResult; - - Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags(void* mmapResult) : - mmapResult(mmapResult) {} - - virtual int open(const char* pathname, int flags, int mode) { - EXPECT_EQ(fakePmemDev, pathname); - EXPECT_EQ(O_RDWR, flags & O_RDWR); - EXPECT_EQ(0, mode); - return 5678; - } - - virtual void* mmap(void* start, size_t length, int prot, int flags, int fd, - off_t offset) { - EXPECT_EQ(5678, fd); - return mmapResult; - } -}; - -TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) { - uint8_t buf[0x100]; // Create a buffer to get memzero'd - Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags depsMock(buf); - PmemKernelAllocator pma(depsMock, fakePmemDev); - - void* base = 0; - int offset = -9182, fd = -9182; - int size = 0x100; - int flags = 0; - int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd); - ASSERT_EQ(0, result); - ASSERT_EQ(buf, base); - ASSERT_EQ(0, offset); - ASSERT_EQ(5678, fd); - for (int i = 0; i < 0x100; ++i) { - ASSERT_EQ(0, buf[i]); - } -} - -/******************************************************************************/ - -typedef Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags; - -TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) { - uint8_t buf[0x100]; // Create a buffer to get memzero'd - Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags depsMock(buf); - PmemKernelAllocator pma(depsMock, fakePmemDev); - - void* base = 0; - int offset = -9182, fd = -9182; - int size = 0x100; - int flags = ~0; - int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd); - ASSERT_EQ(0, result); - ASSERT_EQ(buf, base); - ASSERT_EQ(0, offset); - ASSERT_EQ(5678, fd); - for (int i = 0; i < 0x100; ++i) { - ASSERT_EQ(0, buf[i]); - } -} - -/******************************************************************************/ - -struct Deps_KernelAllocPmemBufferWithEpermOnOpen : public DepsStub { - - virtual int getErrno() { - return EPERM; - } - - virtual int open(const char* pathname, int flags, int mode) { - EXPECT_EQ(fakePmemDev, pathname); - EXPECT_EQ(O_RDWR, flags & O_RDWR); - EXPECT_EQ(0, mode); - return -1; - } -}; - - -TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEpermOnOpen) { - Deps_KernelAllocPmemBufferWithEpermOnOpen depsMock; - PmemKernelAllocator pma(depsMock, fakePmemDev); - - void* base = 0; - int offset = -9182, fd = -9182; - int size = 0x100; - int flags = ~0; - int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd); - ASSERT_EQ(-EPERM, result); - ASSERT_EQ(0, base); - ASSERT_EQ(0, offset); - ASSERT_EQ(-1, fd); -} - -/******************************************************************************/ - -struct Deps_KernelAllocPmemBufferWithEnomemOnMmap : DepsStub { - - virtual int open(const char* pathname, int flags, int mode) { - EXPECT_EQ(fakePmemDev, pathname); - EXPECT_EQ(O_RDWR, flags & O_RDWR); - EXPECT_EQ(0, mode); - return 5678; - } - - virtual void* mmap(void* start, size_t length, int prot, int flags, int fd, - off_t offset) { - return (void*)MAP_FAILED; - } - - virtual int getErrno() { - return ENOMEM; - } -}; - - -TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEnomemOnMmap) { - Deps_KernelAllocPmemBufferWithEnomemOnMmap depsMock; - PmemKernelAllocator pma(depsMock, fakePmemDev); - - void* base = 0; - int offset = -9182, fd = -9182; - int size = 0x100; - int flags = ~0; - int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd); - ASSERT_EQ(-ENOMEM, result); - ASSERT_EQ(0, base); - ASSERT_EQ(0, offset); - ASSERT_EQ(-1, fd); -} - -/******************************************************************************/