tpl_wl_vk_thread: Integrated wl_vk_thread backend. 74/161974/2
authorjoonbum.ko <joonbum.ko@samsung.com>
Fri, 20 Oct 2017 06:04:25 +0000 (15:04 +0900)
committerjoonbum.ko <joonbum.ko@samsung.com>
Tue, 28 Nov 2017 10:52:50 +0000 (19:52 +0900)
Change-Id: Ie4491b28750f5639da02f474a3e5fdb742c6f07b
Signed-off-by: joonbum.ko <joonbum.ko@samsung.com>
src/Makefile.am
src/tpl.c
src/tpl.h
src/tpl_internal.h
src/tpl_wayland_egl_thread.c
src/tpl_wl_vk_thread.c [new file with mode: 0644]

index d29509f..af61301 100644 (file)
@@ -26,6 +26,7 @@ libtpl_egl_la_SOURCES += tpl_wayland_egl.c \
                          tpl_wl_egl_thread.c \
                          tpl_wayland_egl_thread.c \
                          tpl_wayland_vk_wsi.c \
+                         tpl_wl_vk_thread.c \
                          tpl_worker_thread.c \
                          wayland-vulkan/wayland-vulkan-protocol.c
 endif
index 0f75d5f..7b0a213 100644 (file)
--- a/src/tpl.c
+++ b/src/tpl.c
@@ -301,6 +301,9 @@ __tpl_display_init_backend(tpl_display_t *display, tpl_backend_type_t type)
        case TPL_BACKEND_WAYLAND_VULKAN_WSI:
                __tpl_display_init_backend_wayland_vk_wsi(&display->backend);
                break;
+       case TPL_BACKEND_WAYLAND_VULKAN_WSI_THREAD:
+               __tpl_display_init_backend_wl_vk_wsi_thread(&display->backend);
+               break;
        case TPL_BACKEND_TBM:
                __tpl_display_init_backend_tbm(&display->backend, type);
                break;
@@ -343,6 +346,9 @@ __tpl_surface_init_backend(tpl_surface_t *surface, tpl_backend_type_t type)
        case TPL_BACKEND_WAYLAND_VULKAN_WSI:
                __tpl_surface_init_backend_wayland_vk_wsi(&surface->backend);
                break;
+       case TPL_BACKEND_WAYLAND_VULKAN_WSI_THREAD:
+               __tpl_surface_init_backend_wl_vk_wsi_thread(&surface->backend);
+               break;
        case TPL_BACKEND_TBM:
                __tpl_surface_init_backend_tbm(&surface->backend, type);
                break;
index ff20ff4..0ebf067 100644 (file)
--- a/src/tpl.h
+++ b/src/tpl.h
@@ -194,6 +194,7 @@ typedef enum {
        TPL_BACKEND_X11_DRI3,
        TPL_BACKEND_TBM,
        TPL_BACKEND_WAYLAND_VULKAN_WSI,
+       TPL_BACKEND_WAYLAND_VULKAN_WSI_THREAD,
        TPL_BACKEND_TBM_VULKAN_WSI,
        TPL_BACKEND_COUNT,
        TPL_BACKEND_MAX
index 2fa642f..56552a4 100644 (file)
@@ -220,6 +220,7 @@ void __tpl_display_init_backend_tbm(tpl_display_backend_t *backend,
 void __tpl_display_init_backend_wayland_egl(tpl_display_backend_t *backend);
 void __tpl_display_init_backend_wl_egl_thread(tpl_display_backend_t *backend);
 void __tpl_display_init_backend_wayland_vk_wsi(tpl_display_backend_t *backend);
+void __tpl_display_init_backend_wl_vk_wsi_thread(tpl_display_backend_t *backend);
 void __tpl_display_init_backend_x11_dri2(tpl_display_backend_t *backend);
 void __tpl_display_init_backend_x11_dri3(tpl_display_backend_t *backend);
 void __tpl_surface_init_backend_gbm(tpl_surface_backend_t *backend);
@@ -228,6 +229,7 @@ void __tpl_surface_init_backend_tbm(tpl_surface_backend_t *backend,
 void __tpl_surface_init_backend_wayland_egl(tpl_surface_backend_t *backend);
 void __tpl_surface_init_backend_wl_egl_thread(tpl_surface_backend_t *backend);
 void __tpl_surface_init_backend_wayland_vk_wsi(tpl_surface_backend_t *backend);
+void __tpl_surface_init_backend_wl_vk_wsi_thread(tpl_surface_backend_t *backend);
 void __tpl_surface_init_backend_x11_dri2(tpl_surface_backend_t *backend);
 void __tpl_surface_init_backend_x11_dri3(tpl_surface_backend_t *backend);
 
index ad49932..7f12646 100644 (file)
@@ -861,8 +861,6 @@ _twe_display_vk_init(twe_wl_disp_source *disp_source)
                                                   NULL);
        }
 
-       TPL_LOG_T("WL_VK", "wl_vk_client(%p) init.", disp_source->wl_vk_client);
-
 fini:
        if (queue)
                wl_event_queue_destroy(queue);
@@ -950,7 +948,8 @@ twe_display_add(twe_thread* thread,
        source->gfd.revents = 0;
        __tpl_object_init(&source->obj, TPL_OBJECT_DISPLAY, NULL);
 
-       if (backend == TPL_BACKEND_WAYLAND_VULKAN_WSI) {
+       if (backend == TPL_BACKEND_WAYLAND_VULKAN_WSI ||
+                       backend == TPL_BACKEND_WAYLAND_VULKAN_WSI_THREAD) {
                source->is_vulkan_dpy = TPL_TRUE;
                source->surface_capabilities.min_buffer = 2;
                source->surface_capabilities.max_buffer = VK_CLIENT_QUEUE_SIZE;
@@ -1658,6 +1657,10 @@ _twe_thread_wl_vk_surface_commit(twe_wl_surf_source *surf_source,
 
        buf_info->sync_timestamp++;
 
+       TPL_LOG_T("WL_VK", "[COMMIT] wl_buffer(%p) tbm_surface(%p) bo(%d)",
+                         buf_info->wl_buffer, tbm_surface,
+                         tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0)));
+
        if (surf_source->swapchain_properties.present_mode
                        == TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED) {
                if (_twe_surface_wait_vblank(surf_source) != TPL_ERROR_NONE)
@@ -1801,6 +1804,9 @@ _twe_thread_wl_surface_acquire_and_commit(twe_wl_surf_source *surf_source)
                        return;
                }
 
+               TRACE_ASYNC_END((int)tbm_surface, "DRAWING BO(%d)",
+                                               tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0)));
+
                tbm_surface_internal_ref(tbm_surface);
 
                tbm_surface_internal_get_user_data(tbm_surface, KEY_BUFFER_INFO,
@@ -1824,9 +1830,16 @@ _twe_thread_wl_surface_acquire_and_commit(twe_wl_surf_source *surf_source)
 
                        case TPL_DISPLAY_PRESENT_MODE_MAILBOX:
                                if (surf_source->draw_done_buffer) {
+                                       g_mutex_lock(&surf_source->free_queue_mutex);
+                                       TPL_LOG_T("WL_VK", "[SKIP] tbm_surface(%p) bo(%d)",
+                                                         tbm_surface,
+                                                         tbm_bo_export(tbm_surface_internal_get_bo(
+                                                                         tbm_surface, 0)));
                                        tbm_surface_internal_unref(surf_source->draw_done_buffer);
                                        tbm_surface_queue_release(surf_source->tbm_queue,
                                                                                          surf_source->draw_done_buffer);
+                                       g_cond_signal(&surf_source->free_queue_cond);
+                                       g_mutex_unlock(&surf_source->free_queue_mutex);
                                }
 
                                surf_source->draw_done_buffer = tbm_surface;
@@ -1871,7 +1884,6 @@ static gboolean
 _twe_thread_wl_surface_dispatch(GSource *source, GSourceFunc cb, gpointer data)
 {
        twe_wl_surf_source *surf_source = (twe_wl_surf_source *)source;
-       twe_wl_disp_source *disp_source = surf_source->disp_source;
        GIOCondition cond;
 
        if (g_source_is_destroyed(source)) {
@@ -1890,8 +1902,7 @@ _twe_thread_wl_surface_dispatch(GSource *source, GSourceFunc cb, gpointer data)
                        TPL_ERR("Failed to read from event_fd(%d)",
                                        surf_source->event_fd);
 
-               if (!disp_source->is_vulkan_dpy)
-                       _twe_thread_wl_surface_acquire_and_commit(surf_source);
+               _twe_thread_wl_surface_acquire_and_commit(surf_source);
        }
 
        return G_SOURCE_CONTINUE;
@@ -2355,6 +2366,24 @@ twe_surface_create_swapchain(twe_surface_h twe_surface,
                return TPL_ERROR_OUT_OF_MEMORY;
        }
 
+       if (tbm_surface_queue_add_trace_cb(surf_source->tbm_queue,
+                       __cb_tbm_queue_trace_callback,
+                       (void *)surf_source) != TBM_SURFACE_QUEUE_ERROR_NONE) {
+               TPL_ERR("Failed to register trace callback to tbm_surface_queue(%p)",
+                               surf_source->tbm_queue);
+               tbm_surface_queue_destroy(surf_source->tbm_queue);
+               return TPL_ERROR_INVALID_OPERATION;
+       }
+
+       if (tbm_surface_queue_add_acquirable_cb(surf_source->tbm_queue,
+                       __cb_tbm_queue_acquirable_callback,
+                       (void *)surf_source) != TBM_SURFACE_QUEUE_ERROR_NONE) {
+               TPL_ERR("Failed to register acquirable callback to tbm_surface_queue(%p)",
+                               surf_source->tbm_queue);
+               tbm_surface_queue_destroy(surf_source->tbm_queue);
+               return TPL_ERROR_INVALID_OPERATION;
+       }
+
        surf_source->format = format;
        surf_source->swapchain_properties.width = width;
        surf_source->swapchain_properties.height = height;
@@ -2365,7 +2394,7 @@ twe_surface_create_swapchain(twe_surface_h twe_surface,
                          twe_surface, surf_source->tbm_queue);
        TPL_LOG_T("WL_VK",
                          "[SWAPCHAIN_CREATE][2/2] w(%d) h(%d) f(%d) p(%d) b_cnt(%d)",
-                         width, height, present_mode, buffer_count);
+                         width, height, format, present_mode, buffer_count);
 
        return TPL_ERROR_NONE;
 }
diff --git a/src/tpl_wl_vk_thread.c b/src/tpl_wl_vk_thread.c
new file mode 100644 (file)
index 0000000..fd518bf
--- /dev/null
@@ -0,0 +1,616 @@
+#define inline __inline__
+#undef inline
+
+#include "tpl_internal.h"
+
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#include <tbm_surface_queue.h>
+
+#include <tbm_sync.h>
+
+#include "tpl_wayland_egl_thread.h"
+
+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_display {
+       twe_thread *wl_thread;
+       twe_display_h twe_display;
+};
+
+struct _tpl_wayland_vk_wsi_surface {
+       twe_surface_h twe_surface;
+       tbm_surface_queue_h tbm_queue;
+       int buffer_count;
+};
+
+static tpl_result_t __tpl_wl_vk_wsi_surface_destroy_swapchain(
+       tpl_surface_t *surface);
+
+static TPL_INLINE tpl_bool_t
+__tpl_wl_vk_wsi_display_is_wl_display(tpl_handle_t native_dpy)
+{
+       if (!native_dpy) return TPL_FALSE;
+
+       if (twe_check_native_handle_is_wl_display(native_dpy))
+               return TPL_TRUE;
+
+       return TPL_FALSE;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_display_init(tpl_display_t *display)
+{
+       tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display = NULL;
+
+       TPL_ASSERT(display);
+
+       /* Do not allow default display in wayland */
+       if (!display->native_handle) {
+               TPL_ERR("Invalid native handle for display.");
+               return TPL_ERROR_INVALID_PARAMETER;
+       }
+
+       wayland_vk_wsi_display = (tpl_wayland_vk_wsi_display_t *) calloc(1,
+                                                        sizeof(tpl_wayland_vk_wsi_display_t));
+       if (!wayland_vk_wsi_display) {
+               TPL_ERR("Failed to allocate memory for new tpl_wayland_vk_wsi_display_t.");
+               return TPL_ERROR_OUT_OF_MEMORY;
+       }
+
+       display->backend.data = wayland_vk_wsi_display;
+
+       if (twe_check_native_handle_is_wl_display(display->native_handle)) {
+               wayland_vk_wsi_display->wl_thread = twe_thread_create();
+               if (!wayland_vk_wsi_display->wl_thread) {
+                       TPL_ERR("Failed to create twe_thread.");
+                       goto free_display;
+               }
+
+               wayland_vk_wsi_display->twe_display =
+                       twe_display_add(wayland_vk_wsi_display->wl_thread,
+                                                       display->native_handle,
+                                                       display->backend.type);
+               if (!wayland_vk_wsi_display->twe_display) {
+                       TPL_ERR("Failed to add native_display(%p) to thread(%p)",
+                                       display->native_handle,
+                                       wayland_vk_wsi_display->wl_thread);
+                       goto free_display;
+               }
+
+       } else {
+               TPL_ERR("Invalid native handle for display.");
+               goto free_display;
+       }
+
+       TPL_LOG_T("WL_VK",
+                         "[INIT DISPLAY] wayland_vk_wsi_display(%p) twe_thread(%p) twe_display(%p)",
+                         wayland_vk_wsi_display,
+                         wayland_vk_wsi_display->wl_thread,
+                         wayland_vk_wsi_display->twe_display);
+
+       return TPL_ERROR_NONE;
+
+free_display:
+       if (wayland_vk_wsi_display) {
+               if (wayland_vk_wsi_display->twe_display)
+                       twe_display_del(wayland_vk_wsi_display->twe_display);
+               if (wayland_vk_wsi_display->wl_thread)
+                       twe_thread_destroy(wayland_vk_wsi_display->wl_thread);
+
+               wayland_vk_wsi_display->wl_thread = NULL;
+               wayland_vk_wsi_display->twe_display = NULL;
+
+               free(wayland_vk_wsi_display);
+               display->backend.data = NULL;
+       }
+
+       return TPL_ERROR_INVALID_OPERATION;
+}
+
+static void
+__tpl_wl_vk_wsi_display_fini(tpl_display_t *display)
+{
+       tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display;
+
+       TPL_ASSERT(display);
+
+       wayland_vk_wsi_display = (tpl_wayland_vk_wsi_display_t *)display->backend.data;
+       if (wayland_vk_wsi_display) {
+
+               TPL_LOG_T("WL_VK",
+                                 "[FINI] wayland_vk_wsi_display(%p) twe_thread(%p) twe_display(%p)",
+                                 wayland_vk_wsi_display,
+                                 wayland_vk_wsi_display->wl_thread,
+                                 wayland_vk_wsi_display->twe_display);
+
+               if (wayland_vk_wsi_display->twe_display) {
+                       tpl_result_t ret = TPL_ERROR_NONE;
+                       ret = twe_display_del(wayland_vk_wsi_display->twe_display);
+                       if (ret != TPL_ERROR_NONE)
+                               TPL_ERR("Failed to delete twe_display(%p) from twe_thread(%p)",
+                                               wayland_vk_wsi_display->twe_display,
+                                               wayland_vk_wsi_display->wl_thread);
+                       wayland_vk_wsi_display->twe_display = NULL;
+               }
+
+               if (wayland_vk_wsi_display->wl_thread) {
+                       twe_thread_destroy(wayland_vk_wsi_display->wl_thread);
+                       wayland_vk_wsi_display->wl_thread = NULL;
+               }
+
+               free(wayland_vk_wsi_display);
+       }
+       display->backend.data = NULL;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_display_query_config(tpl_display_t *display,
+               tpl_surface_type_t surface_type,
+               int red_size, int green_size,
+               int blue_size, int alpha_size,
+               int color_depth, int *native_visual_id,
+               tpl_bool_t *is_slow)
+{
+       TPL_ASSERT(display);
+
+       if (surface_type == TPL_SURFACE_TYPE_WINDOW && red_size == 8 &&
+                       green_size == 8 && blue_size == 8 &&
+                       (color_depth == 32 || color_depth == 24)) {
+
+               if (alpha_size == 8) {
+                       if (native_visual_id) *native_visual_id = TBM_FORMAT_ARGB8888;
+                       if (is_slow) *is_slow = TPL_FALSE;
+                       return TPL_ERROR_NONE;
+               }
+               if (alpha_size == 0) {
+                       if (native_visual_id) *native_visual_id = TBM_FORMAT_XRGB8888;
+                       if (is_slow) *is_slow = TPL_FALSE;
+                       return TPL_ERROR_NONE;
+               }
+       }
+
+       return TPL_ERROR_INVALID_PARAMETER;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_display_filter_config(tpl_display_t *display,
+                                                                         int *visual_id,
+                                                                         int alpha_size)
+{
+       TPL_IGNORE(display);
+       TPL_IGNORE(visual_id);
+       TPL_IGNORE(alpha_size);
+       return TPL_ERROR_NONE;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_display_query_window_supported_buffer_count(
+       tpl_display_t *display,
+       tpl_handle_t window, int *min, int *max)
+{
+       tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display = NULL;
+       tpl_result_t res = TPL_ERROR_NONE;
+
+       TPL_ASSERT(display);
+       TPL_ASSERT(window);
+
+       wayland_vk_wsi_display = (tpl_wayland_vk_wsi_display_t *)display->backend.data;
+
+       if (!wayland_vk_wsi_display) return TPL_ERROR_INVALID_OPERATION;
+
+       res = twe_display_get_buffer_count(wayland_vk_wsi_display->twe_display,
+                                                                          min, max);
+       if (res != TPL_ERROR_NONE) {
+               TPL_ERR("Failed to query buffer count. twe_display(%p)",
+                               wayland_vk_wsi_display->twe_display);
+               return res;
+       }
+
+       return TPL_ERROR_NONE;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_display_query_window_supported_present_modes(
+       tpl_display_t *display,
+       tpl_handle_t window, int *modes)
+{
+       tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display = NULL;
+       tpl_result_t res = TPL_ERROR_NONE;
+
+       TPL_ASSERT(display);
+       TPL_ASSERT(window);
+
+       wayland_vk_wsi_display = (tpl_wayland_vk_wsi_display_t *)display->backend.data;
+
+       if (!wayland_vk_wsi_display) return TPL_ERROR_INVALID_OPERATION;
+
+       if (modes) {
+               res = twe_display_get_present_mode(wayland_vk_wsi_display->twe_display,
+                                                                                  modes);
+               if (res != TPL_ERROR_NONE) {
+                       TPL_ERR("Failed to query present modes. twe_display(%p)",
+                                       wayland_vk_wsi_display->twe_display);
+                       return res;
+               }
+       }
+
+       return TPL_ERROR_NONE;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_surface_init(tpl_surface_t *surface)
+{
+       tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL;
+       tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display = NULL;
+       twe_surface_h twe_surface = NULL;
+
+       TPL_ASSERT(surface);
+       TPL_ASSERT(surface->type == TPL_SURFACE_TYPE_WINDOW);
+       TPL_ASSERT(surface->native_handle);
+
+       wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *) calloc(1,
+                                                        sizeof(tpl_wayland_vk_wsi_surface_t));
+       if (!wayland_vk_wsi_surface) {
+               TPL_ERR("Failed to allocate memory for new tpl_wayland_vk_wsi_surface_t.");
+               return TPL_ERROR_OUT_OF_MEMORY;
+       }
+
+       wayland_vk_wsi_display =
+               (tpl_wayland_vk_wsi_display_t *)surface->display->backend.data;
+       if (!wayland_vk_wsi_display) {
+               TPL_ERR("Invalid parameter. wayland_vk_wsi_display(%p)",
+                               wayland_vk_wsi_display);
+               free(wayland_vk_wsi_surface);
+               return TPL_ERROR_INVALID_PARAMETER;
+       }
+
+       surface->backend.data = (void *)wayland_vk_wsi_surface;
+       wayland_vk_wsi_surface->tbm_queue = NULL;
+
+       twe_surface = twe_surface_add(wayland_vk_wsi_display->wl_thread,
+                                                                 wayland_vk_wsi_display->twe_display,
+                                                                 surface->native_handle,
+                                                                 surface->format);
+       if (!twe_surface) {
+               TPL_ERR("Failed to add native_surface(%p) to thread(%p)",
+                               surface->native_handle, wayland_vk_wsi_display->wl_thread);
+               free(wayland_vk_wsi_surface);
+               surface->backend.data = NULL;
+               return TPL_ERROR_OUT_OF_MEMORY;
+       }
+
+       wayland_vk_wsi_surface->twe_surface = twe_surface;
+
+       TPL_LOG_T("WL_VK",
+                         "[INIT]tpl_surface(%p) tpl_wayland_vk_wsi_surface(%p) twe_surface(%p)",
+                         surface, wayland_vk_wsi_surface, twe_surface);
+
+       return TPL_ERROR_NONE;
+}
+
+static void
+__tpl_wl_vk_wsi_surface_fini(tpl_surface_t *surface)
+{
+       tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL;
+       tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display = NULL;
+
+       TPL_ASSERT(surface);
+       TPL_ASSERT(surface->display);
+
+       wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *) surface->backend.data;
+       if (wayland_vk_wsi_surface == NULL) return;
+
+       wayland_vk_wsi_display = (tpl_wayland_vk_wsi_display_t *)
+                                                        surface->display->backend.data;
+       if (wayland_vk_wsi_display == NULL) return;
+
+       if (wayland_vk_wsi_surface->tbm_queue)
+               __tpl_wl_vk_wsi_surface_destroy_swapchain(surface);
+
+       TPL_LOG_T("WL_VK",
+                         "[FINI] wayland_vk_wsi_surface(%p) native_surface(%p) twe_surface(%p)",
+                         wayland_vk_wsi_surface, surface->native_handle,
+                         wayland_vk_wsi_surface->twe_surface);
+
+       if (twe_surface_del(wayland_vk_wsi_surface->twe_surface)
+                       != TPL_ERROR_NONE) {
+               TPL_ERR("Failed to delete twe_surface(%p) from thread(%p)",
+                               wayland_vk_wsi_surface->twe_surface,
+                               wayland_vk_wsi_display->wl_thread);
+       }
+
+       wayland_vk_wsi_surface->twe_surface = NULL;
+
+       free(wayland_vk_wsi_surface);
+       surface->backend.data = NULL;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_surface_enqueue_buffer(tpl_surface_t *surface,
+               tbm_surface_h tbm_surface,
+               int num_rects, const int *rects,
+               tbm_fd sync_fence)
+{
+
+       TPL_ASSERT(surface);
+       TPL_ASSERT(surface->display);
+       TPL_ASSERT(surface->display->native_handle);
+       TPL_ASSERT(tbm_surface);
+
+       tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface =
+               (tpl_wayland_vk_wsi_surface_t *) surface->backend.data;
+       tbm_surface_queue_error_e tsq_err;
+
+       if (!tbm_surface_internal_is_valid(tbm_surface)) {
+               TPL_ERR("Failed to enqueue tbm_surface(%p) Invalid value.",
+                               tbm_surface);
+               return TPL_ERROR_INVALID_PARAMETER;
+       }
+
+       if (sync_fence != -1) {
+               tpl_result_t res = TPL_ERROR_NONE;
+               res = twe_surface_set_sync_fd(tbm_surface, sync_fence);
+               if (res != TPL_ERROR_NONE) {
+                       TPL_ERR("Failed to set sync_fd to tbm_surface(%p)", tbm_surface);
+                       tbm_surface_internal_unref(tbm_surface);
+                       return res;
+               }
+       }
+
+       tsq_err = tbm_surface_queue_enqueue(wayland_vk_wsi_surface->tbm_queue,
+                                                                               tbm_surface);
+       if (tsq_err == TBM_SURFACE_QUEUE_ERROR_NONE) {
+               tbm_surface_internal_unref(tbm_surface);
+       } else {
+               TPL_ERR("Failed to enqeueue tbm_surface. | tsq_err = %d", tsq_err);
+               return TPL_ERROR_INVALID_OPERATION;
+       }
+
+       TPL_LOG_T("WL_VK", "[ENQ] tbm_surface(%p) bo(%d)",
+                         tbm_surface,
+                         tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0)));
+
+       return TPL_ERROR_NONE;
+}
+
+static tpl_bool_t
+__tpl_wl_vk_wsi_surface_validate(tpl_surface_t *surface)
+{
+       TPL_ASSERT(surface);
+       TPL_ASSERT(surface->backend.data);
+
+       return TPL_TRUE;
+}
+
+static tbm_surface_h
+__tpl_wl_vk_wsi_surface_dequeue_buffer(tpl_surface_t *surface,
+                                                                                       uint64_t timeout_ns,
+                                                                                       tbm_fd *sync_fence)
+{
+       TPL_ASSERT(surface);
+       TPL_ASSERT(surface->backend.data);
+       TPL_ASSERT(surface->display);
+
+       tbm_surface_h tbm_surface = NULL;
+       tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface =
+               (tpl_wayland_vk_wsi_surface_t *)surface->backend.data;
+       tbm_surface_queue_error_e tsq_err = 0;
+
+       if (sync_fence)
+               *sync_fence = -1;
+
+       if (!tbm_surface_queue_can_dequeue(wayland_vk_wsi_surface->tbm_queue, 0)) {
+               if (timeout_ns == 0) return NULL;
+               else {
+                       tpl_result_t res = TPL_ERROR_NONE;
+                       res = twe_surface_wait_dequeueable(wayland_vk_wsi_surface->twe_surface,
+                                                                                          timeout_ns);
+                       if (res == TPL_ERROR_TIME_OUT) {
+                               TPL_ERR("Failed to get buffer during timeout_ns(%u)", timeout_ns);
+                               return NULL;
+                       } else if (res != TPL_ERROR_NONE) {
+                               TPL_ERR("Invalid parameter. twe_surface(%p) timeout_ns(%u)",
+                                               wayland_vk_wsi_surface->twe_surface, timeout_ns);
+                               return NULL;
+                       }
+               }
+       }
+
+       tsq_err = tbm_surface_queue_dequeue(wayland_vk_wsi_surface->tbm_queue,
+                                                                               &tbm_surface);
+       if (!tbm_surface) {
+               TPL_ERR("Failed to get tbm_surface from tbm_surface_queue | tsq_err = %d",
+                               tsq_err);
+               return NULL;
+       }
+
+       tbm_surface_internal_ref(tbm_surface);
+
+       if (sync_fence) {
+               *sync_fence = twe_surface_create_sync_fd(tbm_surface);
+       }
+
+       TPL_LOG_T("WL_VK", "[DEQ] tbm_surface(%p) bo(%d)",
+                         tbm_surface,
+                         tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0)));
+
+       return tbm_surface;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_surface_get_swapchain_buffers(tpl_surface_t *surface,
+               tbm_surface_h **buffers,
+               int *buffer_count)
+{
+       tbm_surface_h buffer = NULL;
+       tbm_surface_h *swapchain_buffers = NULL;
+       tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL;
+       tbm_surface_queue_error_e tsq_err;
+       int i, dequeue_count;
+       tpl_result_t ret = TPL_ERROR_NONE;
+
+       TPL_ASSERT(surface);
+       TPL_ASSERT(surface->backend.data);
+       TPL_ASSERT(surface->display);
+       TPL_ASSERT(buffers);
+       TPL_ASSERT(buffer_count);
+
+       wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *)surface->backend.data;
+       swapchain_buffers = (tbm_surface_h *)calloc(
+                                                       wayland_vk_wsi_surface->buffer_count, sizeof(tbm_surface_h));
+       if (!swapchain_buffers) {
+               TPL_ERR("Failed to allocate memory for buffers.");
+               return TPL_ERROR_OUT_OF_MEMORY;
+       }
+
+       for (i = 0 ; i < wayland_vk_wsi_surface->buffer_count ; i++) {
+               tsq_err = tbm_surface_queue_dequeue(wayland_vk_wsi_surface->tbm_queue, &buffer);
+               if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
+                       TPL_ERR("Failed to get tbm_surface from tbm_surface_queue | tsq_err = %d",
+                                       tsq_err);
+                       dequeue_count = i;
+                       ret = TPL_ERROR_OUT_OF_MEMORY;
+                       goto get_buffer_fail;
+               }
+               swapchain_buffers[i] = buffer;
+               TPL_DEBUG("swapchain_buffers[%d] = tbm_surface(%p)", i, buffer);
+       }
+
+       for (i = 0 ; i < wayland_vk_wsi_surface->buffer_count ; i++) {
+               tsq_err = tbm_surface_queue_release(wayland_vk_wsi_surface->tbm_queue,
+                                                                                       swapchain_buffers[i]);
+               if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
+                       TPL_ERR("Failed to release tbm_surface. | tsq_err = %d", tsq_err);
+                       ret = TPL_ERROR_INVALID_OPERATION;
+                       goto release_buffer_fail;
+               }
+       }
+
+       *buffers = swapchain_buffers;
+       *buffer_count = wayland_vk_wsi_surface->buffer_count;
+       return TPL_ERROR_NONE;
+
+get_buffer_fail:
+       for (i = 0 ; i < dequeue_count ; i++) {
+               tsq_err = tbm_surface_queue_release(wayland_vk_wsi_surface->tbm_queue,
+                                                                                       swapchain_buffers[i]);
+               if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
+                       TPL_ERR("Failed to release tbm_surface. | tsq_err = %d", tsq_err);
+                       goto release_buffer_fail;
+               }
+       }
+
+release_buffer_fail:
+       free(swapchain_buffers);
+       return ret;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_surface_create_swapchain(tpl_surface_t *surface,
+               tbm_format format, int width,
+               int height, int buffer_count, int present_mode)
+{
+       tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL;
+       tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display = NULL;
+       tpl_result_t res = TPL_ERROR_NONE;
+
+       TPL_ASSERT(surface);
+       TPL_ASSERT(surface->backend.data);
+       TPL_ASSERT(surface->display);
+
+       wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *) surface->backend.data;
+       TPL_ASSERT(wayland_vk_wsi_surface);
+
+       wayland_vk_wsi_display = (tpl_wayland_vk_wsi_display_t *)
+                                                        surface->display->backend.data;
+       TPL_ASSERT(wayland_vk_wsi_display);
+
+       res = twe_surface_create_swapchain(wayland_vk_wsi_surface->twe_surface,
+                                                                          width, height, format,
+                                                                          buffer_count, present_mode);
+       if (res != TPL_ERROR_NONE) {
+               TPL_ERR("Failed to create swapchain. twe_surface(%p)",
+                               wayland_vk_wsi_surface->twe_surface);
+               return res;
+       }
+
+       wayland_vk_wsi_surface->tbm_queue = twe_surface_get_tbm_queue(
+                       wayland_vk_wsi_surface->twe_surface);
+       wayland_vk_wsi_surface->buffer_count = buffer_count;
+
+       return TPL_ERROR_NONE;
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_surface_destroy_swapchain(tpl_surface_t *surface)
+{
+       tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL;
+       tpl_result_t res = TPL_ERROR_NONE;
+
+       TPL_ASSERT(surface);
+       TPL_ASSERT(surface->backend.data);
+       TPL_ASSERT(surface->display);
+
+       wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *) surface->backend.data;
+       TPL_ASSERT(wayland_vk_wsi_surface);
+
+       res = twe_surface_destroy_swapchain(wayland_vk_wsi_surface->twe_surface);
+       if (res != TPL_ERROR_NONE) {
+               TPL_ERR("Failed to destroy swapchain. twe_surface(%p)",
+                               wayland_vk_wsi_surface->twe_surface);
+               return res;
+       }
+
+       return TPL_ERROR_NONE;
+}
+
+tpl_bool_t
+__tpl_display_choose_backend_wayland_vk_wsi_thread(tpl_handle_t native_dpy)
+{
+       if (!native_dpy) return TPL_FALSE;
+
+       if (twe_check_native_handle_is_wl_display(native_dpy))
+               return TPL_TRUE;
+
+       return TPL_FALSE;
+}
+
+void
+__tpl_display_init_backend_wl_vk_wsi_thread(tpl_display_backend_t *backend)
+{
+       TPL_ASSERT(backend);
+
+       backend->type = TPL_BACKEND_WAYLAND_VULKAN_WSI_THREAD;
+       backend->data = NULL;
+
+       backend->init = __tpl_wl_vk_wsi_display_init;
+       backend->fini = __tpl_wl_vk_wsi_display_fini;
+       backend->query_config = __tpl_wl_vk_wsi_display_query_config;
+       backend->filter_config = __tpl_wl_vk_wsi_display_filter_config;
+       backend->query_window_supported_buffer_count =
+               __tpl_wl_vk_wsi_display_query_window_supported_buffer_count;
+       backend->query_window_supported_present_modes =
+               __tpl_wl_vk_wsi_display_query_window_supported_present_modes;
+}
+
+void
+__tpl_surface_init_backend_wl_vk_wsi_thread(tpl_surface_backend_t *backend)
+{
+       TPL_ASSERT(backend);
+
+       backend->type = TPL_BACKEND_WAYLAND_VULKAN_WSI_THREAD;
+       backend->data = NULL;
+
+       backend->init = __tpl_wl_vk_wsi_surface_init;
+       backend->fini = __tpl_wl_vk_wsi_surface_fini;
+       backend->validate = __tpl_wl_vk_wsi_surface_validate;
+       backend->dequeue_buffer = __tpl_wl_vk_wsi_surface_dequeue_buffer;
+       backend->enqueue_buffer = __tpl_wl_vk_wsi_surface_enqueue_buffer;
+       backend->get_swapchain_buffers =
+               __tpl_wl_vk_wsi_surface_get_swapchain_buffers;
+       backend->create_swapchain = __tpl_wl_vk_wsi_surface_create_swapchain;
+       backend->destroy_swapchain = __tpl_wl_vk_wsi_surface_destroy_swapchain;
+}