private_output = (tdm_private_output*)output; \
private_display = private_output->private_display
+static void
+_tdm_output_vblank_timeout_update(tdm_private_output *private_output, int ms_delay);
+
+static tdm_error
+_tdm_output_vblank_timeout_cb(void *user_data)
+{
+ tdm_private_output *private_output = user_data;
+ tdm_private_vblank_handler *v = NULL;
+
+ TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OPERATION_FAILED);
+
+ TDM_ERR("TDM output(%d) vblank TIMEOUT!!", private_output->pipe);
+
+ LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
+ TDM_ERR("vblank_handler(%p) interval(%d) sync(%d) sent_to_frontend(%u) owner_tid(%d)",
+ v, v->interval, v->sync, v->sent_to_frontend, v->owner_tid);
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+INTERN void
+tdm_output_vblank_print_wait_information(tdm_private_output *private_output, void *user_data)
+{
+ tdm_private_vblank_handler *v = NULL;
+
+ TDM_RETURN_IF_FAIL(private_output != NULL);
+ TDM_RETURN_IF_FAIL(user_data != NULL);
+
+ TDM_ERR("TDM output(%d) vblank user_data(%p) info!!", private_output->pipe, user_data);
+
+ LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
+ if (v->user_data != user_data)
+ continue;
+ TDM_ERR("vblank_handler(%p) interval(%d) sync(%d) sent_to_frontend(%u) owner_tid(%d)",
+ v, v->interval, v->sync, v->sent_to_frontend, v->owner_tid);
+ }
+}
+
+static void
+_tdm_output_vblank_timeout_update(tdm_private_output *private_output, int ms_delay)
+{
+ tdm_error ret;
+
+ if (!private_output->vblank_timeout_timer) {
+ private_output->vblank_timeout_timer =
+ tdm_event_loop_add_timer_handler(private_output->private_display,
+ _tdm_output_vblank_timeout_cb,
+ private_output,
+ &ret);
+ if (!private_output->vblank_timeout_timer) {
+ TDM_ERR("output(%d) couldn't add timer", private_output->pipe);
+ return;
+ }
+ TDM_INFO("output(%d) create vblank timeout timer", private_output->pipe);
+ }
+
+ ret = tdm_event_loop_source_timer_update(private_output->vblank_timeout_timer, ms_delay);
+ if (ret != TDM_ERROR_NONE) {
+ TDM_ERR("output(%d) couldn't update timer", private_output->pipe);
+ return;
+ }
+}
static tdm_private_hwc_window *
_tdm_output_find_private_hwc_window(tdm_private_output *private_output,
tdm_thread_cb_output_vblank output_vblank;
tdm_error ret;
+ vblank_handler->sent_to_frontend = 1;
+
output_vblank.base.type = TDM_THREAD_CB_OUTPUT_VBLANK;
output_vblank.base.length = sizeof output_vblank;
output_vblank.output_stamp = vblank_handler->private_output->stamp;
return;
}
+ vblank_handler->sent_to_frontend = 0;
+
+ _tdm_output_vblank_timeout_update(private_output, 0);
+
if (vblank_handler->owner_tid != tid)
TDM_NEVER_GET_HERE();
sync, vblank_handler);
TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed);
+ _tdm_output_vblank_timeout_update(private_output, 1000);
+
if (tdm_debug_module & TDM_DEBUG_COMMIT)
TDM_INFO("output(%d) backend wait_vblank", private_output->pipe);
}
/* for SW */
tdm_event_loop_source *SW_timer;
struct list_head SW_wait_list;
+
+ /* for timeout */
+ tdm_event_loop_source *timeout_timer;
} tdm_private_vblank;
struct _tdm_vblank_wait_info {
double req_time;
unsigned int interval;
+ int hw_interval;
tdm_vblank_handler func;
void *user_data;
static void _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence,
unsigned int tv_sec, unsigned int tv_usec,
void *user_data);
+static void _tdm_vblank_timeout_timer_update(tdm_private_vblank *private_vblank, int ms_delay);
+static void _tdm_vblank_get_client_information(tdm_private_vblank *private_vblank,
+ pid_t *pid, const char **name);
#if 0
static void
{
tdm_vblank_wait_info *w = NULL, *ww = NULL;
+ if (!LIST_IS_EMPTY(&private_vblank->HW_wait_list)) {
+ pid_t pid;
+ const char *proc_name;
+ _tdm_vblank_get_client_information(private_vblank, &pid, &proc_name);
+ VER("TDM HW vblank destroyed forcely!! (pid: %u, name: %s)", pid, proc_name);
+ }
+
LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->HW_wait_list, link) {
LIST_DEL(&w->link);
_tdm_vblank_valid_list_del(&w->valid_link);
if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(value.u32)) {
if (private_vblank->enable_fake)
_tdm_vblank_change_to_SW(private_vblank);
- else
+ else {
+ tdm_display_lock(private_vblank->dpy);
+ _tdm_vblank_timeout_timer_update(private_vblank, 0);
+ tdm_display_unlock(private_vblank->dpy);
+
_tdm_vblank_free_HW_wait(private_vblank, TDM_ERROR_DPMS_OFF, 1);
+ }
}
break;
case TDM_OUTPUT_CHANGE_CONNECTION:
if (private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
if (private_vblank->enable_fake)
_tdm_vblank_change_to_SW(private_vblank);
- else
+ else {
+ tdm_display_lock(private_vblank->dpy);
+ _tdm_vblank_timeout_timer_update(private_vblank, 0);
+ tdm_display_unlock(private_vblank->dpy);
+
_tdm_vblank_free_HW_wait(private_vblank, TDM_ERROR_OUTPUT_DISCONNECTED, 1);
+ }
}
break;
default:
/* LCOV_EXCL_START */
if (error)
*error = TDM_ERROR_OUT_OF_MEMORY;
- VER("alloc failed");
+ TDM_ERR("alloc failed");
return NULL;
/* LCOV_EXCL_STOP */
}
_tdm_vblank_free_HW_wait(private_vblank, 0, 0);
+ if (!LIST_IS_EMPTY(&private_vblank->SW_wait_list)) {
+ pid_t pid;
+ const char *proc_name;
+ _tdm_vblank_get_client_information(private_vblank, &pid, &proc_name);
+ VER("TDM SW vblank destroyed forcely!! (pid: %u, name: %s)", pid, proc_name);
+ }
+
LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->SW_wait_list, link) {
LIST_DEL(&w->link);
_tdm_vblank_valid_list_del(&w->valid_link);
free(w);
}
+ if (private_vblank->timeout_timer) {
+ tdm_display_lock(private_vblank->dpy);
+ tdm_event_loop_source_remove(private_vblank->timeout_timer);
+ tdm_display_unlock(private_vblank->dpy);
+ }
+
VIN("destroyed");
free(private_vblank);
}
static tdm_error
+_tdm_vblank_timeout_timer_cb(void *user_data)
+{
+ tdm_private_vblank *private_vblank = user_data;
+ tdm_vblank_wait_info *w = NULL;
+ pid_t pid;
+ const char *proc_name;
+
+ TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_OPERATION_FAILED);
+
+ _tdm_vblank_get_client_information(private_vblank, &pid, &proc_name);
+
+ VER("TDM vblank TIMEOUT!! (pid: %u, name: %s)", pid, proc_name);
+ VER("quotient(%u) last_seq(%u) last_time(%.6f)", private_vblank->quotient, private_vblank->last_seq, private_vblank->last_time);
+
+ LIST_FOR_EACH_ENTRY(w, &private_vblank->HW_wait_list, link) {
+ VER("wait_info(%p) req_time(%.6f) target_seq(%u) interval(%u) hw_interval(%d)",
+ w, w->req_time, w->target_seq, w->interval, w->hw_interval);
+ tdm_output_vblank_print_wait_information(private_vblank->output, w);
+ }
+
+ LIST_FOR_EACH_ENTRY(w, &private_vblank->SW_wait_list, link) {
+ VER("wait_info(%p) req_time(%.6f) target_time(%.6f) target_seq(%u) interval(%u)",
+ w, w->req_time, w->target_time, w->target_seq, w->interval);
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+static void
+_tdm_vblank_timeout_timer_update(tdm_private_vblank *private_vblank, int ms_delay)
+{
+ tdm_error ret;
+
+ if (!private_vblank->timeout_timer) {
+ private_vblank->timeout_timer =
+ tdm_event_loop_add_timer_handler(private_vblank->dpy,
+ _tdm_vblank_timeout_timer_cb,
+ private_vblank,
+ &ret);
+ if (!private_vblank->timeout_timer) {
+ VER("couldn't add timer");
+ return;
+ }
+ VIN("Create Timeout timer");
+ }
+
+ ret = tdm_event_loop_source_timer_update(private_vblank->timeout_timer, ms_delay);
+ if (ret != TDM_ERROR_NONE) {
+ VER("couldn't update timer");
+ return;
+ }
+
+ if (ms_delay != 0)
+ VDB("timeout timer updated");
+ else
+ VDB("timeout timer disabled");
+}
+
+static tdm_error
_tdm_vblank_sw_timer_update(tdm_private_vblank *private_vblank)
{
tdm_vblank_wait_info *first_wait_info = NULL;
tdm_private_vblank *private_vblank;
if (!_tdm_vblank_check_valid_wait(wait_info)) {
- TDM_DBG("can't find wait(%p) from valid_wait_list", wait_info);
+ TDM_ERR("can't find wait(%p) from valid_wait_list", wait_info);
return;
}
TDM_RETURN_IF_FAIL(tdm_vblank_is_valid(private_vblank));
if (!_tdm_vblank_find_wait(wait_info, &private_vblank->HW_wait_list)) {
- VDB("can't find wait(%p)", wait_info);
+ VER("can't find wait(%p)", wait_info);
return;
}
/* wait_info will be freed in _tdm_vblank_cb_vblank_SW() */
if (ret == TDM_ERROR_NONE) {
- VDB("wait(%p) SW timer", wait_info);
+ VIN("wait(%p) SW timer", wait_info);
return;
}
- VWR("couldn't update sw timer");
+ VER("couldn't update sw timer");
}
+ tdm_display_lock(private_vblank->dpy);
+ _tdm_vblank_timeout_timer_update(private_vblank, 0);
+ tdm_display_unlock(private_vblank->dpy);
+
LIST_DEL(&wait_info->link);
_tdm_vblank_valid_list_del(&wait_info->valid_link);
_tdm_vblank_insert_wait(wait_info, &private_vblank->HW_wait_list);
- hw_interval = wait_info->interval * private_vblank->quotient;
-
if (private_vblank->last_time == 0) {
+ hw_interval = wait_info->interval * private_vblank->quotient;
+
/* SW vblank starts from now. SW vblank doesn't need to be aligned with HW vblank. */
private_vblank->last_seq = 0;
private_vblank->last_time = tdm_helper_get_time();
}
private_vblank->last_interval = hw_interval;
+ wait_info->hw_interval = hw_interval;
if (tdm_ttrace_module & TDM_TTRACE_VBLANK)
TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_Vblank:%u", (unsigned int)private_vblank->stamp);
else {
private_vblank = _tdm_vblank_find(vblank_stamp);
if (!private_vblank) {
- TDM_DBG("can't find vblank(%.0f) from valid_list", vblank_stamp);
+ TDM_ERR("can't find vblank(%.0f) from valid_list", vblank_stamp);
return TDM_ERROR_NONE;
}
}
return TDM_ERROR_OPERATION_FAILED;
}
+ if (!LIST_IS_EMPTY(&private_vblank->HW_wait_list))
+ TDM_NEVER_GET_HERE();
+
first_wait_info = container_of(private_vblank->SW_wait_list.next, first_wait_info, link);
TDM_RETURN_VAL_IF_FAIL(first_wait_info != NULL, TDM_ERROR_OPERATION_FAILED);
+ _tdm_vblank_timeout_timer_update(private_vblank, 0);
+
if (private_vblank->last_seq >= first_wait_info->target_seq)
TDM_ERR("last_seq(%u) target_seq(%u)", private_vblank->last_seq, first_wait_info->target_seq);
/* LCOV_EXCL_STOP */
}
+ tdm_display_lock(private_vblank->dpy);
+ _tdm_vblank_timeout_timer_update(private_vblank, 1000);
+ tdm_display_unlock(private_vblank->dpy);
+
return TDM_ERROR_NONE;
}
/* if the sequence of vblank reaches the max value, sequence can be 0. */
if (private_vblank->last_seq == 0) {
- TDM_WRN("can't calculate interval with sequence(%u)", sequence);
+ VWR("can't calculate interval with sequence(%u)", sequence);
interval = 1;
} else if (sequence > private_vblank->last_seq ||
TDM_VBLANK_SEQ_REACHED_MAX(sequence, private_vblank->last_seq)) {
interval = (unsigned int)((seq_target - curr) / private_vblank->vblank_gap + TDM_TIME_MARGIN) + 1;
} else {
/* this seems error. But we handle this like normal to avoid the unexpected error in cliend side */
- TDM_WRN("sequence(%u) should be over the last sequence(%u)", sequence, private_vblank->last_seq);
+ VER("sequence(%u) should be over the last sequence(%u)", sequence, private_vblank->last_seq);
func(vblank, TDM_ERROR_NONE, private_vblank->last_seq,
TDM_TIME_SEC(private_vblank->last_time), TDM_TIME_USEC(private_vblank->last_time),
user_data);
return count;
}
+static void
+_tdm_vblank_get_client_information(tdm_private_vblank *private_vblank, pid_t *pid, const char **name)
+{
+ struct wl_client *client;
+
+ if (!private_vblank->resource)
+ goto no_client;
+
+ client = wl_resource_get_client(private_vblank->resource);
+ if (!client)
+ goto no_client;
+
+ wl_client_get_credentials(client, pid, NULL, NULL);
+ *name = tdm_server_get_client_name(*pid);
+
+ return;
+
+no_client:
+ *pid = 0;
+ *name = NULL;
+ return;
+}
+
/* LCOV_EXCL_START */
INTERN void
tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len)
pid_t pid = 0;
unsigned int count;
- if (v->resource) {
- struct wl_client *client = wl_resource_get_client(v->resource);
- if (client) {
- wl_client_get_credentials(client, &pid, NULL, NULL);
- proc_name = tdm_server_get_client_name(pid);
- }
- }
+ _tdm_vblank_get_client_information(v, &pid, &proc_name);
count = _tdm_vblank_get_waiting_count(v);