diff --git a/common.mk b/common.mk index 287da3e..a48476e 100644 --- a/common.mk +++ b/common.mk @@ -16,9 +16,6 @@ common_libs := liblog libutils libcutils libhardware #Common C flags common_flags := -DDEBUG_CALC_FPS -Wno-missing-field-initializers -ifeq ($(TARGET_USES_ION),true) -common_flags += -DUSE_ION -endif ifeq ($(ARCH_ARM_HAVE_NEON),true) common_flags += -D__ARM_HAVE_NEON endif diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp index ee8c12e..2e2956c 100644 --- a/libcopybit/copybit.cpp +++ b/libcopybit/copybit.cpp @@ -426,8 +426,7 @@ static int stretch_copybit( } if(src->format == HAL_PIXEL_FORMAT_YV12) { - int usage = GRALLOC_USAGE_PRIVATE_ADSP_HEAP | - GRALLOC_USAGE_PRIVATE_MM_HEAP; + int usage = GRALLOC_USAGE_PRIVATE_MM_HEAP; if (0 == alloc_buffer(&yv12_handle,src->w,src->h, src->format, usage)){ if(0 == convertYV12toYCrCb420SP(src,yv12_handle)){ diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp index 72aa279..5eec414 100644 --- a/libcopybit/copybit_c2d.cpp +++ b/libcopybit/copybit_c2d.cpp @@ -49,7 +49,6 @@ using gralloc::IMemAlloc; using gralloc::IonController; using gralloc::alloc_data; -using android::sp; C2D_STATUS (*LINK_c2dCreateSurface)( uint32 *surface_id, uint32 surface_bits, @@ -110,7 +109,7 @@ enum eC2DFlags { FLAGS_YUV_DESTINATION = 1<<1 }; -static android::sp sAlloc = 0; +static gralloc::IAllocController* sAlloc = 0; /******************************************************************************/ /** State information for each device instance */ @@ -126,6 +125,7 @@ struct copybit_context_t { int fb_width; int fb_height; bool isPremultipliedAlpha; + bool mBlitToFB; }; struct blitlist{ @@ -783,6 +783,16 @@ static int set_parameter_copybit( case COPYBIT_FRAMEBUFFER_HEIGHT: ctx->fb_height = value; break; + case COPYBIT_BLIT_TO_FRAMEBUFFER: + if (COPYBIT_ENABLE == value) { + ctx->mBlitToFB = value; + } else if (COPYBIT_DISABLE == value) { + ctx->mBlitToFB = value; + } else { + ALOGE ("%s:Invalid input for COPYBIT_BLIT_TO_FRAMEBUFFER : %d", + __FUNCTION__, value); + } + break; default: ALOGE("%s: default case param=0x%x", __FUNCTION__, name); return -EINVAL; @@ -922,7 +932,7 @@ static int get_temp_buffer(const bufferInfo& info, alloc_data& data) int allocFlags = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP; if (sAlloc == 0) { - sAlloc = gralloc::IAllocController::getInstance(false); + sAlloc = gralloc::IAllocController::getInstance(); } if (sAlloc == 0) { @@ -930,7 +940,7 @@ static int get_temp_buffer(const bufferInfo& info, alloc_data& data) return COPYBIT_FAILURE; } - int err = sAlloc->allocate(data, allocFlags, 0); + int err = sAlloc->allocate(data, allocFlags); if (0 != err) { ALOGE("%s: allocate failed", __FUNCTION__); return COPYBIT_FAILURE; @@ -944,7 +954,7 @@ static int get_temp_buffer(const bufferInfo& info, alloc_data& data) static void free_temp_buffer(alloc_data &data) { if (-1 != data.fd) { - sp memalloc = sAlloc->getAllocator(data.allocType); + IMemAlloc* memalloc = sAlloc->getAllocator(data.allocType); memalloc->free_buffer(data.base, data.size, 0, data.fd); } } @@ -1163,7 +1173,7 @@ static int stretch_copybit_internal( copy_image((private_handle_t *)src->handle, &src_image, CONVERT_TO_C2D_FORMAT); // Flush the cache - sp memalloc = sAlloc->getAllocator(src_hnd->flags); + IMemAlloc* memalloc = sAlloc->getAllocator(src_hnd->flags); if (memalloc->clean_buffer((void *)(src_hnd->base), src_hnd->size, src_hnd->offset, src_hnd->fd)) { ALOGE("%s: clean_buffer failed", __FUNCTION__); @@ -1234,7 +1244,7 @@ static int stretch_copybit_internal( // copy the temp. destination without the alignment to the actual destination. copy_image(dst_hnd, dst, CONVERT_TO_ANDROID_FORMAT); // Invalidate the cache. - sp memalloc = sAlloc->getAllocator(dst_hnd->flags); + IMemAlloc* memalloc = sAlloc->getAllocator(dst_hnd->flags); memalloc->clean_buffer((void *)(dst_hnd->base), dst_hnd->size, dst_hnd->offset, dst_hnd->fd); } diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp index d55c2cd..1802a75 100644 --- a/libgralloc/alloc_controller.cpp +++ b/libgralloc/alloc_controller.cpp @@ -28,33 +28,16 @@ */ #include -#include #include #include "gralloc_priv.h" #include "alloc_controller.h" #include "memalloc.h" -#ifdef USE_ION #include "ionalloc.h" -#else -#include "pmemalloc.h" -#include "ashmemalloc.h" -#endif #include "gr.h" #include "comptype.h" using namespace gralloc; using namespace qdutils; -using android::sp; - -const int GRALLOC_HEAP_MASK = GRALLOC_USAGE_PRIVATE_ADSP_HEAP | - GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP | - GRALLOC_USAGE_PRIVATE_SMI_HEAP | - GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP | - GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | - GRALLOC_USAGE_PRIVATE_MM_HEAP | - GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP | - GRALLOC_USAGE_PRIVATE_CAMERA_HEAP; - //Common functions static bool canFallback(int usage, bool triedSystem) @@ -74,7 +57,7 @@ static bool canFallback(int usage, bool triedSystem) if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_PRIVATE_CP_BUFFER)) return false; - if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_EXTERNAL_ONLY)) + if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY)) return false; //Return true by default return true; @@ -91,32 +74,23 @@ static bool useUncached(int usage) return false; } -sp IAllocController::sController = NULL; -sp IAllocController::getInstance(bool useMasterHeap) +IAllocController* IAllocController::sController = NULL; +IAllocController* IAllocController::getInstance(void) { if(sController == NULL) { -#ifdef USE_ION sController = new IonController(); -#else - if(useMasterHeap) - sController = new PmemAshmemController(); - else - sController = new PmemKernelController(); -#endif } return sController; } -#ifdef USE_ION //-------------- IonController-----------------------// IonController::IonController() { mIonAlloc = new IonAlloc(); } -int IonController::allocate(alloc_data& data, int usage, - int compositionType) +int IonController::allocate(alloc_data& data, int usage) { int ionFlags = 0; int ret; @@ -139,20 +113,12 @@ int IonController::allocate(alloc_data& data, int usage, if(usage & GRALLOC_USAGE_PRIVATE_MM_HEAP) ionFlags |= ION_HEAP(ION_CP_MM_HEAP_ID); - if(usage & GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP) - ionFlags |= ION_HEAP(ION_CP_WB_HEAP_ID); - if(usage & GRALLOC_USAGE_PRIVATE_CAMERA_HEAP) ionFlags |= ION_HEAP(ION_CAMERA_HEAP_ID); if(usage & GRALLOC_USAGE_PRIVATE_CP_BUFFER) ionFlags |= ION_SECURE; - if(usage & GRALLOC_USAGE_PRIVATE_DO_NOT_MAP) - data.allocType |= private_handle_t::PRIV_FLAGS_NOT_MAPPED; - else - data.allocType &= ~(private_handle_t::PRIV_FLAGS_NOT_MAPPED); - // if no flags are set, default to // SF + IOMMU heaps, so that bypass can work // we can fall back to system heap if @@ -184,9 +150,9 @@ int IonController::allocate(alloc_data& data, int usage, return ret; } -sp IonController::getAllocator(int flags) +IMemAlloc* IonController::getAllocator(int flags) { - sp memalloc; + IMemAlloc* memalloc; if (flags & private_handle_t::PRIV_FLAGS_USES_ION) { memalloc = mIonAlloc; } else { @@ -195,152 +161,7 @@ sp IonController::getAllocator(int flags) return memalloc; } -#endif -//-------------- PmemKernelController-----------------------// -#ifndef USE_ION -PmemKernelController::PmemKernelController() -{ - mPmemAdspAlloc = new PmemKernelAlloc(DEVICE_PMEM_ADSP); - // XXX: Right now, there is no need to maintain an instance - // of the SMI allocator as we need it only in a few cases -} - -PmemKernelController::~PmemKernelController() -{ -} - -int PmemKernelController::allocate(alloc_data& data, int usage, - int compositionType) -{ - int ret = 0; - bool adspFallback = false; - if (!(usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP)) - adspFallback = true; - - // Try SMI first - if ((usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP) || - (usage & GRALLOC_USAGE_EXTERNAL_DISP) || - (usage & GRALLOC_USAGE_PROTECTED)) - { - int tempFd = open(DEVICE_PMEM_SMIPOOL, O_RDWR, 0); - if(tempFd > 0) { - close(tempFd); - sp memalloc; - memalloc = new PmemKernelAlloc(DEVICE_PMEM_SMIPOOL); - ret = memalloc->alloc_buffer(data); - if(ret >= 0) - return ret; - else { - if(adspFallback) - ALOGW("Allocation from SMI failed, trying ADSP"); - } - } - } - - if ((usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) || adspFallback) { - ret = mPmemAdspAlloc->alloc_buffer(data); - } - return ret; -} - -sp PmemKernelController::getAllocator(int flags) -{ - sp memalloc; - if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) - memalloc = mPmemAdspAlloc; - else { - ALOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags); - memalloc = NULL; - } - - return memalloc; -} - -//-------------- PmemAshmmemController-----------------------// - -PmemAshmemController::PmemAshmemController() -{ - mPmemUserspaceAlloc = new PmemUserspaceAlloc(); - mAshmemAlloc = new AshmemAlloc(); - mPmemKernelCtrl = new PmemKernelController(); -} - -PmemAshmemController::~PmemAshmemController() -{ -} - -int PmemAshmemController::allocate(alloc_data& data, int usage, - int compositionType) -{ - int ret = 0; - data.allocType = 0; - - // Make buffers cacheable by default - data.uncached = false; - - // Override if we explicitly need uncached buffers - if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED) - data.uncached = true; - - // If ADSP or SMI is requested use the kernel controller - if(usage & (GRALLOC_USAGE_PRIVATE_ADSP_HEAP| - GRALLOC_USAGE_PRIVATE_SMI_HEAP)) { - ret = mPmemKernelCtrl->allocate(data, usage, compositionType); - if(ret < 0) - ALOGE("%s: Failed to allocate ADSP/SMI memory", __func__); - else - data.allocType = private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP; - return ret; - } - - if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP) { - ret = mAshmemAlloc->alloc_buffer(data); - if(ret >= 0) { - data.allocType = private_handle_t::PRIV_FLAGS_USES_ASHMEM; - data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM; - } - return ret; - } - - // if no memory specific flags are set, - // default to EBI heap, so that bypass - // can work. We can fall back to system - // heap if we run out. - ret = mPmemUserspaceAlloc->alloc_buffer(data); - - // Fallback - if(ret >= 0 ) { - data.allocType = private_handle_t::PRIV_FLAGS_USES_PMEM; - } else if(ret < 0 && canFallback(usage, false)) { - ALOGW("Falling back to ashmem"); - ret = mAshmemAlloc->alloc_buffer(data); - if(ret >= 0) { - data.allocType = private_handle_t::PRIV_FLAGS_USES_ASHMEM; - data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM; - } - } - - return ret; -} - -sp PmemAshmemController::getAllocator(int flags) -{ - sp memalloc; - if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM) - memalloc = mPmemUserspaceAlloc; - else if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) - memalloc = mPmemKernelCtrl->getAllocator(flags); - else if (flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) - memalloc = mAshmemAlloc; - else { - ALOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags); - memalloc = NULL; - } - - return memalloc; -} -#endif size_t getBufferSizeAndDimensions(int width, int height, int format, int& alignedw, int &alignedh) { @@ -421,8 +242,8 @@ int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage) { alloc_data data; int alignedw, alignedh; - android::sp sAlloc = - gralloc::IAllocController::getInstance(false); + gralloc::IAllocController* sAlloc = + gralloc::IAllocController::getInstance(); data.base = 0; data.fd = -1; data.offset = 0; @@ -431,14 +252,15 @@ int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage) data.uncached = useUncached(usage); int allocFlags = usage; - int err = sAlloc->allocate(data, allocFlags, 0); + int err = sAlloc->allocate(data, allocFlags); if (0 != err) { ALOGE("%s: allocate failed", __FUNCTION__); return -ENOMEM; } private_handle_t* hnd = new private_handle_t(data.fd, data.size, - data.allocType, 0, format, alignedw, alignedh); + data.allocType, 0, format, + alignedw, alignedh); hnd->base = (int) data.base; hnd->offset = data.offset; hnd->gpuaddr = 0; @@ -448,10 +270,10 @@ int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage) void free_buffer(private_handle_t *hnd) { - android::sp sAlloc = - gralloc::IAllocController::getInstance(false); + gralloc::IAllocController* sAlloc = + gralloc::IAllocController::getInstance(); if (hnd && hnd->fd > 0) { - sp memalloc = sAlloc->getAllocator(hnd->flags); + IMemAlloc* memalloc = sAlloc->getAllocator(hnd->flags); memalloc->free_buffer((void*)hnd->base, hnd->size, hnd->offset, hnd->fd); } if(hnd) diff --git a/libgralloc/alloc_controller.h b/libgralloc/alloc_controller.h index 134ad40..f04917a 100644 --- a/libgralloc/alloc_controller.h +++ b/libgralloc/alloc_controller.h @@ -29,86 +29,43 @@ #ifndef GRALLOC_ALLOCCONTROLLER_H #define GRALLOC_ALLOCCONTROLLER_H -#include - namespace gralloc { struct alloc_data; class IMemAlloc; class IonAlloc; -class IAllocController : public android::RefBase { +class IAllocController { public: /* Allocate using a suitable method * Returns the type of buffer allocated */ - virtual int allocate(alloc_data& data, int usage, - int compositionType) = 0; + virtual int allocate(alloc_data& data, int usage) = 0; - virtual android::sp getAllocator(int flags) = 0; + virtual IMemAlloc* getAllocator(int flags) = 0; virtual ~IAllocController() {}; - static android::sp getInstance(bool useMasterHeap); + static IAllocController* getInstance(void); private: - static android::sp sController; + static IAllocController* sController; }; class IonController : public IAllocController { public: - virtual int allocate(alloc_data& data, int usage, - int compositionType); + virtual int allocate(alloc_data& data, int usage); - virtual android::sp getAllocator(int flags); + virtual IMemAlloc* getAllocator(int flags); IonController(); private: - android::sp mIonAlloc; + IonAlloc* mIonAlloc; }; - -class PmemKernelController : public IAllocController { - - public: - virtual int allocate(alloc_data& data, int usage, - int compositionType); - - virtual android::sp getAllocator(int flags); - - PmemKernelController (); - - ~PmemKernelController (); - - private: - android::sp mPmemAdspAlloc; - -}; - -// Main pmem controller - this should only -// be used within gralloc -class PmemAshmemController : public IAllocController { - - public: - virtual int allocate(alloc_data& data, int usage, - int compositionType); - - virtual android::sp getAllocator(int flags); - - PmemAshmemController(); - - ~PmemAshmemController(); - - private: - android::sp mPmemUserspaceAlloc; - android::sp mAshmemAlloc; - android::sp mPmemKernelCtrl; - -}; - } //end namespace gralloc #endif // GRALLOC_ALLOCCONTROLLER_H diff --git a/libgralloc/ashmemalloc.cpp b/libgralloc/ashmemalloc.cpp deleted file mode 100644 index b659d90..0000000 --- a/libgralloc/ashmemalloc.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2011-2012, 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) { - ALOGE("couldn't create ashmem (%s)", strerror(errno)); - err = -errno; - } else { - if (ashmem_set_prot_region(fd, prot) < 0) { - ALOGE("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) { - ALOGE("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); - ALOGD("ashmem: Allocated buffer base:%p size:%d fd:%d", - base, data.size, fd); - - } - return err; - -} - -int AshmemAlloc::free_buffer(void* base, size_t size, int offset, int fd) -{ - ALOGD("ashmem: Freeing buffer base:%p size:%d fd:%d", - base, size, fd); - int err = 0; - - if(!base) { - ALOGE("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) -{ - int err = 0; - void *base = 0; - - base = mmap(0, size, PROT_READ| PROT_WRITE, - MAP_SHARED|MAP_POPULATE, fd, 0); - *pBase = base; - if(base == MAP_FAILED) { - ALOGE("ashmem: Failed to map memory in the client: %s", - strerror(errno)); - err = -errno; - } else { - ALOGD("ashmem: Mapped buffer base:%p size:%d fd:%d", - base, size, fd); - } - return err; -} - -int AshmemAlloc::unmap_buffer(void *base, size_t size, int offset) -{ - ALOGD("ashmem: Unmapping buffer base: %p size: %d", base, size); - int err = munmap(base, size); - if(err) { - ALOGE("ashmem: Failed to unmap memory at %p: %s", - base, strerror(errno)); - } - return err; - -} -int AshmemAlloc::clean_buffer(void *base, size_t size, int offset, int fd) -{ - int err = 0; - if (ioctl(fd, ASHMEM_CACHE_FLUSH_RANGE, NULL)) { - ALOGE("ashmem: ASHMEM_CACHE_FLUSH_RANGE failed fd = %d", fd); - } - - return err; -} - diff --git a/libgralloc/ashmemalloc.h b/libgralloc/ashmemalloc.h deleted file mode 100644 index 50daf04..0000000 --- a/libgralloc/ashmemalloc.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2011-2012, 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/libgralloc/gpu.cpp b/libgralloc/gpu.cpp index 4f00e4a..2db6274 100644 --- a/libgralloc/gpu.cpp +++ b/libgralloc/gpu.cpp @@ -29,10 +29,9 @@ #include "alloc_controller.h" using namespace gralloc; -using android::sp; gpu_context_t::gpu_context_t(const private_module_t* module, - sp alloc_ctrl ) : + IAllocController* alloc_ctrl ) : mAllocCtrl(alloc_ctrl) { // Zero out the alloc_device_t @@ -44,9 +43,6 @@ gpu_context_t::gpu_context_t(const private_module_t* module, common.module = const_cast(&module->base.common); common.close = gralloc_close; alloc = gralloc_alloc; -#if 0 - allocSize = gralloc_alloc_size; -#endif free = gralloc_free; } @@ -56,8 +52,8 @@ int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage, { 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) { + // we don't support framebuffer allocations with graphics heap flags + if (usage & GRALLOC_HEAP_MASK) { return -EINVAL; } @@ -140,17 +136,19 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, else data.align = getpagesize(); data.pHandle = (unsigned int) pHandle; - err = mAllocCtrl->allocate(data, usage, 0); + err = mAllocCtrl->allocate(data, usage); if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) { flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED; } - if (usage & GRALLOC_USAGE_EXTERNAL_ONLY) { + if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) { flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY; //The EXTERNAL_BLOCK flag is always an add-on - if (usage & GRALLOC_USAGE_EXTERNAL_BLOCK) { + if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) { flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK; + }if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) { + flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC; } } @@ -242,7 +240,7 @@ int gpu_context_t::free_impl(private_handle_t const* hnd) { m->bufferMask &= ~(1<base, const_cast(hnd)); - sp memalloc = mAllocCtrl->getAllocator(hnd->flags); + IMemAlloc* memalloc = mAllocCtrl->getAllocator(hnd->flags); int err = memalloc->free_buffer((void*)hnd->base, (size_t) hnd->size, hnd->offset, hnd->fd); if(err) diff --git a/libgralloc/gpu.h b/libgralloc/gpu.h index 487f4d1..5a6c0ea 100644 --- a/libgralloc/gpu.h +++ b/libgralloc/gpu.h @@ -25,7 +25,6 @@ #include #include -#include #include "gralloc_priv.h" #include @@ -35,7 +34,7 @@ class IAllocController; class gpu_context_t : public alloc_device_t { public: gpu_context_t(const private_module_t* module, - android::spalloc_ctrl); + IAllocController* alloc_ctrl); int gralloc_alloc_framebuffer_locked(size_t size, int usage, buffer_handle_t* pHandle); @@ -69,7 +68,7 @@ class gpu_context_t : public alloc_device_t { static int gralloc_close(struct hw_device_t *dev); private: - android::sp mAllocCtrl; + IAllocController* mAllocCtrl; void getGrallocInformationFromFormat(int inputFormat, int *colorFormat, int *bufferType); diff --git a/libgralloc/gralloc.cpp b/libgralloc/gralloc.cpp index cf57fee..7924ae3 100644 --- a/libgralloc/gralloc.cpp +++ b/libgralloc/gralloc.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include @@ -33,7 +32,6 @@ #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); @@ -102,7 +100,7 @@ int gralloc_device_open(const hw_module_t* module, const char* name, const private_module_t* m = reinterpret_cast( module); gpu_context_t *dev; - sp alloc_ctrl = IAllocController::getInstance(true); + IAllocController* alloc_ctrl = IAllocController::getInstance(); dev = new gpu_context_t(m, alloc_ctrl); *device = &dev->common; status = 0; diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 9dfcd32..a689bca 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -34,33 +34,22 @@ enum { /* gralloc usage bits indicating the type * of allocation that should be used */ - /* ADSP heap is deprecated, use only if using pmem */ - GRALLOC_USAGE_PRIVATE_ADSP_HEAP = GRALLOC_USAGE_PRIVATE_0, - /* SF heap is used for application buffers, is not secured */ - GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP = GRALLOC_USAGE_PRIVATE_1, - /* SMI heap is deprecated, use only if using pmem */ - GRALLOC_USAGE_PRIVATE_SMI_HEAP = GRALLOC_USAGE_PRIVATE_2, /* SYSTEM heap comes from kernel vmalloc, * can never be uncached, is not secured*/ - GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP = GRALLOC_USAGE_PRIVATE_3, + GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP = GRALLOC_USAGE_PRIVATE_0, + /* SF heap is used for application buffers, is not secured */ + GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP = GRALLOC_USAGE_PRIVATE_1, /* IOMMU heap comes from manually allocated pages, * can be cached/uncached, is not secured */ - GRALLOC_USAGE_PRIVATE_IOMMU_HEAP = 0x01000000, + GRALLOC_USAGE_PRIVATE_IOMMU_HEAP = GRALLOC_USAGE_PRIVATE_2, /* MM heap is a carveout heap for video, can be secured*/ - GRALLOC_USAGE_PRIVATE_MM_HEAP = 0x02000000, - /* WRITEBACK heap is a carveout heap for writeback, can be secured*/ - GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP = 0x04000000, + GRALLOC_USAGE_PRIVATE_MM_HEAP = GRALLOC_USAGE_PRIVATE_3, /* CAMERA heap is a carveout heap for camera, is not secured*/ - GRALLOC_USAGE_PRIVATE_CAMERA_HEAP = 0x08000000, + GRALLOC_USAGE_PRIVATE_CAMERA_HEAP = 0x01000000, /* Set this for allocating uncached memory (using O_DSYNC) * cannot be used with noncontiguous heaps */ - GRALLOC_USAGE_PRIVATE_UNCACHED = 0x00100000, - - /* This flag needs to be set when using a non-contiguous heap from ION. - * If not set, the system heap is assumed to be coming from ashmem - */ - GRALLOC_USAGE_PRIVATE_ION = 0x00200000, + GRALLOC_USAGE_PRIVATE_UNCACHED = 0x02000000, /* This flag can be set to disable genlock synchronization * for the gralloc buffer. If this flag is set the caller @@ -68,26 +57,32 @@ enum { * WARNING - flag is outside the standard PRIVATE region * and may need to be moved if the gralloc API changes */ - GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED = 0X00400000, - - /* Set this flag when you need to avoid mapping the memory in userspace */ - GRALLOC_USAGE_PRIVATE_DO_NOT_MAP = 0X00800000, + GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED = 0X04000000, /* Buffer content should be displayed on an external display only */ - GRALLOC_USAGE_EXTERNAL_ONLY = 0x00010000, + GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY = 0x08000000, /* Only this buffer content should be displayed on external, even if * other EXTERNAL_ONLY buffers are available. Used during suspend. */ - GRALLOC_USAGE_EXTERNAL_BLOCK = 0x00020000, + GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK = 0x00100000, + + /* Close Caption displayed on an external display only */ + GRALLOC_USAGE_PRIVATE_EXTERNAL_CC = 0x00200000, /* Use this flag to request content protected buffers. Please note * that this flag is different from the GRALLOC_USAGE_PROTECTED flag * which can be used for buffers that are not secured for DRM * but still need to be protected from screen captures - * 0x00040000 is reserved and these values are subject to change. */ - GRALLOC_USAGE_PRIVATE_CP_BUFFER = 0x00080000, + GRALLOC_USAGE_PRIVATE_CP_BUFFER = 0x00400000, + + /* Legacy heaps - these heaps are no-ops so we are making them zero + * The flags need to be around to compile certain HALs which have + * not cleaned up the code + */ + GRALLOC_USAGE_PRIVATE_ADSP_HEAP = 0x0, + GRALLOC_USAGE_PRIVATE_SMI_HEAP = 0x0, }; enum { @@ -96,12 +91,12 @@ enum { GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER = 0x080000001, }; +#define GRALLOC_HEAP_MASK (GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |\ + GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP |\ + GRALLOC_USAGE_PRIVATE_IOMMU_HEAP |\ + GRALLOC_USAGE_PRIVATE_MM_HEAP |\ + GRALLOC_USAGE_PRIVATE_CAMERA_HEAP) -#define INTERLACE_MASK 0x80 -#define S3D_FORMAT_MASK 0xFF000 -#define DEVICE_PMEM "/dev/pmem" -#define DEVICE_PMEM_ADSP "/dev/pmem_adsp" -#define DEVICE_PMEM_SMIPOOL "/dev/pmem_smipool" /*****************************************************************************/ enum { /* OEM specific HAL formats */ @@ -169,6 +164,8 @@ struct private_handle_t : public native_handle { PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000, // Display only this buffer on external PRIV_FLAGS_EXTERNAL_BLOCK = 0x00004000, + // Display this buffer on external as close caption + PRIV_FLAGS_EXTERNAL_CC = 0x00008000, }; // file-descriptors diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp index 80f448f..8af5a96 100644 --- a/libgralloc/ionalloc.cpp +++ b/libgralloc/ionalloc.cpp @@ -27,7 +27,7 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - +#define DEBUG 0 #include #include #include @@ -118,9 +118,7 @@ int IonAlloc::alloc_buffer(alloc_data& data) return err; } - if(!(data.flags & ION_SECURE) && - !(data.allocType & private_handle_t::PRIV_FLAGS_NOT_MAPPED)) { - + if(!(data.flags & ION_SECURE)) { base = mmap(0, ionAllocData.len, PROT_READ|PROT_WRITE, MAP_SHARED, fd_data.fd, 0); if(base == MAP_FAILED) { @@ -144,7 +142,7 @@ int IonAlloc::alloc_buffer(alloc_data& data) data.base = base; data.fd = fd_data.fd; ioctl(mIonFd, ION_IOC_FREE, &handle_data); - ALOGD("ion: Allocated buffer base:%p size:%d fd:%d", + ALOGD_IF(DEBUG, "ion: Allocated buffer base:%p size:%d fd:%d", data.base, ionAllocData.len, data.fd); return 0; } @@ -153,7 +151,7 @@ int IonAlloc::alloc_buffer(alloc_data& data) int IonAlloc::free_buffer(void* base, size_t size, int offset, int fd) { Locker::Autolock _l(mLock); - ALOGD("ion: Freeing buffer base:%p size:%d fd:%d", + ALOGD_IF(DEBUG, "ion: Freeing buffer base:%p size:%d fd:%d", base, size, fd); int err = 0; err = open_device(); @@ -181,10 +179,10 @@ int IonAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) *pBase = base; if(base == MAP_FAILED) { err = -errno; - ALOGD("ion: Failed to map memory in the client: %s", + ALOGE("ion: Failed to map memory in the client: %s", strerror(errno)); } else { - ALOGD("ion: Mapped buffer base:%p size:%d offset:%d fd:%d", + ALOGD_IF(DEBUG, "ion: Mapped buffer base:%p size:%d offset:%d fd:%d", base, size, offset, fd); } return err; @@ -192,7 +190,7 @@ int IonAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) int IonAlloc::unmap_buffer(void *base, size_t size, int offset) { - ALOGD("ion: Unmapping buffer base:%p size:%d", base, size); + ALOGD_IF(DEBUG, "ion: Unmapping buffer base:%p size:%d", base, size); int err = 0; if(munmap(base, size)) { err = -errno; diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp index 4249f3f..99f9f08 100644 --- a/libgralloc/mapper.cpp +++ b/libgralloc/mapper.cpp @@ -44,15 +44,14 @@ #include "memalloc.h" using namespace gralloc; -using android::sp; /*****************************************************************************/ // Return the type of allocator - // these are used for mapping/unmapping -static sp getAllocator(int flags) +static IMemAlloc* getAllocator(int flags) { - sp memalloc; - sp alloc_ctrl = IAllocController::getInstance(true); + IMemAlloc* memalloc; + IAllocController* alloc_ctrl = IAllocController::getInstance(); memalloc = alloc_ctrl->getAllocator(flags); return memalloc; } @@ -66,7 +65,7 @@ static int gralloc_map(gralloc_module_t const* module, if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) && !(hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER)) { size_t size = hnd->size; - sp memalloc = getAllocator(hnd->flags) ; + IMemAlloc* memalloc = getAllocator(hnd->flags) ; int err = memalloc->map_buffer(&mappedAddress, size, hnd->offset, hnd->fd); if(err) { @@ -98,7 +97,7 @@ static int gralloc_unmap(gralloc_module_t const* module, int err = -EINVAL; void* base = (void*)hnd->base; size_t size = hnd->size; - sp memalloc = getAllocator(hnd->flags) ; + IMemAlloc* memalloc = getAllocator(hnd->flags) ; if(memalloc != NULL) err = memalloc->unmap_buffer(base, size, hnd->offset); if (err) { @@ -284,7 +283,7 @@ int gralloc_unlock(gralloc_module_t const* module, if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) { int err; - sp memalloc = getAllocator(hnd->flags) ; + IMemAlloc* memalloc = getAllocator(hnd->flags) ; err = memalloc->clean_buffer((void*)hnd->base, hnd->size, hnd->offset, hnd->fd); ALOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x, flags = 0x%x) err=%s\n", @@ -328,25 +327,7 @@ int gralloc_perform(struct gralloc_module_t const* module, 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_UI_CONTIG_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->flags = private_handle_t::PRIV_FLAGS_USES_ION; hnd->size = size; hnd->offset = offset; hnd->base = intptr_t(base) + offset; diff --git a/libgralloc/memalloc.h b/libgralloc/memalloc.h index 349078d..af509fb 100644 --- a/libgralloc/memalloc.h +++ b/libgralloc/memalloc.h @@ -31,7 +31,6 @@ #define GRALLOC_MEMALLOC_H #include -#include namespace gralloc { @@ -47,7 +46,7 @@ struct alloc_data { int allocType; }; -class IMemAlloc : public android::RefBase { +class IMemAlloc { public: // Allocate buffer - fill in the alloc_data diff --git a/libgralloc/pmem_bestfit_alloc.cpp b/libgralloc/pmem_bestfit_alloc.cpp deleted file mode 100644 index 82302fa..0000000 --- a/libgralloc/pmem_bestfit_alloc.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * Copyright (c) 2011-2012, 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 "pmem_bestfit_alloc.h" - - -// align all the memory blocks on a cache-line boundary -const int SimpleBestFitAllocator::kMemoryAlign = 32; - -SimpleBestFitAllocator::SimpleBestFitAllocator() -: mHeapSize(0) -{ -} - -SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size) -: mHeapSize(0) -{ - setSize(size); -} - -SimpleBestFitAllocator::~SimpleBestFitAllocator() -{ - while(!mList.isEmpty()) { - delete mList.remove(mList.head()); - } -} - -ssize_t SimpleBestFitAllocator::setSize(size_t size) -{ - Locker::Autolock _l(mLock); - if (mHeapSize != 0) return -EINVAL; - size_t pagesize = getpagesize(); - mHeapSize = ((size + pagesize-1) & ~(pagesize-1)); - chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign); - mList.insertHead(node); - return size; -} - -size_t SimpleBestFitAllocator::size() const -{ - return mHeapSize; -} - -ssize_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags) -{ - Locker::Autolock _l(mLock); - if (mHeapSize == 0) return -EINVAL; - ssize_t offset = alloc(size, flags); - return offset; -} - -ssize_t SimpleBestFitAllocator::deallocate(size_t offset) -{ - Locker::Autolock _l(mLock); - if (mHeapSize == 0) return -EINVAL; - chunk_t const * const freed = dealloc(offset); - if (freed) { - return 0; - } - return -ENOENT; -} - -ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags) -{ - if (size == 0) { - return 0; - } - size = (size + kMemoryAlign-1) / kMemoryAlign; - chunk_t* free_chunk = 0; - chunk_t* cur = mList.head(); - - size_t pagesize = getpagesize(); - while (cur) { - int extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ; - - // best fit - if (cur->free && (cur->size >= (size+extra))) { - if ((!free_chunk) || (cur->size < free_chunk->size)) { - free_chunk = cur; - } - if (cur->size == size) { - break; - } - } - cur = cur->next; - } - - if (free_chunk) { - const size_t free_size = free_chunk->size; - free_chunk->free = 0; - free_chunk->size = size; - if (free_size > size) { - int extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ; - if (extra) { - chunk_t* split = new chunk_t(free_chunk->start, extra); - free_chunk->start += extra; - mList.insertBefore(free_chunk, split); - } - - ALOGE_IF(((free_chunk->start*kMemoryAlign)&(pagesize-1)), - "page is not aligned!!!"); - - const ssize_t tail_free = free_size - (size+extra); - if (tail_free > 0) { - chunk_t* split = new chunk_t( - free_chunk->start + free_chunk->size, tail_free); - mList.insertAfter(free_chunk, split); - } - } - return (free_chunk->start)*kMemoryAlign; - } - // we are out of PMEM. Print pmem stats - // check if there is any leak or fragmentation - - ALOGD (" Out of PMEM. Dumping PMEM stats for debugging"); - ALOGD (" ------------- PRINT PMEM STATS --------------"); - - cur = mList.head(); - static uint32_t node_count; - static uint64_t allocated, free_space; - - while (cur) { - ALOGD (" Node %d -> Start Address : %u Size %u Free info %d",\ - node_count++, cur->start, cur->size, cur->free); - - // if cur-> free is 1 , the node is free - // calculate the total allocated and total free stats also - - if (cur->free) - free_space += cur->size; - else - allocated += cur->size; - // read next node - cur = cur->next; - } - ALOGD (" Total Allocated: %l Total Free: %l", allocated, free_space ); - - node_count = 0; - allocated = 0; - free_space = 0; - ALOGD ("----------------------------------------------"); - return -ENOMEM; -} - -SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) -{ - start = start / kMemoryAlign; - chunk_t* cur = mList.head(); - while (cur) { - if (cur->start == start) { - LOG_FATAL_IF(cur->free, - "block at offset 0x%08lX of size 0x%08lX already freed", - cur->start*kMemoryAlign, cur->size*kMemoryAlign); - - // merge freed blocks together - chunk_t* freed = cur; - cur->free = 1; - do { - chunk_t* const p = cur->prev; - chunk_t* const n = cur->next; - if (p && (p->free || !cur->size)) { - freed = p; - p->size += cur->size; - mList.remove(cur); - delete cur; - } - cur = n; - } while (cur && cur->free); - - LOG_FATAL_IF(!freed->free, - "freed block at offset 0x%08lX of size 0x%08lX is not free!", - freed->start * kMemoryAlign, freed->size * kMemoryAlign); - - return freed; - } - cur = cur->next; - } - return 0; -} diff --git a/libgralloc/pmem_bestfit_alloc.h b/libgralloc/pmem_bestfit_alloc.h deleted file mode 100644 index 4346ec3..0000000 --- a/libgralloc/pmem_bestfit_alloc.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * Copyright (c) 2011-2012, 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_ALLOCATOR_H_ -#define GRALLOC_ALLOCATOR_H_ - -#include -#include - -#include "gr.h" -#include "pmemalloc.h" - -// ---------------------------------------------------------------------------- - -/* - * A simple templatized doubly linked-list implementation - */ -template -class LinkedList -{ - NODE* mFirst; - NODE* mLast; - - public: - LinkedList() : mFirst(0), mLast(0) { } - bool isEmpty() const { return mFirst == 0; } - NODE const* head() const { return mFirst; } - NODE* head() { return mFirst; } - NODE const* tail() const { return mLast; } - NODE* tail() { return mLast; } - - void insertAfter(NODE* node, NODE* newNode) { - newNode->prev = node; - newNode->next = node->next; - if (node->next == 0) mLast = newNode; - else node->next->prev = newNode; - node->next = newNode; - } - - void insertBefore(NODE* node, NODE* newNode) { - newNode->prev = node->prev; - newNode->next = node; - if (node->prev == 0) mFirst = newNode; - else node->prev->next = newNode; - node->prev = newNode; - } - - void insertHead(NODE* newNode) { - if (mFirst == 0) { - mFirst = mLast = newNode; - newNode->prev = newNode->next = 0; - } else { - newNode->prev = 0; - newNode->next = mFirst; - mFirst->prev = newNode; - mFirst = newNode; - } - } - - void insertTail(NODE* newNode) { - if (mLast == 0) { - insertHead(newNode); - } else { - newNode->prev = mLast; - newNode->next = 0; - mLast->next = newNode; - mLast = newNode; - } - } - - NODE* remove(NODE* node) { - if (node->prev == 0) mFirst = node->next; - else node->prev->next = node->next; - if (node->next == 0) mLast = node->prev; - else node->next->prev = node->prev; - return node; - } -}; - -class SimpleBestFitAllocator : public gralloc::PmemUserspaceAlloc::Allocator -{ - public: - - SimpleBestFitAllocator(); - SimpleBestFitAllocator(size_t size); - virtual ~SimpleBestFitAllocator(); - - virtual ssize_t setSize(size_t size); - - virtual ssize_t allocate(size_t size, uint32_t flags = 0); - virtual ssize_t deallocate(size_t offset); - virtual size_t size() const; - - private: - struct chunk_t { - chunk_t(size_t start, size_t size) - : start(start), size(size), free(1), prev(0), next(0) { - } - size_t start; - size_t size : 28; - int free : 4; - mutable chunk_t* prev; - mutable chunk_t* next; - }; - - ssize_t alloc(size_t size, uint32_t flags); - chunk_t* dealloc(size_t start); - - static const int kMemoryAlign; - mutable Locker mLock; - LinkedList mList; - size_t mHeapSize; -}; -#endif /* GRALLOC_ALLOCATOR_H_ */ diff --git a/libgralloc/pmemalloc.cpp b/libgralloc/pmemalloc.cpp deleted file mode 100644 index 0ac5c7b..0000000 --- a/libgralloc/pmemalloc.cpp +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (c) 2011-2012, 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 "gralloc_priv.h" -#include "pmemalloc.h" -#include "pmem_bestfit_alloc.h" - -using namespace gralloc; -using android::sp; - -// Common functions between userspace -// and kernel allocators -static int getPmemTotalSize(int fd, size_t* size) -{ - //XXX: 7x27 - int err = 0; - pmem_region region; - if (ioctl(fd, PMEM_GET_TOTAL_SIZE, ®ion)) { - err = -errno; - } else { - *size = region.len; - } - return err; -} - -static int getOpenFlags(bool uncached) -{ - if(uncached) - return O_RDWR | O_SYNC; - else - return O_RDWR; -} - -static int connectPmem(int fd, int master_fd) { - if (ioctl(fd, PMEM_CONNECT, master_fd)) - return -errno; - return 0; -} - -static int mapSubRegion(int fd, int offset, size_t size) { - struct pmem_region sub = { offset, size }; - if (ioctl(fd, PMEM_MAP, &sub)) - return -errno; - return 0; -} - -static int unmapSubRegion(int fd, int offset, size_t size) { - struct pmem_region sub = { offset, size }; - if (ioctl(fd, PMEM_UNMAP, &sub)) - return -errno; - return 0; -} - -static int alignPmem(int fd, size_t size, int align) { - struct pmem_allocation allocation; - allocation.size = size; - allocation.align = align; - if (ioctl(fd, PMEM_ALLOCATE_ALIGNED, &allocation)) - return -errno; - return 0; -} - -static int cleanPmem(void *base, size_t size, int offset, int fd) { - struct pmem_addr pmem_addr; - pmem_addr.vaddr = (unsigned long) base; - pmem_addr.offset = offset; - pmem_addr.length = size; - if (ioctl(fd, PMEM_CLEAN_INV_CACHES, &pmem_addr)) - return -errno; - return 0; -} - -//-------------- PmemUserspaceAlloc-----------------------// -PmemUserspaceAlloc::PmemUserspaceAlloc() -{ - mPmemDev = DEVICE_PMEM; - mMasterFd = FD_INIT; - mAllocator = new SimpleBestFitAllocator(); - pthread_mutex_init(&mLock, NULL); -} - -PmemUserspaceAlloc::~PmemUserspaceAlloc() -{ -} - -int PmemUserspaceAlloc::init_pmem_area_locked() -{ - ALOGD("%s: Opening master pmem FD", __FUNCTION__); - int err = 0; - int fd = open(mPmemDev, O_RDWR, 0); - if (fd >= 0) { - size_t size = 0; - err = getPmemTotalSize(fd, &size); - ALOGD("%s: Total pmem size: %d", __FUNCTION__, size); - if (err < 0) { - ALOGE("%s: PMEM_GET_TOTAL_SIZE failed (%d), limp mode", mPmemDev, - err); - size = 8<<20; // 8 MiB - } - mAllocator->setSize(size); - - void* base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, - 0); - if (base == MAP_FAILED) { - err = -errno; - ALOGE("%s: Failed to map pmem master fd: %s", mPmemDev, - strerror(errno)); - base = 0; - close(fd); - fd = -1; - } else { - mMasterFd = fd; - mMasterBase = base; - } - } else { - err = -errno; - ALOGE("%s: Failed to open pmem device: %s", mPmemDev, - strerror(errno)); - } - return err; -} - -int PmemUserspaceAlloc::init_pmem_area() -{ - pthread_mutex_lock(&mLock); - int err = mMasterFd; - if (err == FD_INIT) { - // first time, try to initialize pmem - ALOGD("%s: Initializing pmem area", __FUNCTION__); - err = init_pmem_area_locked(); - if (err) { - ALOGE("%s: failed to initialize pmem area", mPmemDev); - mMasterFd = err; - } - } else if (err < 0) { - // pmem couldn't be initialized, never use it - } else { - // pmem OK - err = 0; - } - pthread_mutex_unlock(&mLock); - return err; - -} - -int PmemUserspaceAlloc::alloc_buffer(alloc_data& data) -{ - int err = init_pmem_area(); - if (err == 0) { - void* base = mMasterBase; - size_t size = data.size; - int offset = mAllocator->allocate(size); - if (offset < 0) { - // no more pmem memory - ALOGE("%s: No more pmem available", mPmemDev); - err = -ENOMEM; - } else { - int openFlags = getOpenFlags(data.uncached); - - // now create the "sub-heap" - int fd = open(mPmemDev, openFlags, 0); - err = fd < 0 ? fd : 0; - - // and connect to it - if (err == 0) - err = connectPmem(fd, mMasterFd); - - // and make it available to the client process - if (err == 0) - err = mapSubRegion(fd, offset, size); - - if (err < 0) { - ALOGE("%s: Failed to initialize pmem sub-heap: %d", mPmemDev, - err); - close(fd); - mAllocator->deallocate(offset); - fd = -1; - } else { - ALOGV("%s: Allocated buffer base:%p size:%d offset:%d fd:%d", - mPmemDev, base, size, offset, fd); - memset((char*)base + offset, 0, size); - //Clean cache before flushing to ensure pmem is properly flushed - err = clean_buffer((void*)((intptr_t) base + offset), size, offset, fd); - if (err < 0) { - ALOGE("cleanPmem failed: (%s)", strerror(errno)); - } - cacheflush(intptr_t(base) + offset, intptr_t(base) + offset + size, 0); - data.base = base; - data.offset = offset; - data.fd = fd; - } - } - } - return err; - -} - -int PmemUserspaceAlloc::free_buffer(void* base, size_t size, int offset, int fd) -{ - ALOGV("%s: Freeing buffer base:%p size:%d offset:%d fd:%d", - mPmemDev, base, size, offset, fd); - int err = 0; - if (fd >= 0) { - int err = unmapSubRegion(fd, offset, size); - ALOGE_IF(err<0, "PMEM_UNMAP failed (%s), fd=%d, sub.offset=%u, " - "sub.size=%u", strerror(errno), fd, offset, size); - if (err == 0) { - // we can't deallocate the memory in case of UNMAP failure - // because it would give that process access to someone else's - // surfaces, which would be a security breach. - mAllocator->deallocate(offset); - } - close(fd); - } - return err; -} - -int PmemUserspaceAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) -{ - int err = 0; - size += offset; - void *base = mmap(0, size, PROT_READ| PROT_WRITE, - MAP_SHARED, fd, 0); - *pBase = base; - if(base == MAP_FAILED) { - err = -errno; - ALOGE("%s: Failed to map buffer size:%d offset:%d fd:%d Error: %s", - mPmemDev, size, offset, fd, strerror(errno)); - } else { - ALOGV("%s: Mapped buffer base:%p size:%d offset:%d fd:%d", - mPmemDev, base, size, offset, fd); - } - return err; - -} - -int PmemUserspaceAlloc::unmap_buffer(void *base, size_t size, int offset) -{ - int err = 0; - //pmem hack - base = (void*)(intptr_t(base) - offset); - size += offset; - ALOGV("%s: Unmapping buffer base:%p size:%d offset:%d", - mPmemDev , base, size, offset); - if (munmap(base, size) < 0) { - err = -errno; - ALOGE("%s: Failed to unmap memory at %p :%s", - mPmemDev, base, strerror(errno)); - - } - - return err; -} - -int PmemUserspaceAlloc::clean_buffer(void *base, size_t size, int offset, int fd) -{ - return cleanPmem(base, size, offset, fd); -} - - -//-------------- PmemKernelAlloc-----------------------// - -PmemKernelAlloc::PmemKernelAlloc(const char* pmemdev) : - mPmemDev(pmemdev) -{ -} - -PmemKernelAlloc::~PmemKernelAlloc() -{ -} - -int PmemKernelAlloc::alloc_buffer(alloc_data& data) -{ - int err, offset = 0; - int openFlags = getOpenFlags(data.uncached); - int size = data.size; - - int fd = open(mPmemDev, openFlags, 0); - if (fd < 0) { - err = -errno; - ALOGE("%s: Error opening %s", __FUNCTION__, mPmemDev); - return err; - } - - if (data.align == 8192) { - // Tile format buffers need physical alignment to 8K - // Default page size does not need this ioctl - err = alignPmem(fd, size, 8192); - if (err < 0) { - ALOGE("alignPmem failed"); - } - } - void* base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - if (base == MAP_FAILED) { - err = -errno; - ALOGE("%s: failed to map pmem fd: %s", mPmemDev, - strerror(errno)); - close(fd); - return err; - } - memset(base, 0, size); - clean_buffer((void*)((intptr_t) base + offset), size, offset, fd); - data.base = base; - data.offset = 0; - data.fd = fd; - ALOGV("%s: Allocated buffer base:%p size:%d fd:%d", - mPmemDev, base, size, fd); - return 0; - -} - -int PmemKernelAlloc::free_buffer(void* base, size_t size, int offset, int fd) -{ - ALOGV("%s: Freeing buffer base:%p size:%d fd:%d", - mPmemDev, base, size, fd); - - int err = unmap_buffer(base, size, offset); - close(fd); - return err; -} - -int PmemKernelAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) -{ - int err = 0; - void *base = mmap(0, size, PROT_READ| PROT_WRITE, - MAP_SHARED, fd, 0); - *pBase = base; - if(base == MAP_FAILED) { - err = -errno; - ALOGE("%s: Failed to map memory in the client: %s", - mPmemDev, strerror(errno)); - } else { - ALOGV("%s: Mapped buffer base:%p size:%d, fd:%d", - mPmemDev, base, size, fd); - } - return err; - -} - -int PmemKernelAlloc::unmap_buffer(void *base, size_t size, int offset) -{ - int err = 0; - if (munmap(base, size)) { - err = -errno; - ALOGW("%s: Error unmapping memory at %p: %s", - mPmemDev, base, strerror(err)); - } - return err; - -} -int PmemKernelAlloc::clean_buffer(void *base, size_t size, int offset, int fd) -{ - return cleanPmem(base, size, offset, fd); -} - diff --git a/libgralloc/pmemalloc.h b/libgralloc/pmemalloc.h deleted file mode 100644 index 82794ec..0000000 --- a/libgralloc/pmemalloc.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2011-2012, 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_PMEMALLOC_H -#define GRALLOC_PMEMALLOC_H - -#include -#include -#include "memalloc.h" - -namespace gralloc { -class PmemUserspaceAlloc : public IMemAlloc { - - public: - class Allocator: public android::RefBase { - public: - virtual ~Allocator() {}; - virtual ssize_t setSize(size_t size) = 0; - virtual size_t size() const = 0; - virtual ssize_t allocate(size_t size, uint32_t flags = 0) = 0; - virtual ssize_t deallocate(size_t offset) = 0; - }; - - 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); - - PmemUserspaceAlloc(); - - ~PmemUserspaceAlloc(); - - private: - int mMasterFd; - void* mMasterBase; - const char* mPmemDev; - android::sp mAllocator; - pthread_mutex_t mLock; - int init_pmem_area(); - int init_pmem_area_locked(); - -}; - -class PmemKernelAlloc : 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); - - PmemKernelAlloc(const char* device); - - ~PmemKernelAlloc(); - private: - const char* mPmemDev; - - -}; - -} -#endif /* GRALLOC_PMEMALLOC_H */ diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk index 5067a2a..51f1e00 100644 --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -9,7 +9,14 @@ LOCAL_SHARED_LIBRARIES := $(common_libs) libEGL liboverlay libgenlock \ libqdutils libhardware_legacy libdl libmemalloc LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"hwcomposer\" LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_SRC_FILES := hwc.cpp hwc_video.cpp hwc_utils.cpp \ - hwc_uimirror.cpp hwc_ext_observer.cpp \ - hwc_copybit.cpp +LOCAL_SRC_FILES := hwc.cpp \ + hwc_video.cpp \ + hwc_utils.cpp \ + hwc_uimirror.cpp \ + hwc_external.cpp \ + hwc_uevents.cpp \ + hwc_copybit.cpp \ + hwc_mdpcomp.cpp \ + hwc_extonly.cpp + include $(BUILD_SHARED_LIBRARY) diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp index 34972b7..1d7cf7b 100644 --- a/libhwcomposer/hwc.cpp +++ b/libhwcomposer/hwc.cpp @@ -20,11 +20,19 @@ #include #include +#include +#include +#include +#include #include "hwc_utils.h" +#include "hwc_qbuf.h" #include "hwc_video.h" #include "hwc_uimirror.h" #include "hwc_copybit.h" +#include "hwc_external.h" +#include "hwc_mdpcomp.h" +#include "hwc_extonly.h" using namespace qhwc; @@ -73,12 +81,22 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) ctx->qbuf->unlockAllPrevious(); if (LIKELY(list)) { + //reset for this draw round + VideoOverlay::reset(); + ExtOnly::reset(); + getLayerStats(ctx, list); + // Mark all layers to COPYBIT initially + CopyBit::prepare(ctx, list); if(VideoOverlay::prepare(ctx, list)) { ctx->overlayInUse = true; //Nothing here + } else if(ExtOnly::prepare(ctx, list)) { + ctx->overlayInUse = true; } else if(UIMirrorOverlay::prepare(ctx, list)) { ctx->overlayInUse = true; + } else if(MDPComp::configure(dev, list)) { + ctx->overlayInUse = true; } else if (0) { //Other features ctx->overlayInUse = true; @@ -86,12 +104,56 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) // fail in non-overlay targets. ctx->overlayInUse = false; } - CopyBit::prepare(ctx, list); } return 0; } +static int hwc_eventControl(struct hwc_composer_device* dev, + int event, int enabled) +{ + int ret = 0; + hwc_context_t* ctx = (hwc_context_t*)(dev); + private_module_t* m = reinterpret_cast( + ctx->mFbDev->common.module); + switch(event) { + case HWC_EVENT_VSYNC: + if(ioctl(m->framebuffer->fd, MSMFB_OVERLAY_VSYNC_CTRL, &enabled) < 0) + ret = -errno; + + if(ctx->mExtDisplay->getExternalDisplay()) { + ret = ctx->mExtDisplay->enableHDMIVsync(enabled); + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int hwc_query(struct hwc_composer_device* dev, + int param, int* value) +{ + hwc_context_t* ctx = (hwc_context_t*)(dev); + private_module_t* m = reinterpret_cast( + ctx->mFbDev->common.module); + + switch (param) { + case HWC_BACKGROUND_LAYER_SUPPORTED: + // Not supported for now + value[0] = 0; + break; + case HWC_VSYNC_PERIOD: + value[0] = 1000000000.0 / m->fps; + ALOGI("fps: %d", value[0]); + break; + default: + return -EINVAL; + } + return 0; + +} + static int hwc_set(hwc_composer_device_t *dev, hwc_display_t dpy, hwc_surface_t sur, @@ -101,9 +163,13 @@ static int hwc_set(hwc_composer_device_t *dev, hwc_context_t* ctx = (hwc_context_t*)(dev); if (LIKELY(list)) { VideoOverlay::draw(ctx, list); + ExtOnly::draw(ctx, list); CopyBit::draw(ctx, list, (EGLDisplay)dpy, (EGLSurface)sur); + MDPComp::draw(ctx, list); EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); UIMirrorOverlay::draw(ctx); + if(ctx->mExtDisplay->getExternalDisplay()) + ctx->mExtDisplay->commit(); } else { ctx->mOverlay->setState(ovutils::OV_CLOSED); ctx->qbuf->unlockAllPrevious(); @@ -118,7 +184,7 @@ static int hwc_set(hwc_composer_device_t *dev, static int hwc_device_close(struct hw_device_t *dev) { if(!dev) { - ALOGE("hwc_device_close null device pointer"); + ALOGE("%s: NULL device pointer", __FUNCTION__); return -1; } closeContext((hwc_context_t*)dev); @@ -136,14 +202,30 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name, struct hwc_context_t *dev; dev = (hwc_context_t*)malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); + + //Initialize hwc context initContext(dev); + + //Setup HWC methods + hwc_methods_t *methods; + methods = (hwc_methods_t *)malloc(sizeof(*methods)); + memset(methods, 0, sizeof(*methods)); + methods->eventControl = hwc_eventControl; + dev->device.common.tag = HARDWARE_DEVICE_TAG; - dev->device.common.version = 0; + //XXX: This disables hardware vsync on 7x27A, 8x25 and 8x55 + // Fix when HW vsync is available on those targets + if(dev->mMDP.version < 410) + dev->device.common.version = 0; + else + dev->device.common.version = HWC_DEVICE_API_VERSION_0_3; 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.registerProcs = hwc_registerProcs; + dev->device.query = hwc_query; + dev->device.methods = methods; *device = &dev->device.common; status = 0; } diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp index 1267f42..1ca77b9 100644 --- a/libhwcomposer/hwc_copybit.cpp +++ b/libhwcomposer/hwc_copybit.cpp @@ -18,8 +18,12 @@ * limitations under the License. */ +#define DEBUG_COPYBIT 0 +#include +#include #include "hwc_copybit.h" -#include "hwc_copybitEngine.h" +#include "hwc_copybit.h" +#include "comptype.h" namespace qhwc { @@ -71,6 +75,23 @@ bool CopyBit::sIsModeOn = false; bool CopyBit::sIsLayerSkip = false; void* CopyBit::egl_lib = NULL; +void CopyBit::openEglLibAndGethandle() +{ + egl_lib = ::dlopen("libEGL_adreno200.so", RTLD_GLOBAL | RTLD_LAZY); + if (!egl_lib) { + return; + } + updateEglHandles(egl_lib); +} +void CopyBit::closeEglLib() +{ + if(egl_lib) + ::dlclose(egl_lib); + + egl_lib = NULL; + updateEglHandles(NULL); +} + void CopyBit::updateEglHandles(void* egl_lib) { if(egl_lib != NULL) { @@ -84,32 +105,124 @@ void CopyBit::updateEglHandles(void* egl_lib) } } -bool CopyBit::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { - for (int i=list->numHwLayers-1; i >= 0 ; i--) { - private_handle_t *hnd = - (private_handle_t *)list->hwLayers[i].handle; - if (isSkipLayer(&list->hwLayers[i])) { - break; - } else if(canUseCopybit(ctx, list, getYuvCount()) - && !ctx->overlayInUse){ - list->hwLayers[i].compositionType = HWC_USE_COPYBIT; - } else { - list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; - } +bool CopyBit::canUseCopybitForYUV(hwc_context_t *ctx) { + // return true for non-overlay targets + if(ctx->mMDP.hasOverlay) { + return false; } return true; } + +bool CopyBit::canUseCopybitForRGB(hwc_context_t *ctx, hwc_layer_list_t *list) { + int compositionType = + qdutils::QCCompositionType::getInstance().getCompositionType(); + + if ((compositionType & qdutils::COMPOSITION_TYPE_C2D) || + (compositionType & qdutils::COMPOSITION_TYPE_DYN)) { + if (sYuvCount) { + //Overlay up & running. Dont use COPYBIT for RGB layers. + // TODO need to implement blending with C2D + return false; + } + } + + if (compositionType & qdutils::COMPOSITION_TYPE_DYN) { + // DYN Composition: + // use copybit, if (TotalRGBRenderArea < 2 * FB Area) + // this is done based on perf inputs in ICS + // TODO: Above condition needs to be re-evaluated in JB + + framebuffer_device_t *fbDev = ctx->mFbDev; + if (!fbDev) { + ALOGE("%s:Invalid FB device", __FUNCTION__); + return false; + } + unsigned int fbArea = (fbDev->width * fbDev->height); + unsigned int renderArea = getRGBRenderingArea(list); + ALOGD_IF (DEBUG_COPYBIT, "%s:renderArea %u, fbArea %u", + __FUNCTION__, renderArea, fbArea); + if (renderArea < (2 * fbArea)) { + return true; + } + } else if ((compositionType & qdutils::COMPOSITION_TYPE_MDP)) { + // MDP composition, use COPYBIT always + return true; + } else if ((compositionType & qdutils::COMPOSITION_TYPE_C2D)) { + // C2D composition, use COPYBIT + return true; + } + return false; +} + +unsigned int CopyBit::getRGBRenderingArea(const hwc_layer_list_t *list) { + //Calculates total rendering area for RGB layers + unsigned int renderArea = 0; + unsigned int w=0, h=0; + for (unsigned int i=0; inumHwLayers; i++) { + private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; + if (hnd) { + if (BUFFER_TYPE_UI == hnd->bufferType) { + getLayerResolution(&list->hwLayers[i], w, h); + renderArea += (w*h); + } + } + } + return renderArea; +} + +bool CopyBit::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { + + int compositionType = + qdutils::QCCompositionType::getInstance().getCompositionType(); + + if ((compositionType & qdutils::COMPOSITION_TYPE_GPU) || + (compositionType & qdutils::COMPOSITION_TYPE_CPU)) { + //GPU/CPU composition, don't change layer composition type + return true; + } + + bool useCopybitForYUV = canUseCopybitForYUV(ctx); + bool useCopybitForRGB = canUseCopybitForRGB(ctx, list); + + if(!(validateParams(ctx, list))) { + ALOGE("%s:Invalid Params", __FUNCTION__); + return false; + } + + for (int i=list->numHwLayers-1; i >= 0 ; i--) { + private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; + + if (isSkipLayer(&list->hwLayers[i])) { + return true; + } else if (hnd->bufferType == BUFFER_TYPE_VIDEO) { + //YUV layer, check, if copybit can be used + if (useCopybitForYUV) { + list->hwLayers[i].compositionType = HWC_USE_COPYBIT; + } + } else if (hnd->bufferType == BUFFER_TYPE_UI) { + //RGB layer, check, if copybit can be used + if (useCopybitForRGB) { + list->hwLayers[i].compositionType = HWC_USE_COPYBIT; + } + } + } + return true; +} + bool CopyBit::draw(hwc_context_t *ctx, hwc_layer_list_t *list, EGLDisplay dpy, - EGLSurface sur){ + EGLSurface sur){ + // draw layers marked for COPYBIT + int retVal = true; for (size_t i=0; inumHwLayers; i++) { - if (list->hwLayers[i].flags & HWC_SKIP_LAYER) { - continue; - } else if (list->hwLayers[i].compositionType == HWC_USE_COPYBIT) { - drawLayerUsingCopybit(ctx, &(list->hwLayers[i]), - (EGLDisplay)dpy, - (EGLSurface)sur, - LINK_eglGetRenderBufferANDROID, - LINK_eglGetCurrentSurface); + if (list->hwLayers[i].compositionType == HWC_USE_COPYBIT) { + retVal = drawLayerUsingCopybit(ctx, &(list->hwLayers[i]), + (EGLDisplay)dpy, + (EGLSurface)sur, + LINK_eglGetRenderBufferANDROID, + LINK_eglGetCurrentSurface); + if(retVal<0) { + ALOGE("%s : drawLayerUsingCopybit failed", __FUNCTION__); + } } } return true; @@ -290,9 +403,8 @@ int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_t *layer, hwc_region_t tmp_hwc_reg = {1,(hwc_rect_t const*)&tmp_hwc_rect}; region_iterator tmp_it(tmp_hwc_reg); copybit->set_parameter(copybit,COPYBIT_TRANSFORM,0); - // TODO : alpha not defined , fix this - // copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, - // (layer->blending == HWC_BLENDING_NONE) ? -1 : layer->alpha); + //TODO: once, we are able to read layer alpha, update this + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255); err = copybit->stretch(copybit,&tmp_dst, &src, &tmp_rect, &srcRect, &tmp_it); if(err < 0){ @@ -318,9 +430,8 @@ int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_t *layer, renderBuffer->height); copybit->set_parameter(copybit, COPYBIT_TRANSFORM, layer->transform); - // TODO : alpha not defined , fix this - // copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, - // (layer->blending == HWC_BLENDING_NONE) ? -1 : layer->alpha); + //TODO: once, we are able to read layer alpha, update this + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255); copybit->set_parameter(copybit, COPYBIT_PREMULTIPLIED_ALPHA, (layer->blending == HWC_BLENDING_PREMULT)? COPYBIT_ENABLE : COPYBIT_DISABLE); @@ -349,8 +460,8 @@ int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_t *layer, return err; } -void CopyBit::getLayerResolution(const hwc_layer_t* layer, int& width, - int& height) +void CopyBit::getLayerResolution(const hwc_layer_t* layer, + unsigned int& width, unsigned int& height) { hwc_rect_t displayFrame = layer->displayFrame; @@ -358,72 +469,34 @@ void CopyBit::getLayerResolution(const hwc_layer_t* layer, int& width, height = displayFrame.bottom - displayFrame.top; } -bool CopyBit::canUseCopybit(hwc_context_t *ctx, const hwc_layer_list_t* list, - const int numYUVBuffers) -{ - // XXX : TODO , currently returning false for MDP4 targets, - // This has to be modified after adding C2D support. - if(ctx->hasOverlay) - return false; +bool CopyBit::validateParams(hwc_context_t *ctx, const hwc_layer_list_t *list) { + //Validate parameters + if (!ctx) { + ALOGE("%s:Invalid HWC context", __FUNCTION__); + return false; + } else if (!list) { + ALOGE("%s:Invalid HWC layer list", __FUNCTION__); + return false; + } - framebuffer_device_t* fbDev = ctx->mFbDevice->getFb(); - if(!fbDev) { - ALOGE("ERROR: canUseCopybit : fb device is invalid"); - return false; - } + framebuffer_device_t *fbDev = ctx->mFbDev; - if (!list) - return false; + if (!fbDev) { + ALOGE("%s:Invalid FB device", __FUNCTION__); + return false; + } - // If , couldnt link to adreno library return false. - if(LINK_eglGetRenderBufferANDROID == NULL || - LINK_eglGetCurrentSurface == NULL ) - return false; + if (LINK_eglGetRenderBufferANDROID == NULL || + LINK_eglGetCurrentSurface == NULL) { + ALOGE("%s:Not able to link to ADRENO", __FUNCTION__); + return false; + } - if(!ctx->hasOverlay) { - if (numYUVBuffers) - return true; - } - - int fb_w = fbDev->width; - int fb_h = fbDev->height; - - /* - * Use copybit only when we need to blit - * max 2 full screen sized regions - */ - - unsigned int renderArea = 0; - - for(unsigned int i = 0; i < list->numHwLayers; i++ ) { - int w, h; - getLayerResolution(&list->hwLayers[i], w, h); - renderArea += w*h; - } - - return (renderArea <= (2 * fb_w * fb_h)); + return true; } -void CopyBit::openEglLibAndGethandle() -{ - egl_lib = ::dlopen("libEGL_adreno200.so", RTLD_GLOBAL | RTLD_LAZY); - if (!egl_lib) { - return; - } - updateEglHandles(egl_lib); -} -void CopyBit::closeEglLib() -{ - if(egl_lib) - ::dlclose(egl_lib); - - egl_lib = NULL; - updateEglHandles(NULL); -} - - //CopybitEngine Class functions -CopybitEngine* CopybitEngine::sInstance = 0;; +CopybitEngine* CopybitEngine::sInstance = 0; struct copybit_device_t* CopybitEngine::getEngine() { return sEngine; @@ -441,9 +514,11 @@ CopybitEngine::CopybitEngine(){ } else { ALOGE("FATAL ERROR: copybit open failed."); } + CopyBit::openEglLibAndGethandle(); } CopybitEngine::~CopybitEngine() { + CopyBit::closeEglLib(); if(sEngine) { copybit_close(sEngine); diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h index adf088b..8390968 100644 --- a/libhwcomposer/hwc_copybit.h +++ b/libhwcomposer/hwc_copybit.h @@ -31,6 +31,11 @@ namespace qhwc { //Feature for using Copybit to display RGB layers. +typedef EGLClientBuffer (*functype_eglGetRenderBufferANDROID) ( + EGLDisplay dpy, + EGLSurface draw); +typedef EGLSurface (*functype_eglGetCurrentSurface)(EGLint readdraw); + class CopyBit { public: //Sets up members and prepares copybit if conditions are met @@ -46,8 +51,11 @@ public: EGLDisplay dpy, EGLSurface surface, functype_eglGetRenderBufferANDROID& LINK_eglGetRenderBufferANDROID, functype_eglGetCurrentSurface LINK_eglGetCurrentSurface); - static bool canUseCopybit(hwc_context_t* ctx, const hwc_layer_list_t* list, - const int numYUVBuffers); + static bool canUseCopybitForYUV (hwc_context_t *ctx); + static bool canUseCopybitForRGB (hwc_context_t *ctx, + hwc_layer_list_t *list); + static bool validateParams (hwc_context_t *ctx, + const hwc_layer_list_t *list); static void closeEglLib(); static void openEglLibAndGethandle(); private: @@ -70,11 +78,26 @@ private: static functype_eglGetRenderBufferANDROID LINK_eglGetRenderBufferANDROID; static functype_eglGetCurrentSurface LINK_eglGetCurrentSurface; - static void getLayerResolution(const hwc_layer_t* layer, int& width, - int& height); + static unsigned int getRGBRenderingArea (const hwc_layer_list_t *list); + static void getLayerResolution(const hwc_layer_t* layer, + unsigned int &width, unsigned int& height); }; +class CopybitEngine { +public: + ~CopybitEngine(); + // API to get copybit engine(non static) + struct copybit_device_t *getEngine(); + // API to get singleton + static CopybitEngine* getInstance(); +private: + CopybitEngine(); + struct copybit_device_t *sEngine; + static CopybitEngine* sInstance; // singleton +}; + + inline void CopyBit::setStats(int yuvCount, int yuvLayerIndex, bool isYuvLayerSkip) { sYuvCount = yuvCount; diff --git a/libhwcomposer/hwc_copybitEngine.h b/libhwcomposer/hwc_copybitEngine.h deleted file mode 100644 index d627e44..0000000 --- a/libhwcomposer/hwc_copybitEngine.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012, Code Aurora Forum. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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 HWC_COPYBIT_ENGINE_H -#define HWC_COPYBIT_ENGINE_H - -namespace qhwc { -class CopybitEngine { -public: - ~CopybitEngine(); - // API to get copybit engine(non static) - struct copybit_device_t *getEngine(); - // API to get singleton - static CopybitEngine* getInstance(); - -private: - CopybitEngine(); - struct copybit_device_t *sEngine; - static CopybitEngine* sInstance; // singleton -}; - -}; //namespace qhwc - -#endif //HWC_COPYBIT_ENGINE_H diff --git a/libhwcomposer/hwc_ext_observer.cpp b/libhwcomposer/hwc_external.cpp similarity index 55% rename from libhwcomposer/hwc_ext_observer.cpp rename to libhwcomposer/hwc_external.cpp index cfe4c74..b5e1e89 100644 --- a/libhwcomposer/hwc_ext_observer.cpp +++ b/libhwcomposer/hwc_external.cpp @@ -18,9 +18,9 @@ * limitations under the License. */ +#define DEBUG 0 #include -#include -#include +#include #include #include #include @@ -31,104 +31,32 @@ #include #include #include - -#include +#include #include #include "hwc_utils.h" -#include "hwc_ext_observer.h" +#include "hwc_external.h" namespace qhwc { -#define EXT_OBSERVER_DEBUG 0 #define DEVICE_ROOT "/sys/devices/virtual/graphics" #define DEVICE_NODE "fb1" -#define SYSFS_CONNECTED DEVICE_ROOT "/" DEVICE_NODE "/connected" #define SYSFS_EDID_MODES DEVICE_ROOT "/" DEVICE_NODE "/edid_modes" #define SYSFS_HPD DEVICE_ROOT "/" DEVICE_NODE "/hpd" -android::sp ExtDisplayObserver:: - sExtDisplayObserverInstance(0); - -ExtDisplayObserver::ExtDisplayObserver() : Thread(false), - fd(-1), mCurrentID(-1), mHwcContext(NULL) +ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1), + mCurrentMode(-1), mHwcContext(ctx) { + memset(&mVInfo, 0, sizeof(mVInfo)); //Enable HPD for HDMI writeHPDOption(1); } -ExtDisplayObserver::~ExtDisplayObserver() { - if (fd > 0) - close(fd); -} - -ExtDisplayObserver *ExtDisplayObserver::getInstance() { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s ", __FUNCTION__); - if(sExtDisplayObserverInstance.get() == NULL) - sExtDisplayObserverInstance = new ExtDisplayObserver(); - return sExtDisplayObserverInstance.get(); -} - -void ExtDisplayObserver::setHwcContext(hwc_context_t* hwcCtx) { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s", __FUNCTION__); - if(hwcCtx) { - mHwcContext = hwcCtx; - } - return; -} -void ExtDisplayObserver::onFirstRef() { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s", __FUNCTION__); - run("ExtDisplayObserver", ANDROID_PRIORITY_DISPLAY); -} - -int ExtDisplayObserver::readyToRun() { - //Initialize the uevent - uevent_init(); - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: success", __FUNCTION__); - return android::NO_ERROR; -} - -void ExtDisplayObserver::handleUEvent(char* str){ - int connected = 0; - // TODO: check for fb2(WFD) driver also - if(!strcasestr(str, DEVICE_NODE)) - { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__); - return; - } - // Event will be of the form: - // change@/devices/virtual/graphics/fb1 ACTION=change - // DEVPATH=/devices/virtual/graphics/fb1 - // SUBSYSTEM=graphics HDCP_STATE=FAIL MAJOR=29 - // for now just parse the online or offline are important for us. - if(!(strncmp(str,"online@",strlen("online@")))) { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: external disp online", __FUNCTION__); - connected = 1; - readResolution(); - //Get the best mode and set - // TODO: DO NOT call this for WFD - setResolution(getBestMode()); - } else if(!(strncmp(str,"offline@",strlen("offline@")))) { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: external disp online", __FUNCTION__); - connected = 0; - close(fd); - } - setExternalDisplayStatus(connected); -} - -bool ExtDisplayObserver::threadLoop() +ExternalDisplay::~ExternalDisplay() { - static char uEventString[1024]; - memset(uEventString, 0, sizeof(uEventString)); - int count = uevent_next_event(uEventString, sizeof(uEventString)); - if(count) { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: UeventString: %s len = %d", - __FUNCTION__, uEventString, count); - handleUEvent(uEventString); - } - return true; + closeFrameBuffer(); } struct disp_mode_timing_type { @@ -213,7 +141,8 @@ static struct disp_mode_timing_type supported_video_mode_lut[] = { {m1920x1080p25_16_9, 1920, 1080, 528, 44, 148, 4, 5, 36, 74250, false}, {m1920x1080p30_16_9, 1920, 1080, 88, 44, 148, 4, 5, 36, 74250, false}, }; -int ExtDisplayObserver::parseResolution(char* edidStr, int* edidModes, int len) + +int ExternalDisplay::parseResolution(char* edidStr, int* edidModes) { char delim = ','; int count = 0; @@ -222,36 +151,34 @@ int ExtDisplayObserver::parseResolution(char* edidStr, int* edidModes, int len) // Ex: 16,4,5,3,32,34,1 // Parse this string to get mode(int) start = (char*) edidStr; - for(int i=0; i 1 && isspace(mEDIDs[len-1])) @@ -262,27 +189,45 @@ bool ExtDisplayObserver::readResolution() close(hdmiEDIDFile); if(len > 0) { // GEt EDID modes from the EDID strings - mModeCount = parseResolution(mEDIDs, mEDIDModes, len); - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: mModeCount = %d", __FUNCTION__, - mModeCount); + mModeCount = parseResolution(mEDIDs, mEDIDModes); + ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__, + mModeCount); } return (strlen(mEDIDs) > 0); } -bool ExtDisplayObserver::openFramebuffer() +bool ExternalDisplay::openFramebuffer() { - if (fd == -1) { - fd = open("/dev/graphics/fb1", O_RDWR); - if (fd < 0) - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: /dev/graphics/fb1 not available" - "\n", __FUNCTION__); + if (mFd == -1) { + mFd = open("/dev/graphics/fb1", O_RDWR); + if (mFd < 0) + ALOGE("%s: /dev/graphics/fb1 not available", __FUNCTION__); } - return (fd > 0); + return (mFd > 0); } +bool ExternalDisplay::closeFrameBuffer() +{ + int ret = 0; + if(mFd > 0) { + ret = close(mFd); + mFd = -1; + } + return (ret == 0); +} -int ExtDisplayObserver::getModeOrder(int mode) +// clears the vinfo, edid, best modes +void ExternalDisplay::resetInfo() +{ + memset(&mVInfo, 0, sizeof(mVInfo)); + memset(mEDIDs, 0, sizeof(mEDIDs)); + memset(mEDIDModes, 0, sizeof(mEDIDModes)); + mModeCount = 0; + mCurrentMode = -1; +} + +int ExternalDisplay::getModeOrder(int mode) { switch (mode) { default: @@ -320,11 +265,11 @@ int ExtDisplayObserver::getModeOrder(int mode) return 16; //1080p@50Hz case m1920x1080p60_16_9: return 17; //1080p@60Hz - } + } } // Get the best mode for the current HD TV -int ExtDisplayObserver::getBestMode() { +int ExternalDisplay::getBestMode() { int bestOrder = 0; int bestMode = m640x480p60_4_3; @@ -338,108 +283,172 @@ int ExtDisplayObserver::getBestMode() { } } return bestMode; - } +} -inline bool ExtDisplayObserver::isValidMode(int ID) +inline bool ExternalDisplay::isValidMode(int ID) { return ((ID >= m640x480p60_4_3) && (ID <= m1920x1080p30_16_9)); } -void ExtDisplayObserver::setResolution(int ID) +void ExternalDisplay::setResolution(int ID) { struct fb_var_screeninfo info; + int ret = 0; if (!openFramebuffer()) return; + ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); + if(ret < 0) { + ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, + strerror(errno)); + } + + ALOGD_IF(DEBUG, "%s: GET Info", __FUNCTION__, + mVInfo.reserved[3], mVInfo.xres, mVInfo.yres, + mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, + mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, + mVInfo.pixclock/1000/1000); //If its a valid mode and its a new ID - update var_screeninfo - if ((isValidMode(ID)) && mCurrentID != ID) { + if ((isValidMode(ID)) && mCurrentMode != ID) { const struct disp_mode_timing_type *mode = - &supported_video_mode_lut[0]; + &supported_video_mode_lut[0]; unsigned count = sizeof(supported_video_mode_lut)/sizeof - (*supported_video_mode_lut); + (*supported_video_mode_lut); for (unsigned int i = 0; i < count; ++i) { const struct disp_mode_timing_type *cur = - &supported_video_mode_lut[i]; + &supported_video_mode_lut[i]; if (cur->video_format == ID) mode = cur; } - ioctl(fd, FBIOGET_VSCREENINFO, &info); - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: GET Info", __FUNCTION__, - info.reserved[3], info.xres, info.yres, - info.right_margin, info.hsync_len, info.left_margin, - info.lower_margin, info.vsync_len, info.upper_margin, - info.pixclock/1000/1000); - mode->set_info(info); - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: SET Info Info", __FUNCTION__, ID, - info.reserved[3], info.xres, info.yres, - info.right_margin, info.hsync_len, info.left_margin, - info.lower_margin, info.vsync_len, info.upper_margin, - info.pixclock/1000/1000); - info.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE; - ioctl(fd, FBIOPUT_VSCREENINFO, &info); - mCurrentID = ID; + mode->set_info(mVInfo); + ALOGD_IF(DEBUG, "%s: SET Info Info", __FUNCTION__, ID, + mVInfo.reserved[3], mVInfo.xres, mVInfo.yres, + mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, + mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, + mVInfo.pixclock/1000/1000); + mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE; + ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo); + if(ret < 0) { + ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s", + __FUNCTION__, strerror(errno)); + } + mCurrentMode = ID; } //Powerup - ioctl(fd, FBIOBLANK, FB_BLANK_UNBLANK); - ioctl(fd, FBIOGET_VSCREENINFO, &info); + ret = ioctl(mFd, FBIOBLANK, FB_BLANK_UNBLANK); + if(ret < 0) { + ALOGD("In %s: FBIOBLANK failed Err Str = %s", __FUNCTION__, + strerror(errno)); + } + ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); + if(ret < 0) { + ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, + strerror(errno)); + } //Pan_Display - ioctl(fd, FBIOPAN_DISPLAY, &info); - property_set("hw.hdmiON", "1"); + ret = ioctl(mFd, FBIOPAN_DISPLAY, &mVInfo); + if(ret < 0) { + ALOGD("In %s: FBIOPAN_DISPLAY failed Err Str = %s", __FUNCTION__, + strerror(errno)); + } } -int ExtDisplayObserver::getExternalDisplay() const +int ExternalDisplay::getExternalDisplay() const { - return mExternalDisplay; + return mExternalDisplay; } -void ExtDisplayObserver::setExternalDisplayStatus(int connected) +void ExternalDisplay::setExternalDisplay(int connected) { hwc_context_t* ctx = mHwcContext; if(ctx) { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: status = %d", __FUNCTION__, - connected); + ALOGD_IF(DEBUG, "%s: status = %d", __FUNCTION__, + connected); + if(connected) { + readResolution(); + //Get the best mode and set + // TODO: DO NOT call this for WFD + setResolution(getBestMode()); + //enable hdmi vsync + enableHDMIVsync(connected); + } else { + // Disable the hdmi vsync + enableHDMIVsync(connected); + closeFrameBuffer(); + resetInfo(); + } // Store the external display - mExternalDisplay = connected;//(external_display_type)value; + mExternalDisplay = connected; + const char* prop = (connected) ? "1" : "0"; + // set system property + property_set("hw.hdmiON", prop); //Invalidate hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; if(!proc) { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: HWC proc not registered", - __FUNCTION__); + ALOGE("%s: HWC proc not registered", + __FUNCTION__); } else { /* Trigger redraw */ - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: Invalidate !!", __FUNCTION__); + ALOGD_IF(DEBUG, "%s: Invalidate !!", __FUNCTION__); proc->invalidate(proc); } } return; } -bool ExtDisplayObserver::writeHPDOption(int userOption) const +bool ExternalDisplay::writeHPDOption(int userOption) const { bool ret = true; int hdmiHPDFile = open(SYSFS_HPD,O_RDWR, 0); if (hdmiHPDFile < 0) { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: state file '%s' not found : ret%d" - "err str: %s", __FUNCTION__, SYSFS_HPD, hdmiHPDFile, strerror(errno)); + ALOGE("%s: state file '%s' not found : ret%d" + "err str: %s", __FUNCTION__, SYSFS_HPD, hdmiHPDFile, + strerror(errno)); ret = false; } else { int err = -1; - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: option = %d", __FUNCTION__, - userOption); + ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, + userOption); if(userOption) err = write(hdmiHPDFile, "1", 2); else err = write(hdmiHPDFile, "0" , 2); if (err <= 0) { - ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: file write failed '%s'", - __FUNCTION__, SYSFS_HPD); + ALOGE("%s: file write failed '%s'", + __FUNCTION__, SYSFS_HPD); ret = false; } close(hdmiHPDFile); } return ret; } + +bool ExternalDisplay::commit() +{ + if(mFd == -1) { + return false; + } else if(ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo) == -1) { + ALOGE("%s: FBIOPUT_VSCREENINFO failed, str: %s", __FUNCTION__, + strerror(errno)); + return false; + } + return true; +} + +int ExternalDisplay::enableHDMIVsync(int enable) +{ + if(mFd > 0) { + int ret = ioctl(mFd, MSMFB_OVERLAY_VSYNC_CTRL, &enable); + if (ret<0) { + ALOGE("%s: enabling HDMI vsync failed, str: %s", __FUNCTION__, + strerror(errno)); + } + } + return -errno; +} + }; + diff --git a/libhwcomposer/hwc_ext_observer.h b/libhwcomposer/hwc_external.h similarity index 51% rename from libhwcomposer/hwc_ext_observer.h rename to libhwcomposer/hwc_external.h index e7cb890..55773c0 100644 --- a/libhwcomposer/hwc_ext_observer.h +++ b/libhwcomposer/hwc_external.h @@ -18,16 +18,16 @@ * limitations under the License. */ -#ifndef HWC_EXT_OBSERVER_H -#define HWC_EXT_OBSERVER_H +#ifndef HWC_EXTERNAL_DISPLAY_H +#define HWC_EXTERNAL_DISPLAY_H -#include +#include struct hwc_context_t; namespace qhwc { -class ExtDisplayObserver : public android::Thread +class ExternalDisplay { //Type of external display - OFF, HDMI, WFD enum external_display_type { @@ -42,39 +42,36 @@ class ExtDisplayObserver : public android::Thread EXT_MIRRORING_ON, }; public: - /*Overrides*/ - virtual bool threadLoop(); - virtual int readyToRun(); - virtual void onFirstRef(); - - virtual ~ExtDisplayObserver(); - static ExtDisplayObserver *getInstance(); - int getExternalDisplay() const; - void setHwcContext(hwc_context_t* hwcCtx); + ExternalDisplay(hwc_context_t* ctx); + ~ExternalDisplay(); + int getExternalDisplay() const; + void setExternalDisplay(int connected); + bool commit(); + int enableHDMIVsync(int enable); private: - ExtDisplayObserver(); - void setExternalDisplayStatus(int connected); - bool readResolution(); - int parseResolution(char* edidStr, int* edidModes, int len); - void setResolution(int ID); - bool openFramebuffer(); - bool writeHPDOption(int userOption) const; - bool isValidMode(int ID); - void handleUEvent(char* str); - int getModeOrder(int mode); - int getBestMode(); + bool readResolution(); + int parseResolution(char* edidStr, int* edidModes); + void setResolution(int ID); + bool openFramebuffer(); + bool closeFrameBuffer(); + bool writeHPDOption(int userOption) const; + bool isValidMode(int ID); + void handleUEvent(char* str, int len); + int getModeOrder(int mode); + int getBestMode(); + void resetInfo(); - int fd; - int mExternalDisplay; - int mCurrentID; - char mEDIDs[128]; - int mEDIDModes[64]; - int mModeCount; - hwc_context_t *mHwcContext; - static android::sp sExtDisplayObserverInstance; + int mFd; + int mExternalDisplay; + int mCurrentMode; + char mEDIDs[128]; + int mEDIDModes[64]; + int mModeCount; + hwc_context_t *mHwcContext; + fb_var_screeninfo mVInfo; }; }; //qhwc // --------------------------------------------------------------------------- -#endif //HWC_EXT_OBSERVER_H +#endif //HWC_EXTERNAL_DISPLAY_H diff --git a/libhwcomposer/hwc_extonly.cpp b/libhwcomposer/hwc_extonly.cpp new file mode 100644 index 0000000..6793760 --- /dev/null +++ b/libhwcomposer/hwc_extonly.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, 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 "hwc_extonly.h" +#include "hwc_external.h" +#include "hwc_qbuf.h" + +namespace qhwc { + +#define EXTONLY_DEBUG 0 + +//Static Members +ovutils::eOverlayState ExtOnly::sState = ovutils::OV_CLOSED; +int ExtOnly::sExtCount = 0; +int ExtOnly::sExtIndex = -1; +bool ExtOnly::sIsExtBlock = false; +bool ExtOnly::sIsModeOn = false; + +//Cache stats, figure out the state, config overlay +bool ExtOnly::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { + sIsModeOn = false; + if(!ctx->mMDP.hasOverlay) { + ALOGD_IF(EXTONLY_DEBUG,"%s, this hw doesnt support overlay", + __FUNCTION__); + return false; + } + if(sExtIndex == -1) { + return false; + } + chooseState(ctx); + //if the state chosen above is CLOSED, skip this block. + if(sState != ovutils::OV_CLOSED) { + hwc_layer_t *extLayer = &list->hwLayers[sExtIndex]; + if(configure(ctx, extLayer)) { + markFlags(extLayer); + sIsModeOn = true; + } + } + + ALOGD_IF(EXTONLY_DEBUG, "%s: stats: extCount = %d, extIndex = %d," + "IsExtBlock = %d, IsModeOn = %d", + __func__, sExtCount, sExtIndex, + sIsExtBlock, sIsModeOn); + + return sIsModeOn; +} + +void ExtOnly::chooseState(hwc_context_t *ctx) { + ALOGD_IF(EXTONLY_DEBUG, "%s: old state = %s", __FUNCTION__, + ovutils::getStateString(sState)); + + ovutils::eOverlayState newState = ovutils::OV_CLOSED; + + if(sExtCount > 0 && + ctx->mExtDisplay->getExternalDisplay()) { + newState = ovutils::OV_DUAL_DISP; + } + + sState = newState; + ALOGD_IF(EXTONLY_DEBUG, "%s: new chosen state = %s", __FUNCTION__, + ovutils::getStateString(sState)); +} + +void ExtOnly::markFlags(hwc_layer_t *layer) { + switch(sState) { + case ovutils::OV_DUAL_DISP: + layer->compositionType = HWC_OVERLAY; + break; + default: + break; + } +} + +bool ExtOnly::configure(hwc_context_t *ctx, hwc_layer_t *layer) { + + overlay::Overlay& ov = *(ctx->mOverlay); + ov.setState(sState); + private_handle_t *hnd = (private_handle_t *)layer->handle; + ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); + ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF; + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; + ovutils::PipeArgs parg(mdpFlags, + info, + ovutils::ZORDER_0, + isFgFlag, + ovutils::ROT_FLAG_DISABLED); + ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; + ov.setSource(pargs, ovutils::OV_PIPE0); + + hwc_rect_t sourceCrop = layer->sourceCrop; + // x,y,w,h + ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, + sourceCrop.right - sourceCrop.left, + sourceCrop.bottom - sourceCrop.top); + ov.setCrop(dcrop, ovutils::OV_PIPE0); + + ov.setTransform(0, ovutils::OV_PIPE0); + + //Setting position same as crop + //FIXME stretch to full screen + ov.setPosition(dcrop, ovutils::OV_PIPE0); + + if (!ov.commit(ovutils::OV_PIPE0)) { + ALOGE("%s: commit fails", __FUNCTION__); + return false; + } + return true; +} + +bool ExtOnly::draw(hwc_context_t *ctx, hwc_layer_list_t *list) +{ + if(!sIsModeOn || sExtIndex == -1) { + return true; + } + + private_handle_t *hnd = (private_handle_t *) + list->hwLayers[sExtIndex].handle; + + // Lock this buffer for read. + ctx->qbuf->lockAndAdd(hnd); + bool ret = true; + overlay::Overlay& ov = *(ctx->mOverlay); + ovutils::eOverlayState state = ov.getState(); + + switch (state) { + case ovutils::OV_DUAL_DISP: + // Play external + if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) { + ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + ret = false; + } + break; + default: + ALOGE("%s Unused state %s", __FUNCTION__, + ovutils::getStateString(state)); + break; + } + + return ret; +} + +}; //namespace qhwc diff --git a/libhwcomposer/hwc_extonly.h b/libhwcomposer/hwc_extonly.h new file mode 100644 index 0000000..26d5fb9 --- /dev/null +++ b/libhwcomposer/hwc_extonly.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, 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 HWC_EXTONLY_H +#define HWC_EXTONLY_H + +#include +#include "hwc_utils.h" + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +namespace qhwc { +//Feature for using overlay to display external-only layers on HDTV +class ExtOnly { +public: + //Sets up members and prepares overlay if conditions are met + static bool prepare(hwc_context_t *ctx, hwc_layer_list_t *list); + //Draws layer if this feature is on + static bool draw(hwc_context_t *ctx, hwc_layer_list_t *list); + //Receives data from hwc + static void setStats(int extCount, int extIndex, bool isExtBlock); + //resets values + static void reset(); +private: + //Choose an appropriate overlay state based on conditions + static void chooseState(hwc_context_t *ctx); + //Configures overlay + static bool configure(hwc_context_t *ctx, hwc_layer_t *layer); + //Marks layer flags if this feature is used + static void markFlags(hwc_layer_t *layer); + //returns ext-only count + static int getExtCount(); + + //The chosen overlay state. + static ovutils::eOverlayState sState; + //Number of ext-only layers in this drawing round. Used for stats/debugging. + //This does not reflect the closed caption layer count even though its + //ext-only. + static int sExtCount; + //Index of ext-only layer. If there are 2 such layers with 1 marked as BLOCK + //then this will hold the index of BLOCK layer. + static int sExtIndex; + //Flags if ext-only layer is BLOCK, which means only this layer (sExtIndex) + //is displayed even if other ext-only layers are present to block their + //content. This is used for stats / debugging only. + static bool sIsExtBlock; + //Flags if this feature is on. + static bool sIsModeOn; +}; + +inline void ExtOnly::setStats(int extCount, int extIndex, bool isExtBlock) { + sExtCount = extCount; + sExtIndex = extIndex; + sIsExtBlock = isExtBlock; +} + +inline int ExtOnly::getExtCount() { return sExtCount; } +inline void ExtOnly::reset() { + sExtCount = 0; + sExtIndex = -1; + sIsExtBlock = false; + sIsModeOn = false; + sState = ovutils::OV_CLOSED; +} + +}; //namespace qhwc + +#endif //HWC_EXTONLY_H diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp new file mode 100644 index 0000000..8107400 --- /dev/null +++ b/libhwcomposer/hwc_mdpcomp.cpp @@ -0,0 +1,829 @@ +/* + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * Not a Contribution, Apache license notifications and license are retained + * for attribution purposes only. + * + * 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 "hwc_mdpcomp.h" +#include "hwc_qbuf.h" +#include "hwc_external.h" + +#define SUPPORT_4LAYER 0 + +namespace qhwc { + +/****** Class PipeMgr ***********/ + +void inline PipeMgr::reset() { + mVGPipes = MAX_VG; + mVGUsed = 0; + mVGIndex = 0; + mRGBPipes = MAX_RGB; + mRGBUsed = 0; + mRGBIndex = MAX_VG; + mTotalAvail = mVGPipes + mRGBPipes; + memset(&mStatus, 0x0 , sizeof(int)*mTotalAvail); +} + +int PipeMgr::req_for_pipe(int pipe_req) { + + switch(pipe_req) { + case PIPE_REQ_VG: //VG + if(mVGPipes){ + mVGPipes--; + mVGUsed++; + mTotalAvail--; + return PIPE_REQ_VG; + } + case PIPE_REQ_RGB: // RGB + if(mRGBPipes) { + mRGBPipes--; + mRGBUsed++; + mTotalAvail--; + return PIPE_REQ_RGB; + } + return PIPE_NONE; + case PIPE_REQ_FB: //FB + if(mRGBPipes) { + mRGBPipes--; + mRGBUsed++; + mTotalAvail--; + mStatus[VAR_INDEX] = PIPE_IN_FB_MODE; + return PIPE_REQ_FB; + } + default: + break; + }; + return PIPE_NONE; +} + +int PipeMgr::assign_pipe(int pipe_pref) { + switch(pipe_pref) { + case PIPE_REQ_VG: //VG + if(mVGUsed) { + mVGUsed--; + mStatus[mVGIndex] = PIPE_IN_COMP_MODE; + return mVGIndex++; + } + case PIPE_REQ_RGB: //RGB + if(mRGBUsed) { + mRGBUsed--; + mStatus[mRGBIndex] = PIPE_IN_COMP_MODE; + return mRGBIndex++; + } + default: + ALOGE("%s: PipeMgr:invalid case in pipe_mgr_assign", + __FUNCTION__); + return -1; + }; +} + +/****** Class MDPComp ***********/ + +MDPComp::State MDPComp::sMDPCompState = MDPCOMP_OFF; +struct MDPComp::frame_info MDPComp::sCurrentFrame; +PipeMgr MDPComp::sPipeMgr; +IdleInvalidator *MDPComp::idleInvalidator = NULL; +bool MDPComp::sIdleFallBack = false; +bool MDPComp::sDebugLogs = false; +int MDPComp::sSkipCount = 0; +int MDPComp::sMaxLayers = 0; + +bool MDPComp::deinit() { + //XXX: Tear down MDP comp state + return true; +} + +void MDPComp::timeout_handler(void *udata) { + struct hwc_context_t* ctx = (struct hwc_context_t*)(udata); + + if(!ctx) { + ALOGE("%s: received empty data in timer callback", __FUNCTION__); + return; + } + + hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; + + if(!proc) { + ALOGE("%s: HWC proc not registered", __FUNCTION__); + return; + } + sIdleFallBack = true; + /* Trigger SF to redraw the current frame */ + proc->invalidate(proc); +} + +void MDPComp::reset( hwc_context_t *ctx, hwc_layer_list_t* list ) { + sCurrentFrame.count = 0; + free(sCurrentFrame.pipe_layer); + sCurrentFrame.pipe_layer = NULL; + + //Reset MDP pipes + sPipeMgr.reset(); + sPipeMgr.setStatus(VAR_INDEX, PIPE_IN_FB_MODE); + +#if SUPPORT_4LAYER + configure_var_pipe(ctx); +#endif + + //Reset flags and states + unsetMDPCompLayerFlags(ctx, list); + if(sMDPCompState == MDPCOMP_ON) { + sMDPCompState = MDPCOMP_OFF_PENDING; + } +} + +void MDPComp::setLayerIndex(hwc_layer_t* layer, const int pipe_index) +{ + layer->flags &= ~HWC_MDPCOMP_INDEX_MASK; + layer->flags |= pipe_index << MDPCOMP_INDEX_OFFSET; +} + +int MDPComp::getLayerIndex(hwc_layer_t* layer) +{ + int byp_index = -1; + + if(layer->flags & HWC_MDPCOMP) { + byp_index = ((layer->flags & HWC_MDPCOMP_INDEX_MASK) >> + MDPCOMP_INDEX_OFFSET); + byp_index = (byp_index < sMaxLayers ? byp_index : -1 ); + } + return byp_index; +} +void MDPComp::print_info(hwc_layer_t* layer) +{ + hwc_rect_t sourceCrop = layer->sourceCrop; + hwc_rect_t displayFrame = layer->displayFrame; + + int s_l = sourceCrop.left; + int s_t = sourceCrop.top; + int s_r = sourceCrop.right; + int s_b = sourceCrop.bottom; + + int d_l = displayFrame.left; + int d_t = displayFrame.top; + int d_r = displayFrame.right; + int d_b = displayFrame.bottom; + + ALOGD_IF(isDebug(), "src:[%d,%d,%d,%d] (%d x %d) \ + dst:[%d,%d,%d,%d] (%d x %d)", + s_l, s_t, s_r, s_b, (s_r - s_l), (s_b - s_t), + d_l, d_t, d_r, d_b, (d_r - d_l), (d_b - d_t)); +} +/* + * Configures pipe(s) for MDP composition + */ +int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_t *layer, + mdp_pipe_info& mdp_info) { + + int nPipeIndex = mdp_info.index; + + if (ctx) { + + private_handle_t *hnd = (private_handle_t *)layer->handle; + + overlay::Overlay& ov = *(ctx->mOverlay); + + if(!hnd) { + ALOGE("%s: layer handle is NULL", __FUNCTION__); + return -1; + } + + + int hw_w = ctx->mFbDev->width; + int hw_h = ctx->mFbDev->height; + + + hwc_rect_t sourceCrop = layer->sourceCrop; + hwc_rect_t displayFrame = layer->displayFrame; + + const int src_w = sourceCrop.right - sourceCrop.left; + const int src_h = sourceCrop.bottom - sourceCrop.top; + + hwc_rect_t crop = sourceCrop; + int crop_w = crop.right - crop.left; + int crop_h = crop.bottom - crop.top; + + hwc_rect_t dst = displayFrame; + int dst_w = dst.right - dst.left; + int dst_h = dst.bottom - dst.top; + + //REDUNDANT ?? + if(hnd != NULL && + (hnd->flags & private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM )) { + ALOGE("%s: failed due to non-pmem memory",__FUNCTION__); + return -1; + } + + if(dst.left < 0 || dst.top < 0 || + dst.right > hw_w || dst.bottom > hw_h) { + ALOGD_IF(isDebug(),"%s: Destination has negative coordinates", + __FUNCTION__); + + qhwc::calculate_crop_rects(crop, dst, hw_w, hw_h); + + //Update calulated width and height + crop_w = crop.right - crop.left; + crop_h = crop.bottom - crop.top; + + dst_w = dst.right - dst.left; + dst_h = dst.bottom - dst.top; + } + + if( (dst_w > hw_w)|| (dst_h > hw_h)) { + ALOGD_IF(isDebug(),"%s: Dest rect exceeds FB", __FUNCTION__); + print_info(layer); + dst_w = hw_w; + dst_h = hw_h; + } + + // Determine pipe to set based on pipe index + ovutils::eDest dest = ovutils::OV_PIPE_ALL; + if (nPipeIndex == 0) { + dest = ovutils::OV_PIPE0; + } else if (nPipeIndex == 1) { + dest = ovutils::OV_PIPE1; + } else if (nPipeIndex == 2) { + dest = ovutils::OV_PIPE2; + } + + ovutils::eZorder zOrder = ovutils::ZORDER_0; + + if(mdp_info.z_order == 0 ) { + zOrder = ovutils::ZORDER_0; + } else if(mdp_info.z_order == 1 ) { + zOrder = ovutils::ZORDER_1; + } else if(mdp_info.z_order == 2 ) { + zOrder = ovutils::ZORDER_2; + } + + // Order order order + // setSource - just setting source + // setParameter - changes src w/h/f accordingly + // setCrop - ROI - src_rect + // setPosition - dst_rect + // commit - commit changes to mdp driver + // queueBuffer - not here, happens when draw is called + + ovutils::eTransform orient = + static_cast(layer->transform); + + ov.setTransform(orient, dest); + ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); + ovutils::eMdpFlags mdpFlags = mdp_info.isVG ? ovutils::OV_MDP_PIPE_SHARE + : ovutils::OV_MDP_FLAGS_NONE; + ovutils::eIsFg isFG = mdp_info.isFG ? ovutils::IS_FG_SET + : ovutils::IS_FG_OFF; + ovutils::PipeArgs parg(mdpFlags, + info, + zOrder, + isFG, + ovutils::ROT_FLAG_DISABLED); + + ovutils::PipeArgs pargs[MAX_PIPES] = { parg, parg, parg }; + if (!ov.setSource(pargs, dest)) { + ALOGE("%s: setSource failed", __FUNCTION__); + return -1; + } + + ovutils::Dim dcrop(crop.left, crop.top, crop_w, crop_h); + if (!ov.setCrop(dcrop, dest)) { + ALOGE("%s: setCrop failed", __FUNCTION__); + return -1; + } + + ovutils::Dim dim(dst.left, dst.top, dst_w, dst_h); + if (!ov.setPosition(dim, dest)) { + ALOGE("%s: setPosition failed", __FUNCTION__); + return -1; + } + + ALOGD_IF(isDebug(),"%s: MDP set: crop[%d,%d,%d,%d] dst[%d,%d,%d,%d] \ + nPipe: %d isFG: %d zorder: %d",__FUNCTION__, dcrop.x, + dcrop.y,dcrop.w, dcrop.h, dim.x, dim.y, dim.w, dim.h, + nPipeIndex,mdp_info.isFG, mdp_info.z_order); + + if (!ov.commit(dest)) { + ALOGE("%s: commit failed", __FUNCTION__); + return -1; + } + } + return 0; +} + +/* + * MDPComp not possible when + * 1. We have more than sMaxLayers + * 2. External display connected + * 3. Composition is triggered by + * Idle timer expiry + * 4. Rotation is needed + * 5. Overlay in use + */ + +bool MDPComp::is_doable(hwc_composer_device_t *dev, + const hwc_layer_list_t* list) { + hwc_context_t* ctx = (hwc_context_t*)(dev); + + if(!ctx) { + ALOGE("%s: hwc context is NULL", __FUNCTION__); + return false; + } + + //Number of layers + if(list->numHwLayers < 1 || list->numHwLayers > sMaxLayers) { + ALOGD_IF(isDebug(), "%s: Unsupported number of layers",__FUNCTION__); + return false; + } + + //Disable MDPComp when ext display connected + if(ctx->mExtDisplay->getExternalDisplay()) { + ALOGD_IF(isDebug(), "%s: External display connected.", __FUNCTION__); + } + + //FB composition on idle timeout + if(sIdleFallBack) { + ALOGD_IF(isDebug(), "%s: idle fallback",__FUNCTION__); + return false; + } + + //MDP composition is not efficient if rotation is needed. + for(unsigned int i = 0; i < list->numHwLayers; ++i) { + if(list->hwLayers[i].transform) { + ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__); + return false; + } + } + + return true; +} + +void MDPComp::setMDPCompLayerFlags(hwc_layer_list_t* list) { + + for(int index = 0 ; index < sCurrentFrame.count; index++ ) + { + int layer_index = sCurrentFrame.pipe_layer[index].layer_index; + if(layer_index >= 0) { + hwc_layer_t* layer = &(list->hwLayers[layer_index]); + + layer->flags |= HWC_MDPCOMP; + layer->compositionType = HWC_OVERLAY; + layer->hints |= HWC_HINT_CLEAR_FB; + } + } +} + +void MDPComp::get_layer_info(hwc_layer_t* layer, int& flags) { + + private_handle_t* hnd = (private_handle_t*)layer->handle; + + if(layer->flags & HWC_SKIP_LAYER) { + flags |= MDPCOMP_LAYER_SKIP; + } else if(hnd != NULL && + (hnd->flags & private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM )) { + flags |= MDPCOMP_LAYER_UNSUPPORTED_MEM; + } + + if(layer->blending != HWC_BLENDING_NONE) + flags |= MDPCOMP_LAYER_BLEND; + + int dst_w, dst_h; + getLayerResolution(layer, dst_w, dst_h); + + hwc_rect_t sourceCrop = layer->sourceCrop; + const int src_w = sourceCrop.right - sourceCrop.left; + const int src_h = sourceCrop.bottom - sourceCrop.top; + if(((src_w > dst_w) || (src_h > dst_h))) { + flags |= MDPCOMP_LAYER_DOWNSCALE; + } +} + +int MDPComp::mark_layers(hwc_layer_list_t* list, layer_mdp_info* layer_info, + frame_info& current_frame) { + + int layer_count = list->numHwLayers; + + if(layer_count > sMaxLayers) { + if(!sPipeMgr.req_for_pipe(PIPE_REQ_FB)) { + ALOGE("%s: binding var pipe to FB failed!!", __FUNCTION__); + return 0; + } + } + + //Parse layers from higher z-order + for(int index = layer_count - 1 ; index >= 0; index-- ) { + hwc_layer_t* layer = &list->hwLayers[index]; + + int layer_prop = 0; + get_layer_info(layer, layer_prop); + + ALOGD_IF(isDebug(),"%s: prop for layer [%d]: %x", __FUNCTION__, + index, layer_prop); + + //Both in cases of NON-CONTIGUOUS memory or SKIP layer, + //current version of mdp composition falls back completely to FB + //composition. + //TO DO: Support dual mode composition + + if(layer_prop & MDPCOMP_LAYER_UNSUPPORTED_MEM) { + ALOGD_IF(isDebug(), "%s: Non contigous memory",__FUNCTION__); + return MDPCOMP_ABORT; + } + + if(layer_prop & MDPCOMP_LAYER_SKIP) { + ALOGD_IF(isDebug(), "%s:skip layer",__FUNCTION__); + return MDPCOMP_ABORT; + } + + //Request for MDP pipes + int pipe_pref = PIPE_REQ_VG; + + if((layer_prop & MDPCOMP_LAYER_DOWNSCALE) && + (layer_prop & MDPCOMP_LAYER_BLEND)) { + pipe_pref = PIPE_REQ_RGB; + } + + int allocated_pipe = sPipeMgr.req_for_pipe( pipe_pref); + if(allocated_pipe) { + layer_info[index].can_use_mdp = true; + layer_info[index].pipe_pref = allocated_pipe; + current_frame.count++; + }else { + ALOGE("%s: pipe marking in mark layer fails for : %d", + __FUNCTION__, allocated_pipe); + return MDPCOMP_FAILURE; + } + } + return MDPCOMP_SUCCESS; +} + +void MDPComp::reset_layer_mdp_info(layer_mdp_info* layer_info, int count) { + for(int i = 0 ; i < count; i++ ) { + layer_info[i].can_use_mdp = false; + layer_info[i].pipe_pref = PIPE_NONE; + } +} + +bool MDPComp::alloc_layer_pipes(hwc_layer_list_t* list, + layer_mdp_info* layer_info, frame_info& current_frame) { + + int layer_count = list->numHwLayers; + int mdp_count = current_frame.count; + int fallback_count = layer_count - mdp_count; + int frame_pipe_count = 0; + + ALOGD_IF(isDebug(), "%s: dual mode: %d total count: %d \ + mdp count: %d fallback count: %d", + __FUNCTION__, (layer_count != mdp_count), + layer_count, mdp_count, fallback_count); + + for(int index = 0 ; index < layer_count ; index++ ) { + hwc_layer_t* layer = &list->hwLayers[index]; + + if(layer_info[index].can_use_mdp) { + pipe_layer_pair& info = current_frame.pipe_layer[frame_pipe_count]; + mdp_pipe_info& pipe_info = info.pipe_index; + + pipe_info.index = sPipeMgr.assign_pipe(layer_info[index].pipe_pref); + pipe_info.isVG = (layer_info[index].pipe_pref == PIPE_REQ_VG); + pipe_info.isFG = (frame_pipe_count == 0); + /* if VAR pipe is attached to FB, FB will be updated with + VSYNC WAIT flag, so no need to set VSYNC WAIT for any + bypass pipes. if not, set VSYNC WAIT to the last updating pipe*/ + pipe_info.vsync_wait = + (sPipeMgr.getStatus(VAR_INDEX) == PIPE_IN_FB_MODE) ? false: + (frame_pipe_count == (mdp_count - 1)); + /* All the layers composed on FB will have MDP zorder 0, so start + assigning from 1*/ + pipe_info.z_order = index - + (fallback_count ? fallback_count - 1 : fallback_count); + + info.layer_index = index; + frame_pipe_count++; + } + } + return 1; +} + +//returns array of layers and their allocated pipes +bool MDPComp::parse_and_allocate(hwc_context_t* ctx, hwc_layer_list_t* list, + frame_info& current_frame ) { + + int layer_count = list->numHwLayers; + + /* clear pipe status */ + sPipeMgr.reset(); + + layer_mdp_info* bp_layer_info = (layer_mdp_info*) + malloc(sizeof(layer_mdp_info)* layer_count); + + reset_layer_mdp_info(bp_layer_info, layer_count); + + /* iterate through layer list to mark candidate */ + if(mark_layers(list, bp_layer_info, current_frame) == MDPCOMP_ABORT) { + free(bp_layer_info); + current_frame.count = 0; + ALOGE_IF(isDebug(), "%s:mark_layers failed!!", __FUNCTION__); + return false; + } + current_frame.pipe_layer = (pipe_layer_pair*) + malloc(sizeof(pipe_layer_pair) * current_frame.count); + + /* allocate MDP pipes for marked layers */ + alloc_layer_pipes( list, bp_layer_info, current_frame); + + free(bp_layer_info); + return true; +} +#if SUPPORT_4LAYER +int MDPComp::configure_var_pipe(hwc_context_t* ctx) { + + if(!ctx) { + ALOGE("%s: invalid context", __FUNCTION__); + return -1; + } + + framebuffer_device_t *fbDev = ctx->fbDev; + if (!fbDev) { + ALOGE("%s: fbDev is NULL", __FUNCTION__); + return -1; + } + + int new_mode = -1, cur_mode; + fbDev->perform(fbDev,EVENT_GET_VAR_PIPE_MODE, (void*)&cur_mode); + + if(sPipeMgr.getStatus(VAR_INDEX) == PIPE_IN_FB_MODE) { + new_mode = VAR_PIPE_FB_ATTACH; + } else if(sPipeMgr.getStatus(VAR_INDEX) == PIPE_IN_BYP_MODE) { + new_mode = VAR_PIPE_FB_DETACH; + fbDev->perform(fbDev,EVENT_WAIT_POSTBUFFER,NULL); + } + + ALOGD_IF(isDebug(),"%s: old_mode: %d new_mode: %d", __FUNCTION__, + cur_mode, new_mode); + + if((new_mode != cur_mode) && (new_mode >= 0)) { + if(fbDev->perform(fbDev,EVENT_SET_VAR_PIPE_MODE,(void*)&new_mode) < 0) { + ALOGE("%s: Setting var pipe mode failed", __FUNCTION__); + } + } + + return 0; +} +#endif + +bool MDPComp::setup(hwc_context_t* ctx, hwc_layer_list_t* list) { + int nPipeIndex, vsync_wait, isFG; + int numHwLayers = list->numHwLayers; + + frame_info ¤t_frame = sCurrentFrame; + current_frame.count = 0; + + if(!ctx) { + ALOGE("%s: invalid context", __FUNCTION__); + return -1; + } + + framebuffer_device_t *fbDev = ctx->mFbDev; + if (!fbDev) { + ALOGE("%s: fbDev is NULL", __FUNCTION__); + return -1; + } + + if(!parse_and_allocate(ctx, list, current_frame)) { +#if SUPPORT_4LAYER + int mode = VAR_PIPE_FB_ATTACH; + if(fbDev->perform(fbDev,EVENT_SET_VAR_PIPE_MODE,(void*)&mode) < 0 ) { + ALOGE("%s: setting var pipe mode failed", __FUNCTION__); + } +#endif + ALOGD_IF(isDebug(), "%s: Falling back to FB", __FUNCTION__); + return false; + } +#if SUPPORT_4LAYER + configure_var_pipe(ctx); +#endif + + overlay::Overlay& ov = *(ctx->mOverlay); + ovutils::eOverlayState state = ov.getState(); + + if (current_frame.count == 1) { + state = ovutils::OV_BYPASS_1_LAYER; + } else if (current_frame.count == 2) { + state = ovutils::OV_BYPASS_2_LAYER; + } else if (current_frame.count == 3) { + state = ovutils::OV_BYPASS_3_LAYER; + } + + ov.setState(state); + + + for (int index = 0 ; index < current_frame.count; index++) { + int layer_index = current_frame.pipe_layer[index].layer_index; + hwc_layer_t* layer = &list->hwLayers[layer_index]; + mdp_pipe_info& cur_pipe = current_frame.pipe_layer[index].pipe_index; + + if( prepare(ctx, layer, cur_pipe) != 0 ) { + ALOGD_IF(isDebug(), "%s: MDPComp failed to configure overlay for \ + layer %d with pipe index:%d",__FUNCTION__, + index, cur_pipe.index); + return false; + } else { + setLayerIndex(layer, index); + } + } + return true; +} + +void MDPComp::unsetMDPCompLayerFlags(hwc_context_t* ctx, hwc_layer_list_t* list) +{ + if (!list) + return; + + for (int index = 0 ; index < sCurrentFrame.count; index++) { + int l_index = sCurrentFrame.pipe_layer[index].layer_index; + if(list->hwLayers[l_index].flags & HWC_MDPCOMP) { + list->hwLayers[l_index].flags &= ~HWC_MDPCOMP; + } + } +} + +int MDPComp::draw(hwc_context_t *ctx, hwc_layer_list_t* list) { + + if(!isEnabled()) { + ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled",__FUNCTION__); + return 0; + } + + if(!ctx || !list) { + ALOGE("%s: invalid contxt or list",__FUNCTION__); + return -1; + } + + overlay::Overlay& ov = *(ctx->mOverlay); + + for(unsigned int i = 0; i < list->numHwLayers; i++ ) + { + hwc_layer_t *layer = &list->hwLayers[i]; + + if(!(layer->flags & HWC_MDPCOMP)) { + ALOGD_IF(isDebug(), "%s: Layer Not flagged for MDP comp", + __FUNCTION__); + continue; + } + + int data_index = getLayerIndex(layer); + mdp_pipe_info& pipe_info = + sCurrentFrame.pipe_layer[data_index].pipe_index; + int index = pipe_info.index; + + if(index < 0) { + ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, index); + return -1; + } + + /* reset Invalidator */ + if(idleInvalidator) + idleInvalidator->markForSleep(); + + ovutils::eDest dest; + + if (index == 0) { + dest = ovutils::OV_PIPE0; + } else if (index == 1) { + dest = ovutils::OV_PIPE1; + } else if (index == 2) { + dest = ovutils::OV_PIPE2; + } + + if (ctx ) { + private_handle_t *hnd = (private_handle_t *)layer->handle; + if(!hnd) { + ALOGE("%s handle null", __FUNCTION__); + return -1; + } + + //lock buffer before queue + //XXX: Handle lock failure + ctx->qbuf->lockAndAdd(hnd); + + ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ + using pipe: %d", __FUNCTION__, layer, + hnd, index ); + + if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) { + ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + return -1; + } + } + layer->flags &= ~HWC_MDPCOMP; + layer->flags |= HWC_MDPCOMP_INDEX_MASK; + } + return 0; +} + +bool MDPComp::init(hwc_context_t *dev) { + + if(!dev) { + ALOGE("%s: Invalid hwc context!!",__FUNCTION__); + return false; + } + +#if SUPPORT_4LAYER + if(MAX_MDPCOMP_LAYERS > MAX_STATIC_PIPES) { + framebuffer_device_t *fbDev = dev->fbDevice; + if(fbDev == NULL) { + ALOGE("%s: FATAL: framebuffer device is NULL", __FUNCTION__); + return false; + } + + //Receive VAR pipe object from framebuffer + if(fbDev->perform(fbDev,EVENT_GET_VAR_PIPE,(void*)&ov) < 0) { + ALOGE("%s: FATAL: getVariablePipe failed!!", __FUNCTION__); + return false; + } + + sPipeMgr.setStatus(VAR_INDEX, PIPE_IN_FB_MODE); + } +#endif + char property[PROPERTY_VALUE_MAX]; + + sMaxLayers = 0; + if(property_get("debug.mdpcomp.maxlayer", property, NULL) > 0) { + if(atoi(property) != 0) + sMaxLayers = atoi(property); + } + + sDebugLogs = false; + if(property_get("debug.mdpcomp.logs", property, NULL) > 0) { + if(atoi(property) != 0) + sDebugLogs = true; + } + + unsigned long idle_timeout = DEFAULT_IDLE_TIME; + if(property_get("debug.mdpcomp.idletime", property, NULL) > 0) { + if(atoi(property) != 0) + idle_timeout = atoi(property); + } + + //create Idle Invalidator + idleInvalidator = IdleInvalidator::getInstance(); + + if(idleInvalidator == NULL) { + ALOGE("%s: failed to instantiate idleInvalidator object", __FUNCTION__); + } else { + idleInvalidator->init(timeout_handler, dev, idle_timeout); + } + return true; +} + +bool MDPComp::configure(hwc_composer_device_t *dev, hwc_layer_list_t* list) { + + if(!isEnabled()) { + ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__); + return false; + } + + hwc_context_t* ctx = (hwc_context_t*)(dev); + + bool isMDPCompUsed = true; + bool doable = is_doable(dev, list); + + if(doable) { + if(setup(ctx, list)) { + setMDPCompLayerFlags(list); + sMDPCompState = MDPCOMP_ON; + } else { + ALOGD_IF(isDebug(),"%s: MDP Comp Failed",__FUNCTION__); + isMDPCompUsed = false; + } + } else { + ALOGD_IF( isDebug(),"%s: MDP Comp not possible[%d]",__FUNCTION__, + doable); + isMDPCompUsed = false; + } + + //Reset states + if(!isMDPCompUsed) { + //Reset current frame + reset(ctx, list); + } + + sIdleFallBack = false; + + return isMDPCompUsed; +} +}; //namespace + diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h new file mode 100644 index 0000000..199204c --- /dev/null +++ b/libhwcomposer/hwc_mdpcomp.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * Not a Contribution, Apache license notifications and license are retained + * for attribution purposes only. + * + * 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 HWC_MDP_COMP +#define HWC_MDP_COMP + +#include +#include +#include +#include + +#define MAX_STATIC_PIPES 3 +#define MDPCOMP_INDEX_OFFSET 4 +#define DEFAULT_IDLE_TIME 2000 + +#define MAX_VG 2 +#define MAX_RGB 2 +#define VAR_INDEX 3 +#define MAX_PIPES (MAX_VG + MAX_RGB) +#define HWC_MDPCOMP_INDEX_MASK 0x00000030 + + +//struct hwc_context_t; + +namespace qhwc { + +// pipe status +enum { + PIPE_UNASSIGNED = 0, + PIPE_IN_FB_MODE, + PIPE_IN_COMP_MODE, +}; + +// pipe request +enum { + PIPE_NONE = 0, + PIPE_REQ_VG, + PIPE_REQ_RGB, + PIPE_REQ_FB, +}; + +// MDP Comp Status +enum { + MDPCOMP_SUCCESS = 0, + MDPCOMP_FAILURE, + MDPCOMP_ABORT, +}; + +//This class manages the status of 4 MDP pipes and keeps +//track of Variable pipe mode. +class PipeMgr { + +public: + PipeMgr() { reset();} + //reset pipemgr params + void reset(); + + //Based on the preference received, pipe mgr + //allocates the best available pipe to handle + //the case + int req_for_pipe(int pipe_req); + + //Allocate requested pipe and update availablity + int assign_pipe(int pipe_pref); + + // Get/Set pipe status + void setStatus(int pipe_index, int pipe_status) { + mStatus[pipe_index] = pipe_status; + } + int getStatus(int pipe_index) { + return mStatus[pipe_index]; + } +private: + int mVGPipes; + int mVGUsed; + int mVGIndex; + int mRGBPipes; + int mRGBUsed; + int mRGBIndex; + int mTotalAvail; + int mStatus[MAX_PIPES]; +}; + + +class MDPComp { + enum State { + MDPCOMP_ON = 0, + MDPCOMP_OFF, + MDPCOMP_OFF_PENDING, + }; + + enum { + MDPCOMP_LAYER_BLEND = 1, + MDPCOMP_LAYER_DOWNSCALE = 2, + MDPCOMP_LAYER_SKIP = 4, + MDPCOMP_LAYER_UNSUPPORTED_MEM = 8, + }; + + struct mdp_pipe_info { + int index; + int z_order; + bool isVG; + bool isFG; + bool vsync_wait; + }; + + struct pipe_layer_pair { + int layer_index; + mdp_pipe_info pipe_index; + native_handle_t* handle; + }; + + struct frame_info { + int count; + struct pipe_layer_pair* pipe_layer; + + }; + + struct layer_mdp_info { + bool can_use_mdp; + int pipe_pref; + }; + + static State sMDPCompState; + static IdleInvalidator *idleInvalidator; + static struct frame_info sCurrentFrame; + static PipeMgr sPipeMgr; + static int sSkipCount; + static int sMaxLayers; + static bool sDebugLogs; + static bool sIdleFallBack; + +public: + /* Handler to invoke frame redraw on Idle Timer expiry */ + static void timeout_handler(void *udata); + + /* configure/tear-down MDPComp params*/ + static bool init(hwc_context_t *ctx); + static bool deinit(); + + /*sets up mdp comp for the current frame */ + static bool configure(hwc_composer_device_t *ctx, hwc_layer_list_t* list); + + /* draw */ + static int draw(hwc_context_t *ctx, hwc_layer_list_t *list); + + /* store frame stats */ + static void setStats(int skipCt) { sSkipCount = skipCt;}; + +private: + + /* get/set pipe index associated with overlay layers */ + static void setLayerIndex(hwc_layer_t* layer, const int pipe_index); + static int getLayerIndex(hwc_layer_t* layer); + + /* set/reset flags for MDPComp */ + static void setMDPCompLayerFlags(hwc_layer_list_t* list); + static void unsetMDPCompLayerFlags(hwc_context_t* ctx, + hwc_layer_list_t* list); + + static void print_info(hwc_layer_t* layer); + + /* configure's overlay pipes for the frame */ + static int prepare(hwc_context_t *ctx, hwc_layer_t *layer, + mdp_pipe_info& mdp_info); + + /* checks for conditions where mdpcomp is not possible */ + static bool is_doable(hwc_composer_device_t *dev, + const hwc_layer_list_t* list); + + static bool setup(hwc_context_t* ctx, hwc_layer_list_t* list); + + /* parses layer for properties affecting mdp comp */ + static void get_layer_info(hwc_layer_t* layer, int& flags); + + /* iterates through layer list to choose candidate to use overlay */ + static int mark_layers(hwc_layer_list_t* list, layer_mdp_info* layer_info, + frame_info& current_frame); + static bool parse_and_allocate(hwc_context_t* ctx, hwc_layer_list_t* list, + frame_info& current_frame ); + + /* clears layer info struct */ + static void reset_layer_mdp_info(layer_mdp_info* layer_mdp_info,int count); + + /* allocates pipes to selected candidates */ + static bool alloc_layer_pipes(hwc_layer_list_t* list, + layer_mdp_info* layer_info, + frame_info& current_frame); + /* updates variable pipe mode for the current frame */ + static int configure_var_pipe(hwc_context_t* ctx); + + /* get/set states */ + static State get_state() { return sMDPCompState; }; + static void set_state(State state) { sMDPCompState = state; }; + + /* reset state */ + static void reset( hwc_context_t *ctx, hwc_layer_list_t* list ); + + /* Is feature enabled */ + static bool isEnabled() { return sMaxLayers ? true : false; }; + /* Is debug enabled */ + static bool isDebug() { return sDebugLogs ? true : false; }; +}; +}; //namespace +#endif diff --git a/libhwcomposer/hwc_qbuf.h b/libhwcomposer/hwc_qbuf.h index a0ade8c..6d75964 100644 --- a/libhwcomposer/hwc_qbuf.h +++ b/libhwcomposer/hwc_qbuf.h @@ -15,6 +15,9 @@ * limitations under the License. */ +#include +#include + // ----------------------------------------------------------------------------- // QueuedBufferStore //This class holds currently and previously queued buffers. diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp new file mode 100644 index 0000000..f58fbd3 --- /dev/null +++ b/libhwcomposer/hwc_uevents.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * + * Not a Contribution, Apache license notifications and license are + * retained for attribution purposes only. + + * 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 DEBUG 0 +#ifndef HWC_OBSERVER_H +#define HWC_OBSERVER_H +#include +#include +#include +#include +#include +#include "hwc_utils.h" +#include "hwc_external.h" + +namespace qhwc { + +const char* MSMFB_DEVICE_FB0 = "change@/devices/virtual/graphics/fb0"; +const char* MSMFB_DEVICE_FB1 = "change@/devices/virtual/graphics/fb1"; +const char* MSMFB_HDMI_NODE = "fb1"; + +static void handle_uevent(hwc_context_t* ctx, const char* udata, int len) +{ + int vsync = 0; + char* hdmi; + int64_t timestamp = 0; + const char *str = udata; + hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; + int hdmiconnected = ctx->mExtDisplay->getExternalDisplay(); + + if(!strcasestr(str, "@/devices/virtual/graphics/fb")) { + ALOGD_IF(DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__); + return; + } + + if(hdmiconnected) + vsync = !strncmp(str, MSMFB_DEVICE_FB1, strlen(MSMFB_DEVICE_FB1)); + else + vsync = !strncmp(str, MSMFB_DEVICE_FB0, strlen(MSMFB_DEVICE_FB0)); + + hdmi = strcasestr(str, MSMFB_HDMI_NODE); + if(vsync) { + str += strlen(str) + 1; + while(*str) { + if (!strncmp(str, "VSYNC=", strlen("VSYNC="))) { + timestamp = strtoull(str + strlen("VSYNC="), NULL, 0); + proc->vsync(proc, 0, timestamp); + } + str += strlen(str) + 1; + if(str - udata >= len) + break; + } + return; + } + + if(hdmi) { + // parse HDMI events + // The event will be of the form: + // change@/devices/virtual/graphics/fb1 ACTION=change + // DEVPATH=/devices/virtual/graphics/fb1 + // SUBSYSTEM=graphics HDCP_STATE=FAIL MAJOR=29 + // for now just parsing onlin/offline info is enough + str = udata; + int connected = 0; + if(!(strncmp(str,"online@",strlen("online@")))) { + connected = 1; + } else if(!(strncmp(str,"offline@",strlen("offline@")))) { + connected = 0; + } + ctx->mExtDisplay->setExternalDisplay(connected); + } + +} + +static void *uevent_loop(void *param) +{ + int len = 0; + static char udata[4096]; + memset(udata, 0, sizeof(udata)); + hwc_context_t * ctx = reinterpret_cast(param); + + setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); + uevent_init(); + + while(1) { + len = uevent_next_event(udata, sizeof(udata) - 2); + handle_uevent(ctx, udata, len); + } + + return NULL; +} + +void init_uevent_thread(hwc_context_t* ctx) +{ + pthread_t uevent_thread; + pthread_create(&uevent_thread, NULL, uevent_loop, (void*) ctx); +} + +}; //namespace +#endif //HWC_OBSERVER_H diff --git a/libhwcomposer/hwc_uimirror.cpp b/libhwcomposer/hwc_uimirror.cpp index 4540be8..d2b766d 100644 --- a/libhwcomposer/hwc_uimirror.cpp +++ b/libhwcomposer/hwc_uimirror.cpp @@ -18,12 +18,14 @@ * limitations under the License. */ +#define HWC_UI_MIRROR 0 +#include +#include #include "hwc_uimirror.h" -#include "hwc_ext_observer.h" +#include "hwc_external.h" namespace qhwc { -#define HWC_UI_MIRROR 0 // Function to get the primary device orientation // Loops thru the hardware layers and returns the orientation of the max. @@ -31,7 +33,7 @@ namespace qhwc { int getDeviceOrientation(hwc_context_t* ctx, hwc_layer_list_t *list) { int orientation = list->hwLayers[0].transform; if(!ctx) { - ALOGD_IF(HWC_UI_MIRROR, "In %s: ctx is NULL!!", __FUNCTION__); + ALOGE("In %s: ctx is NULL!!", __FUNCTION__); return -1; } for(size_t i=0; i <= list->numHwLayers;i++ ) @@ -58,8 +60,14 @@ bool UIMirrorOverlay::sIsUiMirroringOn = false; bool UIMirrorOverlay::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { sState = ovutils::OV_CLOSED; sIsUiMirroringOn = false; + + if(!ctx->mMDP.hasOverlay) { + ALOGD_IF(HWC_UI_MIRROR, "%s, this hw doesnt support mirroring", + __FUNCTION__); + return false; + } // If external display is connected - if(ctx->mExtDisplayObserver->getExternalDisplay()) { + if(ctx->mExtDisplay->getExternalDisplay()) { sState = ovutils::OV_UI_MIRROR; configure(ctx, list); } @@ -73,7 +81,7 @@ bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_layer_list_t *list) overlay::Overlay& ov = *(ctx->mOverlay); // Set overlay state ov.setState(sState); - framebuffer_device_t *fbDev = ctx->mFbDevice->getFb(); + framebuffer_device_t *fbDev = ctx->mFbDev; if(fbDev) { private_module_t* m = reinterpret_cast( fbDev->common.module); @@ -93,7 +101,7 @@ bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_layer_list_t *list) dest = ovutils::OV_PIPE0; } - ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_MEMORY_ID_TYPE_FB; + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; /* - TODO: Secure content if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { ovutils::setMdpFlags(mdpFlags, @@ -143,7 +151,7 @@ bool UIMirrorOverlay::draw(hwc_context_t *ctx) overlay::Overlay& ov = *(ctx->mOverlay); ovutils::eOverlayState state = ov.getState(); ovutils::eDest dest = ovutils::OV_PIPE_ALL; - framebuffer_device_t *fbDev = ctx->mFbDevice->getFb(); + framebuffer_device_t *fbDev = ctx->mFbDev; if(fbDev) { private_module_t* m = reinterpret_cast( fbDev->common.module); @@ -158,20 +166,20 @@ bool UIMirrorOverlay::draw(hwc_context_t *ctx) if (!ov.queueBuffer(m->framebuffer->fd, m->currentOffset, ovutils::OV_PIPE0)) { ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + ret = false; } break; case ovutils::OV_2D_TRUE_UI_MIRROR: if (!ov.queueBuffer(m->framebuffer->fd, m->currentOffset, ovutils::OV_PIPE2)) { ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + ret = false; } break; default: break; } - // TODO: - // Call PANDISPLAY ioctl here to kickoff } return ret; } diff --git a/libhwcomposer/hwc_uimirror.h b/libhwcomposer/hwc_uimirror.h index af43848..98f7896 100644 --- a/libhwcomposer/hwc_uimirror.h +++ b/libhwcomposer/hwc_uimirror.h @@ -20,6 +20,7 @@ #ifndef HWC_UIMIRROR_H #define HWC_UIMIRROR_H #include "hwc_utils.h" +#include "overlay.h" #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp index ae5c526..8bc8bfc 100644 --- a/libhwcomposer/hwc_utils.cpp +++ b/libhwcomposer/hwc_utils.cpp @@ -15,26 +15,43 @@ * limitations under the License. */ +#include #include "hwc_utils.h" #include "mdp_version.h" #include "hwc_video.h" -#include "hwc_ext_observer.h" +#include "hwc_qbuf.h" #include "hwc_copybit.h" +#include "hwc_external.h" +#include "hwc_mdpcomp.h" +#include "hwc_extonly.h" + namespace qhwc { + +// Opens Framebuffer device +static void openFramebufferDevice(hwc_context_t *ctx) +{ + hw_module_t const *module; + if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { + framebuffer_open(module, &(ctx->mFbDev)); + } +} + void initContext(hwc_context_t *ctx) { - //XXX: target specific initializations here + openFramebufferDevice(ctx); ctx->mOverlay = overlay::Overlay::getInstance(); ctx->qbuf = new QueuedBufferStore(); - ctx->mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion(); - ctx->hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay(); - ALOGI("MDP version: %d",ctx->mdpVersion); - - ctx->mExtDisplayObserver = ExtDisplayObserver::getInstance(); - ctx->mExtDisplayObserver->setHwcContext(ctx); - ctx->mFbDevice = FbDevice::getInstance(); + ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion(); + ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay(); + ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType(); ctx->mCopybitEngine = CopybitEngine::getInstance(); - CopyBit::openEglLibAndGethandle(); + ctx->mExtDisplay = new ExternalDisplay(ctx); + MDPComp::init(ctx); + + init_uevent_thread(ctx); + + ALOGI("Initializing Qualcomm Hardware Composer"); + ALOGI("MDP version: %d", ctx->mMDP.version); } void closeContext(hwc_context_t *ctx) @@ -48,15 +65,25 @@ void closeContext(hwc_context_t *ctx) delete ctx->mCopybitEngine; ctx->mCopybitEngine = NULL; } - if(ctx->mFbDevice) { - delete ctx->mFbDevice; - ctx->mFbDevice = NULL; + + if(ctx->mFbDev) { + framebuffer_close(ctx->mFbDev); + ctx->mFbDev = NULL; } + if(ctx->qbuf) { delete ctx->qbuf; ctx->qbuf = NULL; } - CopyBit::closeEglLib(); + + if(ctx->mExtDisplay) { + delete ctx->mExtDisplay; + ctx->mExtDisplay = NULL; + } + + + free(const_cast(ctx->device.methods)); + } void dumpLayer(hwc_layer_t const* l) @@ -80,28 +107,47 @@ void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list) int yuvCount = 0; int yuvLayerIndex = -1; bool isYuvLayerSkip = false; + int skipCount = 0; + int ccLayerIndex = -1; //closed caption + int extLayerIndex = -1; //ext-only or block except closed caption + int extCount = 0; //ext-only except closed caption + bool isExtBlockPresent = false; //is BLOCK layer present for (size_t i = 0; i < list->numHwLayers; i++) { private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if (isYuvBuffer(hnd)) { + if (UNLIKELY(isYuvBuffer(hnd))) { yuvCount++; yuvLayerIndex = i; //Animating if (isSkipLayer(&list->hwLayers[i])) { isYuvLayerSkip = true; } + } else if(UNLIKELY(isExtCC(hnd))) { + ccLayerIndex = i; + } else if(UNLIKELY(isExtBlock(hnd))) { + extCount++; + extLayerIndex = i; + isExtBlockPresent = true; + } else if(UNLIKELY(isExtOnly(hnd))) { + extCount++; + //If BLOCK layer present, dont cache index, display BLOCK only. + if(isExtBlockPresent == false) extLayerIndex = i; } else if (isSkipLayer(&list->hwLayers[i])) { //Popups //If video layer is below a skip layer if(yuvLayerIndex != -1 && yuvLayerIndex < (ssize_t)i) { isYuvLayerSkip = true; } + skipCount++; } } - VideoOverlay::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip); + VideoOverlay::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip, + ccLayerIndex); + ExtOnly::setStats(extCount, extLayerIndex, isExtBlockPresent); CopyBit::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip); + MDPComp::setStats(skipCount); ctx->numHwLayers = list->numHwLayers; return; @@ -163,33 +209,4 @@ void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst, } } -//FbDevice class functions -FbDevice* FbDevice::sInstance = 0;; -struct framebuffer_device_t* FbDevice::getFb() { - return sFb; -} - -FbDevice* FbDevice::getInstance() { - if(sInstance == NULL) - sInstance = new FbDevice(); - return sInstance; -} - -FbDevice::FbDevice(){ - hw_module_t const *module; - if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { - framebuffer_open(module, &sFb); - } else { - ALOGE("FATAL ERROR: framebuffer open failed."); - } -} -FbDevice::~FbDevice() -{ - if(sFb) - { - framebuffer_close(sFb); - sFb = NULL; - } -} - };//namespace diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h index 0bf30c9..71c1f73 100644 --- a/libhwcomposer/hwc_utils.h +++ b/libhwcomposer/hwc_utils.h @@ -17,28 +17,34 @@ #ifndef HWC_UTILS_H #define HWC_UTILS_H -#include -#include + #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hwc_qbuf.h" -#include +#include #define ALIGN_TO(x, align) (((x) + ((align)-1)) & ~((align)-1)) #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) #define FINAL_TRANSFORM_MASK 0x000F +//Fwrd decls struct hwc_context_t; +struct framebuffer_device_t; + +namespace overlay { +class Overlay; +} + namespace qhwc { +//fwrd decl +class QueuedBufferStore; +class ExternalDisplay; +class CopybitEngine; + +struct MDPInfo { + int version; + char panel; + bool hasOverlay; +}; enum external_display_type { EXT_TYPE_NONE, @@ -52,8 +58,13 @@ enum HWCCompositionType { HWC_USE_COPYBIT // This layer is to be handled by copybit }; +enum { + HWC_MDPCOMP = 0x00000002, + HWC_LAYER_RESERVED_0 = 0x00000004, + HWC_LAYER_RESERVED_1 = 0x00000008 +}; + -class ExtDisplayObserver; // ----------------------------------------------------------------------------- // Utility functions - implemented in hwc_utils.cpp void dumpLayer(hwc_layer_t const* l); @@ -78,44 +89,44 @@ static inline bool isYuvBuffer(const private_handle_t* hnd) { static inline bool isBufferLocked(const private_handle_t* hnd) { return (hnd && (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags)); } -// ----------------------------------------------------------------------------- -// Copybit specific - inline or implemented in hwc_copybit.cpp -typedef EGLClientBuffer (*functype_eglGetRenderBufferANDROID) ( - EGLDisplay dpy, - EGLSurface draw); -typedef EGLSurface (*functype_eglGetCurrentSurface)(EGLint readdraw); -// ----------------------------------------------------------------------------- -// Singleton for Framebuffer device -class FbDevice{ -public: - ~FbDevice(); - // API to get Fb device(non static) - struct framebuffer_device_t *getFb(); - // API to get singleton - static FbDevice* getInstance(); +//Return true if buffer is for external display only +static inline bool isExtOnly(const private_handle_t* hnd) { + return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY)); +} -private: - FbDevice(); - struct framebuffer_device_t *sFb; - static FbDevice* sInstance; // singleton -}; +//Return true if buffer is for external display only with a BLOCK flag. +static inline bool isExtBlock(const private_handle_t* hnd) { + return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK)); +} +//Return true if buffer is for external display only with a Close Caption flag. +static inline bool isExtCC(const private_handle_t* hnd) { + return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_CC)); +} + +// Initialize uevent thread +void init_uevent_thread(hwc_context_t* ctx); + +inline void getLayerResolution(const hwc_layer_t* layer, + int& width, int& height) +{ + hwc_rect_t displayFrame = layer->displayFrame; + width = displayFrame.right - displayFrame.left; + height = displayFrame.bottom - displayFrame.top; +} }; //qhwc namespace - // ----------------------------------------------------------------------------- // HWC context // This structure contains overall state struct hwc_context_t { hwc_composer_device_t device; int numHwLayers; - int mdpVersion; - bool hasOverlay; int overlayInUse; //Framebuffer device - qhwc::FbDevice* mFbDevice; + framebuffer_device_t *mFbDev; //Copybit Engine qhwc::CopybitEngine* mCopybitEngine; @@ -127,7 +138,10 @@ struct hwc_context_t { qhwc::QueuedBufferStore *qbuf; // External display related information - qhwc::ExtDisplayObserver*mExtDisplayObserver; + qhwc::ExternalDisplay *mExtDisplay; + + qhwc::MDPInfo mMDP; + }; #endif //HWC_UTILS_H diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp index 180ab86..e2d9be2 100644 --- a/libhwcomposer/hwc_video.cpp +++ b/libhwcomposer/hwc_video.cpp @@ -15,39 +15,52 @@ * limitations under the License. */ +#define VIDEO_DEBUG 0 +#include +#include "hwc_qbuf.h" #include "hwc_video.h" -#include "hwc_ext_observer.h" +#include "hwc_external.h" namespace qhwc { #define FINAL_TRANSFORM_MASK 0x000F -#define VIDEO_DEBUG 0 //Static Members ovutils::eOverlayState VideoOverlay::sState = ovutils::OV_CLOSED; int VideoOverlay::sYuvCount = 0; int VideoOverlay::sYuvLayerIndex = -1; +bool VideoOverlay::sIsYuvLayerSkip = false; +int VideoOverlay::sCCLayerIndex = -1; bool VideoOverlay::sIsModeOn = false; -bool VideoOverlay::sIsLayerSkip = false; //Cache stats, figure out the state, config overlay bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { sIsModeOn = false; - if(!ctx->hasOverlay) { + if(!ctx->mMDP.hasOverlay) { ALOGD_IF(VIDEO_DEBUG,"%s, this hw doesnt support overlay", __FUNCTION__); return false; } + if(sYuvLayerIndex == -1) { + return false; + } chooseState(ctx); //if the state chosen above is CLOSED, skip this block. if(sState != ovutils::OV_CLOSED) { - if(configure(ctx, &list->hwLayers[sYuvLayerIndex])) { + hwc_layer_t *yuvLayer = &list->hwLayers[sYuvLayerIndex]; + hwc_layer_t *ccLayer = NULL; + if(sCCLayerIndex != -1) + ccLayer = &list->hwLayers[sCCLayerIndex]; + + if(configure(ctx, yuvLayer, ccLayer)) { markFlags(&list->hwLayers[sYuvLayerIndex]); + sIsModeOn = true; } } ALOGD_IF(VIDEO_DEBUG, "%s: stats: yuvCount = %d, yuvIndex = %d," - "IsModeOn = %d, IsSkipLayer = %d", __FUNCTION__, sYuvCount, - sYuvLayerIndex, sIsModeOn, sIsLayerSkip); + "IsYuvLayerSkip = %d, ccLayerIndex = %d, IsModeOn = %d", + __FUNCTION__, sYuvCount, sYuvLayerIndex, + sIsYuvLayerSkip, sCCLayerIndex, sIsModeOn); return sIsModeOn; } @@ -57,17 +70,15 @@ void VideoOverlay::chooseState(hwc_context_t *ctx) { ovutils::getStateString(sState)); ovutils::eOverlayState newState = ovutils::OV_CLOSED; - //TODO check if device supports overlay and hdmi //Support 1 video layer if(sYuvCount == 1) { //Skip on primary, display on ext. - if(sIsLayerSkip && ctx->mExtDisplayObserver->getExternalDisplay()) { - //TODO - //VIDEO_ON_TV_ONLY - } else if(sIsLayerSkip) { //skip on primary, no ext + if(sIsYuvLayerSkip && ctx->mExtDisplay->getExternalDisplay()) { + newState = ovutils::OV_2D_VIDEO_ON_TV; + } else if(sIsYuvLayerSkip) { //skip on primary, no ext newState = ovutils::OV_CLOSED; - } else if(ctx->mExtDisplayObserver->getExternalDisplay()) { + } else if(ctx->mExtDisplay->getExternalDisplay()) { //display on both newState = ovutils::OV_2D_VIDEO_ON_PANEL_TV; } else { //display on primary only @@ -86,110 +97,212 @@ void VideoOverlay::markFlags(hwc_layer_t *layer) { layer->compositionType = HWC_OVERLAY; layer->hints |= HWC_HINT_CLEAR_FB; break; - //TODO - //case ovutils::OV_2D_VIDEO_ON_TV: - //just break, dont update flags. + case ovutils::OV_2D_VIDEO_ON_TV: + break; //dont update flags. default: break; } } -bool VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_t *layer) -{ - if (LIKELY(ctx->mOverlay)) { +/* Helpers */ +bool configPrimVid(hwc_context_t *ctx, hwc_layer_t *layer) { + overlay::Overlay& ov = *(ctx->mOverlay); + private_handle_t *hnd = (private_handle_t *)layer->handle; + ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); - overlay::Overlay& ov = *(ctx->mOverlay); - // Set overlay state - ov.setState(sState); + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; + if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { + ovutils::setMdpFlags(mdpFlags, + ovutils::OV_MDP_SECURE_OVERLAY_SESSION); + } - private_handle_t *hnd = (private_handle_t *)layer->handle; - ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); + ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF; + if (ctx->numHwLayers == 1) { + isFgFlag = ovutils::IS_FG_SET; + } - //TODO change this based on state. - ovutils::eDest dest = ovutils::OV_PIPE_ALL; + ovutils::PipeArgs parg(mdpFlags, + info, + ovutils::ZORDER_0, + isFgFlag, + ovutils::ROT_FLAG_DISABLED); + ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; + ov.setSource(pargs, ovutils::OV_PIPE0); - ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; - if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { - ovutils::setMdpFlags(mdpFlags, - ovutils::OV_MDP_SECURE_OVERLAY_SESSION); - } + hwc_rect_t sourceCrop = layer->sourceCrop; + // x,y,w,h + ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, + sourceCrop.right - sourceCrop.left, + sourceCrop.bottom - sourceCrop.top); - ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF; - if (ctx->numHwLayers == 1) { - isFgFlag = ovutils::IS_FG_SET; - } + ovutils::Dim dpos; + hwc_rect_t displayFrame = layer->displayFrame; + dpos.x = displayFrame.left; + dpos.y = displayFrame.top; + dpos.w = (displayFrame.right - displayFrame.left); + dpos.h = (displayFrame.bottom - displayFrame.top); - ovutils::PipeArgs parg(mdpFlags, - info, - ovutils::ZORDER_0, - isFgFlag, - ovutils::ROT_FLAG_DISABLED); - ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; - ov.setSource(pargs, dest); - - hwc_rect_t sourceCrop = layer->sourceCrop; - // x,y,w,h - ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, - sourceCrop.right - sourceCrop.left, - sourceCrop.bottom - sourceCrop.top); - //Only for External - ov.setCrop(dcrop, ovutils::OV_PIPE1); - - // FIXME: Use source orientation for TV when source is portrait - //Only for External - ov.setTransform(0, dest); - - ovutils::Dim dpos; - hwc_rect_t displayFrame = layer->displayFrame; - dpos.x = displayFrame.left; - dpos.y = displayFrame.top; - dpos.w = (displayFrame.right - displayFrame.left); - dpos.h = (displayFrame.bottom - displayFrame.top); - - //Only for External - ov.setPosition(dpos, ovutils::OV_PIPE1); - - //Calculate the rect for primary based on whether the supplied position - //is within or outside bounds. - const int fbWidth = + //Calculate the rect for primary based on whether the supplied position + //is within or outside bounds. + const int fbWidth = ovutils::FrameBufferInfo::getInstance()->getWidth(); - const int fbHeight = + const int fbHeight = ovutils::FrameBufferInfo::getInstance()->getHeight(); - if( displayFrame.left < 0 || + if( displayFrame.left < 0 || displayFrame.top < 0 || displayFrame.right > fbWidth || displayFrame.bottom > fbHeight) { - calculate_crop_rects(sourceCrop, displayFrame, fbWidth, fbHeight); + calculate_crop_rects(sourceCrop, displayFrame, fbWidth, fbHeight); - //Update calculated width and height - dcrop.w = sourceCrop.right - sourceCrop.left; - dcrop.h = sourceCrop.bottom - sourceCrop.top; + //Update calculated width and height + dcrop.w = sourceCrop.right - sourceCrop.left; + dcrop.h = sourceCrop.bottom - sourceCrop.top; - dpos.w = displayFrame.right - displayFrame.left; - dpos.h = displayFrame.bottom - displayFrame.top; - } - - //Only for Primary - ov.setCrop(dcrop, ovutils::OV_PIPE0); - - int transform = layer->transform & FINAL_TRANSFORM_MASK; - ovutils::eTransform orient = - static_cast(transform); - ov.setTransform(orient, ovutils::OV_PIPE0); - - ov.setPosition(dpos, ovutils::OV_PIPE0); - - //Both prim and external - if (!ov.commit(dest)) { - ALOGE("%s: commit fails", __FUNCTION__); - return false; - } - - sIsModeOn = true; + dpos.w = displayFrame.right - displayFrame.left; + dpos.h = displayFrame.bottom - displayFrame.top; } - return sIsModeOn; + + //Only for Primary + ov.setCrop(dcrop, ovutils::OV_PIPE0); + + int transform = layer->transform & FINAL_TRANSFORM_MASK; + ovutils::eTransform orient = + static_cast(transform); + ov.setTransform(orient, ovutils::OV_PIPE0); + + ov.setPosition(dpos, ovutils::OV_PIPE0); + + if (!ov.commit(ovutils::OV_PIPE0)) { + ALOGE("%s: commit fails", __FUNCTION__); + return false; + } + return true; +} + +bool configExtVid(hwc_context_t *ctx, hwc_layer_t *layer) { + overlay::Overlay& ov = *(ctx->mOverlay); + private_handle_t *hnd = (private_handle_t *)layer->handle; + ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); + + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; + if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { + ovutils::setMdpFlags(mdpFlags, + ovutils::OV_MDP_SECURE_OVERLAY_SESSION); + } + + ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF; + if (ctx->numHwLayers == 1) { + isFgFlag = ovutils::IS_FG_SET; + } + + ovutils::PipeArgs parg(mdpFlags, + info, + ovutils::ZORDER_0, + isFgFlag, + ovutils::ROT_FLAG_DISABLED); + ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; + ov.setSource(pargs, ovutils::OV_PIPE1); + + hwc_rect_t sourceCrop = layer->sourceCrop; + // x,y,w,h + ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, + sourceCrop.right - sourceCrop.left, + sourceCrop.bottom - sourceCrop.top); + //Only for External + ov.setCrop(dcrop, ovutils::OV_PIPE1); + + // FIXME: Use source orientation for TV when source is portrait + //Only for External + ov.setTransform(0, ovutils::OV_PIPE1); + + ovutils::Dim dpos; + hwc_rect_t displayFrame = layer->displayFrame; + dpos.x = displayFrame.left; + dpos.y = displayFrame.top; + dpos.w = (displayFrame.right - displayFrame.left); + dpos.h = (displayFrame.bottom - displayFrame.top); + + //Only for External + ov.setPosition(dpos, ovutils::OV_PIPE1); + + if (!ov.commit(ovutils::OV_PIPE1)) { + ALOGE("%s: commit fails", __FUNCTION__); + return false; + } + return true; +} + +bool configExtCC(hwc_context_t *ctx, hwc_layer_t *layer) { + if(layer == NULL) + return true; + + overlay::Overlay& ov = *(ctx->mOverlay); + private_handle_t *hnd = (private_handle_t *)layer->handle; + ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); + ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF; + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; + ovutils::PipeArgs parg(mdpFlags, + info, + ovutils::ZORDER_1, + isFgFlag, + ovutils::ROT_FLAG_DISABLED); + ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; + ov.setSource(pargs, ovutils::OV_PIPE2); + + hwc_rect_t sourceCrop = layer->sourceCrop; + // x,y,w,h + ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, + sourceCrop.right - sourceCrop.left, + sourceCrop.bottom - sourceCrop.top); + //Only for External + ov.setCrop(dcrop, ovutils::OV_PIPE2); + + // FIXME: Use source orientation for TV when source is portrait + //Only for External + ov.setTransform(0, ovutils::OV_PIPE2); + + //Setting position same as crop + //FIXME stretch to full screen + ov.setPosition(dcrop, ovutils::OV_PIPE2); + + if (!ov.commit(ovutils::OV_PIPE2)) { + ALOGE("%s: commit fails", __FUNCTION__); + return false; + } + return true; +} + +bool VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_t *yuvLayer, + hwc_layer_t *ccLayer) { + + bool ret = true; + if (LIKELY(ctx->mOverlay)) { + overlay::Overlay& ov = *(ctx->mOverlay); + // Set overlay state + ov.setState(sState); + switch(sState) { + case ovutils::OV_2D_VIDEO_ON_PANEL: + ret &= configPrimVid(ctx, yuvLayer); + break; + case ovutils::OV_2D_VIDEO_ON_PANEL_TV: + ret &= configExtVid(ctx, yuvLayer); + ret &= configExtCC(ctx, ccLayer); + ret &= configPrimVid(ctx, yuvLayer); + break; + case ovutils::OV_2D_VIDEO_ON_TV: + ret &= configExtVid(ctx, yuvLayer); + ret &= configExtCC(ctx, ccLayer); + break; + default: + return false; + } + } else { + //Ov null + return false; + } + return ret; } bool VideoOverlay::draw(hwc_context_t *ctx, hwc_layer_list_t *list) @@ -198,48 +311,68 @@ bool VideoOverlay::draw(hwc_context_t *ctx, hwc_layer_list_t *list) return true; } - private_handle_t *hnd = - (private_handle_t *)list->hwLayers[sYuvLayerIndex].handle; + private_handle_t *hnd = (private_handle_t *) + list->hwLayers[sYuvLayerIndex].handle; + + private_handle_t *cchnd = NULL; + if(sCCLayerIndex != -1) { + cchnd = (private_handle_t *)list->hwLayers[sCCLayerIndex].handle; + ctx->qbuf->lockAndAdd(cchnd); + } // Lock this buffer for read. ctx->qbuf->lockAndAdd(hnd); + bool ret = true; overlay::Overlay& ov = *(ctx->mOverlay); ovutils::eOverlayState state = ov.getState(); switch (state) { case ovutils::OV_2D_VIDEO_ON_PANEL_TV: - case ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: // Play external if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) { ALOGE("%s: queueBuffer failed for external", __FUNCTION__); ret = false; } - + //Play CC on external + if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset, + ovutils::OV_PIPE2)) { + ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__); + ret = false; + } // Play primary if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) { ALOGE("%s: queueBuffer failed for primary", __FUNCTION__); ret = false; } - - // Wait for external vsync to be done - if (!ov.waitForVsync(ovutils::OV_PIPE1)) { - ALOGE("%s: waitForVsync failed for external", __FUNCTION__); + break; + case ovutils::OV_2D_VIDEO_ON_PANEL: + // Play primary + if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) { + ALOGE("%s: queueBuffer failed for primary", __FUNCTION__); + ret = false; + } + break; + case ovutils::OV_2D_VIDEO_ON_TV: + // Play external + if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) { + ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + ret = false; + } + //Play CC on external + if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset, + ovutils::OV_PIPE2)) { + ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__); ret = false; } break; default: - // In most cases, displaying only to one (primary or external) - // so use OV_PIPE_ALL since overlay will ignore NullPipes - if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE_ALL)) { - ALOGE("%s: queueBuffer failed", __FUNCTION__); - ret = false; - } + ALOGE("%s Unused state %s", __FUNCTION__, + ovutils::getStateString(state)); break; } return ret; } - }; //namespace qhwc diff --git a/libhwcomposer/hwc_video.h b/libhwcomposer/hwc_video.h index c6c6c22..62a32a9 100644 --- a/libhwcomposer/hwc_video.h +++ b/libhwcomposer/hwc_video.h @@ -30,12 +30,16 @@ public: //Draws layer if this feature is on static bool draw(hwc_context_t *ctx, hwc_layer_list_t *list); //Receives data from hwc - static void setStats(int yuvCount, int yuvLayerIndex, bool isYuvLayerSkip); + static void setStats(int yuvCount, int yuvLayerIndex, bool isYuvLayerSkip, + int ccLayerIndex); + //resets values + static void reset(); private: //Choose an appropriate overlay state based on conditions static void chooseState(hwc_context_t *ctx); - //Configures overlay - static bool configure(hwc_context_t *ctx, hwc_layer_t *layer); + //Configures overlay for video prim and ext + static bool configure(hwc_context_t *ctx, hwc_layer_t *yuvlayer, + hwc_layer_t *ccLayer); //Marks layer flags if this feature is used static void markFlags(hwc_layer_t *layer); //returns yuv count @@ -48,20 +52,30 @@ private: //Index of YUV layer, relevant only if count is 1 static int sYuvLayerIndex; //Flags if a yuv layer is animating or below something that is animating - static bool sIsLayerSkip; + static bool sIsYuvLayerSkip; + //Holds the closed caption layer index, -1 by default + static int sCCLayerIndex; //Flags if this feature is on. static bool sIsModeOn; }; inline void VideoOverlay::setStats(int yuvCount, int yuvLayerIndex, - bool isYuvLayerSkip) { + bool isYuvLayerSkip, int ccLayerIndex) { sYuvCount = yuvCount; sYuvLayerIndex = yuvLayerIndex; - sIsLayerSkip = isYuvLayerSkip; + sIsYuvLayerSkip = isYuvLayerSkip; + sCCLayerIndex = ccLayerIndex; } inline int VideoOverlay::getYuvCount() { return sYuvCount; } - +inline void VideoOverlay::reset() { + sYuvCount = 0; + sYuvLayerIndex = -1; + sIsYuvLayerSkip = false; + sCCLayerIndex = -1; + sIsModeOn = false; + sState = ovutils::OV_CLOSED; +} }; //namespace qhwc #endif //HWC_VIDEO_H diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk index 67bb85f..bb83111 100644 --- a/liboverlay/Android.mk +++ b/liboverlay/Android.mk @@ -13,7 +13,6 @@ LOCAL_SRC_FILES := \ overlayCtrl.cpp \ overlayUtils.cpp \ overlayMdp.cpp \ - overlayRotator.cpp \ - overlayTransitions.cpp + overlayRotator.cpp include $(BUILD_SHARED_LIBRARY) diff --git a/liboverlay/mdpWrapper.h b/liboverlay/mdpWrapper.h index 8c5f624..b1eb76c 100644 --- a/liboverlay/mdpWrapper.h +++ b/liboverlay/mdpWrapper.h @@ -75,9 +75,6 @@ bool getOverlay(int fd, mdp_overlay& ov); /* MSMFB_OVERLAY_PLAY */ bool play(int fd, msmfb_overlay_data& od); -/* MSMFB_OVERLAY_PLAY_WAIT */ -bool waitForVsync(int fd, msmfb_overlay_data& od); - /* MSMFB_OVERLAY_3D */ bool set3D(int fd, msmfb_overlay_3d& ov); @@ -191,15 +188,6 @@ inline bool play(int fd, msmfb_overlay_data& od) { return true; } -inline bool waitForVsync(int fd, msmfb_overlay_data& od) { - if (ioctl(fd, MSMFB_OVERLAY_PLAY_WAIT, &od) < 0) { - ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY_WAIT err=%s", - strerror(errno)); - return false; - } - return true; -} - inline bool set3D(int fd, msmfb_overlay_3d& ov) { if (ioctl(fd, MSMFB_OVERLAY_3D, &ov) < 0) { ALOGE("Failed to call ioctl MSMFB_OVERLAY_3D err=%s", diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp index a05a307..3fdb7c4 100644 --- a/liboverlay/overlay.cpp +++ b/liboverlay/overlay.cpp @@ -36,6 +36,35 @@ namespace overlay { +//Helper +bool isStateValid(const utils::eOverlayState& st) { + switch (st) { + case utils::OV_CLOSED: + ALOGE("Overlay %s failed, state is OV_CLOSED; set state first", + __FUNCTION__); + return false; + break; + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_2D_VIDEO_ON_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + case utils::OV_DUAL_DISP: + break; + default: + OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + return false; + } + return true; +} + Overlay::Overlay(): mOv(0) { } @@ -51,26 +80,11 @@ bool Overlay::commit(utils::eDest dest) "%s Overlay and Rotator should be init at this point", __FUNCTION__); utils::eOverlayState st = mState.state(); - switch (st) { - case utils::OV_2D_VIDEO_ON_PANEL: - case utils::OV_2D_VIDEO_ON_PANEL_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - case utils::OV_UI_MIRROR: - case utils::OV_2D_TRUE_UI_MIRROR: - case utils::OV_BYPASS_1_LAYER: - case utils::OV_BYPASS_2_LAYER: - case utils::OV_BYPASS_3_LAYER: - if(!mOv->commit(dest)) { - ALOGE("Overlay %s failed", __FUNCTION__); - return false; - } - break; - default: - OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + if(isStateValid(st)) { + if(!mOv->commit(dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); return false; + } } return true; } @@ -82,56 +96,11 @@ bool Overlay::queueBuffer(int fd, uint32_t offset, "%s Overlay and Rotator should be init at this point", __FUNCTION__); utils::eOverlayState st = mState.state(); - switch (st) { - case utils::OV_2D_VIDEO_ON_PANEL: - case utils::OV_2D_VIDEO_ON_PANEL_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - case utils::OV_UI_MIRROR: - case utils::OV_2D_TRUE_UI_MIRROR: - case utils::OV_BYPASS_1_LAYER: - case utils::OV_BYPASS_2_LAYER: - case utils::OV_BYPASS_3_LAYER: - if(!mOv->queueBuffer(fd, offset, dest)) { - ALOGE("Overlay %s failed", __FUNCTION__); - return false; - } - break; - default: - OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); - return false; - } - return true; -} - -bool Overlay::waitForVsync(utils::eDest dest) -{ - OVASSERT(mOv, - "%s Overlay and Rotator should be init at this point", - __FUNCTION__); - utils::eOverlayState st = mState.state(); - switch (st) { - case utils::OV_2D_VIDEO_ON_PANEL: - case utils::OV_2D_VIDEO_ON_PANEL_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - case utils::OV_UI_MIRROR: - case utils::OV_2D_TRUE_UI_MIRROR: - case utils::OV_BYPASS_1_LAYER: - case utils::OV_BYPASS_2_LAYER: - case utils::OV_BYPASS_3_LAYER: - if(!mOv->waitForVsync(dest)) { - ALOGE("Overlay %s failed", __FUNCTION__); - return false; - } - break; - default: - OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + if(isStateValid(st)) { + if(!mOv->queueBuffer(fd, offset, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); return false; + } } return true; } @@ -143,26 +112,11 @@ bool Overlay::setCrop(const utils::Dim& d, "%s Overlay and Rotator should be init at this point", __FUNCTION__); utils::eOverlayState st = mState.state(); - switch (st) { - case utils::OV_2D_VIDEO_ON_PANEL: - case utils::OV_2D_VIDEO_ON_PANEL_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - case utils::OV_UI_MIRROR: - case utils::OV_2D_TRUE_UI_MIRROR: - case utils::OV_BYPASS_1_LAYER: - case utils::OV_BYPASS_2_LAYER: - case utils::OV_BYPASS_3_LAYER: - if(!mOv->setCrop(d, dest)) { - ALOGE("Overlay %s failed", __FUNCTION__); - return false; - } - break; - default: - OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + if(isStateValid(st)) { + if(!mOv->setCrop(d, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); return false; + } } return true; } @@ -173,26 +127,11 @@ bool Overlay::setPosition(const utils::Dim& d, "%s Overlay and Rotator should be init at this point", __FUNCTION__); utils::eOverlayState st = mState.state(); - switch (st) { - case utils::OV_2D_VIDEO_ON_PANEL: - case utils::OV_2D_VIDEO_ON_PANEL_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - case utils::OV_UI_MIRROR: - case utils::OV_2D_TRUE_UI_MIRROR: - case utils::OV_BYPASS_1_LAYER: - case utils::OV_BYPASS_2_LAYER: - case utils::OV_BYPASS_3_LAYER: - if(!mOv->setPosition(d, dest)) { - ALOGE("Overlay %s failed", __FUNCTION__); - return false; - } - break; - default: - OVASSERT(false, "setPos Unknown state %d", st); + if(isStateValid(st)) { + if(!mOv->setPosition(d, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); return false; + } } return true; } @@ -204,26 +143,11 @@ bool Overlay::setTransform(const int orient, static_cast(orient); utils::eOverlayState st = mState.state(); - switch (st) { - case utils::OV_2D_VIDEO_ON_PANEL: - case utils::OV_2D_VIDEO_ON_PANEL_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - case utils::OV_UI_MIRROR: - case utils::OV_2D_TRUE_UI_MIRROR: - case utils::OV_BYPASS_1_LAYER: - case utils::OV_BYPASS_2_LAYER: - case utils::OV_BYPASS_3_LAYER: - if(!mOv->setTransform(transform, dest)) { - ALOGE("Overlay %s failed", __FUNCTION__); - return false; - } - break; - default: - OVASSERT(false, "%s Unknown state %d", __FUNCTION__ , st); + if(isStateValid(st)) { + if(!mOv->setTransform(transform, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); return false; + } } return true; } @@ -235,38 +159,12 @@ bool Overlay::setSource(const utils::PipeArgs args[utils::MAX_PIPES], args[0], args[1], args[2] }; utils::eOverlayState st = mState.state(); - switch (st) { - case utils::OV_CLOSED: - ALOGE("Overlay %s failed, state is OV_CLOSED, set state first", - __FUNCTION__); - return false; - break; - case utils::OV_2D_VIDEO_ON_PANEL: - case utils::OV_3D_VIDEO_ON_2D_PANEL: - case utils::OV_UI_MIRROR: - case utils::OV_BYPASS_1_LAYER: - case utils::OV_BYPASS_2_LAYER: - case utils::OV_BYPASS_3_LAYER: - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - case utils::OV_3D_VIDEO_ON_3D_TV: - //TODO set zorder for channel 1 as 1 in 3D pipe - case utils::OV_2D_VIDEO_ON_PANEL_TV: - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - break; - case utils::OV_2D_TRUE_UI_MIRROR: - // TODO Set zorder, external VG pipe (video) gets 0, RGB pipe (UI) gets 1 - break; - default: - OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + if(isStateValid(st)) { + if (!mOv->setSource(margs, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); return false; + } } - - if (!mOv->setSource(margs, dest)) { - ALOGE("Overlay %s failed", __FUNCTION__); - return false; - } - return true; } diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h index b3324eb..12b3883 100644 --- a/liboverlay/overlay.h +++ b/liboverlay/overlay.h @@ -57,7 +57,6 @@ public: bool queueBuffer(int fd, uint32_t offset, utils::eDest dest = utils::OV_PIPE_ALL); - bool waitForVsync(utils::eDest dest = utils::OV_PIPE1); void dump() const; diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h index 1398ec4..3c7eb42 100644 --- a/liboverlay/overlayCtrlData.h +++ b/liboverlay/overlayCtrlData.h @@ -119,9 +119,6 @@ public: /* queue buffer to the overlay */ bool queueBuffer(int fd, uint32_t offset); - /* wait for vsync to be done */ - bool waitForVsync(); - /* sump the state of the obj */ void dump() const; @@ -218,15 +215,6 @@ inline bool Data::queueBuffer(int fd, uint32_t offset) { return mMdp.play(fd, offset); } -inline bool Data::waitForVsync() { - // Call mdp waitForVsync - if(!mMdp.waitForVsync()){ - ALOGE("Error in MDP %s", __FUNCTION__); - return false; - } - return true; -} - inline void Data::dump() const { ALOGE("== Dump Data MDP start =="); mMdp.dump(); diff --git a/liboverlay/overlayImpl.h b/liboverlay/overlayImpl.h index 6f950c0..1d22694 100644 --- a/liboverlay/overlayImpl.h +++ b/liboverlay/overlayImpl.h @@ -72,9 +72,6 @@ public: virtual bool queueBuffer(int fd, uint32_t offset, utils::eDest dest = utils::OV_PIPE_ALL) = 0; - /* Wait for vsync to be done on dest */ - virtual bool waitForVsync(utils::eDest dest = utils::OV_PIPE1) = 0; - /* Crop existing destination using Dim coordinates */ virtual bool setCrop(const utils::Dim& d, utils::eDest dest = utils::OV_PIPE_ALL) = 0; @@ -92,9 +89,6 @@ public: virtual bool setSource(const utils::PipeArgs[utils::MAX_PIPES], utils::eDest dest = utils::OV_PIPE_ALL) = 0; - /* Get the overlay pipe type */ - virtual utils::eOverlayPipeType getOvPipeType(utils::eDest dest) const = 0; - /* Dump underlying state */ virtual void dump() const = 0; }; @@ -110,11 +104,6 @@ public: bool setTransform(const utils::eTransform& param) { return true; } bool setSource(const utils::PipeArgs& args) { return true; } bool queueBuffer(int fd, uint32_t offset) { return true; } - bool waitForVsync() { return true; } - // NullPipe will return by val here as opposed to other Pipes. - utils::eOverlayPipeType getOvPipeType() const { - return utils::OV_PIPE_TYPE_NULL; - } void dump() const {} }; @@ -157,8 +146,6 @@ public: utils::eDest dest = utils::OV_PIPE_ALL); virtual bool queueBuffer(int fd, uint32_t offset, utils::eDest dest = utils::OV_PIPE_ALL); - virtual bool waitForVsync(utils::eDest dest = utils::OV_PIPE1); - virtual utils::eOverlayPipeType getOvPipeType(utils::eDest dest) const; virtual void dump() const; private: @@ -615,63 +602,6 @@ bool OverlayImpl::queueBuffer(int fd, uint32_t offset, return true; } -template -bool OverlayImpl::waitForVsync(utils::eDest dest) -{ - OVASSERT(mPipe0 && mPipe1 && mPipe2, - "%s: Pipes are null p0=%p p1=%p p2=%p", - __FUNCTION__, mPipe0, mPipe1, mPipe2); - - if (utils::OV_PIPE0 & dest) { - if(!mPipe0->waitForVsync()) { - ALOGE("OverlayImpl p0 failed to waitForVsync"); - return false; - } - } - - if (utils::OV_PIPE1 & dest) { - if(!mPipe1->waitForVsync()) { - ALOGE("OverlayImpl p1 failed to waitForVsync"); - return false; - } - } - - if (utils::OV_PIPE2 & dest) { - if(!mPipe2->waitForVsync()) { - ALOGE("OverlayImpl p2 failed to waitForVsync"); - return false; - } - } - - return true; -} - -template -utils::eOverlayPipeType OverlayImpl::getOvPipeType( - utils::eDest dest) const -{ - OVASSERT(utils::isValidDest(dest), "%s: OverlayImpl invalid dest=%d", - __FUNCTION__, dest); - - if (utils::OV_PIPE0 & dest) { - OVASSERT(mPipe0, "%s: OverlayImpl pipe0 is null", __FUNCTION__); - return mPipe0->getOvPipeType(); - } - - if (utils::OV_PIPE1 & dest) { - OVASSERT(mPipe1, "%s: OverlayImpl pipe1 is null", __FUNCTION__); - return mPipe1->getOvPipeType(); - } - - if (utils::OV_PIPE2 & dest) { - OVASSERT(mPipe2, "%s: OverlayImpl pipe2 is null", __FUNCTION__); - return mPipe2->getOvPipeType(); - } - - // Should never get here - return utils::OV_PIPE_TYPE_NULL; -} - template void OverlayImpl::dump() const { diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h index 30bda79..1ccd64b 100644 --- a/liboverlay/overlayMdp.h +++ b/liboverlay/overlayMdp.h @@ -221,9 +221,6 @@ public: /* calls wrapper play */ bool play(int fd, uint32_t offset); - /* calls wrapper waitForVsync */ - bool waitForVsync(); - /* dump state of the object */ void dump() const; private: @@ -493,15 +490,6 @@ inline bool MdpData::play(int fd, uint32_t offset) { return true; } -inline bool MdpData::waitForVsync() { - if(!mdp_wrapper::waitForVsync(mFd.getFD(), mOvData)){ - ALOGE("%s failed", __FUNCTION__); - dump(); - return false; - } - return true; -} - } // overlay #endif // OVERLAY_MDP_H diff --git a/liboverlay/overlayMem.h b/liboverlay/overlayMem.h index f8109d1..60ed8fe 100644 --- a/liboverlay/overlayMem.h +++ b/liboverlay/overlayMem.h @@ -94,12 +94,11 @@ private: uint32_t mNumBuffers; /* gralloc alloc controller */ - android::sp mAlloc; + gralloc::IAllocController* mAlloc; }; //-------------------Inlines----------------------------------- -using android::sp; using gralloc::IMemAlloc; using gralloc::alloc_data; @@ -109,7 +108,7 @@ inline OvMem::OvMem() { mAllocType = 0; mBufSz = 0; mNumBuffers = 0; - mAlloc = gralloc::IAllocController::getInstance(false); + mAlloc = gralloc::IAllocController::getInstance(); } inline OvMem::~OvMem() { } @@ -121,7 +120,6 @@ inline bool OvMem::open(uint32_t numbufs, int allocFlags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP; if(isSecure) { allocFlags |= GRALLOC_USAGE_PRIVATE_MM_HEAP; - allocFlags |= GRALLOC_USAGE_PRIVATE_DO_NOT_MAP; allocFlags |= GRALLOC_USAGE_PRIVATE_CP_BUFFER; } @@ -138,12 +136,22 @@ inline bool OvMem::open(uint32_t numbufs, data.align = getpagesize(); data.uncached = true; - err = mAlloc->allocate(data, allocFlags, 0); - if (err != 0) { - ALOGE("OvMem: error allocating memory"); + err = mAlloc->allocate(data, allocFlags); + //see if we can fallback to other heap + //we can try MM_HEAP once if it's not secure playback + if (err != 0 && !isSecure) { + allocFlags |= GRALLOC_USAGE_PRIVATE_MM_HEAP; + err = mAlloc->allocate(data, allocFlags); + if (err != 0) { + ALOGE(" could not allocate from fallback heap"); + return false; + } + } else if (err != 0) { + ALOGE("OvMem: error allocating memory can not fall back"); return false; } + mFd = data.fd; mBaseAddr = data.base; mAllocType = data.allocType; @@ -159,7 +167,7 @@ inline bool OvMem::close() return true; } - sp memalloc = mAlloc->getAllocator(mAllocType); + IMemAlloc* memalloc = mAlloc->getAllocator(mAllocType); ret = memalloc->free_buffer(mBaseAddr, mBufSz * mNumBuffers, 0, mFd); if (ret != 0) { ALOGE("OvMem: error freeing buffer"); diff --git a/liboverlay/overlayState.h b/liboverlay/overlayState.h index ea6860f..e4fbece 100644 --- a/liboverlay/overlayState.h +++ b/liboverlay/overlayState.h @@ -46,17 +46,15 @@ namespace overlay { class OverlayState : utils::NoCopy { public: - /**/ + /*ctor*/ explicit OverlayState(); - /**/ + /*dtor*/ ~OverlayState(); /* return current state */ utils::eOverlayState state() const; - /* Overlay Event */ - /* Hard reset to a new state. If the state is the same * as the current one, it would be a no-op */ OverlayImplBase* reset(utils::eOverlayState s); @@ -68,54 +66,31 @@ public: OverlayImplBase* handleEvent(utils::eOverlayState s, OverlayImplBase* ov); - /* Transitions from XXX to XXX */ - OverlayImplBase* handle_closed(utils::eOverlayState s); - OverlayImplBase* handle_2D_2DPanel(utils::eOverlayState s, - OverlayImplBase* ov); - OverlayImplBase* handle_2D_2DTV(utils::eOverlayState s, - OverlayImplBase* ov); - OverlayImplBase* handle_3D_2DPanel(utils::eOverlayState s, - OverlayImplBase* ov); - OverlayImplBase* handle_3D_3DPanel(utils::eOverlayState s, - OverlayImplBase* ov); - OverlayImplBase* handle_3D_3DTV(utils::eOverlayState s, - OverlayImplBase* ov); - OverlayImplBase* handle_3D_2DTV(utils::eOverlayState s, - OverlayImplBase* ov); - OverlayImplBase* handle_UI_Mirror(utils::eOverlayState s, - OverlayImplBase* ov); - OverlayImplBase* handle_2D_trueUI_Mirror(utils::eOverlayState s, - OverlayImplBase* ov); - OverlayImplBase* handle_bypass(utils::eOverlayState s, - OverlayImplBase* ov); - - /* Transition from any state to 2D video on 2D panel */ - OverlayImplBase* handle_xxx_to_2D_2DPanel(OverlayImplBase* ov); - - /* Transition from any state to 2D video on 2D panel and 2D TV */ - OverlayImplBase* handle_xxx_to_2D_2DTV(OverlayImplBase* ov); - - /* Transition from any state to 3D video on 2D panel */ - OverlayImplBase* handle_xxx_to_3D_2DPanel(OverlayImplBase* ov); - - /* Transition from any state to 3D video on 2D panel and 2D TV */ - OverlayImplBase* handle_xxx_to_3D_2DTV(OverlayImplBase* ov); - - /* Transition from any state to 2D video true UI mirroring (2D video + UI) */ - OverlayImplBase* handle_xxx_to_2D_trueUI_Mirror(OverlayImplBase* ov); - - /* Transitions from any state to 1 layer composition bypass */ - OverlayImplBase* handle_xxx_to_bypass1(OverlayImplBase* ov); - - /* Transitions from any state to 2 layers composition bypass */ - OverlayImplBase* handle_xxx_to_bypass2(OverlayImplBase* ov); - - /* Transitions from any state to 3 layers composition bypass */ - OverlayImplBase* handle_xxx_to_bypass3(OverlayImplBase* ov); - /* Dump */ void dump() const; + private: + + /* Transitions from a state to a state. Default behavior is to move from an + * old state to CLOSED and from CLOSED to a new state. Any impl wishing to + * copy pipes should specialize this call */ + template + OverlayImplBase* handle_from_to(OverlayImplBase* ov); + + /* Just a convenient intermediate function to bring down the number of + * combinations arising from multiple states */ + template + OverlayImplBase* handle_from(utils::eOverlayState toState, + OverlayImplBase* ov); + + /* Substitues for partially specialized templated handle functions since the + * standard doesn't allow partial specialization of functions */ + template + OverlayImplBase* handle_xxx_to_CLOSED(OverlayImplBase* ov); + + template + OverlayImplBase* handle_CLOSED_to_xxx(OverlayImplBase* ov); + /* States here */ utils::eOverlayState mState; }; @@ -133,7 +108,7 @@ template struct StateTraits {}; template <> struct StateTraits { - typedef overlay::GenericPipe pipe0; + typedef overlay::GenericPipe pipe0; //prim video typedef overlay::NullPipe pipe1; // place holder typedef overlay::NullPipe pipe2; // place holder @@ -141,20 +116,33 @@ template <> struct StateTraits typedef NullRotator rot1; typedef NullRotator rot2; - typedef overlay::OverlayImpl ovimpl; + typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits { - typedef overlay::GenericPipe pipe0; - typedef overlay::VideoExtPipe pipe1; - typedef overlay::NullPipe pipe2; // place holder + typedef overlay::GenericPipe pipe0; //prim video + typedef overlay::VideoExtPipe pipe1; //ext video + typedef overlay::GenericPipe pipe2; //ext subtitle typedef Rotator rot0; typedef Rotator rot1; typedef NullRotator rot2; - typedef overlay::OverlayImpl ovimpl; + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::NullPipe pipe0; //nothing on primary with mdp + typedef overlay::VideoExtPipe pipe1; //ext video + typedef overlay::GenericPipe pipe2; //ext subtitle + + typedef NullRotator rot0; + typedef Rotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits @@ -219,7 +207,7 @@ template <> struct StateTraits typedef NullRotator rot1; typedef NullRotator rot2; - typedef overlay::OverlayImpl ovimpl; + typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits @@ -245,7 +233,7 @@ template <> struct StateTraits typedef NullRotator rot1; typedef NullRotator rot2; - typedef overlay::OverlayImpl ovimpl; + typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits @@ -258,7 +246,7 @@ template <> struct StateTraits typedef NullRotator rot1; typedef NullRotator rot2; - typedef overlay::OverlayImpl ovimpl; + typedef overlay::OverlayImpl ovimpl; }; template <> struct StateTraits @@ -274,47 +262,197 @@ template <> struct StateTraits typedef overlay::OverlayImpl ovimpl; }; +template <> struct StateTraits +{ + typedef overlay::GenericPipe pipe0; + typedef overlay::NullPipe pipe1; + typedef overlay::NullPipe pipe2; + + typedef NullRotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + //------------------------Inlines -------------------------------- -inline OverlayState::OverlayState() : mState(utils::OV_CLOSED) -{} +inline OverlayState::OverlayState() : mState(utils::OV_CLOSED){} inline OverlayState::~OverlayState() {} - -inline utils::eOverlayState OverlayState::state() const -{ - return mState; -} - -inline OverlayImplBase* OverlayState::reset(utils::eOverlayState s) -{ +inline utils::eOverlayState OverlayState::state() const { return mState; } +inline OverlayImplBase* OverlayState::reset(utils::eOverlayState s) { return handleEvent(s, 0); } - -inline void OverlayState::dump() const -{ +inline void OverlayState::dump() const { ALOGE("== Dump state %d start/end ==", mState); } -template -inline OverlayImplBase* handle_closed_to_xxx() +inline OverlayImplBase* OverlayState::handleEvent(utils::eOverlayState toState, + OverlayImplBase* ov) { - OverlayImplBase* ov = new typename StateTraits::ovimpl; - RotatorBase* rot0 = new typename StateTraits::rot0; - RotatorBase* rot1 = new typename StateTraits::rot1; - RotatorBase* rot2 = new typename StateTraits::rot2; + OverlayImplBase* newov = ov; // at least, we return the same + if (mState != toState) { + ALOGD_IF(DEBUG_OVERLAY, "%s: state changed %s-->%s", + __FUNCTION__, getStateString(mState), getStateString(toState)); + } else { + ALOGD_IF(DEBUG_OVERLAY, "%s: no state change, state=%s", + __FUNCTION__, getStateString(toState)); + return newov; + } + + switch(mState) + { + case utils::OV_CLOSED: + newov = handle_from(toState, ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_from(toState, ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_from(toState, ov); + break; + case utils::OV_2D_VIDEO_ON_TV: + newov = handle_from(toState, ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_from(toState, ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_from(toState, ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_from(toState, ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_from(toState, + ov); + break; + case utils::OV_UI_MIRROR: + newov = handle_from(toState, ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_from(toState, ov); + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_from(toState, ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_from(toState, ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_from(toState, ov); + break; + case utils::OV_DUAL_DISP: + newov = handle_from(toState, ov); + break; + default: + OVASSERT(1 == 0, "%s: unknown state = %d", __FUNCTION__, mState); + + } + return newov; +} + +template +inline OverlayImplBase* OverlayState::handle_from(utils::eOverlayState toState, + OverlayImplBase* ov) { + + switch(toState) + { + case utils::OV_CLOSED: + ov = handle_xxx_to_CLOSED(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + ov = handle_from_to(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + ov = handle_from_to(ov); + break; + case utils::OV_2D_VIDEO_ON_TV: + ov = handle_from_to(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + ov = handle_from_to(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + ov = handle_from_to(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + ov = handle_from_to(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + ov = handle_from_to(ov); + break; + case utils::OV_UI_MIRROR: + ov = handle_from_to(ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + ov = handle_from_to(ov); + break; + case utils::OV_BYPASS_1_LAYER: + ov = handle_from_to(ov); + break; + case utils::OV_BYPASS_2_LAYER: + ov = handle_from_to(ov); + break; + case utils::OV_BYPASS_3_LAYER: + ov = handle_from_to(ov); + break; + case utils::OV_DUAL_DISP: + ov = handle_from_to(ov); + break; + default: + OVASSERT(1 == 0, "%s: unknown state = %d", __FUNCTION__, toState); + } + mState = toState; + return ov; +} + + +/* Transition default from any to any. Does in two steps. + * Moves from OLD to CLOSED and then from CLOSED to NEW + */ +template +inline OverlayImplBase* OverlayState::handle_from_to(OverlayImplBase* ov) { + handle_xxx_to_CLOSED(ov); + return handle_CLOSED_to_xxx(ov); +} + +//---------------Specializations------------- + + +/* Transition from CLOSED to ANY */ +template +inline OverlayImplBase* OverlayState::handle_CLOSED_to_xxx( + OverlayImplBase* /*ignored*/) { + //If going from CLOSED to CLOSED, nothing to do. + if(TO_STATE == utils::OV_CLOSED) return NULL; + ALOGD("FROM_STATE = %s TO_STATE = %s", + utils::getStateString(utils::OV_CLOSED), + utils::getStateString(TO_STATE)); + OverlayImplBase* ov = new typename StateTraits::ovimpl; + RotatorBase* rot0 = new typename StateTraits::rot0; + RotatorBase* rot1 = new typename StateTraits::rot1; + RotatorBase* rot2 = new typename StateTraits::rot2; if(!ov->init(rot0, rot1, rot2)) { - ALOGE("Overlay failed to init in state %d", STATE); + ALOGE("Overlay failed to init in state %d", TO_STATE); return 0; } return ov; } -inline OverlayImplBase* handle_xxx_to_closed(OverlayImplBase* ov) +/* Transition from ANY to CLOSED */ +template +inline OverlayImplBase* OverlayState::handle_xxx_to_CLOSED(OverlayImplBase* ov) { + //If going from CLOSED to CLOSED, nothing to do. + if(FROM_STATE == utils::OV_CLOSED) return NULL; + ALOGD("FROM_STATE = %s TO_STATE = %s", + utils::getStateString(FROM_STATE), + utils::getStateString(utils::OV_CLOSED)); OVASSERT(ov, "%s: ov is null", __FUNCTION__); - if(!ov->close()) { ALOGE("%s: Failed to ov close", __FUNCTION__); } @@ -323,580 +461,125 @@ inline OverlayImplBase* handle_xxx_to_closed(OverlayImplBase* ov) return 0; } -/* Hard transitions from any state to any state will close and then init */ -template -inline OverlayImplBase* handle_xxx_to_xxx(OverlayImplBase* ov) -{ +/* Transition from 2D_VIDEO_ON_PANEL to 2D_VIDEO_ON_PANEL_TV */ +template<> +inline OverlayImplBase* OverlayState::handle_from_to< + utils::OV_2D_VIDEO_ON_PANEL, + utils::OV_2D_VIDEO_ON_PANEL_TV>( + OverlayImplBase* ov) { OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGD("FROM_STATE = %s TO_STATE = %s", + utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL), + utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL_TV)); + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; - handle_xxx_to_closed(ov); - return handle_closed_to_xxx(); -} - -inline OverlayImplBase* OverlayState::handleEvent(utils::eOverlayState newState, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; // at least, we return the same - if (mState != newState) { - ALOGE_IF(DEBUG_OVERLAY, "%s: state changed %s-->%s", - __FUNCTION__, getStateString(mState), getStateString(newState)); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: no state change, state=%s", - __FUNCTION__, getStateString(newState)); - return newov; - } - - switch(mState) - { - case utils::OV_CLOSED: - newov = handle_closed(newState); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - newov = handle_2D_2DPanel(newState, ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - newov = handle_2D_2DTV(newState, ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - newov = handle_3D_2DPanel(newState, ov); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - newov = handle_3D_3DPanel(newState, ov); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - newov = handle_3D_3DTV(newState, ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - newov = handle_3D_2DTV(newState, ov); - break; - case utils::OV_UI_MIRROR: - newov = handle_UI_Mirror(newState, ov); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - newov = handle_2D_trueUI_Mirror(newState, ov); - break; - case utils::OV_BYPASS_1_LAYER: - case utils::OV_BYPASS_2_LAYER: - case utils::OV_BYPASS_3_LAYER: - newov = handle_bypass(newState, ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, mState); - } - - // FIXME, how to communicate bad transition? - // Should we have bool returned from transition func? - // This is also a very good interview question. - + //copy pipe0/rot0 (primary video) + newov->copyOvPipe(ov, utils::OV_PIPE0); + //close old pipe1, create new pipe1 + ov->closePipe(utils::OV_PIPE1); + RotatorBase* rot1 = new NewState::rot1; + newov->initPipe(rot1, utils::OV_PIPE1); + //close old pipe2, create new pipe2 + ov->closePipe(utils::OV_PIPE2); + RotatorBase* rot2 = new NewState::rot2; + newov->initPipe(rot2, utils::OV_PIPE2); + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; return newov; } -// Transitions from closed to XXX -inline OverlayImplBase* OverlayState::handle_closed(utils::eOverlayState s) -{ - OverlayImplBase* ov = 0; - switch(s) - { - case utils::OV_CLOSED: - // no state change - break; - case utils::OV_2D_VIDEO_ON_PANEL: - ov = handle_closed_to_xxx(); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - ov = handle_closed_to_xxx(); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - ov = handle_closed_to_xxx(); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - ov = handle_closed_to_xxx(); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - ov = handle_closed_to_xxx(); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - ov = handle_closed_to_xxx(); - break; - case utils::OV_UI_MIRROR: - ov = handle_closed_to_xxx(); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - ov = handle_closed_to_xxx(); - break; - case utils::OV_BYPASS_1_LAYER: - ov = handle_closed_to_xxx(); - break; - case utils::OV_BYPASS_2_LAYER: - ov = handle_closed_to_xxx(); - break; - case utils::OV_BYPASS_3_LAYER: - ov = handle_closed_to_xxx(); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; - return ov; -} +/* Transition from 2D_VIDEO_ON_PANEL_TV to 2D_VIDEO_ON_PANEL */ +template<> +inline OverlayImplBase* OverlayState::handle_from_to< + utils::OV_2D_VIDEO_ON_PANEL_TV, + utils::OV_2D_VIDEO_ON_PANEL>( + OverlayImplBase* ov) { + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGD("FROM_STATE = %s TO_STATE = %s", + utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL_TV), + utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL)); -// Transitions from 2D video on 2D panel to XXX -inline OverlayImplBase* OverlayState::handle_2D_2DPanel( - utils::eOverlayState s, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; - switch(s) - { - case utils::OV_CLOSED: - newov = handle_xxx_to_closed(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - // no state change - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - newov = handle_xxx_to_2D_2DTV(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - newov = handle_xxx_to_2D_trueUI_Mirror(ov); - break; - case utils::OV_BYPASS_1_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_2_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_3_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //copy pipe0/rot0 (primary video) + newov->copyOvPipe(ov, utils::OV_PIPE0); + //close old pipe1, create new pipe1 + ov->closePipe(utils::OV_PIPE1); + RotatorBase* rot1 = new NewState::rot1; + newov->initPipe(rot1, utils::OV_PIPE1); + //close old pipe2, create new pipe2 + ov->closePipe(utils::OV_PIPE2); + RotatorBase* rot2 = new NewState::rot2; + newov->initPipe(rot2, utils::OV_PIPE2); + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; return newov; } -// Transitions from 2D video on 2D panel and 2D TV to XXX -inline OverlayImplBase* OverlayState::handle_2D_2DTV( - utils::eOverlayState s, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; - switch(s) - { - case utils::OV_CLOSED: - newov = handle_xxx_to_closed(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - newov = handle_xxx_to_2D_2DPanel(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - // no state change - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - newov = handle_xxx_to_2D_trueUI_Mirror(ov); - break; - case utils::OV_BYPASS_1_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_2_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_3_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; +/* Transition from 2D_VIDEO_ON_PANEL_TV to 2D_VIDEO_ON_TV */ +template<> +inline OverlayImplBase* OverlayState::handle_from_to< + utils::OV_2D_VIDEO_ON_PANEL_TV, + utils::OV_2D_VIDEO_ON_TV>( + OverlayImplBase* ov) { + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGD("FROM_STATE = %s TO_STATE = %s", + utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL_TV), + utils::getStateString(utils::OV_2D_VIDEO_ON_TV)); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //close old pipe0, create new pipe0 + ov->closePipe(utils::OV_PIPE0); + RotatorBase* rot0 = new NewState::rot0; + newov->initPipe(rot0, utils::OV_PIPE0); + //copy pipe1/rot1 (ext video) + newov->copyOvPipe(ov, utils::OV_PIPE1); + //copy pipe2/rot2 (ext cc) + newov->copyOvPipe(ov, utils::OV_PIPE2); + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; return newov; } -// Transitions from 3D video on 2D panel to XXX -inline OverlayImplBase* OverlayState::handle_3D_2DPanel( - utils::eOverlayState s, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; - switch(s) - { - case utils::OV_CLOSED: - newov = handle_xxx_to_closed(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - // no state change - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - newov = handle_xxx_to_3D_2DTV(ov); - break; - case utils::OV_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_1_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_2_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_3_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; +/* Transition from 2D_VIDEO_ON_TV to 2D_VIDEO_ON_PANEL_TV */ +template<> +inline OverlayImplBase* OverlayState::handle_from_to< + utils::OV_2D_VIDEO_ON_TV, + utils::OV_2D_VIDEO_ON_PANEL_TV>( + OverlayImplBase* ov) { + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGD("FROM_STATE = %s TO_STATE = %s", + utils::getStateString(utils::OV_2D_VIDEO_ON_TV), + utils::getStateString(utils::OV_2D_VIDEO_ON_PANEL_TV)); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //close old pipe0, create new pipe0 + ov->closePipe(utils::OV_PIPE0); + RotatorBase* rot0 = new NewState::rot0; + newov->initPipe(rot0, utils::OV_PIPE0); + //copy pipe1/rot1 (ext video) + newov->copyOvPipe(ov, utils::OV_PIPE1); + //copy pipe2/rot2 (ext cc) + newov->copyOvPipe(ov, utils::OV_PIPE2); + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; return newov; } -// Transitions from 3D video on 3D panel to XXX -inline OverlayImplBase* OverlayState::handle_3D_3DPanel( - utils::eOverlayState s, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; - switch(s) - { - case utils::OV_CLOSED: - newov = handle_xxx_to_closed(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - // no state change - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_1_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_2_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_3_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; - return newov; -} - -// Transitions from 3D video on 3D TV to XXX -inline OverlayImplBase* OverlayState::handle_3D_3DTV( - utils::eOverlayState s, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; - switch(s) - { - case utils::OV_CLOSED: - newov = handle_xxx_to_closed(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - // no state change - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_1_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_2_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_3_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; - return newov; -} - -// Transitions from 3D video on 2D panel and 2D TV to XXX -inline OverlayImplBase* OverlayState::handle_3D_2DTV( - utils::eOverlayState s, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; - switch(s) - { - case utils::OV_CLOSED: - newov = handle_xxx_to_closed(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - newov = handle_xxx_to_3D_2DPanel(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - // no state change - break; - case utils::OV_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_1_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_2_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_3_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; - return newov; -} - -// Transitions from UI mirroring to XXX -inline OverlayImplBase* OverlayState::handle_UI_Mirror(utils::eOverlayState s, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; - switch(s) - { - case utils::OV_CLOSED: - newov = handle_xxx_to_closed(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_UI_MIRROR: - // no state change - break; - case utils::OV_2D_TRUE_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_1_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_2_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_3_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; - return newov; -} - -// Transitions from 2D video true UI mirroring (2D video + UI) to XXX -inline OverlayImplBase* OverlayState::handle_2D_trueUI_Mirror(utils::eOverlayState s, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; - switch(s) - { - case utils::OV_CLOSED: - newov = handle_xxx_to_closed(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - newov = handle_xxx_to_2D_2DPanel(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - newov = handle_xxx_to_2D_2DTV(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - // no state change - break; - case utils::OV_BYPASS_1_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_2_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_3_LAYER: - newov = handle_xxx_to_xxx(ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; - return newov; -} - -// Transitions from composition bypass to XXX -inline OverlayImplBase* OverlayState::handle_bypass(utils::eOverlayState s, - OverlayImplBase* ov) -{ - OverlayImplBase* newov = ov; - switch(s) - { - case utils::OV_CLOSED: - newov = handle_xxx_to_closed(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_VIDEO_ON_PANEL_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_PANEL: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_3D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_2D_TRUE_UI_MIRROR: - newov = handle_xxx_to_xxx(ov); - break; - case utils::OV_BYPASS_1_LAYER: - newov = handle_xxx_to_bypass1(ov); - break; - case utils::OV_BYPASS_2_LAYER: - newov = handle_xxx_to_bypass2(ov); - break; - case utils::OV_BYPASS_3_LAYER: - newov = handle_xxx_to_bypass3(ov); - break; - default: - ALOGE("%s: unknown state=%d", __FUNCTION__, s); - } - mState = s; - return newov; -} - - } // overlay #endif // OVERLAY_STATE_H diff --git a/liboverlay/overlayTransitions.cpp b/liboverlay/overlayTransitions.cpp deleted file mode 100644 index 8096ad5..0000000 --- a/liboverlay/overlayTransitions.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* -* Copyright (c) 2012, 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 "overlayState.h" - -namespace overlay { - -/* - * Transition from any state to 2D video on 2D panel - */ -OverlayImplBase* OverlayState::handle_xxx_to_2D_2DPanel( - OverlayImplBase* ov) -{ - OVASSERT(ov, "%s: ov is null", __FUNCTION__); - ALOGE("%s", __FUNCTION__); - - // Create new ovimpl based on new state - typedef StateTraits NewState; - OverlayImplBase* newov = new NewState::ovimpl(); - - //=========================================================== - // For each pipe: - // - If pipe matches, copy from previous into new ovimpl - // - Otherwise init for new and delete from previous ovimpl - //=========================================================== - - // pipe0/rot0 (GenericPipe) - if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_GENERIC) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (GenericPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE0); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe0 (GenericPipe)", __FUNCTION__); - ov->closePipe(utils::OV_PIPE0); - RotatorBase* rot0 = new NewState::rot0; - newov->initPipe(rot0, utils::OV_PIPE0); - } - - // pipe1/rot1 (NullPipe) - if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_NULL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (NullPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE1); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe1 (NullPipe)", __FUNCTION__); - ov->closePipe(utils::OV_PIPE1); - RotatorBase* rot1 = new NewState::rot1; - newov->initPipe(rot1, utils::OV_PIPE1); - } - - // pipe2/rot2 (NullPipe) - if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE2); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe2 (NullPipe)", __FUNCTION__); - ov->closePipe(utils::OV_PIPE2); - RotatorBase* rot2 = new NewState::rot2; - newov->initPipe(rot2, utils::OV_PIPE2); - } - - // All pipes are copied or deleted so no more need for previous ovimpl - delete ov; - ov = 0; - - return newov; -} - -/* - * Transition from any state to 2D video on 2D panel and 2D TV - */ -OverlayImplBase* OverlayState::handle_xxx_to_2D_2DTV( - OverlayImplBase* ov) -{ - OVASSERT(ov, "%s: ov is null", __FUNCTION__); - ALOGE("%s", __FUNCTION__); - - // Create new ovimpl based on new state - typedef StateTraits NewState; - OverlayImplBase* newov = new NewState::ovimpl; - - //=========================================================== - // For each pipe: - // - If pipe matches, copy from previous into new ovimpl - // - Otherwise init for new and delete from previous ovimpl - //=========================================================== - - // pipe0/rot0 (GenericPipe) - if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_GENERIC) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (GenericPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE0); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe0 (GenericPipe)", __FUNCTION__); - RotatorBase* rot0 = new NewState::rot0; - ov->closePipe(utils::OV_PIPE0); - newov->initPipe(rot0, utils::OV_PIPE0); - } - - // pipe1/rot1 (VideoExtPipe) - if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_VIDEO_EXT) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (VideoExtPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE1); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe1 (VideoExtPipe)", __FUNCTION__); - RotatorBase* rot1 = new NewState::rot1; - ov->closePipe(utils::OV_PIPE1); - newov->initPipe(rot1, utils::OV_PIPE1); - } - - // pipe2/rot2 (NullPipe) - if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE2); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe2 (NullPipe)", __FUNCTION__); - RotatorBase* rot2 = new NewState::rot2; - ov->closePipe(utils::OV_PIPE2); - newov->initPipe(rot2, utils::OV_PIPE2); - } - - // All pipes are copied or deleted so no more need for previous ovimpl - delete ov; - ov = 0; - - return newov; -} - -/* - * Transition from any state to 3D video on 2D panel - */ -OverlayImplBase* OverlayState::handle_xxx_to_3D_2DPanel( - OverlayImplBase* ov) -{ - OVASSERT(ov, "%s: ov is null", __FUNCTION__); - ALOGE("%s", __FUNCTION__); - - // Create new ovimpl based on new state - typedef StateTraits NewState; - OverlayImplBase* newov = new NewState::ovimpl; - - //================================================================= - // For each pipe: - // - If pipe matches, copy from previous into new ovimpl. - // (which also makes previous pipe ref 0, so nobody can use) - // - Otherwise init pipe for new ovimpl and delete from previous - //================================================================= - - // pipe0/rot0 (M3DPrimaryPipe) - if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_M3D_PRIMARY) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (M3DPrimaryPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE0); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe0 (M3DPrimaryPipe)", __FUNCTION__); - RotatorBase* rot0 = new NewState::rot0; - ov->closePipe(utils::OV_PIPE0); - newov->initPipe(rot0, utils::OV_PIPE0); - } - - // pipe1/rot1 (NullPipe) - if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_NULL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (NullPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE1); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe1 (NullPipe)", __FUNCTION__); - RotatorBase* rot1 = new NewState::rot1; - ov->closePipe(utils::OV_PIPE1); - newov->initPipe(rot1, utils::OV_PIPE1); - } - - // pipe2/rot2 (NullPipe) - if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE2); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe2 (NullPipe)", __FUNCTION__); - RotatorBase* rot2 = new NewState::rot2; - ov->closePipe(utils::OV_PIPE2); - newov->initPipe(rot2, utils::OV_PIPE2); - } - - // All pipes are copied or deleted so no more need for previous ovimpl - delete ov; - ov = 0; - - return newov; -} - -/* - * Transition from any state to 3D video on 2D panel and 2D TV - */ -OverlayImplBase* OverlayState::handle_xxx_to_3D_2DTV( - OverlayImplBase* ov) -{ - OVASSERT(ov, "%s: ov is null", __FUNCTION__); - ALOGE("%s", __FUNCTION__); - - // Create new ovimpl based on new state - typedef StateTraits NewState; - OverlayImplBase* newov = new NewState::ovimpl; - - //=========================================================== - // For each pipe: - // - If pipe matches, copy from previous into new ovimpl - // - Otherwise init for new and delete from previous ovimpl - //=========================================================== - - // pipe0/rot0 (M3DPrimaryPipe) - if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_M3D_PRIMARY) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (M3DPrimaryPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE0); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe0 (M3DPrimaryPipe)", __FUNCTION__); - RotatorBase* rot0 = new NewState::rot0; - ov->closePipe(utils::OV_PIPE0); - newov->initPipe(rot0, utils::OV_PIPE0); - } - - // pipe1/rot1 (M3DExtPipe) - if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_M3D_EXTERNAL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (M3DExtPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE1); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe1 (M3DExtPipe)", __FUNCTION__); - RotatorBase* rot1 = new NewState::rot1; - ov->closePipe(utils::OV_PIPE1); - newov->initPipe(rot1, utils::OV_PIPE1); - } - - // pipe2/rot2 (NullPipe) - if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE2); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe2 (NullPipe)", __FUNCTION__); - RotatorBase* rot2 = new NewState::rot2; - ov->closePipe(utils::OV_PIPE2); - newov->initPipe(rot2, utils::OV_PIPE2); - } - - // All pipes are copied or deleted so no more need for previous ovimpl - delete ov; - ov = 0; - - return newov; -} - -/* - * Transition from any state to 2D true UI mirroring (2D video + UI) - */ -OverlayImplBase* OverlayState::handle_xxx_to_2D_trueUI_Mirror( - OverlayImplBase* ov) -{ - OVASSERT(ov, "%s: ov is null", __FUNCTION__); - ALOGE("%s", __FUNCTION__); - - // Create new ovimpl based on new state - typedef StateTraits NewState; - OverlayImplBase* newov = new NewState::ovimpl; - - //=========================================================== - // For each pipe: - // - If pipe matches, copy from previous into new ovimpl - // - Otherwise init for new and delete from previous ovimpl - //=========================================================== - - // pipe0/rot0 (GenericPipe) - if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_GENERIC) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (GenericPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE0); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe0 (GenericPipe)", __FUNCTION__); - RotatorBase* rot0 = new NewState::rot0; - ov->closePipe(utils::OV_PIPE0); - newov->initPipe(rot0, utils::OV_PIPE0); - } - - // pipe1/rot1 (VideoExtPipe) - if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_VIDEO_EXT) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (VideoExtPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE1); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe1 (VideoExtPipe)", __FUNCTION__); - RotatorBase* rot1 = new NewState::rot1; - ov->closePipe(utils::OV_PIPE1); - newov->initPipe(rot1, utils::OV_PIPE1); - } - - // pipe2/rot2 (UIMirrorPipe) - if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_UI_MIRROR) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (UIMirrorPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE2); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe2 (UIMirrorPipe)", __FUNCTION__); - RotatorBase* rot2 = new NewState::rot2; - ov->closePipe(utils::OV_PIPE2); - newov->initPipe(rot2, utils::OV_PIPE2); - } - - // All pipes are copied or deleted so no more need for previous ovimpl - delete ov; - ov = 0; - - return newov; -} - -/* - * Transitions from any state to 1 layer composition bypass - */ -OverlayImplBase* OverlayState::handle_xxx_to_bypass1(OverlayImplBase* ov) -{ - OVASSERT(ov, "%s: ov is null", __FUNCTION__); - ALOGE("%s", __FUNCTION__); - - // Create new ovimpl based on new state - typedef StateTraits NewState; - OverlayImplBase* newov = new NewState::ovimpl; - - //=========================================================== - // For each pipe: - // - If pipe matches, copy from previous into new ovimpl - // - Otherwise init for new and delete from previous ovimpl - //=========================================================== - - // pipe0/rot0 (BypassPipe) - if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_BYPASS) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (BypassPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE0); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe0 (BypassPipe)", __FUNCTION__); - RotatorBase* rot0 = new NewState::rot0; - ov->closePipe(utils::OV_PIPE0); - newov->initPipe(rot0, utils::OV_PIPE0); - } - - // pipe1/rot1 (NullPipe) - if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_NULL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (NullPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE1); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe1 (NullPipe)", __FUNCTION__); - RotatorBase* rot1 = new NewState::rot1; - ov->closePipe(utils::OV_PIPE1); - newov->initPipe(rot1, utils::OV_PIPE1); - } - - // pipe2/rot2 (NullPipe) - if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE2); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe2 (NullPipe)", __FUNCTION__); - RotatorBase* rot2 = new NewState::rot2; - ov->closePipe(utils::OV_PIPE2); - newov->initPipe(rot2, utils::OV_PIPE2); - } - - // All pipes are copied or deleted so no more need for previous ovimpl - delete ov; - ov = 0; - - return newov; -} - -/* - * Transitions from any state to 2 layers composition bypass - */ -OverlayImplBase* OverlayState::handle_xxx_to_bypass2(OverlayImplBase* ov) -{ - OVASSERT(ov, "%s: ov is null", __FUNCTION__); - ALOGE("%s", __FUNCTION__); - - // Create new ovimpl based on new state - typedef StateTraits NewState; - OverlayImplBase* newov = new NewState::ovimpl; - - //=========================================================== - // For each pipe: - // - If pipe matches, copy from previous into new ovimpl - // - Otherwise init for new and delete from previous ovimpl - //=========================================================== - - // pipe0/rot0 (BypassPipe) - if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_BYPASS) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (BypassPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE0); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe0 (BypassPipe)", __FUNCTION__); - RotatorBase* rot0 = new NewState::rot0; - ov->closePipe(utils::OV_PIPE0); - newov->initPipe(rot0, utils::OV_PIPE0); - } - - // pipe1/rot1 (BypassPipe) - if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_BYPASS) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (BypassPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE1); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe1 (BypassPipe)", __FUNCTION__); - RotatorBase* rot1 = new NewState::rot1; - ov->closePipe(utils::OV_PIPE1); - newov->initPipe(rot1, utils::OV_PIPE1); - } - - // pipe2/rot2 (NullPipe) - if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE2); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe2 (NullPipe)", __FUNCTION__); - RotatorBase* rot2 = new NewState::rot2; - ov->closePipe(utils::OV_PIPE2); - newov->initPipe(rot2, utils::OV_PIPE2); - } - - // All pipes are copied or deleted so no more need for previous ovimpl - delete ov; - ov = 0; - - return newov; -} - -/* - * Transitions from any state to 3 layers composition bypass - */ -OverlayImplBase* OverlayState::handle_xxx_to_bypass3(OverlayImplBase* ov) -{ - OVASSERT(ov, "%s: ov is null", __FUNCTION__); - ALOGE("%s", __FUNCTION__); - - // Create new ovimpl based on new state - typedef StateTraits NewState; - OverlayImplBase* newov = new NewState::ovimpl; - - //=========================================================== - // For each pipe: - // - If pipe matches, copy from previous into new ovimpl - // - Otherwise init for new and delete from previous ovimpl - //=========================================================== - - // pipe0/rot0 (BypassPipe) - if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_BYPASS) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (BypassPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE0); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe0 (BypassPipe)", __FUNCTION__); - RotatorBase* rot0 = new NewState::rot0; - ov->closePipe(utils::OV_PIPE0); - newov->initPipe(rot0, utils::OV_PIPE0); - } - - // pipe1/rot1 (BypassPipe) - if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_BYPASS) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (BypassPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE1); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe1 (BypassPipe)", __FUNCTION__); - RotatorBase* rot1 = new NewState::rot1; - ov->closePipe(utils::OV_PIPE1); - newov->initPipe(rot1, utils::OV_PIPE1); - } - - // pipe2/rot2 (BypassPipe) - if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_BYPASS) { - ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (BypassPipe)", __FUNCTION__); - newov->copyOvPipe(ov, utils::OV_PIPE2); - } else { - ALOGE_IF(DEBUG_OVERLAY, "%s: init pipe2 (BypassPipe)", __FUNCTION__); - RotatorBase* rot2 = new NewState::rot2; - ov->closePipe(utils::OV_PIPE2); - newov->initPipe(rot2, utils::OV_PIPE2); - } - - // All pipes are copied or deleted so no more need for previous ovimpl - delete ov; - ov = 0; - - return newov; -} - -} // overlay diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp index ce18174..161f05c 100644 --- a/liboverlay/overlayUtils.cpp +++ b/liboverlay/overlayUtils.cpp @@ -149,31 +149,50 @@ bool FrameBufferInfo::supportTrueMirroring() const { } //-------------------------------------------------------- - +//Refer to graphics.h, gralloc_priv.h, msm_mdp.h int getMdpFormat(int format) { switch (format) { + //From graphics.h 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_YCrCb_422_SP: - return MDP_Y_CRCB_H2V1; - case HAL_PIXEL_FORMAT_YCbCr_420_SP: - return MDP_Y_CBCR_H2V2; - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - return MDP_Y_CRCB_H2V2; - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: - return MDP_Y_CBCR_H2V2_TILE; + case HAL_PIXEL_FORMAT_RGB_888: + return MDP_RGB_888; + case HAL_PIXEL_FORMAT_RGB_565: + return MDP_RGB_565; + case HAL_PIXEL_FORMAT_BGRA_8888: + return MDP_BGRA_8888; case HAL_PIXEL_FORMAT_YV12: return MDP_Y_CR_CB_H2V2; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + return MDP_Y_CBCR_H2V1; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + return MDP_Y_CRCB_H2V2; + + //From gralloc_priv.h + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + return MDP_Y_CBCR_H2V2_TILE; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + return MDP_Y_CBCR_H2V2; + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + return MDP_Y_CRCB_H2V1; + case HAL_PIXEL_FORMAT_YCbCr_444_SP: + return MDP_Y_CBCR_H1V1; + case HAL_PIXEL_FORMAT_YCrCb_444_SP: + return MDP_Y_CRCB_H1V1; + default: - ALOGE("Error getMdpFormat format=0x%x", format); + //Unsupported by MDP + //---graphics.h-------- + //HAL_PIXEL_FORMAT_RGBA_5551 + //HAL_PIXEL_FORMAT_RGBA_4444 + //HAL_PIXEL_FORMAT_YCbCr_422_I + //---gralloc_priv.h----- + //HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x7FA30C01 + //HAL_PIXEL_FORMAT_R_8 = 0x10D + //HAL_PIXEL_FORMAT_RG_88 = 0x10E + ALOGE("%s: Unsupported format = 0x%x", __func__, format); return -1; } // not reached diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h index f82fb88..a09010c 100644 --- a/liboverlay/overlayUtils.h +++ b/liboverlay/overlayUtils.h @@ -268,25 +268,11 @@ enum eMdpFlags { OV_MDP_FLAGS_NONE = 0, OV_MDP_PIPE_SHARE = MDP_OV_PIPE_SHARE, OV_MDP_DEINTERLACE = MDP_DEINTERLACE, - OV_MDP_PLAY_NOWAIT = MDP_OV_PLAY_NOWAIT, //deprecated OV_MDP_SECURE_OVERLAY_SESSION = MDP_SECURE_OVERLAY_SESSION, OV_MDP_SOURCE_ROTATED_90 = MDP_SOURCE_ROTATED_90, OV_MDP_MEMORY_ID_TYPE_FB = MDP_MEMORY_ID_TYPE_FB, }; -enum eOverlayPipeType { - OV_PIPE_TYPE_NULL, - OV_PIPE_TYPE_BYPASS, - OV_PIPE_TYPE_GENERIC, - OV_PIPE_TYPE_VIDEO_EXT, - OV_PIPE_TYPE_M3D_EXTERNAL, - OV_PIPE_TYPE_M3D_PRIMARY, - OV_PIPE_TYPE_RGB, - OV_PIPE_TYPE_S3D_EXTERNAL, - OV_PIPE_TYPE_S3D_PRIMARY, - OV_PIPE_TYPE_UI_MIRROR -}; - enum eZorder { ZORDER_0, ZORDER_1, @@ -370,6 +356,7 @@ enum eOverlayState{ /* 2D Video */ OV_2D_VIDEO_ON_PANEL, OV_2D_VIDEO_ON_PANEL_TV, + OV_2D_VIDEO_ON_TV, /* 3D Video on one display (panel or TV) */ OV_3D_VIDEO_ON_2D_PANEL, @@ -382,12 +369,14 @@ enum eOverlayState{ /* UI Mirroring */ OV_UI_MIRROR, OV_2D_TRUE_UI_MIRROR, - OV_M3D_TRUE_UI_MIRROR, // Not yet supported /* Composition Bypass */ OV_BYPASS_1_LAYER, OV_BYPASS_2_LAYER, OV_BYPASS_3_LAYER, + + /* External only for dual-disp */ + OV_DUAL_DISP, }; inline void setMdpFlags(eMdpFlags& f, eMdpFlags v) { @@ -606,6 +595,8 @@ inline const char* getStateString(eOverlayState state){ return "OV_2D_VIDEO_ON_PANEL"; case OV_2D_VIDEO_ON_PANEL_TV: return "OV_2D_VIDEO_ON_PANEL_TV"; + case OV_2D_VIDEO_ON_TV: + return "OV_2D_VIDEO_ON_TV"; case OV_3D_VIDEO_ON_2D_PANEL: return "OV_3D_VIDEO_ON_2D_PANEL"; case OV_3D_VIDEO_ON_3D_PANEL: @@ -624,6 +615,8 @@ inline const char* getStateString(eOverlayState state){ return "OV_BYPASS_2_LAYER"; case OV_BYPASS_3_LAYER: return "OV_BYPASS_3_LAYER"; + case OV_DUAL_DISP: + return "OV_DUAL_DISP"; default: return "UNKNOWN_STATE"; } diff --git a/liboverlay/pipes/overlay3DPipe.h b/liboverlay/pipes/overlay3DPipe.h index 86ebed7..aaff336 100644 --- a/liboverlay/pipes/overlay3DPipe.h +++ b/liboverlay/pipes/overlay3DPipe.h @@ -54,12 +54,10 @@ public: bool close(); bool commit(); bool queueBuffer(int fd, uint32_t offset); - bool waitForVsync(); bool setCrop(const utils::Dim& d); bool setPosition(const utils::Dim& dim); bool setTransform(const utils::eTransform& param); bool setSource(const utils::PipeArgs& args); - utils::eOverlayPipeType getOvPipeType() const; void dump() const; private: overlay::GenericPipe mM3d; @@ -86,12 +84,10 @@ public: bool close(); bool commit(); bool queueBuffer(int fd, uint32_t offset); - bool waitForVsync(); bool setCrop(const utils::Dim& d); bool setPosition(const utils::Dim& dim); bool setTransform(const utils::eTransform& param); bool setSource(const utils::PipeArgs& args); - utils::eOverlayPipeType getOvPipeType() const; void dump() const; private: overlay::GenericPipe mM3d; @@ -118,12 +114,10 @@ public: bool close(); bool commit(); bool queueBuffer(int fd, uint32_t offset); - bool waitForVsync(); bool setCrop(const utils::Dim& d); bool setPosition(const utils::Dim& dim); bool setTransform(const utils::eTransform& param); bool setSource(const utils::PipeArgs& args); - utils::eOverlayPipeType getOvPipeType() const; void dump() const; private: overlay::GenericPipe mS3d; @@ -150,12 +144,10 @@ public: bool close(); bool commit(); bool queueBuffer(int fd, uint32_t offset); - bool waitForVsync(); bool setCrop(const utils::Dim& d); bool setPosition(const utils::Dim& dim); bool setTransform(const utils::eTransform& param); bool setSource(const utils::PipeArgs& args); - utils::eOverlayPipeType getOvPipeType() const; void dump() const; private: /* needed for 3D related IOCTL */ @@ -196,9 +188,6 @@ inline bool M3DExtPipe::queueBuffer(int fd, uint32_t offset) { return mM3d.queueBuffer(fd, offset); } template -inline bool M3DExtPipe::waitForVsync() { - return mM3d.waitForVsync(); } -template inline bool M3DExtPipe::setCrop(const utils::Dim& d) { utils::Dim _dim; if(!utils::getCropS3D(d, _dim, mM3Dfmt)){ @@ -237,10 +226,6 @@ inline bool M3DExtPipe::setSource(const utils::PipeArgs& args) return mM3d.setSource(args); } template -inline utils::eOverlayPipeType M3DExtPipe::getOvPipeType() const { - return utils::OV_PIPE_TYPE_M3D_EXTERNAL; -} -template inline void M3DExtPipe::dump() const { ALOGE("M3DExtPipe Pipe fmt=%d", mM3Dfmt); mM3d.dump(); @@ -272,9 +257,6 @@ inline bool M3DPrimaryPipe::queueBuffer(int fd, uint32_t offset) { return mM3d.queueBuffer(fd, offset); } template -inline bool M3DPrimaryPipe::waitForVsync() { - return mM3d.waitForVsync(); } -template inline bool M3DPrimaryPipe::setCrop(const utils::Dim& d) { utils::Dim _dim; if(!utils::getCropS3D(d, _dim, mM3Dfmt)){ @@ -300,10 +282,6 @@ inline bool M3DPrimaryPipe::setSource(const utils::PipeArgs& args) return mM3d.setSource(args); } template -inline utils::eOverlayPipeType M3DPrimaryPipe::getOvPipeType() const { - return utils::OV_PIPE_TYPE_M3D_PRIMARY; -} -template inline void M3DPrimaryPipe::dump() const { ALOGE("M3DPrimaryPipe Pipe fmt=%d", mM3Dfmt); mM3d.dump(); @@ -337,9 +315,6 @@ inline bool S3DExtPipe::queueBuffer(int fd, uint32_t offset) { return mS3d.queueBuffer(fd, offset); } template -inline bool S3DExtPipe::waitForVsync() { - return mS3d.waitForVsync(); } -template inline bool S3DExtPipe::setCrop(const utils::Dim& d) { utils::Dim _dim; if(!utils::getCropS3D(d, _dim, mS3Dfmt)){ @@ -371,10 +346,6 @@ inline bool S3DExtPipe::setSource(const utils::PipeArgs& args) { return mS3d.setSource(args); } template -inline utils::eOverlayPipeType S3DExtPipe::getOvPipeType() const { - return utils::OV_PIPE_TYPE_S3D_EXTERNAL; -} -template inline void S3DExtPipe::dump() const { ALOGE("S3DExtPipe Pipe fmt=%d", mS3Dfmt); mS3d.dump(); @@ -419,9 +390,6 @@ inline bool S3DPrimaryPipe::queueBuffer(int fd, uint32_t offset) { return mS3d.queueBuffer(fd, offset); } template -inline bool S3DPrimaryPipe::waitForVsync() { - return mS3d.waitForVsync(); } -template inline bool S3DPrimaryPipe::setCrop(const utils::Dim& d) { utils::Dim _dim; if(!utils::getCropS3D(d, _dim, mS3Dfmt)){ @@ -487,10 +455,6 @@ inline bool S3DPrimaryPipe::setSource(const utils::PipeArgs& args) return mS3d.setSource(args); } template -inline utils::eOverlayPipeType S3DPrimaryPipe::getOvPipeType() const { - return utils::OV_PIPE_TYPE_S3D_PRIMARY; -} -template inline void S3DPrimaryPipe::dump() const { ALOGE("S3DPrimaryPipe Pipe fmt=%d", mS3Dfmt); mS3d.dump(); diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h index c2d774b..f3d5141 100644 --- a/liboverlay/pipes/overlayGenPipe.h +++ b/liboverlay/pipes/overlayGenPipe.h @@ -63,8 +63,6 @@ public: /* Data APIs */ /* queue buffer to the overlay */ bool queueBuffer(int fd, uint32_t offset); - /* wait for vsync to be done */ - bool waitForVsync(); /* return cached startup args */ const utils::PipeArgs& getArgs() const; @@ -90,9 +88,6 @@ public: /* return Ctrl fd. Used for S3D */ int getCtrlFd() const; - /* Get the overlay pipe type */ - utils::eOverlayPipeType getOvPipeType() const; - /* dump the state of the object */ void dump() const; private: @@ -187,10 +182,6 @@ inline bool GenericPipe::setSource( const utils::PipeArgs& args) { utils::PipeArgs newargs(args); - //Interlace video handling. - if(newargs.whf.format & INTERLACE_MASK) { - setMdpFlags(newargs.mdpFlags, utils::OV_MDP_DEINTERLACE); - } utils::Whf whf(newargs.whf); //Extract HAL format from lower bytes. Deinterlace if interlaced. whf.format = utils::getColorFormat(whf.format); @@ -280,12 +271,6 @@ inline int GenericPipe::getCtrlFd() const { return mCtrlData.ctrl.getFd(); } -template -inline bool GenericPipe::waitForVsync() { - OVASSERT(isOpen(), "State is closed, cannot waitForVsync"); - return mCtrlData.data.waitForVsync(); -} - template inline utils::Dim GenericPipe::getAspectRatio( const utils::Whf& whf) const @@ -312,11 +297,6 @@ inline utils::Dim GenericPipe::getCrop() const return mCtrlData.ctrl.getCrop(); } -template -inline utils::eOverlayPipeType GenericPipe::getOvPipeType() const { - return utils::OV_PIPE_TYPE_GENERIC; -} - template void GenericPipe::dump() const { diff --git a/liboverlay/pipes/overlayUIMirrorPipe.h b/liboverlay/pipes/overlayUIMirrorPipe.h index 1c22020..c2b73bd 100644 --- a/liboverlay/pipes/overlayUIMirrorPipe.h +++ b/liboverlay/pipes/overlayUIMirrorPipe.h @@ -50,12 +50,10 @@ public: bool close(); bool commit(); bool queueBuffer(int fd, uint32_t offset); - bool waitForVsync(); bool setCrop(const utils::Dim& dim); bool setPosition(const utils::Dim& dim); bool setTransform(const utils::eTransform& param); bool setSource(const utils::PipeArgs& args); - utils::eOverlayPipeType getOvPipeType() const; void dump() const; private: overlay::GenericPipe mUI; @@ -79,8 +77,6 @@ inline bool UIMirrorPipe::commit() { return mUI.commit(); } inline bool UIMirrorPipe::queueBuffer(int fd, uint32_t offset) { return mUI.queueBuffer(fd, offset); } -inline bool UIMirrorPipe::waitForVsync() { - return mUI.waitForVsync(); } inline bool UIMirrorPipe::setCrop(const utils::Dim& dim) { return mUI.setCrop(dim); } @@ -162,9 +158,6 @@ inline bool UIMirrorPipe::setSource(const utils::PipeArgs& args) { return mUI.setSource(arg); } -inline utils::eOverlayPipeType UIMirrorPipe::getOvPipeType() const { - return utils::OV_PIPE_TYPE_UI_MIRROR; -} inline void UIMirrorPipe::dump() const { ALOGE("UI Mirror Pipe"); mUI.dump(); diff --git a/liboverlay/pipes/overlayVideoExtPipe.h b/liboverlay/pipes/overlayVideoExtPipe.h index 8196fe7..d4e1f3f 100644 --- a/liboverlay/pipes/overlayVideoExtPipe.h +++ b/liboverlay/pipes/overlayVideoExtPipe.h @@ -50,12 +50,10 @@ public: bool close(); bool commit(); bool queueBuffer(int fd, uint32_t offset); - bool waitForVsync(); bool setCrop(const utils::Dim& dim); bool setPosition(const utils::Dim& dim); bool setTransform(const utils::eTransform& param); bool setSource(const utils::PipeArgs& args); - utils::eOverlayPipeType getOvPipeType() const; void dump() const; private: overlay::GenericPipe mVideoExt; @@ -74,9 +72,6 @@ inline bool VideoExtPipe::commit() { return mVideoExt.commit(); } inline bool VideoExtPipe::queueBuffer(int fd, uint32_t offset) { return mVideoExt.queueBuffer(fd, offset); } -inline bool VideoExtPipe::waitForVsync() { - return mVideoExt.waitForVsync(); -} inline bool VideoExtPipe::setCrop(const utils::Dim& dim) { return mVideoExt.setCrop(dim); } @@ -105,9 +100,6 @@ inline bool VideoExtPipe::setSource(const utils::PipeArgs& args) { utils::PipeArgs arg(args); return mVideoExt.setSource(arg); } -inline utils::eOverlayPipeType VideoExtPipe::getOvPipeType() const { - return utils::OV_PIPE_TYPE_VIDEO_EXT; -} inline void VideoExtPipe::dump() const { ALOGE("Video Ext Pipe"); mVideoExt.dump(); diff --git a/libqdutils/Android.mk b/libqdutils/Android.mk index dfeae09..61daeac 100644 --- a/libqdutils/Android.mk +++ b/libqdutils/Android.mk @@ -8,5 +8,6 @@ LOCAL_SHARED_LIBRARIES := $(common_libs) LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) LOCAL_CFLAGS := $(common_flags) LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_SRC_FILES := profiler.cpp mdp_version.cpp +LOCAL_SRC_FILES := profiler.cpp mdp_version.cpp \ + idle_invalidator.cpp include $(BUILD_SHARED_LIBRARY) diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp index 0b98e11..d0c0f73 100644 --- a/libqdutils/idle_invalidator.cpp +++ b/libqdutils/idle_invalidator.cpp @@ -27,10 +27,10 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "IdleInvalidator.h" +#include "idle_invalidator.h" #include -#define II_DEBUG 1 +#define II_DEBUG 0 static const char *threadName = "Invalidator"; InvalidatorHandler IdleInvalidator::mHandler = NULL; @@ -38,12 +38,12 @@ android::sp IdleInvalidator::sInstance(0); IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0), mSleepAgain(false), mSleepTime(0) { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); } int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data, unsigned int idleSleepTime) { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); /* store registered handler */ mHandler = reg_handler; @@ -53,8 +53,8 @@ int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data, } bool IdleInvalidator::threadLoop() { - ALOGE_IF(II_DEBUG, "shs %s", __func__); - usleep(mSleepTime * 1000); + ALOGD_IF(II_DEBUG, "%s", __func__); + usleep(mSleepTime * 500); if(mSleepAgain) { //We need to sleep again! mSleepAgain = false; @@ -66,12 +66,12 @@ bool IdleInvalidator::threadLoop() { } int IdleInvalidator::readyToRun() { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); return 0; /*NO_ERROR*/ } void IdleInvalidator::onFirstRef() { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); } void IdleInvalidator::markForSleep() { @@ -81,7 +81,7 @@ void IdleInvalidator::markForSleep() { } IdleInvalidator *IdleInvalidator::getInstance() { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); if(sInstance.get() == NULL) sInstance = new IdleInvalidator(); return sInstance.get(); diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp index 3dadb39..78ca52f 100644 --- a/libqdutils/mdp_version.cpp +++ b/libqdutils/mdp_version.cpp @@ -34,10 +34,11 @@ ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::MDPVersion); namespace qdutils { -static int getMDPVersionFromFB() +MDPVersion::MDPVersion() { int fb_fd = open("/dev/graphics/fb0", O_RDWR); int mdp_version = MDP_V_UNKNOWN; + char panel_type = 0; struct fb_fix_screeninfo fb_finfo; if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_finfo) < 0) { ALOGE("FBIOGET_FSCREENINFO failed"); @@ -61,22 +62,18 @@ static int getMDPVersionFromFB() } else { mdp_version = MDP_V_UNKNOWN; } + int len = strlen("msmfbXX_"); + if (mdp_version == MDP_V3_0_3) + len++; + panel_type = fb_finfo.id[len]; + } close(fb_fd); -#ifdef TARGET_8x50 - // HACK: kernel reports zero so force the correct version - mdp_version = MDP_V3_1; -#endif - return mdp_version; -} - -MDPVersion::MDPVersion() -{ - mMDPVersion = getMDPVersionFromFB(); + mMDPVersion = mdp_version; + mHasOverlay = false; if((mMDPVersion >= MDP_V4_0) || (mMDPVersion == MDP_V_UNKNOWN)) mHasOverlay = true; - else - mHasOverlay = false; + mPanelType = panel_type; } }; //namespace qdutils diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h index 5ec0c67..9137cd4 100644 --- a/libqdutils/mdp_version.h +++ b/libqdutils/mdp_version.h @@ -52,15 +52,29 @@ enum mdp_version { MDSS_V5 = 500, }; +#define MDDI_PANEL '1' +#define EBI2_PANEL '2' +#define LCDC_PANEL '3' +#define EXT_MDDI_PANEL '4' +#define TV_PANEL '5' +#define DTV_PANEL '7' +#define MIPI_VIDEO_PANEL '8' +#define MIPI_CMD_PANEL '9' +#define WRITEBACK_PANEL 'a' +#define LVDS_PANEL 'b' + + class MDPVersion : public Singleton { public: MDPVersion(); ~MDPVersion() { } int getMDPVersion() {return mMDPVersion;} + char getPanelType() {return mPanelType;} bool hasOverlay() {return mHasOverlay;} private: int mMDPVersion; + char mPanelType; bool mHasOverlay; }; }; //namespace qdutils