| /* |
| // Copyright (c) 2014 Intel Corporation |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| */ |
| |
| #include <HwcTrace.h> |
| #include <IDisplayDevice.h> |
| #include <DisplayQuery.h> |
| #include <BufferManager.h> |
| #include <DisplayPlaneManager.h> |
| #include <Hwcomposer.h> |
| #include <DisplayAnalyzer.h> |
| #include <cutils/properties.h> |
| #include <GraphicBuffer.h> |
| #include <ExternalDevice.h> |
| #include <VirtualDevice.h> |
| |
| namespace android { |
| namespace intel { |
| |
| DisplayAnalyzer::DisplayAnalyzer() |
| : mInitialized(false), |
| mVideoExtModeEnabled(true), |
| mVideoExtModeEligible(false), |
| mVideoExtModeActive(false), |
| mBlankDevice(false), |
| mOverlayAllowed(true), |
| mActiveInputState(true), |
| mIgnoreVideoSkipFlag(false), |
| mProtectedVideoSession(false), |
| mCachedNumDisplays(0), |
| mCachedDisplays(0), |
| mPendingEvents(), |
| mEventMutex(), |
| mEventHandledCondition() |
| { |
| } |
| |
| DisplayAnalyzer::~DisplayAnalyzer() |
| { |
| } |
| |
| bool DisplayAnalyzer::initialize() |
| { |
| // by default video extended mode is enabled |
| char prop[PROPERTY_VALUE_MAX]; |
| if (property_get("hwc.video.extmode.enable", prop, "1") > 0) { |
| mVideoExtModeEnabled = atoi(prop) ? true : false; |
| } |
| mVideoExtModeEligible = false; |
| mVideoExtModeActive = false; |
| mBlankDevice = false; |
| mOverlayAllowed = true; |
| mActiveInputState = true; |
| mIgnoreVideoSkipFlag = false; |
| mProtectedVideoSession = false; |
| mCachedNumDisplays = 0; |
| mCachedDisplays = 0; |
| mPendingEvents.clear(); |
| mVideoStateMap.clear(); |
| mInitialized = true; |
| |
| return true; |
| } |
| |
| void DisplayAnalyzer::deinitialize() |
| { |
| mPendingEvents.clear(); |
| mVideoStateMap.clear(); |
| mInitialized = false; |
| } |
| |
| void DisplayAnalyzer::analyzeContents( |
| size_t numDisplays, hwc_display_contents_1_t** displays) |
| { |
| // cache and use them only in this context during analysis |
| mCachedNumDisplays = numDisplays; |
| mCachedDisplays = displays; |
| |
| handlePendingEvents(); |
| |
| if (mVideoExtModeEnabled) { |
| handleVideoExtMode(); |
| } |
| |
| if (mBlankDevice) { |
| // this will make sure device is blanked after geometry changes. |
| // blank event is only processed once |
| blankSecondaryDevice(); |
| } |
| } |
| |
| void DisplayAnalyzer::handleVideoExtMode() |
| { |
| bool eligible = mVideoExtModeEligible; |
| checkVideoExtMode(); |
| if (eligible == mVideoExtModeEligible) { |
| if (mVideoExtModeActive) { |
| // need to mark all layers |
| setCompositionType(0, HWC_OVERLAY, false); |
| } |
| return; |
| } |
| |
| if (mVideoExtModeEligible) { |
| if (mActiveInputState) { |
| VTRACE("input is active"); |
| } else { |
| enterVideoExtMode(); |
| } |
| } else { |
| exitVideoExtMode(); |
| } |
| } |
| |
| void DisplayAnalyzer::checkVideoExtMode() |
| { |
| if (mVideoStateMap.size() != 1) { |
| mVideoExtModeEligible = false; |
| return; |
| } |
| |
| Hwcomposer *hwc = &Hwcomposer::getInstance(); |
| |
| ExternalDevice *eDev = static_cast<ExternalDevice *>(hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL)); |
| VirtualDevice *vDev = static_cast<VirtualDevice *>(hwc->getDisplayDevice(IDisplayDevice::DEVICE_VIRTUAL)); |
| |
| if ((!eDev || !eDev->isConnected()) && (!vDev || !vDev->isFrameServerActive())) { |
| mVideoExtModeEligible = false; |
| return; |
| } |
| |
| bool geometryChanged = false; |
| int activeDisplays = 0; |
| |
| hwc_display_contents_1_t *content = NULL; |
| for (int i = 0; i < (int)mCachedNumDisplays; i++) { |
| content = mCachedDisplays[i]; |
| if (content == NULL) { |
| continue; |
| } |
| activeDisplays++; |
| if (content->flags & HWC_GEOMETRY_CHANGED) { |
| geometryChanged = true; |
| } |
| } |
| |
| if (activeDisplays <= 1) { |
| mVideoExtModeEligible = false; |
| return; |
| } |
| |
| // video state update event may come later than geometry change event. |
| // in that case, video extended mode is not detected properly. |
| #if 0 |
| if (geometryChanged == false) { |
| // use previous analysis result |
| return; |
| } |
| #endif |
| // reset eligibility of video extended mode |
| mVideoExtModeEligible = false; |
| |
| // check if there is video layer in the primary device |
| content = mCachedDisplays[0]; |
| if (content == NULL) { |
| return; |
| } |
| |
| buffer_handle_t videoHandle = 0; |
| bool videoLayerExist = false; |
| bool videoFullScreenOnPrimary = false; |
| bool isVideoLayerSkipped = false; |
| |
| // exclude the frame buffer target layer |
| for (int j = 0; j < (int)content->numHwLayers - 1; j++) { |
| videoLayerExist = isVideoLayer(content->hwLayers[j]); |
| if (videoLayerExist) { |
| if ((content->hwLayers[j].flags & HWC_SKIP_LAYER)) { |
| isVideoLayerSkipped = true; |
| } |
| videoHandle = content->hwLayers[j].handle; |
| videoFullScreenOnPrimary = isVideoFullScreen(0, content->hwLayers[j]); |
| break; |
| } |
| } |
| |
| if (videoLayerExist == false) { |
| // no video layer is found in the primary layer |
| return; |
| } |
| |
| // check whether video layer exists in external device or virtual device |
| // TODO: video may exist in virtual device but no in external device or vice versa |
| // TODO: multiple video layers are not addressed here |
| for (int i = 1; i < (int)mCachedNumDisplays; i++) { |
| content = mCachedDisplays[i]; |
| if (content == NULL) { |
| continue; |
| } |
| |
| // exclude the frame buffer target layer |
| for (int j = 0; j < (int)content->numHwLayers - 1; j++) { |
| if (content->hwLayers[j].handle == videoHandle) { |
| isVideoLayerSkipped |= (content->hwLayers[j].flags & HWC_SKIP_LAYER); |
| VTRACE("video layer exists in device %d", i); |
| if (isVideoLayerSkipped || videoFullScreenOnPrimary){ |
| VTRACE("Video ext mode eligible, %d, %d", |
| isVideoLayerSkipped, videoFullScreenOnPrimary); |
| mVideoExtModeEligible = true; |
| } else { |
| mVideoExtModeEligible = isVideoFullScreen(i, content->hwLayers[j]); |
| } |
| return; |
| } |
| } |
| } |
| } |
| |
| bool DisplayAnalyzer::isVideoExtModeActive() |
| { |
| return mVideoExtModeActive; |
| } |
| |
| bool DisplayAnalyzer::isVideoExtModeEnabled() |
| { |
| #if 1 |
| // enable it for run-time debugging purpose. |
| char prop[PROPERTY_VALUE_MAX]; |
| if (property_get("hwc.video.extmode.enable", prop, "1") > 0) { |
| mVideoExtModeEnabled = atoi(prop) ? true : false; |
| } |
| ITRACE("video extended mode enabled: %d", mVideoExtModeEnabled); |
| #endif |
| |
| return mVideoExtModeEnabled; |
| } |
| |
| bool DisplayAnalyzer::isVideoLayer(hwc_layer_1_t &layer) |
| { |
| bool ret = false; |
| BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); |
| if (!layer.handle) { |
| return false; |
| } |
| DataBuffer *buffer = bm->lockDataBuffer(layer.handle); |
| if (!buffer) { |
| ETRACE("failed to get buffer"); |
| } else { |
| ret = DisplayQuery::isVideoFormat(buffer->getFormat()); |
| bm->unlockDataBuffer(buffer); |
| } |
| return ret; |
| } |
| |
| bool DisplayAnalyzer::isVideoFullScreen(int device, hwc_layer_1_t &layer) |
| { |
| IDisplayDevice *displayDevice = Hwcomposer::getInstance().getDisplayDevice(device); |
| if (!displayDevice) { |
| return false; |
| } |
| int width = 0, height = 0; |
| if (!displayDevice->getDisplaySize(&width, &height)) { |
| return false; |
| } |
| |
| VTRACE("video left %d, right %d, top %d, bottom %d, device width %d, height %d", |
| layer.displayFrame.left, layer.displayFrame.right, |
| layer.displayFrame.top, layer.displayFrame.bottom, |
| width, height); |
| |
| // full-screen defintion: |
| // width of target display frame == width of target device, with 1 pixel of tolerance, or |
| // Height of target display frame == height of target device, with 1 pixel of tolerance, or |
| // width * height of display frame > 90% of width * height of display device, or |
| // any of above condition is met on either primary display or secondary display |
| int dstW = layer.displayFrame.right - layer.displayFrame.left; |
| int dstH = layer.displayFrame.bottom - layer.displayFrame.top; |
| |
| if (abs(dstW - width) > 1 && |
| abs(dstH - height) > 1 && |
| dstW * dstH * 10 < width * height * 9) { |
| VTRACE("video is not full-screen"); |
| return false; |
| } |
| return true; |
| } |
| |
| bool DisplayAnalyzer::isOverlayAllowed() |
| { |
| return mOverlayAllowed; |
| } |
| |
| int DisplayAnalyzer::getVideoInstances() |
| { |
| return (int)mVideoStateMap.size(); |
| } |
| |
| void DisplayAnalyzer::postHotplugEvent(bool connected) |
| { |
| if (!connected) { |
| // enable vsync on the primary device immediately |
| Hwcomposer::getInstance().getVsyncManager()->enableDynamicVsync(true); |
| } |
| |
| // handle hotplug event (vsync switch) asynchronously |
| Event e; |
| e.type = HOTPLUG_EVENT; |
| e.bValue = connected; |
| postEvent(e); |
| Hwcomposer::getInstance().invalidate(); |
| } |
| |
| void DisplayAnalyzer::postVideoEvent(int instanceID, int state) |
| { |
| Event e; |
| e.type = VIDEO_EVENT; |
| e.videoEvent.instanceID = instanceID; |
| e.videoEvent.state = state; |
| postEvent(e); |
| if ((state == VIDEO_PLAYBACK_STARTING) || |
| (state == VIDEO_PLAYBACK_STOPPING && mProtectedVideoSession)) { |
| Hwcomposer::getInstance().invalidate(); |
| mOverlayAllowed = false; |
| hwc_display_contents_1_t *content = NULL; |
| for (int i = 0; i < (int)mCachedNumDisplays; i++) { |
| setCompositionType(i, HWC_FRAMEBUFFER, true); |
| } |
| // wait for up to 100ms until overlay is disabled. |
| int loop = 0; |
| while (loop++ < 6) { |
| if (Hwcomposer::getInstance().getPlaneManager()->isOverlayPlanesDisabled()) |
| break; |
| usleep(16700); |
| } |
| if (loop >= 6) { |
| WTRACE("timeout disabling overlay "); |
| } |
| } |
| } |
| |
| void DisplayAnalyzer::postBlankEvent(bool blank) |
| { |
| Event e; |
| e.type = BLANK_EVENT; |
| e.bValue = blank; |
| postEvent(e); |
| Hwcomposer::getInstance().invalidate(); |
| } |
| |
| void DisplayAnalyzer::postInputEvent(bool active) |
| { |
| Event e; |
| e.type = INPUT_EVENT; |
| e.bValue = active; |
| postEvent(e); |
| Hwcomposer::getInstance().invalidate(); |
| } |
| |
| void DisplayAnalyzer::postIdleEntryEvent(void) |
| { |
| Event e; |
| e.type = IDLE_ENTRY_EVENT; |
| e.nValue = 0; |
| postEvent(e); |
| } |
| |
| void DisplayAnalyzer::postEvent(Event& e) |
| { |
| Mutex::Autolock lock(mEventMutex); |
| mPendingEvents.add(e); |
| } |
| |
| bool DisplayAnalyzer::getEvent(Event& e) |
| { |
| Mutex::Autolock lock(mEventMutex); |
| if (mPendingEvents.size() == 0) { |
| return false; |
| } |
| e = mPendingEvents[0]; |
| mPendingEvents.removeAt(0); |
| return true; |
| } |
| |
| void DisplayAnalyzer::handlePendingEvents() |
| { |
| // handle one event per analysis to avoid blocking surface flinger |
| // some event may take lengthy time to process |
| Event e; |
| if (!getEvent(e)) { |
| return; |
| } |
| |
| switch (e.type) { |
| case HOTPLUG_EVENT: |
| handleHotplugEvent(e.bValue); |
| break; |
| case BLANK_EVENT: |
| handleBlankEvent(e.bValue); |
| break; |
| case VIDEO_EVENT: |
| handleVideoEvent(e.videoEvent.instanceID, e.videoEvent.state); |
| break; |
| case TIMING_EVENT: |
| handleTimingEvent(); |
| break; |
| case INPUT_EVENT: |
| handleInputEvent(e.bValue); |
| break; |
| case DPMS_EVENT: |
| handleDpmsEvent(e.nValue); |
| break; |
| case IDLE_ENTRY_EVENT: |
| handleIdleEntryEvent(e.nValue); |
| break; |
| case IDLE_EXIT_EVENT: |
| handleIdleExitEvent(); |
| break; |
| case VIDEO_CHECK_EVENT: |
| handleVideoCheckEvent(); |
| break; |
| } |
| } |
| |
| void DisplayAnalyzer::handleHotplugEvent(bool connected) |
| { |
| Hwcomposer *hwc = &Hwcomposer::getInstance(); |
| if (connected) { |
| if (mVideoStateMap.size() == 1) { |
| // Some video apps wouldn't update video state again when plugin HDMI |
| // and fail to reset refresh rate |
| ExternalDevice *dev = NULL; |
| dev = (ExternalDevice *)hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL); |
| if (!dev || !dev->isConnected()) { |
| ITRACE("External device isn't connected"); |
| return; |
| } |
| if (hwc->getMultiDisplayObserver()->isExternalDeviceTimingFixed()) { |
| VTRACE("Timing of external device is fixed."); |
| return; |
| } |
| VideoSourceInfo info; |
| int instanceID = mVideoStateMap.keyAt(0); |
| status_t err = hwc->getMultiDisplayObserver()->getVideoSourceInfo( |
| instanceID, &info); |
| if (err == NO_ERROR) { |
| int hz = dev->getRefreshRate(); |
| if (hz > 0 && info.frameRate > 0 && hz != info.frameRate) { |
| ITRACE("Old Hz %d, new one %d", hz, info.frameRate); |
| dev->setRefreshRate(info.frameRate); |
| } else |
| WTRACE("Old Hz %d is invalid, %d", hz, info.frameRate); |
| } |
| } |
| } else { |
| if (mVideoStateMap.size() == 1) { |
| // Reset input state if HDMI is plug out to |
| // avoid entering extended mode immediately after HDMI is plug in |
| mActiveInputState = true; |
| } |
| } |
| } |
| |
| void DisplayAnalyzer::handleBlankEvent(bool blank) |
| { |
| mBlankDevice = blank; |
| // force geometry changed in the secondary device to reset layer composition type |
| for (int i = 0; i < (int)mCachedNumDisplays; i++) { |
| if (i == IDisplayDevice::DEVICE_PRIMARY) { |
| continue; |
| } |
| if (mCachedDisplays[i]) { |
| mCachedDisplays[i]->flags |= HWC_GEOMETRY_CHANGED; |
| } |
| } |
| blankSecondaryDevice(); |
| } |
| |
| void DisplayAnalyzer::handleTimingEvent() |
| { |
| // check whether external device is connected, reset refresh rate to match video frame rate |
| // if video is in playing state or reset refresh rate to default preferred one if video is not |
| // at playing state |
| Hwcomposer *hwc = &Hwcomposer::getInstance(); |
| ExternalDevice *dev = NULL; |
| dev = (ExternalDevice *)hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL); |
| if (!dev) { |
| return; |
| } |
| |
| if (!dev->isConnected()) { |
| return; |
| } |
| |
| if (hwc->getMultiDisplayObserver()->isExternalDeviceTimingFixed()) { |
| VTRACE("Timing of external device is fixed."); |
| return; |
| } |
| |
| int hz = 0; |
| if (mVideoStateMap.size() == 1) { |
| VideoSourceInfo info; |
| int instanceID = mVideoStateMap.keyAt(0); |
| status_t err = hwc->getMultiDisplayObserver()->getVideoSourceInfo( |
| instanceID, &info); |
| if (err == NO_ERROR) { |
| hz = info.frameRate; |
| } |
| } |
| |
| dev->setRefreshRate(hz); |
| } |
| |
| void DisplayAnalyzer::handleVideoEvent(int instanceID, int state) |
| { |
| mVideoStateMap.removeItem(instanceID); |
| if (state != VIDEO_PLAYBACK_STOPPED) { |
| mVideoStateMap.add(instanceID, state); |
| } |
| |
| Hwcomposer *hwc = &Hwcomposer::getInstance(); |
| |
| // sanity check |
| if (hwc->getMultiDisplayObserver()->getVideoSessionNumber() != |
| (int)mVideoStateMap.size()) { |
| WTRACE("session number does not match!!"); |
| mVideoStateMap.clear(); |
| if (state != VIDEO_PLAYBACK_STOPPED) { |
| mVideoStateMap.add(instanceID, state); |
| } |
| } |
| |
| // check if composition type needs to be reset |
| bool reset = false; |
| if ((state == VIDEO_PLAYBACK_STARTING) || |
| (state == VIDEO_PLAYBACK_STOPPING && mProtectedVideoSession)) { |
| // if video is in starting or stopping stage, overlay use is temporarily not allowed to |
| // avoid scrambed RGB overlay if video is protected. |
| mOverlayAllowed = false; |
| reset = true; |
| } else { |
| reset = !mOverlayAllowed; |
| mOverlayAllowed = true; |
| } |
| |
| if (reset) { |
| hwc_display_contents_1_t *content = NULL; |
| for (int i = 0; i < (int)mCachedNumDisplays; i++) { |
| setCompositionType(i, HWC_FRAMEBUFFER, true); |
| } |
| } |
| |
| if (mVideoStateMap.size() == 0) { |
| // reset active input state after video playback stops. |
| // MDS should update input state in 5 seconds after video playback starts |
| mActiveInputState = true; |
| } |
| |
| mProtectedVideoSession = false; |
| if (state == VIDEO_PLAYBACK_STARTED) { |
| VideoSourceInfo info; |
| hwc->getMultiDisplayObserver()->getVideoSourceInfo( |
| getFirstVideoInstanceSessionID(), &info); |
| mProtectedVideoSession = info.isProtected; |
| } |
| // Setting timing immediately, |
| // Don't posthone to next circle |
| handleTimingEvent(); |
| |
| handleVideoCheckEvent(); |
| } |
| |
| void DisplayAnalyzer::blankSecondaryDevice() |
| { |
| hwc_display_contents_1_t *content = NULL; |
| hwc_layer_1 *layer = NULL; |
| for (int i = 0; i < (int)mCachedNumDisplays; i++) { |
| if (i == IDisplayDevice::DEVICE_PRIMARY) { |
| continue; |
| } |
| content = mCachedDisplays[i]; |
| if (content == NULL) { |
| continue; |
| } |
| |
| for (int j = 0; j < (int)content->numHwLayers - 1; j++) { |
| layer = &content->hwLayers[j]; |
| if (!layer) { |
| continue; |
| } |
| if (mBlankDevice) { |
| layer->hints |= HWC_HINT_CLEAR_FB; |
| layer->flags &= ~HWC_SKIP_LAYER; |
| layer->compositionType = HWC_OVERLAY; |
| } else { |
| layer->hints &= ~HWC_HINT_CLEAR_FB; |
| layer->compositionType = HWC_FRAMEBUFFER; |
| } |
| } |
| } |
| } |
| |
| void DisplayAnalyzer::handleInputEvent(bool active) |
| { |
| if (active == mActiveInputState) { |
| WTRACE("same input state: %d", active); |
| } |
| mActiveInputState = active; |
| if (!mVideoExtModeEligible) { |
| ITRACE("not eligible for video extended mode"); |
| return; |
| } |
| |
| if (active) { |
| exitVideoExtMode(); |
| } else { |
| enterVideoExtMode(); |
| } |
| } |
| |
| void DisplayAnalyzer::handleDpmsEvent(int delayCount) |
| { |
| if (mActiveInputState || !mVideoExtModeEligible) { |
| ITRACE("aborting display power off in video extended mode"); |
| return; |
| } |
| |
| if (delayCount < DELAY_BEFORE_DPMS_OFF) { |
| Event e; |
| e.type = DPMS_EVENT; |
| e.nValue = delayCount + 1; |
| postEvent(e); |
| Hwcomposer::getInstance().invalidate(); |
| return; |
| } |
| |
| if (Hwcomposer::getInstance().getVsyncManager()->getVsyncSource() == |
| IDisplayDevice::DEVICE_PRIMARY) { |
| Hwcomposer::getInstance().getDrm()->setDpmsMode( |
| IDisplayDevice::DEVICE_PRIMARY, |
| IDisplayDevice::DEVICE_DISPLAY_STANDBY); |
| ETRACE("primary display is source of vsync, we only dim backlight"); |
| return; |
| } |
| |
| // panel can't be powered off as touch panel shares the power supply with LCD. |
| DTRACE("primary display coupled with touch on Saltbay, only dim backlight"); |
| Hwcomposer::getInstance().getDrm()->setDpmsMode( |
| IDisplayDevice::DEVICE_PRIMARY, |
| IDisplayDevice::DEVICE_DISPLAY_STANDBY); |
| //IDisplayDevice::DEVICE_DISPLAY_OFF); |
| return; |
| } |
| |
| |
| void DisplayAnalyzer::handleIdleEntryEvent(int count) |
| { |
| DTRACE("handling idle entry event, count %d", count); |
| if (hasProtectedLayer()) { |
| ITRACE("Ignoring idle entry as protected layer exists."); |
| setCompositionType(0, HWC_FRAMEBUFFER, true); |
| return; |
| } |
| |
| // stop idle entry if external device is connected |
| if (mCachedDisplays && mCachedDisplays[IDisplayDevice::DEVICE_EXTERNAL]) { |
| ITRACE("Ignoring idle entry as external device is connected."); |
| setCompositionType(0, HWC_FRAMEBUFFER, true); |
| return; |
| } |
| |
| // stop idle entry if video playback is active |
| // TODO: remove this check for Annidale |
| if (mVideoStateMap.size() > 0) { |
| ITRACE("Ignoring idle entry as video session is active."); |
| setCompositionType(0, HWC_FRAMEBUFFER, true); |
| return; |
| } |
| |
| setCompositionType(0, HWC_FORCE_FRAMEBUFFER, true); |
| |
| // next prepare/set will exit idle state. |
| Event e; |
| e.type = IDLE_EXIT_EVENT; |
| postEvent(e); |
| } |
| |
| void DisplayAnalyzer::handleIdleExitEvent() |
| { |
| DTRACE("handling idle exit event"); |
| |
| setCompositionType(0, HWC_FRAMEBUFFER, true); |
| } |
| |
| void DisplayAnalyzer::handleVideoCheckEvent() |
| { |
| // check if the first seen video layer on secondary device (HDMI/WFD) is marked as skipped |
| // it is assumed video is always skipped if the first seen video layer is skipped |
| // this is to workaround secure video layer transmitted over non secure output |
| // and HWC_SKIP_LAYER set during rotation animation. |
| mIgnoreVideoSkipFlag = false; |
| |
| if (mVideoStateMap.size() != 1 || |
| mCachedNumDisplays <= 1) { |
| return; |
| } |
| |
| intptr_t videoHandles[mCachedNumDisplays]; |
| for (int i = 0; i < (int)mCachedNumDisplays; i++) { |
| videoHandles[i] = 0; |
| hwc_display_contents_1_t *content = mCachedDisplays[i]; |
| if (content == NULL) { |
| continue; |
| } |
| for (int j = 0; j < (int)content->numHwLayers - 1; j++) { |
| if (isVideoLayer(content->hwLayers[j])) { |
| videoHandles[i] = (intptr_t)content->hwLayers[j].handle; |
| if (i > 0) { |
| mIgnoreVideoSkipFlag = !(content->hwLayers[j].flags & HWC_SKIP_LAYER); |
| ITRACE("Ignoring video HWC_SKIP_LAYER: %d on output %d", mIgnoreVideoSkipFlag, i); |
| return; |
| } |
| break; |
| } |
| } |
| } |
| |
| if (videoHandles[0]) { |
| WTRACE("Video is on the primary panel only"); |
| return; |
| } |
| |
| // video state map indicates video session is active and there is secondary |
| // display, need to continue checking as video is not found in the buffers yet |
| Event e; |
| e.type = VIDEO_CHECK_EVENT; |
| postEvent(e); |
| } |
| |
| void DisplayAnalyzer::enterVideoExtMode() |
| { |
| if (mVideoExtModeActive) { |
| WTRACE("already in video extended mode."); |
| return; |
| } |
| |
| ITRACE("entering video extended mode..."); |
| mVideoExtModeActive = true; |
| Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource(); |
| |
| setCompositionType(0, HWC_OVERLAY, true); |
| |
| // Do not power off primary display immediately as flip is asynchronous |
| Event e; |
| e.type = DPMS_EVENT; |
| e.nValue = 0; |
| postEvent(e); |
| Hwcomposer::getInstance().invalidate(); |
| } |
| |
| void DisplayAnalyzer::exitVideoExtMode() |
| { |
| if (!mVideoExtModeActive) { |
| WTRACE("Not in video extended mode"); |
| return; |
| } |
| |
| ITRACE("exiting video extended mode..."); |
| |
| mVideoExtModeActive = false; |
| |
| Hwcomposer::getInstance().getDrm()->setDpmsMode( |
| IDisplayDevice::DEVICE_PRIMARY, |
| IDisplayDevice::DEVICE_DISPLAY_ON); |
| |
| Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource(); |
| |
| setCompositionType(0, HWC_FRAMEBUFFER, true); |
| } |
| |
| bool DisplayAnalyzer::isPresentationLayer(hwc_layer_1_t &layer) |
| { |
| if (layer.handle == NULL) { |
| return false; |
| } |
| if (mCachedDisplays == NULL) { |
| return false; |
| } |
| // check if the given layer exists in the primary device |
| hwc_display_contents_1_t *content = mCachedDisplays[0]; |
| if (content == NULL) { |
| return false; |
| } |
| for (size_t i = 0; i < content->numHwLayers - 1; i++) { |
| if (content->hwLayers[i].handle == layer.handle) { |
| VTRACE("Layer exists for Primary device"); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool DisplayAnalyzer::hasProtectedLayer() |
| { |
| DataBuffer * buffer = NULL; |
| hwc_display_contents_1_t *content = NULL; |
| BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); |
| |
| if (bm == NULL){ |
| return false; |
| } |
| |
| if (mCachedDisplays == NULL) { |
| return false; |
| } |
| // check if the given layer exists in the primary device |
| for (int index = 0; index < (int)mCachedNumDisplays; index++) { |
| content = mCachedDisplays[index]; |
| if (content == NULL) { |
| continue; |
| } |
| |
| for (size_t i = 0; i < content->numHwLayers - 1; i++) { |
| if (isProtectedLayer(content->hwLayers[i])) |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| bool DisplayAnalyzer::isProtectedLayer(hwc_layer_1_t &layer) |
| { |
| if (!layer.handle) { |
| return false; |
| } |
| bool ret = false; |
| BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); |
| DataBuffer *buffer = bm->lockDataBuffer(layer.handle); |
| if (!buffer) { |
| ETRACE("failed to get buffer"); |
| } else { |
| ret = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer); |
| bm->unlockDataBuffer(buffer); |
| } |
| return ret; |
| } |
| |
| bool DisplayAnalyzer::ignoreVideoSkipFlag() |
| { |
| return mIgnoreVideoSkipFlag; |
| } |
| |
| void DisplayAnalyzer::setCompositionType(hwc_display_contents_1_t *display, int type) |
| { |
| for (size_t i = 0; i < display->numHwLayers - 1; i++) { |
| hwc_layer_1_t *layer = &display->hwLayers[i]; |
| if (layer) layer->compositionType = type; |
| } |
| } |
| |
| void DisplayAnalyzer::setCompositionType(int device, int type, bool reset) |
| { |
| hwc_display_contents_1_t *content = mCachedDisplays[device]; |
| if (content == NULL) { |
| ETRACE("Invalid device %d", device); |
| return; |
| } |
| |
| // don't need to set geometry changed if layers are just needed to be marked |
| if (reset) { |
| content->flags |= HWC_GEOMETRY_CHANGED; |
| } |
| |
| setCompositionType(content, type); |
| } |
| |
| int DisplayAnalyzer::getFirstVideoInstanceSessionID() { |
| if (mVideoStateMap.size() >= 1) { |
| return mVideoStateMap.keyAt(0); |
| } |
| return -1; |
| } |
| |
| } // namespace intel |
| } // namespace android |
| |