hwc.cpp revision bef8ca47f3b15f7ae3caa871c1ed5da5508aca3f
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 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 "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 < HWC_NUM_DISPLAY_TYPES; 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->mCopyBit[i]) 108 ctx->mCopyBit[i]->reset(); 109 if(ctx->mLayerRotMap[i]) 110 ctx->mLayerRotMap[i]->reset(); 111 } 112} 113 114//clear prev layer prop flags and realloc for current frame 115static void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) { 116 if(ctx->layerProp[dpy]) { 117 delete[] ctx->layerProp[dpy]; 118 ctx->layerProp[dpy] = NULL; 119 } 120 ctx->layerProp[dpy] = new LayerProp[numAppLayers]; 121} 122 123static int display_commit(hwc_context_t *ctx, int dpy) { 124 struct mdp_display_commit commit_info; 125 memset(&commit_info, 0, sizeof(struct mdp_display_commit)); 126 commit_info.flags = MDP_DISPLAY_COMMIT_OVERLAY; 127 if(ioctl(ctx->dpyAttr[dpy].fd, MSMFB_DISPLAY_COMMIT, &commit_info) == -1) { 128 ALOGE("%s: MSMFB_DISPLAY_COMMIT for dpy %d failed", __FUNCTION__,dpy); 129 return -errno; 130 } 131 return 0; 132} 133 134static int hwc_prepare_primary(hwc_composer_device_1 *dev, 135 hwc_display_contents_1_t *list) { 136 hwc_context_t* ctx = (hwc_context_t*)(dev); 137 const int dpy = HWC_DISPLAY_PRIMARY; 138 if (LIKELY(list && list->numHwLayers > 1) && 139 ctx->dpyAttr[dpy].isActive) { 140 reset_layer_prop(ctx, dpy, list->numHwLayers - 1); 141 uint32_t last = list->numHwLayers - 1; 142 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 143 if(fbLayer->handle) { 144 setListStats(ctx, list, dpy); 145 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) { 146 const int fbZ = 0; 147 ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ); 148 } 149 if (ctx->mMDP.version < qdutils::MDP_V4_0) { 150 if(ctx->mCopyBit[dpy]) 151 ctx->mCopyBit[dpy]->prepare(ctx, list, dpy); 152 } 153 } 154 } 155 return 0; 156} 157 158static int hwc_prepare_external(hwc_composer_device_1 *dev, 159 hwc_display_contents_1_t *list, int dpy) { 160 161 hwc_context_t* ctx = (hwc_context_t*)(dev); 162 163 if (LIKELY(list && list->numHwLayers > 1) && 164 ctx->dpyAttr[dpy].isActive && 165 ctx->dpyAttr[dpy].connected) { 166 reset_layer_prop(ctx, dpy, list->numHwLayers - 1); 167 uint32_t last = list->numHwLayers - 1; 168 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 169 if(!ctx->dpyAttr[dpy].isPause) { 170 if(fbLayer->handle) { 171 ctx->mExtDispConfiguring = false; 172 setListStats(ctx, list, dpy); 173 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) { 174 const int fbZ = 0; 175 ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ); 176 } 177 178 /* Temporarily commenting out C2D until we support partial 179 copybit composition for mixed mode MDP 180 181 if((fbZOrder >= 0) && ctx->mCopyBit[dpy]) 182 ctx->mCopyBit[dpy]->prepare(ctx, list, dpy); 183 */ 184 if(ctx->listStats[dpy].isDisplayAnimating) { 185 // Mark all app layers as HWC_OVERLAY for external during 186 // animation, so that SF doesnt draw it on FB 187 for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) { 188 hwc_layer_1_t *layer = &list->hwLayers[i]; 189 layer->compositionType = HWC_OVERLAY; 190 } 191 } 192 } 193 } else { 194 // External Display is in Pause state. 195 // ToDo: 196 // Mark all application layers as OVERLAY so that 197 // GPU will not compose. This is done for power 198 // optimization 199 } 200 } 201 return 0; 202} 203 204static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays, 205 hwc_display_contents_1_t** displays) 206{ 207 int ret = 0; 208 hwc_context_t* ctx = (hwc_context_t*)(dev); 209 Locker::Autolock _bl(ctx->mBlankLock); 210 //Will be unlocked at the end of set 211 ctx->mExtLock.lock(); 212 reset(ctx, numDisplays, displays); 213 214 ctx->mOverlay->configBegin(); 215 ctx->mRotMgr->configBegin(); 216 overlay::Writeback::configBegin(); 217 218 Overlay::setDMAMode(Overlay::DMA_LINE_MODE); 219 220 for (int32_t i = numDisplays; i >= 0; i--) { 221 hwc_display_contents_1_t *list = displays[i]; 222 switch(i) { 223 case HWC_DISPLAY_PRIMARY: 224 ret = hwc_prepare_primary(dev, list); 225 break; 226 case HWC_DISPLAY_EXTERNAL: 227 case HWC_DISPLAY_VIRTUAL: 228 ret = hwc_prepare_external(dev, list, i); 229 break; 230 default: 231 ret = -EINVAL; 232 } 233 } 234 235 ctx->mOverlay->configDone(); 236 ctx->mRotMgr->configDone(); 237 overlay::Writeback::configDone(); 238 239 return ret; 240} 241 242static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy, 243 int event, int enable) 244{ 245 int ret = 0; 246 hwc_context_t* ctx = (hwc_context_t*)(dev); 247 switch(event) { 248 case HWC_EVENT_VSYNC: 249 if (ctx->vstate.enable == enable) 250 break; 251 ret = hwc_vsync_control(ctx, dpy, enable); 252 if(ret == 0) 253 ctx->vstate.enable = !!enable; 254 ALOGD_IF (VSYNC_DEBUG, "VSYNC state changed to %s", 255 (enable)?"ENABLED":"DISABLED"); 256 break; 257#ifdef QCOM_BSP 258 case HWC_EVENT_ORIENTATION: 259 if(dpy == HWC_DISPLAY_PRIMARY) { 260 Locker::Autolock _l(ctx->mBlankLock); 261 // store the primary display orientation 262 // will be used in hwc_video::configure to disable 263 // rotation animation on external display 264 ctx->deviceOrientation = enable; 265 } 266 break; 267#endif 268 default: 269 ret = -EINVAL; 270 } 271 return ret; 272} 273 274static int hwc_blank(struct hwc_composer_device_1* dev, int dpy, int blank) 275{ 276 ATRACE_CALL(); 277 hwc_context_t* ctx = (hwc_context_t*)(dev); 278 279 Locker::Autolock _l(ctx->mBlankLock); 280 int ret = 0; 281 ALOGD_IF(BLANK_DEBUG, "%s: %s display: %d", __FUNCTION__, 282 blank==1 ? "Blanking":"Unblanking", dpy); 283 if(blank) { 284 // free up all the overlay pipes in use 285 // when we get a blank for either display 286 // makes sure that all pipes are freed 287 ctx->mOverlay->configBegin(); 288 ctx->mOverlay->configDone(); 289 ctx->mRotMgr->clear(); 290 overlay::Writeback::clear(); 291 } 292 switch(dpy) { 293 case HWC_DISPLAY_PRIMARY: 294 if(blank) { 295 ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK,FB_BLANK_POWERDOWN); 296 297 if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected == true) { 298 // Surfaceflinger does not send Blank/unblank event to hwc 299 // for virtual display, handle it explicitly when blank for 300 // primary is invoked, so that any pipes unset get committed 301 if (display_commit(ctx, HWC_DISPLAY_VIRTUAL) < 0) { 302 ret = -1; 303 ALOGE("%s:post failed for virtual display !!", 304 __FUNCTION__); 305 } else { 306 ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank; 307 } 308 } 309 } else { 310 ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, FB_BLANK_UNBLANK); 311 if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected == true) { 312 ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank; 313 } 314 } 315 break; 316 case HWC_DISPLAY_EXTERNAL: 317 if(blank) { 318 // call external framebuffer commit on blank, 319 // so that any pipe unsets gets committed 320 if (display_commit(ctx, dpy) < 0) { 321 ret = -1; 322 ALOGE("%s:post failed for external display !! ", 323 __FUNCTION__); 324 } 325 } else { 326 } 327 break; 328 default: 329 return -EINVAL; 330 } 331 // Enable HPD here, as during bootup unblank is called 332 // when SF is completely initialized 333 ctx->mExtDisplay->setHPD(1); 334 if(ret == 0){ 335 ctx->dpyAttr[dpy].isActive = !blank; 336 } else { 337 ALOGE("%s: Failed in %s display: %d error:%s", __FUNCTION__, 338 blank==1 ? "blanking":"unblanking", dpy, strerror(errno)); 339 return ret; 340 } 341 342 ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__, 343 blank==1 ? "blanking":"unblanking", dpy); 344 return 0; 345} 346 347static int hwc_query(struct hwc_composer_device_1* dev, 348 int param, int* value) 349{ 350 hwc_context_t* ctx = (hwc_context_t*)(dev); 351 int supported = HWC_DISPLAY_PRIMARY_BIT; 352 353 switch (param) { 354 case HWC_BACKGROUND_LAYER_SUPPORTED: 355 // Not supported for now 356 value[0] = 0; 357 break; 358 case HWC_DISPLAY_TYPES_SUPPORTED: 359 if(ctx->mMDP.hasOverlay) 360 supported |= HWC_DISPLAY_EXTERNAL_BIT; 361 value[0] = supported; 362 break; 363 default: 364 return -EINVAL; 365 } 366 return 0; 367 368} 369 370 371static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) { 372 ATRACE_CALL(); 373 int ret = 0; 374 const int dpy = HWC_DISPLAY_PRIMARY; 375 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive) { 376 uint32_t last = list->numHwLayers - 1; 377 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 378 int fd = -1; //FenceFD from the Copybit(valid in async mode) 379 bool copybitDone = false; 380 if(ctx->mCopyBit[dpy]) 381 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 382 if(list->numHwLayers > 1) 383 hwc_sync(ctx, list, dpy, fd); 384 385 // Dump the layers for primary 386 if(ctx->mHwcDebug[dpy]) 387 ctx->mHwcDebug[dpy]->dumpLayers(list); 388 389 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 390 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 391 ret = -1; 392 } 393 394 //TODO We dont check for SKIP flag on this layer because we need PAN 395 //always. Last layer is always FB 396 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 397 if(copybitDone) { 398 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 399 } 400 401 if(hnd) { 402 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 403 ALOGE("%s: FBUpdate draw failed", __FUNCTION__); 404 ret = -1; 405 } 406 } 407 408 if (display_commit(ctx, dpy) < 0) { 409 ALOGE("%s: display commit fail!", __FUNCTION__); 410 ret = -1; 411 } 412 } 413 414 closeAcquireFds(list); 415 return ret; 416} 417 418static int hwc_set_external(hwc_context_t *ctx, 419 hwc_display_contents_1_t* list, int dpy) 420{ 421 ATRACE_CALL(); 422 int ret = 0; 423 424 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive && 425 ctx->dpyAttr[dpy].connected) { 426 427 if(!ctx->dpyAttr[dpy].isPause) { 428 uint32_t last = list->numHwLayers - 1; 429 hwc_layer_1_t *fbLayer = &list->hwLayers[last]; 430 int fd = -1; //FenceFD from the Copybit(valid in async mode) 431 bool copybitDone = false; 432 if(ctx->mCopyBit[dpy]) 433 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); 434 435 if(list->numHwLayers > 1) 436 hwc_sync(ctx, list, dpy, fd); 437 438 // Dump the layers for external 439 if(ctx->mHwcDebug[dpy]) 440 ctx->mHwcDebug[dpy]->dumpLayers(list); 441 442 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { 443 ALOGE("%s: MDPComp draw failed", __FUNCTION__); 444 ret = -1; 445 } 446 447 int extOnlyLayerIndex = 448 ctx->listStats[dpy].extOnlyLayerIndex; 449 450 private_handle_t *hnd = (private_handle_t *)fbLayer->handle; 451 if(extOnlyLayerIndex!= -1) { 452 hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex]; 453 hnd = (private_handle_t *)extLayer->handle; 454 } else if(copybitDone) { 455 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); 456 } 457 458 if(hnd && !isYuvBuffer(hnd)) { 459 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { 460 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__); 461 ret = -1; 462 } 463 } 464 } 465 466 if (display_commit(ctx, dpy) < 0) { 467 ALOGE("%s: display commit fail!", __FUNCTION__); 468 ret = -1; 469 } 470 } 471 472 closeAcquireFds(list); 473 return ret; 474} 475 476static int hwc_set(hwc_composer_device_1 *dev, 477 size_t numDisplays, 478 hwc_display_contents_1_t** displays) 479{ 480 int ret = 0; 481 hwc_context_t* ctx = (hwc_context_t*)(dev); 482 Locker::Autolock _bl(ctx->mBlankLock); 483 for (uint32_t i = 0; i <= numDisplays; i++) { 484 hwc_display_contents_1_t* list = displays[i]; 485 switch(i) { 486 case HWC_DISPLAY_PRIMARY: 487 ret = hwc_set_primary(ctx, list); 488 break; 489 case HWC_DISPLAY_EXTERNAL: 490 case HWC_DISPLAY_VIRTUAL: 491 /* ToDo: We are using hwc_set_external path for both External and 492 Virtual displays on HWC1.1. Eventually, we will have 493 separate functions when we move to HWC1.2 494 */ 495 ret = hwc_set_external(ctx, list, i); 496 break; 497 default: 498 ret = -EINVAL; 499 } 500 } 501 // This is only indicative of how many times SurfaceFlinger posts 502 // frames to the display. 503 CALC_FPS(); 504 MDPComp::resetIdleFallBack(); 505 ctx->mVideoTransFlag = false; 506 //Was locked at the beginning of prepare 507 ctx->mExtLock.unlock(); 508 return ret; 509} 510 511int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp, 512 uint32_t* configs, size_t* numConfigs) { 513 int ret = 0; 514 hwc_context_t* ctx = (hwc_context_t*)(dev); 515 //in 1.1 there is no way to choose a config, report as config id # 0 516 //This config is passed to getDisplayAttributes. Ignore for now. 517 switch(disp) { 518 case HWC_DISPLAY_PRIMARY: 519 if(*numConfigs > 0) { 520 configs[0] = 0; 521 *numConfigs = 1; 522 } 523 ret = 0; //NO_ERROR 524 break; 525 case HWC_DISPLAY_EXTERNAL: 526 case HWC_DISPLAY_VIRTUAL: 527 ret = -1; //Not connected 528 if(ctx->dpyAttr[disp].connected) { 529 ret = 0; //NO_ERROR 530 if(*numConfigs > 0) { 531 configs[0] = 0; 532 *numConfigs = 1; 533 } 534 } 535 break; 536 } 537 return ret; 538} 539 540int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp, 541 uint32_t config, const uint32_t* attributes, int32_t* values) { 542 543 hwc_context_t* ctx = (hwc_context_t*)(dev); 544 //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error 545 if( (disp >= HWC_DISPLAY_EXTERNAL) && !ctx->dpyAttr[disp].connected) { 546 return -1; 547 } 548 549 //From HWComposer 550 static const uint32_t DISPLAY_ATTRIBUTES[] = { 551 HWC_DISPLAY_VSYNC_PERIOD, 552 HWC_DISPLAY_WIDTH, 553 HWC_DISPLAY_HEIGHT, 554 HWC_DISPLAY_DPI_X, 555 HWC_DISPLAY_DPI_Y, 556 HWC_DISPLAY_NO_ATTRIBUTE, 557 }; 558 559 const int NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) / 560 sizeof(DISPLAY_ATTRIBUTES)[0]); 561 562 for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { 563 switch (attributes[i]) { 564 case HWC_DISPLAY_VSYNC_PERIOD: 565 values[i] = ctx->dpyAttr[disp].vsync_period; 566 break; 567 case HWC_DISPLAY_WIDTH: 568 values[i] = ctx->dpyAttr[disp].xres; 569 ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp, 570 ctx->dpyAttr[disp].xres); 571 break; 572 case HWC_DISPLAY_HEIGHT: 573 values[i] = ctx->dpyAttr[disp].yres; 574 ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp, 575 ctx->dpyAttr[disp].yres); 576 break; 577 case HWC_DISPLAY_DPI_X: 578 values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0); 579 break; 580 case HWC_DISPLAY_DPI_Y: 581 values[i] = (int32_t) (ctx->dpyAttr[disp].ydpi*1000.0); 582 break; 583 default: 584 ALOGE("Unknown display attribute %d", 585 attributes[i]); 586 return -EINVAL; 587 } 588 } 589 return 0; 590} 591 592void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len) 593{ 594 hwc_context_t* ctx = (hwc_context_t*)(dev); 595 android::String8 aBuf(""); 596 dumpsys_log(aBuf, "Qualcomm HWC state:\n"); 597 dumpsys_log(aBuf, " MDPVersion=%d\n", ctx->mMDP.version); 598 dumpsys_log(aBuf, " DisplayPanel=%c\n", ctx->mMDP.panel); 599 for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) { 600 if(ctx->mMDPComp[dpy]) 601 ctx->mMDPComp[dpy]->dump(aBuf); 602 } 603 char ovDump[2048] = {'\0'}; 604 ctx->mOverlay->getDump(ovDump, 2048); 605 dumpsys_log(aBuf, ovDump); 606 ovDump[0] = '\0'; 607 ctx->mRotMgr->getDump(ovDump, 1024); 608 dumpsys_log(aBuf, ovDump); 609 strlcpy(buff, aBuf.string(), buff_len); 610} 611 612static int hwc_device_close(struct hw_device_t *dev) 613{ 614 if(!dev) { 615 ALOGE("%s: NULL device pointer", __FUNCTION__); 616 return -1; 617 } 618 closeContext((hwc_context_t*)dev); 619 free(dev); 620 621 return 0; 622} 623 624static int hwc_device_open(const struct hw_module_t* module, const char* name, 625 struct hw_device_t** device) 626{ 627 int status = -EINVAL; 628 629 if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { 630 struct hwc_context_t *dev; 631 dev = (hwc_context_t*)malloc(sizeof(*dev)); 632 memset(dev, 0, sizeof(*dev)); 633 634 //Initialize hwc context 635 initContext(dev); 636 637 //Setup HWC methods 638 dev->device.common.tag = HARDWARE_DEVICE_TAG; 639 dev->device.common.version = HWC_DEVICE_API_VERSION_1_1; 640 dev->device.common.module = const_cast<hw_module_t*>(module); 641 dev->device.common.close = hwc_device_close; 642 dev->device.prepare = hwc_prepare; 643 dev->device.set = hwc_set; 644 dev->device.eventControl = hwc_eventControl; 645 dev->device.blank = hwc_blank; 646 dev->device.query = hwc_query; 647 dev->device.registerProcs = hwc_registerProcs; 648 dev->device.dump = hwc_dump; 649 dev->device.getDisplayConfigs = hwc_getDisplayConfigs; 650 dev->device.getDisplayAttributes = hwc_getDisplayAttributes; 651 *device = &dev->device.common; 652 status = 0; 653 } 654 return status; 655} 656