hwc.cpp revision a78cdbc396ebb7e12c21d871fcfe2f6271f1b343
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->mPanelResetStatus) 441 return; 442 443 ALOGD("%s: calling BLANK DISPLAY", __FUNCTION__); 444 ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 1); 445 if (ret < 0) { 446 ALOGE("%s: FBIOBLANK failed to BLANK: %s", __FUNCTION__, 447 strerror(errno)); 448 } 449 450 ALOGD("%s: calling UNBLANK DISPLAY and enabling vsync", __FUNCTION__); 451 ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 0); 452 if (ret < 0) { 453 ALOGE("%s: FBIOBLANK failed to UNBLANK : %s", __FUNCTION__, 454 strerror(errno)); 455 } 456 hwc_vsync_control(ctx, HWC_DISPLAY_PRIMARY, 1); 457 458 ctx->mPanelResetStatus = false; 459} 460 461 462static int hwc_query(struct hwc_composer_device_1* dev, 463 int param, int* value) 464{ 465 hwc_context_t* ctx = (hwc_context_t*)(dev); 466 int supported = HWC_DISPLAY_PRIMARY_BIT; 467 468 switch (param) { 469 case HWC_BACKGROUND_LAYER_SUPPORTED: 470 // Not supported for now 471 value[0] = 0; 472 break; 473 case HWC_DISPLAY_TYPES_SUPPORTED: 474 if(ctx->mMDP.hasOverlay) { 475 supported |= HWC_DISPLAY_VIRTUAL_BIT; 476 if(!qdutils::MDPVersion::getInstance().is8x26()) 477 supported |= HWC_DISPLAY_EXTERNAL_BIT; 478 } 479 value[0] = supported; 480 break; 481 case HWC_FORMAT_RB_SWAP: 482 value[0] = 1; 483 break; 484 case HWC_COLOR_FILL: 485 value[0] = 1; 486 break; 487 default: 488 return -EINVAL; 489 } 490 return 0; 491 492} 493 494 495static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) { 496 ATRACE_CALL(); 497 int ret = 0; 498 const int dpy = HWC_DISPLAY_PRIMARY; 499 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive) { 500 uint32_t last = list->numHwLayers - 1; 501 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 502 int fd = -1; //FenceFD from the Copybit(valid in async mode) 503 bool copybitDone = false; 504 if(ctx->mCopyBit[dpy]) 505 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 506 if(list->numHwLayers > 1) 507 hwc_sync(ctx, list, dpy, fd); 508 509 // Dump the layers for primary 510 if(ctx->mHwcDebug[dpy]) 511 ctx->mHwcDebug[dpy]->dumpLayers(list); 512 513 if (ctx->mVPUClient != NULL) { 514#ifdef VPU_TARGET 515 ctx->mVPUClient->predraw(ctx, dpy, list); 516#endif 517 } 518 else if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 519 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 520 ret = -1; 521 } 522 523 //TODO We dont check for SKIP flag on this layer because we need PAN 524 //always. Last layer is always FB 525 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 526 if(copybitDone && ctx->mMDP.version >= qdutils::MDP_V4_0) { 527 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 528 } 529 530 if(hnd) { 531 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 532 ALOGE("%s: FBUpdate draw failed", __FUNCTION__); 533 ret = -1; 534 } 535 } 536 537 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd, 538 ctx->listStats[dpy].roi)) { 539 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy); 540 ret = -1; 541 } 542 543#ifdef VPU_TARGET 544 if (ctx->mVPUClient != NULL) 545 ctx->mVPUClient->draw(ctx, dpy, list); 546#endif 547 } 548 549 closeAcquireFds(list); 550 return ret; 551} 552 553static int hwc_set_external(hwc_context_t *ctx, 554 hwc_display_contents_1_t* list) 555{ 556 ATRACE_CALL(); 557 int ret = 0; 558 559 const int dpy = HWC_DISPLAY_EXTERNAL; 560 561 562 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive && 563 ctx->dpyAttr[dpy].connected && 564 !ctx->dpyAttr[dpy].isPause) { 565 uint32_t last = list->numHwLayers - 1; 566 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 567 int fd = -1; //FenceFD from the Copybit(valid in async mode) 568 bool copybitDone = false; 569 if(ctx->mCopyBit[dpy]) 570 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 571 572 if(list->numHwLayers > 1) 573 hwc_sync(ctx, list, dpy, fd); 574 575 // Dump the layers for external 576 if(ctx->mHwcDebug[dpy]) 577 ctx->mHwcDebug[dpy]->dumpLayers(list); 578 579 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 580 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 581 ret = -1; 582 } 583 584 int extOnlyLayerIndex = 585 ctx->listStats[dpy].extOnlyLayerIndex; 586 587 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 588 if(extOnlyLayerIndex!= -1) { 589 hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex]; 590 hnd = (private_handle_t *)extLayer->handle; 591 } else if(copybitDone) { 592 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 593 } 594 595 if(hnd && !isYuvBuffer(hnd)) { 596 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 597 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__); 598 ret = -1; 599 } 600 } 601 602 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { 603 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy); 604 ret = -1; 605 } 606 } 607 608 closeAcquireFds(list); 609 return ret; 610} 611 612static int hwc_set(hwc_composer_device_1 *dev, 613 size_t numDisplays, 614 hwc_display_contents_1_t** displays) 615{ 616 int ret = 0; 617 hwc_context_t* ctx = (hwc_context_t*)(dev); 618 for (uint32_t i = 0; i < numDisplays; i++) { 619 hwc_display_contents_1_t* list = displays[i]; 620 int dpy = getDpyforExternalDisplay(ctx, i); 621 switch(dpy) { 622 case HWC_DISPLAY_PRIMARY: 623 ret = hwc_set_primary(ctx, list); 624 break; 625 case HWC_DISPLAY_EXTERNAL: 626 ret = hwc_set_external(ctx, list); 627 break; 628 case HWC_DISPLAY_VIRTUAL: 629 if(ctx->mHWCVirtual) 630 ret = ctx->mHWCVirtual->set(ctx, list); 631 break; 632 default: 633 ret = -EINVAL; 634 } 635 } 636 // This is only indicative of how many times SurfaceFlinger posts 637 // frames to the display. 638 CALC_FPS(); 639 MDPComp::resetIdleFallBack(); 640 ctx->mVideoTransFlag = false; 641 if(ctx->mRotMgr->getNumActiveSessions() == 0) 642 Overlay::setDMAMode(Overlay::DMA_LINE_MODE); 643 //Was locked at the beginning of prepare 644 ctx->mDrawLock.unlock(); 645 return ret; 646} 647 648int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp, 649 uint32_t* configs, size_t* numConfigs) { 650 int ret = 0; 651 hwc_context_t* ctx = (hwc_context_t*)(dev); 652 disp = getDpyforExternalDisplay(ctx, disp); 653 //in 1.1 there is no way to choose a config, report as config id # 0 654 //This config is passed to getDisplayAttributes. Ignore for now. 655 switch(disp) { 656 case HWC_DISPLAY_PRIMARY: 657 if(*numConfigs > 0) { 658 configs[0] = 0; 659 *numConfigs = 1; 660 } 661 ret = 0; //NO_ERROR 662 break; 663 case HWC_DISPLAY_EXTERNAL: 664 case HWC_DISPLAY_VIRTUAL: 665 ret = -1; //Not connected 666 if(ctx->dpyAttr[disp].connected) { 667 ret = 0; //NO_ERROR 668 if(*numConfigs > 0) { 669 configs[0] = 0; 670 *numConfigs = 1; 671 } 672 } 673 break; 674 } 675 return ret; 676} 677 678int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp, 679 uint32_t /*config*/, const uint32_t* attributes, int32_t* values) { 680 681 hwc_context_t* ctx = (hwc_context_t*)(dev); 682 disp = getDpyforExternalDisplay(ctx, disp); 683 //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error 684 if( (disp != HWC_DISPLAY_PRIMARY) && !ctx->dpyAttr[disp].connected) { 685 return -1; 686 } 687 688 //From HWComposer 689 static const uint32_t DISPLAY_ATTRIBUTES[] = { 690 HWC_DISPLAY_VSYNC_PERIOD, 691 HWC_DISPLAY_WIDTH, 692 HWC_DISPLAY_HEIGHT, 693 HWC_DISPLAY_DPI_X, 694 HWC_DISPLAY_DPI_Y, 695 HWC_DISPLAY_NO_ATTRIBUTE, 696 }; 697 698 const int NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) / 699 sizeof(DISPLAY_ATTRIBUTES)[0]); 700 701 for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { 702 switch (attributes[i]) { 703 case HWC_DISPLAY_VSYNC_PERIOD: 704 values[i] = ctx->dpyAttr[disp].vsync_period; 705 break; 706 case HWC_DISPLAY_WIDTH: 707 values[i] = ctx->dpyAttr[disp].xres; 708 ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp, 709 ctx->dpyAttr[disp].xres); 710 break; 711 case HWC_DISPLAY_HEIGHT: 712 values[i] = ctx->dpyAttr[disp].yres; 713 ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp, 714 ctx->dpyAttr[disp].yres); 715 break; 716 case HWC_DISPLAY_DPI_X: 717 values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0); 718 break; 719 case HWC_DISPLAY_DPI_Y: 720 values[i] = (int32_t) (ctx->dpyAttr[disp].ydpi*1000.0); 721 break; 722 default: 723 ALOGE("Unknown display attribute %d", 724 attributes[i]); 725 return -EINVAL; 726 } 727 } 728 return 0; 729} 730 731void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len) 732{ 733 hwc_context_t* ctx = (hwc_context_t*)(dev); 734 Locker::Autolock _l(ctx->mDrawLock); 735 android::String8 aBuf(""); 736 dumpsys_log(aBuf, "Qualcomm HWC state:\n"); 737 dumpsys_log(aBuf, " MDPVersion=%d\n", ctx->mMDP.version); 738 dumpsys_log(aBuf, " DisplayPanel=%c\n", ctx->mMDP.panel); 739 for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) { 740 if(ctx->mMDPComp[dpy]) 741 ctx->mMDPComp[dpy]->dump(aBuf); 742 } 743 char ovDump[2048] = {'\0'}; 744 ctx->mOverlay->getDump(ovDump, 2048); 745 dumpsys_log(aBuf, ovDump); 746 ovDump[0] = '\0'; 747 ctx->mRotMgr->getDump(ovDump, 1024); 748 dumpsys_log(aBuf, ovDump); 749 ovDump[0] = '\0'; 750 if(Writeback::getDump(ovDump, 1024)) { 751 dumpsys_log(aBuf, ovDump); 752 ovDump[0] = '\0'; 753 } 754 strlcpy(buff, aBuf.string(), buff_len); 755} 756 757static int hwc_device_close(struct hw_device_t *dev) 758{ 759 if(!dev) { 760 ALOGE("%s: NULL device pointer", __FUNCTION__); 761 return -1; 762 } 763 closeContext((hwc_context_t*)dev); 764 free(dev); 765 766 return 0; 767} 768 769static int hwc_device_open(const struct hw_module_t* module, const char* name, 770 struct hw_device_t** device) 771{ 772 int status = -EINVAL; 773 774 if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { 775 struct hwc_context_t *dev; 776 dev = (hwc_context_t*)malloc(sizeof(*dev)); 777 memset(dev, 0, sizeof(*dev)); 778 779 //Initialize hwc context 780 initContext(dev); 781 782 //Setup HWC methods 783 dev->device.common.tag = HARDWARE_DEVICE_TAG; 784 dev->device.common.version = HWC_DEVICE_API_VERSION_1_3; 785 dev->device.common.module = const_cast<hw_module_t*>(module); 786 dev->device.common.close = hwc_device_close; 787 dev->device.prepare = hwc_prepare; 788 dev->device.set = hwc_set; 789 dev->device.eventControl = hwc_eventControl; 790 dev->device.blank = hwc_blank; 791 dev->device.query = hwc_query; 792 dev->device.registerProcs = hwc_registerProcs; 793 dev->device.dump = hwc_dump; 794 dev->device.getDisplayConfigs = hwc_getDisplayConfigs; 795 dev->device.getDisplayAttributes = hwc_getDisplayAttributes; 796 *device = &dev->device.common; 797 status = 0; 798 } 799 return status; 800} 801