tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
void *user_data);
tdm_error
+tdm_vblank_init(tdm_display *dpy);
+void
+tdm_vblank_deinit(tdm_display *dpy);
+tdm_error
tdm_vblank_cb_vblank_SW(tdm_vblank *vblank, double vblank_stamp);
tdm_error
+tdm_vblank_cb_vblank_create(tdm_vblank *vblank, double vblank_stamp);
+tdm_error
tdm_vblank_set_add_front(tdm_vblank *vblank, unsigned int add_front);
tdm_error
tdm_vblank_set_resource(tdm_vblank *vblank, struct wl_resource *resource);
TDM_THREAD_CB_PP_DONE,
TDM_THREAD_CB_CAPTURE_DONE,
TDM_THREAD_CB_VBLANK_SW,
+ TDM_THREAD_CB_VBLANK_CREATE,
TDM_THREAD_CB_NEED_VALIDATE,
} tdm_thread_cb_type;
typedef struct _tdm_thread_cb_pp_done tdm_thread_cb_pp_done;
typedef struct _tdm_thread_cb_capture_done tdm_thread_cb_capture_done;
typedef struct _tdm_thread_cb_vblank_sw tdm_thread_cb_vblank_sw;
+typedef struct _tdm_thread_cb_vblank_create tdm_thread_cb_vblank_create;
typedef struct _tdm_thread_cb_need_validate tdm_thread_cb_need_validate;
struct _tdm_thread_cb_base {
double vblank_stamp;
};
+struct _tdm_thread_cb_vblank_create {
+ tdm_thread_cb_base base;
+ double vblank_stamp;
+};
+
struct _tdm_thread_cb_need_validate {
tdm_thread_cb_base base;
tdm_private_output *o;
#include "tdm.h"
#include "tdm_private.h"
#include "tdm_list.h"
+#include "tdm_macro.h"
/* CAUTION:
* Basically tdm vblank doesn't care about thread things.
int offset;
unsigned int enable_fake;
unsigned int ignore_global_fps;
+ unsigned int in_create_handler;
double vblank_gap;
unsigned int quotient;
unsigned int target_seq;
};
+typedef struct _tdm_vblank_create_handler_info {
+ struct list_head link;
+
+ tdm_vblank_create_handler func;
+ void *user_data;
+} tdm_vblank_create_handler_info;
+
/* valid_vblank_list and valid_wait_list should be protected by valid_list_lock because
* tdm_vblank can be used in multi-thread.
*/
static pthread_mutex_t valid_list_lock;
static struct list_head valid_vblank_list;
static struct list_head valid_wait_list;
+static struct list_head create_handler_list;
static unsigned int vblank_list_inited;
static unsigned int vblank_global_fps;
static double stamp = 0;
return TDM_ERROR_NONE;
}
+INTERN tdm_error
+tdm_vblank_cb_vblank_create(tdm_vblank *vblank, double vblank_stamp)
+{
+ tdm_private_vblank *private_vblank;
+ tdm_vblank_create_handler_info *ch_info = NULL, *hh = NULL;
+
+ TDM_RETURN_VAL_IF_FAIL(vblank || vblank_stamp > 0, TDM_ERROR_INVALID_PARAMETER);
+
+ if (vblank)
+ private_vblank = vblank;
+ else {
+ private_vblank = _tdm_vblank_find(vblank_stamp);
+ if (!private_vblank) {
+ TDM_DBG("can't find vblank(%.0f) from valid_list", vblank_stamp);
+ return TDM_ERROR_NONE;
+ }
+ }
+
+ if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
+ tdm_thread_cb_vblank_create vblank_create;
+ tdm_private_display *private_display = private_vblank->dpy;
+ tdm_error ret;
+
+ vblank_create.base.type = TDM_THREAD_CB_VBLANK_CREATE;
+ vblank_create.base.length = sizeof vblank_create;
+ vblank_create.vblank_stamp = private_vblank->stamp;
+
+ ret = tdm_thread_send_cb(private_display->private_loop, &vblank_create.base);
+ TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ return TDM_ERROR_NONE;
+ }
+
+ LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) {
+ private_vblank->in_create_handler = 1;
+ ch_info->func(private_vblank, ch_info->user_data);
+ private_vblank->in_create_handler = 0;
+ }
+
+ 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;
+
+ TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ /* we don't allow adding a create handler in sub-thread because tdm_vblank_create()
+ * can be called in both threads and tdm_thread_send_cb supports only one-way
+ * communication now.
+ */
+ if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
+ TDM_ERR("add_create_handler should be called in main thread");
+ return TDM_ERROR_BAD_REQUEST;
+ }
+
+ ch_info = calloc(1, sizeof *ch_info);
+ TDM_RETURN_VAL_IF_FAIL(ch_info != NULL, TDM_ERROR_OUT_OF_MEMORY);
+
+ ch_info->func = func;
+ ch_info->user_data = user_data;
+
+ LIST_ADDTAIL(&ch_info->link, &create_handler_list);
+
+ 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;
+
+ /* we don't allow adding a create handler in sub-thread because tdm_vblank_create()
+ * can be called in both threads and tdm_thread_send_cb supports only one-way
+ * communication now.
+ */
+ if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
+ TDM_ERR("remove_create_handler should be called in main thread");
+ return;
+ }
+
+ LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) {
+ if (ch_info->func != func && ch_info->user_data != user_data)
+ continue;
+
+ LIST_DEL(&ch_info->link);
+ free(ch_info);
+ return;
+ }
+}
+
+INTERN tdm_error
+tdm_vblank_init(tdm_display *dpy)
+{
+ if (vblank_list_inited)
+ return TDM_ERROR_NONE;
+
+ if (pthread_mutex_init(&valid_list_lock, NULL)) {
+ TDM_ERR("mutex init failed: %m");
+ return TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ LIST_INITHEAD(&valid_vblank_list);
+ LIST_INITHEAD(&valid_wait_list);
+ LIST_INITHEAD(&create_handler_list);
+
+ 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);
+ }
+
+ pthread_mutex_destroy(&valid_list_lock);
+
+ vblank_list_inited = 0;
+}
+
EXTERN tdm_vblank *
tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
{
if (error)
*error = TDM_ERROR_NONE;
- if (!vblank_list_inited) {
- if (pthread_mutex_init(&valid_list_lock, NULL)) {
- /* LCOV_EXCL_START */
- TDM_ERR("mutex init failed: %m");
- if (error)
- *error = TDM_ERROR_OPERATION_FAILED;
- return NULL;
- /* LCOV_EXCL_STOP */
- }
- LIST_INITHEAD(&valid_vblank_list);
- LIST_INITHEAD(&valid_wait_list);
- vblank_list_inited = 1;
- }
-
private_vblank = calloc(1, sizeof * private_vblank);
if (!private_vblank) {
/* LCOV_EXCL_START */
VIN("created. vrefresh(%d) connection(%d)",
private_vblank->vrefresh, private_vblank->connection);
+ tdm_display_lock(private_vblank->dpy);
+ tdm_vblank_cb_vblank_create(NULL, private_vblank->stamp);
+ tdm_display_unlock(private_vblank->dpy);
+
return (tdm_vblank *)private_vblank;
}
TDM_RETURN_IF_FAIL(tdm_vblank_is_valid(vblank));
+ if (private_vblank->in_create_handler) {
+ TDM_ERR("NOT allowed to be called in a create handler");
+ return;
+ }
+
_tdm_vblank_valid_list_del(&private_vblank->valid_link);
if (private_vblank->SW_timer) {
TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER);
TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
+ if (private_vblank->in_create_handler) {
+ TDM_ERR("NOT allowed to be called in a create handler");
+ return TDM_ERROR_BAD_REQUEST;
+ }
+
if (private_vblank->owner_tid != syscall(SYS_gettid)) {
TDM_ERR("SHOULD be called in the owner thread(%d)", (int)private_vblank->owner_tid);
return TDM_ERROR_BAD_REQUEST;