* - use a tdm_event_loop_source object only.
*/
+#define TDM_VBLANK_UINT_MAX 4294967295U
+#define TDM_VBLANK_UINT_1Q 1073741823U /* UINT_MAX / 4 */
+#define TDM_VBLANK_UINT_3Q 3221225471U /* UINT_MAX / 4 * 3 */
+
+/* (seq < TDM_VBLANK_UINT_1Q && TDM_VBLANK_UINT_3Q < last_seq) means
+ * that the sequence value has reached the max value and started from 0 again.
+ */
+#define TDM_VBLANK_SEQ_REACHED_MAX(seq, last_seq) \
+ ((seq) < TDM_VBLANK_UINT_1Q && TDM_VBLANK_UINT_3Q < (last_seq))
+
#define VER(fmt, arg...) TDM_ERR("[%p] "fmt, private_vblank, ##arg)
#define VWR(fmt, arg...) TDM_WRN("[%p] "fmt, private_vblank, ##arg)
#define VIN(fmt, arg...) TDM_INFO("[%p] "fmt, private_vblank, ##arg)
/* for HW */
double HW_vblank_gap;
struct list_head HW_wait_list;
- unsigned int HW_seq_margin;
/* for SW */
tdm_event_loop_source *SW_timer;
return;
}
- /* sequence is the relative value of fps. If fps = 10, sequence should be
- * increased by 10 during 1 second.
- */
- sequence /= private_vblank->quotient;
-
- /* If VBLANK_TYPE_SW_FAKE, HW sequeuce can become less than SW sequeuce.
- * so we will correct it with HW_seq_margin.
- */
- if (private_vblank->last_seq > sequence) {
- unsigned long last, tv;
- last = (unsigned long)private_vblank->last_tv_sec * 1000000 + private_vblank->last_tv_usec;
- tv = (unsigned long)tv_sec * 1000000 + tv_usec;
- private_vblank->HW_seq_margin = ((tv - last) / (unsigned long)private_vblank->vblank_gap) + 1;
- private_vblank->HW_seq_margin += private_vblank->last_seq - sequence;
- }
-
- sequence += private_vblank->HW_seq_margin;
-
if (wait_info->type == VBLANK_TYPE_HW_SW) {
unsigned long target;
tdm_error ret;
target = (unsigned long)tv_sec * 1000000 + tv_usec;
target += (private_vblank->offset * 1000);
- wait_info->target_seq = sequence;
wait_info->target_sec = target / 1000000;
wait_info->target_usec = target % 1000000;
}
if (tdm_debug_module & TDM_DEBUG_VBLANK)
- VIN("wait(%p) sequence(%u) done", wait_info, sequence);
+ VIN("wait(%p) sequence(%u) done", wait_info, wait_info->target_seq);
- private_vblank->last_seq = sequence;
+ private_vblank->last_seq = wait_info->target_seq;
private_vblank->last_tv_sec = tv_sec;
private_vblank->last_tv_usec = tv_usec;
if (wait_info->func)
- wait_info->func(private_vblank, TDM_ERROR_NONE, sequence,
+ wait_info->func(private_vblank, TDM_ERROR_NONE, wait_info->target_seq,
tv_sec, tv_usec, wait_info->user_data);
LIST_DEL(&wait_info->link);
hw_interval = wait_info->interval * private_vblank->quotient;
- if (private_vblank->last_tv_sec != 0) {
- unsigned long last, prev, req, curr;
+ if (private_vblank->last_tv_sec == 0)
+ wait_info->target_seq = 1;
+ else {
+ unsigned long last, prev, req, curr, target;
unsigned int skip = 0;
- unsigned int hw_skip;
last = (unsigned long)private_vblank->last_tv_sec * 1000000 + private_vblank->last_tv_usec;
req = (unsigned long)wait_info->req_sec * 1000000 + wait_info->req_usec;
prev = last + skip * private_vblank->vblank_gap;
curr = tdm_helper_get_time_in_micros();
- hw_skip = (unsigned int)((curr - prev) / private_vblank->HW_vblank_gap);
+ target = prev;
+ while (target < curr)
+ target += private_vblank->vblank_gap;
+
+ hw_interval = (unsigned int)((target - curr) / private_vblank->HW_vblank_gap) + 1;
- hw_interval -= hw_skip;
+ wait_info->target_seq = private_vblank->last_seq;
+ wait_info->target_seq += (target - last) / (unsigned long)private_vblank->vblank_gap;
if (tdm_debug_module & TDM_DEBUG_VBLANK)
VIN("wait(%p) last(%4lu) req(%4lu) prev(%4lu) curr(%4lu) skip(%d) hw_interval(%d)",
skip, hw_interval);
}
- if (hw_interval < 1)
- hw_interval = 1;
-
ret = tdm_output_wait_vblank(private_vblank->output, hw_interval, 0,
_tdm_vblank_cb_vblank_HW, wait_info);
TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
- if (sequence == 0) {
- interval = 1;
- } else if (private_vblank->last_seq == 0) {
+ /* 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);
interval = 1;
- } else if (sequence > private_vblank->last_seq) {
+ } else if (sequence > private_vblank->last_seq ||
+ TDM_VBLANK_SEQ_REACHED_MAX(sequence, private_vblank->last_seq)) {
unsigned long last, curr, seq_target;
last = (unsigned long)private_vblank->last_tv_sec * 1000000 + private_vblank->last_tv_usec;