Merge remote-tracking branch 'caf/jb' into jelly

Conflicts:
	common.mk
	libgralloc/alloc_controller.cpp
	libgralloc/pmem_bestfit_alloc.cpp
	libgralloc/pmemalloc.cpp
	libhwcomposer/hwc_external.cpp
	libqdutils/mdp_version.cpp

Change-Id: I1a0182faeb5e3c10153a5236434b55ff78b0eada
This commit is contained in:
Andrew Sutherland 2012-08-02 23:02:46 -05:00
commit 1ccdbea036
57 changed files with 2848 additions and 3429 deletions

View File

@ -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

View File

@ -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)){

View File

@ -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<gralloc::IAllocController> 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<IMemAlloc> 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<IMemAlloc> 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<IMemAlloc> 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);
}

View File

@ -28,33 +28,16 @@
*/
#include <cutils/log.h>
#include <utils/RefBase.h>
#include <fcntl.h>
#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> IAllocController::sController = NULL;
sp<IAllocController> 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<IMemAlloc> IonController::getAllocator(int flags)
IMemAlloc* IonController::getAllocator(int flags)
{
sp<IMemAlloc> memalloc;
IMemAlloc* memalloc;
if (flags & private_handle_t::PRIV_FLAGS_USES_ION) {
memalloc = mIonAlloc;
} else {
@ -195,152 +161,7 @@ sp<IMemAlloc> 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<IMemAlloc> 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<IMemAlloc> PmemKernelController::getAllocator(int flags)
{
sp<IMemAlloc> 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<IMemAlloc> PmemAshmemController::getAllocator(int flags)
{
sp<IMemAlloc> 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<gralloc::IAllocController> 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<gralloc::IAllocController> sAlloc =
gralloc::IAllocController::getInstance(false);
gralloc::IAllocController* sAlloc =
gralloc::IAllocController::getInstance();
if (hnd && hnd->fd > 0) {
sp<IMemAlloc> 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)

View File

@ -29,86 +29,43 @@
#ifndef GRALLOC_ALLOCCONTROLLER_H
#define GRALLOC_ALLOCCONTROLLER_H
#include <utils/RefBase.h>
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<IMemAlloc> getAllocator(int flags) = 0;
virtual IMemAlloc* getAllocator(int flags) = 0;
virtual ~IAllocController() {};
static android::sp<IAllocController> getInstance(bool useMasterHeap);
static IAllocController* getInstance(void);
private:
static android::sp<IAllocController> 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<IMemAlloc> getAllocator(int flags);
virtual IMemAlloc* getAllocator(int flags);
IonController();
private:
android::sp<IonAlloc> mIonAlloc;
IonAlloc* mIonAlloc;
};
class PmemKernelController : public IAllocController {
public:
virtual int allocate(alloc_data& data, int usage,
int compositionType);
virtual android::sp<IMemAlloc> getAllocator(int flags);
PmemKernelController ();
~PmemKernelController ();
private:
android::sp<IMemAlloc> 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<IMemAlloc> getAllocator(int flags);
PmemAshmemController();
~PmemAshmemController();
private:
android::sp<IMemAlloc> mPmemUserspaceAlloc;
android::sp<IMemAlloc> mAshmemAlloc;
android::sp<IAllocController> mPmemKernelCtrl;
};
} //end namespace gralloc
#endif // GRALLOC_ALLOCCONTROLLER_H

View File

@ -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 <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <cutils/log.h>
#include <linux/ashmem.h>
#include <cutils/ashmem.h>
#include <errno.h>
#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;
}

View File

@ -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 <linux/ion.h>
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 */

View File

@ -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<IAllocController> 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<hw_module_t*>(&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<private_module_t*>(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<<index);
} else {
terminateBuffer(&m->base, const_cast<private_handle_t*>(hnd));
sp<IMemAlloc> 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)

View File

@ -25,7 +25,6 @@
#include <cutils/log.h>
#include <cutils/ashmem.h>
#include <utils/RefBase.h>
#include "gralloc_priv.h"
#include <fb_priv.h>
@ -35,7 +34,7 @@ class IAllocController;
class gpu_context_t : public alloc_device_t {
public:
gpu_context_t(const private_module_t* module,
android::sp<IAllocController>alloc_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<IAllocController> mAllocCtrl;
IAllocController* mAllocCtrl;
void getGrallocInformationFromFormat(int inputFormat,
int *colorFormat,
int *bufferType);

View File

@ -23,7 +23,6 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <cutils/properties.h>
#include <utils/RefBase.h>
#include <linux/android_pmem.h>
@ -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<const private_module_t*>(
module);
gpu_context_t *dev;
sp<IAllocController> alloc_ctrl = IAllocController::getInstance(true);
IAllocController* alloc_ctrl = IAllocController::getInstance();
dev = new gpu_context_t(m, alloc_ctrl);
*device = &dev->common;
status = 0;

View File

@ -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

View File

@ -27,7 +27,7 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define DEBUG 0
#include <linux/ioctl.h>
#include <sys/mman.h>
#include <stdlib.h>
@ -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;

View File

@ -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<IMemAlloc> getAllocator(int flags)
static IMemAlloc* getAllocator(int flags)
{
sp<IMemAlloc> memalloc;
sp<IAllocController> 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<IMemAlloc> 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<IMemAlloc> 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<IMemAlloc> 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, &region) < 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;

View File

@ -31,7 +31,6 @@
#define GRALLOC_MEMALLOC_H
#include <stdlib.h>
#include <utils/RefBase.h>
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

View File

@ -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 <cutils/log.h>
#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;
}

View File

@ -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 <stdint.h>
#include <sys/types.h>
#include "gr.h"
#include "pmemalloc.h"
// ----------------------------------------------------------------------------
/*
* A simple templatized doubly linked-list implementation
*/
template <typename NODE>
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<chunk_t> mList;
size_t mHeapSize;
};
#endif /* GRALLOC_ALLOCATOR_H_ */

View File

@ -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 <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <cutils/log.h>
#include <errno.h>
#include <linux/android_pmem.h>
#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, &region)) {
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);
}

View File

@ -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 <linux/ion.h>
#include <utils/RefBase.h>
#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<Allocator> 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 */

View File

@ -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)

View File

@ -20,11 +20,19 @@
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <EGL/egl.h>
#include <overlay.h>
#include <fb_priv.h>
#include <mdp_version.h>
#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<private_module_t*>(
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<private_module_t*>(
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<hw_module_t*>(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;
}

View File

@ -18,8 +18,12 @@
* limitations under the License.
*/
#define DEBUG_COPYBIT 0
#include <copybit.h>
#include <genlock.h>
#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; i<list->numHwLayers; 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; i<list->numHwLayers; 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);

View File

@ -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;

View File

@ -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

View File

@ -18,9 +18,9 @@
* limitations under the License.
*/
#define DEBUG 0
#include <ctype.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <fcntl.h>
#include <media/IAudioPolicyService.h>
#include <media/AudioSystem.h>
#include <utils/threads.h>
@ -31,104 +31,32 @@
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <hardware_legacy/uevent.h>
#include <sys/resource.h>
#include <cutils/properties.h>
#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> 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<len; i++) {
edidModes[i] = (int) strtol(start, &end, 10);
if(*end != delim) {
// return as we reached end of string
return count;
}
end = &delim;
while(*end == delim) {
edidModes[count] = (int) strtol(start, &end, 10);
start = end+1;
count++;
}
ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count);
for (int i = 0; i < count; i++)
ALOGD_IF(DEBUG, "Mode[%d] = %d", i, edidModes[i]);
return count;
}
bool ExtDisplayObserver::readResolution()
bool ExternalDisplay::readResolution()
{
int hdmiEDIDFile = open(SYSFS_EDID_MODES, O_RDONLY, 0);
int len = -1;
memset(mEDIDs, 0, sizeof(mEDIDs));
memset(mEDIDModes, 0, sizeof(mEDIDModes));
mModeCount = 0;
if (hdmiEDIDFile < 0) {
ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: edid_modes file '%s' not found",
__FUNCTION__, SYSFS_EDID_MODES);
ALOGE("%s: edid_modes file '%s' not found",
__FUNCTION__, SYSFS_EDID_MODES);
return false;
} else {
len = read(hdmiEDIDFile, mEDIDs, sizeof(mEDIDs)-1);
ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: EDID string: %s length = %d",
__FUNCTION__, mEDIDs, len);
ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d",
__FUNCTION__, mEDIDs, len);
if ( len <= 0) {
ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: edid_modes file empty '%s'",
__FUNCTION__, SYSFS_EDID_MODES);
ALOGE("%s: edid_modes file empty '%s'",
__FUNCTION__, SYSFS_EDID_MODES);
}
else {
while (len > 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<ID=%d %dx%d (%d,%d,%d),"
"(%d,%d,%d) %dMHz>", __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<ID=%d %dx%d (%d,%d,%d),"
"(%d,%d,%d) %dMHz>", __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<ID=%d => Info<ID=%d %dx%d"
"(%d,%d,%d), (%d,%d,%d) %dMHz>", __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<ID=%d => Info<ID=%d %dx %d"
"(%d,%d,%d), (%d,%d,%d) %dMHz>", __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;
}
};

View File

@ -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 <utils/threads.h>
#include <fb_priv.h>
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<ExtDisplayObserver> 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

View File

@ -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

View File

@ -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 <overlay.h>
#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

View File

@ -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<ovutils::eTransform>(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 &current_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

220
libhwcomposer/hwc_mdpcomp.h Normal file
View File

@ -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 <hwc_utils.h>
#include <idle_invalidator.h>
#include <cutils/properties.h>
#include <overlay.h>
#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

View File

@ -15,6 +15,9 @@
* limitations under the License.
*/
#include <gralloc_priv.h>
#include <genlock.h>
// -----------------------------------------------------------------------------
// QueuedBufferStore
//This class holds currently and previously queued buffers.

View File

@ -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 <hardware_legacy/uevent.h>
#include <utils/Log.h>
#include <sys/resource.h>
#include <string.h>
#include <stdlib.h>
#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<hwc_context_t *>(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

View File

@ -18,12 +18,14 @@
* limitations under the License.
*/
#define HWC_UI_MIRROR 0
#include <gralloc_priv.h>
#include <fb_priv.h>
#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<private_module_t*>(
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<private_module_t*>(
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;
}

View File

@ -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 ))

View File

@ -15,26 +15,43 @@
* limitations under the License.
*/
#include <overlay.h>
#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<hwc_methods_t *>(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

View File

@ -17,28 +17,34 @@
#ifndef HWC_UTILS_H
#define HWC_UTILS_H
#include <cutils/log.h>
#include <gralloc_priv.h>
#include <hardware/hwcomposer.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <stdlib.h>
#include <string.h>
#include <fb_priv.h>
#include <overlay.h>
#include <copybit.h>
#include <hwc_copybitEngine.h>
#include <genlock.h>
#include "hwc_qbuf.h"
#include <EGL/egl.h>
#include <gralloc_priv.h>
#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

View File

@ -15,39 +15,52 @@
* limitations under the License.
*/
#define VIDEO_DEBUG 0
#include <overlay.h>
#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<ovutils::eTransform>(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<ovutils::eTransform>(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

View File

@ -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

View File

@ -13,7 +13,6 @@ LOCAL_SRC_FILES := \
overlayCtrl.cpp \
overlayUtils.cpp \
overlayMdp.cpp \
overlayRotator.cpp \
overlayTransitions.cpp
overlayRotator.cpp
include $(BUILD_SHARED_LIBRARY)

View File

@ -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",

View File

@ -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<utils::eTransform>(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;
}

View File

@ -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;

View File

@ -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();

View File

@ -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<P0, P1, P2>::queueBuffer(int fd, uint32_t offset,
return true;
}
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::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 <class P0, class P1, class P2>
utils::eOverlayPipeType OverlayImpl<P0, P1, P2>::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 <class P0, class P1, class P2>
void OverlayImpl<P0, P1, P2>::dump() const
{

View File

@ -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

View File

@ -94,12 +94,11 @@ private:
uint32_t mNumBuffers;
/* gralloc alloc controller */
android::sp<gralloc::IAllocController> 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<IMemAlloc> 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");

File diff suppressed because it is too large Load Diff

View File

@ -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<utils::OV_2D_VIDEO_ON_PANEL> 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<utils::OV_2D_VIDEO_ON_PANEL_TV> 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<utils::OV_3D_VIDEO_ON_2D_PANEL> 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<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV> 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<utils::OV_2D_TRUE_UI_MIRROR> 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<utils::OV_BYPASS_1_LAYER> 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<utils::OV_BYPASS_2_LAYER> 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<utils::OV_BYPASS_3_LAYER> 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

View File

@ -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

View File

@ -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";
}

View File

@ -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<utils::EXTERNAL> 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<utils::PRIMARY> 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<utils::EXTERNAL> 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<CHAN>::queueBuffer(int fd, uint32_t offset) {
return mM3d.queueBuffer(fd, offset);
}
template <int CHAN>
inline bool M3DExtPipe<CHAN>::waitForVsync() {
return mM3d.waitForVsync(); }
template <int CHAN>
inline bool M3DExtPipe<CHAN>::setCrop(const utils::Dim& d) {
utils::Dim _dim;
if(!utils::getCropS3D<CHAN>(d, _dim, mM3Dfmt)){
@ -237,10 +226,6 @@ inline bool M3DExtPipe<CHAN>::setSource(const utils::PipeArgs& args)
return mM3d.setSource(args);
}
template <int CHAN>
inline utils::eOverlayPipeType M3DExtPipe<CHAN>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_M3D_EXTERNAL;
}
template <int CHAN>
inline void M3DExtPipe<CHAN>::dump() const {
ALOGE("M3DExtPipe Pipe fmt=%d", mM3Dfmt);
mM3d.dump();
@ -272,9 +257,6 @@ inline bool M3DPrimaryPipe<CHAN>::queueBuffer(int fd, uint32_t offset) {
return mM3d.queueBuffer(fd, offset);
}
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::waitForVsync() {
return mM3d.waitForVsync(); }
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::setCrop(const utils::Dim& d) {
utils::Dim _dim;
if(!utils::getCropS3D<CHAN>(d, _dim, mM3Dfmt)){
@ -300,10 +282,6 @@ inline bool M3DPrimaryPipe<CHAN>::setSource(const utils::PipeArgs& args)
return mM3d.setSource(args);
}
template <int CHAN>
inline utils::eOverlayPipeType M3DPrimaryPipe<CHAN>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_M3D_PRIMARY;
}
template <int CHAN>
inline void M3DPrimaryPipe<CHAN>::dump() const {
ALOGE("M3DPrimaryPipe Pipe fmt=%d", mM3Dfmt);
mM3d.dump();
@ -337,9 +315,6 @@ inline bool S3DExtPipe<CHAN>::queueBuffer(int fd, uint32_t offset) {
return mS3d.queueBuffer(fd, offset);
}
template <int CHAN>
inline bool S3DExtPipe<CHAN>::waitForVsync() {
return mS3d.waitForVsync(); }
template <int CHAN>
inline bool S3DExtPipe<CHAN>::setCrop(const utils::Dim& d) {
utils::Dim _dim;
if(!utils::getCropS3D<CHAN>(d, _dim, mS3Dfmt)){
@ -371,10 +346,6 @@ inline bool S3DExtPipe<CHAN>::setSource(const utils::PipeArgs& args) {
return mS3d.setSource(args);
}
template <int CHAN>
inline utils::eOverlayPipeType S3DExtPipe<CHAN>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_S3D_EXTERNAL;
}
template <int CHAN>
inline void S3DExtPipe<CHAN>::dump() const {
ALOGE("S3DExtPipe Pipe fmt=%d", mS3Dfmt);
mS3d.dump();
@ -419,9 +390,6 @@ inline bool S3DPrimaryPipe<CHAN>::queueBuffer(int fd, uint32_t offset) {
return mS3d.queueBuffer(fd, offset);
}
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::waitForVsync() {
return mS3d.waitForVsync(); }
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::setCrop(const utils::Dim& d) {
utils::Dim _dim;
if(!utils::getCropS3D<CHAN>(d, _dim, mS3Dfmt)){
@ -487,10 +455,6 @@ inline bool S3DPrimaryPipe<CHAN>::setSource(const utils::PipeArgs& args)
return mS3d.setSource(args);
}
template <int CHAN>
inline utils::eOverlayPipeType S3DPrimaryPipe<CHAN>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_S3D_PRIMARY;
}
template <int CHAN>
inline void S3DPrimaryPipe<CHAN>::dump() const {
ALOGE("S3DPrimaryPipe Pipe fmt=%d", mS3Dfmt);
mS3d.dump();

View File

@ -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<PANEL>::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<PANEL>::getCtrlFd() const {
return mCtrlData.ctrl.getFd();
}
template <int PANEL>
inline bool GenericPipe<PANEL>::waitForVsync() {
OVASSERT(isOpen(), "State is closed, cannot waitForVsync");
return mCtrlData.data.waitForVsync();
}
template <int PANEL>
inline utils::Dim GenericPipe<PANEL>::getAspectRatio(
const utils::Whf& whf) const
@ -312,11 +297,6 @@ inline utils::Dim GenericPipe<PANEL>::getCrop() const
return mCtrlData.ctrl.getCrop();
}
template <int PANEL>
inline utils::eOverlayPipeType GenericPipe<PANEL>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_GENERIC;
}
template <int PANEL>
void GenericPipe<PANEL>::dump() const
{

View File

@ -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<ovutils::EXTERNAL> 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();

View File

@ -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<ovutils::EXTERNAL> 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();

View File

@ -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)

View File

@ -27,10 +27,10 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "IdleInvalidator.h"
#include "idle_invalidator.h"
#include <unistd.h>
#define II_DEBUG 1
#define II_DEBUG 0
static const char *threadName = "Invalidator";
InvalidatorHandler IdleInvalidator::mHandler = NULL;
@ -38,12 +38,12 @@ android::sp<IdleInvalidator> 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();

View File

@ -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

View File

@ -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 <MDPVersion>
{
public:
MDPVersion();
~MDPVersion() { }
int getMDPVersion() {return mMDPVersion;}
char getPanelType() {return mPanelType;}
bool hasOverlay() {return mHasOverlay;}
private:
int mMDPVersion;
char mPanelType;
bool mHasOverlay;
};
}; //namespace qdutils