#define CLIENT_QUEUE_SIZE 3
-#define USE_WORKER_THREAD
-#ifndef USE_WORKER_THREAD
-#define USE_WORKER_THREAD 0
-#else
-#include "tpl_worker_thread.h"
-#include <pthread.h>
-#include <time.h>
-#undef USE_WORKER_THREAD
-#define USE_WORKER_THREAD 1
-#endif
-
typedef struct _tpl_wayland_vk_wsi_display tpl_wayland_vk_wsi_display_t;
typedef struct _tpl_wayland_vk_wsi_surface tpl_wayland_vk_wsi_surface_t;
typedef struct _tpl_wayland_vk_wsi_buffer tpl_wayland_vk_wsi_buffer_t;
struct _tpl_wayland_vk_wsi_surface {
tbm_surface_queue_h tbm_queue;
int buffer_count;
-
-#if USE_WORKER_THREAD == 1
- /*
- * TODO: it can move to libtbm
- * libtbm already has free queue's pthread_cond and pthread_mutex
- */
- pthread_mutex_t free_queue_mutex;
- pthread_cond_t free_queue_cond;
-
- /* tbm_surface list */
- tpl_list_t vblank_list;
- pthread_mutex_t vblank_list_mutex;
-
- tpl_bool_t vblank_done;
-
- tpl_worker_surface_t worker_surface;
-#endif
int present_mode;
};
struct wl_proxy *wl_proxy;
tbm_fd sync_timeline;
unsigned int sync_timestamp;
-
-#if USE_WORKER_THREAD == 1
- tbm_fd wait_sync;
-#endif
};
static const struct wl_registry_listener registry_listener;
if (modes) {
*modes = TPL_DISPLAY_PRESENT_MODE_MAILBOX | TPL_DISPLAY_PRESENT_MODE_IMMEDIATE |
wayland_vk_wsi_display->surface_capabilities.present_modes;
-#if USE_WORKER_THREAD == 1
- if (__tpl_worker_support_vblank() == TPL_TRUE)
- *modes |= TPL_DISPLAY_PRESENT_MODE_FIFO | TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED;
-#endif
}
return TPL_ERROR_NONE;
wl_display_flush(surface->display->native_handle);
wayland_vk_wsi_buffer->sync_timestamp++;
-#if USE_WORKER_THREAD == 1
- pthread_mutex_lock(&wayland_vk_wsi_surface->free_queue_mutex);
-#endif
tbm_surface_queue_release(wayland_vk_wsi_surface->tbm_queue, tbm_surface);
-#if USE_WORKER_THREAD == 1
- pthread_mutex_unlock(&wayland_vk_wsi_surface->free_queue_mutex);
- pthread_cond_signal(&wayland_vk_wsi_surface->free_queue_cond);
-#endif
}
static tpl_result_t
tbm_surface_internal_unref(tbm_surface);
-#if USE_WORKER_THREAD == 1
- wayland_vk_wsi_buffer->wait_sync = sync_fence;
-#endif
tsq_err = tbm_surface_queue_enqueue(wayland_vk_wsi_surface->tbm_queue,
tbm_surface);
if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
return TPL_ERROR_INVALID_OPERATION;
}
-#if USE_WORKER_THREAD == 0
if (sync_fence != -1) {
/* non worker thread mode */
/* TODO: set max wait time */
__tpl_wayland_vk_wsi_surface_commit_buffer(surface, tbm_surface);
-#else
- __tpl_worker_new_buffer_notify(&wayland_vk_wsi_surface->worker_surface);
-
-#endif
/*
* tbm_surface insert to free queue.
if (sync_fence)
*sync_fence = -1;
-#if USE_WORKER_THREAD == 0
TPL_OBJECT_UNLOCK(surface);
while (tbm_surface_queue_can_dequeue(
wayland_vk_wsi_surface->tbm_queue, 0) == 0) {
}
}
TPL_OBJECT_LOCK(surface);
-#else
- /*
- * TODO: it can move to libtbm
- * libtbm already has free queue's pthread_cond and pthread_mutex
- */
- struct timespec abs_time;
- if (timeout_ns != UINT64_MAX) {
- clock_gettime(CLOCK_REALTIME, &abs_time);
- abs_time.tv_sec += (timeout_ns / 1000000000L);
- abs_time.tv_nsec += (timeout_ns % 1000000000L);
- if (abs_time.tv_nsec >= 1000000000L) {
- abs_time.tv_sec += (abs_time.tv_nsec / 1000000000L);
- abs_time.tv_nsec = (abs_time.tv_nsec % 1000000000L);
- }
- }
- pthread_mutex_lock(&wayland_vk_wsi_surface->free_queue_mutex);
- while (tbm_surface_queue_can_dequeue(wayland_vk_wsi_surface->tbm_queue,
- 0) == 0) {
- if (timeout_ns != UINT64_MAX) {
- int ret;
- ret = pthread_cond_timedwait(&wayland_vk_wsi_surface->free_queue_cond,
- &wayland_vk_wsi_surface->free_queue_mutex,
- &abs_time);
- if (ret == ETIMEDOUT) {
- /* timeout */
- pthread_mutex_unlock(&wayland_vk_wsi_surface->free_queue_mutex);
- return NULL;
- }
- } else {
- pthread_cond_wait(&wayland_vk_wsi_surface->free_queue_cond,
- &wayland_vk_wsi_surface->free_queue_mutex);
- }
- }
-#endif
tsq_err = tbm_surface_queue_dequeue(wayland_vk_wsi_surface->tbm_queue,
&tbm_surface);
-#if USE_WORKER_THREAD == 1
- pthread_mutex_unlock(&wayland_vk_wsi_surface->free_queue_mutex);
-#endif
+
if (!tbm_surface) {
TPL_ERR("Failed to get tbm_surface from tbm_surface_queue | tsq_err = %d",
tsq_err);
return ret;
}
-#if USE_WORKER_THREAD == 1
-static void
-__tpl_wayland_vk_wsi_process_draw_done(tpl_surface_t *surface,
- tbm_surface_h tbm_surface,
- tpl_result_t result)
-{
- tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL;
- tpl_wayland_vk_wsi_buffer_t *wayland_vk_wsi_buffer = NULL;
- tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display = NULL;
-
- TPL_ASSERT(surface);
- TPL_ASSERT(tbm_surface);
- TPL_ASSERT(tbm_surface_internal_is_valid(tbm_surface));
-
- wayland_vk_wsi_surface =
- (tpl_wayland_vk_wsi_surface_t *)surface->backend.data;
- wayland_vk_wsi_buffer =
- __tpl_wayland_vk_wsi_get_wayland_buffer_from_tbm_surface(tbm_surface);
- wayland_vk_wsi_display = (tpl_wayland_vk_wsi_display_t *)
- surface->display->backend.data;
-
- TPL_ASSERT(wayland_vk_wsi_surface);
- TPL_ASSERT(wayland_vk_wsi_buffer);
- TPL_ASSERT(wayland_vk_wsi_display);
-
- close(wayland_vk_wsi_buffer->wait_sync);
- wayland_vk_wsi_buffer->wait_sync = -1;
-
- /* if server supported current supported mode then just send */
-
- if (wayland_vk_wsi_surface->present_mode &
- wayland_vk_wsi_display->surface_capabilities.present_modes) {
- __tpl_wayland_vk_wsi_surface_commit_buffer(surface, tbm_surface);
- return;
- }
-
- if (wayland_vk_wsi_surface->present_mode == TPL_DISPLAY_PRESENT_MODE_FIFO) {
- pthread_mutex_lock(&wayland_vk_wsi_surface->vblank_list_mutex);
- /* unref in tpl list remove callback
- (__tpl_wayland_vk_wsi_buffer_remove_from_vblank_list) */
- tbm_surface_internal_ref(tbm_surface);
- __tpl_list_push_back(&wayland_vk_wsi_surface->vblank_list, tbm_surface);
- pthread_mutex_unlock(&wayland_vk_wsi_surface->vblank_list_mutex);
- } else if (wayland_vk_wsi_surface->present_mode == TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED &&
- wayland_vk_wsi_surface->vblank_done == TPL_FALSE) {
- /* if can't process previous vblank event, send buffer immediately */
- pthread_mutex_lock(&wayland_vk_wsi_surface->vblank_list_mutex);
- /* unref in tpl list remove callback
- (__tpl_wayland_vk_wsi_buffer_remove_from_vblank_list) */
- tbm_surface_internal_ref(tbm_surface);
- __tpl_list_push_back(&wayland_vk_wsi_surface->vblank_list, tbm_surface);
- wayland_vk_wsi_surface->vblank_done = TPL_TRUE;
- pthread_mutex_unlock(&wayland_vk_wsi_surface->vblank_list_mutex);
- } else {
- __tpl_wayland_vk_wsi_surface_commit_buffer(surface, tbm_surface);
- }
-}
-
-static int
-__tpl_wayland_vk_wsi_draw_wait_fd_get(tpl_surface_t *surface,
- tbm_surface_h tbm_surface)
-{
- tpl_wayland_vk_wsi_buffer_t *wayland_vk_wsi_buffer = NULL;
-
- /*TPL_ASSERT(surface);*/
- TPL_ASSERT(tbm_surface);
-
- wayland_vk_wsi_buffer =
- __tpl_wayland_vk_wsi_get_wayland_buffer_from_tbm_surface(tbm_surface);
-
- TPL_ASSERT(wayland_vk_wsi_buffer);
-
- return wayland_vk_wsi_buffer->wait_sync;
-}
-
-static void
-__tpl_wayland_vk_wsi_buffer_remove_from_vblank_list(void *data)
-{
- tbm_surface_h tbm_surface = data;
- tbm_surface_internal_unref(tbm_surface);
-}
-
-static void
-__tpl_wayland_vk_wsi_vblank(tpl_surface_t *surface, unsigned int sequence,
- unsigned int tv_sec, unsigned int tv_usec)
-{
- tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface;
- tbm_surface_h tbm_surface;
-
- TPL_ASSERT(surface);
-
- wayland_vk_wsi_surface =
- (tpl_wayland_vk_wsi_surface_t *) surface->backend.data;
-
- TPL_ASSERT(wayland_vk_wsi_surface);
-
- if ((wayland_vk_wsi_surface->present_mode &
- (TPL_DISPLAY_PRESENT_MODE_FIFO | TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED)) == 0)
- return;
-
- pthread_mutex_lock(&wayland_vk_wsi_surface->vblank_list_mutex);
- tbm_surface = __tpl_list_pop_front(&wayland_vk_wsi_surface->vblank_list,
- __tpl_wayland_vk_wsi_buffer_remove_from_vblank_list);
- pthread_mutex_unlock(&wayland_vk_wsi_surface->vblank_list_mutex);
-
- if (tbm_surface_internal_is_valid(tbm_surface)) {
- __tpl_wayland_vk_wsi_surface_commit_buffer(surface, tbm_surface);
- wayland_vk_wsi_surface->vblank_done = TPL_TRUE;
- } else {
- wayland_vk_wsi_surface->vblank_done = TPL_FALSE;
- }
-}
-#endif
-
static tpl_result_t
__tpl_wayland_vk_wsi_surface_create_swapchain(tpl_surface_t *surface,
tbm_format format, int width,
if ((present_mode & wayland_vk_wsi_display->surface_capabilities.present_modes) == 0) {
/* server not supported current mode check client mode */
switch (present_mode) {
-#if USE_WORKER_THREAD == 1
- case TPL_DISPLAY_PRESENT_MODE_FIFO:
- case TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED:
- if (__tpl_worker_support_vblank() == TPL_FALSE) {
- TPL_ERR("Unsupported present mode: %d, worker not support vblank",
- present_mode);
- return TPL_ERROR_INVALID_PARAMETER;
- }
- break;
-#endif
case TPL_DISPLAY_PRESENT_MODE_MAILBOX:
case TPL_DISPLAY_PRESENT_MODE_IMMEDIATE:
break;
surface->width = width;
surface->height = height;
-#if USE_WORKER_THREAD == 1
- pthread_mutex_init(&wayland_vk_wsi_surface->free_queue_mutex, NULL);
- pthread_cond_init(&wayland_vk_wsi_surface->free_queue_cond, NULL);
-
- wayland_vk_wsi_surface->worker_surface.surface = surface;
- wayland_vk_wsi_surface->worker_surface.tbm_queue =
- wayland_vk_wsi_surface->tbm_queue;
-
- wayland_vk_wsi_surface->worker_surface.draw_done =
- __tpl_wayland_vk_wsi_process_draw_done;
- wayland_vk_wsi_surface->worker_surface.draw_wait_fd_get =
- __tpl_wayland_vk_wsi_draw_wait_fd_get;
- if ((wayland_vk_wsi_surface->present_mode &
- (TPL_DISPLAY_PRESENT_MODE_FIFO | TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED))) {
- wayland_vk_wsi_surface->worker_surface.vblank =
- __tpl_wayland_vk_wsi_vblank;
- pthread_mutex_init(&wayland_vk_wsi_surface->vblank_list_mutex, NULL);
- __tpl_list_init(&wayland_vk_wsi_surface->vblank_list);
- }
-
- __tpl_worker_surface_list_insert(&wayland_vk_wsi_surface->worker_surface);
-#endif
return TPL_ERROR_NONE;
}
wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *) surface->backend.data;
TPL_ASSERT(wayland_vk_wsi_surface);
-#if USE_WORKER_THREAD == 1
- __tpl_worker_surface_list_remove(&wayland_vk_wsi_surface->worker_surface);
-#endif
if (surface->type == TPL_SURFACE_TYPE_WINDOW) {
wl_display_flush(surface->display->native_handle);
wayland_vk_wsi_surface->tbm_queue = NULL;
}
-#if USE_WORKER_THREAD == 1
- if ((wayland_vk_wsi_surface->present_mode &
- (TPL_DISPLAY_PRESENT_MODE_FIFO | TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED))) {
- pthread_mutex_lock(&wayland_vk_wsi_surface->vblank_list_mutex);
- __tpl_list_fini(&wayland_vk_wsi_surface->vblank_list,
- __tpl_wayland_vk_wsi_buffer_remove_from_vblank_list);
- pthread_mutex_unlock(&wayland_vk_wsi_surface->vblank_list_mutex);
- pthread_mutex_destroy(&wayland_vk_wsi_surface->vblank_list_mutex);
- }
-
- pthread_cond_destroy(&wayland_vk_wsi_surface->free_queue_cond);
- pthread_mutex_destroy(&wayland_vk_wsi_surface->free_queue_mutex);
-#endif
return TPL_ERROR_NONE;
}
+++ /dev/null
-#include "tpl_worker_thread.h"
-#include "tpl_internal.h"
-
-#include <unistd.h>
-/*#define __USE_GNU*/
-#include <pthread.h>
-#include <sys/eventfd.h>
-#include <sys/epoll.h>
-#include <tdm_client.h>
-
-#define TPL_ERR_ERRNO(f, x...) \
- do { int err = errno; char buf[256] = {0,}; \
- strerror_r(err, buf, 255); \
- TPL_ERR(f " | error: %d(%s)", ##x, err, buf); \
- } while (0);
-
-#define TPL_WARN_ERRNO(f, x...) \
- do { int err = errno; char buf[256] = {0,}; \
- strerror_r(err, buf, 255); \
- TPL_WARN(f " | error: %d(%s)", ##x, err, buf); \
- } while (0);
-
-static struct {
- int running;
- int epoll_fd;
- int event_fd;
-
- pthread_t worker_id;
- tpl_list_t surface_list;
- pthread_mutex_t surface_mutex;
- tpl_bool_t support_vblank;
-} tpl_worker_thread;
-
-tpl_bool_t
-__tpl_worker_support_vblank()
-{
- return tpl_worker_thread.support_vblank;
-}
-
-void
-__tpl_worker_surface_list_insert(tpl_worker_surface_t *surface)
-{
- TPL_ASSERT(surface->surface);
-
- if (pthread_mutex_lock(&tpl_worker_thread.surface_mutex) != 0) {
- TPL_ERR_ERRNO("surface list mutex lock failed");
- return;
- }
-
- surface->draw_wait_buffer = NULL;
- __tpl_list_push_back(&tpl_worker_thread.surface_list, surface);
-
- pthread_mutex_unlock(&tpl_worker_thread.surface_mutex);
-}
-
-void
-__tpl_worker_surface_list_remove(tpl_worker_surface_t *surface)
-{
- if (pthread_mutex_lock(&tpl_worker_thread.surface_mutex) != 0) {
- TPL_ERR_ERRNO("surface list mutex lock failed");
- return;
- }
-
- __tpl_list_remove_data(&tpl_worker_thread.surface_list, surface,
- TPL_FIRST, NULL);
-
- pthread_mutex_unlock(&tpl_worker_thread.surface_mutex);
-}
-
-static void
-__tpl_worker_event_send()
-{
- int len;
- uint64_t dummy_event = 1;
-
- if (tpl_worker_thread.event_fd == -1) {
- TPL_ERR("worker thread not working");
- return;
- }
-
- len = write(tpl_worker_thread.event_fd,
- &dummy_event,
- sizeof(dummy_event));
- if (len < 0)
- TPL_WARN_ERRNO("event fd(%d) write failed.",
- tpl_worker_thread.event_fd);
-}
-
-static void
-__tpl_worker_prepare_draw_wait_buffer(int epoll_fd,
- tpl_worker_surface_t *surface)
-{
- if (surface->draw_wait_buffer)
- return;
-
- if (surface->draw_wait_buffer_get) {
- int wait_fd = -1;
- tbm_surface_h tbm_surface;
-
- while ((tbm_surface = surface->draw_wait_buffer_get(surface->surface)) != NULL) {
- if (surface->draw_wait_fd_get)
- wait_fd = surface->draw_wait_fd_get(surface->surface, tbm_surface);
-
- if (wait_fd != -1) {
- struct epoll_event wait_fence_event;
- int epoll_err;
-
- wait_fence_event.events = EPOLLIN;
- wait_fence_event.data.ptr = surface;
- epoll_err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD,
- wait_fd,
- &wait_fence_event);
- if (epoll_err == 0) {
- surface->draw_wait_buffer = tbm_surface;
- return;
- }
- } /* else can't(or not need) wait fence in poll */
-
- if (surface->draw_done)
- surface->draw_done(surface->surface, tbm_surface,
- TPL_ERROR_INVALID_OPERATION);
- }
- return;
- }
-
- while (tbm_surface_queue_can_acquire(surface->tbm_queue, 0)) {
- tbm_surface_h tbm_surface = NULL;
- tbm_surface_queue_error_e tsq_err;
- int wait_fd = -1;
-
- tsq_err = tbm_surface_queue_acquire(surface->tbm_queue, &tbm_surface);
- if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE || tbm_surface == NULL) {
- TPL_ERR("Failed to acquire tbm_surface. | tsq_err = %d", tsq_err);
- return;
- }
-
- if (surface->draw_wait_fd_get)
- wait_fd = surface->draw_wait_fd_get(surface->surface, tbm_surface);
-
- if (wait_fd != -1) {
- struct epoll_event wait_fence_event;
- int epoll_err;
-
- wait_fence_event.events = EPOLLIN;
- wait_fence_event.data.ptr = surface;
- epoll_err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD,
- wait_fd,
- &wait_fence_event);
- if (epoll_err == 0) {
- surface->draw_wait_buffer = tbm_surface;
- return;
- }
- } /* else can't(or not need) wait fence in poll */
-
- if (surface->draw_done)
- surface->draw_done(surface->surface, tbm_surface,
- TPL_ERROR_INVALID_OPERATION);
- }
-}
-
-void
-__tpl_worker_new_buffer_notify(tpl_worker_surface_t *surface)
-{
- TPL_ASSERT(surface->surface);
-
- __tpl_worker_event_send();
-}
-
-static tpl_bool_t
-__tpl_worker_regist_vblank_handler(tdm_client_vblank *tdm_vblank);
-
-static void
-__tpl_worker_cb_vblank(tdm_client_vblank *tdm_vblank, tdm_error error,
- unsigned int sequence, unsigned int tv_sec,
- unsigned int tv_usec, void *user_data)
-{
- tpl_list_node_t *trail;
-
- if (pthread_mutex_lock(&tpl_worker_thread.surface_mutex) != 0) {
- TPL_ERR_ERRNO("surface list mutex lock failed");
- return;
- }
-
- for (trail = __tpl_list_get_front_node(&tpl_worker_thread.surface_list);
- trail != NULL;
- trail = __tpl_list_node_next(trail)) {
- tpl_worker_surface_t *surface;
-
- surface = __tpl_list_node_get_data(trail);
- if (surface->vblank)
- surface->vblank(surface->surface, sequence, tv_sec, tv_usec);
- }
- pthread_mutex_unlock(&tpl_worker_thread.surface_mutex);
-
- __tpl_worker_regist_vblank_handler(tdm_vblank);
-}
-
-static tpl_bool_t
-__tpl_worker_regist_vblank_handler(tdm_client_vblank *tdm_vblank)
-{
- tdm_error tdm_err;
-
- tdm_err = tdm_client_vblank_wait(tdm_vblank,
- 1, /* interval */
- __tpl_worker_cb_vblank, /* handler */
- NULL);
- if (tdm_err != TDM_ERROR_NONE) {
- TPL_ERR("Failed to tdm_client_wait_vblank. error:%d", tdm_err);
- return TPL_FALSE;
- }
- return TPL_TRUE;
-}
-
-static int
-__tpl_worker_prepare_event_fd(int epoll_fd)
-{
- int event_fd;
- struct epoll_event event;
- event.events = EPOLLIN;
- event.data.ptr = &tpl_worker_thread;
-
- event_fd = eventfd(0, EFD_CLOEXEC);
- if (event_fd == -1) {
- TPL_ERR_ERRNO("eventfd() failed");
- return -1;
- }
-
- if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event_fd, &event) != 0) {
- TPL_ERR_ERRNO("eventfd epoll ctl epoll_fd: %d, event_fd: %d.",
- epoll_fd, tpl_worker_thread.event_fd);
- close(event_fd);
- return -1;
- }
- return event_fd;
-}
-
-/* FIXME: Temporarily added 'unused' attribute to suppress warning. */
-/* Remove this attribute when you use this function. */
-static tpl_bool_t __attribute__((unused))
-__tpl_worker_prepare_vblank(int epoll_fd, tdm_client **ret_client, tdm_client_vblank **ret_vblank)
-{
- tdm_error tdm_err;
- tdm_client *tdm_client = NULL;
- tdm_client_output *tdm_output = NULL;
- tdm_client_vblank *tdm_vblank = NULL;
- int tdm_fd, ret;
- struct epoll_event event;
-
- TPL_ASSERT(ret_client);
- TPL_ASSERT(ret_vblank);
-
- tdm_client = tdm_client_create(&tdm_err);
- if (!tdm_client) {
- TPL_ERR("tdm_client_create failed | tdm_err: %d\n", tdm_err);
- goto error_cleanup;
- }
-
- tdm_err = tdm_client_get_fd(tdm_client, &tdm_fd);
- if (tdm_err != TDM_ERROR_NONE || tdm_fd < 0) {
- TPL_ERR("tdm_client_get_fd failed | tdm_err: %d\n", tdm_err);
- goto error_cleanup;
- }
-
- tdm_output = tdm_client_get_output(tdm_client, "primary", &tdm_err);
- if (!tdm_output) {
- TPL_ERR("Failed to get tdm client output. tdm_err(%d)", tdm_err);
- goto error_cleanup;
- }
-
- tdm_vblank = tdm_client_output_create_vblank(tdm_output, &tdm_err);
- if (!tdm_vblank) {
- TPL_ERR("Failed to create tdm vblank output. tdm_err(%d)", tdm_err);
- goto error_cleanup;
- }
-
- tdm_client_vblank_set_enable_fake(tdm_vblank, 1);
- tdm_client_vblank_set_sync(tdm_vblank, 0);
-
- if (__tpl_worker_regist_vblank_handler(tdm_vblank) == TPL_FALSE)
- goto error_cleanup;
-
- event.events = EPOLLIN;
- event.data.ptr = tdm_client;
- ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tdm_fd, &event);
- if (ret != 0) {
- TPL_ERR_ERRNO("tdm epoll ctl epoll_fd: %d, tdm_fd: %d.",
- epoll_fd, tdm_fd);
- goto error_cleanup;
- }
-
- *ret_vblank = tdm_vblank;
- *ret_client = tdm_client;
-
- return TPL_TRUE;
-
-error_cleanup:
- if (tdm_vblank)
- tdm_client_vblank_destroy(tdm_vblank);
- if (tdm_client)
- tdm_client_destroy(tdm_client);
- return TPL_FALSE;
-}
-
-static void *
-__tpl_worker_thread_loop(void *arg)
-{
-#define EPOLL_MAX_SIZE 100
- int ret, epoll_fd = epoll_create(EPOLL_MAX_SIZE);
- struct epoll_event ev_list[EPOLL_MAX_SIZE];
- tdm_client *tdm_client = NULL;
- tdm_client_vblank *tdm_vblank = NULL;
-
- if (epoll_fd == -1) {
- TPL_ERR_ERRNO("epoll create failed");
- goto cleanup;
- }
-
- /* event fd */
- tpl_worker_thread.event_fd = __tpl_worker_prepare_event_fd(epoll_fd);
- if (tpl_worker_thread.event_fd == -1)
- goto cleanup;
-
- /* vblank fd */
- /* FIXME: vblank has performance problem */
- /*if (__tpl_worker_prepare_vblank(epoll_fd, &tdm_client, &tdm_vblank))
- tpl_worker_thread.support_vblank = TPL_TRUE;*/
- tpl_worker_thread.support_vblank = TPL_TRUE;
-
- while (tpl_worker_thread.running) {
- int i;
- tpl_list_node_t *trail;
-
- /* set buffer's sync fd and vblank list */
- if (pthread_mutex_lock(&tpl_worker_thread.surface_mutex) != 0) {
- TPL_ERR_ERRNO("surface list mutex lock failed");
- goto cleanup;
- }
-
- for (trail = __tpl_list_get_front_node(&tpl_worker_thread.surface_list);
- trail != NULL;
- trail = __tpl_list_node_next(trail)) {
- tpl_worker_surface_t *surface = __tpl_list_node_get_data(trail);
- TPL_ASSERT(surface);
-
- __tpl_worker_prepare_draw_wait_buffer(epoll_fd, surface);
- }
- pthread_mutex_unlock(&tpl_worker_thread.surface_mutex);
-
- /* wait events */
-cont_epoll_wait:
- ret = epoll_wait(epoll_fd, ev_list, EPOLL_MAX_SIZE, -1);
- if (ret == -1) {
- if (errno != EINTR)
- TPL_ERR_ERRNO("epoll fd: %d.", epoll_fd);
- goto cont_epoll_wait;
- }
-
- for (i = 0; i < ret; i++) {
- if (ev_list[i].data.ptr == &tpl_worker_thread) {
- /* thread terminate event */
- if (ev_list[i].events & EPOLLIN) {
- int len;
- uint64_t read_buf;
-
- len = read(tpl_worker_thread.event_fd,
- &read_buf, sizeof(uint64_t));
- if (len < 0) {
- TPL_WARN_ERRNO("event fd(%d) read failed.",
- tpl_worker_thread.event_fd);
- continue;
- } else {
- continue;
- }
- }
- } else if (ev_list[i].data.ptr == tdm_client) {
- /* vblank */
- tdm_error tdm_err = tdm_client_handle_events(tdm_client);
-
- if (tdm_err != TDM_ERROR_NONE) {
- TPL_ERR("Failed to tdm_client_handle_events");
- /**
- * TODO: Error handling
- *
- * Currently, no error handling implemented to keep flow identical
- * to ensure no side effect.
- */
- }
- /* process in __tpl_worker_cb_vblank */
- } else {
- /* draw done */
- tpl_worker_surface_t *surface = ev_list[i].data.ptr;
-
- if (!(ev_list[i].events & EPOLLIN))
- continue;
-
- if (surface->draw_wait_buffer) {
- int wait_fd;
-
- wait_fd = surface->draw_wait_fd_get(surface->surface,
- surface->draw_wait_buffer);
- if (wait_fd == -1) {
- if (surface->draw_done)
- surface->draw_done(surface->surface, surface->draw_wait_buffer,
- TPL_ERROR_INVALID_OPERATION);
- surface->draw_wait_buffer = NULL;
- } else {
- int fence_result;
-
- switch (fence_result = tbm_sync_fence_wait(wait_fd, 0)) {
- case 0:
- TPL_ERR_ERRNO("sync_fence_wait return error.");
- break;
- case 1:
- /* some time recieve event two times */
- epoll_ctl(epoll_fd, EPOLL_CTL_DEL, wait_fd, NULL);
- if (surface->draw_done)
- surface->draw_done(surface->surface,
- surface->draw_wait_buffer,
- TPL_ERROR_NONE);
- surface->draw_wait_buffer = NULL;
- break;
- case -1:
- TPL_WARN("sync_fence_wait return timeout.");
- break;
- }
- }
- } else {
- TPL_WARN("recieve already signaled event\n");
- }
-
- /* prepare next buffer in loop start time */
- }
- }
- }
-
-cleanup:
- /* thread cleanup */
- if (tdm_vblank)
- tdm_client_vblank_destroy(tdm_vblank);
- if (tdm_client)
- tdm_client_destroy(tdm_client);
-
- if (epoll_fd != -1) {
- close(epoll_fd);
- epoll_fd = -1;
- }
- if (tpl_worker_thread.event_fd != -1) {
- close(tpl_worker_thread.event_fd);
- tpl_worker_thread.event_fd = -1;
- }
-
- return NULL;
-}
-
-static void __attribute__((constructor))
-__tpl_worker_init(void)
-{
- /*
- * It can be move to display or surface create function
- * with pthread_once
- */
- tpl_worker_thread.running = 1;
- tpl_worker_thread.support_vblank = TPL_FALSE;
-
- if (pthread_mutex_init(&tpl_worker_thread.surface_mutex, NULL) != 0) {
- TPL_ERR_ERRNO("surface list mutex init failed");
- goto error;
- }
-
- __tpl_list_init(&tpl_worker_thread.surface_list);
-
- if (pthread_create(&tpl_worker_thread.worker_id, NULL,
- __tpl_worker_thread_loop,
- NULL) != 0) {
- TPL_ERR_ERRNO("worker thread create failed");
- goto error_thread_create;
- }
- /*pthread_setname_np(tpl_worker_thread.worker_id, "tpl_worker_thread");*/
-
- return;
-
-error_thread_create:
- pthread_mutex_destroy(&tpl_worker_thread.surface_mutex);
-
-error:
- tpl_worker_thread.running = 0;
-}
-
-static void __attribute__((destructor))
-__tpl_worker_fini(void)
-{
- if (tpl_worker_thread.running == 0)
- return;
-
- /* deinitailize global object */
- tpl_worker_thread.running = 0;
-
- /* maybe EPOLLRDHUP not work with eventfd */
- /* close(tpl_worker_thread.event_fd); */
- __tpl_worker_event_send();
-
- if (__tpl_list_get_count(&tpl_worker_thread.surface_list))
- TPL_WARN("called destructor, but tpl surface count: %d",
- __tpl_list_get_count(&tpl_worker_thread.surface_list));
-
- pthread_join(tpl_worker_thread.worker_id, NULL);
- pthread_mutex_destroy(&tpl_worker_thread.surface_mutex);
-}