summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaekyun Kim <tkq.kim@samsung.com>2011-10-04 21:29:21 +0900
committerTaekyun Kim <tkq.kim@samsung.com>2011-10-07 14:20:38 +0900
commit22b66eb4a6cb2ed6b037f65045f71c99eea14cb9 (patch)
tree218c7aeec88d1b30e5bde7234e5b66f69e91755b
parent879b7c21e45b092272e689e05dc867f6260e258f (diff)
Threaded compositingthreaded_composite
-rw-r--r--configure.ac13
-rw-r--r--pixman/Makefile.sources1
-rw-r--r--pixman/pixman-private.h17
-rw-r--r--pixman/pixman-worker-thread.c293
-rw-r--r--pixman/pixman.c2
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++;
}