--- /dev/null
+#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;
+ tbm_surface_h *swapchain_buffers;
+ int buffer_count;
+ tpl_bool_t is_activated;
+ tpl_bool_t reset;
+ tpl_util_atomic_uint swapchain_reference;
+};
+
+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, surface->num_buffers);
+ 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;
+ wayland_vk_wsi_surface->is_activated = TPL_FALSE;
+ wayland_vk_wsi_surface->swapchain_buffers = NULL;
+
+ 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);
+
+ if (wayland_vk_wsi_surface->swapchain_buffers) {
+ free(wayland_vk_wsi_surface->swapchain_buffers);
+ wayland_vk_wsi_surface->swapchain_buffers = NULL;
+ }
+
+ 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 there are received region information,
+ * save it to buf_info in tbm_surface user_data using below API. */
+ if (num_rects && rects) {
+ tpl_result_t ret = TPL_ERROR_NONE;
+ ret = twe_surface_set_damage_region(tbm_surface, num_rects, rects);
+ if (ret != TPL_ERROR_NONE) {
+ TPL_WARN("Failed to set damage region. num_rects(%d) rects(%p)",
+ num_rects, rects);
+ }
+ }
+ 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;
+ }
+
+ if (sync_fence != -1) {
+ tpl_result_t res = TPL_ERROR_NONE;
+ res = twe_surface_set_sync_fd(wayland_vk_wsi_surface->twe_surface,
+ tbm_surface, sync_fence);
+ if (res != TPL_ERROR_NONE) {
+ TPL_WARN("Failed to set sync_fd(%d). Fallback to async mode.",
+ sync_fence);
+ }
+ }
+
+ TPL_LOG_T("WL_VK", "[ENQ] tbm_surface(%p) bo(%d) sync_fence(%d)",
+ tbm_surface,
+ tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0)),
+ sync_fence);
+
+ 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);
+
+ tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface =
+ (tpl_wayland_vk_wsi_surface_t *)surface->backend.data;
+
+ return !(wayland_vk_wsi_surface->reset);
+}
+
+static tpl_result_t
+__tpl_wl_vk_wsi_surface_cancel_dequeued_buffer(tpl_surface_t *surface,
+ tbm_surface_h tbm_surface)
+{
+ tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL;
+ tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
+
+ wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *)surface->backend.data;
+ if (!wayland_vk_wsi_surface) {
+ TPL_ERR("Invalid backend surface. surface(%p) wayland_vk_wsi_surface(%p)",
+ surface, wayland_vk_wsi_surface);
+ return TPL_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!tbm_surface_internal_is_valid(tbm_surface)) {
+ TPL_ERR("Invalid buffer. tbm_surface(%p)", tbm_surface);
+ return TPL_ERROR_INVALID_PARAMETER;
+ }
+
+ tbm_surface_internal_unref(tbm_surface);
+
+ tsq_err = tbm_surface_queue_cancel_dequeue(wayland_vk_wsi_surface->tbm_queue,
+ tbm_surface);
+ if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) {
+ TPL_ERR("Failed to release tbm_surface(%p)", tbm_surface);
+ return TPL_ERROR_INVALID_OPERATION;
+ }
+
+ TPL_LOG_T("WL_VK", "[CANCEL BUFFER] tpl_surface(%p) tbm_surface(%p)",
+ surface, tbm_surface);
+
+ return TPL_ERROR_NONE;
+}
+
+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;
+ tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display =
+ (tpl_wayland_vk_wsi_display_t *)surface->display->backend.data;
+ tbm_surface_queue_error_e tsq_err = 0;
+ tpl_result_t lock_res = TPL_ERROR_NONE;
+ tpl_result_t res = TPL_ERROR_NONE;
+
+ if (sync_fence)
+ *sync_fence = -1;
+
+ TPL_OBJECT_UNLOCK(surface);
+ TRACE_BEGIN("WAIT_DEQUEUEABLE");
+ lock_res = twe_display_lock(wayland_vk_wsi_display->twe_display);
+ res = twe_surface_wait_dequeueable(wayland_vk_wsi_surface->twe_surface,
+ timeout_ns);
+ TRACE_END();
+ TPL_OBJECT_LOCK(surface);
+
+ if (res == TPL_ERROR_TIME_OUT) {
+ TPL_ERR("Failed to get buffer during timeout_ns(%" PRIu64 ")",
+ timeout_ns);
+ if (lock_res == TPL_ERROR_NONE)
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ return NULL;
+ } else if (res != TPL_ERROR_NONE) {
+ TPL_ERR("Invalid operation. twe_surface(%p) timeout_ns(%" PRIu64 ")",
+ wayland_vk_wsi_surface->twe_surface, timeout_ns);
+ if (lock_res == TPL_ERROR_NONE)
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ return NULL;
+ }
+
+ if (wayland_vk_wsi_surface->reset) {
+ TPL_LOG_T("WL_VK", "tbm_queue(%p) has been reset. Do not process dequeue.",
+ wayland_vk_wsi_surface->tbm_queue);
+ if (lock_res == TPL_ERROR_NONE)
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ 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(%p) | tsq_err = %d",
+ wayland_vk_wsi_surface->tbm_queue, tsq_err);
+ if (lock_res == TPL_ERROR_NONE)
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ 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_queue(%p) tbm_surface(%p) bo(%d)",
+ wayland_vk_wsi_surface->tbm_queue, tbm_surface,
+ tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0)));
+
+ if (lock_res == TPL_ERROR_NONE)
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+
+ 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)
+{
+ tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL;
+ tpl_wayland_vk_wsi_display_t *wayland_vk_wsi_display = NULL;
+ int i;
+ tpl_result_t ret = TPL_ERROR_NONE;
+
+ TPL_ASSERT(surface);
+ TPL_ASSERT(surface->backend.data);
+ TPL_ASSERT(surface->display);
+ TPL_ASSERT(surface->display->backend.data);
+ TPL_ASSERT(buffers);
+ TPL_ASSERT(buffer_count);
+
+ wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *)surface->backend.data;
+ wayland_vk_wsi_display = (tpl_wayland_vk_wsi_display_t *)surface->display->backend.data;
+
+ if (twe_display_lock(wayland_vk_wsi_display->twe_display) == TPL_ERROR_NONE) {
+ ret = twe_surface_get_swapchain_buffers(wayland_vk_wsi_surface->twe_surface,
+ NULL, buffer_count);
+ if (ret != TPL_ERROR_NONE) {
+ TPL_ERR("Failed to get buffer_count. twe_surface(%p)",
+ wayland_vk_wsi_surface->twe_surface);
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ return ret;
+ }
+
+ wayland_vk_wsi_surface->swapchain_buffers = (tbm_surface_h *)calloc(
+ *buffer_count,
+ sizeof(tbm_surface_h));
+ if (!wayland_vk_wsi_surface->swapchain_buffers) {
+ TPL_ERR("Failed to allocate memory for buffers.");
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ return TPL_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = twe_surface_get_swapchain_buffers(wayland_vk_wsi_surface->twe_surface,
+ wayland_vk_wsi_surface->swapchain_buffers,
+ buffer_count);
+ if (ret != TPL_ERROR_NONE) {
+ TPL_ERR("Failed to get swapchain_buffers. wayland_vk_wsi_surface(%p) twe_surface(%p)",
+ wayland_vk_wsi_surface, wayland_vk_wsi_surface->twe_surface);
+ free(wayland_vk_wsi_surface->swapchain_buffers);
+ wayland_vk_wsi_surface->swapchain_buffers = NULL;
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ return ret;
+ }
+
+ for (i = 0; i < *buffer_count; i++) {
+ if (wayland_vk_wsi_surface->swapchain_buffers[i]) {
+ TPL_DEBUG("swapchain_buffers[%d] = tbm_surface(%p) bo(%d)",
+ i, wayland_vk_wsi_surface->swapchain_buffers[i],
+ tbm_bo_export(tbm_surface_internal_get_bo(
+ wayland_vk_wsi_surface->swapchain_buffers[i], 0)));
+ tbm_surface_internal_ref(wayland_vk_wsi_surface->swapchain_buffers[i]);
+ }
+ }
+
+ *buffers = wayland_vk_wsi_surface->swapchain_buffers;
+
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ }
+
+ return TPL_ERROR_NONE;
+}
+
+static void
+__cb_tbm_queue_reset_callback(tbm_surface_queue_h surface_queue,
+ void *data)
+{
+ tpl_surface_t *surface = NULL;
+ tpl_wayland_vk_wsi_surface_t *wayland_vk_wsi_surface = NULL;
+ tpl_bool_t is_activated = TPL_FALSE;
+
+ surface = (tpl_surface_t *)data;
+ TPL_CHECK_ON_NULL_RETURN(surface);
+
+ wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *)surface->backend.data;
+ TPL_CHECK_ON_NULL_RETURN(wayland_vk_wsi_surface);
+
+ /* When queue_reset_callback is called, if is_activated is different from
+ * its previous state change the reset flag to TPL_TRUE to get a new buffer
+ * with the changed state(ACTIVATED/DEACTIVATED) at the next frame. */
+ is_activated = twe_surface_check_activated(wayland_vk_wsi_surface->twe_surface);
+
+ if (wayland_vk_wsi_surface->is_activated != is_activated) {
+ if (is_activated) {
+ TPL_LOG_T("WL_VK",
+ "[ACTIVATED_CB] wayland_vk_wsi_surface(%p) tbm_queue(%p)",
+ wayland_vk_wsi_surface, surface_queue);
+ } else {
+ TPL_LOG_T("WL_VK",
+ "[DEACTIVATED_CB] wayland_vk_wsi_surface(%p) tbm_queue(%p)",
+ wayland_vk_wsi_surface, surface_queue);
+ }
+ wayland_vk_wsi_surface->is_activated = is_activated;
+ }
+
+ wayland_vk_wsi_surface->reset = TPL_TRUE;
+
+ if (surface->reset_cb)
+ surface->reset_cb(surface->reset_data);
+}
+
+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);
+
+ if (wayland_vk_wsi_surface->tbm_queue) {
+ int old_width = tbm_surface_queue_get_width(wayland_vk_wsi_surface->tbm_queue);
+ int old_height = tbm_surface_queue_get_height(wayland_vk_wsi_surface->tbm_queue);
+
+ if (old_width != width || old_height != height) {
+ tbm_surface_queue_reset(wayland_vk_wsi_surface->tbm_queue,
+ width, height, format);
+ TPL_LOG_T("WL_VK",
+ "[RESIZE] wayland_vk_wsi_surface(%p) tbm_queue(%p), (%d x %d) -> (%d x %d)",
+ wayland_vk_wsi_surface, wayland_vk_wsi_surface->tbm_queue,
+ old_width, old_height, width, height);
+ }
+
+ if (wayland_vk_wsi_surface->swapchain_buffers) {
+ int i;
+ for (i = 0; i < wayland_vk_wsi_surface->buffer_count; i++) {
+ if (wayland_vk_wsi_surface->swapchain_buffers[i]) {
+ TPL_DEBUG("unref tbm_surface(%p)", wayland_vk_wsi_surface->swapchain_buffers[i]);
+ tbm_surface_internal_unref(wayland_vk_wsi_surface->swapchain_buffers[i]);
+ wayland_vk_wsi_surface->swapchain_buffers[i] = NULL;
+ }
+ }
+
+ free(wayland_vk_wsi_surface->swapchain_buffers);
+ wayland_vk_wsi_surface->swapchain_buffers = NULL;
+ }
+
+ wayland_vk_wsi_surface->buffer_count =
+ tbm_surface_queue_get_size(wayland_vk_wsi_surface->tbm_queue);
+ wayland_vk_wsi_surface->reset = TPL_FALSE;
+
+ __tpl_util_atomic_inc(&wayland_vk_wsi_surface->swapchain_reference);
+
+ TPL_LOG_T("WL_VK", "[REUSE] wayland_vk_wsi_surface(%p) tbm_queue(%p) size(%d)",
+ wayland_vk_wsi_surface, wayland_vk_wsi_surface->tbm_queue,
+ wayland_vk_wsi_surface->buffer_count);
+ return TPL_ERROR_NONE;
+ }
+
+ 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);
+
+ /* Set reset_callback to tbm_queue */
+ if (tbm_surface_queue_add_reset_cb(wayland_vk_wsi_surface->tbm_queue,
+ __cb_tbm_queue_reset_callback,
+ (void *)surface) != TBM_SURFACE_QUEUE_ERROR_NONE) {
+ TPL_ERR("TBM surface queue add reset cb failed!");
+ twe_surface_destroy_swapchain(wayland_vk_wsi_surface->twe_surface);
+ wayland_vk_wsi_surface->tbm_queue = NULL;
+ return TPL_ERROR_INVALID_OPERATION;
+ }
+
+ wayland_vk_wsi_surface->buffer_count = buffer_count;
+ wayland_vk_wsi_surface->reset = TPL_FALSE;
+
+ __tpl_util_atomic_set(&wayland_vk_wsi_surface->swapchain_reference, 1);
+
+ 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_wayland_vk_wsi_display_t *wayland_vk_wsi_display = NULL;
+ tpl_result_t res = TPL_ERROR_NONE;
+ unsigned int ref;
+
+ TPL_ASSERT(surface);
+ TPL_ASSERT(surface->backend.data);
+ TPL_ASSERT(surface->display);
+ TPL_ASSERT(surface->display->backend.data);
+
+ wayland_vk_wsi_surface = (tpl_wayland_vk_wsi_surface_t *) surface->backend.data;
+ wayland_vk_wsi_display = (tpl_wayland_vk_wsi_display_t *) surface->display->backend.data;
+
+ if (twe_display_lock(wayland_vk_wsi_display->twe_display) == TPL_ERROR_NONE) {
+ ref = __tpl_util_atomic_dec(&wayland_vk_wsi_surface->swapchain_reference);
+ if (ref > 0) {
+ TPL_LOG_T("WL_VK",
+ "This swapchain is still valid. | twe_surface(%p)",
+ wayland_vk_wsi_surface->twe_surface);
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ return TPL_ERROR_NONE;
+ }
+
+
+ if (wayland_vk_wsi_surface->reset) {
+ TPL_LOG_T("WL_VK",
+ "Since reset is in the TRUE state, it will not be destroyed.");
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ return TPL_ERROR_NONE;
+ }
+
+ if (wayland_vk_wsi_surface->swapchain_buffers) {
+ int i;
+ for (i = 0; i < wayland_vk_wsi_surface->buffer_count; i++) {
+ TPL_DEBUG("Stop tracking tbm_surface(%p)",
+ wayland_vk_wsi_surface->swapchain_buffers[i]);
+ tbm_surface_internal_unref(wayland_vk_wsi_surface->swapchain_buffers[i]);
+ wayland_vk_wsi_surface->swapchain_buffers[i] = NULL;
+ }
+
+ free(wayland_vk_wsi_surface->swapchain_buffers);
+ wayland_vk_wsi_surface->swapchain_buffers = NULL;
+ }
+
+ 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);
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ return res;
+ }
+
+ wayland_vk_wsi_surface->tbm_queue = NULL;
+
+ twe_display_unlock(wayland_vk_wsi_display->twe_display);
+ }
+
+ 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->cancel_dequeued_buffer =
+ __tpl_wl_vk_wsi_surface_cancel_dequeued_buffer;
+ 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;
+}