1 /* 2 // Copyright(c)2014 IntelCorporation 3 // 4 // LicensedundertheApacheLicense,Version2.0(the"License"); 5 // youmaynotusethisfileexceptincompliancewiththeLicense. 6 // YoumayobtainacopyoftheLicenseat 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unlessrequiredbyapplicablelaworagreedtoinwriting,software 11 // distributedundertheLicenseisdistributedonan"ASIS"BASIS, 12 // WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. 13 // SeetheLicenseforthespecificlanguagegoverningpermissionsand 14 // limitationsundertheLicense. 15 */ 16 #include <common/utils/HwcTrace.h> 17 #include <Hwcomposer.h> 18 #include <common/base/Drm.h> 19 #include <PhysicalDevice.h> 20 21 namespace android { 22 namespace intel { 23 24 PhysicalDevice::PhysicalDevice(uint32_t disp, uint32_t type, Hwcomposer& hwc, DisplayPlaneManager& dpm) 25 : mDisp(disp), 26 mType(type), 27 mHwc(hwc), 28 mDisplayPlaneManager(dpm), 29 mActiveDisplayConfig(-1), 30 mBlankControl(NULL), 31 mVsyncObserver(NULL), 32 mLayerList(NULL), 33 mConnected(false), 34 mBlank(false), 35 mDisplayState(DEVICE_DISPLAY_ON), 36 mInitialized(false) 37 { 38 CTRACE(); 39 40 switch (type) { 41 case DEVICE_PRIMARY: 42 mName = "Primary"; 43 break; 44 case DEVICE_EXTERNAL: 45 mName = "External"; 46 break; 47 default: 48 mName = "Unknown"; 49 } 50 51 mDisplayConfigs.setCapacity(DEVICE_COUNT); 52 } 53 54 PhysicalDevice::~PhysicalDevice() 55 { 56 WARN_IF_NOT_DEINIT(); 57 } 58 59 void PhysicalDevice::onGeometryChanged(hwc_display_contents_1_t *list) 60 { 61 if (!list) { 62 ELOGTRACE("list is NULL"); 63 return; 64 } 65 66 ALOGTRACE("disp = %d, layer number = %d", mDisp, list->numHwLayers); 67 68 // NOTE: should NOT be here 69 if (mLayerList) { 70 WLOGTRACE("mLayerList exists"); 71 DEINIT_AND_DELETE_OBJ(mLayerList); 72 } 73 74 // create a new layer list 75 mLayerList = new HwcLayerList(list, mType); 76 if (!mLayerList) { 77 WLOGTRACE("failed to create layer list"); 78 } 79 } 80 81 bool PhysicalDevice::prePrepare(hwc_display_contents_1_t *display) 82 { 83 RETURN_FALSE_IF_NOT_INIT(); 84 85 // for a null list, delete hwc list 86 if (!mConnected || !display || mBlank) { 87 if (mLayerList) { 88 DEINIT_AND_DELETE_OBJ(mLayerList); 89 } 90 return true; 91 } 92 93 // check if geometry is changed, if changed delete list 94 if ((display->flags & HWC_GEOMETRY_CHANGED) && mLayerList) { 95 DEINIT_AND_DELETE_OBJ(mLayerList); 96 } 97 return true; 98 } 99 100 bool PhysicalDevice::prepare(hwc_display_contents_1_t *display) 101 { 102 RETURN_FALSE_IF_NOT_INIT(); 103 104 if (!mConnected || !display || mBlank) 105 return true; 106 107 // check if geometry is changed 108 if (display->flags & HWC_GEOMETRY_CHANGED) { 109 onGeometryChanged(display); 110 } 111 if (!mLayerList) { 112 WLOGTRACE("null HWC layer list"); 113 return true; 114 } 115 116 // update list with new list 117 return mLayerList->update(display); 118 } 119 120 121 bool PhysicalDevice::commit(hwc_display_contents_1_t *display, IDisplayContext *context) 122 { 123 RETURN_FALSE_IF_NOT_INIT(); 124 125 if (!display || !context || !mLayerList || mBlank) { 126 return true; 127 } 128 129 /* Sync the arguments of Frame Buffer Target layer updated in SurfaceFlinger. */ 130 mLayerList->updateFBT(display); 131 132 return context->commitContents(display, mLayerList); 133 } 134 135 bool PhysicalDevice::vsyncControl(bool enabled) 136 { 137 RETURN_FALSE_IF_NOT_INIT(); 138 139 ALOGTRACE("disp = %d, enabled = %d", mDisp, enabled); 140 return mVsyncObserver->control(enabled); 141 } 142 143 bool PhysicalDevice::blank(bool blank) 144 { 145 RETURN_FALSE_IF_NOT_INIT(); 146 147 mBlank = blank; 148 bool ret = mBlankControl->blank(mDisp, blank); 149 if (ret == false) { 150 ELOGTRACE("failed to blank device"); 151 return false; 152 } 153 154 return true; 155 } 156 157 bool PhysicalDevice::getDisplaySize(int *width, int *height) 158 { 159 RETURN_FALSE_IF_NOT_INIT(); 160 Mutex::Autolock _l(mLock); 161 if (!width || !height) { 162 ELOGTRACE("invalid parameters"); 163 return false; 164 } 165 166 *width = 0; 167 *height = 0; 168 drmModeModeInfo mode; 169 Drm *drm = Hwcomposer::getInstance().getDrm(); 170 bool ret = drm->getModeInfo(mType, mode); 171 if (!ret) { 172 return false; 173 } 174 175 *width = mode.hdisplay; 176 *height = mode.vdisplay; 177 return true; 178 } 179 180 template <typename T> 181 static inline T min(T a, T b) { 182 return a<b ? a : b; 183 } 184 185 bool PhysicalDevice::getDisplayConfigs(uint32_t *configs, 186 size_t *numConfigs) 187 { 188 RETURN_FALSE_IF_NOT_INIT(); 189 190 Mutex::Autolock _l(mLock); 191 192 if (!mConnected) { 193 ILOGTRACE("device is not connected"); 194 return false; 195 } 196 197 if (!configs || !numConfigs || *numConfigs < 1) { 198 ELOGTRACE("invalid parameters"); 199 return false; 200 } 201 202 // fill in all config handles 203 *numConfigs = min(*numConfigs, mDisplayConfigs.size()); 204 for (int i = 0; i < static_cast<int>(*numConfigs); i++) { 205 configs[i] = i; 206 } 207 208 return true; 209 } 210 211 bool PhysicalDevice::getDisplayAttributes(uint32_t config, 212 const uint32_t *attributes, 213 int32_t *values) 214 { 215 RETURN_FALSE_IF_NOT_INIT(); 216 217 Mutex::Autolock _l(mLock); 218 219 if (!mConnected) { 220 ILOGTRACE("device is not connected"); 221 return false; 222 } 223 224 if (!attributes || !values) { 225 ELOGTRACE("invalid parameters"); 226 return false; 227 } 228 229 DisplayConfig *configChosen = mDisplayConfigs.itemAt(config); 230 if (!configChosen) { 231 WLOGTRACE("failed to get display config"); 232 return false; 233 } 234 235 int i = 0; 236 while (attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE) { 237 switch (attributes[i]) { 238 case HWC_DISPLAY_VSYNC_PERIOD: 239 if (configChosen->getRefreshRate()) { 240 values[i] = 1e9 / configChosen->getRefreshRate(); 241 } else { 242 ELOGTRACE("refresh rate is 0!!!"); 243 values[i] = 0; 244 } 245 break; 246 case HWC_DISPLAY_WIDTH: 247 values[i] = configChosen->getWidth(); 248 break; 249 case HWC_DISPLAY_HEIGHT: 250 values[i] = configChosen->getHeight(); 251 break; 252 case HWC_DISPLAY_DPI_X: 253 values[i] = configChosen->getDpiX() * 1000.0f; 254 break; 255 case HWC_DISPLAY_DPI_Y: 256 values[i] = configChosen->getDpiY() * 1000.0f; 257 break; 258 default: 259 ELOGTRACE("unknown attribute %d", attributes[i]); 260 break; 261 } 262 i++; 263 } 264 265 return true; 266 } 267 268 bool PhysicalDevice::compositionComplete() 269 { 270 CTRACE(); 271 // do nothing by default 272 return true; 273 } 274 275 void PhysicalDevice::removeDisplayConfigs() 276 { 277 for (size_t i = 0; i < mDisplayConfigs.size(); i++) { 278 DisplayConfig *config = mDisplayConfigs.itemAt(i); 279 delete config; 280 } 281 282 mDisplayConfigs.clear(); 283 mActiveDisplayConfig = -1; 284 } 285 286 bool PhysicalDevice::detectDisplayConfigs() 287 { 288 Mutex::Autolock _l(mLock); 289 290 Drm *drm = Hwcomposer::getInstance().getDrm(); 291 if (!drm->detect(mType)) { 292 ELOGTRACE("drm detection on device %d failed ", mType); 293 return false; 294 } 295 return updateDisplayConfigs(); 296 } 297 298 bool PhysicalDevice::updateDisplayConfigs() 299 { 300 bool ret; 301 Drm *drm = Hwcomposer::getInstance().getDrm(); 302 303 // reset display configs 304 removeDisplayConfigs(); 305 306 // update device connection status 307 mConnected = drm->isConnected(mType); 308 if (!mConnected) { 309 return true; 310 } 311 312 // reset the number of display configs 313 mDisplayConfigs.setCapacity(1); 314 315 drmModeModeInfo mode; 316 ret = drm->getModeInfo(mType, mode); 317 if (!ret) { 318 ELOGTRACE("failed to get mode info"); 319 mConnected = false; 320 return false; 321 } 322 323 uint32_t mmWidth, mmHeight; 324 ret = drm->getPhysicalSize(mType, mmWidth, mmHeight); 325 if (!ret) { 326 ELOGTRACE("failed to get physical size"); 327 mConnected = false; 328 return false; 329 } 330 331 float physWidthInch = (float)mmWidth * 0.039370f; 332 float physHeightInch = (float)mmHeight * 0.039370f; 333 334 // use current drm mode, likely it's preferred mode 335 int dpiX = 0; 336 int dpiY = 0; 337 if (physWidthInch && physHeightInch) { 338 dpiX = mode.hdisplay / physWidthInch; 339 dpiY = mode.vdisplay / physHeightInch; 340 } else { 341 ELOGTRACE("invalid physical size, EDID read error?"); 342 // don't bail out as it is not a fatal error 343 } 344 // use active fb dimension as config width/height 345 DisplayConfig *config = new DisplayConfig(mode.vrefresh, 346 mode.hdisplay, 347 mode.vdisplay, 348 dpiX, dpiY); 349 // add it to the front of other configs 350 mDisplayConfigs.push_front(config); 351 352 // init the active display config 353 mActiveDisplayConfig = 0; 354 355 drmModeModeInfoPtr modes; 356 drmModeModeInfoPtr compatMode; 357 int modeCount = 0; 358 359 modes = drm->detectAllConfigs(mType, &modeCount); 360 361 for (int i = 0; i < modeCount; i++) { 362 if (modes) { 363 compatMode = &modes[i]; 364 if (!compatMode) 365 continue; 366 if (compatMode->hdisplay == mode.hdisplay && 367 compatMode->vdisplay == mode.vdisplay && 368 compatMode->vrefresh != mode.vrefresh) { 369 370 bool found = false; 371 for (size_t j = 0; j < mDisplayConfigs.size(); j++) { 372 DisplayConfig *config = mDisplayConfigs.itemAt(j); 373 if (config->getRefreshRate() == (int)compatMode->vrefresh) { 374 found = true; 375 break; 376 } 377 } 378 379 if (found) { 380 continue; 381 } 382 383 DisplayConfig *config = new DisplayConfig(compatMode->vrefresh, 384 compatMode->hdisplay, 385 compatMode->vdisplay, 386 dpiX, dpiY); 387 // add it to the end of configs 388 mDisplayConfigs.push_back(config); 389 } 390 } 391 } 392 393 return true; 394 } 395 396 bool PhysicalDevice::initialize() 397 { 398 CTRACE(); 399 400 if (mType != DEVICE_PRIMARY && mType != DEVICE_EXTERNAL) { 401 ELOGTRACE("invalid device type"); 402 return false; 403 } 404 405 // detect display configs 406 bool ret = detectDisplayConfigs(); 407 if (ret == false) { 408 DEINIT_AND_RETURN_FALSE("failed to detect display config"); 409 } 410 411 // create blank control 412 mBlankControl = createBlankControl(); 413 if (!mBlankControl) { 414 DEINIT_AND_RETURN_FALSE("failed to create blank control"); 415 } 416 417 // create vsync event observer 418 mVsyncObserver = new VsyncEventObserver(*this); 419 if (!mVsyncObserver || !mVsyncObserver->initialize()) { 420 DEINIT_AND_RETURN_FALSE("failed to create vsync observer"); 421 } 422 423 mInitialized = true; 424 return true; 425 } 426 427 void PhysicalDevice::deinitialize() 428 { 429 if (mLayerList) { 430 DEINIT_AND_DELETE_OBJ(mLayerList); 431 } 432 433 DEINIT_AND_DELETE_OBJ(mVsyncObserver); 434 435 // destroy blank control 436 if (mBlankControl) { 437 delete mBlankControl; 438 mBlankControl = 0; 439 } 440 441 // remove configs 442 removeDisplayConfigs(); 443 444 mInitialized = false; 445 } 446 447 bool PhysicalDevice::isConnected() const 448 { 449 RETURN_FALSE_IF_NOT_INIT(); 450 451 return mConnected; 452 } 453 454 const char* PhysicalDevice::getName() const 455 { 456 return mName; 457 } 458 459 int PhysicalDevice::getType() const 460 { 461 return mType; 462 } 463 464 void PhysicalDevice::onVsync(int64_t timestamp) 465 { 466 RETURN_VOID_IF_NOT_INIT(); 467 ALOGTRACE("timestamp = %lld", timestamp); 468 469 if (!mConnected) 470 return; 471 472 // notify hwc 473 mHwc.vsync(mType, timestamp); 474 } 475 476 void PhysicalDevice::dump(Dump& d) 477 { 478 d.append("-------------------------------------------------------------\n"); 479 d.append("Device Name: %s (%s)\n", mName, 480 mConnected ? "connected" : "disconnected"); 481 d.append("Display configs (count = %d):\n", mDisplayConfigs.size()); 482 d.append(" CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT | DPI_X | DPI_Y \n"); 483 d.append("--------+--------------+-------+--------+-------+-------\n"); 484 for (size_t i = 0; i < mDisplayConfigs.size(); i++) { 485 DisplayConfig *config = mDisplayConfigs.itemAt(i); 486 if (config) { 487 d.append("%s %2d | %4d | %5d | %4d | %3d | %3d \n", 488 (i == (size_t)mActiveDisplayConfig) ? "* " : " ", 489 i, 490 config->getRefreshRate(), 491 config->getWidth(), 492 config->getHeight(), 493 config->getDpiX(), 494 config->getDpiY()); 495 } 496 } 497 // dump layer list 498 if (mLayerList) 499 mLayerList->dump(d); 500 } 501 502 bool PhysicalDevice::setPowerMode(int mode) 503 { 504 // TODO: set proper blanking modes for HWC 1.4 modes 505 switch (mode) { 506 case HWC_POWER_MODE_OFF: 507 case HWC_POWER_MODE_DOZE: 508 return blank(true); 509 case HWC_POWER_MODE_NORMAL: 510 case HWC_POWER_MODE_DOZE_SUSPEND: 511 return blank(false); 512 default: 513 return false; 514 } 515 return false; 516 } 517 518 int PhysicalDevice::getActiveConfig() 519 { 520 return mActiveDisplayConfig; 521 } 522 523 bool PhysicalDevice::setActiveConfig(int index) 524 { 525 // TODO: for now only implement in external 526 if (index == 0) 527 return true; 528 return false; 529 } 530 531 } // namespace intel 532 } // namespace android 533