libhwcomposer: Add support for 4 layer MDP Comp

This change extends MDP composition to support
upto 4 layers by making border fill as base pipe and
using all MDP h/w pipes in overlay mode.

Conflicts:

	libhwcomposer/hwc.cpp
	libhwcomposer/hwc_utils.cpp
	libhwcomposer/hwc_utils.h

Bug: 7626586
Change-Id: I01a0e53ddfbcf3ed46734f6f3bb0ef7d912ceac6
Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org>
Signed-off-by: Iliyan Malchev <malchev@google.com>
This commit is contained in:
Naseer Ahmed
2012-11-28 18:44:38 -05:00
parent 758bfc5b50
commit 54821fe3a2
9 changed files with 391 additions and 651 deletions

View File

@@ -445,13 +445,17 @@ bool ExternalDisplay::writeHPDOption(int userOption) const
*/ */
bool ExternalDisplay::post() bool ExternalDisplay::post()
{ {
if(mFd == -1) { if(mFd == -1)
return false; return false;
} else if(ioctl(mFd, MSMFB_OVERLAY_COMMIT, &mExternalDisplay) == -1) {
ALOGE("%s: MSMFB_OVERLAY_COMMIT failed, str: %s", __FUNCTION__, struct mdp_display_commit ext_commit;
strerror(errno)); ext_commit.flags |= MDP_DISPLAY_COMMIT_OVERLAY;
if (ioctl(mFd, MSMFB_DISPLAY_COMMIT, &ext_commit) == -1) {
ALOGE("%s: MSMFB_DISPLAY_COMMIT for external failed, str: %s",
__FUNCTION__, strerror(errno));
return false; return false;
} }
return true; return true;
} }

View File

@@ -108,10 +108,11 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
private_module_t* m = private_module_t* m =
reinterpret_cast<private_module_t*>(dev->common.module); reinterpret_cast<private_module_t*>(dev->common.module);
if (hnd && hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { if (hnd) {
m->info.activate = FB_ACTIVATE_VBL | FB_ACTIVATE_FORCE; m->info.activate = FB_ACTIVATE_VBL | FB_ACTIVATE_FORCE;
m->info.yoffset = hnd->offset / m->finfo.line_length; m->info.yoffset = hnd->offset / m->finfo.line_length;
m->commit.var = m->info; m->commit.var = m->info;
m->commit.flags |= MDP_DISPLAY_COMMIT_OVERLAY;
if (ioctl(m->framebuffer->fd, MSMFB_DISPLAY_COMMIT, &m->commit) == -1) { if (ioctl(m->framebuffer->fd, MSMFB_DISPLAY_COMMIT, &m->commit) == -1) {
ALOGE("%s: MSMFB_DISPLAY_COMMIT ioctl failed, err: %s", __FUNCTION__, ALOGE("%s: MSMFB_DISPLAY_COMMIT ioctl failed, err: %s", __FUNCTION__,
strerror(errno)); strerror(errno));

View File

@@ -17,5 +17,6 @@ LOCAL_SRC_FILES := hwc.cpp \
hwc_uevents.cpp \ hwc_uevents.cpp \
hwc_vsync.cpp \ hwc_vsync.cpp \
hwc_fbupdate.cpp \ hwc_fbupdate.cpp \
hwc_mdpcomp.cpp \
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)

View File

@@ -28,6 +28,7 @@
#include "hwc_utils.h" #include "hwc_utils.h"
#include "hwc_video.h" #include "hwc_video.h"
#include "hwc_fbupdate.h" #include "hwc_fbupdate.h"
#include "hwc_mdpcomp.h"
#include "external.h" #include "external.h"
using namespace qhwc; using namespace qhwc;
@@ -97,6 +98,20 @@ static void reset(hwc_context_t *ctx, int numDisplays,
FBUpdate::reset(); FBUpdate::reset();
} }
//clear prev layer prop flags and realloc for current frame
static void reset_layer_prop(hwc_context_t* ctx, int dpy) {
int layer_count = ctx->listStats[dpy].numAppLayers;
if(ctx->layerProp[dpy]) {
delete[] ctx->layerProp[dpy];
ctx->layerProp[dpy] = NULL;
}
if(layer_count) {
ctx->layerProp[dpy] = new LayerProp[layer_count];
}
}
static int hwc_prepare_primary(hwc_composer_device_1 *dev, static int hwc_prepare_primary(hwc_composer_device_1 *dev,
hwc_display_contents_1_t *list) { hwc_display_contents_1_t *list) {
hwc_context_t* ctx = (hwc_context_t*)(dev); hwc_context_t* ctx = (hwc_context_t*)(dev);
@@ -109,7 +124,11 @@ static int hwc_prepare_primary(hwc_composer_device_1 *dev,
if(fbLayer->handle) { if(fbLayer->handle) {
setListStats(ctx, list, HWC_DISPLAY_PRIMARY); setListStats(ctx, list, HWC_DISPLAY_PRIMARY);
ctx->mLayerCache->updateLayerCache(list); ctx->mLayerCache->updateLayerCache(list);
reset_layer_prop(ctx, HWC_DISPLAY_PRIMARY);
if(!MDPComp::configure(ctx, list)) {
VideoOverlay::prepare(ctx, list, HWC_DISPLAY_PRIMARY); VideoOverlay::prepare(ctx, list, HWC_DISPLAY_PRIMARY);
FBUpdate::prepare(ctx, fbLayer, HWC_DISPLAY_PRIMARY);
}
} }
} }
return 0; return 0;
@@ -123,13 +142,14 @@ static int hwc_prepare_external(hwc_composer_device_1 *dev,
ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive && ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive &&
ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected) { ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected) {
setListStats(ctx, list, HWC_DISPLAY_EXTERNAL);
uint32_t last = list->numHwLayers - 1; uint32_t last = list->numHwLayers - 1;
hwc_layer_1_t *fbLayer = &list->hwLayers[last]; hwc_layer_1_t *fbLayer = &list->hwLayers[last];
if(fbLayer->handle) { if(fbLayer->handle) {
FBUpdate::prepare(ctx, fbLayer, HWC_DISPLAY_EXTERNAL); setListStats(ctx, list, HWC_DISPLAY_EXTERNAL);
reset_layer_prop(ctx, HWC_DISPLAY_EXTERNAL);
VideoOverlay::prepare(ctx, list, HWC_DISPLAY_EXTERNAL); VideoOverlay::prepare(ctx, list, HWC_DISPLAY_EXTERNAL);
FBUpdate::prepare(ctx, fbLayer, HWC_DISPLAY_EXTERNAL);
} }
} }
return 0; return 0;
@@ -145,24 +165,20 @@ static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
ctx->mOverlay->configBegin(); ctx->mOverlay->configBegin();
//If securing of h/w in progress skip comp using overlay. for (int32_t i = numDisplays - 1; i >= 0; i--) {
//TODO remove from here when sending FB via overlay
if(ctx->mSecuring == false) {
for (uint32_t i = 0; i < numDisplays; i++) {
hwc_display_contents_1_t *list = displays[i]; hwc_display_contents_1_t *list = displays[i];
switch(i) { switch(i) {
case HWC_DISPLAY_PRIMARY: case HWC_DISPLAY_PRIMARY:
ret = hwc_prepare_primary(dev, list); ret = hwc_prepare_primary(dev, list);
break; break;
case HWC_DISPLAY_EXTERNAL: case HWC_DISPLAY_EXTERNAL:
ret = hwc_prepare_external(dev, list); ret = hwc_prepare_external(dev, list);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
} }
}
ctx->mOverlay->configDone(); ctx->mOverlay->configDone();
return ret; return ret;
@@ -269,14 +285,25 @@ static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
hwc_layer_1_t *fbLayer = &list->hwLayers[last]; hwc_layer_1_t *fbLayer = &list->hwLayers[last];
hwc_sync(ctx, list, HWC_DISPLAY_PRIMARY); hwc_sync(ctx, list, HWC_DISPLAY_PRIMARY);
if (!VideoOverlay::draw(ctx, list, HWC_DISPLAY_PRIMARY)) { if (!VideoOverlay::draw(ctx, list, HWC_DISPLAY_PRIMARY)) {
ALOGE("%s: VideoOverlay::draw fail!", __FUNCTION__); ALOGE("%s: VideoOverlay::draw fail!", __FUNCTION__);
ret = -1; ret = -1;
} }
if (!MDPComp::draw(ctx, list)) {
ALOGE("%s: MDPComp::draw fail!", __FUNCTION__);
ret = -1;
}
//TODO We dont check for SKIP flag on this layer because we need PAN //TODO We dont check for SKIP flag on this layer because we need PAN
//always. Last layer is always FB //always. Last layer is always FB
if(list->hwLayers[last].compositionType == HWC_FRAMEBUFFER_TARGET) { private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
if(fbLayer->compositionType == HWC_FRAMEBUFFER_TARGET && hnd) {
if(!(fbLayer->flags & HWC_SKIP_LAYER)) {
if (!FBUpdate::draw(ctx, fbLayer, HWC_DISPLAY_PRIMARY)) {
ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
ret = -1;
}
}
if (ctx->mFbDev->post(ctx->mFbDev, fbLayer->handle)) { if (ctx->mFbDev->post(ctx->mFbDev, fbLayer->handle)) {
ALOGE("%s: ctx->mFbDev->post fail!", __FUNCTION__); ALOGE("%s: ctx->mFbDev->post fail!", __FUNCTION__);
return -1; return -1;

View File

@@ -17,93 +17,34 @@
*/ */
#include "hwc_mdpcomp.h" #include "hwc_mdpcomp.h"
#include <sys/ioctl.h>
#include "external.h" #include "external.h"
#define SUPPORT_4LAYER 0
namespace qhwc { namespace qhwc {
/****** Class PipeMgr ***********/ namespace ovutils = overlay::utils;
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 ***********/ /****** Class MDPComp ***********/
MDPComp::State MDPComp::sMDPCompState = MDPCOMP_OFF; MDPComp::eState MDPComp::sMDPCompState = MDPCOMP_OFF;
struct MDPComp::frame_info MDPComp::sCurrentFrame; struct MDPComp::FrameInfo MDPComp::sCurrentFrame;
PipeMgr MDPComp::sPipeMgr;
IdleInvalidator *MDPComp::idleInvalidator = NULL; IdleInvalidator *MDPComp::idleInvalidator = NULL;
bool MDPComp::sIdleFallBack = false; bool MDPComp::sIdleFallBack = false;
bool MDPComp::sDebugLogs = false; bool MDPComp::sDebugLogs = false;
int MDPComp::sSkipCount = 0; bool MDPComp::sEnabled = false;
int MDPComp::sMaxLayers = 0; int MDPComp::sActiveMax = 0;
bool MDPComp::sSecuredVid = false;
bool MDPComp::deinit() { bool MDPComp::deinit() {
//XXX: Tear down MDP comp state //XXX: Tear down MDP comp state
return true; return true;
} }
bool MDPComp::isSkipPresent (hwc_context_t *ctx) {
return ctx->listStats[HWC_DISPLAY_PRIMARY].skipCount;
};
bool MDPComp::isYuvPresent (hwc_context_t *ctx) {
return ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount;
};
void MDPComp::timeout_handler(void *udata) { void MDPComp::timeout_handler(void *udata) {
struct hwc_context_t* ctx = (struct hwc_context_t*)(udata); struct hwc_context_t* ctx = (struct hwc_context_t*)(udata);
@@ -125,42 +66,13 @@ void MDPComp::timeout_handler(void *udata) {
void MDPComp::reset(hwc_context_t *ctx, hwc_display_contents_1_t* list ) { void MDPComp::reset(hwc_context_t *ctx, hwc_display_contents_1_t* list ) {
//Reset flags and states //Reset flags and states
unsetMDPCompLayerFlags(ctx, list); unsetMDPCompLayerFlags(ctx, list);
if(sMDPCompState == MDPCOMP_ON) {
sMDPCompState = MDPCOMP_OFF_PENDING;
}
sCurrentFrame.count = 0; sCurrentFrame.count = 0;
if(sCurrentFrame.pipe_layer) { if(sCurrentFrame.pipeLayer) {
free(sCurrentFrame.pipe_layer); free(sCurrentFrame.pipeLayer);
sCurrentFrame.pipe_layer = NULL; sCurrentFrame.pipeLayer = NULL;
} }
//Reset MDP pipes
sPipeMgr.reset();
sPipeMgr.setStatus(VAR_INDEX, PIPE_IN_FB_MODE);
#if SUPPORT_4LAYER
configure_var_pipe(ctx);
#endif
} }
void MDPComp::setLayerIndex(hwc_layer_1_t* layer, const int pipe_index)
{
layer->flags &= ~HWC_MDPCOMP_INDEX_MASK;
layer->flags |= pipe_index << MDPCOMP_INDEX_OFFSET;
}
int MDPComp::getLayerIndex(hwc_layer_1_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_1_t* layer) void MDPComp::print_info(hwc_layer_1_t* layer)
{ {
hwc_rect_t sourceCrop = layer->sourceCrop; hwc_rect_t sourceCrop = layer->sourceCrop;
@@ -181,11 +93,21 @@ void MDPComp::print_info(hwc_layer_1_t* layer)
s_l, s_t, s_r, s_b, (s_r - s_l), (s_b - s_t), 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)); d_l, d_t, d_r, d_b, (d_r - d_l), (d_b - d_t));
} }
void MDPComp::setVidInfo(hwc_layer_1_t *layer, ovutils::eMdpFlags &mdpFlags) {
private_handle_t *hnd = (private_handle_t *)layer->handle;
if(isSecureBuffer(hnd)) {
ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
sSecuredVid = true;
}
}
/* /*
* Configures pipe(s) for MDP composition * Configures pipe(s) for MDP composition
*/ */
int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_1_t *layer, int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_1_t *layer,
mdp_pipe_info& mdp_info) { MdpPipeInfo& mdp_info) {
int nPipeIndex = mdp_info.index; int nPipeIndex = mdp_info.index;
@@ -193,17 +115,15 @@ int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_1_t *layer,
private_handle_t *hnd = (private_handle_t *)layer->handle; private_handle_t *hnd = (private_handle_t *)layer->handle;
overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_PRIMARY]); overlay::Overlay& ov = *ctx->mOverlay;
if(!hnd) { if(!hnd) {
ALOGE("%s: layer handle is NULL", __FUNCTION__); ALOGE("%s: layer handle is NULL", __FUNCTION__);
return -1; return -1;
} }
int hw_w = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
int hw_w = ctx->mFbDev->width; int hw_h = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
int hw_h = ctx->mFbDev->height;
hwc_rect_t sourceCrop = layer->sourceCrop; hwc_rect_t sourceCrop = layer->sourceCrop;
hwc_rect_t displayFrame = layer->displayFrame; hwc_rect_t displayFrame = layer->displayFrame;
@@ -219,18 +139,10 @@ int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_1_t *layer,
int dst_w = dst.right - dst.left; int dst_w = dst.right - dst.left;
int dst_h = dst.bottom - dst.top; 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 || if(dst.left < 0 || dst.top < 0 ||
dst.right > hw_w || dst.bottom > hw_h) { dst.right > hw_w || dst.bottom > hw_h) {
ALOGD_IF(isDebug(),"%s: Destination has negative coordinates", ALOGD_IF(isDebug(),"%s: Destination has negative coordinates",
__FUNCTION__); __FUNCTION__);
qhwc::calculate_crop_rects(crop, dst, hw_w, hw_h, 0); qhwc::calculate_crop_rects(crop, dst, hw_w, hw_h, 0);
//Update calulated width and height //Update calulated width and height
@@ -249,23 +161,18 @@ int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_1_t *layer,
} }
// Determine pipe to set based on pipe index // Determine pipe to set based on pipe index
ovutils::eDest dest = ovutils::OV_PIPE_ALL; ovutils::eDest dest = (ovutils::eDest)mdp_info.index;
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; ovutils::eZorder zOrder = ovutils::ZORDER_0;
if(mdp_info.z_order == 0 ) { if(mdp_info.zOrder == 0 ) {
zOrder = ovutils::ZORDER_0; zOrder = ovutils::ZORDER_0;
} else if(mdp_info.z_order == 1 ) { } else if(mdp_info.zOrder == 1 ) {
zOrder = ovutils::ZORDER_1; zOrder = ovutils::ZORDER_1;
} else if(mdp_info.z_order == 2 ) { } else if(mdp_info.zOrder == 2 ) {
zOrder = ovutils::ZORDER_2; zOrder = ovutils::ZORDER_2;
} else if(mdp_info.zOrder == 3) {
zOrder = ovutils::ZORDER_3;
} }
// Order order order // Order order order
@@ -277,57 +184,53 @@ int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_1_t *layer,
// queueBuffer - not here, happens when draw is called // queueBuffer - not here, happens when draw is called
ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); 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::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
if(isYuvBuffer(hnd))
setVidInfo(layer, mdpFlags);
ovutils::setMdpFlags(mdpFlags,ovutils::OV_MDP_BACKEND_COMPOSITION); ovutils::setMdpFlags(mdpFlags,ovutils::OV_MDP_BACKEND_COMPOSITION);
ovutils::eIsFg isFG = mdp_info.isFG ? ovutils::IS_FG_SET
: ovutils::IS_FG_OFF;
if(layer->blending == HWC_BLENDING_PREMULT) { if(layer->blending == HWC_BLENDING_PREMULT) {
ovutils::setMdpFlags(mdpFlags, ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_BLEND_FG_PREMULT); ovutils::OV_MDP_BLEND_FG_PREMULT);
} }
if(layer->transform & HAL_TRANSFORM_FLIP_H) { ovutils::eTransform orient = overlay::utils::OVERLAY_TRANSFORM_0 ;
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_FLIP_H); if(!(layer->transform & HWC_TRANSFORM_ROT_90)) {
if(layer->transform & HWC_TRANSFORM_FLIP_H) {
ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_FLIP_H);
} }
if(layer->transform & HAL_TRANSFORM_FLIP_V) { if(layer->transform & HWC_TRANSFORM_FLIP_V) {
ovutils::setMdpFlags(mdpFlags, ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_FLIP_V);
ovutils::OV_MDP_FLIP_V); }
} else {
orient = static_cast<ovutils::eTransform>(layer->transform);
} }
ov.setTransform(0, dest);
ovutils::PipeArgs parg(mdpFlags, ovutils::PipeArgs parg(mdpFlags,
info, info,
zOrder, zOrder,
isFG, ovutils::IS_FG_OFF,
ovutils::ROT_FLAG_DISABLED); ovutils::ROT_FLAG_DISABLED);
ovutils::PipeArgs pargs[MAX_PIPES] = { parg, parg, parg }; ov.setSource(parg, dest);
if (!ov.setSource(pargs, dest)) {
ALOGE("%s: setSource failed", __FUNCTION__); ov.setTransform(orient, dest);
return -1;
}
ovutils::Dim dcrop(crop.left, crop.top, crop_w, crop_h); ovutils::Dim dcrop(crop.left, crop.top, crop_w, crop_h);
if (!ov.setCrop(dcrop, dest)) { ov.setCrop(dcrop, dest);
ALOGE("%s: setCrop failed", __FUNCTION__);
return -1;
}
ovutils::Dim dim(dst.left, dst.top, dst_w, dst_h); ovutils::Dim dim(dst.left, dst.top, dst_w, dst_h);
if (!ov.setPosition(dim, dest)) { 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] \ 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, nPipe: %d zorder: %d",__FUNCTION__, dcrop.x,
dcrop.y,dcrop.w, dcrop.h, dim.x, dim.y, dim.w, dim.h, dcrop.y,dcrop.w, dcrop.h, dim.x, dim.y, dim.w, dim.h,
nPipeIndex,mdp_info.isFG, mdp_info.z_order); mdp_info.index, mdp_info.zOrder);
if (!ov.commit(dest)) { if (!ov.commit(dest)) {
ALOGE("%s: commit failed", __FUNCTION__); ALOGE("%s: commit failed", __FUNCTION__);
@@ -347,22 +250,29 @@ int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_1_t *layer,
* 5. Overlay in use * 5. Overlay in use
*/ */
bool MDPComp::is_doable(hwc_context_t *ctx, hwc_display_contents_1_t* list) { bool MDPComp::isDoable(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
//Number of layers //Number of layers
int numAppLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers; int numAppLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
if(numAppLayers < 1 || numAppLayers > (uint32_t)sMaxLayers) {
if(numAppLayers < 1 || numAppLayers > (uint32_t)sActiveMax) {
ALOGD_IF(isDebug(), "%s: Unsupported number of layers",__FUNCTION__); ALOGD_IF(isDebug(), "%s: Unsupported number of layers",__FUNCTION__);
return false; return false;
} }
//Disable MDPComp when ext display connected if(isSecuring(ctx)) {
if(isExternalActive(ctx)) { ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__);
ALOGD_IF(isDebug(), "%s: External display connected.", __FUNCTION__); return false;
}
//Check for skip layers
if(isSkipPresent(ctx)) {
ALOGD_IF(isDebug(), "%s: Skip layers are present",__FUNCTION__);
return false; return false;
} }
//FB composition on idle timeout //FB composition on idle timeout
if(sIdleFallBack) { if(sIdleFallBack) {
sIdleFallBack = false;
ALOGD_IF(isDebug(), "%s: idle fallback",__FUNCTION__); ALOGD_IF(isDebug(), "%s: idle fallback",__FUNCTION__);
return false; return false;
} }
@@ -371,241 +281,110 @@ bool MDPComp::is_doable(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
for(int i = 0; i < numAppLayers; ++i) { for(int i = 0; i < numAppLayers; ++i) {
// As MDP h/w supports flip operation, use MDP comp only for // As MDP h/w supports flip operation, use MDP comp only for
// 180 transforms. Fail for any transform involving 90 (90, 270). // 180 transforms. Fail for any transform involving 90 (90, 270).
if(list->hwLayers[i].transform & HWC_TRANSFORM_ROT_90) { hwc_layer_1_t* layer = &list->hwLayers[i];
private_handle_t *hnd = (private_handle_t *)layer->handle;
if((layer->transform & HWC_TRANSFORM_ROT_90) && !isYuvBuffer(hnd)) {
ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__); ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__);
return false; return false;
} }
} }
return true; return true;
} }
void MDPComp::setMDPCompLayerFlags(hwc_display_contents_1_t* list) { void MDPComp::setMDPCompLayerFlags(hwc_context_t *ctx,
hwc_display_contents_1_t* list) {
LayerProp *layerProp = ctx->layerProp[HWC_DISPLAY_PRIMARY];
for(int index = 0 ; index < sCurrentFrame.count; index++ ) for(int index = 0 ; index < sCurrentFrame.count; index++ ) {
{ hwc_layer_1_t* layer = &(list->hwLayers[index]);
int layer_index = sCurrentFrame.pipe_layer[index].layer_index; layerProp[index].mFlags |= HWC_MDPCOMP;
if(layer_index >= 0) {
hwc_layer_1_t* layer = &(list->hwLayers[layer_index]);
layer->flags |= HWC_MDPCOMP;
layer->compositionType = HWC_OVERLAY; layer->compositionType = HWC_OVERLAY;
layer->hints |= HWC_HINT_CLEAR_FB; layer->hints |= HWC_HINT_CLEAR_FB;
} }
}
} }
void MDPComp::get_layer_info(hwc_layer_1_t* layer, int& flags) { int MDPComp::getMdpPipe(hwc_context_t *ctx, ePipeType type){
overlay::Overlay& ov = *ctx->mOverlay;
int mdp_pipe = -1;
private_handle_t* hnd = (private_handle_t*)layer->handle; switch(type) {
case MDPCOMP_OV_ANY:
if(layer->flags & HWC_SKIP_LAYER) { case MDPCOMP_OV_RGB:
flags |= MDPCOMP_LAYER_SKIP; mdp_pipe = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, HWC_DISPLAY_PRIMARY);
} else if(hnd != NULL && if(mdp_pipe != ovutils::OV_INVALID) {
(hnd->flags & private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM )) { return mdp_pipe;
flags |= MDPCOMP_LAYER_UNSUPPORTED_MEM;
} }
if(layer->blending != HWC_BLENDING_NONE) if(type == MDPCOMP_OV_RGB) {
flags |= MDPCOMP_LAYER_BLEND; //Requested only for RGB pipe
return -1;
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;
} }
case MDPCOMP_OV_VG:
mdp_pipe = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, HWC_DISPLAY_PRIMARY);
if(mdp_pipe != ovutils::OV_INVALID) {
return mdp_pipe;
}
return -1;
default:
ALOGE("%s: Invalid pipe type",__FUNCTION__);
return -1;
};
} }
int MDPComp::mark_layers(hwc_context_t *ctx, bool MDPComp::allocLayerPipes(hwc_context_t *ctx,
hwc_display_contents_1_t* list, layer_mdp_info* layer_info,
frame_info& current_frame) {
int layer_count = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
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_1_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_context_t *ctx,
hwc_display_contents_1_t* list, hwc_display_contents_1_t* list,
layer_mdp_info* layer_info, frame_info& current_frame) { FrameInfo& currentFrame) {
int layer_count = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers; overlay::Overlay& ov = *ctx->mOverlay;
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_1_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_display_contents_1_t* list, frame_info& current_frame ) {
int layer_count = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers; int layer_count = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
/* clear pipe status */ currentFrame.count = layer_count;
sPipeMgr.reset();
layer_mdp_info* bp_layer_info = (layer_mdp_info*) currentFrame.pipeLayer = (PipeLayerPair*)
malloc(sizeof(layer_mdp_info)* layer_count); malloc(sizeof(PipeLayerPair) * currentFrame.count);
reset_layer_mdp_info(bp_layer_info, layer_count); if(isYuvPresent(ctx)) {
int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndex;
/* iterate through layer list to mark candidate */ hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
if(mark_layers(ctx, list, bp_layer_info, current_frame) == MDPCOMP_ABORT) { PipeLayerPair& info = currentFrame.pipeLayer[nYuvIndex];
free(bp_layer_info); MdpPipeInfo& pipe_info = info.pipeIndex;
current_frame.count = 0; pipe_info.index = getMdpPipe(ctx, MDPCOMP_OV_VG);
ALOGE_IF(isDebug(), "%s:mark_layers failed!!", __FUNCTION__); if(pipe_info.index < 0) {
ALOGD_IF(isDebug(), "%s: Unable to get pipe for Videos",
__FUNCTION__);
return false; return false;
} }
current_frame.pipe_layer = (pipe_layer_pair*) pipe_info.zOrder = nYuvIndex;
malloc(sizeof(pipe_layer_pair) * current_frame.count); }
/* allocate MDP pipes for marked layers */ for(int index = 0 ; index < layer_count ; index++ ) {
alloc_layer_pipes(ctx, list, bp_layer_info, current_frame); if(index == ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndex )
continue;
free(bp_layer_info); hwc_layer_1_t* layer = &list->hwLayers[index];
PipeLayerPair& info = currentFrame.pipeLayer[index];
MdpPipeInfo& pipe_info = info.pipeIndex;
pipe_info.index = getMdpPipe(ctx, MDPCOMP_OV_ANY);
if(pipe_info.index < 0) {
ALOGD_IF(isDebug(), "%s: Unable to get pipe for UI", __FUNCTION__);
return false;
}
pipe_info.zOrder = index;
}
return true; 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_display_contents_1_t* list) { bool MDPComp::setup(hwc_context_t* ctx, hwc_display_contents_1_t* list) {
int nPipeIndex, vsync_wait, isFG; int nPipeIndex, vsync_wait, isFG;
int numHwLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers; int numHwLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
frame_info &current_frame = sCurrentFrame; FrameInfo &currentFrame = sCurrentFrame;
current_frame.count = 0; currentFrame.count = 0;
if(current_frame.pipe_layer) { if(currentFrame.pipeLayer) {
free(current_frame.pipe_layer); free(currentFrame.pipeLayer);
current_frame.pipe_layer = NULL; currentFrame.pipeLayer = NULL;
} }
if(!ctx) { if(!ctx) {
@@ -613,125 +392,93 @@ bool MDPComp::setup(hwc_context_t* ctx, hwc_display_contents_1_t* list) {
return -1; return -1;
} }
framebuffer_device_t *fbDev = ctx->mFbDev; if(!allocLayerPipes(ctx, list, currentFrame)) {
if (!fbDev) { //clean current frame data
ALOGE("%s: fbDev is NULL", __FUNCTION__); currentFrame.count = 0;
return -1;
if(currentFrame.pipeLayer) {
free(currentFrame.pipeLayer);
currentFrame.pipeLayer = NULL;
} }
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__); ALOGD_IF(isDebug(), "%s: Falling back to FB", __FUNCTION__);
return false; return false;
} }
#if SUPPORT_4LAYER
configure_var_pipe(ctx);
#endif
overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_PRIMARY]); for (int index = 0 ; index < currentFrame.count; index++) {
ovutils::eOverlayState state = ov.getState(); hwc_layer_1_t* layer = &list->hwLayers[index];
MdpPipeInfo& cur_pipe = currentFrame.pipeLayer[index].pipeIndex;
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_1_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 ) { if( prepare(ctx, layer, cur_pipe) != 0 ) {
ALOGD_IF(isDebug(), "%s: MDPComp failed to configure overlay for \ ALOGD_IF(isDebug(), "%s: MDPComp failed to configure overlay for \
layer %d with pipe index:%d",__FUNCTION__, layer %d with pipe index:%d",__FUNCTION__,
index, cur_pipe.index); index, cur_pipe.index);
return false; return false;
} else {
setLayerIndex(layer, index);
} }
} }
return true; return true;
} }
void MDPComp::unsetMDPCompLayerFlags(hwc_context_t* ctx, hwc_display_contents_1_t* list) void MDPComp::unsetMDPCompLayerFlags(hwc_context_t* ctx,
hwc_display_contents_1_t* list)
{ {
LayerProp *layerProp = ctx->layerProp[HWC_DISPLAY_PRIMARY];
for (int index = 0 ; index < sCurrentFrame.count; index++) { for (int index = 0 ; index < sCurrentFrame.count; index++) {
int l_index = sCurrentFrame.pipe_layer[index].layer_index; if(layerProp[index].mFlags & HWC_MDPCOMP) {
if(list->hwLayers[l_index].flags & HWC_MDPCOMP) { layerProp[index].mFlags &= ~HWC_MDPCOMP;
list->hwLayers[l_index].flags &= ~HWC_MDPCOMP;
} }
if(list->hwLayers[l_index].compositionType == HWC_OVERLAY) { if(list->hwLayers[index].compositionType == HWC_OVERLAY) {
list->hwLayers[l_index].compositionType = HWC_FRAMEBUFFER; list->hwLayers[index].compositionType = HWC_FRAMEBUFFER;
} }
} }
} }
int MDPComp::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) { bool MDPComp::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
if(!isEnabled()) { if(!isEnabled() || !isUsed()) {
ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled",__FUNCTION__); ALOGD_IF(isDebug(),"%s: MDP Comp not configured", __FUNCTION__);
return 0; return true;
} }
if(!ctx || !list) { if(!ctx || !list) {
ALOGE("%s: invalid contxt or list",__FUNCTION__); ALOGE("%s: invalid contxt or list",__FUNCTION__);
return -1; return false;
}
overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_PRIMARY]);
int numHwLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
for(int i = 0; i < numHwLayers; i++ )
{
hwc_layer_1_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 */ /* reset Invalidator */
if(idleInvalidator) if(idleInvalidator)
idleInvalidator->markForSleep(); idleInvalidator->markForSleep();
ovutils::eDest dest; overlay::Overlay& ov = *ctx->mOverlay;
LayerProp *layerProp = ctx->layerProp[HWC_DISPLAY_PRIMARY];
if (index == 0) { int numHwLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
dest = ovutils::OV_PIPE0; for(int i = 0; i < numHwLayers; i++ )
} else if (index == 1) { {
dest = ovutils::OV_PIPE1; hwc_layer_1_t *layer = &list->hwLayers[i];
} else if (index == 2) {
dest = ovutils::OV_PIPE2; if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
continue;
} }
MdpPipeInfo& pipe_info =
sCurrentFrame.pipeLayer[i].pipeIndex;
int index = pipe_info.index;
if(index < 0) {
ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, index);
return false;
}
ovutils::eDest dest = (ovutils::eDest)index;
if (ctx ) { if (ctx ) {
private_handle_t *hnd = (private_handle_t *)layer->handle; private_handle_t *hnd = (private_handle_t *)layer->handle;
if(!hnd) { if(!hnd) {
ALOGE("%s handle null", __FUNCTION__); ALOGE("%s handle null", __FUNCTION__);
return -1; return false;
} }
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
@@ -740,45 +487,75 @@ int MDPComp::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) { if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
ALOGE("%s: queueBuffer failed for external", __FUNCTION__); ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
return -1; return false;
} }
} }
layer->flags &= ~HWC_MDPCOMP;
layer->flags |= HWC_MDPCOMP_INDEX_MASK; layerProp[i].mFlags &= ~HWC_MDPCOMP;
} }
return 0; return true;
} }
bool MDPComp::init(hwc_context_t *dev) { /*
* Sets up BORDERFILL as default base pipe and detaches RGB0.
* Framebuffer is always updated using PLAY ioctl.
*/
if(!dev) { bool MDPComp::setupBasePipe(hwc_context_t *ctx) {
int fb_stride = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].stride;
int fb_width = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
int fb_height = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
int fb_fd = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd;
mdp_overlay ovInfo;
msmfb_overlay_data ovData;
memset(&ovInfo, 0, sizeof(mdp_overlay));
memset(&ovData, 0, sizeof(msmfb_overlay_data));
ovInfo.src.format = MDP_RGB_BORDERFILL;
ovInfo.src.width = fb_width;
ovInfo.src.height = fb_height;
ovInfo.src_rect.w = fb_width;
ovInfo.src_rect.h = fb_height;
ovInfo.dst_rect.w = fb_width;
ovInfo.dst_rect.h = fb_height;
ovInfo.id = MSMFB_NEW_REQUEST;
if (ioctl(fb_fd, MSMFB_OVERLAY_SET, &ovInfo) < 0) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_SET err=%s",
strerror(errno));
return false;
}
ovData.id = ovInfo.id;
if (ioctl(fb_fd, MSMFB_OVERLAY_PLAY, &ovData) < 0) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY err=%s",
strerror(errno));
return false;
}
return true;
}
bool MDPComp::init(hwc_context_t *ctx) {
if(!ctx) {
ALOGE("%s: Invalid hwc context!!",__FUNCTION__); ALOGE("%s: Invalid hwc context!!",__FUNCTION__);
return false; return false;
} }
#if SUPPORT_4LAYER if(!setupBasePipe(ctx)) {
if(MAX_MDPCOMP_LAYERS > MAX_STATIC_PIPES) { ALOGE("%s: Failed to setup primary base pipe", __FUNCTION__);
framebuffer_device_t *fbDev = dev->fbDevice;
if(fbDev == NULL) {
ALOGE("%s: FATAL: framebuffer device is NULL", __FUNCTION__);
return false; 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]; char property[PROPERTY_VALUE_MAX];
sMaxLayers = 0; sEnabled = false;
if(property_get("debug.mdpcomp.maxlayer", property, NULL) > 0) { if((property_get("persist.hwc.mdpcomp.enable", property, NULL) > 0) &&
if(atoi(property) != 0) (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
sMaxLayers = atoi(property); (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
sEnabled = true;
} }
sDebugLogs = false; sDebugLogs = false;
@@ -799,25 +576,29 @@ bool MDPComp::init(hwc_context_t *dev) {
if(idleInvalidator == NULL) { if(idleInvalidator == NULL) {
ALOGE("%s: failed to instantiate idleInvalidator object", __FUNCTION__); ALOGE("%s: failed to instantiate idleInvalidator object", __FUNCTION__);
} else { } else {
idleInvalidator->init(timeout_handler, dev, idle_timeout); idleInvalidator->init(timeout_handler, ctx, idle_timeout);
} }
return true; return true;
} }
bool MDPComp::configure(hwc_context_t *ctx, hwc_display_contents_1_t* list) { bool MDPComp::configure(hwc_context_t *ctx,
hwc_display_contents_1_t* list) {
if(!isEnabled()) { if(!isEnabled()) {
ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__); ALOGE_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
return false; return false;
} }
overlay::Overlay& ov = *ctx->mOverlay;
sActiveMax = ov.availablePipes();
bool isMDPCompUsed = true; bool isMDPCompUsed = true;
bool doable = is_doable(ctx, list); bool doable = isDoable(ctx, list);
if(doable) { if(doable) {
if(setup(ctx, list)) { if(setup(ctx, list)) {
setMDPCompLayerFlags(list); setMDPCompLayerFlags(ctx, list);
sMDPCompState = MDPCOMP_ON;
} else { } else {
ALOGD_IF(isDebug(),"%s: MDP Comp Failed",__FUNCTION__); ALOGD_IF(isDebug(),"%s: MDP Comp Failed",__FUNCTION__);
isMDPCompUsed = false; isMDPCompUsed = false;
@@ -834,7 +615,7 @@ bool MDPComp::configure(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
reset(ctx, list); reset(ctx, list);
} }
sIdleFallBack = false; sMDPCompState = isMDPCompUsed ? MDPCOMP_ON : MDPCOMP_OFF;
return isMDPCompUsed; return isMDPCompUsed;
} }

View File

@@ -24,126 +24,47 @@
#include <cutils/properties.h> #include <cutils/properties.h>
#include <overlay.h> #include <overlay.h>
#define MAX_STATIC_PIPES 3
#define MDPCOMP_INDEX_OFFSET 4
#define DEFAULT_IDLE_TIME 2000 #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 { namespace qhwc {
namespace ovutils = overlay::utils;
// 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 { class MDPComp {
enum State { enum eState {
MDPCOMP_ON = 0, MDPCOMP_ON = 0,
MDPCOMP_OFF, MDPCOMP_OFF,
MDPCOMP_OFF_PENDING,
}; };
enum { enum ePipeType {
MDPCOMP_LAYER_BLEND = 1, MDPCOMP_OV_RGB = ovutils::OV_MDP_PIPE_RGB,
MDPCOMP_LAYER_DOWNSCALE = 2, MDPCOMP_OV_VG = ovutils::OV_MDP_PIPE_VG,
MDPCOMP_LAYER_SKIP = 4, MDPCOMP_OV_ANY,
MDPCOMP_LAYER_UNSUPPORTED_MEM = 8,
}; };
struct mdp_pipe_info { struct MdpPipeInfo {
int index; int index;
int z_order; int zOrder;
bool isVG;
bool isFG;
bool vsync_wait;
}; };
struct pipe_layer_pair { struct PipeLayerPair {
int layer_index; MdpPipeInfo pipeIndex;
mdp_pipe_info pipe_index;
native_handle_t* handle; native_handle_t* handle;
}; };
struct frame_info { struct FrameInfo {
int count; int count;
struct pipe_layer_pair* pipe_layer; struct PipeLayerPair* pipeLayer;
}; };
struct layer_mdp_info { static eState sMDPCompState;
bool can_use_mdp;
int pipe_pref;
};
static State sMDPCompState;
static IdleInvalidator *idleInvalidator; static IdleInvalidator *idleInvalidator;
static struct frame_info sCurrentFrame; static struct FrameInfo sCurrentFrame;
static PipeMgr sPipeMgr; static bool sEnabled;
static int sSkipCount;
static int sMaxLayers;
static bool sDebugLogs; static bool sDebugLogs;
static bool sIdleFallBack; static bool sIdleFallBack;
static int sActiveMax;
static bool sSecuredVid;
public: public:
/* Handler to invoke frame redraw on Idle Timer expiry */ /* Handler to invoke frame redraw on Idle Timer expiry */
@@ -152,24 +73,19 @@ public:
/* configure/tear-down MDPComp params*/ /* configure/tear-down MDPComp params*/
static bool init(hwc_context_t *ctx); static bool init(hwc_context_t *ctx);
static bool deinit(); static bool deinit();
static bool isUsed() { return (sMDPCompState == MDPCOMP_ON); };
/*sets up mdp comp for the current frame */ /*sets up mdp comp for the current frame */
static bool configure(hwc_context_t *ctx, hwc_display_contents_1_t* list); static bool configure(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* draw */ /* draw */
static int draw(hwc_context_t *ctx, hwc_display_contents_1_t *list); static bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list);
/* store frame stats */
static void setStats(int skipCt) { sSkipCount = skipCt;};
private: private:
/* get/set pipe index associated with overlay layers */
static void setLayerIndex(hwc_layer_1_t* layer, const int pipe_index);
static int getLayerIndex(hwc_layer_1_t* layer);
/* set/reset flags for MDPComp */ /* set/reset flags for MDPComp */
static void setMDPCompLayerFlags(hwc_display_contents_1_t* list); static void setMDPCompLayerFlags(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
static void unsetMDPCompLayerFlags(hwc_context_t* ctx, static void unsetMDPCompLayerFlags(hwc_context_t* ctx,
hwc_display_contents_1_t* list); hwc_display_contents_1_t* list);
@@ -177,45 +93,42 @@ private:
/* configure's overlay pipes for the frame */ /* configure's overlay pipes for the frame */
static int prepare(hwc_context_t *ctx, hwc_layer_1_t *layer, static int prepare(hwc_context_t *ctx, hwc_layer_1_t *layer,
mdp_pipe_info& mdp_info); MdpPipeInfo& mdp_info);
/* checks for conditions where mdpcomp is not possible */ /* checks for conditions where mdpcomp is not possible */
static bool is_doable(hwc_context_t *ctx, hwc_display_contents_1_t* list); static bool isDoable(hwc_context_t *ctx, hwc_display_contents_1_t* list);
static bool setup(hwc_context_t* ctx, hwc_display_contents_1_t* list); static bool setup(hwc_context_t* ctx, hwc_display_contents_1_t* list);
/* parses layer for properties affecting mdp comp */
static void get_layer_info(hwc_layer_1_t* layer, int& flags);
/* iterates through layer list to choose candidate to use overlay */
static int mark_layers(hwc_context_t *ctx, hwc_display_contents_1_t* list,
layer_mdp_info* layer_info, frame_info& current_frame);
static bool parse_and_allocate(hwc_context_t* ctx, hwc_display_contents_1_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 */ /* allocates pipes to selected candidates */
static bool alloc_layer_pipes(hwc_context_t *ctx, static bool allocLayerPipes(hwc_context_t *ctx,
hwc_display_contents_1_t* list, hwc_display_contents_1_t* list,
layer_mdp_info* layer_info, FrameInfo& current_frame);
frame_info& current_frame);
/* updates variable pipe mode for the current frame */
static int configure_var_pipe(hwc_context_t* ctx);
/* get/set states */ /* get/set states */
static State get_state() { return sMDPCompState; }; static eState getState() { return sMDPCompState; };
static void set_state(State state) { sMDPCompState = state; };
/* reset state */ /* reset state */
static void reset( hwc_context_t *ctx, hwc_display_contents_1_t* list ); static void reset( hwc_context_t *ctx, hwc_display_contents_1_t* list );
/* Is feature enabled */ /* Is feature enabled */
static bool isEnabled() { return sMaxLayers ? true : false; }; static bool isEnabled() { return sEnabled; };
/* Is debug enabled */ /* Is debug enabled */
static bool isDebug() { return sDebugLogs ? true : false; }; static bool isDebug() { return sDebugLogs ? true : false; };
/* check layer state */
static bool isSkipPresent (hwc_context_t *ctx);
static bool isYuvPresent (hwc_context_t *ctx);
/* configure MDP flags for video buffers */
static void setVidInfo(hwc_layer_1_t *layer, ovutils::eMdpFlags &mdpFlags);
/* set up Border fill as Base pipe */
static bool setupBasePipe(hwc_context_t*);
/* allocate MDP pipes from overlay */
static int getMdpPipe(hwc_context_t *ctx, ePipeType type);
}; };
}; //namespace }; //namespace
#endif #endif

View File

@@ -22,6 +22,7 @@
#include <fb_priv.h> #include <fb_priv.h>
#include <overlay.h> #include <overlay.h>
#include "hwc_utils.h" #include "hwc_utils.h"
#include "hwc_mdpcomp.h"
#include "mdp_version.h" #include "mdp_version.h"
#include "external.h" #include "external.h"
#include "QService.h" #include "QService.h"
@@ -37,6 +38,8 @@ static void openFramebufferDevice(hwc_context_t *ctx)
private_module_t* m = reinterpret_cast<private_module_t*>( private_module_t* m = reinterpret_cast<private_module_t*>(
ctx->mFbDev->common.module); ctx->mFbDev->common.module);
//xres, yres may not be 32 aligned //xres, yres may not be 32 aligned
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].stride = m->finfo.line_length /
(m->info.xres/8);
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = m->info.xres; ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = m->info.xres;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = m->info.yres; ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = m->info.yres;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = ctx->mFbDev->xdpi; ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = ctx->mFbDev->xdpi;
@@ -58,6 +61,7 @@ void initContext(hwc_context_t *ctx)
ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType(); ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
ctx->mExtDisplay = new ExternalDisplay(ctx); ctx->mExtDisplay = new ExternalDisplay(ctx);
ctx->mLayerCache = new LayerCache(); ctx->mLayerCache = new LayerCache();
MDPComp::init(ctx);
pthread_mutex_init(&(ctx->vstate.lock), NULL); pthread_mutex_init(&(ctx->vstate.lock), NULL);
pthread_cond_init(&(ctx->vstate.cond), NULL); pthread_cond_init(&(ctx->vstate.cond), NULL);
@@ -151,6 +155,16 @@ static inline void calc_cut(float& leftCutRatio, float& topCutRatio,
} }
} }
bool isSecuring(hwc_context_t* ctx) {
if((ctx->mMDP.version < qdutils::MDSS_V5) &&
(ctx->mMDP.version > qdutils::MDP_V3_0) &&
ctx->mSecuring) {
return true;
}
return false;
}
//Crops source buffer against destination and FB boundaries //Crops source buffer against destination and FB boundaries
void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst, void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
const int fbWidth, const int fbHeight, int orient) { const int fbWidth, const int fbHeight, int orient) {
@@ -214,8 +228,7 @@ int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy) {
for(uint32_t i = 0; i < list->numHwLayers; i++) { for(uint32_t i = 0; i < list->numHwLayers; i++) {
if((list->hwLayers[i].compositionType == HWC_OVERLAY || if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) && list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) &&
list->hwLayers[i].acquireFenceFd != -1 && list->hwLayers[i].acquireFenceFd != -1 ){
(list->hwLayers[i].flags & HWC_MDPCOMP)) {
acquireFd[count++] = list->hwLayers[i].acquireFenceFd; acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
} }
} }

View File

@@ -58,6 +58,7 @@ struct DisplayAttributes {
uint32_t vsync_period; //nanos uint32_t vsync_period; //nanos
uint32_t xres; uint32_t xres;
uint32_t yres; uint32_t yres;
uint32_t stride;
float xdpi; float xdpi;
float ydpi; float ydpi;
int fd; int fd;
@@ -76,10 +77,15 @@ struct ListStats {
int yuvIndex; int yuvIndex;
}; };
struct LayerProp {
uint32_t mFlags; //qcom specific layer flags
LayerProp():mFlags(0) {};
};
// LayerProp::flag values
enum { enum {
HWC_MDPCOMP = 0x00000002, HWC_MDPCOMP = 0x00000001,
HWC_LAYER_RESERVED_0 = 0x00000004,
HWC_LAYER_RESERVED_1 = 0x00000008
}; };
class LayerCache { class LayerCache {
@@ -103,6 +109,8 @@ class LayerCache {
}; };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Utility functions - implemented in hwc_utils.cpp // Utility functions - implemented in hwc_utils.cpp
void dumpLayer(hwc_layer_1_t const* l); void dumpLayer(hwc_layer_1_t const* l);
@@ -113,7 +121,7 @@ void closeContext(hwc_context_t *ctx);
//Crops source buffer against destination and FB boundaries //Crops source buffer against destination and FB boundaries
void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst, void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
const int fbWidth, const int fbHeight, int orient); const int fbWidth, const int fbHeight, int orient);
bool isSecuring(hwc_context_t* ctx);
bool isExternalActive(hwc_context_t* ctx); bool isExternalActive(hwc_context_t* ctx);
//Sync point impl. //Sync point impl.
@@ -196,33 +204,24 @@ struct vsync_state {
struct hwc_context_t { struct hwc_context_t {
hwc_composer_device_1_t device; hwc_composer_device_1_t device;
const hwc_procs_t* proc; const hwc_procs_t* proc;
//Framebuffer device //Framebuffer device
framebuffer_device_t *mFbDev; framebuffer_device_t *mFbDev;
//Overlay object - NULL for non overlay devices //Overlay object - NULL for non overlay devices
overlay::Overlay *mOverlay; overlay::Overlay *mOverlay;
//QService object //QService object
qService::QService *mQService; qService::QService *mQService;
// External display related information // External display related information
qhwc::ExternalDisplay *mExtDisplay; qhwc::ExternalDisplay *mExtDisplay;
qhwc::MDPInfo mMDP; qhwc::MDPInfo mMDP;
qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES]; qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES];
qhwc::ListStats listStats[HWC_NUM_DISPLAY_TYPES]; qhwc::ListStats listStats[HWC_NUM_DISPLAY_TYPES];
qhwc::LayerCache *mLayerCache; qhwc::LayerCache *mLayerCache;
qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES];
//Securing in progress indicator //Securing in progress indicator
bool mSecuring; bool mSecuring;
//Display in secure mode indicator //Display in secure mode indicator
bool mSecureMode; bool mSecureMode;
//Lock to prevent set from being called while blanking //Lock to prevent set from being called while blanking
mutable Locker mBlankLock; mutable Locker mBlankLock;
//Lock to protect set when detaching external disp //Lock to protect set when detaching external disp

View File

@@ -40,6 +40,11 @@ bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
return false; return false;
} }
if(isSecuring(ctx)) {
ALOGD_IF(VIDEO_DEBUG,"%s: MDP Secure is active", __FUNCTION__);
return false;
}
if(yuvIndex == -1 || ctx->listStats[dpy].yuvCount != 1) { if(yuvIndex == -1 || ctx->listStats[dpy].yuvCount != 1) {
return false; return false;
} }
@@ -106,13 +111,9 @@ bool VideoOverlay::configure(hwc_context_t *ctx, int dpy,
isFgFlag = ovutils::IS_FG_SET; isFgFlag = ovutils::IS_FG_SET;
} }
//TODO change to 1 always when primary FB uses overlay.
const ovutils::eZorder zorder = (dpy == HWC_DISPLAY_PRIMARY) ?
ovutils::ZORDER_0 : ovutils::ZORDER_1;
ovutils::PipeArgs parg(mdpFlags, ovutils::PipeArgs parg(mdpFlags,
info, info,
zorder, ovutils::ZORDER_1,
isFgFlag, isFgFlag,
ovutils::ROT_FLAG_DISABLED); ovutils::ROT_FLAG_DISABLED);