hwc: Add support for copybit(C2D) composition
- Add CopybitEngine to hwc_context
- draw the layer on the HWC_FRAMEBUFFER_TARGET using
copybit(c2d) if it qualifies for C2D composition.
- use fence returned from the copybit during c2d
composition
Change-Id: I052da015cd031f7abd6411d83d7944c335caeff7
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 1249e84..e764c69 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
@@ -20,14 +20,12 @@
#define DEBUG_COPYBIT 0
#include <copybit.h>
-#include <genlock.h>
-#include "hwc_copybit.h"
+#include <utils/Timers.h>
#include "hwc_copybit.h"
#include "comptype.h"
namespace qhwc {
-
struct range {
int current;
int end;
@@ -65,44 +63,9 @@
mutable range r;
};
-// Initialize CopyBit Class Static Mmembers.
-functype_eglGetRenderBufferANDROID CopyBit::LINK_eglGetRenderBufferANDROID
- = NULL;
-functype_eglGetCurrentSurface CopyBit::LINK_eglGetCurrentSurface = NULL;
-int CopyBit::sYuvCount = 0;
-int CopyBit::sYuvLayerIndex = -1;
-bool CopyBit::sIsModeOn = false;
-bool CopyBit::sIsLayerSkip = false;
-void* CopyBit::egl_lib = NULL;
-
-void CopyBit::openEglLibAndGethandle()
-{
- egl_lib = ::dlopen("libEGL_adreno200.so", RTLD_GLOBAL | RTLD_LAZY);
- if (!egl_lib) {
- return;
- }
- updateEglHandles(egl_lib);
-}
-void CopyBit::closeEglLib()
-{
- if(egl_lib)
- ::dlclose(egl_lib);
-
- egl_lib = NULL;
- updateEglHandles(NULL);
-}
-
-void CopyBit::updateEglHandles(void* egl_lib)
-{
- if(egl_lib != NULL) {
- *(void **)&CopyBit::LINK_eglGetRenderBufferANDROID =
- ::dlsym(egl_lib, "eglGetRenderBufferANDROID");
- *(void **)&CopyBit::LINK_eglGetCurrentSurface =
- ::dlsym(egl_lib, "eglGetCurrentSurface");
- }else {
- LINK_eglGetCurrentSurface = NULL;
- LINK_eglGetCurrentSurface = NULL;
- }
+void CopyBit::reset() {
+ mIsModeOn = false;
+ mCopyBitDraw = false;
}
bool CopyBit::canUseCopybitForYUV(hwc_context_t *ctx) {
@@ -113,15 +76,16 @@
return true;
}
-bool CopyBit::canUseCopybitForRGB(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
- int compositionType =
- qdutils::QCCompositionType::getInstance().getCompositionType();
+bool CopyBit::canUseCopybitForRGB(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list,
+ int dpy) {
+ int compositionType = qdutils::QCCompositionType::
+ getInstance().getCompositionType();
if ((compositionType & qdutils::COMPOSITION_TYPE_C2D) ||
(compositionType & qdutils::COMPOSITION_TYPE_DYN)) {
- if (sYuvCount) {
+ if(ctx->listStats[dpy].yuvCount) {
//Overlay up & running. Dont use COPYBIT for RGB layers.
- // TODO need to implement blending with C2D
return false;
}
}
@@ -131,17 +95,13 @@
// use copybit, if (TotalRGBRenderArea < 2 * FB Area)
// this is done based on perf inputs in ICS
// TODO: Above condition needs to be re-evaluated in JB
-
- framebuffer_device_t *fbDev = ctx->mFbDev;
- if (!fbDev) {
- ALOGE("%s:Invalid FB device", __FUNCTION__);
- return false;
- }
- unsigned int fbArea = (fbDev->width * fbDev->height);
+ int fbWidth = ctx->dpyAttr[dpy].xres;
+ int fbHeight = ctx->dpyAttr[dpy].yres;
+ unsigned int fbArea = (fbWidth * fbHeight);
unsigned int renderArea = getRGBRenderingArea(list);
ALOGD_IF (DEBUG_COPYBIT, "%s:renderArea %u, fbArea %u",
__FUNCTION__, renderArea, fbArea);
- if (renderArea < (2 * fbArea)) {
+ if (renderArea <= (2 * fbArea)) {
return true;
}
} else if ((compositionType & qdutils::COMPOSITION_TYPE_MDP)) {
@@ -154,7 +114,8 @@
return false;
}
-unsigned int CopyBit::getRGBRenderingArea(const hwc_display_contents_1_t *list) {
+unsigned int CopyBit::getRGBRenderingArea
+ (const hwc_display_contents_1_t *list) {
//Calculates total rendering area for RGB layers
unsigned int renderArea = 0;
unsigned int w=0, h=0;
@@ -170,71 +131,116 @@
return renderArea;
}
-bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy) {
- int compositionType =
- qdutils::QCCompositionType::getInstance().getCompositionType();
+ if(mEngine == NULL) {
+ // No copybit device found - cannot use copybit
+ return false;
+ }
+ int compositionType = qdutils::QCCompositionType::
+ getInstance().getCompositionType();
- if ((compositionType & qdutils::COMPOSITION_TYPE_GPU) ||
- (compositionType & qdutils::COMPOSITION_TYPE_CPU)) {
+ if ((compositionType == qdutils::COMPOSITION_TYPE_GPU) ||
+ (compositionType == qdutils::COMPOSITION_TYPE_CPU)) {
//GPU/CPU composition, don't change layer composition type
return true;
}
- bool useCopybitForYUV = canUseCopybitForYUV(ctx);
- bool useCopybitForRGB = canUseCopybitForRGB(ctx, list);
-
if(!(validateParams(ctx, list))) {
- ALOGE("%s:Invalid Params", __FUNCTION__);
- return false;
+ ALOGE("%s:Invalid Params", __FUNCTION__);
+ return false;
}
- for (int i=list->numHwLayers-1; i >= 0 ; i--) {
+ if(ctx->listStats[dpy].skipCount) {
+ //GPU will be anyways used
+ return false;
+ }
+
+ bool useCopybitForYUV = canUseCopybitForYUV(ctx);
+ bool useCopybitForRGB = canUseCopybitForRGB(ctx, list, dpy);
+
+ // numAppLayers-1, as we iterate till 0th layer index
+ for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
- if (isSkipLayer(&list->hwLayers[i])) {
- return true;
- } else if (hnd->bufferType == BUFFER_TYPE_VIDEO) {
- //YUV layer, check, if copybit can be used
- if (useCopybitForYUV) {
- list->hwLayers[i].compositionType = HWC_USE_COPYBIT;
- }
- } else if (hnd->bufferType == BUFFER_TYPE_UI) {
- //RGB layer, check, if copybit can be used
- if (useCopybitForRGB) {
- list->hwLayers[i].compositionType = HWC_USE_COPYBIT;
- }
- }
- }
- return true;
-}
-
-bool CopyBit::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list, EGLDisplay dpy,
- EGLSurface sur){
- // draw layers marked for COPYBIT
- int retVal = true;
- for (size_t i=0; i<list->numHwLayers; i++) {
- if (list->hwLayers[i].compositionType == HWC_USE_COPYBIT) {
- retVal = drawLayerUsingCopybit(ctx, &(list->hwLayers[i]),
- (EGLDisplay)dpy,
- (EGLSurface)sur,
- LINK_eglGetRenderBufferANDROID,
- LINK_eglGetCurrentSurface);
- if(retVal<0) {
- ALOGE("%s : drawLayerUsingCopybit failed", __FUNCTION__);
- }
+ if (hnd->bufferType == BUFFER_TYPE_VIDEO) {
+ //YUV layer, check, if copybit can be used
+ // mark the video layer to gpu when all layer is
+ // going to gpu in case of dynamic composition.
+ if (useCopybitForYUV) {
+ list->hwLayers[i].compositionType = HWC_BLIT;
+ mCopyBitDraw = true;
+ }
+ } else if (hnd->bufferType == BUFFER_TYPE_UI) {
+ //RGB layer, check, if copybit can be used
+ if (useCopybitForRGB) {
+ ALOGD_IF(DEBUG_COPYBIT, "%s: Marking layer[%d] for copybit for"
+ "dpy[%d] ", __FUNCTION__, i, dpy);
+ list->hwLayers[i].compositionType = HWC_BLIT;
+ mCopyBitDraw = true;
+ }
}
}
return true;
}
+bool CopyBit::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy, int32_t *fd) {
+ // draw layers marked for COPYBIT
+ int retVal = true;
+ int copybitLayerCount = 0;
+
+ if(mCopyBitDraw == false) // there is no layer marked for copybit
+ return true ;
+
+ size_t fbLayerIndex = ctx->listStats[dpy].fbLayerIndex;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[fbLayerIndex];
+ //render buffer
+ private_handle_t *renderBuffer = (private_handle_t *)fbLayer->handle;
+ if (!renderBuffer) {
+ ALOGE("%s: HWC_FRAMEBUFFER_TARGET layer handle is NULL", __FUNCTION__);
+ return false;
+ }
+ // numAppLayers-1, as we iterate from 0th layer index with HWC_BLIT flag
+ for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ if(!list->hwLayers[i].compositionType == HWC_BLIT) {
+ ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for C2D", __FUNCTION__);
+ continue;
+ }
+ int ret = -1;
+ if (list->hwLayers[i].acquireFenceFd != -1 ) {
+ // Wait for acquire Fence on the App buffers.
+ ret = sync_wait(list->hwLayers[i].acquireFenceFd, 1000);
+ if(ret < 0) {
+ ALOGE("%s: sync_wait error!! error no = %d err str = %s",
+ __FUNCTION__, errno, strerror(errno));
+ }
+ close(list->hwLayers[i].acquireFenceFd);
+ list->hwLayers[i].acquireFenceFd = -1;
+ }
+ retVal = drawLayerUsingCopybit(ctx, &(list->hwLayers[i]),
+ renderBuffer, dpy);
+ copybitLayerCount++;
+ if(retVal < 0) {
+ ALOGE("%s : drawLayerUsingCopybit failed", __FUNCTION__);
+ }
+ }
+
+ if (copybitLayerCount) {
+ copybit_device_t *copybit = getCopyBitDevice();
+ // Async mode
+ copybit->flush_get_fence(copybit, fd);
+ }
+ return true;
+}
+
int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
- EGLDisplay dpy,
- EGLSurface surface,
- functype_eglGetRenderBufferANDROID& LINK_eglGetRenderBufferANDROID,
- functype_eglGetCurrentSurface LINK_eglGetCurrentSurface)
+ private_handle_t *renderBuffer, int dpy)
{
hwc_context_t* ctx = (hwc_context_t*)(dev);
+ int err = 0;
if(!ctx) {
ALOGE("%s: null context ", __FUNCTION__);
return -1;
@@ -246,26 +252,9 @@
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) {
- ALOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__);
- return -1;
- }
- //render buffer
- EGLSurface eglSurface = LINK_eglGetCurrentSurface(EGL_DRAW);
- android_native_buffer_t *renderBuffer =
- (android_native_buffer_t *)LINK_eglGetRenderBufferANDROID(dpy, eglSurface);
- if (!renderBuffer) {
- ALOGE("%s: eglGetRenderBuffer returned NULL buffer", __FUNCTION__);
- genlock_unlock_buffer(hnd);
- return -1;
- }
- private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle;
+ private_handle_t *fbHandle = (private_handle_t *)renderBuffer;
if(!fbHandle) {
ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__);
- genlock_unlock_buffer(hnd);
return -1;
}
@@ -281,8 +270,6 @@
// this needs to change to accomodate vertical stride
// if needed in the future
src.vert_padding = 0;
- // Remove the srcBufferTransform if any
- layer->transform = (layer->transform & FINAL_TRANSFORM_MASK);
// Copybit source rect
hwc_rect_t sourceCrop = layer->sourceCrop;
@@ -302,9 +289,9 @@
dst.h = fbHandle->height;
dst.format = fbHandle->format;
dst.base = (void *)fbHandle->base;
- dst.handle = (native_handle_t *)renderBuffer->handle;
+ dst.handle = (native_handle_t *)fbHandle;
- copybit_device_t *copybit = ctx->mCopybitEngine->getEngine();
+ copybit_device_t *copybit = mEngine;
int32_t screen_w = displayFrame.right - displayFrame.left;
int32_t screen_h = displayFrame.bottom - displayFrame.top;
@@ -330,7 +317,6 @@
ALOGE("%s: wrong params for display screen_w=%d src_crop_width=%d \
screen_w=%d src_crop_width=%d", __FUNCTION__, screen_w,
src_crop_width,screen_w,src_crop_width);
- genlock_unlock_buffer(hnd);
return -1;
}
@@ -346,7 +332,6 @@
ALOGE("%s: greater than max supported size dsdx=%f dtdy=%f \
scaleLimitMax=%f scaleLimitMin=%f", __FUNCTION__,dsdx,dtdy,
scaleLimitMax,1/scaleLimitMin);
- genlock_unlock_buffer(hnd);
return -1;
}
if(dsdx > copybitsMaxScale ||
@@ -411,7 +396,6 @@
__LINE__);
if(tmpHnd)
free_buffer(tmpHnd);
- genlock_unlock_buffer(hnd);
return err;
}
// copy new src and src rect crop
@@ -431,9 +415,8 @@
layer->transform);
//TODO: once, we are able to read layer alpha, update this
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
- copybit->set_parameter(copybit, COPYBIT_PREMULTIPLIED_ALPHA,
- (layer->blending == HWC_BLENDING_PREMULT)?
- COPYBIT_ENABLE : COPYBIT_DISABLE);
+ copybit->set_parameter(copybit, COPYBIT_BLEND_MODE,
+ layer->blending);
copybit->set_parameter(copybit, COPYBIT_DITHER,
(dst.format == HAL_PIXEL_FORMAT_RGB_565)?
COPYBIT_ENABLE : COPYBIT_DISABLE);
@@ -449,13 +432,6 @@
if(err < 0)
ALOGE("%s: copybit stretch failed",__FUNCTION__);
-
- // Unlock this buffer since copybit is done with it.
- err = genlock_unlock_buffer(hnd);
- if (GENLOCK_FAILURE == err) {
- ALOGE("%s: genlock_unlock_buffer failed", __FUNCTION__);
- }
-
return err;
}
@@ -468,62 +444,41 @@
height = displayFrame.bottom - displayFrame.top;
}
-bool CopyBit::validateParams(hwc_context_t *ctx, const hwc_display_contents_1_t *list) {
- //Validate parameters
- if (!ctx) {
- ALOGE("%s:Invalid HWC context", __FUNCTION__);
- return false;
- } else if (!list) {
- ALOGE("%s:Invalid HWC layer list", __FUNCTION__);
- return false;
- }
-
- framebuffer_device_t *fbDev = ctx->mFbDev;
-
- if (!fbDev) {
- ALOGE("%s:Invalid FB device", __FUNCTION__);
- return false;
- }
-
- if (LINK_eglGetRenderBufferANDROID == NULL ||
- LINK_eglGetCurrentSurface == NULL) {
- ALOGE("%s:Not able to link to ADRENO", __FUNCTION__);
- return false;
- }
-
- return true;
+bool CopyBit::validateParams(hwc_context_t *ctx,
+ const hwc_display_contents_1_t *list) {
+ //Validate parameters
+ if (!ctx) {
+ ALOGE("%s:Invalid HWC context", __FUNCTION__);
+ return false;
+ } else if (!list) {
+ ALOGE("%s:Invalid HWC layer list", __FUNCTION__);
+ return false;
+ }
+ return true;
}
-//CopybitEngine Class functions
-CopybitEngine* CopybitEngine::sInstance = 0;
-struct copybit_device_t* CopybitEngine::getEngine() {
- return sEngine;
-}
-CopybitEngine* CopybitEngine::getInstance() {
- if(sInstance == NULL)
- sInstance = new CopybitEngine();
- return sInstance;
+struct copybit_device_t* CopyBit::getCopyBitDevice() {
+ return mEngine;
}
-CopybitEngine::CopybitEngine(){
+CopyBit::CopyBit():mIsModeOn(false), mCopyBitDraw(false){
hw_module_t const *module;
if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
- copybit_open(module, &sEngine);
- CopyBit::openEglLibAndGethandle();
+ if(copybit_open(module, &mEngine) < 0) {
+ ALOGE("FATAL ERROR: copybit open failed.");
+ }
} else {
- ALOGE("FATAL ERROR: copybit open failed.");
+ ALOGE("FATAL ERROR: copybit hw module not found");
}
}
-CopybitEngine::~CopybitEngine()
+CopyBit::~CopyBit()
{
- if(sEngine)
+ if(mEngine)
{
- CopyBit::closeEglLib();
- copybit_close(sEngine);
- sEngine = NULL;
+ copybit_close(mEngine);
+ mEngine = NULL;
}
}
-
}; //namespace qhwc