display : Add support for copybit composition
This change add support for copybit composition in display HAL
for MDP3 targets.
Change-Id: I9bc8e40f624b0760f4faa223cb03a13695611bb3
Acked-by: Sravan Kumar D.V.N <sravank1@codeaurora.org>
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
new file mode 100644
index 0000000..adcd4dc
--- /dev/null
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hwc_copybit.h"
+#include "hwc_copybitEngine.h"
+
+namespace qhwc {
+
+
+struct range {
+ int current;
+ int end;
+};
+struct region_iterator : public copybit_region_t {
+
+ region_iterator(hwc_region_t region) {
+ mRegion = region;
+ r.end = region.numRects;
+ r.current = 0;
+ this->next = iterate;
+ }
+
+private:
+ static int iterate(copybit_region_t const * self, copybit_rect_t* rect){
+ if (!self || !rect) {
+ ALOGE("iterate invalid parameters");
+ return 0;
+ }
+
+ region_iterator const* me =
+ static_cast<region_iterator const*>(self);
+ if (me->r.current != me->r.end) {
+ rect->l = me->mRegion.rects[me->r.current].left;
+ rect->t = me->mRegion.rects[me->r.current].top;
+ rect->r = me->mRegion.rects[me->r.current].right;
+ rect->b = me->mRegion.rects[me->r.current].bottom;
+ me->r.current++;
+ return 1;
+ }
+ return 0;
+ }
+
+ hwc_region_t mRegion;
+ 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::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;
+ }
+}
+
+bool CopyBit::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) {
+ for (int i=list->numHwLayers-1; i >= 0 ; i--) {
+ private_handle_t *hnd =
+ (private_handle_t *)list->hwLayers[i].handle;
+ if (isSkipLayer(&list->hwLayers[i])) {
+ break;
+ } else if(canUseCopybit(ctx, list, getYuvCount())
+ && !ctx->overlayInUse){
+ list->hwLayers[i].compositionType = HWC_USE_COPYBIT;
+ } else {
+ list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
+ }
+ }
+ return true;
+}
+bool CopyBit::draw(hwc_context_t *ctx, hwc_layer_list_t *list, EGLDisplay dpy,
+ EGLSurface sur){
+ for (size_t i=0; i<list->numHwLayers; i++) {
+ if (list->hwLayers[i].flags & HWC_SKIP_LAYER) {
+ continue;
+ } else if (list->hwLayers[i].compositionType == HWC_USE_COPYBIT) {
+ drawLayerUsingCopybit(ctx, &(list->hwLayers[i]),
+ (EGLDisplay)dpy,
+ (EGLSurface)sur,
+ LINK_eglGetRenderBufferANDROID,
+ LINK_eglGetCurrentSurface);
+ }
+ }
+ return true;
+}
+
+int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_t *layer,
+ EGLDisplay dpy,
+ EGLSurface surface,
+ functype_eglGetRenderBufferANDROID& LINK_eglGetRenderBufferANDROID,
+ functype_eglGetCurrentSurface LINK_eglGetCurrentSurface)
+{
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ if(!ctx) {
+ ALOGE("%s: null context ", __FUNCTION__);
+ return -1;
+ }
+
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!hnd) {
+ ALOGE("%s: invalid handle", __FUNCTION__);
+ 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;
+ if(!fbHandle) {
+ ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__);
+ genlock_unlock_buffer(hnd);
+ return -1;
+ }
+
+ // Set the copybit source:
+ copybit_image_t src;
+ src.w = hnd->width;
+ src.h = hnd->height;
+ src.format = hnd->format;
+ src.base = (void *)hnd->base;
+ src.handle = (native_handle_t *)layer->handle;
+ src.horiz_padding = src.w - hnd->width;
+ // Initialize vertical padding to zero for now,
+ // 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;
+ copybit_rect_t srcRect = {sourceCrop.left, sourceCrop.top,
+ sourceCrop.right,
+ sourceCrop.bottom};
+
+ // Copybit destination rect
+ hwc_rect_t displayFrame = layer->displayFrame;
+ copybit_rect_t dstRect = {displayFrame.left, displayFrame.top,
+ displayFrame.right,
+ displayFrame.bottom};
+
+ // Copybit dst
+ copybit_image_t dst;
+ dst.w = ALIGN(fbHandle->width,32);
+ dst.h = fbHandle->height;
+ dst.format = fbHandle->format;
+ dst.base = (void *)fbHandle->base;
+ dst.handle = (native_handle_t *)renderBuffer->handle;
+
+ copybit_device_t *copybit = ctx->mCopybitEngine->getEngine();
+
+ int32_t screen_w = displayFrame.right - displayFrame.left;
+ int32_t screen_h = displayFrame.bottom - displayFrame.top;
+ int32_t src_crop_width = sourceCrop.right - sourceCrop.left;
+ int32_t src_crop_height = sourceCrop.bottom -sourceCrop.top;
+
+ // Copybit dst
+ float copybitsMaxScale =
+ (float)copybit->get(copybit,COPYBIT_MAGNIFICATION_LIMIT);
+ float copybitsMinScale =
+ (float)copybit->get(copybit,COPYBIT_MINIFICATION_LIMIT);
+
+ if((layer->transform == HWC_TRANSFORM_ROT_90) ||
+ (layer->transform == HWC_TRANSFORM_ROT_270)) {
+ //swap screen width and height
+ int tmp = screen_w;
+ screen_w = screen_h;
+ screen_h = tmp;
+ }
+ private_handle_t *tmpHnd = NULL;
+
+ if(screen_w <=0 || screen_h<=0 ||src_crop_width<=0 || src_crop_height<=0 ) {
+ 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;
+ }
+
+ float dsdx = (float)screen_w/src_crop_width;
+ float dtdy = (float)screen_h/src_crop_height;
+
+ float scaleLimitMax = copybitsMaxScale * copybitsMaxScale;
+ float scaleLimitMin = copybitsMinScale * copybitsMinScale;
+ if(dsdx > scaleLimitMax ||
+ dtdy > scaleLimitMax ||
+ dsdx < 1/scaleLimitMin ||
+ dtdy < 1/scaleLimitMin) {
+ 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 ||
+ dtdy > copybitsMaxScale ||
+ dsdx < 1/copybitsMinScale ||
+ dtdy < 1/copybitsMinScale){
+ // The requested scale is out of the range the hardware
+ // can support.
+ ALOGE("%s:%d::Need to scale twice dsdx=%f, dtdy=%f,copybitsMaxScale=%f,\
+ copybitsMinScale=%f,screen_w=%d,screen_h=%d \
+ src_crop_width=%d src_crop_height=%d",__FUNCTION__,__LINE__,
+ dsdx,dtdy,copybitsMaxScale,1/copybitsMinScale,screen_w,screen_h,
+ src_crop_width,src_crop_height);
+
+ //Driver makes width and height as even
+ //that may cause wrong calculation of the ratio
+ //in display and crop.Hence we make
+ //crop width and height as even.
+ src_crop_width = (src_crop_width/2)*2;
+ src_crop_height = (src_crop_height/2)*2;
+
+ int tmp_w = src_crop_width;
+ int tmp_h = src_crop_height;
+
+ if (dsdx > copybitsMaxScale || dtdy > copybitsMaxScale ){
+ tmp_w = src_crop_width*copybitsMaxScale;
+ tmp_h = src_crop_height*copybitsMaxScale;
+ }else if (dsdx < 1/copybitsMinScale ||dtdy < 1/copybitsMinScale ){
+ tmp_w = src_crop_width/copybitsMinScale;
+ tmp_h = src_crop_height/copybitsMinScale;
+ tmp_w = (tmp_w/2)*2;
+ tmp_h = (tmp_h/2)*2;
+ }
+ ALOGE("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h);
+
+ int usage = GRALLOC_USAGE_PRIVATE_MM_HEAP;
+
+ if (0 == alloc_buffer(&tmpHnd, tmp_w, tmp_h, fbHandle->format, usage)){
+ copybit_image_t tmp_dst;
+ copybit_rect_t tmp_rect;
+ tmp_dst.w = tmp_w;
+ tmp_dst.h = tmp_h;
+ tmp_dst.format = tmpHnd->format;
+ tmp_dst.handle = tmpHnd;
+ tmp_dst.horiz_padding = src.horiz_padding;
+ tmp_dst.vert_padding = src.vert_padding;
+ tmp_rect.l = 0;
+ tmp_rect.t = 0;
+ tmp_rect.r = tmp_dst.w;
+ tmp_rect.b = tmp_dst.h;
+ //create one clip region
+ hwc_rect tmp_hwc_rect = {0,0,tmp_rect.r,tmp_rect.b};
+ hwc_region_t tmp_hwc_reg = {1,(hwc_rect_t const*)&tmp_hwc_rect};
+ region_iterator tmp_it(tmp_hwc_reg);
+ copybit->set_parameter(copybit,COPYBIT_TRANSFORM,0);
+ // TODO : alpha not defined , fix this
+ // copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA,
+ // (layer->blending == HWC_BLENDING_NONE) ? -1 : layer->alpha);
+ err = copybit->stretch(copybit,&tmp_dst, &src, &tmp_rect,
+ &srcRect, &tmp_it);
+ if(err < 0){
+ ALOGE("%s:%d::tmp copybit stretch failed",__FUNCTION__,
+ __LINE__);
+ if(tmpHnd)
+ free_buffer(tmpHnd);
+ genlock_unlock_buffer(hnd);
+ return err;
+ }
+ // copy new src and src rect crop
+ src = tmp_dst;
+ srcRect = tmp_rect;
+ }
+ }
+ // Copybit region
+ hwc_region_t region = layer->visibleRegionScreen;
+ region_iterator copybitRegion(region);
+
+ copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH,
+ renderBuffer->width);
+ copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT,
+ renderBuffer->height);
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM,
+ layer->transform);
+ // TODO : alpha not defined , fix this
+ // copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA,
+ // (layer->blending == HWC_BLENDING_NONE) ? -1 : layer->alpha);
+ copybit->set_parameter(copybit, COPYBIT_PREMULTIPLIED_ALPHA,
+ (layer->blending == HWC_BLENDING_PREMULT)?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ (dst.format == HAL_PIXEL_FORMAT_RGB_565)?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+ copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,
+ COPYBIT_ENABLE);
+ err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect,
+ ©bitRegion);
+ copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,
+ COPYBIT_DISABLE);
+
+ if(tmpHnd)
+ free_buffer(tmpHnd);
+
+ 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;
+}
+
+void CopyBit::getLayerResolution(const hwc_layer_t* layer, int& width,
+ int& height)
+{
+ hwc_rect_t displayFrame = layer->displayFrame;
+
+ width = displayFrame.right - displayFrame.left;
+ height = displayFrame.bottom - displayFrame.top;
+}
+
+bool CopyBit::canUseCopybit(hwc_context_t *ctx, const hwc_layer_list_t* list,
+ const int numYUVBuffers)
+{
+ // XXX : TODO , currently returning false for MDP4 targets,
+ // This has to be modified after adding C2D support.
+ if(ctx->hasOverlay)
+ return false;
+
+ framebuffer_device_t* fbDev = ctx->mFbDevice->getFb();
+ if(!fbDev) {
+ ALOGE("ERROR: canUseCopybit : fb device is invalid");
+ return false;
+ }
+
+ if (!list)
+ return false;
+
+ // If , couldnt link to adreno library return false.
+ if(LINK_eglGetRenderBufferANDROID == NULL ||
+ LINK_eglGetCurrentSurface == NULL )
+ return false;
+
+ if(!ctx->hasOverlay) {
+ if (numYUVBuffers)
+ return true;
+ }
+
+ int fb_w = fbDev->width;
+ int fb_h = fbDev->height;
+
+ /*
+ * Use copybit only when we need to blit
+ * max 2 full screen sized regions
+ */
+
+ unsigned int renderArea = 0;
+
+ for(unsigned int i = 0; i < list->numHwLayers; i++ ) {
+ int w, h;
+ getLayerResolution(&list->hwLayers[i], w, h);
+ renderArea += w*h;
+ }
+
+ return (renderArea <= (2 * fb_w * fb_h));
+}
+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);
+}
+
+
+
+//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;
+}
+
+CopybitEngine::CopybitEngine(){
+ hw_module_t const *module;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &sEngine);
+ } else {
+ ALOGE("FATAL ERROR: copybit open failed.");
+ }
+}
+CopybitEngine::~CopybitEngine()
+{
+ if(sEngine)
+ {
+ copybit_close(sEngine);
+ sEngine = NULL;
+ }
+}
+
+}; //namespace qhwc