hardware/qcom/display: External-only display.
Add support for external-only display. Layer buffers marked with GRALLOC_USAGE_EXTERNAL_ONLY will be displayed on external panel only, if available. In addition if the layer buffer also has the flag GRALLOC_USAGE_EXTERNAL_BLOCK then only that layer will be displayed on external (During suspend). When this mode is on, the default mirror mode for external is stopped. Conflicts: libhwcomposer/hwcomposer.cpp Change-Id: I8ea2920384c5b68311ee3fe00707d01ab6568b52
This commit is contained in:
parent
6dd7f17b59
commit
e15d259d8c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
@ -59,6 +59,7 @@ static bool canFallback(int compositionType, int usage, bool triedSystem)
|
||||
// 2. Alloc from system heap was already tried
|
||||
// 3. The heap type is requsted explicitly
|
||||
// 4. The heap type is protected
|
||||
// 5. The buffer is meant for external display only
|
||||
|
||||
if(compositionType == MDP_COMPOSITION)
|
||||
return false;
|
||||
@ -66,6 +67,8 @@ static bool canFallback(int compositionType, int usage, bool triedSystem)
|
||||
return false;
|
||||
if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED))
|
||||
return false;
|
||||
if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_EXTERNAL_ONLY))
|
||||
return false;
|
||||
//Return true by default
|
||||
return true;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* Copyright (c) 2011 Code Aurora Forum. All rights reserved.
|
||||
* Copyright (c) 2011-2012 Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -164,6 +164,14 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage,
|
||||
flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;
|
||||
}
|
||||
|
||||
if (usage & GRALLOC_USAGE_EXTERNAL_ONLY) {
|
||||
flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;
|
||||
//The EXTERNAL_BLOCK flag is always an add-on
|
||||
if (usage & GRALLOC_USAGE_EXTERNAL_BLOCK) {
|
||||
flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
flags |= data.allocType;
|
||||
private_handle_t* hnd = new private_handle_t(data.fd, size, flags,
|
||||
|
@ -60,12 +60,12 @@ enum {
|
||||
|
||||
/* Set this for allocating uncached memory (using O_DSYNC)
|
||||
* cannot be used with noncontiguous heaps */
|
||||
GRALLOC_USAGE_PRIVATE_UNCACHED = 0x00010000,
|
||||
GRALLOC_USAGE_PRIVATE_UNCACHED = 0x00100000,
|
||||
|
||||
/* This flag needs to be set when using a non-contiguous heap from ION.
|
||||
* If not set, the system heap is assumed to be coming from ashmem
|
||||
*/
|
||||
GRALLOC_USAGE_PRIVATE_ION = 0x00020000,
|
||||
GRALLOC_USAGE_PRIVATE_ION = 0x00200000,
|
||||
|
||||
/* This flag can be set to disable genlock synchronization
|
||||
* for the gralloc buffer. If this flag is set the caller
|
||||
@ -73,10 +73,18 @@ enum {
|
||||
* WARNING - flag is outside the standard PRIVATE region
|
||||
* and may need to be moved if the gralloc API changes
|
||||
*/
|
||||
GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED = 0X00040000,
|
||||
GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED = 0X00400000,
|
||||
|
||||
/* Set this flag when you need to avoid mapping the memory in userspace */
|
||||
GRALLOC_USAGE_PRIVATE_DO_NOT_MAP = 0X00080000,
|
||||
GRALLOC_USAGE_PRIVATE_DO_NOT_MAP = 0X00800000,
|
||||
|
||||
/* Buffer content should be displayed on an external display only */
|
||||
GRALLOC_USAGE_EXTERNAL_ONLY = 0x00010000,
|
||||
|
||||
/* Only this buffer content should be displayed on external, even if
|
||||
* other EXTERNAL_ONLY buffers are available. Used during suspend.
|
||||
*/
|
||||
GRALLOC_USAGE_EXTERNAL_BLOCK = 0x00020000,
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -321,6 +329,8 @@ struct private_handle_t {
|
||||
PRIV_FLAGS_SECURE_BUFFER = 0x00000400,
|
||||
PRIV_FLAGS_UNSYNCHRONIZED = 0x00000800, // For explicit synchronization
|
||||
PRIV_FLAGS_NOT_MAPPED = 0x00001000, // Not mapped in userspace
|
||||
PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000, // Display on external only
|
||||
PRIV_FLAGS_EXTERNAL_BLOCK = 0x00004000, // Display only this buffer on external
|
||||
};
|
||||
|
||||
// file-descriptors
|
||||
|
@ -9,8 +9,9 @@ LOCAL_SHARED_LIBRARIES := liblog libcutils libEGL libhardware libutils liboverla
|
||||
LOCAL_SHARED_LIBRARIES += libgenlock libQcomUI libmemalloc
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
hwcomposer.cpp
|
||||
|
||||
hwcomposer.cpp \
|
||||
external_display_only.h
|
||||
|
||||
LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
|
||||
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).hwcomposer\" -DDEBUG_CALC_FPS
|
||||
LOCAL_CFLAGS += -DQCOM_HARDWARE
|
||||
|
498
libhwcomposer/external_display_only.h
Normal file
498
libhwcomposer/external_display_only.h
Normal file
@ -0,0 +1,498 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define EXTDEBUG 0
|
||||
class ExtDispOnly {
|
||||
|
||||
enum ExternalOnlyMode {
|
||||
EXT_ONLY_MODE_OFF = 0,
|
||||
EXT_ONLY_MODE_ON = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
MAX_EXT_ONLY_LAYERS = 2,
|
||||
};
|
||||
|
||||
public:
|
||||
/* Initialize, allocate data members */
|
||||
static void init();
|
||||
|
||||
/* Deallocate data members */
|
||||
static void destroy();
|
||||
|
||||
/* Closes all the overlay channels */
|
||||
static void close();
|
||||
|
||||
/* Prepare overlay and configures mdp pipes */
|
||||
static int prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index,
|
||||
bool waitForVsync);
|
||||
|
||||
/* Returns status of external-only mode */
|
||||
static bool isModeOn();
|
||||
|
||||
/* Updates stats and pipe config related to external_only and external_block layers
|
||||
* If we are staring or stopping this mode, update default mirroring.
|
||||
*/
|
||||
static int update(hwc_context_t* ctx, hwc_layer_list_t* list);
|
||||
|
||||
/* Stores the locked handle for the buffer that was successfully queued */
|
||||
static void storeLockedHandles(hwc_layer_list_t* list);
|
||||
|
||||
/* Queue buffers to mdp for display */
|
||||
static int draw(hwc_context_t *ctx, hwc_layer_list_t *list);
|
||||
|
||||
private:
|
||||
/* Locks a buffer and marks it as locked */
|
||||
static void lockBuffer(native_handle_t *hnd);
|
||||
|
||||
/* Unlocks a buffer and clears the locked flag */
|
||||
static void unlockBuffer(native_handle_t *hnd);
|
||||
|
||||
/* Unlocks buffers queued in previous round (and displayed by now)
|
||||
* Clears the handle cache.
|
||||
*/
|
||||
static void unlockPreviousBuffers();
|
||||
|
||||
/* Closes the a range of overlay channels */
|
||||
static void closeRange(int start);
|
||||
|
||||
/* Start default external mirroring */
|
||||
static void startDefaultMirror(hwc_context_t* ctx);
|
||||
|
||||
/* Stop default external mirroring */
|
||||
static void stopDefaultMirror(hwc_context_t* ctx);
|
||||
|
||||
/* Checks if external-only mode is starting */
|
||||
static bool isExtModeStarting(hwc_context_t* ctx, const int&
|
||||
numExtLayers);
|
||||
|
||||
/* Checks if external-only mode is stopping */
|
||||
static bool isExtModeStopping(hwc_context_t* ctx, const int&
|
||||
numExtLayers);
|
||||
|
||||
//Data members
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
static overlay::OverlayUI* mOvExtUI[MAX_EXT_ONLY_LAYERS];
|
||||
static native_handle_t* previousExtHandle[MAX_EXT_ONLY_LAYERS];
|
||||
static ExternalOnlyMode eExtOnlyMode;
|
||||
static int numExtOnlyLayers;
|
||||
static bool skipLayerPresent;
|
||||
static bool blockLayerPresent;
|
||||
static int blockLayerIndex;
|
||||
#endif
|
||||
}; //class ExtDispOnly
|
||||
|
||||
void ExtDispOnly::lockBuffer(native_handle_t *hnd) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
private_handle_t* phnd = (private_handle_t*)hnd;
|
||||
|
||||
//Genlock is reference counted and recursive.
|
||||
//Do not accidently lock a locked buffer.
|
||||
if(phnd && (phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
|
||||
LOGE_IF(EXTDEBUG, "%s: handle %p already locked", __func__, phnd);
|
||||
return;
|
||||
}
|
||||
if (GENLOCK_FAILURE == genlock_lock_buffer(hnd, GENLOCK_READ_LOCK,
|
||||
GENLOCK_MAX_TIMEOUT)) {
|
||||
LOGE("%s: genlock_lock_buffer(READ) failed", __func__);
|
||||
return;
|
||||
}
|
||||
phnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK;
|
||||
LOGE_IF(EXTDEBUG, "%s: locked handle = %p", __func__, hnd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExtDispOnly::unlockBuffer(native_handle_t *hnd) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
//Check if buffer is still around
|
||||
if(private_handle_t::validate(hnd) != 0) {
|
||||
LOGE("%s Handle already deallocated", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
private_handle_t* phnd = (private_handle_t*)hnd;
|
||||
|
||||
//Check if buffer was locked in the first place
|
||||
if((phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK) == 0) {
|
||||
LOGE("%s Handle not locked, cannot unlock", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
//Actually try to unlock
|
||||
if (GENLOCK_FAILURE == genlock_unlock_buffer(hnd)) {
|
||||
LOGE("%s: genlock_unlock_buffer failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
//Clear the locked flag
|
||||
phnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK;
|
||||
LOGE_IF(EXTDEBUG, "%s: unlocked handle = %p", __func__, hnd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExtDispOnly::unlockPreviousBuffers() {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
for(int i = 0; (i < MAX_EXT_ONLY_LAYERS) && previousExtHandle[i]; i++) {
|
||||
LOGE_IF(EXTDEBUG, "%s", __func__);
|
||||
ExtDispOnly::unlockBuffer(previousExtHandle[i]);
|
||||
previousExtHandle[i] = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExtDispOnly::init() {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) {
|
||||
mOvExtUI[i] = new overlay::OverlayUI();
|
||||
previousExtHandle[i] = NULL;
|
||||
}
|
||||
eExtOnlyMode = EXT_ONLY_MODE_OFF;
|
||||
numExtOnlyLayers = 0;
|
||||
skipLayerPresent = false;
|
||||
blockLayerPresent = false;
|
||||
blockLayerIndex = -1;
|
||||
LOGE_IF(EXTDEBUG, "%s", __func__);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExtDispOnly::destroy() {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) {
|
||||
delete mOvExtUI[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExtDispOnly::closeRange(int start) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
for (int index = start; index < MAX_EXT_ONLY_LAYERS; index++) {
|
||||
if(previousExtHandle[index]) {
|
||||
LOGE_IF(EXTDEBUG, "%s", __func__);
|
||||
ExtDispOnly::unlockBuffer(previousExtHandle[index]);
|
||||
previousExtHandle[index] = NULL;
|
||||
}
|
||||
mOvExtUI[index]->closeChannel();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void inline ExtDispOnly::close() {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
closeRange(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ExtDispOnly::prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index,
|
||||
bool waitForVsync) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
|
||||
ctx->pendingHDMI == true)
|
||||
return -1;
|
||||
|
||||
if (ctx && mOvExtUI[index]) {
|
||||
private_hwc_module_t* hwcModule = reinterpret_cast<
|
||||
private_hwc_module_t*>(ctx->device.common.module);
|
||||
if (!hwcModule) {
|
||||
LOGE("%s null module", __func__);
|
||||
return -1;
|
||||
}
|
||||
private_handle_t *hnd = (private_handle_t *)layer->handle;
|
||||
if(!hnd) {
|
||||
LOGE("%s handle null", __func__);
|
||||
return -1;
|
||||
}
|
||||
overlay::OverlayUI *ovUI = mOvExtUI[index];
|
||||
int ret = 0;
|
||||
//int orientation = layer->transform;
|
||||
//Assuming layers will always be source landscape
|
||||
const int orientation = 0;
|
||||
overlay_buffer_info info;
|
||||
hwc_rect_t sourceCrop = layer->sourceCrop;
|
||||
info.width = sourceCrop.right - sourceCrop.left;
|
||||
info.height = sourceCrop.bottom - sourceCrop.top;
|
||||
info.format = hnd->format;
|
||||
info.size = hnd->size;
|
||||
info.secure = false;
|
||||
|
||||
const int fbnum = ctx->mHDMIEnabled; //HDMI or WFD
|
||||
const bool isFg = false;
|
||||
//Just to differentiate zorders for different layers
|
||||
const int zorder = index;
|
||||
const bool isVGPipe = true;
|
||||
ovUI->setSource(info, orientation);
|
||||
ovUI->setDisplayParams(fbnum, waitForVsync, isFg, zorder, isVGPipe);
|
||||
const int fbWidth = ovUI->getFBWidth();
|
||||
const int fbHeight = ovUI->getFBHeight();
|
||||
ovUI->setPosition(0, 0, fbWidth, fbHeight);
|
||||
if(ovUI->commit() != overlay::NO_ERROR) {
|
||||
LOGE("%s: Overlay Commit failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
LOGE_IF(EXTDEBUG, "%s", __func__);
|
||||
#endif
|
||||
return overlay::NO_ERROR;
|
||||
}
|
||||
|
||||
inline void ExtDispOnly::startDefaultMirror(hwc_context_t* ctx) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx;
|
||||
private_hwc_module_t* hwcModule =
|
||||
reinterpret_cast<private_hwc_module_t*>(dev->common.module);
|
||||
framebuffer_device_t *fbDev = hwcModule->fbDevice;
|
||||
if (fbDev) {
|
||||
//mHDMIEnabled could be HDMI/WFD/NO EXTERNAL
|
||||
fbDev->enableHDMIOutput(fbDev, ctx->mHDMIEnabled);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void ExtDispOnly::stopDefaultMirror(hwc_context_t* ctx) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx;
|
||||
private_hwc_module_t* hwcModule =
|
||||
reinterpret_cast<private_hwc_module_t*>(dev->common.module);
|
||||
framebuffer_device_t *fbDev = hwcModule->fbDevice;
|
||||
if (fbDev) {
|
||||
fbDev->enableHDMIOutput(fbDev, EXT_DISPLAY_OFF);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool ExtDispOnly::isExtModeStarting(hwc_context_t* ctx, const int&
|
||||
numExtLayers) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
return ((eExtOnlyMode == EXT_ONLY_MODE_OFF) && numExtLayers);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool ExtDispOnly::isExtModeStopping(hwc_context_t* ctx, const int&
|
||||
numExtLayers) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
return ((eExtOnlyMode == EXT_ONLY_MODE_ON) && (numExtLayers == 0));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool ExtDispOnly::isModeOn() {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
return (eExtOnlyMode == EXT_ONLY_MODE_ON);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
int ExtDispOnly::update(hwc_context_t* ctx, hwc_layer_list_t* list) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
int numExtLayers = 0;
|
||||
bool skipLayerPresent = false;
|
||||
bool blockLayerPresent = false;
|
||||
int blockLayerIndex = -1;
|
||||
|
||||
//Book-keeping done each cycle
|
||||
for (size_t i = 0; i < list->numHwLayers; i++) {
|
||||
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
|
||||
// Dont draw in this round
|
||||
if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
|
||||
skipLayerPresent = true;
|
||||
}
|
||||
if(hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY)) {
|
||||
numExtLayers++;
|
||||
// No way we can let this be drawn by GPU to fb0
|
||||
if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
|
||||
list->hwLayers[i].flags &= ~ HWC_SKIP_LAYER;
|
||||
}
|
||||
list->hwLayers[i].flags |= HWC_USE_EXT_ONLY;
|
||||
list->hwLayers[i].compositionType = HWC_USE_OVERLAY;
|
||||
list->hwLayers[i].hints &= ~HWC_HINT_CLEAR_FB;
|
||||
//EXTERNAL_BLOCK is always an add-on
|
||||
if(hnd && (hnd->flags &
|
||||
private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK)) {
|
||||
blockLayerPresent = true;
|
||||
blockLayerIndex = i;
|
||||
list->hwLayers[i].flags |= HWC_USE_EXT_BLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Update Default mirroring state
|
||||
if (isExtModeStarting(ctx, numExtLayers)) {
|
||||
stopDefaultMirror(ctx);
|
||||
} else if (isExtModeStopping(ctx, numExtLayers)) {
|
||||
startDefaultMirror(ctx);
|
||||
}
|
||||
|
||||
//Cache our stats
|
||||
eExtOnlyMode = numExtLayers ? EXT_ONLY_MODE_ON : EXT_ONLY_MODE_OFF;
|
||||
numExtOnlyLayers = numExtLayers;
|
||||
skipLayerPresent = skipLayerPresent;
|
||||
blockLayerPresent = blockLayerPresent;
|
||||
blockLayerIndex = blockLayerIndex;
|
||||
|
||||
LOGE_IF(EXTDEBUG, "%s: numExtLayers = %d skipLayerPresent = %d", __func__,
|
||||
numExtLayers, skipLayerPresent);
|
||||
//If skip layer present return. Buffers to be unlocked in draw phase.
|
||||
if(skipLayerPresent) {
|
||||
return overlay::NO_ERROR;
|
||||
}
|
||||
|
||||
//If External is not connected, dont setup pipes, just return
|
||||
if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
|
||||
ctx->pendingHDMI == true) {
|
||||
ExtDispOnly::close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//Update pipes
|
||||
bool waitForVsync = true;
|
||||
bool index = 0;
|
||||
|
||||
if (blockLayerPresent) {
|
||||
ExtDispOnly::closeRange(1);
|
||||
ExtDispOnly::prepare(ctx, &(list->hwLayers[blockLayerIndex]),
|
||||
index, waitForVsync);
|
||||
} else if (numExtLayers) {
|
||||
ExtDispOnly::closeRange(numExtLayers);
|
||||
for (size_t i = 0; i < list->numHwLayers; i++) {
|
||||
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
|
||||
if(hnd && hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY) {
|
||||
waitForVsync = (index == (numExtLayers - 1));
|
||||
ExtDispOnly::prepare(ctx, &(list->hwLayers[i]),
|
||||
index, waitForVsync);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ExtDispOnly::close();
|
||||
}
|
||||
#endif
|
||||
return overlay::NO_ERROR;
|
||||
}
|
||||
|
||||
void ExtDispOnly::storeLockedHandles(hwc_layer_list_t* list) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
int index = 0;
|
||||
if(blockLayerPresent) {
|
||||
private_handle_t *hnd = (private_handle_t *)
|
||||
list->hwLayers[blockLayerIndex].handle;
|
||||
if(list->hwLayers[blockLayerIndex].flags & HWC_USE_EXT_ONLY) {
|
||||
if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
|
||||
ExtDispOnly::lockBuffer(hnd);
|
||||
}
|
||||
previousExtHandle[index] = hnd;
|
||||
LOGE_IF(EXTDEBUG, "%s BLOCK: handle = %p", __func__, hnd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < list->numHwLayers; i++) {
|
||||
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
|
||||
if(list->hwLayers[i].flags & HWC_USE_EXT_ONLY) {
|
||||
if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
|
||||
ExtDispOnly::lockBuffer(hnd);
|
||||
}
|
||||
previousExtHandle[index] = hnd;
|
||||
index++;
|
||||
LOGE_IF(EXTDEBUG, "%s: handle = %p", __func__, hnd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int ExtDispOnly::draw(hwc_context_t *ctx, hwc_layer_list_t *list) {
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
LOGE_IF(EXTDEBUG, "%s", __func__);
|
||||
if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
|
||||
ctx->pendingHDMI == true) {
|
||||
ExtDispOnly::close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = overlay::NO_ERROR;
|
||||
int index = 0;
|
||||
|
||||
//If skip layer present or list invalid unlock and return.
|
||||
if(skipLayerPresent || list == NULL) {
|
||||
ExtDispOnly::unlockPreviousBuffers();
|
||||
return overlay::NO_ERROR;
|
||||
}
|
||||
|
||||
if(blockLayerPresent) {
|
||||
private_handle_t *hnd = (private_handle_t*)
|
||||
list->hwLayers[blockLayerIndex].handle;
|
||||
ExtDispOnly::lockBuffer(hnd);
|
||||
ret = mOvExtUI[index]->queueBuffer(hnd);
|
||||
if (ret) {
|
||||
LOGE("%s queueBuffer failed", __func__);
|
||||
// Unlock the locked buffer
|
||||
ExtDispOnly::unlockBuffer(hnd);
|
||||
ExtDispOnly::close();
|
||||
return -1;
|
||||
}
|
||||
ExtDispOnly::unlockPreviousBuffers();
|
||||
ExtDispOnly::storeLockedHandles(list);
|
||||
return overlay::NO_ERROR;
|
||||
}
|
||||
|
||||
for(int i = 0; i < list->numHwLayers; i++) {
|
||||
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
|
||||
if(hnd && list->hwLayers[i].flags & HWC_USE_EXT_ONLY) {
|
||||
overlay::OverlayUI *ovUI = mOvExtUI[index];
|
||||
ExtDispOnly::lockBuffer(hnd);
|
||||
ret = ovUI->queueBuffer(hnd);
|
||||
if (ret) {
|
||||
LOGE("%s queueBuffer failed", __func__);
|
||||
// Unlock the all the currently locked buffers
|
||||
for (int j = 0; j <= i; j++) {
|
||||
private_handle_t *tmphnd =
|
||||
(private_handle_t *)list->hwLayers[j].handle;
|
||||
if(hnd && list->hwLayers[j].flags & HWC_USE_EXT_ONLY)
|
||||
ExtDispOnly::unlockBuffer(tmphnd);
|
||||
}
|
||||
ExtDispOnly::close();
|
||||
return -1;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
ExtDispOnly::unlockPreviousBuffers();
|
||||
ExtDispOnly::storeLockedHandles(list);
|
||||
#endif
|
||||
return overlay::NO_ERROR;
|
||||
}
|
||||
|
||||
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
|
||||
overlay::OverlayUI* ExtDispOnly::mOvExtUI[MAX_EXT_ONLY_LAYERS];
|
||||
native_handle_t* ExtDispOnly::previousExtHandle[MAX_EXT_ONLY_LAYERS];
|
||||
ExtDispOnly::ExternalOnlyMode ExtDispOnly::eExtOnlyMode;
|
||||
int ExtDispOnly::numExtOnlyLayers;
|
||||
bool ExtDispOnly::skipLayerPresent;
|
||||
bool ExtDispOnly::blockLayerPresent;
|
||||
int ExtDispOnly::blockLayerIndex;
|
||||
#endif
|
@ -131,6 +131,10 @@ struct private_hwc_module_t HAL_MODULE_INFO_SYM = {
|
||||
isBypassEnabled: false,
|
||||
};
|
||||
|
||||
//Only at this point would the compiler know all storage class sizes.
|
||||
//The header has hooks which need to know those beforehand.
|
||||
#include "external_display_only.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void dump_layer(hwc_layer_t const* l) {
|
||||
@ -398,6 +402,10 @@ inline static bool isBypassDoable(hwc_composer_device_t *dev, const int yuvCount
|
||||
}
|
||||
#endif
|
||||
|
||||
if(ExtDispOnly::isModeOn()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Bypass is not efficient if rotation is needed.
|
||||
for(int i = 0; i < list->numHwLayers; ++i) {
|
||||
if(list->hwLayers[i].transform) {
|
||||
@ -775,16 +783,19 @@ static void handleHDMIStateChange(hwc_composer_device_t *dev, int externaltype)
|
||||
hwc_context_t* ctx = (hwc_context_t*)(dev);
|
||||
private_hwc_module_t* hwcModule = reinterpret_cast<private_hwc_module_t*>(
|
||||
dev->common.module);
|
||||
framebuffer_device_t *fbDev = hwcModule->fbDevice;
|
||||
if (fbDev) {
|
||||
fbDev->enableHDMIOutput(fbDev, externaltype);
|
||||
}
|
||||
//Route the event to fbdev only if we are in default mirror mode
|
||||
if(ExtDispOnly::isModeOn() == false) {
|
||||
framebuffer_device_t *fbDev = hwcModule->fbDevice;
|
||||
if (fbDev) {
|
||||
fbDev->enableHDMIOutput(fbDev, externaltype);
|
||||
}
|
||||
|
||||
if(ctx && ctx->mOverlayLibObject) {
|
||||
overlay::Overlay *ovLibObject = ctx->mOverlayLibObject;
|
||||
if (!externaltype) {
|
||||
// Close the external overlay channels if HDMI is disconnected
|
||||
ovLibObject->closeExternalChannel();
|
||||
if(ctx && ctx->mOverlayLibObject) {
|
||||
overlay::Overlay *ovLibObject = ctx->mOverlayLibObject;
|
||||
if (!externaltype) {
|
||||
// Close the external overlay channels if HDMI is disconnected
|
||||
ovLibObject->closeExternalChannel();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -802,9 +813,10 @@ static void hwc_enableHDMIOutput(hwc_composer_device_t *dev, int externaltype) {
|
||||
dev->common.module);
|
||||
framebuffer_device_t *fbDev = hwcModule->fbDevice;
|
||||
overlay::Overlay *ovLibObject = ctx->mOverlayLibObject;
|
||||
if(externaltype && (externaltype != ctx->mHDMIEnabled)) {
|
||||
if(externaltype && ctx->mHDMIEnabled &&
|
||||
(externaltype != ctx->mHDMIEnabled)) {
|
||||
// Close the current external display - as the SF will
|
||||
// prioritize and send the correct external display
|
||||
// prioritize and send the correct external display HDMI/WFD
|
||||
handleHDMIStateChange(dev, 0);
|
||||
}
|
||||
// Store the external display
|
||||
@ -953,6 +965,7 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
|
||||
unsetBypassBufferLockState(ctx);
|
||||
#endif
|
||||
unlockPreviousOverlayBuffer(ctx);
|
||||
ExtDispOnly::close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1018,9 +1031,7 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
|
||||
list->hwLayers[layer_countdown].hints &= ~HWC_HINT_CLEAR_FB;
|
||||
layer_countdown--;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && (yuvBufferCount == 1)) {
|
||||
} else if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && (yuvBufferCount == 1)) {
|
||||
int flags = WAIT_FOR_VSYNC;
|
||||
flags |= (1 == list->numHwLayers) ? DISABLE_FRAMEBUFFER_FETCH : 0;
|
||||
if (!isValidDestination(hwcModule->fbDevice, list->hwLayers[i].displayFrame)) {
|
||||
@ -1032,15 +1043,13 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
|
||||
// We've opened the channel. Set the state to open.
|
||||
ctx->hwcOverlayStatus = HWC_OVERLAY_OPEN;
|
||||
#endif
|
||||
}
|
||||
else if (hwcModule->compositionType & (COMPOSITION_TYPE_C2D|
|
||||
} else if (hwcModule->compositionType & (COMPOSITION_TYPE_C2D|
|
||||
COMPOSITION_TYPE_MDP)) {
|
||||
//Fail safe path: If drawing with overlay fails,
|
||||
|
||||
//Use C2D if available.
|
||||
list->hwLayers[i].compositionType = HWC_USE_COPYBIT;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//If C2D is not enabled fall back to GPU.
|
||||
list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
|
||||
}
|
||||
@ -1065,8 +1074,9 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
|
||||
list->hwLayers[i].compositionType = HWC_USE_OVERLAY;
|
||||
list->hwLayers[i].hints |= HWC_HINT_CLEAR_FB;
|
||||
layerType |= HWC_ORIG_RESOLUTION;
|
||||
}
|
||||
else if (hnd && (hwcModule->compositionType &
|
||||
} else if (hnd && hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY) {
|
||||
//handle later after other layers are handled
|
||||
} else if (hnd && (hwcModule->compositionType &
|
||||
(COMPOSITION_TYPE_C2D|COMPOSITION_TYPE_MDP))) {
|
||||
list->hwLayers[i].compositionType = HWC_USE_COPYBIT;
|
||||
} else if ((hwcModule->compositionType == COMPOSITION_TYPE_DYN)
|
||||
@ -1078,6 +1088,9 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
|
||||
}
|
||||
}
|
||||
|
||||
//Update the stats and pipe config for external-only layers
|
||||
ExtDispOnly::update(ctx, list);
|
||||
|
||||
if (skipComposition) {
|
||||
list->flags |= HWC_SKIP_COMPOSITION;
|
||||
} else {
|
||||
@ -1445,6 +1458,7 @@ static int hwc_set(hwc_composer_device_t *dev,
|
||||
hwc_context_t* ctx = (hwc_context_t*)(dev);
|
||||
if(!ctx) {
|
||||
LOGE("hwc_set invalid context");
|
||||
ExtDispOnly::close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1456,14 +1470,19 @@ static int hwc_set(hwc_composer_device_t *dev,
|
||||
unlockPreviousBypassBuffers(ctx);
|
||||
unsetBypassBufferLockState(ctx);
|
||||
#endif
|
||||
ExtDispOnly::close();
|
||||
unlockPreviousOverlayBuffer(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
for (size_t i=0; i<list->numHwLayers; i++) {
|
||||
if (list->hwLayers[i].flags & HWC_SKIP_LAYER) {
|
||||
continue;
|
||||
if (list) {
|
||||
for (size_t i=0; i<list->numHwLayers; i++) {
|
||||
if (list->hwLayers[i].flags & HWC_SKIP_LAYER) {
|
||||
continue;
|
||||
} else if(list->hwLayers[i].flags & HWC_USE_EXT_ONLY) {
|
||||
continue;
|
||||
//Draw after layers for primary are drawn
|
||||
#ifdef COMPOSITION_BYPASS
|
||||
} else if (list->hwLayers[i].flags & HWC_COMP_BYPASS) {
|
||||
drawLayerUsingBypass(ctx, &(list->hwLayers[i]), i);
|
||||
@ -1477,6 +1496,12 @@ static int hwc_set(hwc_composer_device_t *dev,
|
||||
drawLayerUsingCopybit(dev, &(list->hwLayers[i]), (EGLDisplay)dpy, (EGLSurface)sur);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool canSkipComposition = list && list->flags & HWC_SKIP_COMPOSITION;
|
||||
//Draw External-only layers
|
||||
if(ExtDispOnly::draw(ctx, list) != overlay::NO_ERROR) {
|
||||
ExtDispOnly::close();
|
||||
}
|
||||
|
||||
#ifdef COMPOSITION_BYPASS
|
||||
unlockPreviousBypassBuffers(ctx);
|
||||
@ -1545,6 +1570,9 @@ static int hwc_device_close(struct hw_device_t *dev)
|
||||
unlockPreviousBypassBuffers(ctx);
|
||||
unsetBypassBufferLockState(ctx);
|
||||
#endif
|
||||
ExtDispOnly::close();
|
||||
ExtDispOnly::destroy();
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
return 0;
|
||||
@ -1633,7 +1661,7 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name,
|
||||
unsetBypassBufferLockState(dev);
|
||||
dev->bypassState = BYPASS_OFF;
|
||||
#endif
|
||||
|
||||
ExtDispOnly::init();
|
||||
#if defined HDMI_DUAL_DISPLAY
|
||||
dev->mHDMIEnabled = EXT_DISPLAY_OFF;
|
||||
dev->pendingHDMI = false;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -274,6 +274,8 @@ void OverlayUI::setDisplayParams(int fbNum, bool waitForVsync, bool isFg, int
|
||||
|
||||
mOvInfo.flags = flags;
|
||||
mOvInfo.z_order = zorder;
|
||||
|
||||
mobjDisplay.openDisplay(mFBNum);
|
||||
}
|
||||
|
||||
void OverlayUI::setPosition(int x, int y, int w, int h) {
|
||||
@ -390,14 +392,10 @@ status_t OverlayUI::closeChannel() {
|
||||
|
||||
status_t OverlayUI::startOVSession() {
|
||||
status_t ret = NO_INIT;
|
||||
ret = mobjDisplay.openDisplay(mFBNum);
|
||||
|
||||
if (ret != NO_ERROR)
|
||||
return ret;
|
||||
|
||||
mdp_overlay ovInfo = mOvInfo;
|
||||
|
||||
if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_SET, &ovInfo)) {
|
||||
LOGE("Overlay set failed..");
|
||||
LOGE("%s: Overlay set failed", __FUNCTION__);
|
||||
ret = BAD_VALUE;
|
||||
} else {
|
||||
mSessionID = ovInfo.id;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <ui/Region.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <utils/Singleton.h>
|
||||
#include "../libgralloc/gralloc_priv.h"
|
||||
|
||||
using namespace android;
|
||||
using android::sp;
|
||||
@ -83,6 +84,8 @@ enum {
|
||||
HWC_USE_ORIGINAL_RESOLUTION = 0x10000000,
|
||||
HWC_DO_NOT_USE_OVERLAY = 0x20000000,
|
||||
HWC_COMP_BYPASS = 0x40000000,
|
||||
HWC_USE_EXT_ONLY = 0x80000000, //Layer displayed on external only
|
||||
HWC_USE_EXT_BLOCK = 0x01000000, //Layer displayed on external only
|
||||
HWC_BYPASS_RESERVE_0 = 0x00000010,
|
||||
HWC_BYPASS_RESERVE_1 = 0x00000020,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user