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;
}