HWC: Use 2 VG pipes for YUV layer with width > 2048
To minimize usage of decimation when 4K x 2K video is played on primary, split the yuv layer into 2 halves and configure each layer to individual VG pipes. With this approach, decimation can be avoided in some 4K x 2K video use cases, thereby improving performance. Change-Id: I7cddfab787c50f6ff132eaa7f5a3d9cfd636c282
This commit is contained in:
@@ -45,6 +45,7 @@ bool MDPComp::sEnablePartialFrameUpdate = false;
|
||||
int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
|
||||
float MDPComp::sMaxBw = 2.3f;
|
||||
double MDPComp::sBwClaimed = 0.0;
|
||||
bool MDPComp::sEnable4k2kYUVSplit = false;
|
||||
|
||||
MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
|
||||
if(isDisplaySplit(ctx, dpy)) {
|
||||
@@ -154,6 +155,12 @@ bool MDPComp::init(hwc_context_t *ctx) {
|
||||
idleInvalidator->init(timeout_handler, ctx, idle_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
if((property_get("debug.mdpcomp.4k2kSplit", property, "0") > 0) &&
|
||||
(!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
|
||||
(!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
|
||||
sEnable4k2kYUVSplit = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -588,6 +595,10 @@ bool MDPComp::fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
|
||||
mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount -
|
||||
mCurrentFrame.dropCount;
|
||||
|
||||
if(sEnable4k2kYUVSplit){
|
||||
modifymdpCountfor4k2k(ctx, list);
|
||||
}
|
||||
|
||||
if(!resourceCheck(ctx, list)) {
|
||||
ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
|
||||
return false;
|
||||
@@ -643,6 +654,10 @@ bool MDPComp::cacheBasedComp(hwc_context_t *ctx,
|
||||
|
||||
int mdpCount = mCurrentFrame.mdpCount;
|
||||
|
||||
if(sEnable4k2kYUVSplit){
|
||||
modifymdpCountfor4k2k(ctx, list);
|
||||
}
|
||||
|
||||
//Will benefit cases where a video has non-updating background.
|
||||
if((mDpy > HWC_DISPLAY_PRIMARY) and
|
||||
(mdpCount > MAX_SEC_LAYERS)) {
|
||||
@@ -713,6 +728,10 @@ bool MDPComp::loadBasedCompPreferGPU(hwc_context_t *ctx,
|
||||
mCurrentFrame.fbCount = batchSize;
|
||||
mCurrentFrame.mdpCount = mCurrentFrame.layerCount - batchSize;
|
||||
|
||||
if(sEnable4k2kYUVSplit){
|
||||
modifymdpCountfor4k2k(ctx, list);
|
||||
}
|
||||
|
||||
if(!resourceCheck(ctx, list)) {
|
||||
ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
|
||||
return false;
|
||||
@@ -764,6 +783,10 @@ bool MDPComp::loadBasedCompPreferMDP(hwc_context_t *ctx,
|
||||
mCurrentFrame.fbCount = fbBatchSize;
|
||||
mCurrentFrame.mdpCount = mCurrentFrame.layerCount - fbBatchSize;
|
||||
|
||||
if(sEnable4k2kYUVSplit){
|
||||
modifymdpCountfor4k2k(ctx, list);
|
||||
}
|
||||
|
||||
if(!resourceCheck(ctx, list)) {
|
||||
ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
|
||||
return false;
|
||||
@@ -1092,10 +1115,23 @@ bool MDPComp::programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
|
||||
MdpPipeInfo* cur_pipe = mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
|
||||
cur_pipe->zOrder = mdpNextZOrder++;
|
||||
|
||||
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
|
||||
if(configure4k2kYuv(ctx, layer,
|
||||
mCurrentFrame.mdpToLayer[mdpIndex])
|
||||
!= 0 ){
|
||||
ALOGD_IF(isDebug(), "%s: Failed to configure split pipes \
|
||||
for layer %d",__FUNCTION__, index);
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
mdpNextZOrder++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
|
||||
ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
|
||||
layer %d",__FUNCTION__, index);
|
||||
layer %d",__FUNCTION__, index);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1119,6 +1155,20 @@ bool MDPComp::programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
|
||||
mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
|
||||
cur_pipe->zOrder = mdpIdx++;
|
||||
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
|
||||
if(configure4k2kYuv(ctx, layer,
|
||||
mCurrentFrame.mdpToLayer[mdpIndex])
|
||||
!= 0 ){
|
||||
ALOGD_IF(isDebug(), "%s: Failed to configure split pipes \
|
||||
for layer %d",__FUNCTION__, index);
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
mdpIdx++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(configure(ctx, layer,
|
||||
mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
|
||||
ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
|
||||
@@ -1232,6 +1282,20 @@ int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
|
||||
mCurrentFrame.map();
|
||||
//Configure framebuffer first if applicable
|
||||
if(mCurrentFrame.fbZ >= 0) {
|
||||
//If 4k2k Yuv layer split is possible, and if
|
||||
//fbz is above 4k2k layer, increment fb zorder by 1
|
||||
//as we split 4k2k layer and increment zorder for right half
|
||||
//of the layer
|
||||
if(sEnable4k2kYUVSplit){
|
||||
int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
|
||||
for(int index = 0; index < n4k2kYuvCount; index++){
|
||||
int n4k2kYuvIndex =
|
||||
ctx->listStats[mDpy].yuv4k2kIndices[index];
|
||||
if(mCurrentFrame.fbZ > n4k2kYuvIndex){
|
||||
mCurrentFrame.fbZ += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list,
|
||||
mCurrentFrame.fbZ)) {
|
||||
ALOGE("%s configure framebuffer failed", __func__);
|
||||
@@ -1262,6 +1326,11 @@ int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
|
||||
//Try to compose atleast YUV layers through MDP comp and let
|
||||
//all the RGB layers compose in FB
|
||||
//Destination over
|
||||
|
||||
if(sEnable4k2kYUVSplit){
|
||||
modifymdpCountfor4k2k(ctx, list);
|
||||
}
|
||||
|
||||
mCurrentFrame.fbZ = -1;
|
||||
if(mCurrentFrame.fbCount)
|
||||
mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
|
||||
@@ -1311,8 +1380,45 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool MDPComp::allocSplitVGPipesfor4k2k(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list, int index) {
|
||||
|
||||
bool bRet = true;
|
||||
hwc_layer_1_t* layer = &list->hwLayers[index];
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
int mdpIndex = mCurrentFrame.layerToMDP[index];
|
||||
PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
|
||||
info.pipeInfo = new MdpYUVPipeInfo;
|
||||
info.rot = NULL;
|
||||
MdpYUVPipeInfo& pipe_info = *(MdpYUVPipeInfo*)info.pipeInfo;
|
||||
ePipeType type = MDPCOMP_OV_VG;
|
||||
|
||||
pipe_info.lIndex = ovutils::OV_INVALID;
|
||||
pipe_info.rIndex = ovutils::OV_INVALID;
|
||||
|
||||
pipe_info.lIndex = getMdpPipe(ctx, type, Overlay::MIXER_DEFAULT);
|
||||
if(pipe_info.lIndex == ovutils::OV_INVALID){
|
||||
bRet = false;
|
||||
ALOGD_IF(isDebug(),"%s: allocating first VG pipe failed",
|
||||
__FUNCTION__);
|
||||
}
|
||||
pipe_info.rIndex = getMdpPipe(ctx, type, Overlay::MIXER_DEFAULT);
|
||||
if(pipe_info.rIndex == ovutils::OV_INVALID){
|
||||
bRet = false;
|
||||
ALOGD_IF(isDebug(),"%s: allocating second VG pipe failed",
|
||||
__FUNCTION__);
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
//=============MDPCompNonSplit===================================================
|
||||
|
||||
void MDPCompNonSplit::modifymdpCountfor4k2k(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list){
|
||||
//As we split 4kx2k yuv layer and program to 2 VG pipes
|
||||
//(if available) increase mdpcount accordingly
|
||||
mCurrentFrame.mdpCount += ctx->listStats[mDpy].yuv4k2kCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures pipe(s) for MDP composition
|
||||
*/
|
||||
@@ -1364,7 +1470,10 @@ bool MDPCompNonSplit::areVGPipesAvailable(hwc_context_t *ctx,
|
||||
hwc_layer_1_t* layer = &list->hwLayers[i];
|
||||
hwc_rect_t dst = layer->displayFrame;
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
if(isYuvBuffer(hnd)) {
|
||||
if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
|
||||
pipesNeeded = pipesNeeded + 2;
|
||||
}
|
||||
else if(isYuvBuffer(hnd)) {
|
||||
pipesNeeded++;
|
||||
}
|
||||
}
|
||||
@@ -1389,6 +1498,12 @@ bool MDPCompNonSplit::allocLayerPipes(hwc_context_t *ctx,
|
||||
|
||||
hwc_layer_1_t* layer = &list->hwLayers[index];
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
|
||||
if(allocSplitVGPipesfor4k2k(ctx, list, index)){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int mdpIndex = mCurrentFrame.layerToMDP[index];
|
||||
PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
|
||||
info.pipeInfo = new MdpPipeInfoNonSplit;
|
||||
@@ -1414,6 +1529,20 @@ bool MDPCompNonSplit::allocLayerPipes(hwc_context_t *ctx,
|
||||
return true;
|
||||
}
|
||||
|
||||
int MDPCompNonSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
|
||||
PipeLayerPair& PipeLayerPair) {
|
||||
MdpYUVPipeInfo& mdp_info =
|
||||
*(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
|
||||
eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
|
||||
eIsFg isFg = IS_FG_OFF;
|
||||
eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
|
||||
eDest lDest = mdp_info.lIndex;
|
||||
eDest rDest = mdp_info.rIndex;
|
||||
|
||||
return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg,
|
||||
lDest, rDest, &PipeLayerPair.rot);
|
||||
}
|
||||
|
||||
bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
|
||||
|
||||
if(!isEnabled()) {
|
||||
@@ -1452,36 +1581,75 @@ bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
|
||||
|
||||
int mdpIndex = mCurrentFrame.layerToMDP[i];
|
||||
|
||||
MdpPipeInfoNonSplit& pipe_info =
|
||||
if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit)
|
||||
{
|
||||
MdpYUVPipeInfo& pipe_info =
|
||||
*(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
|
||||
Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
|
||||
ovutils::eDest indexL = pipe_info.lIndex;
|
||||
ovutils::eDest indexR = pipe_info.rIndex;
|
||||
int fd = hnd->fd;
|
||||
uint32_t offset = hnd->offset;
|
||||
if(rot) {
|
||||
rot->queueBuffer(fd, offset);
|
||||
fd = rot->getDstMemId();
|
||||
offset = rot->getDstOffset();
|
||||
}
|
||||
if(indexL != ovutils::OV_INVALID) {
|
||||
ovutils::eDest destL = (ovutils::eDest)indexL;
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer, hnd, indexL );
|
||||
if (!ov.queueBuffer(fd, offset, destL)) {
|
||||
ALOGE("%s: queueBuffer failed for display:%d",
|
||||
__FUNCTION__, mDpy);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(indexR != ovutils::OV_INVALID) {
|
||||
ovutils::eDest destR = (ovutils::eDest)indexR;
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer, hnd, indexR );
|
||||
if (!ov.queueBuffer(fd, offset, destR)) {
|
||||
ALOGE("%s: queueBuffer failed for display:%d",
|
||||
__FUNCTION__, mDpy);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
MdpPipeInfoNonSplit& pipe_info =
|
||||
*(MdpPipeInfoNonSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
|
||||
ovutils::eDest dest = pipe_info.index;
|
||||
if(dest == ovutils::OV_INVALID) {
|
||||
ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer,
|
||||
hnd, dest );
|
||||
|
||||
int fd = hnd->fd;
|
||||
uint32_t offset = hnd->offset;
|
||||
|
||||
Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
|
||||
if(rot) {
|
||||
if(!rot->queueBuffer(fd, offset))
|
||||
ovutils::eDest dest = pipe_info.index;
|
||||
if(dest == ovutils::OV_INVALID) {
|
||||
ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest);
|
||||
return false;
|
||||
fd = rot->getDstMemId();
|
||||
offset = rot->getDstOffset();
|
||||
}
|
||||
}
|
||||
|
||||
if (!ov.queueBuffer(fd, offset, dest)) {
|
||||
ALOGE("%s: queueBuffer failed for display:%d ", __FUNCTION__, mDpy);
|
||||
return false;
|
||||
if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer,
|
||||
hnd, dest );
|
||||
|
||||
int fd = hnd->fd;
|
||||
uint32_t offset = hnd->offset;
|
||||
|
||||
Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
|
||||
if(rot) {
|
||||
if(!rot->queueBuffer(fd, offset))
|
||||
return false;
|
||||
fd = rot->getDstMemId();
|
||||
offset = rot->getDstOffset();
|
||||
}
|
||||
|
||||
if (!ov.queueBuffer(fd, offset, dest)) {
|
||||
ALOGE("%s: queueBuffer failed for display:%d ",
|
||||
__FUNCTION__, mDpy);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
layerProp[i].mFlags &= ~HWC_MDPCOMP;
|
||||
@@ -1491,6 +1659,23 @@ bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
|
||||
|
||||
//=============MDPCompSplit===================================================
|
||||
|
||||
void MDPCompSplit::modifymdpCountfor4k2k(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list){
|
||||
//if 4kx2k yuv layer is totally present in either in left half
|
||||
//or right half then try splitting the yuv layer to avoid decimation
|
||||
int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
|
||||
const int lSplit = getLeftSplit(ctx, mDpy);
|
||||
for(int index = 0; index < n4k2kYuvCount; index++){
|
||||
int n4k2kYuvIndex = ctx->listStats[mDpy].yuv4k2kIndices[index];
|
||||
hwc_layer_1_t* layer = &list->hwLayers[n4k2kYuvIndex];
|
||||
hwc_rect_t dst = layer->displayFrame;
|
||||
|
||||
if((dst.left > lSplit)||(dst.right < lSplit)){
|
||||
mCurrentFrame.mdpCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int MDPCompSplit::pipesNeeded(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list,
|
||||
int mixer) {
|
||||
@@ -1563,6 +1748,12 @@ bool MDPCompSplit::areVGPipesAvailable(hwc_context_t *ctx,
|
||||
hwc_layer_1_t* layer = &list->hwLayers[i];
|
||||
hwc_rect_t dst = layer->displayFrame;
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
|
||||
if((dst.left > lSplit)||(dst.right < lSplit)){
|
||||
pipesNeeded = pipesNeeded + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(isYuvBuffer(hnd)) {
|
||||
if(dst.left < lSplit) {
|
||||
pipesNeeded++;
|
||||
@@ -1618,6 +1809,15 @@ bool MDPCompSplit::allocLayerPipes(hwc_context_t *ctx,
|
||||
|
||||
hwc_layer_1_t* layer = &list->hwLayers[index];
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
hwc_rect_t dst = layer->displayFrame;
|
||||
const int lSplit = getLeftSplit(ctx, mDpy);
|
||||
if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
|
||||
if((dst.left > lSplit)||(dst.right < lSplit)){
|
||||
if(allocSplitVGPipesfor4k2k(ctx, list, index)){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
int mdpIndex = mCurrentFrame.layerToMDP[index];
|
||||
PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
|
||||
info.pipeInfo = new MdpPipeInfoSplit;
|
||||
@@ -1642,6 +1842,27 @@ bool MDPCompSplit::allocLayerPipes(hwc_context_t *ctx,
|
||||
return true;
|
||||
}
|
||||
|
||||
int MDPCompSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
|
||||
PipeLayerPair& PipeLayerPair) {
|
||||
const int lSplit = getLeftSplit(ctx, mDpy);
|
||||
hwc_rect_t dst = layer->displayFrame;
|
||||
if((dst.left > lSplit)||(dst.right < lSplit)){
|
||||
MdpYUVPipeInfo& mdp_info =
|
||||
*(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
|
||||
eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
|
||||
eIsFg isFg = IS_FG_OFF;
|
||||
eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
|
||||
eDest lDest = mdp_info.lIndex;
|
||||
eDest rDest = mdp_info.rIndex;
|
||||
|
||||
return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg,
|
||||
lDest, rDest, &PipeLayerPair.rot);
|
||||
}
|
||||
else{
|
||||
return configure(ctx, layer, PipeLayerPair);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures pipe(s) for MDP composition
|
||||
*/
|
||||
@@ -1704,48 +1925,88 @@ bool MDPCompSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
|
||||
|
||||
int mdpIndex = mCurrentFrame.layerToMDP[i];
|
||||
|
||||
MdpPipeInfoSplit& pipe_info =
|
||||
*(MdpPipeInfoSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
|
||||
Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
|
||||
if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit)
|
||||
{
|
||||
MdpYUVPipeInfo& pipe_info =
|
||||
*(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
|
||||
Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
|
||||
ovutils::eDest indexL = pipe_info.lIndex;
|
||||
ovutils::eDest indexR = pipe_info.rIndex;
|
||||
int fd = hnd->fd;
|
||||
uint32_t offset = hnd->offset;
|
||||
if(rot) {
|
||||
rot->queueBuffer(fd, offset);
|
||||
fd = rot->getDstMemId();
|
||||
offset = rot->getDstOffset();
|
||||
}
|
||||
if(indexL != ovutils::OV_INVALID) {
|
||||
ovutils::eDest destL = (ovutils::eDest)indexL;
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer, hnd, indexL );
|
||||
if (!ov.queueBuffer(fd, offset, destL)) {
|
||||
ALOGE("%s: queueBuffer failed for display:%d",
|
||||
__FUNCTION__, mDpy);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ovutils::eDest indexL = pipe_info.lIndex;
|
||||
ovutils::eDest indexR = pipe_info.rIndex;
|
||||
|
||||
int fd = hnd->fd;
|
||||
int offset = hnd->offset;
|
||||
|
||||
if(ctx->mAD->isModeOn()) {
|
||||
if(ctx->mAD->draw(ctx, fd, offset)) {
|
||||
fd = ctx->mAD->getDstFd(ctx);
|
||||
offset = ctx->mAD->getDstOffset(ctx);
|
||||
if(indexR != ovutils::OV_INVALID) {
|
||||
ovutils::eDest destR = (ovutils::eDest)indexR;
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer, hnd, indexR );
|
||||
if (!ov.queueBuffer(fd, offset, destR)) {
|
||||
ALOGE("%s: queueBuffer failed for display:%d",
|
||||
__FUNCTION__, mDpy);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
MdpPipeInfoSplit& pipe_info =
|
||||
*(MdpPipeInfoSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
|
||||
Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
|
||||
|
||||
if(rot) {
|
||||
rot->queueBuffer(fd, offset);
|
||||
fd = rot->getDstMemId();
|
||||
offset = rot->getDstOffset();
|
||||
}
|
||||
ovutils::eDest indexL = pipe_info.lIndex;
|
||||
ovutils::eDest indexR = pipe_info.rIndex;
|
||||
|
||||
//************* play left mixer **********
|
||||
if(indexL != ovutils::OV_INVALID) {
|
||||
ovutils::eDest destL = (ovutils::eDest)indexL;
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer, hnd, indexL );
|
||||
if (!ov.queueBuffer(fd, offset, destL)) {
|
||||
ALOGE("%s: queueBuffer failed for left mixer", __FUNCTION__);
|
||||
return false;
|
||||
int fd = hnd->fd;
|
||||
int offset = hnd->offset;
|
||||
|
||||
if(ctx->mAD->isModeOn()) {
|
||||
if(ctx->mAD->draw(ctx, fd, offset)) {
|
||||
fd = ctx->mAD->getDstFd(ctx);
|
||||
offset = ctx->mAD->getDstOffset(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//************* play right mixer **********
|
||||
if(indexR != ovutils::OV_INVALID) {
|
||||
ovutils::eDest destR = (ovutils::eDest)indexR;
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer, hnd, indexR );
|
||||
if (!ov.queueBuffer(fd, offset, destR)) {
|
||||
ALOGE("%s: queueBuffer failed for right mixer", __FUNCTION__);
|
||||
return false;
|
||||
if(rot) {
|
||||
rot->queueBuffer(fd, offset);
|
||||
fd = rot->getDstMemId();
|
||||
offset = rot->getDstOffset();
|
||||
}
|
||||
|
||||
//************* play left mixer **********
|
||||
if(indexL != ovutils::OV_INVALID) {
|
||||
ovutils::eDest destL = (ovutils::eDest)indexL;
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer, hnd, indexL );
|
||||
if (!ov.queueBuffer(fd, offset, destL)) {
|
||||
ALOGE("%s: queueBuffer failed for left mixer",
|
||||
__FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//************* play right mixer **********
|
||||
if(indexR != ovutils::OV_INVALID) {
|
||||
ovutils::eDest destR = (ovutils::eDest)indexR;
|
||||
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
|
||||
using pipe: %d", __FUNCTION__, layer, hnd, indexR );
|
||||
if (!ov.queueBuffer(fd, offset, destR)) {
|
||||
ALOGE("%s: queueBuffer failed for right mixer",
|
||||
__FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,12 @@ protected:
|
||||
virtual ~MdpPipeInfo(){};
|
||||
};
|
||||
|
||||
struct MdpYUVPipeInfo : public MdpPipeInfo{
|
||||
ovutils::eDest lIndex;
|
||||
ovutils::eDest rIndex;
|
||||
virtual ~MdpYUVPipeInfo(){};
|
||||
};
|
||||
|
||||
/* per layer data */
|
||||
struct PipeLayerPair {
|
||||
MdpPipeInfo *pipeInfo;
|
||||
@@ -133,7 +139,12 @@ protected:
|
||||
/* Checks for pipes needed versus pipes available */
|
||||
virtual bool arePipesAvailable(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list) = 0;
|
||||
|
||||
/* increments mdpCount if 4k2k yuv layer split is enabled*/
|
||||
virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list) = 0;
|
||||
/* configures 4kx2k yuv layer*/
|
||||
virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
|
||||
PipeLayerPair& PipeLayerPair) = 0;
|
||||
/* set/reset flags for MDPComp */
|
||||
void setMDPCompLayerFlags(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list);
|
||||
@@ -219,6 +230,10 @@ protected:
|
||||
static IdleInvalidator *idleInvalidator;
|
||||
struct FrameInfo mCurrentFrame;
|
||||
struct LayerCache mCachedFrame;
|
||||
//Enable 4kx2k yuv layer split
|
||||
static bool sEnable4k2kYUVSplit;
|
||||
bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list, int index);
|
||||
};
|
||||
|
||||
class MDPCompNonSplit : public MDPComp {
|
||||
@@ -248,6 +263,14 @@ private:
|
||||
/* Checks for video pipes needed versus pipes available */
|
||||
virtual bool areVGPipesAvailable(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list);
|
||||
|
||||
/* increments mdpCount if 4k2k yuv layer split is enabled*/
|
||||
virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list);
|
||||
|
||||
/* configures 4kx2k yuv layer to 2 VG pipes*/
|
||||
virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
|
||||
PipeLayerPair& PipeLayerPair);
|
||||
};
|
||||
|
||||
class MDPCompSplit : public MDPComp {
|
||||
@@ -281,6 +304,14 @@ private:
|
||||
virtual bool areVGPipesAvailable(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list);
|
||||
|
||||
/* increments mdpCount if 4k2k yuv layer split is enabled*/
|
||||
virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
|
||||
hwc_display_contents_1_t* list);
|
||||
|
||||
/* configures 4kx2k yuv layer*/
|
||||
virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
|
||||
PipeLayerPair& PipeLayerPair);
|
||||
|
||||
int pipesNeeded(hwc_context_t *ctx, hwc_display_contents_1_t* list,
|
||||
int mixer);
|
||||
};
|
||||
|
||||
@@ -743,6 +743,7 @@ void setListStats(hwc_context_t *ctx,
|
||||
ctx->listStats[dpy].roi = ovutils::Dim(0, 0,
|
||||
(int)ctx->dpyAttr[dpy].xres, (int)ctx->dpyAttr[dpy].yres);
|
||||
ctx->listStats[dpy].secureUI = false;
|
||||
ctx->listStats[dpy].yuv4k2kCount = 0;
|
||||
|
||||
trimList(ctx, list, dpy);
|
||||
optimizeLayerRects(ctx, list, dpy);
|
||||
@@ -765,6 +766,7 @@ void setListStats(hwc_context_t *ctx,
|
||||
|
||||
//reset yuv indices
|
||||
ctx->listStats[dpy].yuvIndices[i] = -1;
|
||||
ctx->listStats[dpy].yuv4k2kIndices[i] = -1;
|
||||
|
||||
if (isSecureBuffer(hnd)) {
|
||||
ctx->listStats[dpy].isSecurePresent = true;
|
||||
@@ -779,6 +781,12 @@ void setListStats(hwc_context_t *ctx,
|
||||
ctx->listStats[dpy].yuvIndices[yuvCount] = i;
|
||||
yuvCount++;
|
||||
|
||||
if(UNLIKELY(is4kx2kYuvBuffer(hnd))){
|
||||
int& yuv4k2kCount = ctx->listStats[dpy].yuv4k2kCount;
|
||||
ctx->listStats[dpy].yuv4k2kIndices[yuv4k2kCount] = i;
|
||||
yuv4k2kCount++;
|
||||
}
|
||||
|
||||
if((layer->transform & HWC_TRANSFORM_ROT_90) &&
|
||||
canUseRotator(ctx, dpy)) {
|
||||
if( (dpy == HWC_DISPLAY_PRIMARY) &&
|
||||
@@ -1681,6 +1689,129 @@ int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
|
||||
const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
|
||||
eIsFg& isFg, const eDest& lDest, const eDest& rDest,
|
||||
Rotator **rot) {
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
if(!hnd) {
|
||||
ALOGE("%s: layer handle is NULL", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
|
||||
|
||||
int hw_w = ctx->dpyAttr[dpy].xres;
|
||||
int hw_h = ctx->dpyAttr[dpy].yres;
|
||||
hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);;
|
||||
hwc_rect_t dst = layer->displayFrame;
|
||||
int transform = layer->transform;
|
||||
eTransform orient = static_cast<eTransform>(transform);
|
||||
const int downscale = 0;
|
||||
int rotFlags = ROT_FLAGS_NONE;
|
||||
//Splitting only YUV layer on primary panel needs different zorders
|
||||
//for both layers as both the layers are configured to single mixer
|
||||
eZorder lz = z;
|
||||
eZorder rz = (eZorder)(z + 1);
|
||||
|
||||
Whf whf(getWidth(hnd), getHeight(hnd),
|
||||
getMdpFormat(hnd->format), hnd->size);
|
||||
|
||||
setMdpFlags(layer, mdpFlagsL, 0, transform);
|
||||
trimLayer(ctx, dpy, transform, crop, dst);
|
||||
|
||||
if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
|
||||
(*rot) = ctx->mRotMgr->getNext();
|
||||
if((*rot) == NULL) return -1;
|
||||
if(!dpy)
|
||||
BwcPM::setBwc(ctx, crop, dst, transform, mdpFlagsL);
|
||||
//Configure rotator for pre-rotation
|
||||
if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
|
||||
ALOGE("%s: configRotator failed!", __FUNCTION__);
|
||||
ctx->mOverlay->clear(dpy);
|
||||
return -1;
|
||||
}
|
||||
ctx->mLayerRotMap[dpy]->add(layer, *rot);
|
||||
whf.format = (*rot)->getDstFormat();
|
||||
updateSource(orient, whf, crop);
|
||||
rotFlags |= ROT_PREROTATED;
|
||||
}
|
||||
|
||||
eMdpFlags mdpFlagsR = mdpFlagsL;
|
||||
int lSplit = dst.left + (dst.right - dst.left)/2;
|
||||
|
||||
hwc_rect_t tmp_cropL = {0}, tmp_dstL = {0};
|
||||
hwc_rect_t tmp_cropR = {0}, tmp_dstR = {0};
|
||||
|
||||
if(lDest != OV_INVALID) {
|
||||
tmp_cropL = crop;
|
||||
tmp_dstL = dst;
|
||||
hwc_rect_t scissor = {dst.left, dst.top, lSplit, dst.bottom };
|
||||
qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0);
|
||||
}
|
||||
if(rDest != OV_INVALID) {
|
||||
tmp_cropR = crop;
|
||||
tmp_dstR = dst;
|
||||
hwc_rect_t scissor = {lSplit, dst.top, dst.right, dst.bottom };
|
||||
qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0);
|
||||
}
|
||||
|
||||
sanitizeSourceCrop(tmp_cropL, tmp_cropR, hnd);
|
||||
|
||||
//When buffer is H-flipped, contents of mixer config also needs to swapped
|
||||
//Not needed if the layer is confined to one half of the screen.
|
||||
//If rotator has been used then it has also done the flips, so ignore them.
|
||||
if((orient & OVERLAY_TRANSFORM_FLIP_H) && lDest != OV_INVALID
|
||||
&& rDest != OV_INVALID && (*rot) == NULL) {
|
||||
hwc_rect_t new_cropR;
|
||||
new_cropR.left = tmp_cropL.left;
|
||||
new_cropR.right = new_cropR.left + (tmp_cropR.right - tmp_cropR.left);
|
||||
|
||||
hwc_rect_t new_cropL;
|
||||
new_cropL.left = new_cropR.right;
|
||||
new_cropL.right = tmp_cropR.right;
|
||||
|
||||
tmp_cropL.left = new_cropL.left;
|
||||
tmp_cropL.right = new_cropL.right;
|
||||
|
||||
tmp_cropR.left = new_cropR.left;
|
||||
tmp_cropR.right = new_cropR.right;
|
||||
|
||||
}
|
||||
|
||||
//For the mdp, since either we are pre-rotating or MDP does flips
|
||||
orient = OVERLAY_TRANSFORM_0;
|
||||
transform = 0;
|
||||
|
||||
//configure left half
|
||||
if(lDest != OV_INVALID) {
|
||||
PipeArgs pargL(mdpFlagsL, whf, lz, isFg,
|
||||
static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
|
||||
(ovutils::eBlending) getBlending(layer->blending));
|
||||
|
||||
if(configMdp(ctx->mOverlay, pargL, orient,
|
||||
tmp_cropL, tmp_dstL, metadata, lDest) < 0) {
|
||||
ALOGE("%s: commit failed for left half config", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//configure right half
|
||||
if(rDest != OV_INVALID) {
|
||||
PipeArgs pargR(mdpFlagsR, whf, rz, isFg,
|
||||
static_cast<eRotFlags>(rotFlags),
|
||||
layer->planeAlpha,
|
||||
(ovutils::eBlending) getBlending(layer->blending));
|
||||
if(configMdp(ctx->mOverlay, pargR, orient,
|
||||
tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
|
||||
ALOGE("%s: commit failed for right half config", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool canUseRotator(hwc_context_t *ctx, int dpy) {
|
||||
if(qdutils::MDPVersion::getInstance().is8x26() &&
|
||||
ctx->mVirtualDisplay->isConnected() &&
|
||||
|
||||
@@ -99,6 +99,8 @@ struct ListStats {
|
||||
int extOnlyLayerIndex;
|
||||
bool needsAlphaScale;
|
||||
bool preMultipliedAlpha;
|
||||
int yuv4k2kIndices[MAX_NUM_APP_LAYERS];
|
||||
int yuv4k2kCount;
|
||||
// Notifies hwcomposer about the start and end of animation
|
||||
// This will be set to true during animation, otherwise false.
|
||||
bool isDisplayAnimating;
|
||||
@@ -283,6 +285,13 @@ int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
|
||||
ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
|
||||
const ovutils::eDest& rDest, overlay::Rotator **rot);
|
||||
|
||||
//Routine to split and configure high resolution YUV layer (> 2048 width)
|
||||
int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
|
||||
const int& dpy,
|
||||
ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
|
||||
ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
|
||||
const ovutils::eDest& rDest, overlay::Rotator **rot);
|
||||
|
||||
//On certain targets DMA pipes are used for rotation and they won't be available
|
||||
//for line operations. On a per-target basis we can restrict certain use cases
|
||||
//from using rotator, since we know before-hand that such scenarios can lead to
|
||||
@@ -305,6 +314,12 @@ static inline bool isYuvBuffer(const private_handle_t* hnd) {
|
||||
return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO));
|
||||
}
|
||||
|
||||
// Returns true if the buffer is yuv
|
||||
static inline bool is4kx2kYuvBuffer(const private_handle_t* hnd) {
|
||||
return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) &&
|
||||
(hnd->width > 2048));
|
||||
}
|
||||
|
||||
// Returns true if the buffer is secure
|
||||
static inline bool isSecureBuffer(const private_handle_t* hnd) {
|
||||
return (hnd && (private_handle_t::PRIV_FLAGS_SECURE_BUFFER & hnd->flags));
|
||||
|
||||
Reference in New Issue
Block a user