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