hwc.cpp revision 201e4c9a80c1adb32ac8271a95721aa838c4d9fe
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 } 216 return 0; 217} 218 219static int hwc_prepare_external(hwc_composer_device_1 *dev, 220 hwc_display_contents_1_t *list) { 221 ATRACE_CALL(); 222 hwc_context_t* ctx = (hwc_context_t*)(dev); 223 const int dpy = HWC_DISPLAY_EXTERNAL; 224 225 if (LIKELY(list && list->numHwLayers > 1) && 226 ctx->dpyAttr[dpy].isActive && 227 ctx->dpyAttr[dpy].connected) { 228 reset_layer_prop(ctx, dpy, list->numHwLayers - 1); 229 if(!ctx->dpyAttr[dpy].isPause) { 230 ctx->dpyAttr[dpy].isConfiguring = false; 231 setListStats(ctx, list, dpy); 232 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) { 233 const int fbZ = 0; 234 ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ); 235 } 236 } else { 237 /* External Display is in Pause state. 238 * Mark all application layers as OVERLAY so that 239 * GPU will not compose. 240 */ 241 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) { 242 hwc_layer_1_t *layer = &list->hwLayers[i]; 243 layer->compositionType = HWC_OVERLAY; 244 } 245 } 246 } 247 return 0; 248} 249 250static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays, 251 hwc_display_contents_1_t** displays) 252{ 253 int ret = 0; 254 hwc_context_t* ctx = (hwc_context_t*)(dev); 255 256 if (ctx->mPanelResetStatus) { 257 ALOGW("%s: panel is in bad state. reset the panel", __FUNCTION__); 258 reset_panel(dev); 259 } 260 261 //Will be unlocked at the end of set 262 ctx->mDrawLock.lock(); 263 reset(ctx, numDisplays, displays); 264 265 ctx->mOverlay->configBegin(); 266 ctx->mRotMgr->configBegin(); 267 overlay::Writeback::configBegin(); 268 269 for (int32_t i = (numDisplays-1); i >= 0; i--) { 270 hwc_display_contents_1_t *list = displays[i]; 271 int dpy = getDpyforExternalDisplay(ctx, i); 272 switch(dpy) { 273 case HWC_DISPLAY_PRIMARY: 274 ret = hwc_prepare_primary(dev, list); 275 break; 276 case HWC_DISPLAY_EXTERNAL: 277 ret = hwc_prepare_external(dev, list); 278 break; 279 case HWC_DISPLAY_VIRTUAL: 280 if(ctx->mHWCVirtual) 281 ret = ctx->mHWCVirtual->prepare(dev, list); 282 break; 283 default: 284 ret = -EINVAL; 285 } 286 } 287 288 ctx->mOverlay->configDone(); 289 ctx->mRotMgr->configDone(); 290 overlay::Writeback::configDone(); 291 292 return ret; 293} 294 295static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy, 296 int event, int enable) 297{ 298 ATRACE_CALL(); 299 int ret = 0; 300 hwc_context_t* ctx = (hwc_context_t*)(dev); 301 switch(event) { 302 case HWC_EVENT_VSYNC: 303 if (ctx->vstate.enable == enable) 304 break; 305 ret = hwc_vsync_control(ctx, dpy, enable); 306 if(ret == 0) 307 ctx->vstate.enable = !!enable; 308 ALOGD_IF (VSYNC_DEBUG, "VSYNC state changed to %s", 309 (enable)?"ENABLED":"DISABLED"); 310 break; 311#ifdef QCOM_BSP 312 case HWC_EVENT_ORIENTATION: 313 if(dpy == HWC_DISPLAY_PRIMARY) { 314 Locker::Autolock _l(ctx->mDrawLock); 315 // store the primary display orientation 316 ctx->deviceOrientation = enable; 317 } 318 break; 319#endif 320 default: 321 ret = -EINVAL; 322 } 323 return ret; 324} 325 326static int hwc_blank(struct hwc_composer_device_1* dev, int dpy, int blank) 327{ 328 ATRACE_CALL(); 329 hwc_context_t* ctx = (hwc_context_t*)(dev); 330 331 Locker::Autolock _l(ctx->mDrawLock); 332 int ret = 0, value = 0; 333 334 /* In case of non-hybrid WFD session, we are fooling SF by 335 * piggybacking on HDMI display ID for virtual. 336 * TODO: Not needed once we have WFD client working on top 337 * of Google API's. 338 */ 339 dpy = getDpyforExternalDisplay(ctx,dpy); 340 341 ALOGD_IF(BLANK_DEBUG, "%s: %s display: %d", __FUNCTION__, 342 blank==1 ? "Blanking":"Unblanking", dpy); 343 if(blank) { 344 // free up all the overlay pipes in use 345 // when we get a blank for either display 346 // makes sure that all pipes are freed 347 ctx->mOverlay->configBegin(); 348 ctx->mOverlay->configDone(); 349 ctx->mRotMgr->clear(); 350 // If VDS is connected, do not clear WB object as it 351 // will end up detaching IOMMU. This is required 352 // to send black frame to WFD sink on power suspend. 353 // Note: With this change, we keep the WriteBack object 354 // alive on power suspend for AD use case. 355 } 356 switch(dpy) { 357 case HWC_DISPLAY_PRIMARY: 358 value = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK; 359 if(ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, value) < 0 ) { 360 ALOGE("%s: Failed to handle blank event(%d) for Primary!!", 361 __FUNCTION__, blank ); 362 return -1; 363 } 364 365 if(!blank) { 366 // Enable HPD here, as during bootup unblank is called 367 // when SF is completely initialized 368 ctx->mExtDisplay->setHPD(1); 369 } 370 371 ctx->dpyAttr[dpy].isActive = !blank; 372 373 if(ctx->mVirtualonExtActive) { 374 /* if mVirtualonExtActive is true, display hal will 375 * receive unblank calls for non-hybrid WFD solution 376 * since we piggyback on HDMI. 377 * TODO: Not needed once we have WFD client working on top 378 of Google API's */ 379 break; 380 } 381 case HWC_DISPLAY_VIRTUAL: 382 /* There are two ways to reach this block of code. 383 384 * Display hal has received unblank call on HWC_DISPLAY_EXTERNAL 385 and ctx->mVirtualonExtActive is true. In this case, non-hybrid 386 WFD is active. If so, getDpyforExternalDisplay will return dpy 387 as HWC_DISPLAY_VIRTUAL. 388 389 * Display hal has received unblank call on HWC_DISPLAY_PRIMARY 390 and since SF is not aware of VIRTUAL DISPLAY being handle by HWC, 391 it wont send blank / unblank events for it. We piggyback on 392 PRIMARY DISPLAY events to release mdp pipes and 393 activate/deactivate VIRTUAL DISPLAY. 394 395 * TODO: This separate case statement is not needed once we have 396 WFD client working on top of Google API's. 397 398 */ 399 400 if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) { 401 if(blank and (!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause)) { 402 int dpy = HWC_DISPLAY_VIRTUAL; 403 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { 404 ALOGE("%s: display commit fail for virtual!", __FUNCTION__); 405 ret = -1; 406 } 407 } 408 ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank; 409 } 410 break; 411 case HWC_DISPLAY_EXTERNAL: 412 if(blank) { 413 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { 414 ALOGE("%s: display commit fail for external!", __FUNCTION__); 415 ret = -1; 416 } 417 } 418 ctx->dpyAttr[dpy].isActive = !blank; 419 break; 420 default: 421 return -EINVAL; 422 } 423 424 ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__, 425 blank ? "blanking":"unblanking", dpy); 426 return ret; 427} 428 429static void reset_panel(struct hwc_composer_device_1* dev) 430{ 431 int ret = 0; 432 hwc_context_t* ctx = (hwc_context_t*)(dev); 433 434 if (!ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive) { 435 ALOGD ("%s : Display OFF - Skip BLANK & UNBLANK", __FUNCTION__); 436 ctx->mPanelResetStatus = false; 437 return; 438 } 439 440 ALOGD("%s: calling BLANK DISPLAY", __FUNCTION__); 441 ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 1); 442 if (ret < 0) { 443 ALOGE("%s: FBIOBLANK failed to BLANK: %s", __FUNCTION__, 444 strerror(errno)); 445 } 446 447 ALOGD("%s: calling UNBLANK DISPLAY and enabling vsync", __FUNCTION__); 448 ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 0); 449 if (ret < 0) { 450 ALOGE("%s: FBIOBLANK failed to UNBLANK : %s", __FUNCTION__, 451 strerror(errno)); 452 } 453 hwc_vsync_control(ctx, HWC_DISPLAY_PRIMARY, 1); 454 455 ctx->mPanelResetStatus = false; 456} 457 458 459static int hwc_query(struct hwc_composer_device_1* dev, 460 int param, int* value) 461{ 462 hwc_context_t* ctx = (hwc_context_t*)(dev); 463 int supported = HWC_DISPLAY_PRIMARY_BIT; 464 465 switch (param) { 466 case HWC_BACKGROUND_LAYER_SUPPORTED: 467 // Not supported for now 468 value[0] = 0; 469 break; 470 case HWC_DISPLAY_TYPES_SUPPORTED: 471 if(ctx->mMDP.hasOverlay) { 472 supported |= HWC_DISPLAY_VIRTUAL_BIT; 473 if(!qdutils::MDPVersion::getInstance().is8x26()) 474 supported |= HWC_DISPLAY_EXTERNAL_BIT; 475 } 476 value[0] = supported; 477 break; 478 case HWC_FORMAT_RB_SWAP: 479 value[0] = 1; 480 break; 481 case HWC_COLOR_FILL: 482 value[0] = 1; 483 break; 484 default: 485 return -EINVAL; 486 } 487 return 0; 488 489} 490 491 492static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) { 493 ATRACE_CALL(); 494 int ret = 0; 495 const int dpy = HWC_DISPLAY_PRIMARY; 496 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive) { 497 uint32_t last = list->numHwLayers - 1; 498 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 499 int fd = -1; //FenceFD from the Copybit(valid in async mode) 500 bool copybitDone = false; 501 if(ctx->mCopyBit[dpy]) 502 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 503 if(list->numHwLayers > 1) 504 hwc_sync(ctx, list, dpy, fd); 505 506 // Dump the layers for primary 507 if(ctx->mHwcDebug[dpy]) 508 ctx->mHwcDebug[dpy]->dumpLayers(list); 509 510 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 511 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 512 ret = -1; 513 } 514 515 //TODO We dont check for SKIP flag on this layer because we need PAN 516 //always. Last layer is always FB 517 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 518 if(copybitDone && ctx->mMDP.version >= qdutils::MDP_V4_0) { 519 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 520 } 521 522 if(hnd) { 523 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 524 ALOGE("%s: FBUpdate draw failed", __FUNCTION__); 525 ret = -1; 526 } 527 } 528 529 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd, 530 ctx->listStats[dpy].roi)) { 531 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy); 532 ret = -1; 533 } 534 535 } 536 537 closeAcquireFds(list); 538 return ret; 539} 540 541static int hwc_set_external(hwc_context_t *ctx, 542 hwc_display_contents_1_t* list) 543{ 544 ATRACE_CALL(); 545 int ret = 0; 546 547 const int dpy = HWC_DISPLAY_EXTERNAL; 548 549 550 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive && 551 ctx->dpyAttr[dpy].connected && 552 !ctx->dpyAttr[dpy].isPause) { 553 uint32_t last = list->numHwLayers - 1; 554 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 555 int fd = -1; //FenceFD from the Copybit(valid in async mode) 556 bool copybitDone = false; 557 if(ctx->mCopyBit[dpy]) 558 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 559 560 if(list->numHwLayers > 1) 561 hwc_sync(ctx, list, dpy, fd); 562 563 // Dump the layers for external 564 if(ctx->mHwcDebug[dpy]) 565 ctx->mHwcDebug[dpy]->dumpLayers(list); 566 567 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 568 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 569 ret = -1; 570 } 571 572 int extOnlyLayerIndex = 573 ctx->listStats[dpy].extOnlyLayerIndex; 574 575 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 576 if(extOnlyLayerIndex!= -1) { 577 hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex]; 578 hnd = (private_handle_t *)extLayer->handle; 579 } else if(copybitDone) { 580 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 581 } 582 583 if(hnd && !isYuvBuffer(hnd)) { 584 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 585 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__); 586 ret = -1; 587 } 588 } 589 590 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { 591 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy); 592 ret = -1; 593 } 594 } 595 596 closeAcquireFds(list); 597 return ret; 598} 599 600static int hwc_set(hwc_composer_device_1 *dev, 601 size_t numDisplays, 602 hwc_display_contents_1_t** displays) 603{ 604 int ret = 0; 605 hwc_context_t* ctx = (hwc_context_t*)(dev); 606 for (uint32_t i = 0; i < numDisplays; i++) { 607 hwc_display_contents_1_t* list = displays[i]; 608 int dpy = getDpyforExternalDisplay(ctx, i); 609 switch(dpy) { 610 case HWC_DISPLAY_PRIMARY: 611 ret = hwc_set_primary(ctx, list); 612 break; 613 case HWC_DISPLAY_EXTERNAL: 614 ret = hwc_set_external(ctx, list); 615 break; 616 case HWC_DISPLAY_VIRTUAL: 617 if(ctx->mHWCVirtual) 618 ret = ctx->mHWCVirtual->set(ctx, list); 619 break; 620 default: 621 ret = -EINVAL; 622 } 623 } 624 // This is only indicative of how many times SurfaceFlinger posts 625 // frames to the display. 626 CALC_FPS(); 627 MDPComp::resetIdleFallBack(); 628 ctx->mVideoTransFlag = false; 629 if(ctx->mRotMgr->getNumActiveSessions() == 0) 630 Overlay::setDMAMode(Overlay::DMA_LINE_MODE); 631 //Was locked at the beginning of prepare 632 ctx->mDrawLock.unlock(); 633 return ret; 634} 635 636int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp, 637 uint32_t* configs, size_t* numConfigs) { 638 int ret = 0; 639 hwc_context_t* ctx = (hwc_context_t*)(dev); 640 disp = getDpyforExternalDisplay(ctx, disp); 641 //in 1.1 there is no way to choose a config, report as config id # 0 642 //This config is passed to getDisplayAttributes. Ignore for now. 643 switch(disp) { 644 case HWC_DISPLAY_PRIMARY: 645 if(*numConfigs > 0) { 646 configs[0] = 0; 647 *numConfigs = 1; 648 } 649 ret = 0; //NO_ERROR 650 break; 651 case HWC_DISPLAY_EXTERNAL: 652 case HWC_DISPLAY_VIRTUAL: 653 ret = -1; //Not connected 654 if(ctx->dpyAttr[disp].connected) { 655 ret = 0; //NO_ERROR 656 if(*numConfigs > 0) { 657 configs[0] = 0; 658 *numConfigs = 1; 659 } 660 } 661 break; 662 } 663 return ret; 664} 665 666int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp, 667 uint32_t /*config*/, const uint32_t* attributes, int32_t* values) { 668 669 hwc_context_t* ctx = (hwc_context_t*)(dev); 670 disp = getDpyforExternalDisplay(ctx, disp); 671 //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error 672 if( (disp != HWC_DISPLAY_PRIMARY) && !ctx->dpyAttr[disp].connected) { 673 return -1; 674 } 675 676 //From HWComposer 677 static const uint32_t DISPLAY_ATTRIBUTES[] = { 678 HWC_DISPLAY_VSYNC_PERIOD, 679 HWC_DISPLAY_WIDTH, 680 HWC_DISPLAY_HEIGHT, 681 HWC_DISPLAY_DPI_X, 682 HWC_DISPLAY_DPI_Y, 683 HWC_DISPLAY_NO_ATTRIBUTE, 684 }; 685 686 const int NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) / 687 sizeof(DISPLAY_ATTRIBUTES)[0]); 688 689 for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { 690 switch (attributes[i]) { 691 case HWC_DISPLAY_VSYNC_PERIOD: 692 values[i] = ctx->dpyAttr[disp].vsync_period; 693 break; 694 case HWC_DISPLAY_WIDTH: 695 values[i] = ctx->dpyAttr[disp].xres; 696 ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp, 697 ctx->dpyAttr[disp].xres); 698 break; 699 case HWC_DISPLAY_HEIGHT: 700 values[i] = ctx->dpyAttr[disp].yres; 701 ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp, 702 ctx->dpyAttr[disp].yres); 703 break; 704 case HWC_DISPLAY_DPI_X: 705 values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0); 706 break; 707 case HWC_DISPLAY_DPI_Y: 708 values[i] = (int32_t) (ctx->dpyAttr[disp].ydpi*1000.0); 709 break; 710 default: 711 ALOGE("Unknown display attribute %d", 712 attributes[i]); 713 return -EINVAL; 714 } 715 } 716 return 0; 717} 718 719void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len) 720{ 721 hwc_context_t* ctx = (hwc_context_t*)(dev); 722 Locker::Autolock _l(ctx->mDrawLock); 723 android::String8 aBuf(""); 724 dumpsys_log(aBuf, "Qualcomm HWC state:\n"); 725 dumpsys_log(aBuf, " MDPVersion=%d\n", ctx->mMDP.version); 726 dumpsys_log(aBuf, " DisplayPanel=%c\n", ctx->mMDP.panel); 727 for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) { 728 if(ctx->mMDPComp[dpy]) 729 ctx->mMDPComp[dpy]->dump(aBuf); 730 } 731 char ovDump[2048] = {'\0'}; 732 ctx->mOverlay->getDump(ovDump, 2048); 733 dumpsys_log(aBuf, ovDump); 734 ovDump[0] = '\0'; 735 ctx->mRotMgr->getDump(ovDump, 1024); 736 dumpsys_log(aBuf, ovDump); 737 ovDump[0] = '\0'; 738 if(Writeback::getDump(ovDump, 1024)) { 739 dumpsys_log(aBuf, ovDump); 740 ovDump[0] = '\0'; 741 } 742 strlcpy(buff, aBuf.string(), buff_len); 743} 744 745static int hwc_device_close(struct hw_device_t *dev) 746{ 747 if(!dev) { 748 ALOGE("%s: NULL device pointer", __FUNCTION__); 749 return -1; 750 } 751 closeContext((hwc_context_t*)dev); 752 free(dev); 753 754 return 0; 755} 756 757static int hwc_device_open(const struct hw_module_t* module, const char* name, 758 struct hw_device_t** device) 759{ 760 int status = -EINVAL; 761 762 if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { 763 struct hwc_context_t *dev; 764 dev = (hwc_context_t*)malloc(sizeof(*dev)); 765 if(dev == NULL) 766 return status; 767 memset(dev, 0, sizeof(*dev)); 768 769 //Initialize hwc context 770 initContext(dev); 771 772 //Setup HWC methods 773 dev->device.common.tag = HARDWARE_DEVICE_TAG; 774 dev->device.common.version = HWC_DEVICE_API_VERSION_1_3; 775 dev->device.common.module = const_cast<hw_module_t*>(module); 776 dev->device.common.close = hwc_device_close; 777 dev->device.prepare = hwc_prepare; 778 dev->device.set = hwc_set; 779 dev->device.eventControl = hwc_eventControl; 780 dev->device.blank = hwc_blank; 781 dev->device.query = hwc_query; 782 dev->device.registerProcs = hwc_registerProcs; 783 dev->device.dump = hwc_dump; 784 dev->device.getDisplayConfigs = hwc_getDisplayConfigs; 785 dev->device.getDisplayAttributes = hwc_getDisplayAttributes; 786 *device = &dev->device.common; 787 status = 0; 788 } 789 return status; 790} 791