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