DisplayAnalyzer.cpp revision 177b44e0661a92d06f8f37c51e59af86423f7a95
1/* 2 * Copyright © 2012 Intel Corporation 3 * All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 * 24 * Authors: 25 * Jackie Li <yaodong.li@intel.com> 26 * 27 */ 28 29#include <HwcTrace.h> 30#include <IDisplayDevice.h> 31#include <DisplayQuery.h> 32#include <BufferManager.h> 33#include <DisplayPlaneManager.h> 34#include <Hwcomposer.h> 35#include <DisplayAnalyzer.h> 36#include <cutils/properties.h> 37#include <GraphicBuffer.h> 38#include <ExternalDevice.h> 39 40namespace android { 41namespace intel { 42 43DisplayAnalyzer::DisplayAnalyzer() 44 : mInitialized(false), 45 mVideoExtModeEnabled(true), 46 mVideoExtModeEligible(false), 47 mVideoExtModeActive(false), 48 mBlankDevice(false), 49 mOverlayAllowed(true), 50 mActiveInputState(true), 51 mCachedNumDisplays(0), 52 mCachedDisplays(0), 53 mPendingEvents(), 54 mEventMutex(), 55 mEventHandledCondition() 56{ 57} 58 59DisplayAnalyzer::~DisplayAnalyzer() 60{ 61} 62 63bool DisplayAnalyzer::initialize() 64{ 65 // by default video extended mode is enabled 66 char prop[PROPERTY_VALUE_MAX]; 67 if (property_get("hwc.video.extmode.enable", prop, "1") > 0) { 68 mVideoExtModeEnabled = atoi(prop) ? true : false; 69 } 70 mVideoExtModeEligible = false; 71 mVideoExtModeActive = false; 72 mBlankDevice = false; 73 mOverlayAllowed = true; 74 mActiveInputState = true; 75 mCachedNumDisplays = 0; 76 mCachedDisplays = 0; 77 mPendingEvents.clear(); 78 mVideoStateMap.clear(); 79 mInitialized = true; 80 81 return true; 82} 83 84void DisplayAnalyzer::deinitialize() 85{ 86 mPendingEvents.clear(); 87 mVideoStateMap.clear(); 88 mInitialized = false; 89} 90 91void DisplayAnalyzer::analyzeContents( 92 size_t numDisplays, hwc_display_contents_1_t** displays) 93{ 94 // cache and use them only in this context during analysis 95 mCachedNumDisplays = numDisplays; 96 mCachedDisplays = displays; 97 98 handlePendingEvents(); 99 100 if (mVideoExtModeEnabled) { 101 handleVideoExtMode(); 102 } 103 104 if (mBlankDevice) { 105 // this will make sure device is blanked after geometry changes. 106 // blank event is only processed once 107 blankSecondaryDevice(); 108 } 109} 110 111void DisplayAnalyzer::handleVideoExtMode() 112{ 113 bool eligible = mVideoExtModeEligible; 114 checkVideoExtMode(); 115 if (eligible == mVideoExtModeEligible) { 116 if (mVideoExtModeActive) { 117 // need to mark all layers 118 setCompositionType(0, HWC_OVERLAY, false); 119 } 120 return; 121 } 122 123 if (mVideoExtModeEligible) { 124 if (mActiveInputState) { 125 VTRACE("input is active"); 126 } else { 127 enterVideoExtMode(); 128 } 129 } else { 130 exitVideoExtMode(); 131 } 132} 133 134void DisplayAnalyzer::checkVideoExtMode() 135{ 136 if (mVideoStateMap.size() != 1) { 137 mVideoExtModeEligible = false; 138 return; 139 } 140 141 bool geometryChanged = false; 142 int activeDisplays = 0; 143 144 hwc_display_contents_1_t *content = NULL; 145 for (int i = 0; i < (int)mCachedNumDisplays; i++) { 146 content = mCachedDisplays[i]; 147 if (content == NULL) { 148 continue; 149 } 150 activeDisplays++; 151 if (content->flags & HWC_GEOMETRY_CHANGED) { 152 geometryChanged = true; 153 } 154 } 155 156 if (activeDisplays <= 1) { 157 mVideoExtModeEligible = false; 158 return; 159 } 160 161 // video state update event may come later than geometry change event. 162 // in that case, video extended mode is not detected properly. 163#if 0 164 if (geometryChanged == false) { 165 // use previous analysis result 166 return; 167 } 168#endif 169 170 // reset eligibility of video extended mode 171 mVideoExtModeEligible = false; 172 173 // check if there is video layer in the primary device 174 content = mCachedDisplays[0]; 175 if (content == NULL) { 176 return; 177 } 178 179 uint32_t videoHandle = 0; 180 bool videoLayerExist = false; 181 // exclude the frame buffer target layer 182 for (int j = 0; j < (int)content->numHwLayers - 1; j++) { 183 videoLayerExist = isVideoLayer(content->hwLayers[j]); 184 if (videoLayerExist) { 185 videoHandle = (uint32_t)content->hwLayers[j].handle; 186 break; 187 } 188 } 189 190 if (videoLayerExist == false) { 191 // no video layer is found in the primary layer 192 return; 193 } 194 195 // check whether video layer exists in external device or virtual device 196 // TODO: video may exist in virtual device but no in external device or vice versa 197 // TODO: multiple video layers are not addressed here 198 for (int i = 1; i < (int)mCachedNumDisplays; i++) { 199 content = mCachedDisplays[i]; 200 if (content == NULL) { 201 continue; 202 } 203 204 // exclude the frame buffer target layer 205 for (int j = 0; j < (int)content->numHwLayers - 1; j++) { 206 if ((uint32_t)content->hwLayers[j].handle == videoHandle) { 207 VTRACE("video layer exists in device %d", i); 208 mVideoExtModeEligible = isVideoFullScreen(i, content->hwLayers[j]); 209 return; 210 } 211 } 212 } 213} 214 215bool DisplayAnalyzer::isVideoExtModeActive() 216{ 217 return mVideoExtModeActive; 218} 219 220bool DisplayAnalyzer::isVideoExtModeEnabled() 221{ 222#if 1 223 // enable it for run-time debugging purpose. 224 char prop[PROPERTY_VALUE_MAX]; 225 if (property_get("hwc.video.extmode.enable", prop, "1") > 0) { 226 mVideoExtModeEnabled = atoi(prop) ? true : false; 227 } 228 ITRACE("video extended mode enabled: %d", mVideoExtModeEnabled); 229#endif 230 231 return mVideoExtModeEnabled; 232} 233 234bool DisplayAnalyzer::isVideoLayer(hwc_layer_1_t &layer) 235{ 236 bool ret = false; 237 BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); 238 if (!layer.handle) { 239 return false; 240 } 241 DataBuffer *buffer = bm->lockDataBuffer((uint32_t)layer.handle); 242 if (!buffer) { 243 ETRACE("failed to get buffer"); 244 } else { 245 ret = DisplayQuery::isVideoFormat(buffer->getFormat()); 246 bm->unlockDataBuffer(buffer); 247 } 248 return ret; 249} 250 251bool DisplayAnalyzer::isVideoFullScreen(int device, hwc_layer_1_t &layer) 252{ 253 IDisplayDevice *displayDevice = Hwcomposer::getInstance().getDisplayDevice(device); 254 if (!displayDevice) { 255 return false; 256 } 257 int width = 0, height = 0; 258 if (!displayDevice->getDisplaySize(&width, &height)) { 259 return false; 260 } 261 262 VTRACE("video left %d, right %d, top %d, bottom %d, device width %d, height %d", 263 layer.displayFrame.left, layer.displayFrame.right, 264 layer.displayFrame.top, layer.displayFrame.bottom, 265 width, height); 266 267 int dstW = layer.displayFrame.right - layer.displayFrame.left; 268 int dstH = layer.displayFrame.bottom - layer.displayFrame.top; 269 if (dstW < width - 1 && 270 dstH < height - 1) { 271 VTRACE("video is not full-screen"); 272 return false; 273 } 274 return true; 275} 276 277bool DisplayAnalyzer::isOverlayAllowed() 278{ 279 return mOverlayAllowed; 280} 281 282int DisplayAnalyzer::getVideoInstances() 283{ 284 return (int)mVideoStateMap.size(); 285} 286 287void DisplayAnalyzer::postHotplugEvent(bool connected) 288{ 289 if (!connected) { 290 // enable vsync on the primary device immediately 291 Hwcomposer::getInstance().getVsyncManager()->enableDynamicVsync(true); 292 } 293 294 // handle hotplug event (vsync switch) asynchronously 295 Event e; 296 e.type = HOTPLUG_EVENT; 297 e.bValue = connected; 298 postEvent(e); 299 Hwcomposer::getInstance().invalidate(); 300} 301 302void DisplayAnalyzer::postVideoEvent(int instanceID, int state) 303{ 304 Event e; 305 e.type = VIDEO_EVENT; 306 e.videoEvent.instanceID = instanceID; 307 e.videoEvent.state = state; 308 postEvent(e); 309 310 if ((state == VIDEO_PLAYBACK_STARTING) || 311 (state == VIDEO_PLAYBACK_STOPPING && hasProtectedLayer())) { 312 Hwcomposer::getInstance().invalidate(); 313 Mutex::Autolock lock(mEventMutex); 314 // ideally overlay should be disabled in the surface flinger thread, if it is not processed 315 // in close to one vsync cycle (50ms) it will be safely disabled in this thread context 316 // there is no threading issue 317 status_t err = mEventHandledCondition.waitRelative(mEventMutex, milliseconds(50)); 318 if (err == -ETIMEDOUT) { 319 WTRACE("timeout waiting for event handling"); 320 Hwcomposer::getInstance().getPlaneManager()->disableOverlayPlanes(); 321 } 322 } 323} 324 325void DisplayAnalyzer::postBlankEvent(bool blank) 326{ 327 Event e; 328 e.type = BLANK_EVENT; 329 e.bValue = blank; 330 postEvent(e); 331 Hwcomposer::getInstance().invalidate(); 332} 333 334void DisplayAnalyzer::postInputEvent(bool active) 335{ 336 Event e; 337 e.type = INPUT_EVENT; 338 e.bValue = active; 339 postEvent(e); 340 Hwcomposer::getInstance().invalidate(); 341} 342 343void DisplayAnalyzer::postEvent(Event& e) 344{ 345 Mutex::Autolock lock(mEventMutex); 346 mPendingEvents.add(e); 347} 348 349bool DisplayAnalyzer::getEvent(Event& e) 350{ 351 Mutex::Autolock lock(mEventMutex); 352 if (mPendingEvents.size() == 0) { 353 return false; 354 } 355 e = mPendingEvents[0]; 356 mPendingEvents.removeAt(0); 357 return true; 358} 359 360void DisplayAnalyzer::handlePendingEvents() 361{ 362 // handle one event per analysis to avoid blocking surface flinger 363 // some event may take lengthy time to process 364 Event e; 365 if (!getEvent(e)) { 366 return; 367 } 368 369 switch (e.type) { 370 case HOTPLUG_EVENT: 371 handleHotplugEvent(e.bValue); 372 break; 373 case BLANK_EVENT: 374 handleBlankEvent(e.bValue); 375 break; 376 case VIDEO_EVENT: 377 handleVideoEvent(e.videoEvent.instanceID, e.videoEvent.state); 378 break; 379 case TIMING_EVENT: 380 handleTimingEvent(); 381 break; 382 case INPUT_EVENT: 383 handleInputEvent(e.bValue); 384 break; 385 case DPMS_EVENT: 386 handleDpmsEvent(e.nValue); 387 break; 388 } 389} 390 391void DisplayAnalyzer::handleHotplugEvent(bool connected) 392{ 393} 394 395void DisplayAnalyzer::handleBlankEvent(bool blank) 396{ 397 mBlankDevice = blank; 398 // force geometry changed in the secondary device to reset layer composition type 399 for (int i = 0; i < (int)mCachedNumDisplays; i++) { 400 if (i == IDisplayDevice::DEVICE_PRIMARY) { 401 continue; 402 } 403 if (mCachedDisplays[i]) { 404 mCachedDisplays[i]->flags |= HWC_GEOMETRY_CHANGED; 405 } 406 } 407 blankSecondaryDevice(); 408} 409 410void DisplayAnalyzer::handleTimingEvent() 411{ 412 // check whether external device is connected, reset refresh rate to match video frame rate 413 // if video is in playing state or reset refresh rate to default preferred one if video is not 414 // at playing state 415 Hwcomposer *hwc = &Hwcomposer::getInstance(); 416 ExternalDevice *dev = NULL; 417 dev = (ExternalDevice *)hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL); 418 if (!dev) { 419 return; 420 } 421 422 if (!dev->isConnected()) { 423 return; 424 } 425 426 if (hwc->getMultiDisplayObserver()->isExternalDeviceTimingFixed()) { 427 VTRACE("Timing of external device is fixed."); 428 return; 429 } 430 431 int hz = 0; 432 if (mVideoStateMap.size() == 1) { 433 VideoSourceInfo info; 434 int instanceID = mVideoStateMap.keyAt(0); 435 status_t err = hwc->getMultiDisplayObserver()->getVideoSourceInfo( 436 instanceID, &info); 437 if (err == NO_ERROR) { 438 hz = info.frameRate; 439 } 440 } 441 442 dev->setRefreshRate(hz); 443} 444 445void DisplayAnalyzer::handleVideoEvent(int instanceID, int state) 446{ 447 mVideoStateMap.removeItem(instanceID); 448 if (state != VIDEO_PLAYBACK_STOPPED) { 449 mVideoStateMap.add(instanceID, state); 450 } 451 452 Hwcomposer *hwc = &Hwcomposer::getInstance(); 453 454 // sanity check 455 if (hwc->getMultiDisplayObserver()->getVideoSessionNumber() != 456 (int)mVideoStateMap.size()) { 457 WTRACE("session number does not match!!"); 458 mVideoStateMap.clear(); 459 if (state != VIDEO_PLAYBACK_STOPPED) { 460 mVideoStateMap.add(instanceID, state); 461 } 462 } 463 464 // check if composition type needs to be reset 465 bool reset = false; 466 if ((state == VIDEO_PLAYBACK_STARTING) || 467 (state == VIDEO_PLAYBACK_STOPPING && hasProtectedLayer())) { 468 // if video is in starting or stopping stage, overlay use is temporarily not allowed to 469 // avoid scrambed RGB overlay if video is protected. 470 mOverlayAllowed = false; 471 reset = true; 472 473 // disable overlay plane and acknolwdge the waiting thread 474 hwc->getPlaneManager()->disableOverlayPlanes(); 475 mEventHandledCondition.signal(); 476 } else { 477 reset = !mOverlayAllowed; 478 mOverlayAllowed = true; 479 } 480 481 if (reset) { 482 hwc_display_contents_1_t *content = NULL; 483 for (int i = 0; i < (int)mCachedNumDisplays; i++) { 484 setCompositionType(i, HWC_FRAMEBUFFER, true); 485 } 486 } 487 488 // delay changing timing as it is a lengthy operation 489 if (state == VIDEO_PLAYBACK_STARTED || 490 state == VIDEO_PLAYBACK_STOPPED) { 491 Event e; 492 e.type = TIMING_EVENT; 493 postEvent(e); 494 } 495} 496 497void DisplayAnalyzer::blankSecondaryDevice() 498{ 499 hwc_display_contents_1_t *content = NULL; 500 hwc_layer_1 *layer = NULL; 501 for (int i = 0; i < (int)mCachedNumDisplays; i++) { 502 if (i == IDisplayDevice::DEVICE_PRIMARY) { 503 continue; 504 } 505 content = mCachedDisplays[i]; 506 if (content == NULL) { 507 continue; 508 } 509 510 for (int j = 0; j < (int)content->numHwLayers - 1; j++) { 511 layer = &content->hwLayers[j]; 512 if (!layer) { 513 continue; 514 } 515 if (mBlankDevice) { 516 layer->hints |= HWC_HINT_CLEAR_FB; 517 layer->flags &= ~HWC_SKIP_LAYER; 518 layer->compositionType = HWC_OVERLAY; 519 } else { 520 layer->hints &= ~HWC_HINT_CLEAR_FB; 521 layer->compositionType = HWC_FRAMEBUFFER; 522 } 523 } 524 } 525} 526 527void DisplayAnalyzer::handleInputEvent(bool active) 528{ 529 mActiveInputState = active; 530 if (!mVideoExtModeEligible) { 531 ITRACE("not eligible for video extended mode"); 532 return; 533 } 534 535 if (active) { 536 exitVideoExtMode(); 537 } else { 538 enterVideoExtMode(); 539 } 540} 541 542void DisplayAnalyzer::handleDpmsEvent(int delayCount) 543{ 544 if (mActiveInputState || !mVideoExtModeEligible) { 545 ITRACE("aborting display power off in video extended mode"); 546 return; 547 } 548 549 if (delayCount < DELAY_BEFORE_DPMS_OFF) { 550 Event e; 551 e.type = DPMS_EVENT; 552 e.nValue = delayCount + 1; 553 postEvent(e); 554 return; 555 } 556 557 if (Hwcomposer::getInstance().getVsyncManager()->getVsyncSource() == 558 IDisplayDevice::DEVICE_PRIMARY) { 559 ETRACE("primary display is source of vsync, it can't be powered off"); 560 return; 561 } 562 563 ITRACE("powering off primary display..."); 564 Hwcomposer::getInstance().getDrm()->setDpmsMode( 565 IDisplayDevice::DEVICE_PRIMARY, 566 IDisplayDevice::DEVICE_DISPLAY_OFF); 567} 568 569void DisplayAnalyzer::enterVideoExtMode() 570{ 571 if (mVideoExtModeActive) { 572 WTRACE("already in video extended mode."); 573 return; 574 } 575 576 ITRACE("entering video extended mode..."); 577 mVideoExtModeActive = true; 578 Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource(); 579 580 setCompositionType(0, HWC_OVERLAY, true); 581 582 // Do not power off primary display immediately as flip is asynchronous 583 Event e; 584 e.type = DPMS_EVENT; 585 e.nValue = 0; 586 postEvent(e); 587} 588 589void DisplayAnalyzer::exitVideoExtMode() 590{ 591 if (!mVideoExtModeActive) { 592 WTRACE("Not in video extended mode"); 593 return; 594 } 595 596 ITRACE("exitting video extended mode..."); 597 598 mVideoExtModeActive = false; 599 600 Hwcomposer::getInstance().getDrm()->setDpmsMode( 601 IDisplayDevice::DEVICE_PRIMARY, 602 IDisplayDevice::DEVICE_DISPLAY_ON); 603 604 Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource(); 605 606 setCompositionType(0, HWC_FRAMEBUFFER, true); 607} 608 609bool DisplayAnalyzer::isPresentationLayer(hwc_layer_1_t &layer) 610{ 611 if (layer.handle == NULL) { 612 return false; 613 } 614 if (mCachedDisplays == NULL) { 615 return false; 616 } 617 // check if the given layer exists in the primary device 618 hwc_display_contents_1_t *content = mCachedDisplays[0]; 619 if (content == NULL) { 620 return false; 621 } 622 for (size_t i = 0; i < content->numHwLayers - 1; i++) { 623 if ((uint32_t)content->hwLayers[i].handle == (uint32_t)layer.handle) { 624 VTRACE("Layer exists for Primary device"); 625 return false; 626 } 627 } 628 return true; 629} 630 631bool DisplayAnalyzer::hasProtectedLayer() 632{ 633 DataBuffer * buffer = NULL; 634 hwc_display_contents_1_t *content = NULL; 635 BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); 636 637 if (bm == NULL){ 638 return false; 639 } 640 641 if (mCachedDisplays == NULL) { 642 return false; 643 } 644 // check if the given layer exists in the primary device 645 for (int index = 0; index < (int)mCachedNumDisplays; index++) { 646 content = mCachedDisplays[index]; 647 if (content == NULL) { 648 continue; 649 } 650 651 for (size_t i = 0; i < content->numHwLayers - 1; i++) { 652 if (isProtectedLayer(content->hwLayers[i])) 653 return true; 654 } 655 } 656 657 return false; 658} 659 660bool DisplayAnalyzer::isProtectedLayer(hwc_layer_1_t &layer) 661{ 662 if (!layer.handle) { 663 return false; 664 } 665 bool ret = false; 666 BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); 667 DataBuffer *buffer = bm->lockDataBuffer((uint32_t)layer.handle); 668 if (!buffer) { 669 ETRACE("failed to get buffer"); 670 } else { 671 ret = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer); 672 bm->unlockDataBuffer(buffer); 673 } 674 return ret; 675} 676 677void DisplayAnalyzer::setCompositionType(hwc_display_contents_1_t *display, int type) 678{ 679 for (size_t i = 0; i < display->numHwLayers - 1; i++) { 680 hwc_layer_1_t *layer = &display->hwLayers[i]; 681 if (layer) layer->compositionType = type; 682 } 683} 684 685void DisplayAnalyzer::setCompositionType(int device, int type, bool reset) 686{ 687 hwc_display_contents_1_t *content = mCachedDisplays[device]; 688 if (content == NULL) { 689 ETRACE("Invalid device %d", device); 690 return; 691 } 692 693 // don't need to set geometry changed if layers are just needed to be marked 694 if (reset) { 695 content->flags |= HWC_GEOMETRY_CHANGED; 696 } 697 698 setCompositionType(content, type); 699} 700 701} // namespace intel 702} // namespace android 703 704