YUV layer updates during animation and popups.

-- During animation, if yuv layer is marked skip close overlay channels.
   But if HDMI is connected, let them remain open, and send data.

-- During popups on paused video, if the layer above it is skip,
   let the video layer be displayed via overlay.

-- Fix MDP pipe closing mechanism for yuv content.

-- Synchronize notification to gralloc with actual video channel status.

CRs-Fixed: 342892

Change-Id: I98f442c12e59e4fcf93af87a251e3d489e624c0b
(cherry picked from commit 752ee11eb0318dbb2bfdc5200c320cd2db972eb9)
This commit is contained in:
Sushil Chauhan 2012-03-11 14:04:13 -07:00 committed by Andrew Sutherland
parent d6ffef4cef
commit 4e0b4170a1

View File

@ -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<private_hwc_module_t*>(
@ -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 ; i<list->numHwLayers ; 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];