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