+static void
+_tdm_vblank_thread_cb_create(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data)
+{
+ tdm_thread_cb_vblank_create *vblank_create = (tdm_thread_cb_vblank_create *)cb_base;
+ tdm_vblank_create_handler_info *ch_info = user_data;
+ tdm_private_vblank *private_vblank;
+
+ TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
+
+ assert(ch_info != NULL);
+
+ private_vblank = _tdm_vblank_find_object(private_display, vblank_create->vblank_stamp);
+ if (!private_vblank) {
+ TDM_DBG("can't find vblank(%.0f) from valid_list", vblank_create->vblank_stamp);
+ return;
+ }
+
+ private_vblank->in_create_handler = 1;
+ tdm_display_unlock(private_display);
+ ch_info->func(private_vblank, ch_info->user_data);
+ tdm_display_lock(private_display);
+ private_vblank->in_create_handler = 0;
+}
+
+static tdm_error
+_tdm_vblank_call_thread_cb(tdm_private_vblank *private_vblank)
+{
+ tdm_thread_cb_vblank_create vblank_create;
+ tdm_error ret;
+
+ memset(&vblank_create, 0, sizeof vblank_create);
+ vblank_create.base.type = TDM_THREAD_CB_VBLANK_CREATE;
+ vblank_create.base.length = sizeof vblank_create;
+ vblank_create.base.object_stamp = 1;
+ vblank_create.base.data = NULL;
+ vblank_create.base.sync = 0;
+ vblank_create.vblank_stamp = private_vblank->stamp;
+
+ ret = tdm_thread_cb_call(private_vblank->dpy, &vblank_create.base, 1);
+ TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ return TDM_ERROR_NONE;
+}
+
+EXTERN tdm_error
+tdm_vblank_add_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data)
+{
+ tdm_vblank_create_handler_info *ch_info = NULL;
+ tdm_error ret;
+
+ TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
+ TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ pthread_mutex_lock(&valid_list_lock);
+
+ LIST_FOR_EACH_ENTRY(ch_info, &create_handler_list, link) {
+ if (ch_info->func == func && ch_info->user_data == user_data) {
+ TDM_ERR("can't be added twice");
+ pthread_mutex_unlock(&valid_list_lock);
+ return TDM_ERROR_BAD_REQUEST;
+ }
+ }
+
+ ch_info = calloc(1, sizeof *ch_info);
+ if (!ch_info) {
+ TDM_ERR("alloc failed: %m");
+ pthread_mutex_unlock(&valid_list_lock);
+ return TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ tdm_display_lock(dpy);
+ ret = tdm_thread_cb_add(dpy, TDM_THREAD_CB_VBLANK_CREATE, NULL, _tdm_vblank_thread_cb_create, ch_info);
+ tdm_display_unlock(dpy);
+
+ if (ret != TDM_ERROR_NONE) {
+ TDM_ERR("tdm_thread_cb_add failed");
+ free(ch_info);
+ pthread_mutex_unlock(&valid_list_lock);
+ return ret;
+ }
+
+ ch_info->func = func;
+ ch_info->user_data = user_data;
+
+ LIST_ADDTAIL(&ch_info->link, &create_handler_list);
+
+ pthread_mutex_unlock(&valid_list_lock);
+
+ return TDM_ERROR_NONE;
+}
+
+EXTERN void
+tdm_vblank_remove_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data)
+{
+ tdm_vblank_create_handler_info *ch_info = NULL, *hh = NULL;
+
+ TDM_RETURN_IF_FAIL(dpy != NULL);
+ TDM_RETURN_IF_FAIL(func != NULL);
+
+ tdm_display_lock(dpy);
+ pthread_mutex_lock(&valid_list_lock);
+ LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) {
+ if (ch_info->func != func || ch_info->user_data != user_data)
+ continue;
+
+ tdm_thread_cb_remove(dpy, TDM_THREAD_CB_VBLANK_CREATE, NULL, _tdm_vblank_thread_cb_create, ch_info);
+
+ LIST_DEL(&ch_info->link);
+ free(ch_info);
+ pthread_mutex_unlock(&valid_list_lock);
+ tdm_display_unlock(dpy);
+ return;
+ }
+ pthread_mutex_unlock(&valid_list_lock);
+ tdm_display_unlock(dpy);
+}
+
+static void*
+_tdm_vblank_find_display(tdm_private_display *private_display, double stamp)
+{
+ return private_display;
+}
+
+INTERN tdm_error
+tdm_vblank_init(tdm_display *dpy)
+{
+ if (vblank_list_inited)
+ return TDM_ERROR_NONE;
+
+ LIST_INITHEAD(&valid_vblank_list);
+ LIST_INITHEAD(&valid_wait_list);
+ LIST_INITHEAD(&create_handler_list);
+
+ tdm_thread_cb_set_find_func(TDM_THREAD_CB_VBLANK_SW, _tdm_vblank_find_object);
+ tdm_thread_cb_set_find_func(TDM_THREAD_CB_VBLANK_CREATE, _tdm_vblank_find_display);
+
+ vblank_list_inited = 1;
+
+ return TDM_ERROR_NONE;
+}
+
+INTERN void
+tdm_vblank_deinit(tdm_display *dpy)
+{
+ tdm_vblank_create_handler_info *ch_info = NULL, *hh = NULL;
+
+ if (!vblank_list_inited)
+ return;
+
+ if (!LIST_IS_EMPTY(&valid_vblank_list))
+ TDM_NEVER_GET_HERE();
+
+ if (!LIST_IS_EMPTY(&valid_wait_list))
+ TDM_NEVER_GET_HERE();
+
+ LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) {
+ LIST_DEL(&ch_info->link);
+ free(ch_info);
+ }
+
+ vblank_list_inited = 0;
+}
+