correct the wrong behavior when the sequence value reaches the MAX(4,294,967,295) 77/86677/2
authorBoram Park <boram1288.park@samsung.com>
Fri, 2 Sep 2016 07:47:27 +0000 (16:47 +0900)
committerBoram Park <boram1288.park@samsung.com>
Mon, 5 Sep 2016 00:34:58 +0000 (09:34 +0900)
- The sequence value of tdm client vblank will start 1 always.
- When the sequence reaches MAX, then it will become 0 at the next vblank.

Change-Id: Ie66cf5ac717246e309e6e2d86eb5c0b1fc2e71c7

client/tdm_client.h
src/tdm_vblank.c

index 1c2ef7d..e7df780 100644 (file)
@@ -385,8 +385,6 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli
  * #tdm_client_vblank_set_enable_fake sets true. Once #tdm_client_vblank_wait_seq
  * returns TDM_ERROR_NONE, the user client vblank handler(#tdm_client_vblank_handler)
  * SHOULD be called on reaching the target sequence.
- * If the sequence value is 0, the result will be the same with calling
- * #tdm_client_vblank_wait with (interval = 1).
  * @param[in] vblank The client vblank object
  * @param[in] sequence The target sequence number
  * @param[in] func The user client vblank handler
index 8ff13e5..777a5ff 100644 (file)
  * - 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)
@@ -89,7 +99,6 @@ typedef struct _tdm_private_vblank {
        /* 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;
@@ -508,24 +517,6 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence,
                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;
@@ -535,7 +526,6 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence,
                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;
 
@@ -554,14 +544,14 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence,
        }
 
        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);
@@ -580,10 +570,11 @@ _tdm_vblank_wait_HW(tdm_vblank_wait_info *wait_info)
 
        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;
@@ -592,9 +583,14 @@ _tdm_vblank_wait_HW(tdm_vblank_wait_info *wait_info)
                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)",
@@ -602,9 +598,6 @@ _tdm_vblank_wait_HW(tdm_vblank_wait_info *wait_info)
                                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);
 
@@ -802,12 +795,13 @@ tdm_vblank_wait_seq(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_u
        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;