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 
getObject(hwc_context_t * ctx,const int & dpy)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 
IFBUpdate(hwc_context_t * ctx,const int & dpy)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 
reset()65 void IFBUpdate::reset() {
66     mModeOn = false;
67     mRot = NULL;
68 }
69 
prepareAndValidate(hwc_context_t * ctx,hwc_display_contents_1 * list,int fbZorder)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====================================
FBUpdateNonSplit(hwc_context_t * ctx,const int & dpy)79 FBUpdateNonSplit::FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy):
80         IFBUpdate(ctx, dpy) {}
81 
reset()82 void FBUpdateNonSplit::reset() {
83     IFBUpdate::reset();
84     mDest = ovutils::OV_INVALID;
85 }
86 
preRotateExtDisplay(hwc_context_t * ctx,hwc_layer_1_t * layer,ovutils::Whf & info,hwc_rect_t & sourceCrop,ovutils::eMdpFlags & mdpFlags,int & rotFlags)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 
prepare(hwc_context_t * ctx,hwc_display_contents_1 * list,hwc_rect_t fbUpdatingRect,int fbZorder)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
configure(hwc_context_t * ctx,hwc_display_contents_1 * list,hwc_rect_t fbUpdatingRect,int fbZorder)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 
draw(hwc_context_t * ctx,private_handle_t * hnd)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====================================
FBUpdateSplit(hwc_context_t * ctx,const int & dpy)249 FBUpdateSplit::FBUpdateSplit(hwc_context_t *ctx, const int& dpy):
250         IFBUpdate(ctx, dpy) {}
251 
reset()252 void FBUpdateSplit::reset() {
253     IFBUpdate::reset();
254     mDestLeft = ovutils::OV_INVALID;
255     mDestRight = ovutils::OV_INVALID;
256     mRot = NULL;
257 }
258 
prepare(hwc_context_t * ctx,hwc_display_contents_1 * list,hwc_rect_t fbUpdatingRect,int fbZorder)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
configure(hwc_context_t * ctx,hwc_display_contents_1 * list,hwc_rect_t fbUpdatingRect,int fbZorder)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 
draw(hwc_context_t * ctx,private_handle_t * hnd)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====================================
FBSrcSplit(hwc_context_t * ctx,const int & dpy)431 FBSrcSplit::FBSrcSplit(hwc_context_t *ctx, const int& dpy):
432         FBUpdateSplit(ctx, dpy) {}
433 
configure(hwc_context_t * ctx,hwc_display_contents_1 * list,hwc_rect_t fbUpdatingRect,int fbZorder)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