Home | History | Annotate | Download | only in libhwcomposer
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
      4  *
      5  * Not a Contribution, Apache license notifications and license are
      6  * retained for attribution purposes only.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  */
     20 
     21 #define DEBUG_FBUPDATE 0
     22 #include <cutils/properties.h>
     23 #include <gralloc_priv.h>
     24 #include <overlay.h>
     25 #include <overlayRotator.h>
     26 #include "hwc_fbupdate.h"
     27 #include "mdp_version.h"
     28 
     29 using namespace qdutils;
     30 using namespace overlay;
     31 using overlay::Rotator;
     32 using namespace overlay::utils;
     33 
     34 namespace qhwc {
     35 
     36 namespace ovutils = overlay::utils;
     37 
     38 IFBUpdate* IFBUpdate::getObject(hwc_context_t *ctx, const int& dpy) {
     39     if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
     40         return new FBSrcSplit(ctx, dpy);
     41     } else if(isDisplaySplit(ctx, dpy)) {
     42         return new FBUpdateSplit(ctx, dpy);
     43     }
     44     return new FBUpdateNonSplit(ctx, dpy);
     45 }
     46 
     47 IFBUpdate::IFBUpdate(hwc_context_t *ctx, const int& dpy) : mDpy(dpy) {
     48     unsigned int size = 0;
     49     uint32_t xres = ctx->dpyAttr[mDpy].xres;
     50     uint32_t yres = ctx->dpyAttr[mDpy].yres;
     51     if (ctx->dpyAttr[dpy].customFBSize) {
     52         //GPU will render and compose at new resolution
     53         //So need to have FB at new resolution
     54         xres = ctx->dpyAttr[mDpy].xres_new;
     55         yres = ctx->dpyAttr[mDpy].yres_new;
     56     }
     57     getBufferAttributes((int)xres, (int)yres,
     58             HAL_PIXEL_FORMAT_RGBA_8888,
     59             0,
     60             mAlignedFBWidth,
     61             mAlignedFBHeight,
     62             mTileEnabled, size);
     63 }
     64 
     65 void IFBUpdate::reset() {
     66     mModeOn = false;
     67     mRot = NULL;
     68 }
     69 
     70 bool IFBUpdate::prepareAndValidate(hwc_context_t *ctx,
     71             hwc_display_contents_1 *list, int fbZorder) {
     72     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     73     mModeOn = prepare(ctx, list, layer->displayFrame, fbZorder) &&
     74             ctx->mOverlay->validateAndSet(mDpy, ctx->dpyAttr[mDpy].fd);
     75     return mModeOn;
     76 }
     77 
     78 //================= Low res====================================
     79 FBUpdateNonSplit::FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy):
     80         IFBUpdate(ctx, dpy) {}
     81 
     82 void FBUpdateNonSplit::reset() {
     83     IFBUpdate::reset();
     84     mDest = ovutils::OV_INVALID;
     85 }
     86 
     87 bool FBUpdateNonSplit::preRotateExtDisplay(hwc_context_t *ctx,
     88                                             hwc_layer_1_t *layer,
     89                                             ovutils::Whf &info,
     90                                             hwc_rect_t& sourceCrop,
     91                                             ovutils::eMdpFlags& mdpFlags,
     92                                             int& rotFlags)
     93 {
     94     int extOrient = getExtOrientation(ctx);
     95     ovutils::eTransform orient = static_cast<ovutils::eTransform >(extOrient);
     96     if(mDpy && (extOrient & HWC_TRANSFORM_ROT_90)) {
     97         mRot = ctx->mRotMgr->getNext();
     98         if(mRot == NULL) return false;
     99         ctx->mLayerRotMap[mDpy]->add(layer, mRot);
    100         // Composed FB content will have black bars, if the viewFrame of the
    101         // external is different from {0, 0, fbWidth, fbHeight}, so intersect
    102         // viewFrame with sourceCrop to avoid those black bars
    103         sourceCrop = getIntersection(sourceCrop, ctx->mViewFrame[mDpy]);
    104         //Configure rotator for pre-rotation
    105         if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) {
    106             ALOGE("%s: configRotator Failed!", __FUNCTION__);
    107             mRot = NULL;
    108             return false;
    109         }
    110         updateSource(orient, info, sourceCrop, mRot);
    111         rotFlags |= ovutils::ROT_PREROTATED;
    112     }
    113     return true;
    114 }
    115 
    116 bool FBUpdateNonSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
    117                              hwc_rect_t fbUpdatingRect, int fbZorder) {
    118     if(!ctx->mMDP.hasOverlay) {
    119         ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
    120                  __FUNCTION__);
    121         return false;
    122     }
    123     mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
    124     return mModeOn;
    125 }
    126 
    127 // Configure
    128 bool FBUpdateNonSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
    129                                hwc_rect_t fbUpdatingRect, int fbZorder) {
    130     bool ret = false;
    131     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
    132     if (LIKELY(ctx->mOverlay)) {
    133         overlay::Overlay& ov = *(ctx->mOverlay);
    134 
    135         int flags = mTileEnabled ?
    136             private_handle_t::PRIV_FLAGS_TILE_RENDERED : 0;
    137         ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
    138                 ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, flags));
    139 
    140         Overlay::PipeSpecs pipeSpecs;
    141         pipeSpecs.formatClass = Overlay::FORMAT_RGB;
    142         pipeSpecs.needsScaling = qhwc::needsScaling(layer);
    143         pipeSpecs.dpy = mDpy;
    144         pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
    145         pipeSpecs.fb = true;
    146 
    147         ovutils::eDest dest = ov.getPipe(pipeSpecs);
    148         if(dest == ovutils::OV_INVALID) { //None available
    149             ALOGE("%s: No pipes available to configure fb for dpy %d",
    150                 __FUNCTION__, mDpy);
    151             return false;
    152         }
    153         mDest = dest;
    154 
    155         if((mDpy && ctx->deviceOrientation) &&
    156             ctx->listStats[mDpy].isDisplayAnimating) {
    157             fbZorder = 0;
    158         }
    159 
    160         ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
    161         ovutils::setMdpFlags(mdpFlags,
    162                 ovutils::OV_MDP_SMP_FORCE_ALLOC);
    163         ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
    164 
    165         hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
    166         hwc_rect_t displayFrame = layer->displayFrame;
    167 
    168         // No FB update optimization on (1) Custom FB resolution,
    169         // (2) External Mirror mode, (3) External orientation
    170         if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
    171            && !ctx->mExtOrientation) {
    172             sourceCrop = fbUpdatingRect;
    173             displayFrame = fbUpdatingRect;
    174         }
    175 
    176         int transform = layer->transform;
    177         int rotFlags = ovutils::ROT_FLAGS_NONE;
    178 
    179         ovutils::eTransform orient =
    180                     static_cast<ovutils::eTransform>(transform);
    181         // use ext orientation if any
    182         int extOrient = getExtOrientation(ctx);
    183 
    184         // Do not use getNonWormholeRegion() function to calculate the
    185         // sourceCrop during animation on external display and
    186         // Dont do wormhole calculation when extorientation is set on External
    187         // Dont do wormhole calculation when scaling mode is set on External
    188         if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
    189             sourceCrop = layer->displayFrame;
    190         } else if((mDpy && !extOrient
    191                   && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
    192             if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
    193                 !ctx->dpyAttr[mDpy].customFBSize) {
    194                 getNonWormholeRegion(list, sourceCrop);
    195                 displayFrame = sourceCrop;
    196             }
    197         }
    198         calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
    199                                    transform, orient);
    200         //Store the displayFrame, will be used in getDisplayViewFrame
    201         ctx->dpyAttr[mDpy].mDstRect = displayFrame;
    202         setMdpFlags(ctx, layer, mdpFlags, 0, transform);
    203         // For External use rotator if there is a rotation value set
    204         ret = preRotateExtDisplay(ctx, layer, info,
    205                 sourceCrop, mdpFlags, rotFlags);
    206         if(!ret) {
    207             ALOGE("%s: preRotate for external Failed!", __FUNCTION__);
    208             return false;
    209         }
    210         //For the mdp, since either we are pre-rotating or MDP does flips
    211         orient = ovutils::OVERLAY_TRANSFORM_0;
    212         transform = 0;
    213         ovutils::PipeArgs parg(mdpFlags, info, zOrder,
    214                                static_cast<ovutils::eRotFlags>(rotFlags),
    215                                ovutils::DEFAULT_PLANE_ALPHA,
    216                                (ovutils::eBlending)
    217                                getBlending(layer->blending));
    218         ret = true;
    219         if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
    220                     NULL, mDest) < 0) {
    221             ALOGE("%s: configMdp failed for dpy %d", __FUNCTION__, mDpy);
    222             ret = false;
    223         }
    224     }
    225     return ret;
    226 }
    227 
    228 bool FBUpdateNonSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
    229 {
    230     if(!mModeOn) {
    231         return true;
    232     }
    233     bool ret = true;
    234     overlay::Overlay& ov = *(ctx->mOverlay);
    235     ovutils::eDest dest = mDest;
    236     int fd = hnd->fd;
    237     uint32_t offset = (uint32_t)hnd->offset;
    238     if(mRot) {
    239         if(!mRot->queueBuffer(fd, offset))
    240             return false;
    241         fd = mRot->getDstMemId();
    242         offset = mRot->getDstOffset();
    243     }
    244     if (!ov.queueBuffer(fd, offset, dest)) {
    245         ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
    246         ret = false;
    247     }
    248     return ret;
    249 }
    250 
    251 //================= High res====================================
    252 FBUpdateSplit::FBUpdateSplit(hwc_context_t *ctx, const int& dpy):
    253         IFBUpdate(ctx, dpy) {}
    254 
    255 void FBUpdateSplit::reset() {
    256     IFBUpdate::reset();
    257     mDestLeft = ovutils::OV_INVALID;
    258     mDestRight = ovutils::OV_INVALID;
    259     mRot = NULL;
    260 }
    261 
    262 bool FBUpdateSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
    263                               hwc_rect_t fbUpdatingRect, int fbZorder) {
    264     if(!ctx->mMDP.hasOverlay) {
    265         ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
    266                  __FUNCTION__);
    267         return false;
    268     }
    269     mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
    270     ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
    271     return mModeOn;
    272 }
    273 
    274 // Configure
    275 bool FBUpdateSplit::configure(hwc_context_t *ctx,
    276         hwc_display_contents_1 *list, hwc_rect_t fbUpdatingRect, int fbZorder) {
    277     bool ret = false;
    278     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
    279     if (LIKELY(ctx->mOverlay)) {
    280         int flags = mTileEnabled ?
    281             private_handle_t::PRIV_FLAGS_TILE_RENDERED : 0;
    282         ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
    283                 ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, flags));
    284 
    285         overlay::Overlay& ov = *(ctx->mOverlay);
    286         ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
    287         ovutils::setMdpFlags(mdpFlags,
    288                 ovutils::OV_MDP_SMP_FORCE_ALLOC);
    289         ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
    290         ovutils::eTransform orient =
    291             static_cast<ovutils::eTransform>(layer->transform);
    292         const int hw_w = ctx->dpyAttr[mDpy].xres;
    293         const int hw_h = ctx->dpyAttr[mDpy].yres;
    294         const int lSplit = getLeftSplit(ctx, mDpy);
    295         mDestLeft = ovutils::OV_INVALID;
    296         mDestRight = ovutils::OV_INVALID;
    297         hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
    298         hwc_rect_t displayFrame = layer->displayFrame;
    299 
    300         // No FB update optimization on (1) Custom FB resolution,
    301         // (2) External Mirror mode, (3) External orientation
    302         if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
    303            && !ctx->mExtOrientation) {
    304             sourceCrop = fbUpdatingRect;
    305             displayFrame = fbUpdatingRect;
    306         }
    307 
    308         int transform = layer->transform;
    309         // use ext orientation if any
    310         int extOrient = getExtOrientation(ctx);
    311 
    312         // Do not use getNonWormholeRegion() function to calculate the
    313         // sourceCrop during animation on external display and
    314         // Dont do wormhole calculation when extorientation is set on External
    315         // Dont do wormhole calculation when scaling mode is set on External
    316         if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
    317             sourceCrop = layer->displayFrame;
    318         } else if((mDpy && !extOrient
    319                   && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
    320             if(!qdutils::MDPVersion::getInstance().is8x26() &&
    321                 !ctx->dpyAttr[mDpy].customFBSize) {
    322                 getNonWormholeRegion(list, sourceCrop);
    323                 displayFrame = sourceCrop;
    324             }
    325         }
    326 
    327         calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
    328                                    transform, orient);
    329 
    330         ret = true;
    331         Overlay::PipeSpecs pipeSpecs;
    332         pipeSpecs.formatClass = Overlay::FORMAT_RGB;
    333         pipeSpecs.needsScaling = qhwc::needsScaling(layer);
    334         pipeSpecs.dpy = mDpy;
    335         pipeSpecs.fb = true;
    336 
    337         /* Configure left pipe */
    338         if(displayFrame.left < lSplit) {
    339             pipeSpecs.mixer = Overlay::MIXER_LEFT;
    340             ovutils::eDest destL = ov.getPipe(pipeSpecs);
    341             if(destL == ovutils::OV_INVALID) { //None available
    342                 ALOGE("%s: No pipes available to configure fb for dpy %d's left"
    343                       " mixer", __FUNCTION__, mDpy);
    344                 return false;
    345             }
    346 
    347             mDestLeft = destL;
    348 
    349             //XXX: FB layer plane alpha is currently sent as zero from
    350             //surfaceflinger
    351             ovutils::PipeArgs pargL(mdpFlags,
    352                                     info,
    353                                     zOrder,
    354                                     ovutils::ROT_FLAGS_NONE,
    355                                     ovutils::DEFAULT_PLANE_ALPHA,
    356                                     (ovutils::eBlending)
    357                                     getBlending(layer->blending));
    358             hwc_rect_t cropL = sourceCrop;
    359             hwc_rect_t dstL = displayFrame;
    360             hwc_rect_t scissorL = {0, 0, lSplit, hw_h };
    361             qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0);
    362 
    363             if (configMdp(ctx->mOverlay, pargL, orient, cropL,
    364                            dstL, NULL, destL)< 0) {
    365                 ALOGE("%s: configMdp fails for left FB", __FUNCTION__);
    366                 ret = false;
    367             }
    368         }
    369 
    370         /* Configure right pipe */
    371         if(displayFrame.right > lSplit) {
    372             pipeSpecs.mixer = Overlay::MIXER_RIGHT;
    373             ovutils::eDest destR = ov.getPipe(pipeSpecs);
    374             if(destR == ovutils::OV_INVALID) { //None available
    375                 ALOGE("%s: No pipes available to configure fb for dpy %d's"
    376                       " right mixer", __FUNCTION__, mDpy);
    377                 return false;
    378             }
    379 
    380             mDestRight = destR;
    381             ovutils::eMdpFlags mdpFlagsR = mdpFlags;
    382             ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER);
    383 
    384             //XXX: FB layer plane alpha is currently sent as zero from
    385             //surfaceflinger
    386             ovutils::PipeArgs pargR(mdpFlagsR,
    387                                     info,
    388                                     zOrder,
    389                                     ovutils::ROT_FLAGS_NONE,
    390                                     ovutils::DEFAULT_PLANE_ALPHA,
    391                                     (ovutils::eBlending)
    392                                     getBlending(layer->blending));
    393 
    394             hwc_rect_t cropR = sourceCrop;
    395             hwc_rect_t dstR = displayFrame;
    396             hwc_rect_t scissorR = {lSplit, 0, hw_w, hw_h };
    397             qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0);
    398 
    399             dstR.left -= lSplit;
    400             dstR.right -= lSplit;
    401 
    402             if (configMdp(ctx->mOverlay, pargR, orient, cropR,
    403                            dstR, NULL, destR) < 0) {
    404                 ALOGE("%s: configMdp fails for right FB", __FUNCTION__);
    405                 ret = false;
    406             }
    407         }
    408     }
    409     return ret;
    410 }
    411 
    412 bool FBUpdateSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
    413 {
    414     if(!mModeOn) {
    415         return true;
    416     }
    417     bool ret = true;
    418     overlay::Overlay& ov = *(ctx->mOverlay);
    419     if(mDestLeft != ovutils::OV_INVALID) {
    420         if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestLeft)) {
    421             ALOGE("%s: queue failed for left of dpy = %d",
    422                   __FUNCTION__, mDpy);
    423             ret = false;
    424         }
    425     }
    426     if(mDestRight != ovutils::OV_INVALID) {
    427         if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestRight)) {
    428             ALOGE("%s: queue failed for right of dpy = %d",
    429                   __FUNCTION__, mDpy);
    430             ret = false;
    431         }
    432     }
    433     return ret;
    434 }
    435 
    436 //=================FBSrcSplit====================================
    437 FBSrcSplit::FBSrcSplit(hwc_context_t *ctx, const int& dpy):
    438         FBUpdateSplit(ctx, dpy) {}
    439 
    440 bool FBSrcSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
    441         hwc_rect_t fbUpdatingRect, int fbZorder) {
    442     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
    443     overlay::Overlay& ov = *(ctx->mOverlay);
    444 
    445     int flags = mTileEnabled ? private_handle_t::PRIV_FLAGS_TILE_RENDERED : 0;
    446     ovutils::Whf info(mAlignedFBWidth,
    447             mAlignedFBHeight,
    448             ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, flags));
    449 
    450     ovutils::eMdpFlags mdpFlags = OV_MDP_BLEND_FG_PREMULT;
    451     ovutils::setMdpFlags(mdpFlags,
    452                 ovutils::OV_MDP_SMP_FORCE_ALLOC);
    453     ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
    454 
    455     ovutils::PipeArgs parg(mdpFlags,
    456             info,
    457             zOrder,
    458             ovutils::ROT_FLAGS_NONE,
    459             ovutils::DEFAULT_PLANE_ALPHA,
    460             (ovutils::eBlending)
    461             getBlending(layer->blending));
    462 
    463     hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
    464     hwc_rect_t displayFrame = layer->displayFrame;
    465 
    466     // No FB update optimization on (1) Custom FB resolution,
    467     // (2) External Mirror mode, (3) External orientation
    468     if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
    469        && !ctx->mExtOrientation) {
    470         sourceCrop = fbUpdatingRect;
    471         displayFrame = fbUpdatingRect;
    472     }
    473     int transform = layer->transform;
    474     ovutils::eTransform orient =
    475             static_cast<ovutils::eTransform>(transform);
    476 
    477     // use ext orientation if any
    478     int extOrient = getExtOrientation(ctx);
    479 
    480     // Do not use getNonWormholeRegion() function to calculate the
    481     // sourceCrop during animation on external display and
    482     // Dont do wormhole calculation when extorientation is set on External
    483     // Dont do wormhole calculation when scaling mode is set on External
    484     if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
    485         sourceCrop = layer->displayFrame;
    486     } else if((mDpy && !extOrient
    487               && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
    488         if(!qdutils::MDPVersion::getInstance().is8x26() &&
    489             !ctx->dpyAttr[mDpy].customFBSize) {
    490             getNonWormholeRegion(list, sourceCrop);
    491             displayFrame = sourceCrop;
    492         }
    493     }
    494 
    495     calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
    496                                transform, orient);
    497     hwc_rect_t cropL = sourceCrop;
    498     hwc_rect_t cropR = sourceCrop;
    499     hwc_rect_t dstL = displayFrame;
    500     hwc_rect_t dstR = displayFrame;
    501 
    502     //Request left pipe (or 1 by default)
    503     Overlay::PipeSpecs pipeSpecs;
    504     pipeSpecs.formatClass = Overlay::FORMAT_RGB;
    505     pipeSpecs.needsScaling = qhwc::needsScaling(layer);
    506     pipeSpecs.dpy = mDpy;
    507     pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
    508     pipeSpecs.fb = true;
    509     ovutils::eDest destL = ov.getPipe(pipeSpecs);
    510     if(destL == ovutils::OV_INVALID) {
    511         ALOGE("%s: No pipes available to configure fb for dpy %d's left"
    512                 " mixer", __FUNCTION__, mDpy);
    513         return false;
    514     }
    515 
    516     ovutils::eDest destR = ovutils::OV_INVALID;
    517 
    518     /*  Use 2 pipes IF
    519         a) FB's width is > Mixer width or
    520         b) On primary, driver has indicated with caps to split always. This is
    521            based on an empirically derived value of panel height.
    522     */
    523 
    524     const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
    525             qdutils::MDPVersion::getInstance().isSrcSplitAlways();
    526     const uint32_t lSplit = getLeftSplit(ctx, mDpy);
    527     const uint32_t cropWidth = sourceCrop.right - sourceCrop.left;
    528     const uint32_t cropHeight = sourceCrop.bottom - sourceCrop.top;
    529     const uint32_t dstWidth = displayFrame.right - displayFrame.left;
    530     const uint32_t dstHeight = displayFrame.bottom - displayFrame.top;
    531     const uint32_t layerClock = getLayerClock(dstWidth, dstHeight, cropHeight);
    532     const uint32_t mixerClock = lSplit;
    533 
    534     if((cropWidth > qdutils::MDPVersion::getInstance().getMaxPipeWidth()) or
    535             (primarySplitAlways and
    536             (cropWidth > lSplit or layerClock > mixerClock))) {
    537         destR = ov.getPipe(pipeSpecs);
    538         if(destR == ovutils::OV_INVALID) {
    539             ALOGE("%s: No pipes available to configure fb for dpy %d's right"
    540                     " mixer", __FUNCTION__, mDpy);
    541             return false;
    542         }
    543 
    544         if(ctx->mOverlay->needsPrioritySwap(destL, destR)) {
    545             qhwc::swap(destL, destR);
    546         }
    547 
    548         //Split crop equally when using 2 pipes
    549         cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
    550         cropR.left = cropL.right;
    551         dstL.right = (displayFrame.right + displayFrame.left) / 2;
    552         dstR.left = dstL.right;
    553     }
    554 
    555     mDestLeft = destL;
    556     mDestRight = destR;
    557 
    558     if(destL != OV_INVALID) {
    559         if(configMdp(ctx->mOverlay, parg, orient,
    560                     cropL, dstL, NULL /*metadata*/, destL) < 0) {
    561             ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
    562             return false;
    563         }
    564     }
    565 
    566     //configure right pipe
    567     if(destR != OV_INVALID) {
    568         if(configMdp(ctx->mOverlay, parg, orient,
    569                     cropR, dstR, NULL /*metadata*/, destR) < 0) {
    570             ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
    571             return false;
    572         }
    573     }
    574 
    575     return true;
    576 }
    577 
    578 //---------------------------------------------------------------------
    579 }; //namespace qhwc
    580