499 lines
17 KiB
C
499 lines
17 KiB
C
|
/*
|
||
|
* 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
|