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 retained 6 * 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#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) 21#include <fcntl.h> 22#include <errno.h> 23 24#include <cutils/log.h> 25#include <cutils/atomic.h> 26#include <EGL/egl.h> 27#include <utils/Trace.h> 28#include <sys/ioctl.h> 29#include <overlay.h> 30#include <overlayRotator.h> 31#include <overlayWriteback.h> 32#include <mdp_version.h> 33#include "hwc_utils.h" 34#include "hwc_fbupdate.h" 35#include "hwc_mdpcomp.h" 36#include "hwc_dump_layers.h" 37#include "external.h" 38#include "hwc_copybit.h" 39#include "hwc_ad.h" 40#include "profiler.h" 41#include "hwc_virtual.h" 42 43using namespace qhwc; 44using namespace overlay; 45 46#define VSYNC_DEBUG 0 47#define BLANK_DEBUG 1 48 49static int hwc_device_open(const struct hw_module_t* module, 50 const char* name, 51 struct hw_device_t** device); 52 53static struct hw_module_methods_t hwc_module_methods = { 54 open: hwc_device_open 55}; 56 57static void reset_panel(struct hwc_composer_device_1* dev); 58 59hwc_module_t HAL_MODULE_INFO_SYM = { 60 common: { 61 tag: HARDWARE_MODULE_TAG, 62 version_major: 2, 63 version_minor: 0, 64 id: HWC_HARDWARE_MODULE_ID, 65 name: "Qualcomm Hardware Composer Module", 66 author: "CodeAurora Forum", 67 methods: &hwc_module_methods, 68 dso: 0, 69 reserved: {0}, 70 } 71}; 72 73/* In case of non-hybrid WFD session, we are fooling SF by piggybacking on 74 * HDMI display ID for virtual. This helper is needed to differentiate their 75 * paths in HAL. 76 * TODO: Not needed once we have WFD client working on top of Google API's */ 77 78static int getDpyforExternalDisplay(hwc_context_t *ctx, int dpy) { 79 if(dpy == HWC_DISPLAY_EXTERNAL && ctx->mVirtualonExtActive) 80 return HWC_DISPLAY_VIRTUAL; 81 return dpy; 82} 83 84/* 85 * Save callback functions registered to HWC 86 */ 87static void hwc_registerProcs(struct hwc_composer_device_1* dev, 88 hwc_procs_t const* procs) 89{ 90 ALOGI("%s", __FUNCTION__); 91 hwc_context_t* ctx = (hwc_context_t*)(dev); 92 if(!ctx) { 93 ALOGE("%s: Invalid context", __FUNCTION__); 94 return; 95 } 96 ctx->proc = procs; 97 98 // Now that we have the functions needed, kick off 99 // the uevent & vsync threads 100 init_uevent_thread(ctx); 101 init_vsync_thread(ctx); 102} 103 104//Helper 105static void reset(hwc_context_t *ctx, int numDisplays, 106 hwc_display_contents_1_t** displays) { 107 108 ctx->numActiveDisplays = 0; 109 ctx->isPaddingRound = false; 110 111 for(int i = 0; i < numDisplays; i++) { 112 hwc_display_contents_1_t *list = displays[i]; 113 // XXX:SurfaceFlinger no longer guarantees that this 114 // value is reset on every prepare. However, for the layer 115 // cache we need to reset it. 116 // We can probably rethink that later on 117 if (LIKELY(list && list->numHwLayers > 0)) { 118 for(uint32_t j = 0; j < list->numHwLayers; j++) { 119 if(list->hwLayers[j].compositionType != HWC_FRAMEBUFFER_TARGET) 120 list->hwLayers[j].compositionType = HWC_FRAMEBUFFER; 121 } 122 123 /* For display devices like SSD and screenrecord, we cannot 124 * rely on isActive and connected attributes of dpyAttr to 125 * determine if the displaydevice is active. Hence in case if 126 * the layer-list is non-null and numHwLayers > 0, we assume 127 * the display device to be active. 128 */ 129 ctx->numActiveDisplays += 1; 130 131 if((ctx->mPrevHwLayerCount[i] == 1) and (list->numHwLayers > 1)) { 132 /* If the previous cycle for dpy 'i' has 0 AppLayers and the 133 * current cycle has atleast 1 AppLayer, padding round needs 134 * to be invoked on current cycle to free up the resources. 135 */ 136 ctx->isPaddingRound = true; 137 } 138 ctx->mPrevHwLayerCount[i] = list->numHwLayers; 139 } else { 140 ctx->mPrevHwLayerCount[i] = 0; 141 } 142 143 if(ctx->mFBUpdate[i]) 144 ctx->mFBUpdate[i]->reset(); 145 if(ctx->mCopyBit[i]) 146 ctx->mCopyBit[i]->reset(); 147 if(ctx->mLayerRotMap[i]) 148 ctx->mLayerRotMap[i]->reset(); 149 } 150 151 ctx->mAD->reset(); 152 MDPComp::reset(); 153 if(ctx->mHWCVirtual) 154 ctx->mHWCVirtual->destroy(ctx, numDisplays, displays); 155} 156 157bool isEqual(float f1, float f2) { 158 return ((int)(f1*100) == (int)(f2*100)) ? true : false; 159} 160 161static void scaleDisplayFrame(hwc_context_t *ctx, int dpy, 162 hwc_display_contents_1_t *list) { 163 float origXres = ctx->dpyAttr[dpy].xres_orig; 164 float origYres = ctx->dpyAttr[dpy].yres_orig; 165 float fakeXres = ctx->dpyAttr[dpy].xres; 166 float fakeYres = ctx->dpyAttr[dpy].yres; 167 float xresRatio = origXres / fakeXres; 168 float yresRatio = origYres / fakeYres; 169 for (size_t i = 0; i < list->numHwLayers; i++) { 170 hwc_layer_1_t *layer = &list->hwLayers[i]; 171 hwc_rect_t& displayFrame = layer->displayFrame; 172 hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); 173 float layerWidth = displayFrame.right - displayFrame.left; 174 float layerHeight = displayFrame.bottom - displayFrame.top; 175 float sourceWidth = sourceCrop.right - sourceCrop.left; 176 float sourceHeight = sourceCrop.bottom - sourceCrop.top; 177 178 if (isEqual(layerWidth / sourceWidth, xresRatio) && 179 isEqual(layerHeight / sourceHeight, yresRatio)) 180 break; 181 182 displayFrame.left = xresRatio * displayFrame.left; 183 displayFrame.top = yresRatio * displayFrame.top; 184 displayFrame.right = displayFrame.left + layerWidth * xresRatio; 185 displayFrame.bottom = displayFrame.top + layerHeight * yresRatio; 186 } 187} 188 189static int hwc_prepare_primary(hwc_composer_device_1 *dev, 190 hwc_display_contents_1_t *list) { 191 ATRACE_CALL(); 192 hwc_context_t* ctx = (hwc_context_t*)(dev); 193 const int dpy = HWC_DISPLAY_PRIMARY; 194 bool fbComp = false; 195 if (LIKELY(list && list->numHwLayers > 1) && 196 ctx->dpyAttr[dpy].isActive) { 197 198 if (ctx->dpyAttr[dpy].customFBSize) 199 scaleDisplayFrame(ctx, dpy, list); 200 201 reset_layer_prop(ctx, dpy, list->numHwLayers - 1); 202 setListStats(ctx, list, dpy); 203 204 fbComp = (ctx->mMDPComp[dpy]->prepare(ctx, list) < 0); 205 206 if (fbComp) { 207 const int fbZ = 0; 208 ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ); 209 } 210 211 if (ctx->mMDP.version < qdutils::MDP_V4_0) { 212 if(ctx->mCopyBit[dpy]) 213 ctx->mCopyBit[dpy]->prepare(ctx, list, dpy); 214 } 215 setGPUHint(ctx, list); 216 } 217 return 0; 218} 219 220static int hwc_prepare_external(hwc_composer_device_1 *dev, 221 hwc_display_contents_1_t *list) { 222 ATRACE_CALL(); 223 hwc_context_t* ctx = (hwc_context_t*)(dev); 224 const int dpy = HWC_DISPLAY_EXTERNAL; 225 226 if (LIKELY(list && list->numHwLayers > 1) && 227 ctx->dpyAttr[dpy].isActive && 228 ctx->dpyAttr[dpy].connected) { 229 reset_layer_prop(ctx, dpy, list->numHwLayers - 1); 230 if(!ctx->dpyAttr[dpy].isPause) { 231 ctx->dpyAttr[dpy].isConfiguring = false; 232 setListStats(ctx, list, dpy); 233 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) { 234 const int fbZ = 0; 235 ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ); 236 } 237 } else { 238 /* External Display is in Pause state. 239 * Mark all application layers as OVERLAY so that 240 * GPU will not compose. 241 */ 242 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) { 243 hwc_layer_1_t *layer = &list->hwLayers[i]; 244 layer->compositionType = HWC_OVERLAY; 245 } 246 } 247 } 248 return 0; 249} 250 251static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays, 252 hwc_display_contents_1_t** displays) 253{ 254 int ret = 0; 255 hwc_context_t* ctx = (hwc_context_t*)(dev); 256 257 if (ctx->mPanelResetStatus) { 258 ALOGW("%s: panel is in bad state. reset the panel", __FUNCTION__); 259 reset_panel(dev); 260 } 261 262 //Will be unlocked at the end of set 263 ctx->mDrawLock.lock(); 264 reset(ctx, numDisplays, displays); 265 266 ctx->mOverlay->configBegin(); 267 ctx->mRotMgr->configBegin(); 268 overlay::Writeback::configBegin(); 269 270 for (int32_t i = (numDisplays-1); i >= 0; i--) { 271 hwc_display_contents_1_t *list = displays[i]; 272 int dpy = getDpyforExternalDisplay(ctx, i); 273 switch(dpy) { 274 case HWC_DISPLAY_PRIMARY: 275 ret = hwc_prepare_primary(dev, list); 276 break; 277 case HWC_DISPLAY_EXTERNAL: 278 ret = hwc_prepare_external(dev, list); 279 break; 280 case HWC_DISPLAY_VIRTUAL: 281 if(ctx->mHWCVirtual) 282 ret = ctx->mHWCVirtual->prepare(dev, list); 283 break; 284 default: 285 ret = -EINVAL; 286 } 287 } 288 289 ctx->mOverlay->configDone(); 290 ctx->mRotMgr->configDone(); 291 overlay::Writeback::configDone(); 292 293 return ret; 294} 295 296static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy, 297 int event, int enable) 298{ 299 ATRACE_CALL(); 300 int ret = 0; 301 hwc_context_t* ctx = (hwc_context_t*)(dev); 302 switch(event) { 303 case HWC_EVENT_VSYNC: 304 if (ctx->vstate.enable == enable) 305 break; 306 ret = hwc_vsync_control(ctx, dpy, enable); 307 if(ret == 0) 308 ctx->vstate.enable = !!enable; 309 ALOGD_IF (VSYNC_DEBUG, "VSYNC state changed to %s", 310 (enable)?"ENABLED":"DISABLED"); 311 break; 312#ifdef QCOM_BSP 313 case HWC_EVENT_ORIENTATION: 314 if(dpy == HWC_DISPLAY_PRIMARY) { 315 Locker::Autolock _l(ctx->mDrawLock); 316 // store the primary display orientation 317 ctx->deviceOrientation = enable; 318 } 319 break; 320#endif 321 default: 322 ret = -EINVAL; 323 } 324 return ret; 325} 326 327static int hwc_blank(struct hwc_composer_device_1* dev, int dpy, int blank) 328{ 329 ATRACE_CALL(); 330 hwc_context_t* ctx = (hwc_context_t*)(dev); 331 332 Locker::Autolock _l(ctx->mDrawLock); 333 int ret = 0, value = 0; 334 335 /* In case of non-hybrid WFD session, we are fooling SF by 336 * piggybacking on HDMI display ID for virtual. 337 * TODO: Not needed once we have WFD client working on top 338 * of Google API's. 339 */ 340 dpy = getDpyforExternalDisplay(ctx,dpy); 341 342 ALOGD_IF(BLANK_DEBUG, "%s: %s display: %d", __FUNCTION__, 343 blank==1 ? "Blanking":"Unblanking", dpy); 344 if(blank) { 345 // free up all the overlay pipes in use 346 // when we get a blank for either display 347 // makes sure that all pipes are freed 348 ctx->mOverlay->configBegin(); 349 ctx->mOverlay->configDone(); 350 ctx->mRotMgr->clear(); 351 // If VDS is connected, do not clear WB object as it 352 // will end up detaching IOMMU. This is required 353 // to send black frame to WFD sink on power suspend. 354 // Note: With this change, we keep the WriteBack object 355 // alive on power suspend for AD use case. 356 } 357 switch(dpy) { 358 case HWC_DISPLAY_PRIMARY: 359 value = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK; 360 if(ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, value) < 0 ) { 361 ALOGE("%s: Failed to handle blank event(%d) for Primary!!", 362 __FUNCTION__, blank ); 363 return -1; 364 } 365 366 if(!blank) { 367 // Enable HPD here, as during bootup unblank is called 368 // when SF is completely initialized 369 ctx->mExtDisplay->setHPD(1); 370 } 371 372 ctx->dpyAttr[dpy].isActive = !blank; 373 374 if(ctx->mVirtualonExtActive) { 375 /* if mVirtualonExtActive is true, display hal will 376 * receive unblank calls for non-hybrid WFD solution 377 * since we piggyback on HDMI. 378 * TODO: Not needed once we have WFD client working on top 379 of Google API's */ 380 break; 381 } 382 case HWC_DISPLAY_VIRTUAL: 383 /* There are two ways to reach this block of code. 384 385 * Display hal has received unblank call on HWC_DISPLAY_EXTERNAL 386 and ctx->mVirtualonExtActive is true. In this case, non-hybrid 387 WFD is active. If so, getDpyforExternalDisplay will return dpy 388 as HWC_DISPLAY_VIRTUAL. 389 390 * Display hal has received unblank call on HWC_DISPLAY_PRIMARY 391 and since SF is not aware of VIRTUAL DISPLAY being handle by HWC, 392 it wont send blank / unblank events for it. We piggyback on 393 PRIMARY DISPLAY events to release mdp pipes and 394 activate/deactivate VIRTUAL DISPLAY. 395 396 * TODO: This separate case statement is not needed once we have 397 WFD client working on top of Google API's. 398 399 */ 400 401 if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) { 402 if(blank and (!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause)) { 403 int dpy = HWC_DISPLAY_VIRTUAL; 404 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { 405 ALOGE("%s: display commit fail for virtual!", __FUNCTION__); 406 ret = -1; 407 } 408 } 409 ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank; 410 } 411 break; 412 case HWC_DISPLAY_EXTERNAL: 413 if(blank) { 414 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { 415 ALOGE("%s: display commit fail for external!", __FUNCTION__); 416 ret = -1; 417 } 418 } 419 ctx->dpyAttr[dpy].isActive = !blank; 420 break; 421 default: 422 return -EINVAL; 423 } 424 425 ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__, 426 blank ? "blanking":"unblanking", dpy); 427 return ret; 428} 429 430static void reset_panel(struct hwc_composer_device_1* dev) 431{ 432 int ret = 0; 433 hwc_context_t* ctx = (hwc_context_t*)(dev); 434 435 if (!ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive) { 436 ALOGD ("%s : Display OFF - Skip BLANK & UNBLANK", __FUNCTION__); 437 ctx->mPanelResetStatus = false; 438 return; 439 } 440 441 ALOGD("%s: calling BLANK DISPLAY", __FUNCTION__); 442 ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 1); 443 if (ret < 0) { 444 ALOGE("%s: FBIOBLANK failed to BLANK: %s", __FUNCTION__, 445 strerror(errno)); 446 } 447 448 ALOGD("%s: calling UNBLANK DISPLAY and enabling vsync", __FUNCTION__); 449 ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 0); 450 if (ret < 0) { 451 ALOGE("%s: FBIOBLANK failed to UNBLANK : %s", __FUNCTION__, 452 strerror(errno)); 453 } 454 hwc_vsync_control(ctx, HWC_DISPLAY_PRIMARY, 1); 455 456 ctx->mPanelResetStatus = false; 457} 458 459 460static int hwc_query(struct hwc_composer_device_1* dev, 461 int param, int* value) 462{ 463 hwc_context_t* ctx = (hwc_context_t*)(dev); 464 int supported = HWC_DISPLAY_PRIMARY_BIT; 465 466 switch (param) { 467 case HWC_BACKGROUND_LAYER_SUPPORTED: 468 // Not supported for now 469 value[0] = 0; 470 break; 471 case HWC_DISPLAY_TYPES_SUPPORTED: 472 if(ctx->mMDP.hasOverlay) { 473 supported |= HWC_DISPLAY_VIRTUAL_BIT; 474 if(!(qdutils::MDPVersion::getInstance().is8x26() || 475 qdutils::MDPVersion::getInstance().is8x16())) 476 supported |= HWC_DISPLAY_EXTERNAL_BIT; 477 } 478 value[0] = supported; 479 break; 480 case HWC_FORMAT_RB_SWAP: 481 value[0] = 1; 482 break; 483 case HWC_COLOR_FILL: 484 value[0] = 1; 485 break; 486 default: 487 return -EINVAL; 488 } 489 return 0; 490 491} 492 493 494static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) { 495 ATRACE_CALL(); 496 int ret = 0; 497 const int dpy = HWC_DISPLAY_PRIMARY; 498 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive) { 499 uint32_t last = list->numHwLayers - 1; 500 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 501 int fd = -1; //FenceFD from the Copybit(valid in async mode) 502 bool copybitDone = false; 503 if(ctx->mCopyBit[dpy]) 504 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 505 if(list->numHwLayers > 1) 506 hwc_sync(ctx, list, dpy, fd); 507 508 // Dump the layers for primary 509 if(ctx->mHwcDebug[dpy]) 510 ctx->mHwcDebug[dpy]->dumpLayers(list); 511 512 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 513 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 514 ret = -1; 515 } 516 517 //TODO We dont check for SKIP flag on this layer because we need PAN 518 //always. Last layer is always FB 519 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 520 if(copybitDone && ctx->mMDP.version >= qdutils::MDP_V4_0) { 521 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 522 } 523 524 if(hnd) { 525 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 526 ALOGE("%s: FBUpdate draw failed", __FUNCTION__); 527 ret = -1; 528 } 529 } 530 531 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd, 532 ctx->listStats[dpy].roi)) { 533 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy); 534 ret = -1; 535 } 536 537 } 538 539 closeAcquireFds(list); 540 return ret; 541} 542 543static int hwc_set_external(hwc_context_t *ctx, 544 hwc_display_contents_1_t* list) 545{ 546 ATRACE_CALL(); 547 int ret = 0; 548 549 const int dpy = HWC_DISPLAY_EXTERNAL; 550 551 552 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive && 553 ctx->dpyAttr[dpy].connected && 554 !ctx->dpyAttr[dpy].isPause) { 555 uint32_t last = list->numHwLayers - 1; 556 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 557 int fd = -1; //FenceFD from the Copybit(valid in async mode) 558 bool copybitDone = false; 559 if(ctx->mCopyBit[dpy]) 560 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 561 562 if(list->numHwLayers > 1) 563 hwc_sync(ctx, list, dpy, fd); 564 565 // Dump the layers for external 566 if(ctx->mHwcDebug[dpy]) 567 ctx->mHwcDebug[dpy]->dumpLayers(list); 568 569 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 570 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 571 ret = -1; 572 } 573 574 int extOnlyLayerIndex = 575 ctx->listStats[dpy].extOnlyLayerIndex; 576 577 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 578 if(extOnlyLayerIndex!= -1) { 579 hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex]; 580 hnd = (private_handle_t *)extLayer->handle; 581 } else if(copybitDone) { 582 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 583 } 584 585 if(hnd && !isYuvBuffer(hnd)) { 586 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 587 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__); 588 ret = -1; 589 } 590 } 591 592 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { 593 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy); 594 ret = -1; 595 } 596 } 597 598 closeAcquireFds(list); 599 return ret; 600} 601 602static int hwc_set(hwc_composer_device_1 *dev, 603 size_t numDisplays, 604 hwc_display_contents_1_t** displays) 605{ 606 int ret = 0; 607 hwc_context_t* ctx = (hwc_context_t*)(dev); 608 for (uint32_t i = 0; i < numDisplays; i++) { 609 hwc_display_contents_1_t* list = displays[i]; 610 int dpy = getDpyforExternalDisplay(ctx, i); 611 switch(dpy) { 612 case HWC_DISPLAY_PRIMARY: 613 ret = hwc_set_primary(ctx, list); 614 break; 615 case HWC_DISPLAY_EXTERNAL: 616 ret = hwc_set_external(ctx, list); 617 break; 618 case HWC_DISPLAY_VIRTUAL: 619 if(ctx->mHWCVirtual) 620 ret = ctx->mHWCVirtual->set(ctx, list); 621 break; 622 default: 623 ret = -EINVAL; 624 } 625 } 626 // This is only indicative of how many times SurfaceFlinger posts 627 // frames to the display. 628 CALC_FPS(); 629 MDPComp::resetIdleFallBack(); 630 ctx->mVideoTransFlag = false; 631 if(ctx->mRotMgr->getNumActiveSessions() == 0) 632 Overlay::setDMAMode(Overlay::DMA_LINE_MODE); 633 //Was locked at the beginning of prepare 634 ctx->mDrawLock.unlock(); 635 return ret; 636} 637 638int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp, 639 uint32_t* configs, size_t* numConfigs) { 640 int ret = 0; 641 hwc_context_t* ctx = (hwc_context_t*)(dev); 642 disp = getDpyforExternalDisplay(ctx, disp); 643 //in 1.1 there is no way to choose a config, report as config id # 0 644 //This config is passed to getDisplayAttributes. Ignore for now. 645 switch(disp) { 646 case HWC_DISPLAY_PRIMARY: 647 if(*numConfigs > 0) { 648 configs[0] = 0; 649 *numConfigs = 1; 650 } 651 ret = 0; //NO_ERROR 652 break; 653 case HWC_DISPLAY_EXTERNAL: 654 case HWC_DISPLAY_VIRTUAL: 655 ret = -1; //Not connected 656 if(ctx->dpyAttr[disp].connected) { 657 ret = 0; //NO_ERROR 658 if(*numConfigs > 0) { 659 configs[0] = 0; 660 *numConfigs = 1; 661 } 662 } 663 break; 664 } 665 return ret; 666} 667 668int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp, 669 uint32_t /*config*/, const uint32_t* attributes, int32_t* values) { 670 671 hwc_context_t* ctx = (hwc_context_t*)(dev); 672 disp = getDpyforExternalDisplay(ctx, disp); 673 //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error 674 if( (disp != HWC_DISPLAY_PRIMARY) && !ctx->dpyAttr[disp].connected) { 675 return -1; 676 } 677 678 //From HWComposer 679 static const uint32_t DISPLAY_ATTRIBUTES[] = { 680 HWC_DISPLAY_VSYNC_PERIOD, 681 HWC_DISPLAY_WIDTH, 682 HWC_DISPLAY_HEIGHT, 683 HWC_DISPLAY_DPI_X, 684 HWC_DISPLAY_DPI_Y, 685 HWC_DISPLAY_NO_ATTRIBUTE, 686 }; 687 688 const int NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) / 689 sizeof(DISPLAY_ATTRIBUTES)[0]); 690 691 for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { 692 switch (attributes[i]) { 693 case HWC_DISPLAY_VSYNC_PERIOD: 694 values[i] = ctx->dpyAttr[disp].vsync_period; 695 break; 696 case HWC_DISPLAY_WIDTH: 697 values[i] = ctx->dpyAttr[disp].xres; 698 ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp, 699 ctx->dpyAttr[disp].xres); 700 break; 701 case HWC_DISPLAY_HEIGHT: 702 values[i] = ctx->dpyAttr[disp].yres; 703 ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp, 704 ctx->dpyAttr[disp].yres); 705 break; 706 case HWC_DISPLAY_DPI_X: 707 values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0); 708 break; 709 case HWC_DISPLAY_DPI_Y: 710 values[i] = (int32_t) (ctx->dpyAttr[disp].ydpi*1000.0); 711 break; 712 default: 713 ALOGE("Unknown display attribute %d", 714 attributes[i]); 715 return -EINVAL; 716 } 717 } 718 return 0; 719} 720 721void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len) 722{ 723 hwc_context_t* ctx = (hwc_context_t*)(dev); 724 Locker::Autolock _l(ctx->mDrawLock); 725 android::String8 aBuf(""); 726 dumpsys_log(aBuf, "Qualcomm HWC state:\n"); 727 dumpsys_log(aBuf, " MDPVersion=%d\n", ctx->mMDP.version); 728 dumpsys_log(aBuf, " DisplayPanel=%c\n", ctx->mMDP.panel); 729 if(ctx->vstate.fakevsync) 730 dumpsys_log(aBuf, " Vsync is being faked!!\n"); 731 for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) { 732 if(ctx->mMDPComp[dpy]) 733 ctx->mMDPComp[dpy]->dump(aBuf); 734 } 735 char ovDump[2048] = {'\0'}; 736 ctx->mOverlay->getDump(ovDump, 2048); 737 dumpsys_log(aBuf, ovDump); 738 ovDump[0] = '\0'; 739 ctx->mRotMgr->getDump(ovDump, 1024); 740 dumpsys_log(aBuf, ovDump); 741 ovDump[0] = '\0'; 742 if(Writeback::getDump(ovDump, 1024)) { 743 dumpsys_log(aBuf, ovDump); 744 ovDump[0] = '\0'; 745 } 746 strlcpy(buff, aBuf.string(), buff_len); 747} 748 749static int hwc_device_close(struct hw_device_t *dev) 750{ 751 if(!dev) { 752 ALOGE("%s: NULL device pointer", __FUNCTION__); 753 return -1; 754 } 755 closeContext((hwc_context_t*)dev); 756 free(dev); 757 758 return 0; 759} 760 761static int hwc_device_open(const struct hw_module_t* module, const char* name, 762 struct hw_device_t** device) 763{ 764 int status = -EINVAL; 765 766 if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { 767 struct hwc_context_t *dev; 768 dev = (hwc_context_t*)malloc(sizeof(*dev)); 769 if(dev == NULL) 770 return status; 771 memset(dev, 0, sizeof(*dev)); 772 773 //Initialize hwc context 774 initContext(dev); 775 776 //Setup HWC methods 777 dev->device.common.tag = HARDWARE_DEVICE_TAG; 778 dev->device.common.version = HWC_DEVICE_API_VERSION_1_3; 779 dev->device.common.module = const_cast<hw_module_t*>(module); 780 dev->device.common.close = hwc_device_close; 781 dev->device.prepare = hwc_prepare; 782 dev->device.set = hwc_set; 783 dev->device.eventControl = hwc_eventControl; 784 dev->device.blank = hwc_blank; 785 dev->device.query = hwc_query; 786 dev->device.registerProcs = hwc_registerProcs; 787 dev->device.dump = hwc_dump; 788 dev->device.getDisplayConfigs = hwc_getDisplayConfigs; 789 dev->device.getDisplayAttributes = hwc_getDisplayAttributes; 790 *device = &dev->device.common; 791 status = 0; 792 } 793 return status; 794} 795