Add support for panel resolution switch. This feature makes use of the Linux modedb feature that lists available modes in /sys/class/graphics/fb0/modes and accepts a mode change when written to /sys/class/graphics/fb0/mode Clients can link to APIs exposed in display_config.h, these internally resolve to binder calls into HWC. For debugging, mode changes can be made over binder using shell commands. adb shell service call display.qservice CODE ARGS ARGS can include config index and display (only primary supported) setActiveConfig(): adb shell service call display.qservice 25 i32 INDEX i32 0 getActiveConfig(): adb shell service call display.qservice 26 i32 0 getConfigCount(): adb shell service call display.qservice 27 i32 0 getDisplayAttributes(): adb shell service call display.qservice 28 i32 INDEX i32 0 Change-Id: I97d34cc9c0e521a3bd5c948eeea6d1e07db7b7ff
604 lines
23 KiB
C++
604 lines
23 KiB
C++
/*
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
* Copyright (C) 2012-2014, The Linux Foundation. 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_FBUPDATE 0
|
|
#include <cutils/properties.h>
|
|
#include <gralloc_priv.h>
|
|
#include <overlay.h>
|
|
#include <overlayRotator.h>
|
|
#include "hwc_fbupdate.h"
|
|
#include "mdp_version.h"
|
|
#include <video/msm_hdmi_modes.h>
|
|
|
|
using namespace qdutils;
|
|
using namespace overlay;
|
|
using overlay::Rotator;
|
|
using namespace overlay::utils;
|
|
|
|
namespace qhwc {
|
|
|
|
namespace ovutils = overlay::utils;
|
|
|
|
IFBUpdate* IFBUpdate::getObject(hwc_context_t *ctx, const int& dpy) {
|
|
if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
|
|
return new FBSrcSplit(ctx, dpy);
|
|
} else if(isDisplaySplit(ctx, dpy)) {
|
|
return new FBUpdateSplit(ctx, dpy);
|
|
}
|
|
return new FBUpdateNonSplit(ctx, dpy);
|
|
}
|
|
|
|
IFBUpdate::IFBUpdate(hwc_context_t *ctx, const int& dpy) : mDpy(dpy) {
|
|
unsigned int size = 0;
|
|
uint32_t xres = ctx->dpyAttr[mDpy].xres;
|
|
uint32_t yres = ctx->dpyAttr[mDpy].yres;
|
|
if (ctx->dpyAttr[dpy].fbScaling) {
|
|
xres = ctx->dpyAttr[mDpy].xresFB;
|
|
yres = ctx->dpyAttr[mDpy].yresFB;
|
|
}
|
|
getBufferAttributes((int)xres, (int)yres,
|
|
HAL_PIXEL_FORMAT_RGBA_8888,
|
|
0,
|
|
mAlignedFBWidth,
|
|
mAlignedFBHeight,
|
|
mTileEnabled, size);
|
|
}
|
|
|
|
void IFBUpdate::reset() {
|
|
mModeOn = false;
|
|
mRot = NULL;
|
|
}
|
|
|
|
bool IFBUpdate::prepareAndValidate(hwc_context_t *ctx,
|
|
hwc_display_contents_1 *list, int fbZorder) {
|
|
hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
|
|
mModeOn = prepare(ctx, list, layer->displayFrame, fbZorder) &&
|
|
ctx->mOverlay->validateAndSet(mDpy, ctx->dpyAttr[mDpy].fd);
|
|
return mModeOn;
|
|
}
|
|
|
|
//================= Low res====================================
|
|
FBUpdateNonSplit::FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy):
|
|
IFBUpdate(ctx, dpy) {}
|
|
|
|
void FBUpdateNonSplit::reset() {
|
|
IFBUpdate::reset();
|
|
mDest = ovutils::OV_INVALID;
|
|
}
|
|
|
|
bool FBUpdateNonSplit::preRotateExtDisplay(hwc_context_t *ctx,
|
|
hwc_layer_1_t *layer,
|
|
ovutils::Whf &info,
|
|
hwc_rect_t& sourceCrop,
|
|
ovutils::eMdpFlags& mdpFlags,
|
|
int& rotFlags)
|
|
{
|
|
int extOrient = getExtOrientation(ctx);
|
|
ovutils::eTransform orient = static_cast<ovutils::eTransform >(extOrient);
|
|
if(mDpy && (extOrient & HWC_TRANSFORM_ROT_90)) {
|
|
mRot = ctx->mRotMgr->getNext();
|
|
if(mRot == NULL) return false;
|
|
ctx->mLayerRotMap[mDpy]->add(layer, mRot);
|
|
// Composed FB content will have black bars, if the viewFrame of the
|
|
// external is different from {0, 0, fbWidth, fbHeight}, so intersect
|
|
// viewFrame with sourceCrop to avoid those black bars
|
|
sourceCrop = getIntersection(sourceCrop, ctx->mViewFrame[mDpy]);
|
|
//Configure rotator for pre-rotation
|
|
if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) {
|
|
ALOGE("%s: configRotator Failed!", __FUNCTION__);
|
|
mRot = NULL;
|
|
return false;
|
|
}
|
|
updateSource(orient, info, sourceCrop, mRot);
|
|
rotFlags |= ovutils::ROT_PREROTATED;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FBUpdateNonSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
|
|
hwc_rect_t fbUpdatingRect, int fbZorder) {
|
|
if(!ctx->mMDP.hasOverlay) {
|
|
ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
|
|
__FUNCTION__);
|
|
return false;
|
|
}
|
|
mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
|
|
return mModeOn;
|
|
}
|
|
|
|
// Configure
|
|
bool FBUpdateNonSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
|
|
hwc_rect_t fbUpdatingRect, int fbZorder) {
|
|
bool ret = false;
|
|
hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
|
|
if (LIKELY(ctx->mOverlay)) {
|
|
overlay::Overlay& ov = *(ctx->mOverlay);
|
|
|
|
int flags = mTileEnabled ?
|
|
private_handle_t::PRIV_FLAGS_TILE_RENDERED : 0;
|
|
ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
|
|
ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, flags));
|
|
|
|
Overlay::PipeSpecs pipeSpecs;
|
|
pipeSpecs.formatClass = Overlay::FORMAT_RGB;
|
|
pipeSpecs.needsScaling = qhwc::needsScaling(layer);
|
|
pipeSpecs.dpy = mDpy;
|
|
pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
|
|
pipeSpecs.fb = true;
|
|
|
|
ovutils::eDest dest = ov.getPipe(pipeSpecs);
|
|
if(dest == ovutils::OV_INVALID) { //None available
|
|
ALOGE("%s: No pipes available to configure fb for dpy %d",
|
|
__FUNCTION__, mDpy);
|
|
return false;
|
|
}
|
|
mDest = dest;
|
|
|
|
if((mDpy && ctx->deviceOrientation) &&
|
|
ctx->listStats[mDpy].isDisplayAnimating) {
|
|
fbZorder = 0;
|
|
}
|
|
|
|
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
|
|
ovutils::setMdpFlags(mdpFlags,
|
|
ovutils::OV_MDP_SMP_FORCE_ALLOC);
|
|
ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
|
|
|
|
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
|
|
hwc_rect_t displayFrame = layer->displayFrame;
|
|
|
|
// No FB update optimization on (1) Custom FB resolution,
|
|
// (2) External Mirror mode, (3) External orientation
|
|
if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
|
|
&& !ctx->mExtOrientation) {
|
|
sourceCrop = fbUpdatingRect;
|
|
displayFrame = fbUpdatingRect;
|
|
}
|
|
|
|
int transform = layer->transform;
|
|
int rotFlags = ovutils::ROT_FLAGS_NONE;
|
|
|
|
ovutils::eTransform orient =
|
|
static_cast<ovutils::eTransform>(transform);
|
|
// use ext orientation if any
|
|
int extOrient = getExtOrientation(ctx);
|
|
|
|
// Do not use getNonWormholeRegion() function to calculate the
|
|
// sourceCrop during animation on external display and
|
|
// Dont do wormhole calculation when extorientation is set on External
|
|
// Dont do wormhole calculation when scaling mode is set on External
|
|
if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
|
|
sourceCrop = layer->displayFrame;
|
|
} else if((mDpy && !extOrient
|
|
&& !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
|
|
if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
|
|
!ctx->dpyAttr[mDpy].fbScaling) {
|
|
getNonWormholeRegion(list, sourceCrop);
|
|
displayFrame = sourceCrop;
|
|
}
|
|
}
|
|
calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
|
|
transform, orient);
|
|
//Store the displayFrame, will be used in getDisplayViewFrame
|
|
ctx->dpyAttr[mDpy].mDstRect = displayFrame;
|
|
setMdpFlags(ctx, layer, mdpFlags, 0, transform);
|
|
// For External use rotator if there is a rotation value set
|
|
ret = preRotateExtDisplay(ctx, layer, info,
|
|
sourceCrop, mdpFlags, rotFlags);
|
|
if(!ret) {
|
|
ALOGE("%s: preRotate for external Failed!", __FUNCTION__);
|
|
return false;
|
|
}
|
|
//For the mdp, since either we are pre-rotating or MDP does flips
|
|
orient = ovutils::OVERLAY_TRANSFORM_0;
|
|
transform = 0;
|
|
ovutils::PipeArgs parg(mdpFlags, info, zOrder,
|
|
static_cast<ovutils::eRotFlags>(rotFlags),
|
|
ovutils::DEFAULT_PLANE_ALPHA,
|
|
(ovutils::eBlending)
|
|
getBlending(layer->blending));
|
|
ret = true;
|
|
if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
|
|
NULL, mDest) < 0) {
|
|
ALOGE("%s: configMdp failed for dpy %d", __FUNCTION__, mDpy);
|
|
ret = false;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool FBUpdateNonSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
|
|
{
|
|
if(!mModeOn) {
|
|
return true;
|
|
}
|
|
bool ret = true;
|
|
overlay::Overlay& ov = *(ctx->mOverlay);
|
|
ovutils::eDest dest = mDest;
|
|
int fd = hnd->fd;
|
|
uint32_t offset = (uint32_t)hnd->offset;
|
|
if(mRot) {
|
|
if(!mRot->queueBuffer(fd, offset))
|
|
return false;
|
|
fd = mRot->getDstMemId();
|
|
offset = mRot->getDstOffset();
|
|
}
|
|
if (!ov.queueBuffer(fd, offset, dest)) {
|
|
ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
|
|
ret = false;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//================= High res====================================
|
|
FBUpdateSplit::FBUpdateSplit(hwc_context_t *ctx, const int& dpy):
|
|
IFBUpdate(ctx, dpy) {}
|
|
|
|
void FBUpdateSplit::reset() {
|
|
IFBUpdate::reset();
|
|
mDestLeft = ovutils::OV_INVALID;
|
|
mDestRight = ovutils::OV_INVALID;
|
|
mRot = NULL;
|
|
}
|
|
|
|
bool FBUpdateSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
|
|
hwc_rect_t fbUpdatingRect, int fbZorder) {
|
|
if(!ctx->mMDP.hasOverlay) {
|
|
ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
|
|
__FUNCTION__);
|
|
return false;
|
|
}
|
|
mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
|
|
ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
|
|
return mModeOn;
|
|
}
|
|
|
|
// Configure
|
|
bool FBUpdateSplit::configure(hwc_context_t *ctx,
|
|
hwc_display_contents_1 *list, hwc_rect_t fbUpdatingRect, int fbZorder) {
|
|
bool ret = false;
|
|
hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
|
|
if (LIKELY(ctx->mOverlay)) {
|
|
int flags = mTileEnabled ?
|
|
private_handle_t::PRIV_FLAGS_TILE_RENDERED : 0;
|
|
ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
|
|
ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, flags));
|
|
|
|
overlay::Overlay& ov = *(ctx->mOverlay);
|
|
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
|
|
ovutils::setMdpFlags(mdpFlags,
|
|
ovutils::OV_MDP_SMP_FORCE_ALLOC);
|
|
ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
|
|
ovutils::eTransform orient =
|
|
static_cast<ovutils::eTransform>(layer->transform);
|
|
const int hw_w = ctx->dpyAttr[mDpy].xres;
|
|
const int hw_h = ctx->dpyAttr[mDpy].yres;
|
|
const int lSplit = getLeftSplit(ctx, mDpy);
|
|
mDestLeft = ovutils::OV_INVALID;
|
|
mDestRight = ovutils::OV_INVALID;
|
|
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
|
|
hwc_rect_t displayFrame = layer->displayFrame;
|
|
|
|
// No FB update optimization on (1) Custom FB resolution,
|
|
// (2) External Mirror mode, (3) External orientation
|
|
if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
|
|
&& !ctx->mExtOrientation) {
|
|
sourceCrop = fbUpdatingRect;
|
|
displayFrame = fbUpdatingRect;
|
|
}
|
|
|
|
int transform = layer->transform;
|
|
// use ext orientation if any
|
|
int extOrient = getExtOrientation(ctx);
|
|
|
|
// Do not use getNonWormholeRegion() function to calculate the
|
|
// sourceCrop during animation on external display and
|
|
// Dont do wormhole calculation when extorientation is set on External
|
|
// Dont do wormhole calculation when scaling mode is set on External
|
|
if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
|
|
sourceCrop = layer->displayFrame;
|
|
} else if((mDpy && !extOrient
|
|
&& !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
|
|
if(!qdutils::MDPVersion::getInstance().is8x26() &&
|
|
!ctx->dpyAttr[mDpy].fbScaling) {
|
|
getNonWormholeRegion(list, sourceCrop);
|
|
displayFrame = sourceCrop;
|
|
}
|
|
}
|
|
|
|
calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
|
|
transform, orient);
|
|
|
|
ret = true;
|
|
Overlay::PipeSpecs pipeSpecs;
|
|
pipeSpecs.formatClass = Overlay::FORMAT_RGB;
|
|
pipeSpecs.needsScaling = qhwc::needsScaling(layer);
|
|
pipeSpecs.dpy = mDpy;
|
|
pipeSpecs.fb = true;
|
|
|
|
/* Configure left pipe */
|
|
if(displayFrame.left < lSplit) {
|
|
pipeSpecs.mixer = Overlay::MIXER_LEFT;
|
|
ovutils::eDest destL = ov.getPipe(pipeSpecs);
|
|
if(destL == ovutils::OV_INVALID) { //None available
|
|
ALOGE("%s: No pipes available to configure fb for dpy %d's left"
|
|
" mixer", __FUNCTION__, mDpy);
|
|
return false;
|
|
}
|
|
|
|
mDestLeft = destL;
|
|
|
|
//XXX: FB layer plane alpha is currently sent as zero from
|
|
//surfaceflinger
|
|
ovutils::PipeArgs pargL(mdpFlags,
|
|
info,
|
|
zOrder,
|
|
ovutils::ROT_FLAGS_NONE,
|
|
ovutils::DEFAULT_PLANE_ALPHA,
|
|
(ovutils::eBlending)
|
|
getBlending(layer->blending));
|
|
hwc_rect_t cropL = sourceCrop;
|
|
hwc_rect_t dstL = displayFrame;
|
|
hwc_rect_t scissorL = {0, 0, lSplit, hw_h };
|
|
qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0);
|
|
|
|
if (configMdp(ctx->mOverlay, pargL, orient, cropL,
|
|
dstL, NULL, destL)< 0) {
|
|
ALOGE("%s: configMdp fails for left FB", __FUNCTION__);
|
|
ret = false;
|
|
}
|
|
}
|
|
|
|
/* Configure right pipe */
|
|
if(displayFrame.right > lSplit) {
|
|
pipeSpecs.mixer = Overlay::MIXER_RIGHT;
|
|
ovutils::eDest destR = ov.getPipe(pipeSpecs);
|
|
if(destR == ovutils::OV_INVALID) { //None available
|
|
ALOGE("%s: No pipes available to configure fb for dpy %d's"
|
|
" right mixer", __FUNCTION__, mDpy);
|
|
return false;
|
|
}
|
|
|
|
mDestRight = destR;
|
|
ovutils::eMdpFlags mdpFlagsR = mdpFlags;
|
|
ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER);
|
|
|
|
//XXX: FB layer plane alpha is currently sent as zero from
|
|
//surfaceflinger
|
|
ovutils::PipeArgs pargR(mdpFlagsR,
|
|
info,
|
|
zOrder,
|
|
ovutils::ROT_FLAGS_NONE,
|
|
ovutils::DEFAULT_PLANE_ALPHA,
|
|
(ovutils::eBlending)
|
|
getBlending(layer->blending));
|
|
|
|
hwc_rect_t cropR = sourceCrop;
|
|
hwc_rect_t dstR = displayFrame;
|
|
hwc_rect_t scissorR = {lSplit, 0, hw_w, hw_h };
|
|
qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0);
|
|
|
|
dstR.left -= lSplit;
|
|
dstR.right -= lSplit;
|
|
|
|
if (configMdp(ctx->mOverlay, pargR, orient, cropR,
|
|
dstR, NULL, destR) < 0) {
|
|
ALOGE("%s: configMdp fails for right FB", __FUNCTION__);
|
|
ret = false;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool FBUpdateSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
|
|
{
|
|
if(!mModeOn) {
|
|
return true;
|
|
}
|
|
bool ret = true;
|
|
overlay::Overlay& ov = *(ctx->mOverlay);
|
|
if(mDestLeft != ovutils::OV_INVALID) {
|
|
if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestLeft)) {
|
|
ALOGE("%s: queue failed for left of dpy = %d",
|
|
__FUNCTION__, mDpy);
|
|
ret = false;
|
|
}
|
|
}
|
|
if(mDestRight != ovutils::OV_INVALID) {
|
|
if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestRight)) {
|
|
ALOGE("%s: queue failed for right of dpy = %d",
|
|
__FUNCTION__, mDpy);
|
|
ret = false;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//=================FBSrcSplit====================================
|
|
FBSrcSplit::FBSrcSplit(hwc_context_t *ctx, const int& dpy):
|
|
FBUpdateSplit(ctx, dpy) {}
|
|
|
|
bool FBSrcSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
|
|
hwc_rect_t fbUpdatingRect, int fbZorder) {
|
|
hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
|
|
overlay::Overlay& ov = *(ctx->mOverlay);
|
|
|
|
int flags = mTileEnabled ? private_handle_t::PRIV_FLAGS_TILE_RENDERED : 0;
|
|
ovutils::Whf info(mAlignedFBWidth,
|
|
mAlignedFBHeight,
|
|
ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, flags));
|
|
|
|
ovutils::eMdpFlags mdpFlags = OV_MDP_BLEND_FG_PREMULT;
|
|
ovutils::setMdpFlags(mdpFlags,
|
|
ovutils::OV_MDP_SMP_FORCE_ALLOC);
|
|
ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
|
|
|
|
ovutils::PipeArgs parg(mdpFlags,
|
|
info,
|
|
zOrder,
|
|
ovutils::ROT_FLAGS_NONE,
|
|
ovutils::DEFAULT_PLANE_ALPHA,
|
|
(ovutils::eBlending)
|
|
getBlending(layer->blending));
|
|
|
|
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
|
|
hwc_rect_t displayFrame = layer->displayFrame;
|
|
|
|
// No FB update optimization on (1) Custom FB resolution,
|
|
// (2) External Mirror mode, (3) External orientation
|
|
if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
|
|
&& !ctx->mExtOrientation) {
|
|
sourceCrop = fbUpdatingRect;
|
|
displayFrame = fbUpdatingRect;
|
|
}
|
|
int transform = layer->transform;
|
|
ovutils::eTransform orient =
|
|
static_cast<ovutils::eTransform>(transform);
|
|
|
|
// use ext orientation if any
|
|
int extOrient = getExtOrientation(ctx);
|
|
|
|
// Do not use getNonWormholeRegion() function to calculate the
|
|
// sourceCrop during animation on external display and
|
|
// Dont do wormhole calculation when extorientation is set on External
|
|
// Dont do wormhole calculation when scaling mode is set on External
|
|
if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
|
|
sourceCrop = layer->displayFrame;
|
|
} else if((mDpy && !extOrient
|
|
&& !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
|
|
if(!qdutils::MDPVersion::getInstance().is8x26() &&
|
|
!ctx->dpyAttr[mDpy].fbScaling) {
|
|
getNonWormholeRegion(list, sourceCrop);
|
|
displayFrame = sourceCrop;
|
|
}
|
|
}
|
|
|
|
calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
|
|
transform, orient);
|
|
hwc_rect_t cropL = sourceCrop;
|
|
hwc_rect_t cropR = sourceCrop;
|
|
hwc_rect_t dstL = displayFrame;
|
|
hwc_rect_t dstR = displayFrame;
|
|
|
|
if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_SIDE_BY_SIDE) {
|
|
dstL.left = displayFrame.left/2;
|
|
dstL.right = displayFrame.right/2;
|
|
|
|
dstR.left = mAlignedFBWidth/2 + displayFrame.left/2;
|
|
dstR.right = mAlignedFBWidth/2 + displayFrame.right/2;
|
|
} else if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_TOP_AND_BOTTOM) {
|
|
dstL.top = displayFrame.top/2;
|
|
dstL.bottom = displayFrame.bottom/2;
|
|
|
|
dstR.top = mAlignedFBHeight/2 + displayFrame.top/2;
|
|
dstR.bottom = mAlignedFBHeight/2 + displayFrame.bottom/2;
|
|
}
|
|
|
|
//Request left pipe (or 1 by default)
|
|
Overlay::PipeSpecs pipeSpecs;
|
|
pipeSpecs.formatClass = Overlay::FORMAT_RGB;
|
|
pipeSpecs.needsScaling = (qhwc::needsScaling(layer) ||
|
|
needs3DComposition(ctx,mDpy));
|
|
pipeSpecs.dpy = mDpy;
|
|
pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
|
|
pipeSpecs.fb = true;
|
|
ovutils::eDest destL = ov.getPipe(pipeSpecs);
|
|
if(destL == ovutils::OV_INVALID) {
|
|
ALOGE("%s: No pipes available to configure fb for dpy %d's left"
|
|
" mixer", __FUNCTION__, mDpy);
|
|
return false;
|
|
}
|
|
|
|
ovutils::eDest destR = ovutils::OV_INVALID;
|
|
|
|
/* Use 2 pipes IF
|
|
a) FB's width is > Mixer width or
|
|
b) On primary, driver has indicated with caps to split always. This is
|
|
based on an empirically derived value of panel height.
|
|
c) The composition is 3D
|
|
*/
|
|
|
|
const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
|
|
qdutils::MDPVersion::getInstance().isSrcSplitAlways();
|
|
const uint32_t lSplit = getLeftSplit(ctx, mDpy);
|
|
const uint32_t cropWidth = sourceCrop.right - sourceCrop.left;
|
|
const uint32_t cropHeight = sourceCrop.bottom - sourceCrop.top;
|
|
const uint32_t dstWidth = displayFrame.right - displayFrame.left;
|
|
const uint32_t dstHeight = displayFrame.bottom - displayFrame.top;
|
|
const uint32_t layerClock = getLayerClock(dstWidth, dstHeight, cropHeight);
|
|
const uint32_t mixerClock = lSplit;
|
|
|
|
if((cropWidth > qdutils::MDPVersion::getInstance().getMaxPipeWidth()) or
|
|
(primarySplitAlways and
|
|
(cropWidth > lSplit or layerClock > mixerClock)) or
|
|
needs3DComposition(ctx, mDpy)) {
|
|
destR = ov.getPipe(pipeSpecs);
|
|
if(destR == ovutils::OV_INVALID) {
|
|
ALOGE("%s: No pipes available to configure fb for dpy %d's right"
|
|
" mixer", __FUNCTION__, mDpy);
|
|
return false;
|
|
}
|
|
|
|
if(ctx->mOverlay->needsPrioritySwap(destL, destR)) {
|
|
qhwc::swap(destL, destR);
|
|
}
|
|
|
|
//Split crop equally when using 2 pipes
|
|
if(!needs3DComposition(ctx, mDpy)) {
|
|
cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
|
|
cropR.left = cropL.right;
|
|
dstL.right = (displayFrame.right + displayFrame.left) / 2;
|
|
dstR.left = dstL.right;
|
|
}
|
|
}
|
|
|
|
mDestLeft = destL;
|
|
mDestRight = destR;
|
|
|
|
if(destL != OV_INVALID) {
|
|
if(configMdp(ctx->mOverlay, parg, orient,
|
|
cropL, dstL, NULL /*metadata*/, destL) < 0) {
|
|
ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// XXX: Figure out why we need this with source split
|
|
// Currently, the driver silently fails to configure the right pipe
|
|
// if we don't increment the zorder
|
|
if (needs3DComposition(ctx, mDpy))
|
|
parg.zorder = eZorder(parg.zorder + 1);
|
|
|
|
//configure right pipe
|
|
if(destR != OV_INVALID) {
|
|
if(configMdp(ctx->mOverlay, parg, orient,
|
|
cropR, dstR, NULL /*metadata*/, destR) < 0) {
|
|
ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
}; //namespace qhwc
|