diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 020cf76..f7fe1c4 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -81,6 +81,8 @@ struct hwc_context_t { /* our private state goes below here */ overlay::Overlay* mOverlayLibObject; native_handle_t *previousOverlayHandle; + native_handle_t *currentOverlayHandle; + int yuvBufferCount; #ifdef COMPOSITION_BYPASS overlay::OverlayUI* mOvUI[MAX_BYPASS_LAYERS]; native_handle_t* previousBypassHandle[MAX_BYPASS_LAYERS]; @@ -542,6 +544,40 @@ void closeExtraPipes(hwc_context_t* ctx) { } #endif //COMPOSITION_BYPASS + +// Returns true if external panel is connected +static inline bool isExternalConnected(const hwc_context_t* ctx) { +#if defined HDMI_DUAL_DISPLAY + return (ctx->mHDMIEnabled != EXT_TYPE_NONE); +#endif + return false; +} + +// Returns true if we have a skip layer +static inline bool isSkipLayer(const hwc_layer_t* layer) { + return (layer && (layer->flags & HWC_SKIP_LAYER)); +} + +// Returns true if the buffer is yuv +static inline bool isYuvBuffer(const private_handle_t* hnd) { + return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO)); +} + +//Return true if buffer is marked locked +static inline bool isBufferLocked(const private_handle_t* hnd) { + return (hnd && (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags)); +} + +//Marks layers for GPU composition +static inline void markForGPUComp(const hwc_context_t *ctx, + hwc_layer_list_t* list, const int limit) { + for(int i = 0; i < limit; i++) { + list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + list->hwLayers[i].hints &= ~HWC_HINT_CLEAR_FB; + } +} + + static int setVideoOverlayStatusInGralloc(hwc_context_t* ctx, const bool enable) { #if defined HDMI_DUAL_DISPLAY private_hwc_module_t* hwcModule = reinterpret_cast( @@ -563,28 +599,6 @@ static int setVideoOverlayStatusInGralloc(hwc_context_t* ctx, const bool enable) return 0; } -static void setHWCOverlayStatus(hwc_context_t *ctx, bool isVideoPresent) { - - switch (ctx->hwcOverlayStatus) { - case HWC_OVERLAY_OPEN: - ctx->hwcOverlayStatus = - isVideoPresent ? HWC_OVERLAY_OPEN : HWC_OVERLAY_PREPARE_TO_CLOSE; - break; - case HWC_OVERLAY_PREPARE_TO_CLOSE: - ctx->hwcOverlayStatus = - isVideoPresent ? HWC_OVERLAY_OPEN : HWC_OVERLAY_CLOSED; - break; - case HWC_OVERLAY_CLOSED: - ctx->hwcOverlayStatus = - isVideoPresent ? HWC_OVERLAY_OPEN : HWC_OVERLAY_CLOSED; - break; - default: - LOGE("%s: Invalid hwcOverlayStatus (status =%d)", __FUNCTION__, - ctx->hwcOverlayStatus); - break; - } -} - static int hwc_closeOverlayChannels(hwc_context_t* ctx) { #ifdef USE_OVERLAY overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; @@ -600,6 +614,7 @@ static int hwc_closeOverlayChannels(hwc_context_t* ctx) { ovLibObject->closeChannel(); // Inform the gralloc that video overlay has stopped. setVideoOverlayStatusInGralloc(ctx, false); + ctx->hwcOverlayStatus = HWC_OVERLAY_CLOSED; } #endif return 0; @@ -698,21 +713,19 @@ static int prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer, const int flag void unlockPreviousOverlayBuffer(hwc_context_t* ctx) { - if (ctx->previousOverlayHandle) { - // Validate the handle before attempting to use it. - if (!private_handle_t::validate(ctx->previousOverlayHandle)) { - private_handle_t *hnd = (private_handle_t*)ctx->previousOverlayHandle; - // Unlock any previously locked buffers - if (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags) { - if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle)) { - ctx->previousOverlayHandle = NULL; - hnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK; - } else { - LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); - } + private_handle_t *hnd = (private_handle_t*)ctx->previousOverlayHandle; + if (isBufferLocked(hnd) && !private_handle_t::validate(hnd)) { + if (GENLOCK_NO_ERROR == genlock_unlock_buffer(hnd)) { + //If previous is same as current, keep locked. + if(hnd != ctx->currentOverlayHandle) { + hnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK; } + } else { + LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); } } + ctx->previousOverlayHandle = ctx->currentOverlayHandle; + ctx->currentOverlayHandle = NULL; } bool canSkipComposition(hwc_context_t* ctx, int yuvBufferCount, int currentLayerCount, @@ -872,9 +885,6 @@ static int getYUVBufferCount (const hwc_layer_list_t* list) { if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && !(list->hwLayers[i].flags & HWC_DO_NOT_USE_OVERLAY)) { yuvBufferCount++; - if (yuvBufferCount > 1) { - break; - } } } } @@ -956,9 +966,11 @@ static int getLayersNotUpdatingCount(const hwc_layer_list_t* list) { return numLayersNotUpdating; } + static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { hwc_context_t* ctx = (hwc_context_t*)(dev); + ctx->currentOverlayHandle = NULL; if(!ctx) { LOGE("hwc_prepare invalid context"); @@ -989,11 +1001,16 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { if (list) { useCopybit = canUseCopybit(hwcModule->fbDevice, list); - yuvBufferCount = getYUVBufferCount(list); + ctx->yuvBufferCount = getYUVBufferCount(list); + yuvBufferCount = ctx->yuvBufferCount; numLayersNotUpdating = getLayersNotUpdatingCount(list); skipComposition = canSkipComposition(ctx, yuvBufferCount, list->numHwLayers, numLayersNotUpdating); + if ((yuvBufferCount == 0) && (ctx->hwcOverlayStatus == HWC_OVERLAY_OPEN)) { + ctx->hwcOverlayStatus = HWC_OVERLAY_PREPARE_TO_CLOSE; + } + if (yuvBufferCount == 1) { s3dVideoFormat = getS3DVideoFormat(list); if (s3dVideoFormat) @@ -1005,61 +1022,57 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { unlockPreviousOverlayBuffer(ctx); } - if (list->flags & HWC_GEOMETRY_CHANGED) { - if (yuvBufferCount == 1) { - // Inform the gralloc of the current video overlay status - setVideoOverlayStatusInGralloc(ctx, true); - } - } - for (size_t i=0 ; inumHwLayers ; i++) { private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; // If there is a single Fullscreen layer, we can bypass it - TBD // If there is only one video/camera buffer, we can bypass itn - if (list->hwLayers[i].flags & HWC_SKIP_LAYER) { - // During the animaton UI layers are marked as SKIP - // need to still mark the layer for S3D composition + if (isSkipLayer(&list->hwLayers[i])) { isSkipLayerPresent = true; skipComposition = false; //Reset count, so that we end up composing once after animation //is over, in case of overlay. ctx->previousLayerCount = -1; + //If YUV layer is marked as SKIP, close pipes. + //If External is connected we still want to pump data to it, + //so keep the pipes open. + if(isYuvBuffer(hnd) && !isExternalConnected(ctx)) { + if (ctx->hwcOverlayStatus == HWC_OVERLAY_OPEN) + ctx->hwcOverlayStatus = HWC_OVERLAY_PREPARE_TO_CLOSE; + unlockPreviousOverlayBuffer(ctx); + } + // During the animaton UI layers are marked as SKIP + // need to still mark the layer for S3D composition if (isS3DCompositionNeeded) markUILayerForS3DComposition(list->hwLayers[i], s3dVideoFormat); - ssize_t layer_countdown = ((ssize_t)i); - // Mark every layer below the SKIP layer to be composed by the GPU - while (layer_countdown >= 0) - { - private_handle_t *countdown_handle = - (private_handle_t *)list->hwLayers[layer_countdown].handle; - if (countdown_handle && (countdown_handle->bufferType == BUFFER_TYPE_VIDEO) - && (yuvBufferCount == 1)) { - unlockPreviousOverlayBuffer(ctx); - } - list->hwLayers[layer_countdown].compositionType = HWC_FRAMEBUFFER; - list->hwLayers[layer_countdown].hints &= ~HWC_HINT_CLEAR_FB; - layer_countdown--; - } + list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + list->hwLayers[i].hints &= ~HWC_HINT_CLEAR_FB; + markForGPUComp(ctx, list, i); } else if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && (yuvBufferCount == 1)) { + setVideoOverlayStatusInGralloc(ctx, true); int flags = WAIT_FOR_VSYNC; flags |= (1 == list->numHwLayers) ? DISABLE_FRAMEBUFFER_FETCH : 0; if (!isValidDestination(hwcModule->fbDevice, list->hwLayers[i].displayFrame)) { list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + list->hwLayers[i].hints &= ~HWC_HINT_CLEAR_FB; //Even though there are no skip layers, animation is still //ON and in its final stages. //Reset count, so that we end up composing once after animation //is done, if overlay is used. ctx->previousLayerCount = -1; skipComposition = false; + if (ctx->hwcOverlayStatus == HWC_OVERLAY_OPEN) + ctx->hwcOverlayStatus = HWC_OVERLAY_PREPARE_TO_CLOSE; + unlockPreviousOverlayBuffer(ctx); #ifdef USE_OVERLAY } else if(prepareOverlay(ctx, &(list->hwLayers[i]), flags) == 0) { list->hwLayers[i].compositionType = HWC_USE_OVERLAY; list->hwLayers[i].hints |= HWC_HINT_CLEAR_FB; // We've opened the channel. Set the state to open. ctx->hwcOverlayStatus = HWC_OVERLAY_OPEN; + #endif } else if (hwcModule->compositionType & (COMPOSITION_TYPE_C2D| COMPOSITION_TYPE_MDP)) { @@ -1076,6 +1089,7 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { skipComposition = false; } } else if (getLayerS3DFormat(list->hwLayers[i])) { + setVideoOverlayStatusInGralloc(ctx, true); int flags = WAIT_FOR_VSYNC; flags |= (1 == list->numHwLayers) ? DISABLE_FRAMEBUFFER_FETCH : 0; #ifdef USE_OVERLAY @@ -1394,6 +1408,7 @@ static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer) LOGE("drawLayerUsingLayer null module "); return -1; } + private_handle_t *hnd = (private_handle_t *)layer->handle; overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; int ret = 0; @@ -1407,19 +1422,15 @@ static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer) ret = ovLibObject->queueBuffer(hnd); - // Unlock the previously locked buffer, since the overlay has completed reading the buffer - unlockPreviousOverlayBuffer(ctx); - if (!ret) { LOGE("drawLayerUsingOverlay queueBuffer failed"); // Unlock the buffer handle genlock_unlock_buffer(hnd); - ctx->previousOverlayHandle = NULL; } else { // Store the current buffer handle as the one that is to be unlocked after // the next overlay play call. - ctx->previousOverlayHandle = hnd; hnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK; + ctx->currentOverlayHandle = hnd; } return ret; @@ -1552,6 +1563,10 @@ static int hwc_set(hwc_composer_device_t *dev, CALC_FPS(); } } + + // Unlock the previously locked buffer, since the overlay has completed reading the buffer + unlockPreviousOverlayBuffer(ctx); + #if defined HDMI_DUAL_DISPLAY if(ctx->pendingHDMI) { handleHDMIStateChange(dev, ctx->mHDMIEnabled); @@ -1560,9 +1575,6 @@ static int hwc_set(hwc_composer_device_t *dev, #endif hwc_closeOverlayChannels(ctx); - int yuvBufferCount = getYUVBufferCount(list); - setHWCOverlayStatus(ctx, yuvBufferCount); - return ret; } @@ -1696,6 +1708,7 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name, dev->pendingHDMI = false; #endif dev->previousOverlayHandle = NULL; + dev->currentOverlayHandle = NULL; dev->hwcOverlayStatus = HWC_OVERLAY_CLOSED; dev->previousLayerCount = -1; char value[PROPERTY_VALUE_MAX];