1/* 2// Copyright (c) 2014 Intel Corporation 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15*/ 16#include <common/utils/HwcTrace.h> 17#include <Hwcomposer.h> 18#include <common/base/Drm.h> 19#include <PhysicalDevice.h> 20 21namespace android { 22namespace intel { 23 24PhysicalDevice::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 54PhysicalDevice::~PhysicalDevice() 55{ 56 WARN_IF_NOT_DEINIT(); 57} 58 59void 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 81bool 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 100bool 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 121bool 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 131bool 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 139bool 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 153bool 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 176template <typename T> 177static inline T min(T a, T b) { 178 return a<b ? a : b; 179} 180 181bool 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 207bool 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 264bool PhysicalDevice::compositionComplete() 265{ 266 CTRACE(); 267 // do nothing by default 268 return true; 269} 270 271void 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 282bool 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 294bool 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 392bool 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 423void 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 443bool PhysicalDevice::isConnected() const 444{ 445 RETURN_FALSE_IF_NOT_INIT(); 446 447 return mConnected; 448} 449 450const char* PhysicalDevice::getName() const 451{ 452 return mName; 453} 454 455int PhysicalDevice::getType() const 456{ 457 return mType; 458} 459 460void 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 472void 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 498bool 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 514int PhysicalDevice::getActiveConfig() 515{ 516 return mActiveDisplayConfig; 517} 518 519bool 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