diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp index 3abf069..e5e748c 100644 --- a/libgralloc/alloc_controller.cpp +++ b/libgralloc/alloc_controller.cpp @@ -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; } diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp index 679cf37..18f810f 100755 --- a/libgralloc/gpu.cpp +++ b/libgralloc/gpu.cpp @@ -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, diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 7ef6f54..3db7786 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -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 diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk index b2ef60c..49cfe00 100644 --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -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 diff --git a/libhwcomposer/external_display_only.h b/libhwcomposer/external_display_only.h new file mode 100644 index 0000000..fdab560 --- /dev/null +++ b/libhwcomposer/external_display_only.h @@ -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(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(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 diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index fb1fe62..f38ac4b 100644 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -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( 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; inumHwLayers; i++) { - if (list->hwLayers[i].flags & HWC_SKIP_LAYER) { - continue; + if (list) { + for (size_t i=0; inumHwLayers; 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; diff --git a/liboverlay/overlayLibUI.cpp b/liboverlay/overlayLibUI.cpp index 3e2e850..89eb2f7 100755 --- a/liboverlay/overlayLibUI.cpp +++ b/liboverlay/overlayLibUI.cpp @@ -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; diff --git a/libqcomui/qcom_ui.h b/libqcomui/qcom_ui.h index fa68695..6cad8ed 100644 --- a/libqcomui/qcom_ui.h +++ b/libqcomui/qcom_ui.h @@ -36,6 +36,7 @@ #include #include #include +#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, };