1/* 2* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. 3* 4* Redistribution and use in source and binary forms, with or without 5* modification, are permitted provided that the following conditions are 6* met: 7* * Redistributions of source code must retain the above copyright 8* notice, this list of conditions and the following disclaimer. 9* * Redistributions in binary form must reproduce the above 10* copyright notice, this list of conditions and the following 11* disclaimer in the documentation and/or other materials provided 12* with the distribution. 13* * Neither the name of The Linux Foundation nor the names of its 14* contributors may be used to endorse or promote products derived 15* from this software without specific prior written permission. 16* 17* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*/ 29 30#include <dlfcn.h> 31#include "overlay.h" 32#include "pipes/overlayGenPipe.h" 33#include "mdp_version.h" 34#include "qdMetaData.h" 35#include "qd_utils.h" 36 37namespace overlay { 38using namespace utils; 39using namespace qdutils; 40 41Overlay::Overlay() { 42 int numPipes = qdutils::MDPVersion::getInstance().getTotalPipes(); 43 PipeBook::NUM_PIPES = (numPipes <= utils::OV_MAX)? numPipes : utils::OV_MAX; 44 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 45 mPipeBook[i].init(); 46 } 47 48 initScalar(); 49 setDMAMultiplexingSupported(); 50} 51 52Overlay::~Overlay() { 53 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 54 mPipeBook[i].destroy(); 55 } 56 destroyScalar(); 57} 58 59void Overlay::configBegin() { 60 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 61 //Mark as available for this round. 62 PipeBook::resetUse(i); 63 PipeBook::resetAllocation(i); 64 } 65} 66 67void Overlay::configDone() { 68 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 69 if((PipeBook::isNotUsed(i) && !sessionInProgress((eDest)i)) || 70 isSessionEnded((eDest)i)) { 71 //Forces UNSET on pipes, flushes rotator memory and session, closes 72 //fds 73 mPipeBook[i].destroy(); 74 } 75 } 76 PipeBook::save(); 77} 78 79int Overlay::getPipeId(utils::eDest dest) { 80 return mPipeBook[(int)dest].mPipe->getPipeId(); 81} 82 83eDest Overlay::getDest(int pipeid) { 84 eDest dest = OV_INVALID; 85 // finding the dest corresponding to the given pipe 86 for(int i=0; i < PipeBook::NUM_PIPES; ++i) { 87 if(mPipeBook[i].valid() && mPipeBook[i].mPipe->getPipeId() == pipeid) { 88 return (eDest)i; 89 } 90 } 91 return dest; 92} 93 94eDest Overlay::reservePipe(int pipeid) { 95 eDest dest = getDest(pipeid); 96 PipeBook::setAllocation((int)dest); 97 return dest; 98} 99 100eDest Overlay::nextPipe(eMdpPipeType type, const PipeSpecs& pipeSpecs) { 101 eDest dest = OV_INVALID; 102 int dpy = pipeSpecs.dpy; 103 int mixer = pipeSpecs.mixer; 104 int formatType = pipeSpecs.formatClass; 105 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 106 if( (type == OV_MDP_PIPE_ANY || //Pipe type match 107 type == PipeBook::getPipeType((eDest)i)) && 108 (mPipeBook[i].mDisplay == DPY_UNUSED || //Free or same display 109 mPipeBook[i].mDisplay == dpy) && 110 (mPipeBook[i].mMixer == MIXER_UNUSED || //Free or same mixer 111 mPipeBook[i].mMixer == mixer) && 112 (mPipeBook[i].mFormatType == FORMAT_NONE || //Free or same format 113 mPipeBook[i].mFormatType == formatType) && 114 PipeBook::isNotAllocated(i) && //Free pipe 115 ( (sDMAMultiplexingSupported && dpy) || 116 !(sDMAMode == DMA_BLOCK_MODE && //DMA pipe in Line mode 117 PipeBook::getPipeType((eDest)i) == OV_MDP_PIPE_DMA)) ){ 118 //DMA-Multiplexing is only supported for WB on 8x26 119 dest = (eDest)i; 120 PipeBook::setAllocation(i); 121 break; 122 } 123 } 124 125 if(dest != OV_INVALID) { 126 int index = (int)dest; 127 mPipeBook[index].mDisplay = dpy; 128 mPipeBook[index].mMixer = mixer; 129 mPipeBook[index].mFormatType = formatType; 130 if(not mPipeBook[index].valid()) { 131 mPipeBook[index].mPipe = new GenericPipe(dpy); 132 mPipeBook[index].mSession = PipeBook::NONE; 133 } 134 } 135 136 return dest; 137} 138 139utils::eDest Overlay::getPipe(const PipeSpecs& pipeSpecs) { 140 if(MDPVersion::getInstance().is8x26()) { 141 return getPipe_8x26(pipeSpecs); 142 } else if(MDPVersion::getInstance().is8x16()) { 143 return getPipe_8x16(pipeSpecs); 144 } else if(MDPVersion::getInstance().is8x39()) { 145 return getPipe_8x39(pipeSpecs); 146 } else if(MDPVersion::getInstance().is8994()) { 147 return getPipe_8994(pipeSpecs); 148 } 149 150 eDest dest = OV_INVALID; 151 152 //The default behavior is to assume RGB and VG pipes have scalars 153 if(pipeSpecs.formatClass == FORMAT_YUV) { 154 return nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 155 } else if(pipeSpecs.fb == false) { //RGB App layers 156 if(not pipeSpecs.needsScaling) { 157 dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); 158 } 159 if(dest == OV_INVALID) { 160 dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); 161 } 162 if(dest == OV_INVALID) { 163 dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 164 } 165 } else { //FB layer 166 dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); 167 if(dest == OV_INVALID) { 168 dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 169 } 170 //Some features can cause FB to have scaling as well. 171 //If we ever come to this block with FB needing scaling, 172 //the screen will be black for a frame, since the FB won't get a pipe 173 //but atleast this will prevent a hang 174 if(dest == OV_INVALID and (not pipeSpecs.needsScaling)) { 175 dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); 176 } 177 } 178 return dest; 179} 180 181utils::eDest Overlay::getPipe_8x26(const PipeSpecs& pipeSpecs) { 182 //Use this to hide all the 8x26 requirements that cannot be humanly 183 //described in a generic way 184 eDest dest = OV_INVALID; 185 if(pipeSpecs.formatClass == FORMAT_YUV) { //video 186 return nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 187 } else if(pipeSpecs.fb == false) { //RGB app layers 188 if((not pipeSpecs.needsScaling) and 189 (not (pipeSpecs.numActiveDisplays > 1 && 190 pipeSpecs.dpy == DPY_PRIMARY))) { 191 dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); 192 } 193 if(dest == OV_INVALID) { 194 dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); 195 } 196 if(dest == OV_INVALID) { 197 dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 198 } 199 } else { //FB layer 200 //For 8x26 Secondary we use DMA always for FB for inline rotation 201 if(pipeSpecs.dpy == DPY_PRIMARY) { 202 dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); 203 if(dest == OV_INVALID) { 204 dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 205 } 206 } 207 if(dest == OV_INVALID and (not pipeSpecs.needsScaling) and 208 (not (pipeSpecs.numActiveDisplays > 1 && 209 pipeSpecs.dpy == DPY_PRIMARY))) { 210 dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); 211 } 212 } 213 return dest; 214} 215 216utils::eDest Overlay::getPipe_8x16(const PipeSpecs& pipeSpecs) { 217 //Having such functions help keeping the interface generic but code specific 218 //and rife with assumptions 219 eDest dest = OV_INVALID; 220 if(pipeSpecs.formatClass == FORMAT_YUV or pipeSpecs.needsScaling) { 221 return nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 222 } else { 223 //Since this is a specific func, we can assume stuff like RGB pipe not 224 //having scalar blocks 225 dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); 226 if(dest == OV_INVALID) { 227 dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); 228 } 229 if(dest == OV_INVALID) { 230 dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 231 } 232 } 233 return dest; 234} 235 236utils::eDest Overlay::getPipe_8x39(const PipeSpecs& pipeSpecs) { 237 //8x16 & 8x36 has same number of pipes, pipe-types & scaling capabilities. 238 //Rely on 8x16 until we see a need to change. 239 return getPipe_8x16(pipeSpecs); 240} 241 242utils::eDest Overlay::getPipe_8994(const PipeSpecs& pipeSpecs) { 243 //If DMA pipes need to be used in block mode for downscale, there could be 244 //cases where consecutive rounds need separate modes, which cannot be 245 //supported since we at least need 1 round in between where the DMA is 246 //unused 247 eDest dest = OV_INVALID; 248 if(pipeSpecs.formatClass == FORMAT_YUV) { 249 return nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 250 } else { 251 dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); 252 if(dest == OV_INVALID) { 253 dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); 254 } 255 if(dest == OV_INVALID and not pipeSpecs.needsScaling) { 256 dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); 257 } 258 } 259 return dest; 260} 261 262void Overlay::endAllSessions() { 263 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 264 if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START) 265 mPipeBook[i].mSession = PipeBook::END; 266 } 267} 268 269bool Overlay::isPipeTypeAttached(eMdpPipeType type) { 270 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 271 if(type == PipeBook::getPipeType((eDest)i) && 272 mPipeBook[i].mDisplay != DPY_UNUSED) { 273 return true; 274 } 275 } 276 return false; 277} 278 279int Overlay::comparePipePriority(utils::eDest pipe1Index, 280 utils::eDest pipe2Index) { 281 validate((int)pipe1Index); 282 validate((int)pipe2Index); 283 uint8_t pipe1Prio = mPipeBook[(int)pipe1Index].mPipe->getPriority(); 284 uint8_t pipe2Prio = mPipeBook[(int)pipe2Index].mPipe->getPriority(); 285 if(pipe1Prio > pipe2Prio) 286 return -1; 287 if(pipe1Prio < pipe2Prio) 288 return 1; 289 return 0; 290} 291 292bool Overlay::commit(utils::eDest dest) { 293 bool ret = false; 294 validate((int)dest); 295 296 if(mPipeBook[dest].mPipe->commit()) { 297 ret = true; 298 PipeBook::setUse((int)dest); 299 } else { 300 clear(mPipeBook[dest].mDisplay); 301 } 302 return ret; 303} 304 305bool Overlay::queueBuffer(int fd, uint32_t offset, 306 utils::eDest dest) { 307 bool ret = false; 308 validate((int)dest); 309 //Queue only if commit() has succeeded (and the bit set) 310 if(PipeBook::isUsed((int)dest)) { 311 ret = mPipeBook[dest].mPipe->queueBuffer(fd, offset); 312 } 313 return ret; 314} 315 316void Overlay::setCrop(const utils::Dim& d, 317 utils::eDest dest) { 318 validate((int)dest); 319 mPipeBook[dest].mPipe->setCrop(d); 320} 321 322void Overlay::setColor(const uint32_t color, 323 utils::eDest dest) { 324 validate((int)dest); 325 mPipeBook[dest].mPipe->setColor(color); 326} 327 328void Overlay::setPosition(const utils::Dim& d, 329 utils::eDest dest) { 330 validate((int)dest); 331 mPipeBook[dest].mPipe->setPosition(d); 332} 333 334void Overlay::setTransform(const int orient, 335 utils::eDest dest) { 336 validate((int)dest); 337 338 utils::eTransform transform = 339 static_cast<utils::eTransform>(orient); 340 mPipeBook[dest].mPipe->setTransform(transform); 341 342} 343 344void Overlay::setSource(const utils::PipeArgs args, 345 utils::eDest dest) { 346 validate((int)dest); 347 348 setPipeType(dest, PipeBook::getPipeType(dest)); 349 mPipeBook[dest].mPipe->setSource(args); 350} 351 352void Overlay::setVisualParams(const MetaData_t& metadata, utils::eDest dest) { 353 validate((int)dest); 354 mPipeBook[dest].mPipe->setVisualParams(metadata); 355} 356 357void Overlay::setPipeType(utils::eDest pipeIndex, 358 const utils::eMdpPipeType pType) { 359 mPipeBook[pipeIndex].mPipe->setPipeType(pType); 360} 361 362Overlay* Overlay::getInstance() { 363 if(sInstance == NULL) { 364 sInstance = new Overlay(); 365 } 366 return sInstance; 367} 368 369// Clears any VG pipes allocated to the fb devices 370// Generates a LUT for pipe types. 371int Overlay::initOverlay() { 372 int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion(); 373 int numPipesXType[OV_MDP_PIPE_ANY] = {0}; 374 numPipesXType[OV_MDP_PIPE_RGB] = 375 qdutils::MDPVersion::getInstance().getRGBPipes(); 376 numPipesXType[OV_MDP_PIPE_VG] = 377 qdutils::MDPVersion::getInstance().getVGPipes(); 378 numPipesXType[OV_MDP_PIPE_DMA] = 379 qdutils::MDPVersion::getInstance().getDMAPipes(); 380 381 int index = 0; 382 for(int X = 0; X < (int)OV_MDP_PIPE_ANY; X++) { //iterate over types 383 for(int j = 0; j < numPipesXType[X]; j++) { //iterate over num 384 PipeBook::pipeTypeLUT[index] = (utils::eMdpPipeType)X; 385 index++; 386 } 387 } 388 389 if (mdpVersion < qdutils::MDSS_V5 && mdpVersion > qdutils::MDP_V3_0_5) { 390 msmfb_mixer_info_req req; 391 mdp_mixer_info *minfo = NULL; 392 char name[64]; 393 int fd = -1; 394 for(int i = 0; i < MAX_FB_DEVICES; i++) { 395 snprintf(name, 64, FB_DEVICE_TEMPLATE, i); 396 ALOGD("initoverlay:: opening the device:: %s", name); 397 fd = ::open(name, O_RDWR, 0); 398 if(fd < 0) { 399 ALOGE("cannot open framebuffer(%d)", i); 400 return -1; 401 } 402 //Get the mixer configuration */ 403 req.mixer_num = i; 404 if (ioctl(fd, MSMFB_MIXER_INFO, &req) == -1) { 405 ALOGE("ERROR: MSMFB_MIXER_INFO ioctl failed"); 406 close(fd); 407 return -1; 408 } 409 minfo = req.info; 410 for (int j = 0; j < req.cnt; j++) { 411 ALOGD("ndx=%d num=%d z_order=%d", minfo->pndx, minfo->pnum, 412 minfo->z_order); 413 // except the RGB base layer with z_order of -1, clear any 414 // other pipes connected to mixer. 415 if((minfo->z_order) != -1) { 416 int index = minfo->pndx; 417 ALOGD("Unset overlay with index: %d at mixer %d", index, i); 418 if(ioctl(fd, MSMFB_OVERLAY_UNSET, &index) == -1) { 419 ALOGE("ERROR: MSMFB_OVERLAY_UNSET failed"); 420 close(fd); 421 return -1; 422 } 423 } 424 minfo++; 425 } 426 close(fd); 427 fd = -1; 428 } 429 } 430 431 FILE *displayDeviceFP = NULL; 432 char fbType[MAX_FRAME_BUFFER_NAME_SIZE]; 433 char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE]; 434 const char *strDtvPanel = "dtv panel"; 435 const char *strWbPanel = "writeback panel"; 436 437 for(int num = 1; num < MAX_FB_DEVICES; num++) { 438 snprintf (msmFbTypePath, sizeof(msmFbTypePath), 439 "/sys/class/graphics/fb%d/msm_fb_type", num); 440 displayDeviceFP = fopen(msmFbTypePath, "r"); 441 442 if(displayDeviceFP){ 443 fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE, 444 displayDeviceFP); 445 446 if(strncmp(fbType, strDtvPanel, strlen(strDtvPanel)) == 0) { 447 sDpyFbMap[DPY_EXTERNAL] = num; 448 } else if(strncmp(fbType, strWbPanel, strlen(strWbPanel)) == 0) { 449 sDpyFbMap[DPY_WRITEBACK] = num; 450 } 451 452 fclose(displayDeviceFP); 453 } 454 } 455 456 return 0; 457} 458 459bool Overlay::displayCommit(const int& fd) { 460 utils::Dim lRoi, rRoi; 461 return displayCommit(fd, lRoi, rRoi); 462} 463 464bool Overlay::displayCommit(const int& fd, const utils::Dim& lRoi, 465 const utils::Dim& rRoi) { 466 //Commit 467 struct mdp_display_commit info; 468 memset(&info, 0, sizeof(struct mdp_display_commit)); 469 info.flags = MDP_DISPLAY_COMMIT_OVERLAY; 470 info.l_roi.x = lRoi.x; 471 info.l_roi.y = lRoi.y; 472 info.l_roi.w = lRoi.w; 473 info.l_roi.h = lRoi.h; 474 info.r_roi.x = rRoi.x; 475 info.r_roi.y = rRoi.y; 476 info.r_roi.w = rRoi.w; 477 info.r_roi.h = rRoi.h; 478 479 if(!mdp_wrapper::displayCommit(fd, info)) { 480 ALOGE("%s: commit failed", __func__); 481 return false; 482 } 483 return true; 484} 485 486void Overlay::getDump(char *buf, size_t len) { 487 int totalPipes = 0; 488 const char *str = "\nOverlay State\n\n"; 489 strlcat(buf, str, len); 490 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 491 if(mPipeBook[i].valid()) { 492 mPipeBook[i].mPipe->getDump(buf, len); 493 char str[64] = {'\0'}; 494 snprintf(str, 64, "Display=%d\n\n", mPipeBook[i].mDisplay); 495 strlcat(buf, str, len); 496 totalPipes++; 497 } 498 } 499 char str_pipes[64] = {'\0'}; 500 snprintf(str_pipes, 64, "Pipes=%d\n\n", totalPipes); 501 strlcat(buf, str_pipes, len); 502} 503 504void Overlay::clear(int dpy) { 505 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 506 if (mPipeBook[i].mDisplay == dpy) { 507 // Mark as available for this round 508 PipeBook::resetUse(i); 509 PipeBook::resetAllocation(i); 510 if(getPipeId((utils::eDest)i) == -1) { 511 mPipeBook[i].destroy(); 512 } 513 } 514 } 515} 516 517bool Overlay::validateAndSet(const int& dpy, const int& fbFd) { 518 GenericPipe* pipeArray[PipeBook::NUM_PIPES]; 519 memset(pipeArray, 0, sizeof(GenericPipe*)*(PipeBook::NUM_PIPES)); 520 521 int num = 0; 522 for(int i = 0; i < PipeBook::NUM_PIPES; i++) { 523 if(PipeBook::isUsed(i) && mPipeBook[i].valid() && 524 mPipeBook[i].mDisplay == dpy) { 525 pipeArray[num++] = mPipeBook[i].mPipe; 526 } 527 } 528 529 //Protect against misbehaving clients 530 return num ? GenericPipe::validateAndSet(pipeArray, num, fbFd) : true; 531} 532 533void Overlay::initScalar() { 534 if(sLibScaleHandle == NULL) { 535 sLibScaleHandle = dlopen("libscale.so", RTLD_NOW); 536 if(sLibScaleHandle) { 537 *(void **) &sFnProgramScale = 538 dlsym(sLibScaleHandle, "programScale"); 539 } 540 } 541} 542 543void Overlay::destroyScalar() { 544 if(sLibScaleHandle) { 545 dlclose(sLibScaleHandle); 546 sLibScaleHandle = NULL; 547 } 548} 549 550void Overlay::PipeBook::init() { 551 mPipe = NULL; 552 mDisplay = DPY_UNUSED; 553 mMixer = MIXER_UNUSED; 554 mFormatType = FORMAT_NONE; 555} 556 557void Overlay::PipeBook::destroy() { 558 if(mPipe) { 559 delete mPipe; 560 mPipe = NULL; 561 } 562 mDisplay = DPY_UNUSED; 563 mMixer = MIXER_UNUSED; 564 mFormatType = FORMAT_NONE; 565 mSession = NONE; 566} 567 568Overlay* Overlay::sInstance = 0; 569int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1, -1}; 570int Overlay::sDMAMode = DMA_LINE_MODE; 571bool Overlay::sDMAMultiplexingSupported = false; 572bool Overlay::sDebugPipeLifecycle = false; 573int Overlay::PipeBook::NUM_PIPES = 0; 574int Overlay::PipeBook::sPipeUsageBitmap = 0; 575int Overlay::PipeBook::sLastUsageBitmap = 0; 576int Overlay::PipeBook::sAllocatedBitmap = 0; 577utils::eMdpPipeType Overlay::PipeBook::pipeTypeLUT[utils::OV_MAX] = 578 {utils::OV_MDP_PIPE_ANY}; 579void *Overlay::sLibScaleHandle = NULL; 580int (*Overlay::sFnProgramScale)(struct mdp_overlay_list *) = NULL; 581 582}; // namespace overlay 583