From 21a016dd3305edc56c8d219f5151e584822ffc51 Mon Sep 17 00:00:00 2001 From: Joonbum Ko Date: Wed, 6 Jan 2021 13:37:15 +0900 Subject: [PATCH] Implement backend surface of tpl_wl_egl_thread. Change-Id: I391559ab9ebf6f926a6242795b7b5871b7ecf34f Signed-off-by: Joonbum Ko --- src/tpl_utils_gthread.h | 2 +- src/tpl_wl_egl.c | 1399 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 1069 insertions(+), 332 deletions(-) diff --git a/src/tpl_utils_gthread.h b/src/tpl_utils_gthread.h index 66ad277..a30b86f 100644 --- a/src/tpl_utils_gthread.h +++ b/src/tpl_utils_gthread.h @@ -97,7 +97,7 @@ void tpl_gsource_destroy(tpl_gsource *source, tpl_bool_t destroy_in_thread); /** - * Send an message to dispatch the gsource attached to the thread. + * Send a message to dispatch the gsource attached to the thread. * * @param source Pointer to tpl_gsource to send message. * @param message Value to be read in thread.. diff --git a/src/tpl_wl_egl.c b/src/tpl_wl_egl.c index 3079519..ba3fb80 100644 --- a/src/tpl_wl_egl.c +++ b/src/tpl_wl_egl.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -56,8 +57,8 @@ struct _tpl_wl_egl_display { tpl_bool_t prepared; struct tizen_surface_shm *tss; /* used for surface buffer_flush */ - struct wp_presentation *presentation; - struct zwp_linux_explicit_synchronization_v1 *explicit_sync; + struct wp_presentation *presentation; /* for presentation feedback */ + struct zwp_linux_explicit_synchronization_v1 *explicit_sync; /* for explicit fence sync */ }; struct _tpl_wl_egl_surface { @@ -65,59 +66,59 @@ struct _tpl_wl_egl_surface { tbm_surface_queue_h tbm_queue; - struct wl_surface *surf; struct wl_egl_window *wl_egl_window; - struct zwp_linux_surface_synchronization_v1 *surface_sync; - struct tizen_surface_shm_flusher *tss_flusher; + struct wl_surface *wl_surface; + struct zwp_linux_surface_synchronization_v1 *surface_sync; /* for explicit fence sync */ + struct tizen_surface_shm_flusher *tss_flusher; /* used for surface buffer_flush */ + + tdm_client_vblank *vblank; /* surface information */ - int latest_transform; - int rotation; - int format; int render_done_cnt; unsigned int serial; + int width; + int height; + int format; + int latest_transform; + int rotation; + int post_interval; tpl_wl_egl_display_t *wl_egl_display; + tpl_surface_t *tpl_surface; /* the lists for buffer tracing */ tpl_list_t *committed_buffers; /* Trace tbm_surface from wl_surface_commit() to RELEASE */ tpl_list_t *in_use_buffers; /* Trace tbm_surface from DEQUEUE to ENQUEUE */ - tpl_list_t *fence_waiting_sources; /* Trace fence_wait_source from ENQUEUE to fence signaled */ + tpl_list_t *fence_waiting_bufferss; /* Trace buffers from ENQUEUE to fence signaled */ tpl_list_t *vblank_waiting_buffers; /* for FIFO/FIFO_RELAXED modes */ tpl_list_t *render_done_fences; /* for attaching to twe_thread with fences passed by enqueue */ + tpl_list_t *presentation_feedbacks; /* for tracing presentation feedbacks */ - tdm_client_vblank *vblank; - - tbm_fd commit_sync_timeline; - int commit_sync_timestamp; - unsigned int commit_sync_fence_number; + struct { + tpl_gmutex mutex; + int fd; + } commit_sync; - tbm_fd presentation_sync_timeline; - int presentation_sync_timestamp; - int presentation_sync_ts_backup; - int presentation_sync_req_cnt; + struct { + tpl_gmutex mutex; + int fd; + } presentation_sync; - tpl_gmutex pst_mutex; - tpl_gmutex surf_mutex; tpl_gmutex free_queue_mutex; tpl_gcond free_queue_cond; - /* for waiting draw done */ - tpl_bool_t use_sync_fence; - - /* to use zwp_linux_surface_synchronization */ - tpl_bool_t use_surface_sync; + tpl_gmutex surf_mutex; + tpl_gcond surf_cond; + /* for waiting draw done */ + tpl_bool_t use_render_done_fence; tpl_bool_t is_activated; tpl_bool_t reset; /* TRUE if queue reseted by external */ tpl_bool_t need_to_enqueue; - tpl_bool_t rotation_capability; + tpl_bool_t prerotation_capability; tpl_bool_t vblank_done; - tpl_bool_t is_destroying; - tpl_bool_t set_serial_is_used; /* Will be deprecated */ - - int post_interval; + tpl_bool_t set_serial_is_used; }; struct _tpl_wl_egl_bufer { @@ -385,121 +386,6 @@ _wl_display_print_err(tpl_wl_egl_display_t *wl_egl_display, wl_egl_display->last_error = errno; } -static tpl_bool_t -__thread_func_disp_prepare(tpl_gsource *gsource) -{ - tpl_wl_egl_display_t *wl_egl_display = - (tpl_wl_egl_display_t *)tpl_gsource_get_data(gsource); - - /* If this wl_egl_display is already prepared, - * do nothing in this function. */ - if (wl_egl_display->prepared) - return TPL_FALSE; - - /* If there is a last_error, there is no need to poll, - * so skip directly to dispatch. - * prepare -> dispatch */ - if (wl_egl_display->last_error) - return TPL_TRUE; - - while (wl_display_prepare_read_queue(wl_egl_display->wl_display, - wl_egl_display->ev_queue) != 0) { - if (wl_display_dispatch_queue_pending(wl_egl_display->wl_display, - wl_egl_display->ev_queue) == -1) { - _wl_display_print_err(wl_egl_display, "dispatch_queue_pending"); - } - } - - wl_egl_display->prepared = TPL_TRUE; - - wl_display_flush(wl_egl_display->wl_display); - - return TPL_FALSE; -} - -static tpl_bool_t -__thread_func_disp_check(tpl_gsource *gsource) -{ - tpl_wl_egl_display_t *wl_egl_display = - (tpl_wl_egl_display_t *)tpl_gsource_get_data(gsource); - tpl_bool_t ret = TPL_FALSE; - - if (!wl_egl_display->prepared) - return ret; - - /* If prepared, but last_error is set, - * cancel_read is executed and FALSE is returned. - * That can lead to G_SOURCE_REMOVE by calling disp_prepare again - * and skipping disp_check from prepare to disp_dispatch. - * check -> prepare -> dispatch -> G_SOURCE_REMOVE */ - if (wl_egl_display->prepared && wl_egl_display->last_error) { - wl_display_cancel_read(wl_egl_display->wl_display); - return ret; - } - - if (tpl_gsource_check_io_condition(gsource)) { - if (wl_display_read_events(wl_egl_display->wl_display) == -1) - _wl_display_print_err(wl_egl_display, "read_event"); - ret = TPL_TRUE; - } else { - wl_display_cancel_read(wl_egl_display->wl_display); - ret = TPL_FALSE; - } - - wl_egl_display->prepared = TPL_FALSE; - - return ret; -} - -static tpl_bool_t -__thread_func_disp_dispatch(tpl_gsource *gsource) -{ - tpl_wl_egl_display_t *wl_egl_display = - (tpl_wl_egl_display_t *)tpl_gsource_get_data(gsource); - - /* If there is last_error, SOURCE_REMOVE should be returned - * to remove the gsource from the main loop. - * This is because wl_egl_display is not valid since last_error was set.*/ - if (wl_egl_display->last_error) { - return TPL_GSOURCE_REMOVE; - } - - g_mutex_lock(&wl_egl_display->wl_event_mutex); - if (tpl_gsource_check_io_condition(gsource)) { - if (wl_display_dispatch_queue_pending(wl_egl_display->wl_display, - wl_egl_display->ev_queue) == -1) { - _wl_display_print_err(wl_egl_display, "dispatch_queue_pending"); - } - } - - wl_display_flush(wl_egl_display->wl_display); - g_mutex_unlock(&wl_egl_display->wl_event_mutex); - - return TPL_GSOURCE_CONTINUE; -} - -static void -__thread_func_disp_finalize(tpl_gsource *source) -{ - tpl_wl_egl_display_t *wl_egl_display = - (tpl_wl_egl_display_t *)tpl_gsource_get_data(gsource); - - if (wl_egl_display->wl_initialized) - _thread_wl_display_fini(wl_egl_display); - - TPL_LOG_T("WL_EGL", "finalize| wl_egl_display(%p) tpl_gsource(%p)", - wl_egl_display, source); - - return; -} - -static tpl_gsource_functions disp_funcs = { - .prepare = __thread_func_disp_prepare, - .check = __thread_func_disp_check, - .dispatch = __thread_func_disp_dispatch, - .finalize = __thread_func_disp_finalize, -}; - static void* _thread_init(void *data) { @@ -802,6 +688,123 @@ _thread_wl_display_fini(tpl_wl_egl_display_t *wl_egl_display) wl_egl_display->wl_display); } +static tpl_bool_t +__thread_func_disp_prepare(tpl_gsource *gsource) +{ + tpl_wl_egl_display_t *wl_egl_display = + (tpl_wl_egl_display_t *)tpl_gsource_get_data(gsource); + + /* If this wl_egl_display is already prepared, + * do nothing in this function. */ + if (wl_egl_display->prepared) + return TPL_FALSE; + + /* If there is a last_error, there is no need to poll, + * so skip directly to dispatch. + * prepare -> dispatch */ + if (wl_egl_display->last_error) + return TPL_TRUE; + + while (wl_display_prepare_read_queue(wl_egl_display->wl_display, + wl_egl_display->ev_queue) != 0) { + if (wl_display_dispatch_queue_pending(wl_egl_display->wl_display, + wl_egl_display->ev_queue) == -1) { + _wl_display_print_err(wl_egl_display, "dispatch_queue_pending"); + } + } + + wl_egl_display->prepared = TPL_TRUE; + + wl_display_flush(wl_egl_display->wl_display); + + return TPL_FALSE; +} + +static tpl_bool_t +__thread_func_disp_check(tpl_gsource *gsource) +{ + tpl_wl_egl_display_t *wl_egl_display = + (tpl_wl_egl_display_t *)tpl_gsource_get_data(gsource); + tpl_bool_t ret = TPL_FALSE; + + if (!wl_egl_display->prepared) + return ret; + + /* If prepared, but last_error is set, + * cancel_read is executed and FALSE is returned. + * That can lead to G_SOURCE_REMOVE by calling disp_prepare again + * and skipping disp_check from prepare to disp_dispatch. + * check -> prepare -> dispatch -> G_SOURCE_REMOVE */ + if (wl_egl_display->prepared && wl_egl_display->last_error) { + wl_display_cancel_read(wl_egl_display->wl_display); + return ret; + } + + if (tpl_gsource_check_io_condition(gsource)) { + if (wl_display_read_events(wl_egl_display->wl_display) == -1) + _wl_display_print_err(wl_egl_display, "read_event"); + ret = TPL_TRUE; + } else { + wl_display_cancel_read(wl_egl_display->wl_display); + ret = TPL_FALSE; + } + + wl_egl_display->prepared = TPL_FALSE; + + return ret; +} + +static tpl_bool_t +__thread_func_disp_dispatch(tpl_gsource *gsource, uint64_t message) +{ + tpl_wl_egl_display_t *wl_egl_display = + (tpl_wl_egl_display_t *)tpl_gsource_get_data(gsource); + + TPL_IGNORE(message); + + /* If there is last_error, SOURCE_REMOVE should be returned + * to remove the gsource from the main loop. + * This is because wl_egl_display is not valid since last_error was set.*/ + if (wl_egl_display->last_error) { + return TPL_GSOURCE_REMOVE; + } + + g_mutex_lock(&wl_egl_display->wl_event_mutex); + if (tpl_gsource_check_io_condition(gsource)) { + if (wl_display_dispatch_queue_pending(wl_egl_display->wl_display, + wl_egl_display->ev_queue) == -1) { + _wl_display_print_err(wl_egl_display, "dispatch_queue_pending"); + } + } + + wl_display_flush(wl_egl_display->wl_display); + g_mutex_unlock(&wl_egl_display->wl_event_mutex); + + return TPL_GSOURCE_CONTINUE; +} + +static void +__thread_func_disp_finalize(tpl_gsource *gsource) +{ + tpl_wl_egl_display_t *wl_egl_display = + (tpl_wl_egl_display_t *)tpl_gsource_get_data(gsource); + + if (wl_egl_display->wl_initialized) + _thread_wl_display_fini(wl_egl_display); + + TPL_LOG_T("WL_EGL", "finalize| wl_egl_display(%p) tpl_gsource(%p)", + wl_egl_display, gsource); + + return; +} + +static tpl_gsource_functions disp_funcs = { + .prepare = __thread_func_disp_prepare, + .check = __thread_func_disp_check, + .dispatch = __thread_func_disp_dispatch, + .finalize = __thread_func_disp_finalize, +}; + static tpl_result_t __tpl_wl_egl_display_query_config(tpl_display_t *display, tpl_surface_type_t surface_type, @@ -861,7 +864,7 @@ __tpl_wl_egl_display_get_window_info(tpl_display_t *display, if (width) *width = wl_egl_window->width; if (height) *height = wl_egl_window->height; if (format) { - struct tizen_private *tizen_private = _get_tizen_private(wl_egl_window); + struct tizen_private *tizen_private = (struct tizen_private *)wl_egl_window->driver_private; if (tizen_private && tizen_private->data) { tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)tizen_private->data; *format = wl_egl_surface->format; @@ -919,175 +922,331 @@ __tpl_wl_egl_display_get_buffer_from_native_pixmap(tpl_handle_t pixmap) return tbm_surface; } - - - - -static void -__cb_tbm_surface_queue_reset_callback(tbm_surface_queue_h surface_queue, - void *data) +static tpl_result_t +__tpl_wl_egl_surface_init(tpl_surface_t *surface) { - tpl_surface_t *surface = NULL; + tpl_wl_egl_display_t *wl_egl_display = NULL; tpl_wl_egl_surface_t *wl_egl_surface = NULL; - tpl_bool_t is_activated = TPL_FALSE; - int width, height; + tbm_surface_queue_h tbm_queue = NULL; + tpl_gsource *surf_source = NULL; + tpl_result_t ret = TPL_ERROR_NONE; - surface = (tpl_surface_t *)data; - TPL_CHECK_ON_NULL_RETURN(surface); + struct wl_egl_window *wl_egl_window = + (struct wl_egl_window *)surface->native_handle; - wl_egl_surface = (tpl_wl_egl_surface_t *)surface->backend.data; - TPL_CHECK_ON_NULL_RETURN(wl_egl_surface); + TPL_ASSERT(surface); + TPL_ASSERT(surface->display); + TPL_ASSERT(surface->type == TPL_SURFACE_TYPE_WINDOW); + TPL_ASSERT(surface->native_handle); - /* When the queue is resized, change the reset flag to TPL_TRUE to reflect - * the changed window size at the next frame. */ - width = tbm_surface_queue_get_width(surface_queue); - height = tbm_surface_queue_get_height(surface_queue); - if (surface->width != width || surface->height != height) { - TPL_LOG_T("WL_EGL", - "[QUEUE_RESIZE_CB] wl_egl_surface(%p) tbm_queue(%p) (%dx%d)", - wl_egl_surface, surface_queue, width, height); + wl_egl_display = + (tpl_wl_egl_display_t *)surface->display->backend.data; + if (!wl_egl_display) { + TPL_ERR("Invalid parameter. wl_egl_display(%p)", + wl_egl_display); + return TPL_ERROR_INVALID_PARAMETER; } - /* 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(wl_egl_surface->twe_surface); - if (wl_egl_surface->is_activated != is_activated) { - if (is_activated) { - TPL_LOG_T("WL_EGL", - "[ACTIVATED_CB] wl_egl_surface(%p) tbm_queue(%p)", - wl_egl_surface, surface_queue); - } else { - TPL_LOG_T("WL_EGL", - "[DEACTIVATED_CB] wl_egl_surface(%p) tbm_queue(%p)", - wl_egl_surface, surface_queue); + wl_egl_surface = (tpl_wl_egl_surface_t *) calloc(1, + sizeof(tpl_wl_egl_surface_t)); + if (!wl_egl_surface) { + TPL_ERR("Failed to allocate memory for new tpl_wl_egl_surface_t."); + return TPL_ERROR_OUT_OF_MEMORY; + } + + surf_source = tpl_gsource_create(wl_egl_display->thread, (void *)wl_egl_surface, + -1, surf_funcs, SOURCE_TYPE_NORMAL); + if (!surf_source) { + TPL_ERR("Failed to create surf_source with wl_egl_surface(%p)", + wl_egl_surface); + goto surf_source_create_fail; + } + + surface->backend.data = (void *)wl_egl_surface; + surface->width = wl_egl_window->width; + surface->height = wl_egl_window->height; + surface->rotation = 0; + + wl_egl_surface->tpl_surface = surface; + wl_egl_surface->width = wl_egl_window->width; + wl_egl_surface->height = wl_egl_window->height; + wl_egl_surface->format = surface->format; + + wl_egl_surface->surf_source = surf_source; + wl_egl_surface->wl_egl_window = wl_egl_window; + wl_egl_surface->wl_surface = wl_egl_window->surface; + + wl_egl_surface->wl_egl_display = wl_egl_display; + + wl_egl_surface->reset = TPL_FALSE; + wl_egl_surface->is_activated = TPL_FALSE; + wl_egl_surface->need_to_enqueue = TPL_FALSE; + wl_egl_surface->prerotation_capability = TPL_FALSE; + wl_egl_surface->vblank_done = TPL_TRUE; + wl_egl_surface->use_render_done_fence = TPL_FALSE; + wl_egl_surface->set_serial_is_used = TPL_FALSE; + + wl_egl_surface->latest_transform = 0; + wl_egl_surface->render_done_cnt = 0; + wl_egl_surface->serial = 0; + + wl_egl_surface->vblank = NULL; + wl_egl_surface->tss_flusher = NULL; + wl_egl_surface->surface_sync = NULL; + + wl_egl_surface->post_interval = surface->post_interval; + + wl_egl_surface->commit_sync.fd = -1; + wl_egl_surface->presentation_sync.fd = -1; + + { + struct tizen_private *tizen_private = NULL; + + if (wl_egl_window->driver_private) + tizen_private = (struct tizen_private *)wl_egl_window->driver_private; + else { + tizen_private = tizen_private_create(); + wl_egl_window->driver_private = (void *)tizen_private; + } + + if (tizen_private) { + tizen_private->data = (void *)wl_egl_surface; + tizen_private->rotate_callback = (void *)__cb_rotate_callback; + tizen_private->get_rotation_capability = (void *) + __cb_get_rotation_capability; + tizen_private->set_window_serial_callback = (void *) + __cb_set_window_serial_callback; + tizen_private->create_commit_sync_fd = (void *)__cb_create_commit_sync_fd; + tizen_private->create_presentation_sync_fd = (void *)__cb_create_presentation_sync_fd; + + wl_egl_window->destroy_window_callback = (void *)__cb_destroy_callback; + wl_egl_window->resize_callback = (void *)__cb_resize_callback; } } - wl_egl_surface->reset = TPL_TRUE; + tpl_gmutex_init(&wl_egl_surface->commit_sync.mutex); + tpl_gmutex_init(&wl_egl_surface->presentation_sync.mutex); - if (surface->reset_cb) - surface->reset_cb(surface->reset_data); -} + tpl_gmutex_init(&wl_egl_surface->free_queue_mutex); + tpl_gmutex_init(&wl_egl_surface->surf_mutex); + tpl_gcond_init(&wl_egl_surface->free_queue_cond); + tpl_gcond_init(&wl_egl_surface->surf_cond); -void __cb_window_rotate_callback(void *data) -{ - tpl_surface_t *surface = (tpl_surface_t *)data; - tpl_wl_egl_surface_t *wl_egl_surface = NULL; - int rotation; + /* Initialize in thread */ + tpl_gmutex_lock(&wl_egl_surface->surf_mutex); + tpl_gsource_send_message(wl_egl_surface->surf_source, 1); + tpl_gcond_wait(&wl_egl_surface->surf_cond, &wl_egl_surface->surf_mutex); + tpl_gmutex_unlock(&wl_egl_surface->surf_mutex); - if (!surface) { - TPL_ERR("Inavlid parameter. surface is NULL."); - return; - } + TPL_ASSERT(wl_egl_surface->tbm_queue); - wl_egl_surface = (tpl_wl_egl_surface_t *)surface->backend.data; - if (!wl_egl_surface) { - TPL_ERR("Invalid parameter. surface->backend.data is NULL"); - return; - } + TPL_INFO("[SURFACE_INIT]", + "tpl_surface(%p) wl_egl_surface(%p) gsource(%p)", + surface, wl_egl_surface, wl_egl_surface->surf_source); - rotation = twe_surface_get_rotation(wl_egl_surface->twe_surface); + return TPL_ERROR_NONE; - surface->rotation = rotation; +surf_source_create_fail: + free(wl_egl_surface); + surface->backend.data = NULL; + return TPL_ERROR_INVALID_OPERATION; } -static tpl_result_t -__tpl_wl_egl_surface_init(tpl_surface_t *surface) +static tbm_surface_queue_h +_thread_create_tbm_queue(tpl_wl_egl_surface_t *wl_egl_surface, + struct wayland_tbm_client *wl_tbm_client, + int num_buffers) { - tpl_wl_egl_display_t *wl_egl_display = NULL; - tpl_wl_egl_surface_t *wl_egl_surface = NULL; tbm_surface_queue_h tbm_queue = NULL; - twe_surface_h twe_surface = NULL; - tpl_result_t ret = TPL_ERROR_NONE; + tbm_bufmgr bufmgr = NULL; + unsigned int capability; - TPL_ASSERT(surface); - TPL_ASSERT(surface->display); - TPL_ASSERT(surface->type == TPL_SURFACE_TYPE_WINDOW); - TPL_ASSERT(surface->native_handle); + struct wl_surface *wl_surface = wl_egl_surface->wl_surface; + int width = wl_egl_surface->width; + int height = wl_egl_surface->height; + int format = wl_egl_surface->format; - wl_egl_display = - (tpl_wl_egl_display_t *)surface->display->backend.data; - if (!wl_egl_display) { - TPL_ERR("Invalid parameter. wl_egl_display(%p)", - wl_egl_display); - return TPL_ERROR_INVALID_PARAMETER; + if (!wl_tbm_client || !wl_surface) { + TPL_ERR("Invalid parameters. wl_tbm_client(%p) wl_surface(%p)", + wl_tbm_client, wl_surface); + return NULL; } - wl_egl_surface = (tpl_wl_egl_surface_t *) calloc(1, - sizeof(tpl_wl_egl_surface_t)); - if (!wl_egl_surface) { - TPL_ERR("Failed to allocate memory for new tpl_wl_egl_surface_t."); - return TPL_ERROR_OUT_OF_MEMORY; + bufmgr = tbm_bufmgr_init(-1); + capability = tbm_bufmgr_get_capability(bufmgr); + tbm_bufmgr_deinit(bufmgr); + + if (capability & TBM_BUFMGR_CAPABILITY_TILED_MEMORY) { + tbm_queue = wayland_tbm_client_create_surface_queue_tiled( + wl_tbm_client, + wl_surface, + num_buffers, + width, + height, + format); + } else { + tbm_queue = wayland_tbm_client_create_surface_queue( + wl_tbm_client, + wl_surface, + num_buffers, + width, + height, + format); + } + + if (tbm_queue) { + TPL_ERR("Failed to create tbm_queue. wl_tbm_client(%p)", + wl_tbm_client); + return NULL; } - surface->backend.data = (void *)wl_egl_surface; + if (tbm_surface_queue_set_modes( + tbm_queue, TBM_SURFACE_QUEUE_MODE_GUARANTEE_CYCLE) != + TBM_SURFACE_QUEUE_ERROR_NONE) { + TPL_ERR("Failed to set queue mode to tbm_surface_queue(%p)", + tbm_queue); + tbm_surface_queue_destroy(tbm_queue); + return NULL; + } - if (__tpl_object_init(&wl_egl_surface->base, - TPL_OBJECT_SURFACE, - NULL) != TPL_ERROR_NONE) { - TPL_ERR("Failed to initialize backend surface's base object!"); - goto object_init_fail; + if (tbm_surface_queue_add_reset_cb( + tbm_queue, + __cb_tbm_queue_reset_callback, + (void *)wl_egl_surface) != TBM_SURFACE_QUEUE_ERROR_NONE) { + TPL_ERR("Failed to register reset callback to tbm_surface_queue(%p)", + tbm_queue); + tbm_surface_queue_destroy(tbm_queue); + return NULL; } - twe_surface = twe_surface_add(wl_egl_display->wl_egl_thread, - wl_egl_display->twe_display, - surface->native_handle, - surface->format, surface->num_buffers); - if (!twe_surface) { - TPL_ERR("Failed to add native_window(%p) to thread(%p)", - surface->native_handle, wl_egl_display->wl_egl_thread); - goto create_twe_surface_fail; + if (tbm_surface_queue_add_trace_cb( + tbm_queue, + __cb_tbm_queue_trace_callback, + (void *)wl_egl_surface) != TBM_SURFACE_QUEUE_ERROR_NONE) { + TPL_ERR("Failed to register trace callback to tbm_surface_queue(%p)", + tbm_queue); + tbm_surface_queue_destroy(tbm_queue); + return NULL; } - tbm_queue = twe_surface_get_tbm_queue(twe_surface); - if (!tbm_queue) { - TPL_ERR("Failed to get tbm_queue from twe_surface(%p)", twe_surface); - goto queue_create_fail; + if (tbm_surface_queue_add_acquirable_cb( + tbm_queue, + __cb_tbm_queue_acquirable_callback, + (void *)wl_egl_surface) != TBM_SURFACE_QUEUE_ERROR_NONE) { + TPL_ERR("Failed to register acquirable callback to tbm_surface_queue(%p)", + tbm_queue); + tbm_surface_queue_destroy(tbm_queue); + return NULL; } - /* Set reset_callback to tbm_queue */ - if (tbm_surface_queue_add_reset_cb(tbm_queue, - __cb_tbm_surface_queue_reset_callback, - (void *)surface)) { - TPL_ERR("TBM surface queue add reset cb failed!"); - goto add_reset_cb_fail; + return tbm_queue; +} + +static tdm_client_vblank* +_thread_create_tdm_client_vblank(tdm_client *tdm_client) +{ + tdm_client_vblank *vblank = NULL; + tdm_client_output *tdm_output = NULL; + tdm_error tdm_err = TDM_ERROR_NONE; + + if (!tdm_client) { + TPL_ERR("Invalid parameter. tdm_client(%p)", tdm_client); + return NULL; } - wl_egl_surface->reset = TPL_FALSE; - wl_egl_surface->twe_surface = twe_surface; - wl_egl_surface->tbm_queue = tbm_queue; - wl_egl_surface->is_activated = TPL_FALSE; - wl_egl_surface->need_to_enqueue = TPL_TRUE; + tdm_output = tdm_client_get_output(tdm_client, "primary", &tdm_err); + if (!tdm_output || tdm_err != TDM_ERROR_NONE) { + TPL_ERR("Failed to get tdm_client_output. tdm_err(%d)", tdm_err); + return NULL; + } + + vblank = tdm_client_output_create_vblank(tdm_output, &tdm_err); + if (!vblank || tdm_err != TDM_ERROR_NONE) { + TPL_ERR("Failed to create vblank. tdm_err(%d)", tdm_err); + return NULL; + } - surface->width = tbm_surface_queue_get_width(tbm_queue); - surface->height = tbm_surface_queue_get_height(tbm_queue); - surface->rotation = twe_surface_get_rotation(twe_surface); + tdm_client_vblank_set_enable_fake(vblank, 1); + tdm_client_vblank_set_sync(vblank, 0); - ret = twe_surface_set_rotate_callback(twe_surface, (void *)surface, - (tpl_surface_cb_func_t)__cb_window_rotate_callback); - if (ret != TPL_ERROR_NONE) { - TPL_WARN("Failed to register rotate callback."); + return vblank; +} + +static void +_thread_wl_egl_surface_init(tpl_wl_egl_surface_t *wl_egl_surface) +{ + tpl_wl_egl_display_t *wl_egl_display = wl_egl_surface->wl_egl_display; + + wl_egl_surface->tbm_queue = _thread_create_tbm_queue( + wl_egl_surface->wl_surface, + wl_egl_display->wl_tbm_client, + wl_egl_surface->width, + wl_egl_surface->height, + wl_egl_surface->format, + CLIENT_QUEUE_SIZE); + if (!wl_egl_surface->tbm_queue) { + TPL_ERR("Failed to create tbm_queue. wl_egl_surface(%p) wl_tbm_client(%p)", + wl_egl_surface, wl_egl_display->wl_tbm_client); + return; } - TPL_LOG_T("WL_EGL", - "[INIT1/2]tpl_surface(%p) tpl_wl_egl_surface(%p) twe_surface(%p)", - surface, wl_egl_surface, twe_surface); - TPL_LOG_T("WL_EGL", - "[INIT2/2]size(%dx%d)rot(%d)|tbm_queue(%p)|native_window(%p)", - surface->width, surface->height, surface->rotation, - tbm_queue, surface->native_handle); + TPL_INFO("[QUEUE_CREATION]", + "wl_egl_surface(%p) wl_surface(%p) wl_tbm_client(%p)", + wl_egl_surface, wl_egl_surface->wl_surface, + wl_egl_display->wl_tbm_client); + TPL_INFO("[QUEUE_CREATION]", + "tbm_queue(%p) size(%d x %d) X %d format(%d)", + wl_egl_surface->tbm_queue, + wl_egl_surface->width, + wl_egl_surface->height, + CLIENT_QUEUE_SIZE, + wl_egl_surface->format); - return TPL_ERROR_NONE; + wl_egl_surface->vblank = _thread_create_tdm_client_vblank( + wl_egl_display->tdm_client); + if (wl_egl_surface->vblank) { + TPL_INFO("[VBLANK_INIT]", + "wl_egl_surface(%p) tdm_client(%p) vblank(%p)", + wl_egl_surface, wl_egl_display->tdm_client, + wl_egl_surface->vblank); + } -add_reset_cb_fail: -queue_create_fail: - twe_surface_del(twe_surface); -create_twe_surface_fail: -object_init_fail: - free(wl_egl_surface); - surface->backend.data = NULL; - return TPL_ERROR_INVALID_OPERATION; + if (wl_egl_display->tss) { + wl_egl_surface->tss_flusher = + tizen_surface_shm_get_flusher(wl_egl_display->tss, + wl_egl_surface->wl_surface); + } + + if (wl_egl_surface->tss_flusher) { + tizen_surface_shm_flusher_add_listener(surf_source->tss_flusher, + &tss_flusher_listener, + wl_egl_surface); + TPL_INFO("[FLUSHER_INIT]", + "wl_egl_surface(%p) tss_flusher(%p)", + wl_egl_surface, wl_egl_surface->tss_flusher); + } + + if (wl_egl_display->explicit_sync && wl_egl_display->use_explicit_sync) { + wl_egl_surface->surface_sync = + zwp_linux_explicit_synchronization_v1_get_synchronization( + wl_egl_display->explicit_sync, wl_egl_surface->wl_surface); + if (wl_egl_surface->surface_sync) { + TPL_INFO("[EXPLICIT_SYNC_INIT]", + "wl_egl_surface(%p) surface_sync(%p)", + wl_egl_surface, wl_egl_surface->surface_sync); + } else { + TPL_WARN("Failed to create surface_sync. | wl_egl_surface(%p)", + wl_egl_surface); + wl_egl_display->use_explicit_sync = TPL_FALSE; + } + } + + wl_egl_surface->committed_buffers = __tpl_list_alloc(); + wl_egl_surface->in_use_buffers = __tpl_list_alloc(); + wl_egl_surface->fence_waiting_buffers = __tpl_list_alloc(); + wl_egl_surface->vblank_waiting_buffers = __tpl_list_alloc(); + wl_egl_surface->render_done_fences = __tpl_list_alloc(); + wl_egl_surface->presentation_feedbacks = __tpl_list_alloc(); } static void @@ -1099,70 +1258,286 @@ __tpl_wl_egl_surface_fini(tpl_surface_t *surface) TPL_ASSERT(surface); TPL_ASSERT(surface->display); + TPL_CHECK_ON_NULL_RETURN(surface->type == TPL_SURFACE_TYPE_WINDOW); + wl_egl_surface = (tpl_wl_egl_surface_t *) surface->backend.data; TPL_CHECK_ON_NULL_RETURN(wl_egl_surface); - TPL_OBJECT_LOCK(wl_egl_surface); + wl_egl_display = wl_egl_surface->wl_egl_display; + TPL_CHECK_ON_NULL_RETURN(wl_egl_display); + + TPL_INFO("[SURFACE_FINI][BEGIN]", + "wl_egl_surface(%p) wl_surface(%p) tbm_queue(%p)", + wl_egl_surface, + wl_egl_surface->wl_surface, wl_egl_surface->tbm_queue); + + if (wl_egl_surface->surf_source) + tpl_gsource_destroy(wl_egl_surface->surf_source, TPL_TRUE); + wl_egl_surface->surf_source = NULL; + + if (wl_egl_surface->wl_egl_window) { + struct tizen_private *tizen_private = NULL; + struct wl_egl_window *wl_egl_window = wl_egl_surface->wl_egl_window; + TPL_INFO("[WL_EGL_WINDOW_FINI]", + "wl_egl_surface(%p) wl_egl_window(%p) wl_surface(%p)", + wl_egl_surface, wl_egl_window, + wl_egl_surface->wl_surface); + tizen_private = (struct tizen_private *)wl_egl_window->driver_private; + if (tizen_private) { + tizen_private->set_window_serial_callback = NULL; + tizen_private->rotate_callback = NULL; + tizen_private->get_rotation_capability = NULL; + tizen_private->create_presentation_sync_fd = NULL; + tizen_private->create_commit_sync_fd = NULL; + tizen_private->set_frontbuffer_callback = NULL; + tizen_private->merge_sync_fds = NULL; + tizen_private->data = NULL; + free(tizen_private); + + wl_egl_window->dirver_private = NULL; + } - wl_egl_display = (tpl_wl_egl_display_t *) - surface->display->backend.data; + wl_egl_window->destroy_window_callback = NULL; + wl_egl_window->resize_callback = NULL; - if (wl_egl_display == NULL) { - TPL_ERR("check failed: wl_egl_display == NULL"); - TPL_OBJECT_UNLOCK(wl_egl_surface); - return; + wl_egl_surface->wl_egl_window = NULL; } - if (surface->type == TPL_SURFACE_TYPE_WINDOW) { - TPL_LOG_T("WL_EGL", - "[FINI] wl_egl_surface(%p) native_window(%p) twe_surface(%p)", - wl_egl_surface, surface->native_handle, - wl_egl_surface->twe_surface); - - if (twe_surface_del(wl_egl_surface->twe_surface) - != TPL_ERROR_NONE) { - TPL_ERR("Failed to delete twe_surface(%p) from thread(%p)", - wl_egl_surface->twe_surface, - wl_egl_display->wl_egl_thread); + wl_egl_surface->wl_surface = NULL; + wl_egl_surface->wl_egl_display = NULL; + wl_egl_surface->tpl_surface = NULL; + + tpl_gmutex_lock(&wl_egl_surface->commit_sync.mutex); + tpl_gmutex_unlock(&wl_egl_surface->commit_sync.mutex); + tpl_gmutex_clear(&wl_egl_surface->commit_sync.mutex); + + tpl_gmutex_lock(&wl_egl_surface->presentation_sync.mutex); + tpl_gmutex_unlock(&wl_egl_surface->presentation_sync.mutex); + tpl_gmutex_clear(&wl_egl_surface->presentation_sync.mutex); + + tpl_gmutex_lock(&wl_egl_surface->free_queue_mutex); + tpl_gmutex_unlock(&wl_egl_surface->free_queue_mutex); + tpl_gmutex_clear(&wl_egl_surface->free_queue_cond); + + tpl_gmutex_clear(&wl_egl_surface->surf_mutex); + tpl_gcond_clear(&wl_egl_surface->surf_cond); + + g_cond_clear(&wl_egl_surface->free_queue_cond); + g_mutex_clear(&wl_egl_surface->free_queue_mutex); + + TPL_INFO("[SURFACE_FINI][END]", "wl_egl_surface(%p)", wl_egl_surface); + + free(wl_egl_surface); + surface->backend.data = NULL; +} + +static void +_thread_wl_egl_surface_fini(tpl_wl_egl_surface_t *wl_egl_surface) +{ + tpl_wl_egl_display_t *wl_egl_display = wl_egl_surface->wl_egl_display; + + tpl_gmutex_lock(&wl_egl_surface->surf_mutex); + + TPL_INFO("[SURFACE_FINI]", + "wl_egl_surface(%p) wl_egl_window(%p) wl_surface(%p)", + wl_egl_surface, wl_egl_surface->wl_egl_window, + wl_egl_surface->wl_surface); + + tpl_gmutex_lock(&wl_egl_surface->presentation_sync.mutex); + + /* TODO + if (wl_egl_display->presentation && wl_egl_surface->presentation_feedbacks) { + while (!__tpl_list_is_empty(wl_egl_surface->presentation_feedbacks)) { + tbm_surface_h tbm_surface = + __tpl_list_pop_front(wl_egl_surface->presentation_feedbacks, NULL); + if (tbm_surface_internal_is_valid(tbm_surface)) { + twe_wl_buffer_info *buf_info = NULL; + tbm_surface_internal_get_user_data(tbm_surface, KEY_BUFFER_INFO, + (void **)&buf_info); + if (buf_info && buf_info->presentation_sync_fd != -1 && + buf_info->presentation_feedback) { + + _write_to_eventfd(buf_info->presentation_sync_fd); + close(buf_info->presentation_sync_fd); + buf_info->presentation_sync_fd = -1; + + wp_presentation_feedback_destroy(buf_info->presentation_feedback); + buf_info->presentation_feedback = NULL; + } + } + } + } + + if (wl_egl_surface->presentation_sync.fd != -1) { + _write_to_eventfd(surf_source->presentation_sync.fd); + close(surf_source->presentation_sync.fd); + surf_source->presentation_sync.fd = -1; + } + */ + tpl_gmutex_unlock(&wl_egl_surface->presentation_sync.mutex); + + /* TODO buffer + if (wl_egl_surface->in_use_buffers) { + __tpl_list_free(wl_egl_surface->in_use_buffers, + (tpl_free_func_t)__cb_buffer_remove_from_list); + wl_egl_surface->in_use_buffers = NULL; + } + + if (surf_source->committed_buffers) { + while (!__tpl_list_is_empty(surf_source->committed_buffers)) { + tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE; + tbm_surface_h tbm_surface = + __tpl_list_pop_front(surf_source->committed_buffers, + (tpl_free_func_t)__cb_buffer_remove_from_list); + + TRACE_ASYNC_END((int)tbm_surface, "[COMMIT ~ RELEASE] BO(%d)", + _get_tbm_surface_bo_name(tbm_surface)); + tsq_err = tbm_surface_queue_release(surf_source->tbm_queue, tbm_surface); + if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) + TPL_ERR("Failed to release. tbm_surface(%p) tsq_err(%d)", + tbm_surface, tsq_err); + } + __tpl_list_free(surf_source->committed_buffers, NULL); + surf_source->committed_buffers = NULL; + } + + if (surf_source->vblank_waiting_buffers) { + while (!__tpl_list_is_empty(surf_source->vblank_waiting_buffers)) { + tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE; + tbm_surface_h tbm_surface = + __tpl_list_pop_front(surf_source->vblank_waiting_buffers, + (tpl_free_func_t)__cb_buffer_remove_from_list); + + tsq_err = tbm_surface_queue_release(surf_source->tbm_queue, tbm_surface); + if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) + TPL_ERR("Failed to release. tbm_surface(%p) tsq_err(%d)", + tbm_surface, tsq_err); } + __tpl_list_free(surf_source->vblank_waiting_buffers, NULL); + surf_source->vblank_waiting_buffers = NULL; + } + + if (surf_source->use_sync_fence && surf_source->fence_waiting_sources) { + while (!__tpl_list_is_empty(surf_source->fence_waiting_sources)) { + twe_fence_wait_source *wait_source = + __tpl_list_pop_front(surf_source->fence_waiting_sources, + NULL); + if (!g_source_is_destroyed(&wait_source->gsource)) { + tbm_surface_internal_unref(wait_source->tbm_surface); + wait_source->tbm_surface = NULL; + + close(wait_source->fence_fd); + wait_source->fence_fd = -1; + + g_source_remove_unix_fd(&wait_source->gsource, wait_source->tag); + g_source_destroy(&wait_source->gsource); + g_source_unref(&wait_source->gsource); + } + } + } + */ + + if (wl_egl_surface->surface_sync) { + TPL_INFO("[SURFACE_SYNC_DESTROY]", "wl_egl_surface(%p) surface_sync(%p)", + wl_egl_surface, wl_egl_surface->surface_sync); + zwp_linux_surface_synchronization_v1_destroy(wl_egl_surface->surface_sync); + wl_egl_surface->surface_sync = NULL; + } + + if (wl_egl_surface->tss_flusher) { + TPL_INFO("[FLUSHER_DESTROY]", + "wl_egl_surface(%p) tss_flusher(%p)", + wl_egl_surface, wl_egl_surface->tss_flusher); + tizen_surface_shm_flusher_destroy(wl_egl_surface->tss_flusher); + wl_egl_surface->tss_flusher = NULL; + } - wl_egl_surface->twe_surface = NULL; + if (wl_egl_surface->vblank) { + TPL_INFO("[VBLANK_DESTROY]", + "wl_egl_surface(%p) vblank(%p)", + wl_egl_surface, wl_egl_surface->vblank); + tdm_client_vblank_destroy(wl_egl_surface->vblank); + wl_egl_surface->vblank = NULL; + } + + if (wl_egl_surface->tbm_queue) { + TPL_INFO("[TBM_QUEUE_DESTROY]", + "wl_egl_surface(%p) tbm_queue(%p)", + wl_egl_surface, wl_egl_surface->tbm_queue); + tbm_surface_queue_destroy(wl_egl_surface->tbm_queue); wl_egl_surface->tbm_queue = NULL; } - TPL_OBJECT_UNLOCK(wl_egl_surface); - __tpl_object_fini(&wl_egl_surface->base); - free(wl_egl_surface); - surface->backend.data = NULL; + tpl_gmutex_unlock(&wl_egl_surface->surf_mutex); } +static tpl_bool_t +__thread_func_surf_dispatch(tpl_gsource *gsource, uint64_t message) +{ + tpl_wl_egl_surface_t *wl_egl_surface = NULL; + tpl_result_t res = TPL_ERROR_NONE; + ssize_t s; + uint64_t message = 0; + + wl_egl_surface = (tpl_wl_egl_surface_t *)tpl_gsource_get_data(gsource); + + /* Initialize surface */ + if (message == 1) { + tpl_gmutex_lock(&wl_egl_surface->surf_mutex); + TPL_DEBUG("wl_egl_surface(%p) initialize message received!", + wl_egl_surface); + _thread_wl_egl_surface_init(wl_egl_surface); + tpl_gcond_signal(wl_egl_surface->surf_cond); + tpl_gmutex_unlock(&wl_egl_surface->surf_mutex); + } else if (message == 2) { + tpl_gmutex_lock(&wl_egl_surface->surf_mutex); + TPL_DEBUG("wl_egl_surface(%p) acquirable message received!", + wl_egl_surface); + /* TODO acquirable */ + tpl_gmutex_unlock(&wl_egl_surface->surf_mutex); + } + + return TPL_TRUE; +} + +static void +__thread_func_surf_finalize(tpl_gsource *gsource) +{ + tpl_wl_egl_surface_t *wl_egl_surface = NULL; + + wl_egl_surface = (tpl_wl_egl_surface_t *)tpl_gsource_get_data(gsource); + TPL_CHECK_ON_NULL_RETURN(wl_egl_surface); + + _thread_wl_egl_surface_fini(wl_egl_surface); + + TPL_DEBUG("[FINALIZE] gsource(%p) wl_egl_surface(%d)", + gsource, wl_egl_surface); +} + +static tpl_gsource_functions surf_funcs = { + .prepare = NULL, + .check = NULL, + .dispatch = __thread_func_surf_dispatch, + .finalize = __thread_func_surf_finalize, +}; + static tpl_result_t __tpl_wl_egl_surface_set_rotation_capability(tpl_surface_t *surface, tpl_bool_t set) { tpl_wl_egl_surface_t *wl_egl_surface = NULL; - if (!surface) { - TPL_ERR("Invalid parameter. tpl_surface(%p)", surface); - return TPL_ERROR_INVALID_PARAMETER; - } + TPL_CHECK_ON_NULL_RETURN_VAL(surface, TPL_ERROR_INVALID_PARAMETER); wl_egl_surface = (tpl_wl_egl_surface_t *)surface->backend.data; - if (!wl_egl_surface) { - TPL_ERR("Invalid parameter. surface(%p) wl_egl_surface(%p)", - surface, wl_egl_surface); - return TPL_ERROR_INVALID_PARAMETER; - } - if (!wl_egl_surface->twe_surface) { - TPL_ERR("Invalid parameter. wl_egl_surface(%p) twe_surface(%p)", - wl_egl_surface, wl_egl_surface->twe_surface); - return TPL_ERROR_INVALID_PARAMETER; - } + TPL_CHECK_ON_TRUE_RETURN_VAL(wl_egl_surface, TPL_ERROR_INVALID_PARAMETER); - twe_surface_set_rotation_capablity(wl_egl_surface->twe_surface, - set); + TPL_INFO("[SET_PREROTATION_CAPABILITY]", + "wl_egl_surface(%p) prerotation capability set to [%s]", + wl_egl_surface, (set ? "TRUE" : "FALSE")); + wl_egl_surface->prerotation_capability = set; return TPL_ERROR_NONE; } @@ -1172,26 +1547,17 @@ __tpl_wl_egl_surface_set_post_interval(tpl_surface_t *surface, { tpl_wl_egl_surface_t *wl_egl_surface = NULL; - if (!surface) { - TPL_ERR("Invalid parameter. tpl_surface(%p)", surface); - return TPL_ERROR_INVALID_PARAMETER; - } + TPL_CHECK_ON_NULL_RETURN_VAL(surface, TPL_ERROR_INVALID_PARAMETER); wl_egl_surface = (tpl_wl_egl_surface_t *)surface->backend.data; - if (!wl_egl_surface) { - TPL_ERR("Invalid parameter. surface(%p) wl_egl_surface(%p)", - surface, wl_egl_surface); - return TPL_ERROR_INVALID_PARAMETER; - } - if (!wl_egl_surface->twe_surface) { - TPL_ERR("Invalid parameter. wl_egl_surface(%p) twe_surface(%p)", - wl_egl_surface, wl_egl_surface->twe_surface); - return TPL_ERROR_INVALID_PARAMETER; - } + TPL_CHECK_ON_TRUE_RETURN_VAL(wl_egl_surface, TPL_ERROR_INVALID_PARAMETER); - twe_surface_set_post_interval(wl_egl_surface->twe_surface, - post_interval); + TPL_INFO("[SET_POST_INTERVAL]", + "wl_egl_surface(%p) post_interval(%d -> %d)", + wl_egl_surface, wl_egl_surface->post_interval, post_interval); + + wl_egl_surface->post_interval = post_interval; return TPL_ERROR_NONE; } @@ -1507,11 +1873,19 @@ __tpl_wl_egl_surface_get_size(tpl_surface_t *surface, int *width, int *height) tpl_bool_t __tpl_display_choose_backend_wl_egl_thread(tpl_handle_t native_dpy) { - if (!native_dpy) return TPL_FALSE; + struct wl_interface *wl_egl_native_dpy = *(void **) native_dpy; + TPL_CHECK_ON_NULL_RETURN_VAL(wl_egl_native_dpy, TPL_FALSE); - if (twe_check_native_handle_is_wl_display(native_dpy)) + /* MAGIC CHECK: A native display handle is a wl_display if the de-referenced first value + is a memory address pointing the structure of wl_display_interface. */ + if (wl_egl_native_dpy == &wl_display_interface) return TPL_TRUE; + if (strncmp(wl_egl_native_dpy->name, wl_display_interface.name, + strlen(wl_display_interface.name)) == 0) { + return TPL_TRUE; + } + return TPL_FALSE; } @@ -1556,3 +1930,366 @@ __tpl_surface_init_backend_wl_egl_thread(tpl_surface_backend_t *backend) __tpl_wl_egl_surface_get_size; } +/* -- BEGIN -- wl_egl_window callback functions */ +static void +__cb_destroy_callback(void *private) +{ + struct tizen_private *tizen_private = (struct tizen_private *)private; + tpl_wl_egl_surface_t *wl_egl_surface = NULL; + + if (!tizen_private) { + TPL_LOG_B("WL_EGL", "[DESTROY_CB] Already destroyed surface"); + return; + } + + wl_egl_surface = (tpl_wl_egl_surface_t *)tizen_private->data; + if (wl_egl_surface) { + TPL_WARN("[DESTROY_CB][!!!ABNORMAL BEHAVIOR!!!] wl_egl_window(%p) is destroyed.", + wl_egl_surface->wl_egl_window); + TPL_WARN("[DESTROY_CB] native window should be destroyed after eglDestroySurface."); + + tpl_gmutex_lock(&wl_egl_surface->surf_mutex); + wl_egl_surface->wl_egl_window->destroy_window_callback = NULL; + wl_egl_surface->wl_egl_window->resize_callback = NULL; + wl_egl_surface->wl_egl_window->driver_private = NULL; + wl_egl_surface->wl_egl_window = NULL; + wl_egl_surface->surf = NULL; + wl_egl_surface->is_destroying = TPL_TRUE; + + tizen_private->set_window_serial_callback = NULL; + tizen_private->rotate_callback = NULL; + tizen_private->get_rotation_capability = NULL; + tizen_private->set_frontbuffer_callback = NULL; + tizen_private->create_commit_sync_fd = NULL; + tizen_private->create_presentation_sync_fd = NULL; + tizen_private->data = NULL; + + free(tizen_private); + tizen_private = NULL; + tpl_gmutex_unlock(&surf_source->surf_mutex); + } +} + +static void +__cb_resize_callback(struct wl_egl_window *wl_egl_window, void *private) +{ + TPL_ASSERT(private); + TPL_ASSERT(wl_egl_window); + + struct tizen_private *tizen_private = (struct tizen_private *)private; + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)tizen_private->data; + int cur_w, cur_h, req_w, req_h, format; + + if (!wl_egl_surface) { + TPL_ERR("Invalid wl_egl_window(%p) tizen_private->data is null.", + wl_egl_window); + return; + } + + format = wl_egl_surface->format; + cur_w = wl_egl_surface->width; + cur_h = wl_egl_surface->height; + req_w = wl_egl_window->width; + req_h = wl_egl_window->height; + + TPL_INFO("[WINDOW_RESIZE]", + "wl_egl_surface(%p) wl_egl_window(%p) (%dx%d) -> (%dx%d)", + wl_egl_surface, wl_egl_window, cur_w, cur_h, req_w, req_h); + + if (tbm_surface_queue_reset(wl_egl_surface->tbm_queue, req_w, req_h, format) + != TBM_SURFACE_QUEUE_ERROR_NONE) { + TPL_ERR("Failed to reset tbm_surface_queue(%p)", wl_egl_surface->tbm_queue); + return; + } +} +/* -- END -- wl_egl_window callback functions */ + +/* -- BEGIN -- wl_egl_window tizen private callback functions */ + +/* There is no usecase for using prerotation callback below */ +static void +__cb_rotate_callback(struct wl_egl_window *wl_egl_window, void *private) +{ + TPL_ASSERT(private); + TPL_ASSERT(wl_egl_window); + + struct tizen_private *tizen_private = (struct tizen_private *)private; + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)tizen_private->data; + int rotation = tizen_private->rotation; + + if (!wl_egl_surface) { + TPL_ERR("Invalid wl_egl_window(%p) tizen_private->data is null.", + wl_egl_window); + return; + } + + TPL_INFO("[WINDOW_ROTATE]", + "wl_egl_surface(%p) wl_egl_window(%p) (%d) -> (%d)", + wl_egl_surface, wl_egl_window, + wl_egl_surface->rotation, rotation); + + wl_egl_surface->rotation = rotation; +} + +/* There is no usecase for using prerotation callback below */ +static int +__cb_get_rotation_capability(struct wl_egl_window *wl_egl_window, + void *private) +{ + TPL_ASSERT(private); + TPL_ASSERT(wl_egl_window); + + int rotation_capability = WL_EGL_WINDOW_TIZEN_CAPABILITY_NONE; + struct tizen_private *tizen_private = (struct tizen_private *)private; + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)tizen_private->data; + + if (!wl_egl_surface) { + TPL_ERR("Invalid wl_egl_window(%p) tizen_private->data is null.", + wl_egl_window); + return rotation_capability; + } + + if (wl_egl_surface->rotation_capability == TPL_TRUE) + rotation_capability = WL_EGL_WINDOW_TIZEN_CAPABILITY_ROTATION_SUPPORTED; + else + rotation_capability = WL_EGL_WINDOW_TIZEN_CAPABILITY_ROTATION_UNSUPPORTED; + + + return rotation_capability; +} + +static void +__cb_set_window_serial_callback(struct wl_egl_window *wl_egl_window, + void *private, unsigned int serial) +{ + TPL_ASSERT(private); + TPL_ASSERT(wl_egl_window); + + struct tizen_private *tizen_private = (struct tizen_private *)private; + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)tizen_private->data; + + if (!wl_egl_surface) { + TPL_ERR("Invalid wl_egl_window(%p) tizen_private->data is null.", + wl_egl_window); + return; + } + + wl_egl_surface->set_serial_is_used = TPL_TRUE; + wl_egl_surface->serial = serial; +} + +static int +__cb_create_commit_sync_fd(struct wl_egl_window *wl_egl_window, void *private) +{ + TPL_ASSERT(private); + TPL_ASSERT(wl_egl_window); + + int commit_sync_fd = -1; + + struct tizen_private *tizen_private = (struct tizen_private *)private; + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)tizen_private->data; + + if (!wl_egl_surface) { + TPL_ERR("Invalid parameter. wl_egl_surface is NULL", wl_egl_surface); + return -1; + } + + tpl_gmutex_lock(&wl_egl_surface->commit_sync.mutex); + + if (wl_egl_surface->commit_sync.fd != -1) { + commit_sync_fd = dup(wl_egl_surface->commit_sync.fd); + TRACE_MARK("[ONLY_DUP] commit_sync_fd(%d) dup(%d)", + wl_egl_surface->commit_sync.fd, commit_sync_fd); + TPL_DEBUG("[DUP_COMMIT_SYNC] wl_egl_surface(%p) commit_sync_fd(%d) dup(%d)", + wl_egl_surface, wl_egl_surface->commit_sync.fd, commit_sync_fd); + tpl_gmutex_unlock(&wl_egl_surface->commit_sync.mutex); + return commit_sync_fd; + } + + wl_egl_surface->commit_sync.fd = eventfd(0, EFD_CLOEXEC); + if (wl_egl_surface->commit_sync.fd == -1) { + TPL_ERR("Failed to create commit_sync_fd. wl_egl_surface(%p)", wl_egl_surface); + tpl_gmutex_unlock(&wl_egl_surface->commit_sync.mutex); + return -1; + } + + commit_sync_fd = dup(wl_egl_surface->commit_sync.fd); + + TRACE_MARK("[CREATE] commit_sync_fd(%d) dup(%d)", + wl_egl_surface->commit_sync.fd, commit_sync_fd); + TPL_DEBUG("[CREATE_COMMIT_SYNC] wl_egl_surface(%p) commit_sync_fd(%d)", + wl_egl_surface, commit_sync_fd); + + tpl_gmutex_unlock(&wl_egl_surface->commit_sync.mutex); + + return commit_sync_fd; +} + +static int +__cb_create_presentation_sync_fd(struct wl_egl_window *wl_egl_window, void *private) +{ + TPL_ASSERT(private); + TPL_ASSERT(wl_egl_window); + + int presentation_sync_fd = -1; + + struct tizen_private *tizen_private = (struct tizen_private *)private; + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)tizen_private->data; + + if (!wl_egl_surface) { + TPL_ERR("Invalid parameter. wl_egl_surface is NULL", wl_egl_surface); + return -1; + } + + tpl_gmutex_lock(&wl_egl_surface->presentation_sync.mutex); + if (wl_egl_surface->presentation_sync.fd != -1) { + presentation_sync_fd = dup(wl_egl_surface->presentation_sync.fd); + TRACE_MARK("[ONLY_DUP] presentation_sync_fd(%d) dup(%d)", + wl_egl_surface->presentation_sync.fd, presentation_sync_fd); + TPL_DEBUG("[DUP_PRESENTATION_SYNC] wl_egl_surface(%p) presentation_sync_fd(%d) dup(%d)", + wl_egl_surface, wl_egl_surface->presentation_sync.fd, presentation_sync_fd); + tpl_gmutex_unlock(&wl_egl_surface->presentation_sync.mutex); + return presentation_sync_fd; + } + + wl_egl_surface->presentation_sync.fd = eventfd(0, EFD_CLOEXEC); + if (wl_egl_surface->presentation_sync.fd == -1) { + TPL_ERR("Failed to create presentation_sync_fd. wl_egl_surface(%p)", wl_egl_surface); + tpl_gmutex_unlock(&wl_egl_surface->presentation_sync.mutex); + return -1; + } + + presentation_sync_fd = dup(wl_egl_surface->presentation_sync.fd); + TRACE_MARK("[CREATE] presentation_sync_fd(%d) dup(%d)", + wl_egl_surface->presentation_sync.fd, presentation_sync_fd); + TPL_DEBUG("[CREATE_PRESENTATION_SYNC] wl_egl_surface(%p) presentation_sync_fd(%d) dup(%d)", + wl_egl_surface, wl_egl_surface->presentation_sync.fd, presentation_sync_fd); + + tpl_gmutex_unlock(&wl_egl_surface->presentation_sync.mutex); + + return presentation_sync_fd; +} +/* -- END -- wl_egl_window tizen private callback functions */ + +/* -- BEGIN -- tizen_surface_shm_flusher_listener */ +static void __cb_tss_flusher_flush_callback(void *data, + struct tizen_surface_shm_flusher *tss_flusher) +{ + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)data; + tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE; + + TPL_INFO("[BUFFER_FLUSH]", "wl_egl_surface(%p) tbm_queue(%p)", + wl_egl_surface, wl_egl_surface->tbm_queue); + + tsq_err = tbm_surface_queue_flush(wl_egl_surface->tbm_queue); + if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) { + TPL_ERR("Failed to flush tbm_queue(%p)", wl_egl_surface->tbm_queue); + return; + } +} + +static void __cb_tss_flusher_free_flush_callback(void *data, + struct tizen_surface_shm_flusher *tss_flusher) +{ + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)data; + tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE; + + TPL_INFO("[FREE_BUFFER_FLUSH]", "wl_egl_surface(%p) tbm_queue(%p)", + wl_egl_surface, wl_egl_surface->tbm_queue); + + tsq_err = tbm_surface_queue_free_flush(wl_egl_surface->tbm_queue); + if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE) { + TPL_ERR("Failed to free flush tbm_queue(%p)", wl_egl_surface->tbm_queue); + return; + } +} + +static const struct tizen_surface_shm_flusher_listener +tss_flusher_listener = { + __cb_tss_flusher_flush_callback, + __cb_tss_flusher_free_flush_callback +}; +/* -- END -- tizen_surface_shm_flusher_listener */ + + +/* -- BEGIN -- tbm_surface_queue callback funstions */ +static void +__cb_tbm_queue_reset_callback(tbm_surface_queue_h tbm_queue, + void *data) +{ + tpl_wl_egl_surface_t *wl_egl_surface = NULL; + tpl_wl_egl_display_t *wl_egl_display = NULL; + tpl_surface_t *surface = NULL; + tpl_bool_t is_activated = TPL_FALSE; + int width, height; + + wl_egl_surface = (tpl_wl_egl_surface_t *)data; + TPL_CHECK_ON_NULL_RETURN(wl_egl_surface); + + wl_egl_display = wl_egl_surface->wl_egl_display; + TPL_CHECK_ON_NULL_RETURN(wl_egl_display); + + surface = wl_egl_surface->tpl_surface; + TPL_CHECK_ON_NULL_RETURN(surface); + + /* When the queue is resized, change the reset flag to TPL_TRUE to reflect + * the changed window size at the next frame. */ + width = tbm_surface_queue_get_width(tbm_queue); + height = tbm_surface_queue_get_height(tbm_queue); + if (surface->width != width || surface->height != height) { + TPL_INFO("[QUEUE_RESIZE]", + "wl_egl_surface(%p) tbm_queue(%p) (%dx%d) -> (%dx%d)", + wl_egl_surface, tbm_queue, + surface->width, surface->height, width, height); + } + + /* 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 = wayland_tbm_client_queue_check_activate(wl_egl_display->wl_tbm_client, + wl_egl_surface->tbm_queue); + if (wl_egl_surface->is_activated != is_activated) { + if (is_activated) { + TPL_INFO("[ACTIVATED]", + "wl_egl_surface(%p) wl_surface(%p) tbm_queue(%p)", + wl_egl_surface, wl_egl_surface->wl_surface, tbm_queue); + } else { + TPL_LOG_T("[DEACTIVATED]", + " wl_egl_surface(%p) wl_surface(%p) tbm_queue(%p)", + wl_egl_surface, wl_egl_surface->wl_surface, tbm_queue); + } + } + + wl_egl_surface->reset = TPL_TRUE; + + if (surface->reset_cb) + surface->reset_cb(surface->reset_data); +} + +static void __cb_tbm_queue_trace_callback(tbm_surface_queue_h tbm_queue, + tbm_surface_h tbm_surface, + tbm_surface_queue_trace trace, + void *data) +{ + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)data; + + /* TODO */ +} + +static void +__cb_tbm_queue_acquirable_callback(tbm_surface_queue_h tbm_queue, + void *data) +{ + TPL_IGNORE(tbm_queue); + + tpl_wl_egl_surface_t *wl_egl_surface = (tpl_wl_egl_surface_t *)data; + TPL_CHECK_ON_NULL_RETURN(wl_egl_surface); + + tpl_gmutex_lock(&wl_egl_surface->surf_mutex); + + tpl_gsource_send_message(wl_egl_surface->surf_source, 2); + + tpl_gmutex_unlock(&wl_egl_surface->surf_mutex); +} + +/* -- END -- tbm_surface_queue callback funstions */ -- 2.7.4