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