libcopybit: Merge copybit HAL from jb

Single commit having all the following commits

commit f39e512ad6f51cf35ab00995e52a39f31e76e77f
Author: Naomi Luis <nluis@codeaurora.org>
Date:   Fri Oct 19 14:41:32 2012 -0700

    copybit_c2d: Use a single draw call for surfaces with different rotations

    - When opening the copybit module, query the c2d driver capabilities.
    - If supported, use a single draw call for blitting surfaces with different
    orientations using the target target rotate override flag.
    - If not supported, invoke finish_copybit to draw the layers with the
    previous orientation before applying the current orientation.

    Change-Id: I0446f2817786321c9caa2eabf7b6679e5ecbcabe

commit a4008ff75150c1591c0dca46354e6bb8b30a675b
Author: Naomi Luis <nluis@codeaurora.org>
Date:   Thu Oct 18 15:26:15 2012 -0700

    Display: Add copybit_c2d performance optimizations

    Following performance optimizations have been made to copybit_c2d
    - Club all the layers into a single draw call. When finish_copybit
    is invoked, the draw and finish are executed.
    - Send the layer blend mode to copybit.
    - If the blend is set to none, set the pre-multiplied alpha flag.
    SurfaceFlinger assumes all surfaces have pre-multiplied alpha unless
    explicitly specified. Copybit_c2d does the same.

    The following cases are currently exempt from this optimization:
    - Change in C2D target
    - The template surfaces limit has been reached
    - Max. blit object limit has been reached.
    - Change in target transform.
    - Use of any temporary source/destination surfaces.

    Change-Id: I5ad1dc48bbe6d38d319116ccaa800fefb4fbf9f6

commit b188d739f69272c4820e1a33c5e10aa2f2825a5f
Author: Naomi Luis <nluis@codeaurora.org>
Date:   Mon Oct 15 11:17:11 2012 -0700

    copybit: Add finish API

    Add the finish API to copybit. This API is used to indicate the
    end of the drawing required by the copybit client.

    Change-Id: Ica4d13dbe6e7aeb7f88aabb734bf03e86c043acc

commit ecd56ace395fce78c14e2e753d3221218d062899
Author: Naomi Luis <nluis@codeaurora.org>
Date:   Mon Oct 15 11:21:08 2012 -0700

    copybit: Clean up copybit_c2d

    - Remove unused functions
    - Do nothing for the COPYBIT_BLIT_TO_FRAMEBUFFER case when using c2d
    composition.

    Change-Id: Idc416ce3742bb41f060e52ac70add44e584032b9

commit 35d45d0cff5f6fe866fcb5df71444824a45e046e
Author: Naomi Luis <nluis@codeaurora.org>
Date:   Wed Oct 17 10:37:33 2012 -0700

    copybit: Use correct alignment in get_size()

    get_size() is used to get the size required by c2d. It's alignment
    should be 32 and not 16.

    Change-Id: I9fedca0186d0ea19883b967e127417b059621a99

commit 31311da328cbe2229fcf8d8d8e276ec64005bcb3
Author: Ramakant Singh <ramaka@codeaurora.org>
Date:   Thu Sep 20 15:58:29 2012 +0530

    HWC: use uncached buffer for tmp yv12 and tmp stretch buffer.

    Change-Id: Iecc2a9c3c9a365d00d3491ce1007a36484209346
    CRs-fixed: 396574

commit 5503c90b5001aa4d863139eebcd9c0c43f265702
Author: Pawan Kumar <pavaku@codeaurora.org>
Date:   Mon Sep 3 09:14:13 2012 +0530

    copybit: Fix crash when copy_image is called with Tile format

    Add check for copy_image failure case.
    CRs-Fixed: 393122

    Change-Id: I5765120e87a135795d771c5d331275a66ade7e23

commit 48975bc53702ecba66ecaa5e5769036bb91f5cf2
Merge: feb1cd6 ab25cb4
Author: Linux Build Service Account <lnxbuild@localhost>
Date:   Sat Sep 1 13:36:47 2012 -0700

    Merge "Display ::Use proper ion heap id" into jb

commit ab25cb4818d9b87886678972f2861bacc93c580a
Author: Ramakant Singh <ramaka@codeaurora.org>
Date:   Thu Aug 9 14:23:39 2012 +0530

    Display ::Use proper ion heap id

    Change the MM heap to CAMERA heap for 7627a in use case
    1.Intermediate stretch of low resolution clips
    2.Software conversion of Y12 format

    Change-Id: Ib705d3245f601256179e2dedccbc707df85eb431
    CRs-Fixed: 383115

commit 90bcaadf41451d89fe80f96961ffc0a07a333145
Author: Prabhanjan Kandula <pkandula@codeaurora.org>
Date:   Mon Aug 6 12:50:12 2012 +0530

    libcopybit: fix YUV buffer alignments as per gralloc

    buffer alignment in copybit should be in sync with
    gralloc allignments while allocating buffer.

    CRs-fixed: 377051
    Change-Id: Ib2ae64e368ea3c92d3494c71da605197ccb4a9a5

    Conflicts:

        libcopybit/copybit_c2d.cpp

commit 95cf0038ea6eb02314024d673418464f0739ddb4
Author: Sravan Kumar D.V.N <sravank1@codeaurora.org>
Date:   Thu Aug 2 14:37:37 2012 +0530

    copybit : Add support for NV12_ENCODABLE format

    Change-Id: I7087dcad2238a3c35cc15c28d75b76a9e3ca6718

Change-Id: I748bffb4215d27f609beec209af0a5047858a314
diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp
index ea5dd2a..6cda9a5 100644
--- a/libcopybit/copybit_c2d.cpp
+++ b/libcopybit/copybit_c2d.cpp
@@ -1,6 +1,9 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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.
@@ -76,10 +79,12 @@
 
 C2D_STATUS (*LINK_c2dDestroySurface)( uint32 surface_id );
 
-C2D_STATUS (*LINK_c2dMapAddr) ( int mem_fd, void * hostptr, uint32 len, uint32 offset, uint32 flags, void ** gpuaddr);
+C2D_STATUS (*LINK_c2dMapAddr) ( int mem_fd, void * hostptr, uint32 len,
+                                uint32 offset, uint32 flags, void ** gpuaddr);
 
 C2D_STATUS (*LINK_c2dUnMapAddr) ( void * gpuaddr);
 
+C2D_STATUS (*LINK_c2dGetDriverCapabilities) ( C2D_DRIVER_INFO * driver_info);
 /******************************************************************************/
 
 #if defined(COPYBIT_Z180)
@@ -89,7 +94,15 @@
 #error "Unsupported HW version"
 #endif
 
-#define NUM_SURFACES 3
+// The following defines can be changed as required i.e. as we encounter
+// complex use cases.
+#define MAX_RGB_SURFACES 8        // Max. RGB layers currently supported per draw
+#define MAX_YUV_2_PLANE_SURFACES 4// Max. 2-plane YUV layers currently supported per draw
+#define MAX_YUV_3_PLANE_SURFACES 1// Max. 3-plane YUV layers currently supported per draw
+// +1 for the destination surface. We cannot have multiple destination surfaces.
+#define MAX_SURFACES (MAX_RGB_SURFACES + MAX_YUV_2_PLANE_SURFACES + MAX_YUV_3_PLANE_SURFACES + 1)
+#define NUM_SURFACE_TYPES 3      // RGB_SURFACE + YUV_SURFACE_2_PLANES + YUV_SURFACE_3_PLANES
+#define MAX_BLIT_OBJECT_COUNT 50 // Max. blit objects that can be passed per draw
 
 enum {
     RGB_SURFACE,
@@ -103,8 +116,9 @@
 };
 
 enum eC2DFlags {
-    FLAGS_PREMULTIPLIED_ALPHA = 1<<0,
-    FLAGS_YUV_DESTINATION     = 1<<1
+    FLAGS_PREMULTIPLIED_ALPHA  = 1<<0,
+    FLAGS_YUV_DESTINATION      = 1<<1,
+    FLAGS_TEMP_SRC_DST         = 1<<2
 };
 
 static gralloc::IAllocController* sAlloc = 0;
@@ -113,22 +127,29 @@
 /** State information for each device instance */
 struct copybit_context_t {
     struct copybit_device_t device;
-    unsigned int src[NUM_SURFACES];  /* src surfaces */
-    unsigned int dst[NUM_SURFACES];  /* dst surfaces */
-    unsigned int trg_transform;      /* target transform */
-    C2D_OBJECT blitState;
+    // Templates for the various source surfaces. These templates are created
+    // to avoid the expensive create/destroy C2D Surfaces
+    C2D_OBJECT_STR blit_rgb_object[MAX_RGB_SURFACES];
+    C2D_OBJECT_STR blit_yuv_2_plane_object[MAX_YUV_2_PLANE_SURFACES];
+    C2D_OBJECT_STR blit_yuv_3_plane_object[MAX_YUV_3_PLANE_SURFACES];
+    C2D_OBJECT_STR blit_list[MAX_BLIT_OBJECT_COUNT]; // Z-ordered list of blit objects
+    C2D_DRIVER_INFO c2d_driver_info;
     void *libc2d2;
     alloc_data temp_src_buffer;
     alloc_data temp_dst_buffer;
+    unsigned int dst[NUM_SURFACE_TYPES]; // dst surfaces
+    unsigned int mapped_gpu_addr[MAX_SURFACES]; // GPU addresses mapped inside copybit
+    int blit_rgb_count;         // Total RGB surfaces being blit
+    int blit_yuv_2_plane_count; // Total 2 plane YUV surfaces being
+    int blit_yuv_3_plane_count; // Total 3 plane YUV  surfaces being blit
+    int blit_count;             // Total blit objects.
+    unsigned int trg_transform;      /* target transform */
     int fb_width;
     int fb_height;
-    bool isPremultipliedAlpha;
-    bool mBlitToFB;
-};
-
-struct blitlist{
-    uint32_t count;
-    C2D_OBJECT blitObjects[12];
+    int src_global_alpha;
+    int config_mask;
+    int dst_surface_type;
+    bool is_premultiplied_alpha;
 };
 
 struct bufferInfo {
@@ -189,7 +210,9 @@
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:   return C2D_COLOR_FORMAT_420_NV21;
         case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: return C2D_COLOR_FORMAT_420_NV12 |
                                                   C2D_FORMAT_MACROTILED;
-        default:                              ALOGE("%s: invalid format (0x%x", __FUNCTION__, format); return -EINVAL;
+        default:                              ALOGE("%s: invalid format (0x%x",
+                                                     __FUNCTION__, format);
+                                              return -EINVAL;
     }
     return -EINVAL;
 }
@@ -201,7 +224,7 @@
         case HAL_PIXEL_FORMAT_RGBX_8888:      return C2D_COLOR_FORMAT_8888_ARGB |
                                               C2D_FORMAT_DISABLE_ALPHA;
         case HAL_PIXEL_FORMAT_RGBA_8888:      return C2D_COLOR_FORMAT_8888_ARGB;
-                                              // The U and V need to be interchanged when the target is YUV
+        // The U and V need to be interchanged when the target is YUV
         case HAL_PIXEL_FORMAT_YCbCr_420_SP:   return C2D_COLOR_FORMAT_420_NV21;
         case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:return C2D_COLOR_FORMAT_420_NV21;
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:   return C2D_COLOR_FORMAT_420_NV12;
@@ -251,7 +274,8 @@
     return c2dBpp;
 }
 
-static uint32 c2d_get_gpuaddr( struct private_handle_t *handle)
+static uint32 c2d_get_gpuaddr(copybit_context_t* ctx, struct private_handle_t *handle,
+                              int &mapped_idx)
 {
     uint32 memtype, *gpuaddr;
     C2D_STATUS rc;
@@ -271,13 +295,36 @@
         return 0;
     }
 
-    rc = LINK_c2dMapAddr(handle->fd, (void*)handle->base, handle->size, handle->offset, memtype, (void**)&gpuaddr);
+    rc = LINK_c2dMapAddr(handle->fd, (void*)handle->base, handle->size,
+                                      handle->offset, memtype, (void**)&gpuaddr);
+
     if (rc == C2D_STATUS_OK) {
+        // We have mapped the GPU address inside copybit. We need to unmap this
+        // address after the blit. Store this address
+        for (int i = 0; i < MAX_SURFACES; i++) {
+            if (ctx->mapped_gpu_addr[i] == 0) {
+                ctx->mapped_gpu_addr[i] = (uint32) gpuaddr;
+                mapped_idx = i;
+                break;
+            }
+        }
+
         return (uint32) gpuaddr;
     }
     return 0;
 }
 
+static void unmap_gpuaddr(copybit_context_t* ctx, int mapped_idx)
+{
+    if (!ctx || (mapped_idx == -1))
+        return;
+
+    if (ctx->mapped_gpu_addr[mapped_idx]) {
+        LINK_c2dUnMapAddr( (void*)ctx->mapped_gpu_addr[mapped_idx]);
+        ctx->mapped_gpu_addr[mapped_idx] = 0;
+    }
+}
+
 static int is_supported_rgb_format(int format)
 {
     switch(format) {
@@ -379,20 +426,24 @@
 }
 
 /** create C2D surface from copybit image */
-static int set_image( uint32 surfaceId, const struct copybit_image_t *rhs,
-                      int *cformat, uint32_t *mapped, const eC2DFlags flags)
+static int set_image(copybit_context_t* ctx, uint32 surfaceId,
+                      const struct copybit_image_t *rhs,
+                      const eC2DFlags flags, int &mapped_idx)
 {
     struct private_handle_t* handle = (struct private_handle_t*)rhs->handle;
     C2D_SURFACE_TYPE surfaceType;
     int status = COPYBIT_SUCCESS;
+    uint32 gpuaddr = 0;
+    int c2d_format;
+    mapped_idx = -1;
 
     if (flags & FLAGS_YUV_DESTINATION) {
-        *cformat = get_c2d_format_for_yuv_destination(rhs->format);
+        c2d_format = get_c2d_format_for_yuv_destination(rhs->format);
     } else {
-        *cformat = get_format(rhs->format);
+        c2d_format = get_format(rhs->format);
     }
 
-    if(*cformat == -EINVAL) {
+    if(c2d_format == -EINVAL) {
         ALOGE("%s: invalid format", __FUNCTION__);
         return -EINVAL;
     }
@@ -403,12 +454,13 @@
     }
 
     if (handle->gpuaddr == 0) {
-        handle->gpuaddr = c2d_get_gpuaddr(handle);
-        if(!handle->gpuaddr) {
+        gpuaddr = c2d_get_gpuaddr(ctx, handle, mapped_idx);
+        if(!gpuaddr) {
             ALOGE("%s: c2d_get_gpuaddr failed", __FUNCTION__);
             return COPYBIT_FAILURE;
         }
-        *mapped = 1;
+    } else {
+        gpuaddr = handle->gpuaddr;
     }
 
     /* create C2D surface */
@@ -418,26 +470,27 @@
 
         surfaceType = (C2D_SURFACE_TYPE) (C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS);
 
-        surfaceDef.phys = (void*) handle->gpuaddr;
+        surfaceDef.phys = (void*) gpuaddr;
         surfaceDef.buffer = (void*) (handle->base);
 
-        surfaceDef.format = *cformat |
+        surfaceDef.format = c2d_format |
             ((flags & FLAGS_PREMULTIPLIED_ALPHA) ? C2D_FORMAT_PREMULTIPLIED : 0);
         surfaceDef.width = rhs->w;
         surfaceDef.height = rhs->h;
         int aligned_width = ALIGN(surfaceDef.width,32);
         surfaceDef.stride = (aligned_width * c2diGetBpp(surfaceDef.format))>>3;
 
-        if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType, &surfaceDef)) {
+        if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType,
+                                  &surfaceDef)) {
             ALOGE("%s: RGB Surface c2dUpdateSurface ERROR", __FUNCTION__);
-            goto error;
+            unmap_gpuaddr(ctx, mapped_idx);
             status = COPYBIT_FAILURE;
         }
     } else if (is_supported_yuv_format(rhs->format) == COPYBIT_SUCCESS) {
         C2D_YUV_SURFACE_DEF surfaceDef;
         memset(&surfaceDef, 0, sizeof(surfaceDef));
         surfaceType = (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS);
-        surfaceDef.format = *cformat;
+        surfaceDef.format = c2d_format;
 
         bufferInfo info;
         info.width = rhs->w;
@@ -448,199 +501,88 @@
         status = calculate_yuv_offset_and_stride(info, yuvInfo);
         if(status != COPYBIT_SUCCESS) {
             ALOGE("%s: calculate_yuv_offset_and_stride error", __FUNCTION__);
-            goto error;
+            unmap_gpuaddr(ctx, mapped_idx);
         }
 
         surfaceDef.width = rhs->w;
         surfaceDef.height = rhs->h;
         surfaceDef.plane0 = (void*) (handle->base);
-        surfaceDef.phys0 = (void*) (handle->gpuaddr);
+        surfaceDef.phys0 = (void*) (gpuaddr);
         surfaceDef.stride0 = yuvInfo.yStride;
 
         surfaceDef.plane1 = (void*) (handle->base + yuvInfo.plane1_offset);
-        surfaceDef.phys1 = (void*) (handle->gpuaddr + yuvInfo.plane1_offset);
+        surfaceDef.phys1 = (void*) (gpuaddr + yuvInfo.plane1_offset);
         surfaceDef.stride1 = yuvInfo.plane1_stride;
         if (3 == get_num_planes(rhs->format)) {
             surfaceDef.plane2 = (void*) (handle->base + yuvInfo.plane2_offset);
-            surfaceDef.phys2 = (void*) (handle->gpuaddr + yuvInfo.plane2_offset);
+            surfaceDef.phys2 = (void*) (gpuaddr + yuvInfo.plane2_offset);
             surfaceDef.stride2 = yuvInfo.plane2_stride;
         }
 
         if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType,
                                   &surfaceDef)) {
             ALOGE("%s: YUV Surface c2dUpdateSurface ERROR", __FUNCTION__);
-            goto error;
+            unmap_gpuaddr(ctx, mapped_idx);
             status = COPYBIT_FAILURE;
         }
     } else {
         ALOGE("%s: invalid format 0x%x", __FUNCTION__, rhs->format);
-        goto error;
+        unmap_gpuaddr(ctx, mapped_idx);
         status = COPYBIT_FAILURE;
     }
 
     return status;
-
-error:
-    if(*mapped == 1) {
-        LINK_c2dUnMapAddr( (void*) handle->gpuaddr);
-        handle->gpuaddr = 0;
-        *mapped = 0;
-    }
-    return status;
 }
 
-static int set_src_image( uint32 *surfaceId, const struct copybit_image_t *rhs,
-                          int *cformat, uint32 *mapped)
+/** copy the bits */
+static int msm_copybit(struct copybit_context_t *ctx, unsigned int target)
 {
-    struct private_handle_t* handle = (struct private_handle_t*)rhs->handle;
-    *cformat  = get_format(rhs->format);
-    C2D_SURFACE_TYPE surfaceType;
-    uint32 gpuaddr = (uint32)handle->gpuaddr;
-    int status = COPYBIT_SUCCESS;
-
-    if (handle->gpuaddr == 0)
-    {
-        handle->gpuaddr = c2d_get_gpuaddr( handle);
-        if(!handle->gpuaddr)
-            return COPYBIT_FAILURE;
-
-        *mapped = 1;
+    if (ctx->blit_count == 0) {
+        return COPYBIT_SUCCESS;
     }
 
-    /* create C2D surface */
-    if(is_supported_rgb_format(rhs->format) == COPYBIT_SUCCESS) {
-        /* RGB */
-        C2D_RGB_SURFACE_DEF surfaceDef;
-        surfaceType = (C2D_SURFACE_TYPE) (C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY);
+    for (int i = 0; i < ctx->blit_count; i++)
+    {
+        ctx->blit_list[i].next = &(ctx->blit_list[i+1]);
+    }
 
-        surfaceDef.phys = (void*) handle->gpuaddr;
-        surfaceDef.buffer = (void*) (handle->base);
-        surfaceDef.buffer = (void*) (handle->base + handle->offset);
-
-        surfaceDef.format = get_format(rhs->format);
-        surfaceDef.width = rhs->w;
-        surfaceDef.height = rhs->h;
-        surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32);
-
-        if(LINK_c2dCreateSurface( surfaceId, C2D_TARGET, surfaceType,(void*)&surfaceDef)) {
-            ALOGE("%s: LINK_c2dCreateSurface error", __FUNCTION__);
-            status = COPYBIT_FAILURE;
-            goto error;
-        }
-    } else if(is_supported_yuv_format(rhs->format) == COPYBIT_SUCCESS) {
-        /* YUV */
-        C2D_YUV_SURFACE_DEF surfaceDef;
-        int offset = 0;
-        int yStride = 0;
-        int uvStride = 0;
-        memset(&surfaceDef, 0, sizeof(surfaceDef));
-
-        surfaceType = (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY);
-        surfaceDef.format = get_format(rhs->format);
-        bufferInfo info;
-        info.width = rhs->w;
-        info.height = rhs->h;
-        info.format = rhs->format;
-
-        yuvPlaneInfo yuvInfo;
-        status = calculate_yuv_offset_and_stride(info, yuvInfo);
-        if(status != COPYBIT_SUCCESS) {
-            ALOGE("%s: calculate_yuv_offset_and_stride error", __FUNCTION__);
-            goto error;
-        }
-
-        surfaceDef.width = rhs->w;
-        surfaceDef.height = rhs->h;
-        surfaceDef.plane0 = (void*) (handle->base);
-        surfaceDef.phys0 = (void*) handle->gpuaddr;
-        surfaceDef.stride0 = yuvInfo.yStride;
-
-        surfaceDef.plane1 = (void*) (handle->base + yuvInfo.plane1_offset);
-        surfaceDef.phys1 = (void*) (handle->gpuaddr + yuvInfo.plane1_offset);
-        surfaceDef.stride1 = yuvInfo.plane1_stride;
-
-        if(LINK_c2dCreateSurface( surfaceId, C2D_TARGET | C2D_SOURCE, surfaceType,
-                                  (void*)&surfaceDef)) {
-            ALOGE("%s: YUV surface LINK_c2dCreateSurface error", __func__);
-            status = COPYBIT_FAILURE;
-            goto error;
-        }
-    } else {
-        ALOGE("%s: Invalid format 0x%x", __FUNCTION__, rhs->format);
-        status = COPYBIT_FAILURE;
+    ctx->blit_list[ctx->blit_count-1].next = NULL;
+    if(LINK_c2dDraw(target,ctx->trg_transform, 0x0, 0, 0, ctx->blit_list,
+                    ctx->blit_count)) {
+        ALOGE("%s: LINK_c2dDraw ERROR", __FUNCTION__);
+        return COPYBIT_FAILURE;
     }
 
     return COPYBIT_SUCCESS;
-
-error:
-    if(*mapped == 1) {
-        LINK_c2dUnMapAddr( (void*) handle->gpuaddr);
-        handle->gpuaddr = 0;
-        *mapped = 0;
-    }
-    return status;
 }
 
-void unset_image( uint32 surfaceId, const struct copybit_image_t *rhs,
-                  uint32 mmapped)
+
+static int finish_copybit(struct copybit_device_t *dev)
 {
-    struct private_handle_t* handle = (struct private_handle_t*)rhs->handle;
+    struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+    if (!ctx)
+        return COPYBIT_FAILURE;
 
-    if (mmapped && handle->gpuaddr) {
-        // Unmap this gpuaddr
-        LINK_c2dUnMapAddr( (void*) handle->gpuaddr);
-        handle->gpuaddr = 0;
-    }
-}
+   int status = msm_copybit(ctx, ctx->dst[ctx->dst_surface_type]);
 
-static int blit_to_target( uint32 surfaceId, const struct copybit_image_t *rhs)
-{
-    struct private_handle_t* handle = (struct private_handle_t*)rhs->handle;
-    uint32 cformat  = get_format(rhs->format);
-    C2D_SURFACE_TYPE surfaceType;
-    uint32 memoryMapped = 0;
-    int status = COPYBIT_SUCCESS;
-
-    if (!handle->gpuaddr) {
-        handle->gpuaddr = c2d_get_gpuaddr(handle);
-        if(!handle->gpuaddr)
-            return COPYBIT_FAILURE;
-
-        memoryMapped = 1;
+   if(LINK_c2dFinish(ctx->dst[ctx->dst_surface_type])) {
+        ALOGE("%s: LINK_c2dFinish ERROR", __FUNCTION__);
+        return COPYBIT_FAILURE;
     }
 
-    /* create C2D surface */
-
-    if(cformat) {
-        /* RGB */
-        C2D_RGB_SURFACE_DEF surfaceDef;
-        memset(&surfaceDef, 0, sizeof(surfaceDef));
-
-        surfaceDef.buffer = (void*) handle->base;
-        surfaceDef.phys = (void*) handle->gpuaddr;
-
-        surfaceType = C2D_SURFACE_RGB_HOST;
-        surfaceDef.format = get_format(rhs->format);
-        surfaceDef.width = rhs->w;
-        surfaceDef.height = rhs->h;
-        surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32);
-
-        if(LINK_c2dReadSurface(surfaceId, surfaceType, (void*)&surfaceDef, 0, 0)) {
-            ALOGE("%s: LINK_c2dReadSurface ERROR", __func__);
-            status = COPYBIT_FAILURE;
-            goto done;
+    // Unmap any mapped addresses.
+    for (int i = 0; i < MAX_SURFACES; i++) {
+        if (ctx->mapped_gpu_addr[i]) {
+            LINK_c2dUnMapAddr( (void*)ctx->mapped_gpu_addr[i]);
+            ctx->mapped_gpu_addr[i] = 0;
         }
     }
-    else {
-        /* YUV */
-        /* TODO */
-    }
 
-done:
-    if (memoryMapped) {
-        LINK_c2dUnMapAddr( (void*) handle->gpuaddr);
-        handle->gpuaddr = 0;
-    }
+    // Reset the counts after the draw.
+    ctx->blit_rgb_count = 0;
+    ctx->blit_yuv_2_plane_count = 0;
+    ctx->blit_yuv_3_plane_count = 0;
+    ctx->blit_count = 0;
     return status;
 }
 
@@ -696,24 +638,6 @@
     c2dObject->config_mask |= C2D_SCISSOR_RECT_BIT;
 }
 
-/** copy the bits */
-static int msm_copybit(struct copybit_context_t *dev, blitlist *list, uint32 target)
-{
-    unsigned int objects;
-
-    for(objects = 0; objects < list->count; objects++) {
-        list->blitObjects[objects].next = &(list->blitObjects[objects+1]);
-    }
-
-    if(LINK_c2dDraw(target,dev->trg_transform, 0x0, 0, 0, list->blitObjects,
-                    list->count)) {
-        ALOGE("%s: LINK_c2dDraw ERROR", __FUNCTION__);
-        return COPYBIT_FAILURE;
-    }
-
-    return COPYBIT_SUCCESS;
-}
-
 /*****************************************************************************/
 
 /** Set a parameter to value */
@@ -729,67 +653,79 @@
     }
 
     switch(name) {
-        case COPYBIT_ROTATION_DEG:
-            ctx->blitState.rotation = value<<16;
-            /* SRC rotation */
-            if(!value)
-                ctx->blitState.config_mask &=~C2D_ROTATE_BIT;;
-            break;
         case COPYBIT_PLANE_ALPHA:
+        {
             if (value < 0)      value = 0;
             if (value >= 256)   value = 255;
 
-            ctx->blitState.global_alpha = value;
-
-            if(ctx->blitState.global_alpha<255)
-                ctx->blitState.config_mask |= C2D_GLOBAL_ALPHA_BIT;
+            ctx->src_global_alpha = value;
+            if (value < 255)
+                ctx->config_mask |= C2D_GLOBAL_ALPHA_BIT;
             else
-                ctx->blitState.config_mask &=~C2D_GLOBAL_ALPHA_BIT;
-            break;
-        case COPYBIT_DITHER:
-            /* TODO */
-            break;
-        case COPYBIT_BLUR:
-            /* TODO */
-            break;
-        case COPYBIT_TRANSFORM:
-            ctx->blitState.config_mask &=~C2D_ROTATE_BIT;
-            ctx->blitState.config_mask &=~C2D_MIRROR_H_BIT;
-            ctx->blitState.config_mask &=~C2D_MIRROR_V_BIT;
-            ctx->trg_transform = C2D_TARGET_ROTATE_0;
-
-            if((value&0x7) == COPYBIT_TRANSFORM_ROT_180)
-                ctx->trg_transform = C2D_TARGET_ROTATE_180;
-            else if((value&0x7) == COPYBIT_TRANSFORM_ROT_270)
-                ctx->trg_transform = C2D_TARGET_ROTATE_90;
-            else {
-                if(value&COPYBIT_TRANSFORM_FLIP_H)
-                    ctx->blitState.config_mask |= C2D_MIRROR_H_BIT;
-                if(value&COPYBIT_TRANSFORM_FLIP_V)
-                    ctx->blitState.config_mask |= C2D_MIRROR_V_BIT;
-                if(value&COPYBIT_TRANSFORM_ROT_90)
-                    ctx->trg_transform = C2D_TARGET_ROTATE_270;
+                ctx->config_mask &= ~C2D_GLOBAL_ALPHA_BIT;
+        }
+        break;
+        case COPYBIT_BLEND_MODE:
+        {
+            if (value == COPYBIT_BLENDING_NONE) {
+                ctx->config_mask |= C2D_ALPHA_BLEND_NONE;
+                ctx->is_premultiplied_alpha = true;
+            } else if (value == COPYBIT_BLENDING_PREMULT) {
+                ctx->is_premultiplied_alpha = true;
+            } else {
+                ctx->config_mask &= ~C2D_ALPHA_BLEND_NONE;
             }
-            break;
-        case COPYBIT_PREMULTIPLIED_ALPHA:
-            (value == COPYBIT_ENABLE) ? ctx->isPremultipliedAlpha = true :
-                ctx->isPremultipliedAlpha = false;
-            break;
+        }
+        break;
+        case COPYBIT_TRANSFORM:
+        {
+            unsigned int transform = 0;
+            uint32 config_mask = 0;
+            config_mask |= C2D_OVERRIDE_GLOBAL_TARGET_ROTATE_CONFIG;
+            if((value & 0x7) == COPYBIT_TRANSFORM_ROT_180) {
+                transform = C2D_TARGET_ROTATE_180;
+                config_mask |= C2D_OVERRIDE_TARGET_ROTATE_180;
+            } else if((value & 0x7) == COPYBIT_TRANSFORM_ROT_270) {
+                transform = C2D_TARGET_ROTATE_90;
+                config_mask |= C2D_OVERRIDE_TARGET_ROTATE_90;
+            } else if(value == COPYBIT_TRANSFORM_ROT_90) {
+                transform = C2D_TARGET_ROTATE_270;
+                config_mask |= C2D_OVERRIDE_TARGET_ROTATE_270;
+            } else {
+                config_mask |= C2D_OVERRIDE_TARGET_ROTATE_0;
+                if(value & COPYBIT_TRANSFORM_FLIP_H) {
+                    config_mask |= C2D_MIRROR_H_BIT;
+                } else if(value & COPYBIT_TRANSFORM_FLIP_V) {
+                    config_mask |= C2D_MIRROR_V_BIT;
+                }
+            }
+
+            if (transform != ctx->trg_transform) {
+                if (ctx->c2d_driver_info.capabilities_mask &
+                    C2D_DRIVER_SUPPORTS_OVERRIDE_TARGET_ROTATE_OP) {
+                    ctx->config_mask |= config_mask;
+                } else {
+                    // The transform for this surface does not match the current
+                    // target transform. Draw all previous surfaces. This will be
+                    // changed once we have a new mechanism to send different
+                    // target rotations to c2d.
+                    finish_copybit(dev);
+                }
+            }
+            ctx->trg_transform = transform;
+        }
+        break;
         case COPYBIT_FRAMEBUFFER_WIDTH:
             ctx->fb_width = value;
             break;
         case COPYBIT_FRAMEBUFFER_HEIGHT:
             ctx->fb_height = value;
             break;
+        case COPYBIT_ROTATION_DEG:
+        case COPYBIT_DITHER:
+        case COPYBIT_BLUR:
         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);
-            }
+            // Do nothing
             break;
         default:
             ALOGE("%s: default case param=0x%x", __FUNCTION__, name);
@@ -898,14 +834,14 @@
             {
                 // Chroma for this format is aligned to 2K.
                 size = ALIGN((aligned_w*h), 2048) +
-                    ALIGN(w/2, 32) * h/2 *2;
+                        ALIGN(aligned_w/2, 32) * (h/2) *2;
                 size = ALIGN(size, 4096);
             } break;
         case HAL_PIXEL_FORMAT_YCbCr_420_SP:
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
             {
-                size = aligned_w*h +
-                    ALIGN(w/2, 32) * h/2 *2;
+                size = aligned_w * h +
+                       ALIGN(aligned_w/2, 32) * (h/2) * 2;
                 size = ALIGN(size, 4096);
             } break;
         default: break;
@@ -998,6 +934,19 @@
         handle = 0;
     }
 }
+
+static bool need_to_execute_draw(struct copybit_context_t* ctx,
+                                          eC2DFlags flags)
+{
+    if (flags & FLAGS_TEMP_SRC_DST) {
+        return true;
+    }
+    if (flags & FLAGS_YUV_DESTINATION) {
+        return true;
+    }
+    return false;
+}
+
 /** do a stretch blit type operation */
 static int stretch_copybit_internal(
     struct copybit_device_t *dev,
@@ -1010,14 +959,10 @@
 {
     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
     int status = COPYBIT_SUCCESS;
-    uint32 maxCount;
-    uint32 src_mapped = 0, trg_mapped = 0;
-    blitlist list;
-    C2D_OBJECT *req;
-    memset(&list, 0, sizeof(list));
-    int cformat;
-    c2d_ts_handle timestamp;
-    uint32 src_surface_index = 0, dst_surface_index = 0;
+    int flags = 0;
+    int src_surface_type;
+    int mapped_src_idx = -1, mapped_dst_idx = -1;
+    C2D_OBJECT_STR src_surface;
 
     if (!ctx) {
         ALOGE("%s: null context error", __FUNCTION__);
@@ -1030,40 +975,54 @@
     }
 
     if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) {
-        ALOGE("%s : dst dimension error dst w %d h %d",  __FUNCTION__, dst->w, dst->h);
+        ALOGE("%s : dst dimension error dst w %d h %d",  __FUNCTION__, dst->w,
+                                                         dst->h);
         return -EINVAL;
     }
 
-    maxCount = sizeof(list.blitObjects)/sizeof(C2D_OBJECT);
-
-    struct copybit_rect_t clip;
-    list.count = 0;
-
     if (is_valid_destination_format(dst->format) == COPYBIT_FAILURE) {
-        ALOGE("%s: Invalid destination format format = 0x%x", __FUNCTION__, dst->format);
+        ALOGE("%s: Invalid destination format format = 0x%x", __FUNCTION__,
+                                                              dst->format);
         return COPYBIT_FAILURE;
     }
 
-    bool isYUVDestination = false;
+    int dst_surface_type;
     if (is_supported_rgb_format(dst->format) == COPYBIT_SUCCESS) {
-        dst_surface_index = RGB_SURFACE;
+        dst_surface_type = RGB_SURFACE;
+        flags |= FLAGS_PREMULTIPLIED_ALPHA;
     } else if (is_supported_yuv_format(dst->format) == COPYBIT_SUCCESS) {
-        isYUVDestination = true;
         int num_planes = get_num_planes(dst->format);
+        flags |= FLAGS_YUV_DESTINATION;
         if (num_planes == 2) {
-            dst_surface_index = YUV_SURFACE_2_PLANES;
+            dst_surface_type = YUV_SURFACE_2_PLANES;
         } else if (num_planes == 3) {
-            dst_surface_index = YUV_SURFACE_3_PLANES;
+            dst_surface_type = YUV_SURFACE_3_PLANES;
         } else {
             ALOGE("%s: dst number of YUV planes is invalid dst format = 0x%x",
                   __FUNCTION__, dst->format);
             return COPYBIT_FAILURE;
         }
     } else {
-        ALOGE("%s: Invalid dst surface format 0x%x", __FUNCTION__, dst->format);
+        ALOGE("%s: Invalid dst surface format 0x%x", __FUNCTION__,
+                                                     dst->format);
         return COPYBIT_FAILURE;
     }
 
+    if (ctx->blit_rgb_count == MAX_RGB_SURFACES ||
+        ctx->blit_yuv_2_plane_count == MAX_YUV_2_PLANE_SURFACES ||
+        ctx->blit_yuv_3_plane_count == MAX_YUV_2_PLANE_SURFACES ||
+        ctx->blit_count == MAX_BLIT_OBJECT_COUNT ||
+        ctx->dst_surface_type != dst_surface_type) {
+        // we have reached the max. limits of our internal structures or
+        // changed the target.
+        // Draw the remaining surfaces. We need to do the finish here since
+        // we need to free up the surface templates.
+        finish_copybit(dev);
+    }
+
+    ctx->dst_surface_type = dst_surface_type;
+
+    // Update the destination
     copybit_image_t dst_image;
     dst_image.w = dst->w;
     dst_image.h = dst->h;
@@ -1072,7 +1031,7 @@
     // Check if we need a temp. copy for the destination. We'd need this the destination
     // width is not aligned to 32. This case occurs for YUV formats. RGB formats are
     // aligned to 32.
-    bool needTempDestination = need_temp_buffer(dst);
+    bool need_temp_dst = need_temp_buffer(dst);
     bufferInfo dst_info;
     populate_buffer_info(dst, dst_info);
     private_handle_t* dst_hnd = new private_handle_t(-1, 0, 0, 0, dst_info.format,
@@ -1081,7 +1040,7 @@
         ALOGE("%s: dst_hnd is null", __FUNCTION__);
         return COPYBIT_FAILURE;
     }
-    if (needTempDestination) {
+    if (need_temp_dst) {
         if (get_size(dst_info) != ctx->temp_dst_buffer.size) {
             free_temp_buffer(ctx->temp_dst_buffer);
             // Create a temp buffer and set that as the destination.
@@ -1100,35 +1059,40 @@
         dst_image.handle = dst_hnd;
     }
 
-    int flags = 0;
-    flags |= (ctx->isPremultipliedAlpha) ? FLAGS_PREMULTIPLIED_ALPHA : 0;
-    flags |= (isYUVDestination) ? FLAGS_YUV_DESTINATION : 0;
-
-    status = set_image( ctx->dst[dst_surface_index], &dst_image,
-                        &cformat, &trg_mapped, (eC2DFlags)flags);
+    status = set_image(ctx, ctx->dst[ctx->dst_surface_type], &dst_image,
+                       (eC2DFlags)flags, mapped_dst_idx);
     if(status) {
         ALOGE("%s: dst: set_image error", __FUNCTION__);
         delete_handle(dst_hnd);
+        unmap_gpuaddr(ctx, mapped_dst_idx);
         return COPYBIT_FAILURE;
     }
 
+    // Update the source
+    flags = 0;
     if(is_supported_rgb_format(src->format) == COPYBIT_SUCCESS) {
-        src_surface_index = RGB_SURFACE;
+        src_surface_type = RGB_SURFACE;
+        src_surface = ctx->blit_rgb_object[ctx->blit_rgb_count];
     } else if (is_supported_yuv_format(src->format) == COPYBIT_SUCCESS) {
         int num_planes = get_num_planes(src->format);
         if (num_planes == 2) {
-            src_surface_index = YUV_SURFACE_2_PLANES;
+            src_surface_type = YUV_SURFACE_2_PLANES;
+            src_surface = ctx->blit_yuv_2_plane_object[ctx->blit_yuv_2_plane_count];
         } else if (num_planes == 3) {
-            src_surface_index = YUV_SURFACE_3_PLANES;
+            src_surface_type = YUV_SURFACE_3_PLANES;
+            src_surface = ctx->blit_yuv_3_plane_object[ctx->blit_yuv_2_plane_count];
         } else {
             ALOGE("%s: src number of YUV planes is invalid src format = 0x%x",
                   __FUNCTION__, src->format);
             delete_handle(dst_hnd);
+            unmap_gpuaddr(ctx, mapped_dst_idx);
             return -EINVAL;
         }
     } else {
-        ALOGE("%s: Invalid source surface format 0x%x", __FUNCTION__, src->format);
+        ALOGE("%s: Invalid source surface format 0x%x", __FUNCTION__,
+                                                        src->format);
         delete_handle(dst_hnd);
+        unmap_gpuaddr(ctx, mapped_dst_idx);
         return -EINVAL;
     }
 
@@ -1138,24 +1102,27 @@
     src_image.format = src->format;
     src_image.handle = src->handle;
 
-    bool needTempSource = need_temp_buffer(src);
+    bool need_temp_src = need_temp_buffer(src);
     bufferInfo src_info;
     populate_buffer_info(src, src_info);
     private_handle_t* src_hnd = new private_handle_t(-1, 0, 0, 0, src_info.format,
-                                                     src_info.width, src_info.height);
+                                                 src_info.width, src_info.height);
     if (NULL == src_hnd) {
         ALOGE("%s: src_hnd is null", __FUNCTION__);
         delete_handle(dst_hnd);
+        unmap_gpuaddr(ctx, mapped_dst_idx);
         return COPYBIT_FAILURE;
     }
-    if (needTempSource) {
+    if (need_temp_src) {
         if (get_size(src_info) != ctx->temp_src_buffer.size) {
             free_temp_buffer(ctx->temp_src_buffer);
             // Create a temp buffer and set that as the destination.
-            if (COPYBIT_SUCCESS != get_temp_buffer(src_info, ctx->temp_src_buffer)) {
+            if (COPYBIT_SUCCESS != get_temp_buffer(src_info,
+                                               ctx->temp_src_buffer)) {
                 ALOGE("%s: get_temp_buffer(src) failed", __FUNCTION__);
                 delete_handle(dst_hnd);
                 delete_handle(src_hnd);
+                unmap_gpuaddr(ctx, mapped_dst_idx);
                 return COPYBIT_FAILURE;
             }
         }
@@ -1168,7 +1135,15 @@
         src_image.handle = src_hnd;
 
         // Copy the source.
-        copy_image((private_handle_t *)src->handle, &src_image, CONVERT_TO_C2D_FORMAT);
+        status = copy_image((private_handle_t *)src->handle, &src_image,
+                                CONVERT_TO_C2D_FORMAT);
+        if (status == COPYBIT_FAILURE) {
+            ALOGE("%s:copy_image failed in temp source",__FUNCTION__);
+            delete_handle(dst_hnd);
+            delete_handle(src_hnd);
+            unmap_gpuaddr(ctx, mapped_dst_idx);
+            return status;
+        }
 
         // Flush the cache
         IMemAlloc* memalloc = sAlloc->getAllocator(src_hnd->flags);
@@ -1177,70 +1152,90 @@
             ALOGE("%s: clean_buffer failed", __FUNCTION__);
             delete_handle(dst_hnd);
             delete_handle(src_hnd);
+            unmap_gpuaddr(ctx, mapped_dst_idx);
             return COPYBIT_FAILURE;
         }
     }
 
-    status = set_image( ctx->src[src_surface_index], &src_image,
-                        &cformat, &src_mapped, (eC2DFlags)flags);
+    flags |= (ctx->is_premultiplied_alpha) ? FLAGS_PREMULTIPLIED_ALPHA : 0;
+    flags |= (ctx->dst_surface_type != RGB_SURFACE) ? FLAGS_YUV_DESTINATION : 0;
+    status = set_image(ctx, src_surface.surface_id, &src_image,
+                       (eC2DFlags)flags, mapped_src_idx);
     if(status) {
-        ALOGE("%s: set_src_image error", __FUNCTION__);
+        ALOGE("%s: set_image (src) error", __FUNCTION__);
         delete_handle(dst_hnd);
         delete_handle(src_hnd);
+        unmap_gpuaddr(ctx, mapped_dst_idx);
+        unmap_gpuaddr(ctx, mapped_src_idx);
         return COPYBIT_FAILURE;
     }
 
+    src_surface.config_mask = C2D_NO_BILINEAR_BIT | C2D_NO_ANTIALIASING_BIT |
+                              ctx->config_mask;
+    src_surface.global_alpha = ctx->src_global_alpha;
     if (enableBlend) {
-        if(ctx->blitState.config_mask & C2D_GLOBAL_ALPHA_BIT) {
-            ctx->blitState.config_mask &= ~C2D_ALPHA_BLEND_NONE;
-            if(!(ctx->blitState.global_alpha)) {
+        if(src_surface.config_mask & C2D_GLOBAL_ALPHA_BIT) {
+            src_surface.config_mask &= ~C2D_ALPHA_BLEND_NONE;
+            if(!(src_surface.global_alpha)) {
                 // src alpha is zero
-                unset_image( ctx->src[src_surface_index],
-                             &src_image, src_mapped);
-                unset_image( ctx->dst[dst_surface_index],
-                             &dst_image, trg_mapped);
                 delete_handle(dst_hnd);
                 delete_handle(src_hnd);
-                return status;
+                unmap_gpuaddr(ctx, mapped_dst_idx);
+                unmap_gpuaddr(ctx, mapped_src_idx);
+                return COPYBIT_FAILURE;
             }
         } else {
-            if(is_alpha(cformat))
-                ctx->blitState.config_mask &= ~C2D_ALPHA_BLEND_NONE;
+            int c2d_format = get_format(src->format);
+            if(is_alpha(c2d_format))
+                src_surface.config_mask &= ~C2D_ALPHA_BLEND_NONE;
             else
-                ctx->blitState.config_mask |= C2D_ALPHA_BLEND_NONE;
+                src_surface.config_mask |= C2D_ALPHA_BLEND_NONE;
         }
     } else {
-        ctx->blitState.config_mask |= C2D_ALPHA_BLEND_NONE;
+        src_surface.config_mask |= C2D_ALPHA_BLEND_NONE;
     }
 
-    ctx->blitState.surface_id = ctx->src[src_surface_index];
+    if (src_surface_type == RGB_SURFACE) {
+        ctx->blit_rgb_object[ctx->blit_rgb_count] = src_surface;
+        ctx->blit_rgb_count++;
+    } else if (src_surface_type == YUV_SURFACE_2_PLANES) {
+        ctx->blit_yuv_2_plane_object[ctx->blit_yuv_2_plane_count] = src_surface;
+        ctx->blit_yuv_2_plane_count++;
+    } else {
+        ctx->blit_yuv_3_plane_object[ctx->blit_yuv_3_plane_count] = src_surface;
+        ctx->blit_yuv_3_plane_count++;
+    }
 
+    struct copybit_rect_t clip;
     while ((status == 0) && region->next(region, &clip)) {
-        req = &(list.blitObjects[list.count]);
-        memcpy(req,&ctx->blitState,sizeof(C2D_OBJECT));
-
-        set_rects(ctx, req, dst_rect, src_rect, &clip);
-
-        if (++list.count == maxCount) {
-            status = msm_copybit(ctx, &list, ctx->dst[dst_surface_index]);
-            list.count = 0;
+        set_rects(ctx, &(src_surface), dst_rect, src_rect, &clip);
+        if (ctx->blit_count == MAX_BLIT_OBJECT_COUNT) {
+            ALOGW("Reached end of blit count");
+            finish_copybit(dev);;
         }
-    }
-    if ((status == 0) && list.count) {
-        status = msm_copybit(ctx, &list, ctx->dst[dst_surface_index]);
+        ctx->blit_list[ctx->blit_count] = src_surface;
+        ctx->blit_count++;
     }
 
-    if(LINK_c2dFinish(ctx->dst[dst_surface_index])) {
-        ALOGE("%s: LINK_c2dFinish ERROR", __FUNCTION__);
+    // Check if we need to perform an early draw-finish.
+    flags |= (need_temp_dst || need_temp_src) ? FLAGS_TEMP_SRC_DST : 0;
+    if (need_to_execute_draw(ctx, (eC2DFlags)flags))
+    {
+        finish_copybit(dev);
     }
 
-    unset_image( ctx->src[src_surface_index], &src_image,
-                 src_mapped);
-    unset_image( ctx->dst[dst_surface_index], &dst_image,
-                 trg_mapped);
-    if (needTempDestination) {
-        // copy the temp. destination without the alignment to the actual destination.
-        copy_image(dst_hnd, dst, CONVERT_TO_ANDROID_FORMAT);
+    if (need_temp_dst) {
+        // copy the temp. destination without the alignment to the actual
+        // destination.
+        status = copy_image(dst_hnd, dst, CONVERT_TO_ANDROID_FORMAT);
+        if (status == COPYBIT_FAILURE) {
+            ALOGE("%s:copy_image failed in temp Dest",__FUNCTION__);
+            delete_handle(dst_hnd);
+            delete_handle(src_hnd);
+            unmap_gpuaddr(ctx, mapped_dst_idx);
+            unmap_gpuaddr(ctx, mapped_src_idx);
+            return status;
+        }
         // Invalidate the cache.
         IMemAlloc* memalloc = sAlloc->getAllocator(dst_hnd->flags);
         memalloc->clean_buffer((void *)(dst_hnd->base), dst_hnd->size,
@@ -1248,12 +1243,15 @@
     }
     delete_handle(dst_hnd);
     delete_handle(src_hnd);
-    ctx->isPremultipliedAlpha = false;
+
+    ctx->is_premultiplied_alpha = false;
     ctx->fb_width = 0;
     ctx->fb_height = 0;
+    ctx->config_mask = 0;
     return status;
 }
 
+
 static int stretch_copybit(
     struct copybit_device_t *dev,
     struct copybit_image_t const *dst,
@@ -1263,7 +1261,7 @@
     struct copybit_region_t const *region)
 {
     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
-    bool needsBlending = (ctx->blitState.global_alpha != 0);
+    bool needsBlending = (ctx->src_global_alpha != 0);
     return stretch_copybit_internal(dev, dst, src, dst_rect, src_rect,
                                     region, needsBlending);
 }
@@ -1282,26 +1280,48 @@
 
 /*****************************************************************************/
 
+static void clean_up(copybit_context_t* ctx)
+{
+    if (!ctx)
+        return;
+
+    for (int i = 0; i < NUM_SURFACE_TYPES; i++) {
+        if (ctx->dst[i])
+            LINK_c2dDestroySurface(ctx->dst[i]);
+    }
+
+    for (int i = 0; i < MAX_RGB_SURFACES; i++) {
+        if (ctx->blit_rgb_object[i].surface_id)
+            LINK_c2dDestroySurface(ctx->blit_rgb_object[i].surface_id);
+    }
+
+    for (int i = 0; i < MAX_YUV_2_PLANE_SURFACES; i++) {
+        if (ctx->blit_yuv_2_plane_object[i].surface_id)
+            LINK_c2dDestroySurface(ctx->blit_yuv_2_plane_object[i].surface_id);
+    }
+
+    for (int i = 0; i < MAX_YUV_3_PLANE_SURFACES; i++) {
+        if (ctx->blit_yuv_3_plane_object[i].surface_id)
+            LINK_c2dDestroySurface(ctx->blit_yuv_3_plane_object[i].surface_id);
+    }
+
+    if (ctx->libc2d2) {
+        ::dlclose(ctx->libc2d2);
+        ALOGV("dlclose(libc2d2)");
+    }
+
+    free(ctx);
+}
+
 /** Close the copybit device */
 static int close_copybit(struct hw_device_t *dev)
 {
     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
     if (ctx) {
-        for(int i = 0; i <NUM_SURFACES; i++) {
-            LINK_c2dDestroySurface(ctx->dst[i]);
-            LINK_c2dDestroySurface(ctx->src[i]);
-        }
-
-        if (ctx->libc2d2) {
-            ::dlclose(ctx->libc2d2);
-            ALOGV("dlclose(libc2d2)");
-        }
-
         free_temp_buffer(ctx->temp_src_buffer);
         free_temp_buffer(ctx->temp_dst_buffer);
-        free(ctx);
     }
-
+    clean_up(ctx);
     return 0;
 }
 
@@ -1323,16 +1343,13 @@
 
     /* initialize drawstate */
     memset(ctx, 0, sizeof(*ctx));
-
-    for (int i=0; i< NUM_SURFACES; i++) {
-        ctx->dst[i] = -1;
-        ctx->src[i] = -1;
-    }
-
     ctx->libc2d2 = ::dlopen("libC2D2.so", RTLD_NOW);
     if (!ctx->libc2d2) {
         ALOGE("FATAL ERROR: could not dlopen libc2d2.so: %s", dlerror());
-        goto error;
+        clean_up(ctx);
+        status = COPYBIT_FAILURE;
+        *device = NULL;
+        return status;
     }
     *(void **)&LINK_c2dCreateSurface = ::dlsym(ctx->libc2d2,
                                                "c2dCreateSurface");
@@ -1351,12 +1368,18 @@
                                          "c2dMapAddr");
     *(void **)&LINK_c2dUnMapAddr = ::dlsym(ctx->libc2d2,
                                            "c2dUnMapAddr");
+    *(void **)&LINK_c2dGetDriverCapabilities = ::dlsym(ctx->libc2d2,
+                                           "c2dGetDriverCapabilities");
 
     if (!LINK_c2dCreateSurface || !LINK_c2dUpdateSurface || !LINK_c2dReadSurface
-        || !LINK_c2dDraw || !LINK_c2dFlush || !LINK_c2dWaitTimestamp || !LINK_c2dFinish
-        || !LINK_c2dDestroySurface) {
+        || !LINK_c2dDraw || !LINK_c2dFlush || !LINK_c2dWaitTimestamp ||
+        !LINK_c2dFinish  || !LINK_c2dDestroySurface ||
+        !LINK_c2dGetDriverCapabilities) {
         ALOGE("%s: dlsym ERROR", __FUNCTION__);
-        goto error;
+        clean_up(ctx);
+        status = COPYBIT_FAILURE;
+        *device = NULL;
+        return status;
     }
 
     ctx->device.common.tag = HARDWARE_DEVICE_TAG;
@@ -1367,8 +1390,7 @@
     ctx->device.get = get;
     ctx->device.blit = blit_copybit;
     ctx->device.stretch = stretch_copybit;
-    ctx->blitState.config_mask = C2D_NO_BILINEAR_BIT | C2D_NO_ANTIALIASING_BIT;
-    ctx->trg_transform = C2D_TARGET_ROTATE_0;
+    ctx->device.finish = finish_copybit;
 
     /* Create RGB Surface */
     surfDefinition.buffer = (void*)0xdddddddd;
@@ -1379,24 +1401,45 @@
     surfDefinition.format = C2D_COLOR_FORMAT_8888_ARGB;
     if (LINK_c2dCreateSurface(&(ctx->dst[RGB_SURFACE]), C2D_TARGET | C2D_SOURCE,
                               (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST |
-                                                 C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY ), &surfDefinition)) {
-        ALOGE("%s: create ctx->dst[RGB_SURFACE] failed", __FUNCTION__);
-        ctx->dst[RGB_SURFACE] = -1;
-        goto error;
+                                                 C2D_SURFACE_WITH_PHYS |
+                                                 C2D_SURFACE_WITH_PHYS_DUMMY ),
+                                                 &surfDefinition)) {
+        ALOGE("%s: create ctx->dst_surface[RGB_SURFACE] failed", __FUNCTION__);
+        ctx->dst[RGB_SURFACE] = 0;
+        clean_up(ctx);
+        status = COPYBIT_FAILURE;
+        *device = NULL;
+        return status;
     }
 
-
-    if (LINK_c2dCreateSurface(&(ctx->src[RGB_SURFACE]), C2D_TARGET | C2D_SOURCE,
+    unsigned int surface_id = 0;
+    for (int i = 0; i < MAX_RGB_SURFACES; i++)
+    {
+        if (LINK_c2dCreateSurface(&surface_id, C2D_TARGET | C2D_SOURCE,
                               (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST |
-                                                 C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), &surfDefinition)) {
-        ALOGE("%s: create ctx->src[RGB_SURFACE] failed", __FUNCTION__);
-        ctx->src[RGB_SURFACE] = -1;
-        goto error;
+                                                 C2D_SURFACE_WITH_PHYS |
+                                                 C2D_SURFACE_WITH_PHYS_DUMMY ),
+                                                 &surfDefinition)) {
+            ALOGE("%s: create RGB source surface %d failed", __FUNCTION__, i);
+            ctx->blit_rgb_object[i].surface_id = 0;
+            status = COPYBIT_FAILURE;
+            break;
+        } else {
+            ctx->blit_rgb_object[i].surface_id = surface_id;
+            ALOGW("%s i = %d surface_id=%d",  __FUNCTION__, i,
+                                          ctx->blit_rgb_object[i].surface_id);
+        }
     }
 
-    /* Create YUV source surface */
-    yuvSurfaceDef.format = C2D_COLOR_FORMAT_420_NV12;
+    if (status == COPYBIT_FAILURE) {
+        clean_up(ctx);
+        status = COPYBIT_FAILURE;
+        *device = NULL;
+        return status;
+    }
 
+    // Create 2 plane YUV surfaces
+    yuvSurfaceDef.format = C2D_COLOR_FORMAT_420_NV12;
     yuvSurfaceDef.width = 4;
     yuvSurfaceDef.height = 4;
     yuvSurfaceDef.plane0 = (void*)0xaaaaaaaa;
@@ -1406,48 +1449,101 @@
     yuvSurfaceDef.plane1 = (void*)0xaaaaaaaa;
     yuvSurfaceDef.phys1 = (void*) 0xaaaaaaaa;
     yuvSurfaceDef.stride1 = 4;
-
-    if (LINK_c2dCreateSurface(&(ctx->src[YUV_SURFACE_2_PLANES]),
-                              C2D_TARGET | C2D_SOURCE,
-                              (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST|C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY),
-                              &yuvSurfaceDef)) {
-        ALOGE("%s: create ctx->src[YUV_SURFACE_2_PLANES] failed", __FUNCTION__);
-        ctx->src[YUV_SURFACE_2_PLANES] = -1;
-        goto error;
-    }
-
     if (LINK_c2dCreateSurface(&(ctx->dst[YUV_SURFACE_2_PLANES]),
                               C2D_TARGET | C2D_SOURCE,
-                              (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY),
+                              (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST |
+                               C2D_SURFACE_WITH_PHYS |
+                               C2D_SURFACE_WITH_PHYS_DUMMY),
                               &yuvSurfaceDef)) {
         ALOGE("%s: create ctx->dst[YUV_SURFACE_2_PLANES] failed", __FUNCTION__);
-        ctx->dst[YUV_SURFACE_2_PLANES] = -1;
-        goto error;
+        ctx->dst[YUV_SURFACE_2_PLANES] = 0;
+        clean_up(ctx);
+        status = COPYBIT_FAILURE;
+        *device = NULL;
+        return status;
     }
 
+    for (int i=0; i < MAX_YUV_2_PLANE_SURFACES; i++)
+    {
+        if (LINK_c2dCreateSurface(&surface_id, C2D_TARGET | C2D_SOURCE,
+                              (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST |
+                                                 C2D_SURFACE_WITH_PHYS |
+                                                 C2D_SURFACE_WITH_PHYS_DUMMY ),
+                              &yuvSurfaceDef)) {
+            ALOGE("%s: create YUV source %d failed", __FUNCTION__, i);
+            ctx->blit_yuv_2_plane_object[i].surface_id = 0;
+            status = COPYBIT_FAILURE;
+            break;
+        } else {
+            ctx->blit_yuv_2_plane_object[i].surface_id = surface_id;
+            ALOGW("%s: 2 Plane YUV i=%d surface_id=%d",  __FUNCTION__, i,
+                                   ctx->blit_yuv_2_plane_object[i].surface_id);
+        }
+    }
+
+    if (status == COPYBIT_FAILURE) {
+        clean_up(ctx);
+        status = COPYBIT_FAILURE;
+        *device = NULL;
+        return status;
+    }
+
+    // Create YUV 3 plane surfaces
     yuvSurfaceDef.format = C2D_COLOR_FORMAT_420_YV12;
     yuvSurfaceDef.plane2 = (void*)0xaaaaaaaa;
     yuvSurfaceDef.phys2 = (void*) 0xaaaaaaaa;
     yuvSurfaceDef.stride2 = 4;
 
-    if (LINK_c2dCreateSurface(&(ctx->src[YUV_SURFACE_3_PLANES]),
-                              C2D_TARGET | C2D_SOURCE,
-                              (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY),
-                              &yuvSurfaceDef)) {
-        ALOGE("%s: create ctx->src[YUV_SURFACE_3_PLANES] failed", __FUNCTION__);
-        ctx->src[YUV_SURFACE_3_PLANES] = -1;
-        goto error;
-    }
-
     if (LINK_c2dCreateSurface(&(ctx->dst[YUV_SURFACE_3_PLANES]),
                               C2D_TARGET | C2D_SOURCE,
-                              (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY),
+                              (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST |
+                                                 C2D_SURFACE_WITH_PHYS |
+                                                 C2D_SURFACE_WITH_PHYS_DUMMY),
                               &yuvSurfaceDef)) {
         ALOGE("%s: create ctx->dst[YUV_SURFACE_3_PLANES] failed", __FUNCTION__);
-        ctx->dst[YUV_SURFACE_3_PLANES] = -1;
-        goto error;
+        ctx->dst[YUV_SURFACE_3_PLANES] = 0;
+        clean_up(ctx);
+        status = COPYBIT_FAILURE;
+        *device = NULL;
+        return status;
     }
 
+    for (int i=0; i < MAX_YUV_3_PLANE_SURFACES; i++)
+    {
+        if (LINK_c2dCreateSurface(&(surface_id),
+                              C2D_TARGET | C2D_SOURCE,
+                              (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST |
+                                                 C2D_SURFACE_WITH_PHYS |
+                                                 C2D_SURFACE_WITH_PHYS_DUMMY),
+                              &yuvSurfaceDef)) {
+            ALOGE("%s: create 3 plane YUV surface %d failed", __FUNCTION__, i);
+            ctx->blit_yuv_3_plane_object[i].surface_id = 0;
+            status = COPYBIT_FAILURE;
+            break;
+        } else {
+            ctx->blit_yuv_3_plane_object[i].surface_id = surface_id;
+            ALOGW("%s: 3 Plane YUV i=%d surface_id=%d",  __FUNCTION__, i,
+                                   ctx->blit_yuv_3_plane_object[i].surface_id);
+        }
+    }
+
+    if (status == COPYBIT_FAILURE) {
+        clean_up(ctx);
+        status = COPYBIT_FAILURE;
+        *device = NULL;
+        return status;
+    }
+
+    if (LINK_c2dGetDriverCapabilities(&(ctx->c2d_driver_info))) {
+         ALOGE("%s: LINK_c2dGetDriverCapabilities failed", __FUNCTION__);
+         clean_up(ctx);
+         status = COPYBIT_FAILURE;
+        *device = NULL;
+        return status;
+    }
+    // Initialize context variables.
+    ctx->trg_transform = C2D_TARGET_ROTATE_0;
+
     ctx->temp_src_buffer.fd = -1;
     ctx->temp_src_buffer.base = 0;
     ctx->temp_src_buffer.size = 0;
@@ -1458,28 +1554,12 @@
 
     ctx->fb_width = 0;
     ctx->fb_height = 0;
-    ctx->isPremultipliedAlpha = false;
+
+    ctx->blit_rgb_count = 0;
+    ctx->blit_yuv_2_plane_count = 0;
+    ctx->blit_yuv_3_plane_count = 0;
+    ctx->blit_count = 0;
 
     *device = &ctx->device.common;
     return status;
-
-error:
-    for (int i = 0; i<NUM_SURFACES; i++) {
-        if (-1 != (ctx->src[i])) {
-            LINK_c2dDestroySurface(ctx->src[i]);
-            ctx->src[i] = -1;
-        }
-        if (-1 != (ctx->dst[i])) {
-            LINK_c2dDestroySurface(ctx->dst[i]);
-            ctx->dst[i] = -1;
-        }
-    }
-    if (ctx->libc2d2)
-        ::dlclose(ctx->libc2d2);
-    if (ctx)
-        free(ctx);
-    status = COPYBIT_FAILURE;
-    *device = NULL;
-
-    return status;
 }