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:
commit
1ccdbea036
@ -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
|
||||
|
@ -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)){
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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, ®ion) < 0)
|
||||
hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION;
|
||||
else
|
||||
hnd->flags = private_handle_t::PRIV_FLAGS_USES_PMEM |
|
||||
private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH;
|
||||
} else {
|
||||
if (memoryFlags & GRALLOC_USAGE_PRIVATE_ION)
|
||||
hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION;
|
||||
else
|
||||
hnd->flags = private_handle_t::PRIV_FLAGS_USES_ASHMEM;
|
||||
}
|
||||
|
||||
hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION;
|
||||
hnd->size = size;
|
||||
hnd->offset = offset;
|
||||
hnd->base = intptr_t(base) + offset;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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_ */
|
@ -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, ®ion)) {
|
||||
err = -errno;
|
||||
} else {
|
||||
*size = region.len;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int getOpenFlags(bool uncached)
|
||||
{
|
||||
if(uncached)
|
||||
return O_RDWR | O_SYNC;
|
||||
else
|
||||
return O_RDWR;
|
||||
}
|
||||
|
||||
static int connectPmem(int fd, int master_fd) {
|
||||
if (ioctl(fd, PMEM_CONNECT, master_fd))
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mapSubRegion(int fd, int offset, size_t size) {
|
||||
struct pmem_region sub = { offset, size };
|
||||
if (ioctl(fd, PMEM_MAP, &sub))
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unmapSubRegion(int fd, int offset, size_t size) {
|
||||
struct pmem_region sub = { offset, size };
|
||||
if (ioctl(fd, PMEM_UNMAP, &sub))
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alignPmem(int fd, size_t size, int align) {
|
||||
struct pmem_allocation allocation;
|
||||
allocation.size = size;
|
||||
allocation.align = align;
|
||||
if (ioctl(fd, PMEM_ALLOCATE_ALIGNED, &allocation))
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cleanPmem(void *base, size_t size, int offset, int fd) {
|
||||
struct pmem_addr pmem_addr;
|
||||
pmem_addr.vaddr = (unsigned long) base;
|
||||
pmem_addr.offset = offset;
|
||||
pmem_addr.length = size;
|
||||
if (ioctl(fd, PMEM_CLEAN_INV_CACHES, &pmem_addr))
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------- PmemUserspaceAlloc-----------------------//
|
||||
PmemUserspaceAlloc::PmemUserspaceAlloc()
|
||||
{
|
||||
mPmemDev = DEVICE_PMEM;
|
||||
mMasterFd = FD_INIT;
|
||||
mAllocator = new SimpleBestFitAllocator();
|
||||
pthread_mutex_init(&mLock, NULL);
|
||||
}
|
||||
|
||||
PmemUserspaceAlloc::~PmemUserspaceAlloc()
|
||||
{
|
||||
}
|
||||
|
||||
int PmemUserspaceAlloc::init_pmem_area_locked()
|
||||
{
|
||||
ALOGD("%s: Opening master pmem FD", __FUNCTION__);
|
||||
int err = 0;
|
||||
int fd = open(mPmemDev, O_RDWR, 0);
|
||||
if (fd >= 0) {
|
||||
size_t size = 0;
|
||||
err = getPmemTotalSize(fd, &size);
|
||||
ALOGD("%s: Total pmem size: %d", __FUNCTION__, size);
|
||||
if (err < 0) {
|
||||
ALOGE("%s: PMEM_GET_TOTAL_SIZE failed (%d), limp mode", mPmemDev,
|
||||
err);
|
||||
size = 8<<20; // 8 MiB
|
||||
}
|
||||
mAllocator->setSize(size);
|
||||
|
||||
void* base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd,
|
||||
0);
|
||||
if (base == MAP_FAILED) {
|
||||
err = -errno;
|
||||
ALOGE("%s: Failed to map pmem master fd: %s", mPmemDev,
|
||||
strerror(errno));
|
||||
base = 0;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
} else {
|
||||
mMasterFd = fd;
|
||||
mMasterBase = base;
|
||||
}
|
||||
} else {
|
||||
err = -errno;
|
||||
ALOGE("%s: Failed to open pmem device: %s", mPmemDev,
|
||||
strerror(errno));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int PmemUserspaceAlloc::init_pmem_area()
|
||||
{
|
||||
pthread_mutex_lock(&mLock);
|
||||
int err = mMasterFd;
|
||||
if (err == FD_INIT) {
|
||||
// first time, try to initialize pmem
|
||||
ALOGD("%s: Initializing pmem area", __FUNCTION__);
|
||||
err = init_pmem_area_locked();
|
||||
if (err) {
|
||||
ALOGE("%s: failed to initialize pmem area", mPmemDev);
|
||||
mMasterFd = err;
|
||||
}
|
||||
} else if (err < 0) {
|
||||
// pmem couldn't be initialized, never use it
|
||||
} else {
|
||||
// pmem OK
|
||||
err = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&mLock);
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int PmemUserspaceAlloc::alloc_buffer(alloc_data& data)
|
||||
{
|
||||
int err = init_pmem_area();
|
||||
if (err == 0) {
|
||||
void* base = mMasterBase;
|
||||
size_t size = data.size;
|
||||
int offset = mAllocator->allocate(size);
|
||||
if (offset < 0) {
|
||||
// no more pmem memory
|
||||
ALOGE("%s: No more pmem available", mPmemDev);
|
||||
err = -ENOMEM;
|
||||
} else {
|
||||
int openFlags = getOpenFlags(data.uncached);
|
||||
|
||||
// now create the "sub-heap"
|
||||
int fd = open(mPmemDev, openFlags, 0);
|
||||
err = fd < 0 ? fd : 0;
|
||||
|
||||
// and connect to it
|
||||
if (err == 0)
|
||||
err = connectPmem(fd, mMasterFd);
|
||||
|
||||
// and make it available to the client process
|
||||
if (err == 0)
|
||||
err = mapSubRegion(fd, offset, size);
|
||||
|
||||
if (err < 0) {
|
||||
ALOGE("%s: Failed to initialize pmem sub-heap: %d", mPmemDev,
|
||||
err);
|
||||
close(fd);
|
||||
mAllocator->deallocate(offset);
|
||||
fd = -1;
|
||||
} else {
|
||||
ALOGV("%s: Allocated buffer base:%p size:%d offset:%d fd:%d",
|
||||
mPmemDev, base, size, offset, fd);
|
||||
memset((char*)base + offset, 0, size);
|
||||
//Clean cache before flushing to ensure pmem is properly flushed
|
||||
err = clean_buffer((void*)((intptr_t) base + offset), size, offset, fd);
|
||||
if (err < 0) {
|
||||
ALOGE("cleanPmem failed: (%s)", strerror(errno));
|
||||
}
|
||||
cacheflush(intptr_t(base) + offset, intptr_t(base) + offset + size, 0);
|
||||
data.base = base;
|
||||
data.offset = offset;
|
||||
data.fd = fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int PmemUserspaceAlloc::free_buffer(void* base, size_t size, int offset, int fd)
|
||||
{
|
||||
ALOGV("%s: Freeing buffer base:%p size:%d offset:%d fd:%d",
|
||||
mPmemDev, base, size, offset, fd);
|
||||
int err = 0;
|
||||
if (fd >= 0) {
|
||||
int err = unmapSubRegion(fd, offset, size);
|
||||
ALOGE_IF(err<0, "PMEM_UNMAP failed (%s), fd=%d, sub.offset=%u, "
|
||||
"sub.size=%u", strerror(errno), fd, offset, size);
|
||||
if (err == 0) {
|
||||
// we can't deallocate the memory in case of UNMAP failure
|
||||
// because it would give that process access to someone else's
|
||||
// surfaces, which would be a security breach.
|
||||
mAllocator->deallocate(offset);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int PmemUserspaceAlloc::map_buffer(void **pBase, size_t size, int offset, int fd)
|
||||
{
|
||||
int err = 0;
|
||||
size += offset;
|
||||
void *base = mmap(0, size, PROT_READ| PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
*pBase = base;
|
||||
if(base == MAP_FAILED) {
|
||||
err = -errno;
|
||||
ALOGE("%s: Failed to map buffer size:%d offset:%d fd:%d Error: %s",
|
||||
mPmemDev, size, offset, fd, strerror(errno));
|
||||
} else {
|
||||
ALOGV("%s: Mapped buffer base:%p size:%d offset:%d fd:%d",
|
||||
mPmemDev, base, size, offset, fd);
|
||||
}
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int PmemUserspaceAlloc::unmap_buffer(void *base, size_t size, int offset)
|
||||
{
|
||||
int err = 0;
|
||||
//pmem hack
|
||||
base = (void*)(intptr_t(base) - offset);
|
||||
size += offset;
|
||||
ALOGV("%s: Unmapping buffer base:%p size:%d offset:%d",
|
||||
mPmemDev , base, size, offset);
|
||||
if (munmap(base, size) < 0) {
|
||||
err = -errno;
|
||||
ALOGE("%s: Failed to unmap memory at %p :%s",
|
||||
mPmemDev, base, strerror(errno));
|
||||
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int PmemUserspaceAlloc::clean_buffer(void *base, size_t size, int offset, int fd)
|
||||
{
|
||||
return cleanPmem(base, size, offset, fd);
|
||||
}
|
||||
|
||||
|
||||
//-------------- PmemKernelAlloc-----------------------//
|
||||
|
||||
PmemKernelAlloc::PmemKernelAlloc(const char* pmemdev) :
|
||||
mPmemDev(pmemdev)
|
||||
{
|
||||
}
|
||||
|
||||
PmemKernelAlloc::~PmemKernelAlloc()
|
||||
{
|
||||
}
|
||||
|
||||
int PmemKernelAlloc::alloc_buffer(alloc_data& data)
|
||||
{
|
||||
int err, offset = 0;
|
||||
int openFlags = getOpenFlags(data.uncached);
|
||||
int size = data.size;
|
||||
|
||||
int fd = open(mPmemDev, openFlags, 0);
|
||||
if (fd < 0) {
|
||||
err = -errno;
|
||||
ALOGE("%s: Error opening %s", __FUNCTION__, mPmemDev);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (data.align == 8192) {
|
||||
// Tile format buffers need physical alignment to 8K
|
||||
// Default page size does not need this ioctl
|
||||
err = alignPmem(fd, size, 8192);
|
||||
if (err < 0) {
|
||||
ALOGE("alignPmem failed");
|
||||
}
|
||||
}
|
||||
void* base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (base == MAP_FAILED) {
|
||||
err = -errno;
|
||||
ALOGE("%s: failed to map pmem fd: %s", mPmemDev,
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
memset(base, 0, size);
|
||||
clean_buffer((void*)((intptr_t) base + offset), size, offset, fd);
|
||||
data.base = base;
|
||||
data.offset = 0;
|
||||
data.fd = fd;
|
||||
ALOGV("%s: Allocated buffer base:%p size:%d fd:%d",
|
||||
mPmemDev, base, size, fd);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int PmemKernelAlloc::free_buffer(void* base, size_t size, int offset, int fd)
|
||||
{
|
||||
ALOGV("%s: Freeing buffer base:%p size:%d fd:%d",
|
||||
mPmemDev, base, size, fd);
|
||||
|
||||
int err = unmap_buffer(base, size, offset);
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
int PmemKernelAlloc::map_buffer(void **pBase, size_t size, int offset, int fd)
|
||||
{
|
||||
int err = 0;
|
||||
void *base = mmap(0, size, PROT_READ| PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
*pBase = base;
|
||||
if(base == MAP_FAILED) {
|
||||
err = -errno;
|
||||
ALOGE("%s: Failed to map memory in the client: %s",
|
||||
mPmemDev, strerror(errno));
|
||||
} else {
|
||||
ALOGV("%s: Mapped buffer base:%p size:%d, fd:%d",
|
||||
mPmemDev, base, size, fd);
|
||||
}
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int PmemKernelAlloc::unmap_buffer(void *base, size_t size, int offset)
|
||||
{
|
||||
int err = 0;
|
||||
if (munmap(base, size)) {
|
||||
err = -errno;
|
||||
ALOGW("%s: Error unmapping memory at %p: %s",
|
||||
mPmemDev, base, strerror(err));
|
||||
}
|
||||
return err;
|
||||
|
||||
}
|
||||
int PmemKernelAlloc::clean_buffer(void *base, size_t size, int offset, int fd)
|
||||
{
|
||||
return cleanPmem(base, size, offset, fd);
|
||||
}
|
||||
|
@ -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 */
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -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
|
156
libhwcomposer/hwc_extonly.cpp
Normal file
156
libhwcomposer/hwc_extonly.cpp
Normal 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
|
82
libhwcomposer/hwc_extonly.h
Normal file
82
libhwcomposer/hwc_extonly.h
Normal 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
|
829
libhwcomposer/hwc_mdpcomp.cpp
Normal file
829
libhwcomposer/hwc_mdpcomp.cpp
Normal 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 ¤t_frame = sCurrentFrame;
|
||||
current_frame.count = 0;
|
||||
|
||||
if(!ctx) {
|
||||
ALOGE("%s: invalid context", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
framebuffer_device_t *fbDev = ctx->mFbDev;
|
||||
if (!fbDev) {
|
||||
ALOGE("%s: fbDev is NULL", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!parse_and_allocate(ctx, list, current_frame)) {
|
||||
#if SUPPORT_4LAYER
|
||||
int mode = VAR_PIPE_FB_ATTACH;
|
||||
if(fbDev->perform(fbDev,EVENT_SET_VAR_PIPE_MODE,(void*)&mode) < 0 ) {
|
||||
ALOGE("%s: setting var pipe mode failed", __FUNCTION__);
|
||||
}
|
||||
#endif
|
||||
ALOGD_IF(isDebug(), "%s: Falling back to FB", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
#if SUPPORT_4LAYER
|
||||
configure_var_pipe(ctx);
|
||||
#endif
|
||||
|
||||
overlay::Overlay& ov = *(ctx->mOverlay);
|
||||
ovutils::eOverlayState state = ov.getState();
|
||||
|
||||
if (current_frame.count == 1) {
|
||||
state = ovutils::OV_BYPASS_1_LAYER;
|
||||
} else if (current_frame.count == 2) {
|
||||
state = ovutils::OV_BYPASS_2_LAYER;
|
||||
} else if (current_frame.count == 3) {
|
||||
state = ovutils::OV_BYPASS_3_LAYER;
|
||||
}
|
||||
|
||||
ov.setState(state);
|
||||
|
||||
|
||||
for (int index = 0 ; index < current_frame.count; index++) {
|
||||
int layer_index = current_frame.pipe_layer[index].layer_index;
|
||||
hwc_layer_t* layer = &list->hwLayers[layer_index];
|
||||
mdp_pipe_info& cur_pipe = current_frame.pipe_layer[index].pipe_index;
|
||||
|
||||
if( prepare(ctx, layer, cur_pipe) != 0 ) {
|
||||
ALOGD_IF(isDebug(), "%s: MDPComp failed to configure overlay for \
|
||||
layer %d with pipe index:%d",__FUNCTION__,
|
||||
index, cur_pipe.index);
|
||||
return false;
|
||||
} else {
|
||||
setLayerIndex(layer, index);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MDPComp::unsetMDPCompLayerFlags(hwc_context_t* ctx, hwc_layer_list_t* list)
|
||||
{
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
for (int index = 0 ; index < sCurrentFrame.count; index++) {
|
||||
int l_index = sCurrentFrame.pipe_layer[index].layer_index;
|
||||
if(list->hwLayers[l_index].flags & HWC_MDPCOMP) {
|
||||
list->hwLayers[l_index].flags &= ~HWC_MDPCOMP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int MDPComp::draw(hwc_context_t *ctx, hwc_layer_list_t* list) {
|
||||
|
||||
if(!isEnabled()) {
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled",__FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!ctx || !list) {
|
||||
ALOGE("%s: invalid contxt or list",__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
overlay::Overlay& ov = *(ctx->mOverlay);
|
||||
|
||||
for(unsigned int i = 0; i < list->numHwLayers; i++ )
|
||||
{
|
||||
hwc_layer_t *layer = &list->hwLayers[i];
|
||||
|
||||
if(!(layer->flags & HWC_MDPCOMP)) {
|
||||
ALOGD_IF(isDebug(), "%s: Layer Not flagged for MDP comp",
|
||||
__FUNCTION__);
|
||||
continue;
|
||||
}
|
||||
|
||||
int data_index = getLayerIndex(layer);
|
||||
mdp_pipe_info& pipe_info =
|
||||
sCurrentFrame.pipe_layer[data_index].pipe_index;
|
||||
int index = pipe_info.index;
|
||||
|
||||
if(index < 0) {
|
||||
ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* reset Invalidator */
|
||||
if(idleInvalidator)
|
||||
idleInvalidator->markForSleep();
|
||||
|
||||
ovutils::eDest dest;
|
||||
|
||||
if (index == 0) {
|
||||
dest = ovutils::OV_PIPE0;
|
||||
} else if (index == 1) {
|
||||
dest = ovutils::OV_PIPE1;
|
||||
} else if (index == 2) {
|
||||
dest = ovutils::OV_PIPE2;
|
||||
}
|
||||
|
||||
if (ctx ) {
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
if(!hnd) {
|
||||
ALOGE("%s handle null", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//lock buffer before queue
|
||||
//XXX: Handle lock failure
|
||||
ctx->qbuf->lockAndAdd(hnd);
|
||||
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer,
|
||||
hnd, index );
|
||||
|
||||
if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
|
||||
ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
layer->flags &= ~HWC_MDPCOMP;
|
||||
layer->flags |= HWC_MDPCOMP_INDEX_MASK;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MDPComp::init(hwc_context_t *dev) {
|
||||
|
||||
if(!dev) {
|
||||
ALOGE("%s: Invalid hwc context!!",__FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if SUPPORT_4LAYER
|
||||
if(MAX_MDPCOMP_LAYERS > MAX_STATIC_PIPES) {
|
||||
framebuffer_device_t *fbDev = dev->fbDevice;
|
||||
if(fbDev == NULL) {
|
||||
ALOGE("%s: FATAL: framebuffer device is NULL", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Receive VAR pipe object from framebuffer
|
||||
if(fbDev->perform(fbDev,EVENT_GET_VAR_PIPE,(void*)&ov) < 0) {
|
||||
ALOGE("%s: FATAL: getVariablePipe failed!!", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
sPipeMgr.setStatus(VAR_INDEX, PIPE_IN_FB_MODE);
|
||||
}
|
||||
#endif
|
||||
char property[PROPERTY_VALUE_MAX];
|
||||
|
||||
sMaxLayers = 0;
|
||||
if(property_get("debug.mdpcomp.maxlayer", property, NULL) > 0) {
|
||||
if(atoi(property) != 0)
|
||||
sMaxLayers = atoi(property);
|
||||
}
|
||||
|
||||
sDebugLogs = false;
|
||||
if(property_get("debug.mdpcomp.logs", property, NULL) > 0) {
|
||||
if(atoi(property) != 0)
|
||||
sDebugLogs = true;
|
||||
}
|
||||
|
||||
unsigned long idle_timeout = DEFAULT_IDLE_TIME;
|
||||
if(property_get("debug.mdpcomp.idletime", property, NULL) > 0) {
|
||||
if(atoi(property) != 0)
|
||||
idle_timeout = atoi(property);
|
||||
}
|
||||
|
||||
//create Idle Invalidator
|
||||
idleInvalidator = IdleInvalidator::getInstance();
|
||||
|
||||
if(idleInvalidator == NULL) {
|
||||
ALOGE("%s: failed to instantiate idleInvalidator object", __FUNCTION__);
|
||||
} else {
|
||||
idleInvalidator->init(timeout_handler, dev, idle_timeout);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MDPComp::configure(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
|
||||
|
||||
if(!isEnabled()) {
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
hwc_context_t* ctx = (hwc_context_t*)(dev);
|
||||
|
||||
bool isMDPCompUsed = true;
|
||||
bool doable = is_doable(dev, list);
|
||||
|
||||
if(doable) {
|
||||
if(setup(ctx, list)) {
|
||||
setMDPCompLayerFlags(list);
|
||||
sMDPCompState = MDPCOMP_ON;
|
||||
} else {
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp Failed",__FUNCTION__);
|
||||
isMDPCompUsed = false;
|
||||
}
|
||||
} else {
|
||||
ALOGD_IF( isDebug(),"%s: MDP Comp not possible[%d]",__FUNCTION__,
|
||||
doable);
|
||||
isMDPCompUsed = false;
|
||||
}
|
||||
|
||||
//Reset states
|
||||
if(!isMDPCompUsed) {
|
||||
//Reset current frame
|
||||
reset(ctx, list);
|
||||
}
|
||||
|
||||
sIdleFallBack = false;
|
||||
|
||||
return isMDPCompUsed;
|
||||
}
|
||||
}; //namespace
|
||||
|
220
libhwcomposer/hwc_mdpcomp.h
Normal file
220
libhwcomposer/hwc_mdpcomp.h
Normal 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
|
@ -15,6 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gralloc_priv.h>
|
||||
#include <genlock.h>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// QueuedBufferStore
|
||||
//This class holds currently and previously queued buffers.
|
||||
|
115
libhwcomposer/hwc_uevents.cpp
Normal file
115
libhwcomposer/hwc_uevents.cpp
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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 ))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -13,7 +13,6 @@ LOCAL_SRC_FILES := \
|
||||
overlayCtrl.cpp \
|
||||
overlayUtils.cpp \
|
||||
overlayMdp.cpp \
|
||||
overlayRotator.cpp \
|
||||
overlayTransitions.cpp
|
||||
overlayRotator.cpp
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
@ -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
|
@ -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
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user