libhwcomposer: Use genlock to lock/unlock buffers for composition.

For copybit composition, aquire a read lock on the buffer, before
the blit operation and release the lock after the blit operation.

For overlay, aquire a read lock on buffer N that is sent to the
overlay. After the play call for buffer N returns, unlock the lock
held by buffer (N-1).

Change-Id: I3ff178d8ed8e3a289c199237dbec501afdb7e717
This commit is contained in:
Naomi Luis 2011-11-21 21:01:30 -08:00 committed by Ramakrishna Prasad N
parent 8e61389886
commit be1b5f3d66
2 changed files with 72 additions and 7 deletions

4
libhwcomposer/Android.mk Normal file → Executable file
View File

@ -6,16 +6,20 @@ include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libcutils libEGL libhardware libutils liboverlay
LOCAL_SHARED_LIBRARIES += libgenlock
LOCAL_SRC_FILES := \
hwcomposer.cpp
LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).hwcomposer\"
LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
LOCAL_C_INCLUDES += hardware/qcom/display/liboverlay
LOCAL_C_INCLUDES += hardware/qcom/display/libcopybit
LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
ifeq ($(TARGET_HAVE_HDMI_OUT),true)
LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY

75
libhwcomposer/hwcomposer.cpp Normal file → Executable file
View File

@ -37,6 +37,7 @@
#include <EGL/eglext.h>
#include <ui/android_native_buffer.h>
#include <gralloc_priv.h>
#include <genlock.h>
/*****************************************************************************/
#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1))
@ -94,6 +95,7 @@ struct hwc_context_t {
hwc_composer_device_t device;
/* our private state goes below here */
overlay::Overlay* mOverlayLibObject;
native_handle_t *previousOverlayHandle;
#ifdef COMPOSITION_BYPASS
overlay::OverlayUI* mOvUI[MAX_BYPASS_LAYERS];
int animCount;
@ -739,6 +741,12 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
s3dVideoFormat = getS3DVideoFormat(list);
if (s3dVideoFormat)
isS3DCompositionNeeded = isS3DCompositionRequired();
} else {
if (ctx->previousOverlayHandle) {
// Unlock any previously locked buffers
if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle))
ctx->previousOverlayHandle = NULL;
}
}
if (list->flags & HWC_GEOMETRY_CHANGED) {
@ -763,7 +771,6 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
bool waitForVsync = skipComposition ? true:false;
if (!isValidDestination(hwcModule->fbDevice, list->hwLayers[i].displayFrame)) {
list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
skipComposition = false;
#ifdef USE_OVERLAY
} else if(prepareOverlay(ctx, &(list->hwLayers[i]), waitForVsync) == 0) {
list->hwLayers[i].compositionType = HWC_USE_OVERLAY;
@ -778,11 +785,17 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
//Use C2D if available.
list->hwLayers[i].compositionType = HWC_USE_COPYBIT;
skipComposition = false;
}
else {
//If C2D is not enabled fall back to GPU.
list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
}
if (HWC_USE_OVERLAY != list->hwLayers[i].compositionType) {
if (ctx->previousOverlayHandle) {
// Unlock any previously locked buffers before the fallback.
if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle))
ctx->previousOverlayHandle = NULL;
}
skipComposition = false;
}
} else if (isS3DCompositionNeeded) {
@ -890,6 +903,14 @@ static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer,
return -1;
}
// Lock this buffer for read.
genlock_lock_type lockType = GENLOCK_READ_LOCK;
int err = genlock_lock_buffer(hnd, lockType, GENLOCK_MAX_TIMEOUT);
if (GENLOCK_FAILURE == err) {
LOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__);
return -1;
}
// Set the copybit source:
copybit_image_t src;
src.w = ALIGN(hnd->width, 32);
@ -915,11 +936,13 @@ static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer,
android_native_buffer_t *renderBuffer = (android_native_buffer_t *)eglGetRenderBufferANDROID(dpy, surface);
if (!renderBuffer) {
LOGE("eglGetRenderBufferANDROID returned NULL buffer");
genlock_unlock_buffer(hnd);
return -1;
}
private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle;
if(!fbHandle) {
LOGE("Framebuffer handle is NULL");
genlock_unlock_buffer(hnd);
return -1;
}
dst.w = ALIGN(fbHandle->width,32);
@ -938,11 +961,17 @@ static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer,
(layer->blending == HWC_BLENDING_NONE) ? 0xFF : layer->alpha);
copybit->set_parameter(copybit, COPYBIT_PREMULTIPLIED_ALPHA,
(layer->blending == HWC_BLENDING_PREMULT)? COPYBIT_ENABLE : COPYBIT_DISABLE);
int err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, &copybitRegion);
err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, &copybitRegion);
if(err < 0)
LOGE("copybit stretch failed");
// Unlock this buffer since copybit is done with it.
err = genlock_unlock_buffer(hnd);
if (GENLOCK_FAILURE == err) {
LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__);
}
return err;
}
@ -958,13 +987,37 @@ static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer)
overlay::Overlay *ovLibObject = ctx->mOverlayLibObject;
int ret = 0;
ret = ovLibObject->queueBuffer(hnd);
if (!ret) {
LOGE("drawLayerUsingOverlay queueBuffer failed");
// Lock this buffer for read.
if (GENLOCK_NO_ERROR != genlock_lock_buffer(hnd, GENLOCK_READ_LOCK,
GENLOCK_MAX_TIMEOUT)) {
LOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__);
return -1;
}
ret = ovLibObject->queueBuffer(hnd);
// Unlock the previously locked buffer, since the overlay has completed reading the buffer
if (ctx->previousOverlayHandle) {
if (GENLOCK_FAILURE == genlock_unlock_buffer(ctx->previousOverlayHandle)) {
LOGE("%s: genlock_unlock_buffer for the previous handle failed",
__FUNCTION__);
}
}
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;
}
return ret;
}
return 0;
return -1;
}
static int hwc_set(hwc_composer_device_t *dev,
@ -1050,6 +1103,13 @@ static int hwc_device_close(struct hw_device_t *dev)
hwcModule->fbDevice = NULL;
}
if (ctx->previousOverlayHandle) {
if (GENLOCK_NO_ERROR != genlock_unlock_buffer(ctx->previousOverlayHandle)) {
LOGE("%s: genlock_unlock_buffer for the previous handle failed",
__FUNCTION__);
}
}
if (ctx) {
delete ctx->mOverlayLibObject;
ctx->mOverlayLibObject = NULL;
@ -1142,6 +1202,7 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name,
dev->mHDMIEnabled = false;
dev->pendingHDMI = false;
#endif
dev->previousOverlayHandle = NULL;
dev->hwcOverlayStatus = HWC_OVERLAY_CLOSED;
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;