diff options
author | Taekyun Kim <tkq.kim@samsung.com> | 2011-10-04 21:29:21 +0900 |
---|---|---|
committer | Taekyun Kim <tkq.kim@samsung.com> | 2011-10-07 14:20:38 +0900 |
commit | 22b66eb4a6cb2ed6b037f65045f71c99eea14cb9 (patch) | |
tree | 218c7aeec88d1b30e5bde7234e5b66f69e91755b | |
parent | 879b7c21e45b092272e689e05dc867f6260e258f (diff) |
Threaded compositingthreaded_composite
-rw-r--r-- | configure.ac | 13 | ||||
-rw-r--r-- | pixman/Makefile.sources | 1 | ||||
-rw-r--r-- | pixman/pixman-private.h | 17 | ||||
-rw-r--r-- | pixman/pixman-worker-thread.c | 293 | ||||
-rw-r--r-- | pixman/pixman.c | 2 |
5 files changed, 325 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 481d0bb..5691702 100644 --- a/configure.ac +++ b/configure.ac @@ -647,6 +647,19 @@ if test $enable_timers = yes ; then fi AC_SUBST(PIXMAN_TIMERS) +dnl ============================================== +dnl Worker thread + +AC_ARG_ENABLE(worker-thread, + [AC_HELP_STRING([--enable-worker-thread], + [enable parallel threaded compositing [default=no]])], + [enable_worker_thread=$enableval], [enable_worker_thread=no]) + +if test $enable_worker_thread = yes ; then + AC_DEFINE(PIXMAN_USE_WORKER_THREAD, 1, [enable parallel threaded compositing]) +fi +AC_SUBST(PIXMAN_USE_WORKER_THREAD) + dnl =================================== dnl GTK+ diff --git a/pixman/Makefile.sources b/pixman/Makefile.sources index ca3f001..6c3bed3 100644 --- a/pixman/Makefile.sources +++ b/pixman/Makefile.sources @@ -24,6 +24,7 @@ libpixman_sources = \ pixman-timer.c \ pixman-trap.c \ pixman-utils.c \ + pixman-worker-thread.c \ $(NULL) libpixman_headers = \ diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h index 4d645fe..cb82585 100644 --- a/pixman/pixman-private.h +++ b/pixman/pixman-private.h @@ -969,4 +969,21 @@ void pixman_timer_register (pixman_timer_t *timer); #endif /* PIXMAN_TIMERS */ +#ifdef PIXMAN_USE_WORKER_THREAD +void +_pixman_enqueue_composite (pixman_composite_func_t func, + pixman_implementation_t *imp, + pixman_composite_info_t *info, + pixman_bool_t wait_finish); +#else +static inline void +_pixman_enqueue_composite (pixman_composite_func_t func, + pixman_implementation_t *imp, + pixman_composite_info_t *info, + pixman_bool_t wait_finish); +{ + func (imp, info); +} +#endif + #endif /* PIXMAN_PRIVATE_H */ diff --git a/pixman/pixman-worker-thread.c b/pixman/pixman-worker-thread.c new file mode 100644 index 0000000..655850e --- /dev/null +++ b/pixman/pixman-worker-thread.c @@ -0,0 +1,293 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "pixman-private.h" + +#include <stdlib.h> +#include <pthread.h> +#include <sched.h> + +#define PIXMAN_NUM_WORKERS 4 +#define PIXMAN_QUEUE_SIZE 16 + +typedef struct pixman_composite_task pixman_composite_task_t; +typedef struct pixman_composite_task_queue pixman_composite_task_queue_t; +typedef struct pixman_worker pixman_worker_t; + +struct pixman_composite_task +{ + pixman_composite_func_t func; + pixman_implementation_t *imp; + pixman_composite_info_t info; +}; + +struct pixman_composite_task_queue +{ + pixman_composite_task_t tasks[PIXMAN_QUEUE_SIZE]; + int head; + int tail; +}; + +typedef enum +{ + PIXMAN_WORKER_VALID, + PIXMAN_WORKER_INVALID, +} pixman_worker_status_t; + +struct pixman_worker +{ + pixman_worker_status_t status; + pthread_t thread; + pixman_composite_task_queue_t queue; + pthread_mutex_t lock; + pthread_cond_t cond_ping; + pthread_cond_t cond_pong; +}; + +#ifdef PIXMAN_USE_WORKER_THREAD +/* Interface for task queue (ring buffer) */ +static inline pixman_bool_t +queue_is_empty (const pixman_composite_task_queue_t *queue) +{ + return queue->head == queue->tail; +} + +static inline pixman_bool_t +queue_is_full (const pixman_composite_task_queue_t *queue) +{ + int next_tail = queue->tail + 1; + + if (next_tail >= PIXMAN_QUEUE_SIZE) + return queue->head == 0; + + return next_tail == queue->head; +} + +static inline pixman_composite_task_t * +get_head (pixman_composite_task_queue_t *queue) +{ + if (!queue_is_empty (queue)) + return &(queue->tasks[queue->head]); + + return NULL; +} + +static inline pixman_bool_t +pop_head (pixman_composite_task_queue_t *queue) +{ + if (!queue_is_empty (queue)) + { + if (++(queue->head) == PIXMAN_QUEUE_SIZE) + queue->head = 0; + + return TRUE; + } + + return FALSE; +} + +static inline pixman_bool_t +push_tail (pixman_composite_task_queue_t *queue, pixman_composite_task_t *task) +{ + if (!queue_is_full (queue)) + { + queue->tasks[queue->tail] = *task; + if (++(queue->tail) == PIXMAN_QUEUE_SIZE) + queue->tail = 0; + + return TRUE; + } + + return FALSE; +} + +static pixman_bool_t use_worker = FALSE; +static pixman_worker_t workers[PIXMAN_NUM_WORKERS]; + +void *_pixman_worker_mainloop(void *arg) +{ + pixman_worker_t *worker = (pixman_worker_t*)arg; + pixman_composite_task_t *task; + + while (1) + { + pthread_mutex_lock (&(worker->lock)); + + if (queue_is_empty (&(worker->queue))) + { + pthread_cond_wait (&(worker->cond_ping), &(worker->lock)); + + if (queue_is_empty (&(worker->queue))) + { + pthread_mutex_unlock (&(worker->lock)); + pthread_exit (0); + } + } + + while (!queue_is_empty (&(worker->queue))) + { + task = get_head (&(worker->queue)); + task->func (task->imp, &(task->info)); + pop_head (&(worker->queue)); + } + + pthread_mutex_unlock (&(worker->lock)); + } +} + +void +_pixman_workers_fini (void); + +pixman_bool_t +_pixman_workers_init (void) +{ + int i; + + memset (workers, 0x00, PIXMAN_NUM_WORKERS * (int)sizeof (pixman_worker_t)); + + for (i = 0; i < PIXMAN_NUM_WORKERS; i++) + workers[i].status = PIXMAN_WORKER_INVALID; + + for (i = 0; i < PIXMAN_NUM_WORKERS; i++) + { + if (pthread_mutex_init (&workers[i].lock, NULL) != 0) + { + _pixman_log_error (FUNC, "Failed to initialize mutex\n"); + goto error; + } + + if (pthread_cond_init (&(workers[i].cond_ping), NULL)) + { + pthread_mutex_destroy (&(workers[i].lock)); + _pixman_log_error (FUNC, "Failed to initialize conditional variable\n"); + goto error; + } + + if (pthread_cond_init (&(workers[i].cond_pong), NULL)) + { + pthread_mutex_destroy (&(workers[i].lock)); + pthread_cond_destroy (&(workers[i].cond_ping)); + _pixman_log_error (FUNC, "Failed to initialize conditional variable\n"); + goto error; + } + + if (pthread_create (&(workers[i].thread), NULL, + _pixman_worker_mainloop, (void*)&workers[i]) != 0) + { + pthread_mutex_destroy (&(workers[i].lock)); + pthread_cond_destroy (&(workers[i].cond_ping)); + pthread_cond_destroy (&(workers[i].cond_pong)); + _pixman_log_error (FUNC, "Failed to create thread\n"); + goto error; + } + + workers[i].status = PIXMAN_WORKER_VALID; + } + + return TRUE; + +error: + _pixman_workers_fini (); + return FALSE; +} + +void +_pixman_workers_fini (void) +{ + int i; + + for (i = 0; i < PIXMAN_NUM_WORKERS; i++) + { + if (workers[i].status == PIXMAN_WORKER_VALID) + { + pthread_mutex_lock (&(workers[i].lock)); + + /* A signal without any new task will terminate the worker. */ + pthread_cond_signal (&(workers[i].cond_ping)); + + pthread_mutex_unlock (&(workers[i].lock)); + pthread_join (workers[i].thread, NULL); + pthread_mutex_destroy (&(workers[i].lock)); + pthread_cond_destroy (&(workers[i].cond_ping)); + pthread_cond_destroy (&(workers[i].cond_pong)); + } + } +} + +#ifdef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR +static void __attribute__((constructor)) +pixman_workers_constructor (void) +{ + if (_pixman_workers_init ()) + use_worker = TRUE; +} + +static void __attribute__((destructor)) +pixman_workers_destructor (void) +{ + _pixman_workers_fini (); +} +#endif + +void +_pixman_enqueue_composite (pixman_composite_func_t func, + pixman_implementation_t *imp, + pixman_composite_info_t *info, + pixman_bool_t wait_finish) +{ + if (use_worker && info->height > 32 && info->width > 32) + { + int i = 0; + int height; + pixman_composite_task_t task; + + task.func = func; + task.imp = imp; + task.info = *info; + + height = info->height / PIXMAN_NUM_WORKERS; + + for (i = 0; i < PIXMAN_NUM_WORKERS; i++) + { + task.info.src_y = info->src_y + height * i; + task.info.mask_y = info->mask_y + height * i; + task.info.dest_y = info->dest_y + height * i; + + if (i == (PIXMAN_NUM_WORKERS - 1)) + task.info.height = info->height - (PIXMAN_NUM_WORKERS - 1) * height; + else + task.info.height = height; + + pthread_mutex_lock (&(workers[i].lock)); + push_tail(&(workers[i].queue), &task); + pthread_cond_signal (&(workers[i].cond_ping)); + pthread_mutex_unlock (&(workers[i].lock)); + } + + + if (wait_finish) + { + sched_yield(); + + for (i = 0; i < PIXMAN_NUM_WORKERS; i++) + { + pthread_mutex_lock (&(workers[i].lock)); + + while (!queue_is_empty (&(workers[i].queue))) + { + pthread_mutex_unlock (&(workers[i].lock)); + sched_yield(); + pthread_mutex_lock (&(workers[i].lock)); + } + + pthread_mutex_unlock (&(workers[i].lock)); + } + } + } + else + { + func (imp, info); + } +} + +#endif //PIXMAN_USE_WORKER_THREAD diff --git a/pixman/pixman.c b/pixman/pixman.c index 87f5a93..ae8139f 100644 --- a/pixman/pixman.c +++ b/pixman/pixman.c @@ -818,7 +818,7 @@ pixman_image_composite32 (pixman_op_t op, info.width = pbox->x2 - pbox->x1; info.height = pbox->y2 - pbox->y1; - func (imp, &info); + _pixman_enqueue_composite (func, imp, &info, TRUE); pbox++; } |