libcopybit: Add Async mode support for C2D

- flush_get_fence API to copybit.h - which is async,
  which returns the fenceFD
- flush_get_fence calls C2dflush and c2dCreateFenceFD
  signals the c2d_wait_thread which waits for
  transcation to finish and cleanup resources

Change-Id: I98d5e08ea1cbce9732970c68c1e47b6f396249ce
diff --git a/libcopybit/c2d2.h b/libcopybit/c2d2.h
index 8209425..886f38a 100644
--- a/libcopybit/c2d2.h
+++ b/libcopybit/c2d2.h
@@ -232,33 +232,6 @@
     C2D_DRAW_LINE_NOLAST     = (1 << 17), /* disable last pixel draw for line */
 } C2D_SOURCE_CONFIG;
 
-/* Configuration bits, driver capabilities used by 2Dapplications */
-typedef enum {
-    C2D_DRIVER_SUPPORTS_GLOBAL_ALPHA_OP           = (1 << 0),
-    C2D_DRIVER_SUPPORTS_TILE_OP                   = (1 << 1),
-    C2D_DRIVER_SUPPORTS_COLOR_KEY_OP              = (1 << 2),
-    C2D_DRIVER_SUPPORTS_NO_PIXEL_ALPHA_OP         = (1 << 3),
-    C2D_DRIVER_SUPPORTS_TARGET_ROTATE_OP          = (1 << 4),
-    C2D_DRIVER_SUPPORTS_ANTI_ALIASING_OP          = (1 << 5), /* antialiasing */
-    C2D_DRIVER_SUPPORTS_BILINEAR_FILTER_OP        = (1 << 6),   /* antialiasing */
-    C2D_DRIVER_SUPPORTS_LENS_CORRECTION_OP        = (1 << 7),
-    C2D_DRIVER_SUPPORTS_OVERRIDE_TARGET_ROTATE_OP = (1 << 8),
-    C2D_DRIVER_SUPPORTS_SHADER_BLOB_OP            = (1 << 9),
-    C2D_DRIVER_SUPPORTS_MASK_SURFACE_OP           = (1 << 10),  /* mask surface */
-    C2D_DRIVER_SUPPORTS_MIRROR_H_OP               = (1 << 11), /* horizontal flip */
-    C2D_DRIVER_SUPPORTS_MIRROR_V_OP               = (1 << 12), /* vertical flip */
-    C2D_DRIVER_SUPPORTS_SCISSOR_RECT_OP           = (1 << 13),
-    C2D_DRIVER_SUPPORTS_SOURCE_RECT_OP            = (1 << 14),
-    C2D_DRIVER_SUPPORTS_TARGET_RECT_OP            = (1 << 15),
-    C2D_DRIVER_SUPPORTS_ROTATE_OP                 = (1 << 16), /* all rotations */
-    C2D_DRIVER_SUPPORTS_ALL_CAPABILITIES_OP       = ((0xFFFFFFFF) >> (31 - 16)) /* mask for all capabilities supported */
-} C2D_DRIVER_CAPABILITIES;
-
-/* 2D driver workaround bits used by the 2D applications */
-typedef enum {
-    C2D_DRIVER_WORKAROUND_NONE  = 0, /* NO workaround */
-    C2D_DRIVER_WORKAROUND_SWAP_UV_FOR_YUV_TARGET  = (1 << 0), /* Swap UV when this flag set */
-} C2D_DRIVER_WORKAROUND;
 
 /* Target configuration bits, defines rotation + mirroring.
  * Mirror is applied prior to rotation if enabled. */
@@ -334,15 +307,6 @@
                                         /* this bit is valid with HOST types */
 } C2D_SURFACE_TYPE;
 
-/* Structure to query Driver information */
-typedef struct {
-    uint32 capabilities_mask;
-    uint32 workaround_mask;
-    uint32 reserved1;
-    uint32 reserved2;
-    uint32 reserved3;
-} C2D_DRIVER_INFO;
-
 /* Structure for registering a RGB buffer as a blit surface */
 typedef struct {
     uint32 format;   /* RGB color format plus additional mode bits */
@@ -424,6 +388,51 @@
     struct C2D_OBJECT_STR *next; /* pointer to the next object or NULL */
 } C2D_OBJECT;
 
+/* Configuration bits, driver capabilities used by 2Dapplications */
+typedef enum {
+    C2D_DRIVER_SUPPORTS_GLOBAL_ALPHA_OP           = (1 << 0),
+    C2D_DRIVER_SUPPORTS_TILE_OP                   = (1 << 1),
+    C2D_DRIVER_SUPPORTS_COLOR_KEY_OP              = (1 << 2),
+    C2D_DRIVER_SUPPORTS_NO_PIXEL_ALPHA_OP         = (1 << 3),
+    C2D_DRIVER_SUPPORTS_TARGET_ROTATE_OP          = (1 << 4),
+    C2D_DRIVER_SUPPORTS_ANTI_ALIASING_OP          = (1 << 5), /* antialiasing */
+    C2D_DRIVER_SUPPORTS_BILINEAR_FILTER_OP        = (1 << 6),
+    C2D_DRIVER_SUPPORTS_LENS_CORRECTION_OP        = (1 << 7),
+    C2D_DRIVER_SUPPORTS_OVERRIDE_TARGET_ROTATE_OP = (1 << 8),
+    C2D_DRIVER_SUPPORTS_SHADER_BLOB_OP            = (1 << 9),
+    C2D_DRIVER_SUPPORTS_MASK_SURFACE_OP           = (1 << 10), /* mask surface */
+    C2D_DRIVER_SUPPORTS_MIRROR_H_OP               = (1 << 11), /* horizontal flip */
+    C2D_DRIVER_SUPPORTS_MIRROR_V_OP               = (1 << 12), /* vertical flip */
+    C2D_DRIVER_SUPPORTS_SCISSOR_RECT_OP           = (1 << 13),
+    C2D_DRIVER_SUPPORTS_SOURCE_RECT_OP            = (1 << 14),
+    C2D_DRIVER_SUPPORTS_TARGET_RECT_OP            = (1 << 15),
+    C2D_DRIVER_SUPPORTS_ROTATE_OP                 = (1 << 16), /* all rotations */
+    C2D_DRIVER_SUPPORTS_FLUSH_WITH_FENCE_FD_OP    = (1 << 17), /* all rotations */
+    C2D_DRIVER_SUPPORTS_ALL_CAPABILITIES_OP       = ((0xFFFFFFFF) >> (31 - 17)) /* mask for all capabilities supported */
+} C2D_DRIVER_CAPABILITIES;
+
+/* 2D driver workaround bits used by the 2D applications */
+typedef enum {
+    C2D_DRIVER_WORKAROUND_NONE  = 0, /* NO workaround */
+    C2D_DRIVER_WORKAROUND_SWAP_UV_FOR_YUV_TARGET  = (1 << 0), /* Swap UV when this flag set */
+} C2D_DRIVER_WORKAROUND;
+
+/* Structure to query Driver information */
+typedef struct {
+    uint32 capabilities_mask;
+    uint32 workaround_mask;
+    uint32 reserved1;
+    uint32 reserved2;
+    uint32 reserved3;
+} C2D_DRIVER_INFO;
+
+/* Structure to query Driver information */
+typedef struct {
+    uint32          max_surface_template_needed;
+    uint32          reserved1;
+    uint32          reserved2;
+    uint32          reserved3;
+} C2D_DRIVER_SETUP_INFO;
 
 /*****************************************************************************/
 /**************************** C2D API 2.0 ********************************/
@@ -662,6 +671,9 @@
  * driver_info is the information about driver */
 C2D_API C2D_STATUS c2dGetDriverCapabilities( C2D_DRIVER_INFO * driver_info);
 
+/* create a fence fd for the timestamp */
+C2D_API C2D_STATUS c2dCreateFenceFD( uint32 target_id, c2d_ts_handle timestamp, int32 *fd);
+
 /*****************************************************************************/
 
 #ifdef __cplusplus
diff --git a/libcopybit/copybit.h b/libcopybit/copybit.h
index 5adc433..d57b84d 100644
--- a/libcopybit/copybit.h
+++ b/libcopybit/copybit.h
@@ -240,6 +240,16 @@
     */
   int (*finish)(struct copybit_device_t *dev);
 
+  /**
+    * Trigger the copybit draw operation(async).
+    *
+    * @param dev from open
+    *
+    * @param fd - gets the fencefd
+    *
+    * @return 0 if successful
+    */
+  int (*flush_get_fence)(struct copybit_device_t *dev, int* fd);
 };
 
 
diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp
index 6cda9a5..2fa55cd 100644
--- a/libcopybit/copybit_c2d.cpp
+++ b/libcopybit/copybit_c2d.cpp
@@ -17,8 +17,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #include <cutils/log.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
 
 #include <stdint.h>
 #include <string.h>
@@ -85,6 +86,10 @@
 C2D_STATUS (*LINK_c2dUnMapAddr) ( void * gpuaddr);
 
 C2D_STATUS (*LINK_c2dGetDriverCapabilities) ( C2D_DRIVER_INFO * driver_info);
+
+/* create a fence fd for the timestamp */
+C2D_STATUS (*LINK_c2dCreateFenceFD) ( uint32 target_id, c2d_ts_handle timestamp,
+                                                            int32 *fd);
 /******************************************************************************/
 
 #if defined(COPYBIT_Z180)
@@ -150,6 +155,15 @@
     int config_mask;
     int dst_surface_type;
     bool is_premultiplied_alpha;
+    void* time_stamp;
+
+    // used for signaling the wait thread
+    bool wait_timestamp;
+    pthread_t wait_thread_id;
+    bool stop_thread;
+    pthread_mutex_t wait_cleanup_lock;
+    pthread_cond_t wait_cleanup_cond;
+
 };
 
 struct bufferInfo {
@@ -193,6 +207,46 @@
 };
 
 
+/* thread function which waits on the timeStamp and cleans up the surfaces */
+static void* c2d_wait_loop(void* ptr) {
+    copybit_context_t* ctx = (copybit_context_t*)(ptr);
+    char thread_name[64] = "copybitWaitThr";
+    prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
+    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+
+    while(ctx->stop_thread == false) {
+        pthread_mutex_lock(&ctx->wait_cleanup_lock);
+        while(ctx->wait_timestamp == false && !ctx->stop_thread) {
+            pthread_cond_wait(&(ctx->wait_cleanup_cond),
+                              &(ctx->wait_cleanup_lock));
+        }
+        if(ctx->wait_timestamp) {
+            if(LINK_c2dWaitTimestamp(ctx->time_stamp)) {
+                ALOGE("%s: LINK_c2dWaitTimeStamp ERROR!!", __FUNCTION__);
+            }
+            ctx->wait_timestamp = false;
+            // 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;
+                }
+            }
+            // 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;
+        }
+        pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+        if(ctx->stop_thread)
+            break;
+    }
+    pthread_exit(NULL);
+    return NULL;
+}
+
+
 /* convert COPYBIT_FORMAT to C2D format */
 static int get_format(int format) {
     switch (format) {
@@ -545,18 +599,46 @@
     {
         ctx->blit_list[i].next = &(ctx->blit_list[i+1]);
     }
-
     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;
 }
 
 
+
+static int flush_get_fence_copybit (struct copybit_device_t *dev, int* fd)
+{
+    struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+    int status = COPYBIT_FAILURE;
+    if (!ctx)
+        return COPYBIT_FAILURE;
+    pthread_mutex_lock(&ctx->wait_cleanup_lock);
+    status = msm_copybit(ctx, ctx->dst[ctx->dst_surface_type]);
+
+    if(LINK_c2dFlush(ctx->dst[ctx->dst_surface_type], &ctx->time_stamp)) {
+        ALOGE("%s: LINK_c2dFlush ERROR", __FUNCTION__);
+        // unlock the mutex and return failure
+        pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+        return COPYBIT_FAILURE;
+    }
+    if(LINK_c2dCreateFenceFD(ctx->dst[ctx->dst_surface_type], ctx->time_stamp,
+                                                                        fd)) {
+        ALOGE("%s: LINK_c2dCreateFenceFD ERROR", __FUNCTION__);
+        status = COPYBIT_FAILURE;
+    }
+    if(status == COPYBIT_SUCCESS) {
+        //signal the wait_thread
+        ctx->wait_timestamp = true;
+        pthread_cond_signal(&ctx->wait_cleanup_cond);
+    }
+    pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+    return status;
+}
+
 static int finish_copybit(struct copybit_device_t *dev)
 {
     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
@@ -647,11 +729,13 @@
     int value)
 {
     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+    int status = COPYBIT_SUCCESS;
     if (!ctx) {
         ALOGE("%s: null context", __FUNCTION__);
         return -EINVAL;
     }
 
+    pthread_mutex_lock(&ctx->wait_cleanup_lock);
     switch(name) {
         case COPYBIT_PLANE_ALPHA:
         {
@@ -729,11 +813,11 @@
             break;
         default:
             ALOGE("%s: default case param=0x%x", __FUNCTION__, name);
-            return -EINVAL;
+            status = -EINVAL;
             break;
     }
-
-    return COPYBIT_SUCCESS;
+    pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+    return status;
 }
 
 /** Get a static info value */
@@ -1211,7 +1295,7 @@
         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);;
+            finish_copybit(dev);
         }
         ctx->blit_list[ctx->blit_count] = src_surface;
         ctx->blit_count++;
@@ -1261,9 +1345,13 @@
     struct copybit_region_t const *region)
 {
     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+    int status = COPYBIT_SUCCESS;
     bool needsBlending = (ctx->src_global_alpha != 0);
-    return stretch_copybit_internal(dev, dst, src, dst_rect, src_rect,
+    pthread_mutex_lock(&ctx->wait_cleanup_lock);
+    status = stretch_copybit_internal(dev, dst, src, dst_rect, src_rect,
                                     region, needsBlending);
+    pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+    return status;
 }
 
 /** Perform a blit type operation */
@@ -1282,9 +1370,21 @@
 
 static void clean_up(copybit_context_t* ctx)
 {
+    void* ret;
     if (!ctx)
         return;
 
+    // stop the wait_cleanup_thread
+    pthread_mutex_lock(&ctx->wait_cleanup_lock);
+    ctx->stop_thread = true;
+    // Signal waiting thread
+    pthread_cond_signal(&ctx->wait_cleanup_cond);
+    pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+    // waits for the cleanup thread to exit
+    pthread_join(ctx->wait_thread_id, &ret);
+    pthread_mutex_destroy(&ctx->wait_cleanup_lock);
+    pthread_cond_destroy (&ctx->wait_cleanup_cond);
+
     for (int i = 0; i < NUM_SURFACE_TYPES; i++) {
         if (ctx->dst[i])
             LINK_c2dDestroySurface(ctx->dst[i]);
@@ -1370,11 +1470,13 @@
                                            "c2dUnMapAddr");
     *(void **)&LINK_c2dGetDriverCapabilities = ::dlsym(ctx->libc2d2,
                                            "c2dGetDriverCapabilities");
+    *(void **)&LINK_c2dCreateFenceFD = ::dlsym(ctx->libc2d2,
+                                           "c2dCreateFenceFD");
 
     if (!LINK_c2dCreateSurface || !LINK_c2dUpdateSurface || !LINK_c2dReadSurface
         || !LINK_c2dDraw || !LINK_c2dFlush || !LINK_c2dWaitTimestamp ||
         !LINK_c2dFinish  || !LINK_c2dDestroySurface ||
-        !LINK_c2dGetDriverCapabilities) {
+        !LINK_c2dGetDriverCapabilities || !LINK_c2dCreateFenceFD) {
         ALOGE("%s: dlsym ERROR", __FUNCTION__);
         clean_up(ctx);
         status = COPYBIT_FAILURE;
@@ -1391,6 +1493,7 @@
     ctx->device.blit = blit_copybit;
     ctx->device.stretch = stretch_copybit;
     ctx->device.finish = finish_copybit;
+    ctx->device.flush_get_fence = flush_get_fence_copybit;
 
     /* Create RGB Surface */
     surfDefinition.buffer = (void*)0xdddddddd;
@@ -1560,6 +1663,19 @@
     ctx->blit_yuv_3_plane_count = 0;
     ctx->blit_count = 0;
 
+    ctx->wait_timestamp = false;
+    ctx->stop_thread = false;
+    pthread_mutex_init(&(ctx->wait_cleanup_lock), NULL);
+    pthread_cond_init(&(ctx->wait_cleanup_cond), NULL);
+    /* Start the wait thread */
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    pthread_create(&ctx->wait_thread_id, &attr, &c2d_wait_loop,
+                                                            (void *)ctx);
+    pthread_attr_destroy(&attr);
+
     *device = &ctx->device.common;
     return status;
 }