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/common.mk b/common.mk
index 99dfbdf..ecf5d66 100644
--- a/common.mk
+++ b/common.mk
@@ -2,6 +2,7 @@
 common_includes := hardware/qcom/display/libgralloc
 common_includes += hardware/qcom/display/libgenlock
 common_includes += hardware/qcom/display/liboverlay
+common_includes += hardware/qcom/display/libcopybit
 common_includes += hardware/qcom/display/libqdutils
 
 ifeq ($(TARGET_USES_POST_PROCESSING),true)
diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp
index 977a3ab..f79c33b 100644
--- a/libcopybit/copybit.cpp
+++ b/libcopybit/copybit.cpp
@@ -60,6 +60,7 @@
     int     mFD;
     uint8_t mAlpha;
     int     mFlags;
+    bool    mBlitToFB;
 };
 
 /**
@@ -212,6 +213,10 @@
     req->alpha = dev->mAlpha;
     req->transp_mask = MDP_TRANSP_NOP;
     req->flags = dev->mFlags | flags;
+    // check if we are blitting to f/b
+    if (COPYBIT_ENABLE == dev->mBlitToFB) {
+        req->flags |= MDP_MEMORY_ID_TYPE_FB;
+    }
 #if defined(COPYBIT_QSD8K)
     req->flags |= MDP_BLEND_FG_PREMULT;
 #endif
@@ -322,6 +327,16 @@
                 ctx->mFlags &= ~0x7;
                 ctx->mFlags |= value & 0x7;
                 break;
+            case COPYBIT_BLIT_TO_FRAMEBUFFER:
+                if (COPYBIT_ENABLE == value) {
+                    ctx->mBlitToFB = value;
+                } else if (COPYBIT_DISABLE == value) {
+                    ctx->mBlitToFB = value;
+                } else {
+                    ALOGE ("%s:Invalid input for COPYBIT_BLIT_TO_FRAMEBUFFER : %d",
+                            __FUNCTION__, value);
+                }
+                break;
             default:
                 status = -EINVAL;
                 break;
diff --git a/libcopybit/copybit.h b/libcopybit/copybit.h
index 6384dfe..c14af74 100644
--- a/libcopybit/copybit.h
+++ b/libcopybit/copybit.h
@@ -52,6 +52,10 @@
 
 /* name for copybit_set_parameter */
 enum {
+    /* Default blit destination is offline buffer */
+    /* clients to set this to '1', if blitting to framebuffer */
+    /* and reset to '0', after calling blit/stretch */
+    COPYBIT_BLIT_TO_FRAMEBUFFER = 0,
     /* rotation of the source image in degrees (0 to 359) */
     COPYBIT_ROTATION_DEG    = 1,
     /* plane alpha value */
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 8e04606..5067a2a 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -6,9 +6,10 @@
 LOCAL_MODULE_TAGS             := optional
 LOCAL_C_INCLUDES              := $(common_includes) $(kernel_includes)
 LOCAL_SHARED_LIBRARIES        := $(common_libs) libEGL liboverlay libgenlock \
-                                 libqdutils libhardware_legacy
+                                 libqdutils libhardware_legacy libdl libmemalloc
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"hwcomposer\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
 LOCAL_SRC_FILES               :=  hwc.cpp hwc_video.cpp hwc_utils.cpp \
-                                  hwc_uimirror.cpp hwc_ext_observer.cpp
+                                  hwc_uimirror.cpp hwc_ext_observer.cpp \
+                                  hwc_copybit.cpp
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 1b1aa86..7826a5f 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -20,11 +20,11 @@
 
 #include <cutils/log.h>
 #include <cutils/atomic.h>
-#include <EGL/egl.h>
 
 #include "hwc_utils.h"
 #include "hwc_video.h"
 #include "hwc_uimirror.h"
+#include "hwc_copybit.h"
 
 using namespace qhwc;
 
@@ -83,7 +83,11 @@
         } else if (0) {
             //Other features
             ctx->overlayInUse = true;
+        } else { // Else set this flag to false, otherwise video cases
+                 // fail in non-overlay targets.
+            ctx->overlayInUse = false;
         }
+        CopyBit::prepare(ctx, list);
     }
 
     return 0;
@@ -98,6 +102,7 @@
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     if (LIKELY(list)) {
         VideoOverlay::draw(ctx, list);
+        CopyBit::draw(ctx, list, (EGLDisplay)dpy, (EGLSurface)sur);
         EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur);
         UIMirrorOverlay::draw(ctx);
     } else {
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,
+                                                   &copybitRegion);
+    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
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
new file mode 100644
index 0000000..adf088b
--- /dev/null
+++ b/libhwcomposer/hwc_copybit.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+#ifndef HWC_COPYBIT_H
+#define HWC_COPYBIT_H
+#include "hwc_utils.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <gralloc_priv.h>
+#include <gr.h>
+#include <dlfcn.h>
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+namespace qhwc {
+//Feature for using Copybit to display RGB layers.
+class CopyBit {
+public:
+    //Sets up members and prepares copybit if conditions are met
+    static bool prepare(hwc_context_t *ctx, hwc_layer_list_t *list);
+    //Draws layer if the layer is set for copybit in prepare
+    static bool draw(hwc_context_t *ctx, hwc_layer_list_t *list, EGLDisplay dpy,
+                                                                EGLSurface sur);
+    //Receives data from hwc
+    static void setStats(int yuvCount, int yuvLayerIndex, bool isYuvLayerSkip);
+
+    static void updateEglHandles(void*);
+    static int  drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_t *layer,
+                                        EGLDisplay dpy, EGLSurface surface,
+        functype_eglGetRenderBufferANDROID& LINK_eglGetRenderBufferANDROID,
+                  functype_eglGetCurrentSurface LINK_eglGetCurrentSurface);
+    static bool canUseCopybit(hwc_context_t* ctx, const hwc_layer_list_t* list,
+                                                      const int numYUVBuffers);
+    static void closeEglLib();
+    static void openEglLibAndGethandle();
+private:
+    //Marks layer flags if this feature is used
+    static void markFlags(hwc_layer_t *layer);
+    //returns yuv count
+    static int getYuvCount();
+
+    //Number of yuv layers in this drawing round
+    static int sYuvCount;
+    //Index of YUV layer, relevant only if count is 1
+    static int sYuvLayerIndex;
+    //Flags if a yuv layer is animating or below something that is animating
+    static bool sIsLayerSkip;
+    //Flags if this feature is on.
+    static bool sIsModeOn;
+    //handle for adreno lib
+    static void* egl_lib;
+
+    static functype_eglGetRenderBufferANDROID LINK_eglGetRenderBufferANDROID;
+    static functype_eglGetCurrentSurface LINK_eglGetCurrentSurface;
+
+    static void getLayerResolution(const hwc_layer_t* layer, int& width,
+                                                           int& height);
+
+};
+
+inline void CopyBit::setStats(int yuvCount, int yuvLayerIndex,
+        bool isYuvLayerSkip) {
+    sYuvCount = yuvCount;
+    sYuvLayerIndex = yuvLayerIndex;
+    sIsLayerSkip = isYuvLayerSkip;
+}
+
+inline int CopyBit::getYuvCount() { return sYuvCount; }
+
+
+}; //namespace qhwc
+
+#endif //HWC_COPYBIT_H
diff --git a/libhwcomposer/hwc_copybitEngine.h b/libhwcomposer/hwc_copybitEngine.h
new file mode 100644
index 0000000..d627e44
--- /dev/null
+++ b/libhwcomposer/hwc_copybitEngine.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+#ifndef HWC_COPYBIT_ENGINE_H
+#define HWC_COPYBIT_ENGINE_H
+
+namespace qhwc {
+class CopybitEngine {
+public:
+    ~CopybitEngine();
+    // API to get copybit engine(non static)
+    struct copybit_device_t *getEngine();
+    // API to get singleton
+    static CopybitEngine* getInstance();
+
+private:
+    CopybitEngine();
+    struct copybit_device_t *sEngine;
+    static CopybitEngine* sInstance; // singleton
+};
+
+}; //namespace qhwc
+
+#endif //HWC_COPYBIT_ENGINE_H
diff --git a/libhwcomposer/hwc_uimirror.cpp b/libhwcomposer/hwc_uimirror.cpp
index f5cf3e6..4540be8 100644
--- a/libhwcomposer/hwc_uimirror.cpp
+++ b/libhwcomposer/hwc_uimirror.cpp
@@ -73,11 +73,11 @@
         overlay::Overlay& ov = *(ctx->mOverlay);
         // Set overlay state
         ov.setState(sState);
-        framebuffer_device_t *fbDev = ctx->fbDev;
+        framebuffer_device_t *fbDev = ctx->mFbDevice->getFb();
         if(fbDev) {
             private_module_t* m = reinterpret_cast<private_module_t*>(
                     fbDev->common.module);
-            int alignedW = ALIGN(m->info.xres, 32);
+            int alignedW = ALIGN_TO(m->info.xres, 32);
 
             private_handle_t const* hnd =
                     reinterpret_cast<private_handle_t const*>(m->framebuffer);
@@ -143,7 +143,7 @@
     overlay::Overlay& ov = *(ctx->mOverlay);
     ovutils::eOverlayState state = ov.getState();
     ovutils::eDest dest = ovutils::OV_PIPE_ALL;
-    framebuffer_device_t *fbDev = ctx->fbDev;
+    framebuffer_device_t *fbDev = ctx->mFbDevice->getFb();
     if(fbDev) {
         private_module_t* m = reinterpret_cast<private_module_t*>(
                               fbDev->common.module);
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index ea2fe66..ae5c526 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -19,11 +19,11 @@
 #include "mdp_version.h"
 #include "hwc_video.h"
 #include "hwc_ext_observer.h"
+#include "hwc_copybit.h"
 namespace qhwc {
 void initContext(hwc_context_t *ctx)
 {
     //XXX: target specific initializations here
-    openFramebufferDevice(ctx);
     ctx->mOverlay = overlay::Overlay::getInstance();
     ctx->qbuf = new QueuedBufferStore();
     ctx->mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
@@ -32,6 +32,9 @@
 
     ctx->mExtDisplayObserver = ExtDisplayObserver::getInstance();
     ctx->mExtDisplayObserver->setHwcContext(ctx);
+    ctx->mFbDevice = FbDevice::getInstance();
+    ctx->mCopybitEngine = CopybitEngine::getInstance();
+    CopyBit::openEglLibAndGethandle();
 }
 
 void closeContext(hwc_context_t *ctx)
@@ -41,23 +44,19 @@
         ctx->mOverlay = NULL;
     }
 
-    if(ctx->fbDev) {
-        framebuffer_close(ctx->fbDev);
-        ctx->fbDev = NULL;
+    if(ctx->mCopybitEngine) {
+        delete ctx->mCopybitEngine;
+        ctx->mCopybitEngine = NULL;
     }
-
+    if(ctx->mFbDevice) {
+        delete ctx->mFbDevice;
+        ctx->mFbDevice = NULL;
+    }
     if(ctx->qbuf) {
         delete ctx->qbuf;
         ctx->qbuf = NULL;
     }
-}
-
-// Opens Framebuffer device
-void openFramebufferDevice(hwc_context_t *ctx) {
-    hw_module_t const *module;
-    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
-        framebuffer_open(module, &(ctx->fbDev));
-    }
+    CopyBit::closeEglLib();
 }
 
 void dumpLayer(hwc_layer_t const* l)
@@ -102,6 +101,7 @@
     }
 
     VideoOverlay::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip);
+    CopyBit::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip);
 
     ctx->numHwLayers = list->numHwLayers;
     return;
@@ -163,4 +163,33 @@
     }
 }
 
+//FbDevice class functions
+FbDevice* FbDevice::sInstance = 0;;
+struct framebuffer_device_t* FbDevice::getFb() {
+   return sFb;
+}
+
+FbDevice* FbDevice::getInstance() {
+   if(sInstance == NULL)
+       sInstance = new FbDevice();
+   return sInstance;
+}
+
+FbDevice::FbDevice(){
+    hw_module_t const *module;
+    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
+        framebuffer_open(module, &sFb);
+    } else {
+       ALOGE("FATAL ERROR: framebuffer open failed.");
+    }
+}
+FbDevice::~FbDevice()
+{
+    if(sFb)
+    {
+       framebuffer_close(sFb);
+       sFb = NULL;
+    }
+}
+
 };//namespace
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 2ee7188..0bf30c9 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -26,16 +26,33 @@
 #include <string.h>
 #include <fb_priv.h>
 #include <overlay.h>
+#include <copybit.h>
+#include <hwc_copybitEngine.h>
 #include <genlock.h>
 #include "hwc_qbuf.h"
+#include <EGL/egl.h>
 
-#define ALIGN(x, align)     (((x) + ((align)-1)) & ~((align)-1))
+#define ALIGN_TO(x, align)     (((x) + ((align)-1)) & ~((align)-1))
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+#define FINAL_TRANSFORM_MASK 0x000F
 
 struct hwc_context_t;
 namespace qhwc {
 
+enum external_display_type {
+    EXT_TYPE_NONE,
+    EXT_TYPE_HDMI,
+    EXT_TYPE_WIFI
+};
+enum HWCCompositionType {
+    HWC_USE_GPU = HWC_FRAMEBUFFER, // This layer is to be handled by
+                                   //                 Surfaceflinger
+    HWC_USE_OVERLAY = HWC_OVERLAY, // This layer is to be handled by the overlay
+    HWC_USE_COPYBIT                // This layer is to be handled by copybit
+};
+
+
 class ExtDisplayObserver;
 // -----------------------------------------------------------------------------
 // Utility functions - implemented in hwc_utils.cpp
@@ -43,7 +60,6 @@
 void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list);
 void initContext(hwc_context_t *ctx);
 void closeContext(hwc_context_t *ctx);
-void openFramebufferDevice(hwc_context_t *ctx);
 //Crops source buffer against destination and FB boundaries
 void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
         const int fbWidth, const int fbHeight);
@@ -62,6 +78,28 @@
 static inline bool isBufferLocked(const private_handle_t* hnd) {
     return (hnd && (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags));
 }
+// -----------------------------------------------------------------------------
+// Copybit specific - inline or implemented in hwc_copybit.cpp
+typedef EGLClientBuffer (*functype_eglGetRenderBufferANDROID) (
+                                                     EGLDisplay dpy,
+                                                    EGLSurface draw);
+typedef EGLSurface (*functype_eglGetCurrentSurface)(EGLint readdraw);
+
+// -----------------------------------------------------------------------------
+// Singleton for Framebuffer device
+class FbDevice{
+public:
+    ~FbDevice();
+    // API to get Fb device(non static)
+    struct framebuffer_device_t *getFb();
+    // API to get singleton
+    static FbDevice* getInstance();
+
+private:
+    FbDevice();
+    struct framebuffer_device_t *sFb;
+    static FbDevice* sInstance; // singleton
+};
 
 }; //qhwc namespace
 
@@ -77,7 +115,10 @@
     int overlayInUse;
 
     //Framebuffer device
-    framebuffer_device_t *fbDev;
+    qhwc::FbDevice* mFbDevice;
+
+    //Copybit Engine
+    qhwc::CopybitEngine* mCopybitEngine;
 
     //Overlay object - NULL for non overlay devices
     overlay::Overlay *mOverlay;
diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp
index 525d662..180ab86 100644
--- a/libhwcomposer/hwc_video.cpp
+++ b/libhwcomposer/hwc_video.cpp
@@ -33,6 +33,10 @@
 //Cache stats, figure out the state, config overlay
 bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) {
     sIsModeOn = false;
+    if(!ctx->hasOverlay) {
+       ALOGD_IF(VIDEO_DEBUG,"%s, this hw doesnt support overlay", __FUNCTION__);
+       return false;
+    }
     chooseState(ctx);
     //if the state chosen above is CLOSED, skip this block.
     if(sState != ovutils::OV_CLOSED) {