1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * Copyright (C) 2012-2013, 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 "external.h" 37#include "hwc_copybit.h" 38#include "hwc_ad.h" 39#include "profiler.h" 40 41using namespace qhwc; 42using namespace overlay; 43 44#define VSYNC_DEBUG 0 45#define BLANK_DEBUG 1 46 47static int hwc_device_open(const struct hw_module_t* module, 48 const char* name, 49 struct hw_device_t** device); 50 51static struct hw_module_methods_t hwc_module_methods = { 52 open: hwc_device_open 53}; 54 55hwc_module_t HAL_MODULE_INFO_SYM = { 56 common: { 57 tag: HARDWARE_MODULE_TAG, 58 version_major: 2, 59 version_minor: 0, 60 id: HWC_HARDWARE_MODULE_ID, 61 name: "Qualcomm Hardware Composer Module", 62 author: "CodeAurora Forum", 63 methods: &hwc_module_methods, 64 dso: 0, 65 reserved: {0}, 66 } 67}; 68 69/* 70 * Save callback functions registered to HWC 71 */ 72static void hwc_registerProcs(struct hwc_composer_device_1* dev, 73 hwc_procs_t const* procs) 74{ 75 ALOGI("%s", __FUNCTION__); 76 hwc_context_t* ctx = (hwc_context_t*)(dev); 77 if(!ctx) { 78 ALOGE("%s: Invalid context", __FUNCTION__); 79 return; 80 } 81 ctx->proc = procs; 82 83 // Now that we have the functions needed, kick off 84 // the uevent & vsync threads 85 init_uevent_thread(ctx); 86 init_vsync_thread(ctx); 87} 88 89//Helper 90static void reset(hwc_context_t *ctx, int numDisplays, 91 hwc_display_contents_1_t** displays) { 92 for(int i = 0; i < MAX_DISPLAYS; i++) { 93 hwc_display_contents_1_t *list = displays[i]; 94 // XXX:SurfaceFlinger no longer guarantees that this 95 // value is reset on every prepare. However, for the layer 96 // cache we need to reset it. 97 // We can probably rethink that later on 98 if (LIKELY(list && list->numHwLayers > 1)) { 99 for(uint32_t j = 0; j < list->numHwLayers; j++) { 100 if(list->hwLayers[j].compositionType != HWC_FRAMEBUFFER_TARGET) 101 list->hwLayers[j].compositionType = HWC_FRAMEBUFFER; 102 } 103 } 104 105 if(ctx->mFBUpdate[i]) 106 ctx->mFBUpdate[i]->reset(); 107 if(ctx->mMDPComp[i]) 108 ctx->mMDPComp[i]->reset(); 109 if(ctx->mCopyBit[i]) 110 ctx->mCopyBit[i]->reset(); 111 if(ctx->mLayerRotMap[i]) 112 ctx->mLayerRotMap[i]->reset(); 113 } 114 115 ctx->mAD->reset(); 116} 117 118//clear prev layer prop flags and realloc for current frame 119static void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) { 120 if(ctx->layerProp[dpy]) { 121 delete[] ctx->layerProp[dpy]; 122 ctx->layerProp[dpy] = NULL; 123 } 124 ctx->layerProp[dpy] = new LayerProp[numAppLayers]; 125} 126 127static void handleGeomChange(hwc_context_t *ctx, int dpy, 128 hwc_display_contents_1_t *list) { 129 if(list->flags & HWC_GEOMETRY_CHANGED) { 130 ctx->mOverlay->forceSet(dpy); 131 } 132} 133 134static int display_commit(hwc_context_t *ctx, int dpy) { 135 int fbFd = ctx->dpyAttr[dpy].fd; 136 if(fbFd == -1) { 137 ALOGE("%s: Invalid FB fd for display: %d", __FUNCTION__, dpy); 138 return -1; 139 } 140 141 struct mdp_display_commit commit_info; 142 memset(&commit_info, 0, sizeof(struct mdp_display_commit)); 143 commit_info.flags = MDP_DISPLAY_COMMIT_OVERLAY; 144 if(ioctl(fbFd, MSMFB_DISPLAY_COMMIT, &commit_info) == -1) { 145 ALOGE("%s: MSMFB_DISPLAY_COMMIT for primary failed", __FUNCTION__); 146 return -errno; 147 } 148 return 0; 149} 150 151static int hwc_prepare_primary(hwc_composer_device_1 *dev, 152 hwc_display_contents_1_t *list) { 153 ATRACE_CALL(); 154 hwc_context_t* ctx = (hwc_context_t*)(dev); 155 const int dpy = HWC_DISPLAY_PRIMARY; 156 if (LIKELY(list && list->numHwLayers > 1) && 157 ctx->dpyAttr[dpy].isActive) { 158 reset_layer_prop(ctx, dpy, list->numHwLayers - 1); 159 handleGeomChange(ctx, dpy, list); 160 setListStats(ctx, list, dpy); 161 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) { 162 const int fbZ = 0; 163 ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ); 164 } 165 if (ctx->mMDP.version < qdutils::MDP_V4_0) { 166 if(ctx->mCopyBit[dpy]) 167 ctx->mCopyBit[dpy]->prepare(ctx, list, dpy); 168 } 169 } 170 return 0; 171} 172 173static int hwc_prepare_external(hwc_composer_device_1 *dev, 174 hwc_display_contents_1_t *list) { 175 176 ATRACE_CALL(); 177 hwc_context_t* ctx = (hwc_context_t*)(dev); 178 const int dpy = HWC_DISPLAY_EXTERNAL; 179 180 if (LIKELY(list && list->numHwLayers > 1) && 181 ctx->dpyAttr[dpy].isActive && 182 ctx->dpyAttr[dpy].connected) { 183 reset_layer_prop(ctx, dpy, list->numHwLayers - 1); 184 handleGeomChange(ctx, dpy, list); 185 if(!ctx->dpyAttr[dpy].isPause) { 186 ctx->dpyAttr[dpy].isConfiguring = false; 187 setListStats(ctx, list, dpy); 188 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) { 189 const int fbZ = 0; 190 ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ); 191 } 192 193 /* Temporarily commenting out C2D until we support partial 194 copybit composition for mixed mode MDP 195 196 if((fbZOrder >= 0) && ctx->mCopyBit[dpy]) 197 ctx->mCopyBit[dpy]->prepare(ctx, list, dpy); 198 */ 199 } else { 200 // External Display is in Pause state. 201 // ToDo: 202 // Mark all application layers as OVERLAY so that 203 // GPU will not compose. This is done for power 204 // optimization 205 } 206 } 207 return 0; 208} 209 210static int hwc_prepare_virtual(hwc_composer_device_1 *dev, 211 hwc_display_contents_1_t *list) { 212 ATRACE_CALL(); 213 hwc_context_t* ctx = (hwc_context_t*)(dev); 214 const int dpy = HWC_DISPLAY_VIRTUAL; 215 216 if (list && list->outbuf && list->numHwLayers > 0) { 217 reset_layer_prop(ctx, dpy, list->numHwLayers - 1); 218 uint32_t last = list->numHwLayers - 1; 219 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 220 int fbWidth = 0, fbHeight = 0; 221 getLayerResolution(fbLayer, fbWidth, fbHeight); 222 ctx->dpyAttr[dpy].xres = fbWidth; 223 ctx->dpyAttr[dpy].yres = fbHeight; 224 225 if(ctx->dpyAttr[dpy].connected == false) { 226 ctx->dpyAttr[dpy].connected = true; 227 setupSecondaryObjs(ctx, dpy); 228 } 229 230 ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd(); 231 private_handle_t *ohnd = (private_handle_t *)list->outbuf; 232 Writeback::getInstance()->configureDpyInfo(ohnd->width, ohnd->height); 233 setListStats(ctx, list, dpy); 234 235 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) { 236 const int fbZ = 0; 237 ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ); 238 } 239 } 240 return 0; 241} 242 243static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays, 244 hwc_display_contents_1_t** displays) 245{ 246 int ret = 0; 247 hwc_context_t* ctx = (hwc_context_t*)(dev); 248 //Will be unlocked at the end of set 249 ctx->mDrawLock.lock(); 250 reset(ctx, numDisplays, displays); 251 252 ctx->mOverlay->configBegin(); 253 ctx->mRotMgr->configBegin(); 254 overlay::Writeback::configBegin(); 255 256 Overlay::setDMAMode(Overlay::DMA_LINE_MODE); 257 258 //Cleanup virtual display objs, since there is no explicit disconnect 259 if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected && 260 (numDisplays <= HWC_NUM_PHYSICAL_DISPLAY_TYPES || 261 displays[HWC_DISPLAY_VIRTUAL] == NULL)) { 262 ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false; 263 clearSecondaryObjs(ctx, HWC_DISPLAY_VIRTUAL); 264 } 265 266 for (int32_t i = numDisplays - 1; i >= 0; i--) { 267 hwc_display_contents_1_t *list = displays[i]; 268 switch(i) { 269 case HWC_DISPLAY_PRIMARY: 270 ret = hwc_prepare_primary(dev, list); 271 break; 272 case HWC_DISPLAY_EXTERNAL: 273 ret = hwc_prepare_external(dev, list); 274 break; 275 case HWC_DISPLAY_VIRTUAL: 276 ret = hwc_prepare_virtual(dev, list); 277 break; 278 default: 279 ret = -EINVAL; 280 } 281 } 282 283 ctx->mOverlay->configDone(); 284 ctx->mRotMgr->configDone(); 285 overlay::Writeback::configDone(); 286 287 return ret; 288} 289 290static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy, 291 int event, int enable) 292{ 293 ATRACE_CALL(); 294 int ret = 0; 295 hwc_context_t* ctx = (hwc_context_t*)(dev); 296 switch(event) { 297 case HWC_EVENT_VSYNC: 298 if(!ctx->dpyAttr[dpy].isActive) { 299 ALOGE("Display is blanked - Cannot %s vsync", 300 enable ? "enable" : "disable"); 301 return -EINVAL; 302 } 303 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 default: 313 ret = -EINVAL; 314 } 315 return ret; 316} 317 318static int hwc_blank(struct hwc_composer_device_1* dev, int dpy, int blank) 319{ 320 ATRACE_CALL(); 321 hwc_context_t* ctx = (hwc_context_t*)(dev); 322 323 Locker::Autolock _l(ctx->mDrawLock); 324 int ret = 0; 325 ALOGD_IF(BLANK_DEBUG, "%s: %s display: %d", __FUNCTION__, 326 blank==1 ? "Blanking":"Unblanking", dpy); 327 if (blank || (dpy == HWC_DISPLAY_PRIMARY && 328 !ctx->dpyAttr[dpy].isActive )) { 329 // free up all the overlay pipes in use 330 // when we get a blank for either display 331 // makes sure that all pipes are freed 332 ctx->mOverlay->configBegin(); 333 ctx->mOverlay->configDone(); 334 ctx->mRotMgr->clear(); 335 overlay::Writeback::clear(); 336 } 337 switch(dpy) { 338 case HWC_DISPLAY_PRIMARY: 339 if(blank) { 340 ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, 341 FB_BLANK_POWERDOWN); 342 } else { 343 ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK,FB_BLANK_UNBLANK); 344 } 345 break; 346 case HWC_DISPLAY_EXTERNAL: 347 case HWC_DISPLAY_VIRTUAL: 348 if(blank) { 349 // call external framebuffer commit on blank, 350 // so that any pipe unsets gets committed 351 if (display_commit(ctx, dpy) < 0) { 352 ret = -1; 353 ALOGE("%s:post failed for dpy %d", 354 __FUNCTION__, dpy); 355 } 356 } else { 357 } 358 break; 359 default: 360 return -EINVAL; 361 } 362 if(ret == 0){ 363 ctx->dpyAttr[dpy].isActive = !blank; 364 } else { 365 ALOGE("%s: Failed in %s display: %d error:%s", __FUNCTION__, 366 blank==1 ? "blanking":"unblanking", dpy, strerror(errno)); 367 return ret; 368 } 369 370 ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__, 371 blank==1 ? "blanking":"unblanking", dpy); 372 return 0; 373} 374 375static int hwc_query(struct hwc_composer_device_1* dev, 376 int param, int* value) 377{ 378 hwc_context_t* ctx = (hwc_context_t*)(dev); 379 int supported = HWC_DISPLAY_PRIMARY_BIT; 380 381 switch (param) { 382 case HWC_BACKGROUND_LAYER_SUPPORTED: 383 // Not supported for now 384 value[0] = 0; 385 break; 386 case HWC_DISPLAY_TYPES_SUPPORTED: //Unused by f/w 387 if(ctx->mMDP.hasOverlay) { 388 supported |= HWC_DISPLAY_VIRTUAL_BIT; 389 if(!qdutils::MDPVersion::getInstance().is8x26()) 390 supported |= HWC_DISPLAY_EXTERNAL_BIT; 391 } 392 value[0] = supported; 393 break; 394 default: 395 return -EINVAL; 396 } 397 return 0; 398 399} 400 401 402static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) { 403 ATRACE_CALL(); 404 int ret = 0; 405 const int dpy = HWC_DISPLAY_PRIMARY; 406 407 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive) { 408 uint32_t last = list->numHwLayers - 1; 409 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 410 int fd = -1; //FenceFD from the Copybit(valid in async mode) 411 bool copybitDone = false; 412 if(ctx->mCopyBit[dpy]) 413 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 414 if(list->numHwLayers > 1) 415 hwc_sync(ctx, list, dpy, fd); 416 417 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 418 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 419 ret = -1; 420 } 421 422 //TODO We dont check for SKIP flag on this layer because we need PAN 423 //always. Last layer is always FB 424 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 425 if(copybitDone) { 426 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 427 } 428 429 if(hnd) { 430 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 431 ALOGE("%s: FBUpdate draw failed", __FUNCTION__); 432 ret = -1; 433 } 434 } 435 436 if (display_commit(ctx, dpy) < 0) { 437 ALOGE("%s: display commit fail!", __FUNCTION__); 438 ret = -1; 439 } 440 } 441 442 closeAcquireFds(list, dpy); 443 return ret; 444} 445 446static int hwc_set_external(hwc_context_t *ctx, 447 hwc_display_contents_1_t* list) 448{ 449 ATRACE_CALL(); 450 int ret = 0; 451 const int dpy = HWC_DISPLAY_EXTERNAL; 452 453 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive && 454 !ctx->dpyAttr[dpy].isPause && 455 ctx->dpyAttr[dpy].connected) { 456 uint32_t last = list->numHwLayers - 1; 457 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 458 int fd = -1; //FenceFD from the Copybit(valid in async mode) 459 bool copybitDone = false; 460 if(ctx->mCopyBit[dpy]) 461 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 462 463 if(list->numHwLayers > 1) 464 hwc_sync(ctx, list, dpy, fd); 465 466 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 467 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 468 ret = -1; 469 } 470 471 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 472 if(copybitDone) { 473 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 474 } 475 476 if(hnd) { 477 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 478 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__); 479 ret = -1; 480 } 481 } 482 483 if (display_commit(ctx, dpy) < 0) { 484 ALOGE("%s: display commit fail!", __FUNCTION__); 485 ret = -1; 486 } 487 } 488 489 closeAcquireFds(list, dpy); 490 return ret; 491} 492 493static int hwc_set_virtual(hwc_context_t *ctx, 494 hwc_display_contents_1_t* list) { 495 ATRACE_CALL(); 496 int ret = 0; 497 const int dpy = HWC_DISPLAY_VIRTUAL; 498 499 if (list && list->outbuf && list->numHwLayers > 0) { 500 uint32_t last = list->numHwLayers - 1; 501 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 502 503 if(fbLayer->handle && ctx->dpyAttr[dpy].connected 504#ifndef FORCE_HWC_FOR_VIRTUAL_DISPLAYS 505 //XXX: If we're not forcing virtual via HWC, 506 //full GLES compositions will not be routed through here. 507 && !isGLESOnlyComp(ctx, dpy) 508#endif 509 ) { 510 511 private_handle_t *ohnd = (private_handle_t *)list->outbuf; 512 int format = ohnd->format; 513 if (format == HAL_PIXEL_FORMAT_RGBA_8888) 514 format = HAL_PIXEL_FORMAT_RGBX_8888; 515 Writeback::getInstance()->setOutputFormat( 516 utils::getMdpFormat(format)); 517 518 int fd = -1; //FenceFD from the Copybit 519 hwc_sync(ctx, list, dpy, fd); 520 521 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 522 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 523 ret = -1; 524 } 525 526 if (!ctx->mFBUpdate[dpy]->draw(ctx, 527 (private_handle_t *)fbLayer->handle)) { 528 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__); 529 ret = -1; 530 } 531 532 Writeback::getInstance()->queueBuffer(ohnd->fd, ohnd->offset); 533 if (display_commit(ctx, dpy) < 0) { 534 ALOGE("%s: display commit fail!", __FUNCTION__); 535 ret = -1; 536 } 537 } else if(list->outbufAcquireFenceFd >= 0) { 538 //If we dont handle the frame, set retireFenceFd to outbufFenceFd, 539 //which will make sure, the framework waits on it and closes it. 540 //The other way is to wait on outbufFenceFd ourselves, close it and 541 //set retireFenceFd to -1. Since we want hwc to be async, choosing 542 //the former. 543 //Also dup because, the closeAcquireFds() will close the outbufFence 544 list->retireFenceFd = dup(list->outbufAcquireFenceFd); 545 } 546 } 547 548 closeAcquireFds(list, dpy); 549 return ret; 550} 551 552 553static int hwc_set(hwc_composer_device_1 *dev, 554 size_t numDisplays, 555 hwc_display_contents_1_t** displays) 556{ 557 int ret = 0; 558 hwc_context_t* ctx = (hwc_context_t*)(dev); 559 for (uint32_t i = 0; i < numDisplays; i++) { 560 hwc_display_contents_1_t* list = displays[i]; 561 switch(i) { 562 case HWC_DISPLAY_PRIMARY: 563 ret = hwc_set_primary(ctx, list); 564 break; 565 case HWC_DISPLAY_EXTERNAL: 566 ret = hwc_set_external(ctx, list); 567 break; 568 case HWC_DISPLAY_VIRTUAL: 569 ret = hwc_set_virtual(ctx, list); 570 break; 571 default: 572 ret = -EINVAL; 573 } 574 } 575 // This is only indicative of how many times SurfaceFlinger posts 576 // frames to the display. 577 CALC_FPS(); 578 MDPComp::resetIdleFallBack(); 579 ctx->mVideoTransFlag = false; 580 //Was locked at the beginning of prepare 581 ctx->mDrawLock.unlock(); 582 return ret; 583} 584 585int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp, 586 uint32_t* configs, size_t* numConfigs) { 587 int ret = 0; 588 hwc_context_t* ctx = (hwc_context_t*)(dev); 589 //in 1.1 there is no way to choose a config, report as config id # 0 590 //This config is passed to getDisplayAttributes. Ignore for now. 591 switch(disp) { 592 case HWC_DISPLAY_PRIMARY: 593 if(*numConfigs > 0) { 594 configs[0] = 0; 595 *numConfigs = 1; 596 } 597 ret = 0; //NO_ERROR 598 break; 599 case HWC_DISPLAY_EXTERNAL: 600 ret = -1; //Not connected 601 if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected) { 602 ret = 0; //NO_ERROR 603 if(*numConfigs > 0) { 604 configs[0] = 0; 605 *numConfigs = 1; 606 } 607 } 608 break; 609 } 610 return ret; 611} 612 613int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp, 614 uint32_t config, const uint32_t* attributes, int32_t* values) { 615 616 hwc_context_t* ctx = (hwc_context_t*)(dev); 617 //If hotpluggable displays are inactive return error 618 if(disp == HWC_DISPLAY_EXTERNAL && !ctx->dpyAttr[disp].connected) { 619 return -1; 620 } 621 622 //From HWComposer 623 static const uint32_t DISPLAY_ATTRIBUTES[] = { 624 HWC_DISPLAY_VSYNC_PERIOD, 625 HWC_DISPLAY_WIDTH, 626 HWC_DISPLAY_HEIGHT, 627 HWC_DISPLAY_DPI_X, 628 HWC_DISPLAY_DPI_Y, 629 HWC_DISPLAY_NO_ATTRIBUTE, 630 }; 631 632 const int NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) / 633 sizeof(DISPLAY_ATTRIBUTES)[0]); 634 635 for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { 636 switch (attributes[i]) { 637 case HWC_DISPLAY_VSYNC_PERIOD: 638 values[i] = ctx->dpyAttr[disp].vsync_period; 639 break; 640 case HWC_DISPLAY_WIDTH: 641 values[i] = ctx->dpyAttr[disp].xres; 642 ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp, 643 ctx->dpyAttr[disp].xres); 644 break; 645 case HWC_DISPLAY_HEIGHT: 646 values[i] = ctx->dpyAttr[disp].yres; 647 ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp, 648 ctx->dpyAttr[disp].yres); 649 break; 650 case HWC_DISPLAY_DPI_X: 651 values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0); 652 break; 653 case HWC_DISPLAY_DPI_Y: 654 values[i] = (int32_t) (ctx->dpyAttr[disp].ydpi*1000.0); 655 break; 656 default: 657 ALOGE("Unknown display attribute %d", 658 attributes[i]); 659 return -EINVAL; 660 } 661 } 662 return 0; 663} 664 665void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len) 666{ 667 hwc_context_t* ctx = (hwc_context_t*)(dev); 668 Locker::Autolock _l(ctx->mDrawLock); 669 android::String8 aBuf(""); 670 dumpsys_log(aBuf, "Qualcomm HWC state:\n"); 671 dumpsys_log(aBuf, " MDPVersion=%d\n", ctx->mMDP.version); 672 dumpsys_log(aBuf, " DisplayPanel=%c\n", ctx->mMDP.panel); 673 for(int dpy = 0; dpy < MAX_DISPLAYS; dpy++) { 674 if(ctx->mMDPComp[dpy]) 675 ctx->mMDPComp[dpy]->dump(aBuf); 676 } 677 char ovDump[2048] = {'\0'}; 678 ctx->mOverlay->getDump(ovDump, 2048); 679 dumpsys_log(aBuf, ovDump); 680 ovDump[0] = '\0'; 681 ctx->mRotMgr->getDump(ovDump, 1024); 682 dumpsys_log(aBuf, ovDump); 683 ovDump[0] = '\0'; 684 if(Writeback::getDump(ovDump, 1024)) { 685 dumpsys_log(aBuf, ovDump); 686 ovDump[0] = '\0'; 687 } 688 strlcpy(buff, aBuf.string(), buff_len); 689} 690 691static int hwc_device_close(struct hw_device_t *dev) 692{ 693 if(!dev) { 694 ALOGE("%s: NULL device pointer", __FUNCTION__); 695 return -1; 696 } 697 closeContext((hwc_context_t*)dev); 698 free(dev); 699 700 return 0; 701} 702 703static int hwc_device_open(const struct hw_module_t* module, const char* name, 704 struct hw_device_t** device) 705{ 706 int status = -EINVAL; 707 708 if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { 709 struct hwc_context_t *dev; 710 dev = (hwc_context_t*)malloc(sizeof(*dev)); 711 memset(dev, 0, sizeof(*dev)); 712 713 //Initialize hwc context 714 initContext(dev); 715 716 //Setup HWC methods 717 dev->device.common.tag = HARDWARE_DEVICE_TAG; 718 dev->device.common.version = HWC_DEVICE_API_VERSION_1_3; 719 dev->device.common.module = const_cast<hw_module_t*>(module); 720 dev->device.common.close = hwc_device_close; 721 dev->device.prepare = hwc_prepare; 722 dev->device.set = hwc_set; 723 dev->device.eventControl = hwc_eventControl; 724 dev->device.blank = hwc_blank; 725 dev->device.query = hwc_query; 726 dev->device.registerProcs = hwc_registerProcs; 727 dev->device.dump = hwc_dump; 728 dev->device.getDisplayConfigs = hwc_getDisplayConfigs; 729 dev->device.getDisplayAttributes = hwc_getDisplayAttributes; 730 *device = &dev->device.common; 731 status = 0; 732 } 733 return status; 734} 735