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             ctx->dpyAttr[mDpy].fbformat,
     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         ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
    136                 ovutils::getMdpFormat(ctx->dpyAttr[mDpy].fbformat,
    137                     mTileEnabled));
    138 
    139         Overlay::PipeSpecs pipeSpecs;
    140         pipeSpecs.formatClass = Overlay::FORMAT_RGB;
    141         pipeSpecs.needsScaling = qhwc::needsScaling(layer);
    142         pipeSpecs.dpy = mDpy;
    143         pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
    144         pipeSpecs.fb = true;
    145 
    146         ovutils::eDest dest = ov.getPipe(pipeSpecs);
    147         if(dest == ovutils::OV_INVALID) { //None available
    148             ALOGE("%s: No pipes available to configure fb for dpy %d",
    149                 __FUNCTION__, mDpy);
    150             return false;
    151         }
    152         mDest = dest;
    153 
    154         if((mDpy && ctx->deviceOrientation) &&
    155             ctx->listStats[mDpy].isDisplayAnimating) {
    156             fbZorder = 0;
    157         }
    158 
    159         ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
    160         ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
    161 
    162         hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
    163         hwc_rect_t displayFrame = layer->displayFrame;
    164 
    165         // No FB update optimization on (1) Custom FB resolution,
    166         // (2) External Mirror mode, (3) External orientation
    167         if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
    168            && !ctx->mExtOrientation) {
    169             sourceCrop = fbUpdatingRect;
    170             displayFrame = fbUpdatingRect;
    171         }
    172 
    173         int transform = layer->transform;
    174         int rotFlags = ovutils::ROT_FLAGS_NONE;
    175 
    176         ovutils::eTransform orient =
    177                     static_cast<ovutils::eTransform>(transform);
    178         // use ext orientation if any
    179         int extOrient = getExtOrientation(ctx);
    180 
    181         // Do not use getNonWormholeRegion() function to calculate the
    182         // sourceCrop during animation on external display and
    183         // Dont do wormhole calculation when extorientation is set on External
    184         // Dont do wormhole calculation when scaling mode is set on External
    185         if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
    186             sourceCrop = layer->displayFrame;
    187         } else if((mDpy && !extOrient
    188                   && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
    189             if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
    190                 !ctx->dpyAttr[mDpy].customFBSize) {
    191                 getNonWormholeRegion(list, sourceCrop);
    192                 displayFrame = sourceCrop;
    193             }
    194         }
    195         calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
    196                                    transform, orient);
    197         //Store the displayFrame, will be used in getDisplayViewFrame
    198         ctx->dpyAttr[mDpy].mDstRect = displayFrame;
    199         setMdpFlags(ctx, layer, mdpFlags, 0, transform);
    200         // For External use rotator if there is a rotation value set
    201         ret = preRotateExtDisplay(ctx, layer, info,
    202                 sourceCrop, mdpFlags, rotFlags);
    203         if(!ret) {
    204             ALOGE("%s: preRotate for external Failed!", __FUNCTION__);
    205             return false;
    206         }
    207         //For the mdp, since either we are pre-rotating or MDP does flips
    208         orient = ovutils::OVERLAY_TRANSFORM_0;
    209         transform = 0;
    210         ovutils::PipeArgs parg(mdpFlags, info, zOrder,
    211                                static_cast<ovutils::eRotFlags>(rotFlags),
    212                                ovutils::DEFAULT_PLANE_ALPHA,
    213                                (ovutils::eBlending)
    214                                getBlending(layer->blending));
    215         ret = true;
    216         if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
    217                     NULL, mDest) < 0) {
    218             ALOGE("%s: configMdp failed for dpy %d", __FUNCTION__, mDpy);
    219             ret = false;
    220         }
    221     }
    222     return ret;
    223 }
    224 
    225 bool FBUpdateNonSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
    226 {
    227     if(!mModeOn) {
    228         return true;
    229     }
    230     bool ret = true;
    231     overlay::Overlay& ov = *(ctx->mOverlay);
    232     ovutils::eDest dest = mDest;
    233     int fd = hnd->fd;
    234     uint32_t offset = (uint32_t)hnd->offset;
    235     if(mRot) {
    236         if(!mRot->queueBuffer(fd, offset))
    237             return false;
    238         fd = mRot->getDstMemId();
    239         offset = mRot->getDstOffset();
    240     }
    241     if (!ov.queueBuffer(fd, offset, dest)) {
    242         ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
    243         ret = false;
    244     }
    245     return ret;
    246 }
    247 
    248 //================= High res====================================
    249 FBUpdateSplit::FBUpdateSplit(hwc_context_t *ctx, const int& dpy):
    250         IFBUpdate(ctx, dpy) {}
    251 
    252 void FBUpdateSplit::reset() {
    253     IFBUpdate::reset();
    254     mDestLeft = ovutils::OV_INVALID;
    255     mDestRight = ovutils::OV_INVALID;
    256     mRot = NULL;
    257 }
    258 
    259 bool FBUpdateSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
    260                               hwc_rect_t fbUpdatingRect, int fbZorder) {
    261     if(!ctx->mMDP.hasOverlay) {
    262         ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
    263                  __FUNCTION__);
    264         return false;
    265     }
    266     mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
    267     ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
    268     return mModeOn;
    269 }
    270 
    271 // Configure
    272 bool FBUpdateSplit::configure(hwc_context_t *ctx,
    273         hwc_display_contents_1 *list, hwc_rect_t fbUpdatingRect, int fbZorder) {
    274     bool ret = false;
    275     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
    276     if (LIKELY(ctx->mOverlay)) {
    277         ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
    278                           ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888,
    279                                                 mTileEnabled));
    280 
    281         overlay::Overlay& ov = *(ctx->mOverlay);
    282         ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
    283         ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
    284         ovutils::eTransform orient =
    285             static_cast<ovutils::eTransform>(layer->transform);
    286         const int hw_w = ctx->dpyAttr[mDpy].xres;
    287         const int hw_h = ctx->dpyAttr[mDpy].yres;
    288         const int lSplit = getLeftSplit(ctx, mDpy);
    289         mDestLeft = ovutils::OV_INVALID;
    290         mDestRight = ovutils::OV_INVALID;
    291         hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
    292         hwc_rect_t displayFrame = layer->displayFrame;
    293 
    294         // No FB update optimization on (1) Custom FB resolution,
    295         // (2) External Mirror mode, (3) External orientation
    296         if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
    297            && !ctx->mExtOrientation) {
    298             sourceCrop = fbUpdatingRect;
    299             displayFrame = fbUpdatingRect;
    300         }
    301 
    302         int transform = layer->transform;
    303         // use ext orientation if any
    304         int extOrient = getExtOrientation(ctx);
    305 
    306         // Do not use getNonWormholeRegion() function to calculate the
    307         // sourceCrop during animation on external display and
    308         // Dont do wormhole calculation when extorientation is set on External
    309         // Dont do wormhole calculation when scaling mode is set on External
    310         if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
    311             sourceCrop = layer->displayFrame;
    312         } else if((mDpy && !extOrient
    313                   && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
    314             if(!qdutils::MDPVersion::getInstance().is8x26() &&
    315                 !ctx->dpyAttr[mDpy].customFBSize) {
    316                 getNonWormholeRegion(list, sourceCrop);
    317                 displayFrame = sourceCrop;
    318             }
    319         }
    320 
    321         calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
    322                                    transform, orient);
    323 
    324         ret = true;
    325         Overlay::PipeSpecs pipeSpecs;
    326         pipeSpecs.formatClass = Overlay::FORMAT_RGB;
    327         pipeSpecs.needsScaling = qhwc::needsScaling(layer);
    328         pipeSpecs.dpy = mDpy;
    329         pipeSpecs.fb = true;
    330 
    331         /* Configure left pipe */
    332         if(displayFrame.left < lSplit) {
    333             pipeSpecs.mixer = Overlay::MIXER_LEFT;
    334             ovutils::eDest destL = ov.getPipe(pipeSpecs);
    335             if(destL == ovutils::OV_INVALID) { //None available
    336                 ALOGE("%s: No pipes available to configure fb for dpy %d's left"
    337                       " mixer", __FUNCTION__, mDpy);
    338                 return false;
    339             }
    340 
    341             mDestLeft = destL;
    342 
    343             //XXX: FB layer plane alpha is currently sent as zero from
    344             //surfaceflinger
    345             ovutils::PipeArgs pargL(mdpFlags,
    346                                     info,
    347                                     zOrder,
    348                                     ovutils::ROT_FLAGS_NONE,
    349                                     ovutils::DEFAULT_PLANE_ALPHA,
    350                                     (ovutils::eBlending)
    351                                     getBlending(layer->blending));
    352             hwc_rect_t cropL = sourceCrop;
    353             hwc_rect_t dstL = displayFrame;
    354             hwc_rect_t scissorL = {0, 0, lSplit, hw_h };
    355             qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0);
    356 
    357             if (configMdp(ctx->mOverlay, pargL, orient, cropL,
    358                            dstL, NULL, destL)< 0) {
    359                 ALOGE("%s: configMdp fails for left FB", __FUNCTION__);
    360                 ret = false;
    361             }
    362         }
    363 
    364         /* Configure right pipe */
    365         if(displayFrame.right > lSplit) {
    366             pipeSpecs.mixer = Overlay::MIXER_RIGHT;
    367             ovutils::eDest destR = ov.getPipe(pipeSpecs);
    368             if(destR == ovutils::OV_INVALID) { //None available
    369                 ALOGE("%s: No pipes available to configure fb for dpy %d's"
    370                       " right mixer", __FUNCTION__, mDpy);
    371                 return false;
    372             }
    373 
    374             mDestRight = destR;
    375             ovutils::eMdpFlags mdpFlagsR = mdpFlags;
    376             ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER);
    377 
    378             //XXX: FB layer plane alpha is currently sent as zero from
    379             //surfaceflinger
    380             ovutils::PipeArgs pargR(mdpFlagsR,
    381                                     info,
    382                                     zOrder,
    383                                     ovutils::ROT_FLAGS_NONE,
    384                                     ovutils::DEFAULT_PLANE_ALPHA,
    385                                     (ovutils::eBlending)
    386                                     getBlending(layer->blending));
    387 
    388             hwc_rect_t cropR = sourceCrop;
    389             hwc_rect_t dstR = displayFrame;
    390             hwc_rect_t scissorR = {lSplit, 0, hw_w, hw_h };
    391             qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0);
    392 
    393             dstR.left -= lSplit;
    394             dstR.right -= lSplit;
    395 
    396             if (configMdp(ctx->mOverlay, pargR, orient, cropR,
    397                            dstR, NULL, destR) < 0) {
    398                 ALOGE("%s: configMdp fails for right FB", __FUNCTION__);
    399                 ret = false;
    400             }
    401         }
    402     }
    403     return ret;
    404 }
    405 
    406 bool FBUpdateSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
    407 {
    408     if(!mModeOn) {
    409         return true;
    410     }
    411     bool ret = true;
    412     overlay::Overlay& ov = *(ctx->mOverlay);
    413     if(mDestLeft != ovutils::OV_INVALID) {
    414         if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestLeft)) {
    415             ALOGE("%s: queue failed for left of dpy = %d",
    416                   __FUNCTION__, mDpy);
    417             ret = false;
    418         }
    419     }
    420     if(mDestRight != ovutils::OV_INVALID) {
    421         if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestRight)) {
    422             ALOGE("%s: queue failed for right of dpy = %d",
    423                   __FUNCTION__, mDpy);
    424             ret = false;
    425         }
    426     }
    427     return ret;
    428 }
    429 
    430 //=================FBSrcSplit====================================
    431 FBSrcSplit::FBSrcSplit(hwc_context_t *ctx, const int& dpy):
    432         FBUpdateSplit(ctx, dpy) {}
    433 
    434 bool FBSrcSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
    435         hwc_rect_t fbUpdatingRect, int fbZorder) {
    436     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
    437     overlay::Overlay& ov = *(ctx->mOverlay);
    438 
    439     ovutils::Whf info(mAlignedFBWidth,
    440             mAlignedFBHeight,
    441             ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888,
    442                 mTileEnabled));
    443 
    444     ovutils::eMdpFlags mdpFlags = OV_MDP_BLEND_FG_PREMULT;
    445     ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
    446 
    447     ovutils::PipeArgs parg(mdpFlags,
    448             info,
    449             zOrder,
    450             ovutils::ROT_FLAGS_NONE,
    451             ovutils::DEFAULT_PLANE_ALPHA,
    452             (ovutils::eBlending)
    453             getBlending(layer->blending));
    454 
    455     hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
    456     hwc_rect_t displayFrame = layer->displayFrame;
    457 
    458     // No FB update optimization on (1) Custom FB resolution,
    459     // (2) External Mirror mode, (3) External orientation
    460     if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
    461        && !ctx->mExtOrientation) {
    462         sourceCrop = fbUpdatingRect;
    463         displayFrame = fbUpdatingRect;
    464     }
    465     int transform = layer->transform;
    466     ovutils::eTransform orient =
    467             static_cast<ovutils::eTransform>(transform);
    468 
    469     // use ext orientation if any
    470     int extOrient = getExtOrientation(ctx);
    471 
    472     // Do not use getNonWormholeRegion() function to calculate the
    473     // sourceCrop during animation on external display and
    474     // Dont do wormhole calculation when extorientation is set on External
    475     // Dont do wormhole calculation when scaling mode is set on External
    476     if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
    477         sourceCrop = layer->displayFrame;
    478     } else if((mDpy && !extOrient
    479               && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
    480         if(!qdutils::MDPVersion::getInstance().is8x26() &&
    481             !ctx->dpyAttr[mDpy].customFBSize) {
    482             getNonWormholeRegion(list, sourceCrop);
    483             displayFrame = sourceCrop;
    484         }
    485     }
    486 
    487     calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
    488                                transform, orient);
    489     hwc_rect_t cropL = sourceCrop;
    490     hwc_rect_t cropR = sourceCrop;
    491     hwc_rect_t dstL = displayFrame;
    492     hwc_rect_t dstR = displayFrame;
    493 
    494     //Request left pipe (or 1 by default)
    495     Overlay::PipeSpecs pipeSpecs;
    496     pipeSpecs.formatClass = Overlay::FORMAT_RGB;
    497     pipeSpecs.needsScaling = qhwc::needsScaling(layer);
    498     pipeSpecs.dpy = mDpy;
    499     pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
    500     pipeSpecs.fb = true;
    501     ovutils::eDest destL = ov.getPipe(pipeSpecs);
    502     if(destL == ovutils::OV_INVALID) {
    503         ALOGE("%s: No pipes available to configure fb for dpy %d's left"
    504                 " mixer", __FUNCTION__, mDpy);
    505         return false;
    506     }
    507 
    508     ovutils::eDest destR = ovutils::OV_INVALID;
    509 
    510     /*  Use 2 pipes IF
    511         a) FB's width is > Mixer width or
    512         b) On primary, driver has indicated with caps to split always. This is
    513            based on an empirically derived value of panel height.
    514     */
    515 
    516     const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
    517             qdutils::MDPVersion::getInstance().isSrcSplitAlways();
    518     const uint32_t lSplit = getLeftSplit(ctx, mDpy);
    519     const uint32_t cropWidth = sourceCrop.right - sourceCrop.left;
    520 
    521     if((cropWidth > qdutils::MDPVersion::getInstance().getMaxMixerWidth()) or
    522             (primarySplitAlways and cropWidth > lSplit)) {
    523         destR = ov.getPipe(pipeSpecs);
    524         if(destR == ovutils::OV_INVALID) {
    525             ALOGE("%s: No pipes available to configure fb for dpy %d's right"
    526                     " mixer", __FUNCTION__, mDpy);
    527             return false;
    528         }
    529 
    530         if(ctx->mOverlay->comparePipePriority(destL, destR) == -1) {
    531             qhwc::swap(destL, destR);
    532         }
    533 
    534         //Split crop equally when using 2 pipes
    535         cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
    536         cropR.left = cropL.right;
    537         dstL.right = (displayFrame.right + displayFrame.left) / 2;
    538         dstR.left = dstL.right;
    539     }
    540 
    541     mDestLeft = destL;
    542     mDestRight = destR;
    543 
    544     if(destL != OV_INVALID) {
    545         if(configMdp(ctx->mOverlay, parg, orient,
    546                     cropL, dstL, NULL /*metadata*/, destL) < 0) {
    547             ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
    548             return false;
    549         }
    550     }
    551 
    552     //configure right pipe
    553     if(destR != OV_INVALID) {
    554         if(configMdp(ctx->mOverlay, parg, orient,
    555                     cropR, dstR, NULL /*metadata*/, destR) < 0) {
    556             ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
    557             return false;
    558         }
    559     }
    560 
    561     return true;
    562 }
    563 
    564 //---------------------------------------------------------------------
    565 }; //namespace qhwc
    566