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