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