use SW timer when output disconnected 91/148591/1
authorBoram Park <boram1288.park@samsung.com>
Fri, 8 Sep 2017 05:35:40 +0000 (14:35 +0900)
committerBoram Park <boram1288.park@samsung.com>
Fri, 8 Sep 2017 07:01:23 +0000 (16:01 +0900)
If enable_fake == 1, use SW timer when output disconnected as well as DPMS off.

Change-Id: I9e528b6eb6749d099c6b8f7ff765ce46a7728f5a

client/tdm_client.c
client/tdm_client.h
src/tdm_vblank.c

index 6ab849d..d80100d 100644 (file)
@@ -833,11 +833,16 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli
        if (!private_vblank->started)
                private_vblank->started = 1;
 
-       if (private_output->watch_output_changes)
-               if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) {
-                       TDM_INFO("dpms off");
+       if (private_output->watch_output_changes && !private_vblank->enable_fake) {
+               if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
+                       TDM_ERR("output disconnected");
+                       return TDM_ERROR_OUTPUT_DISCONNECTED;
+               }
+               if (private_output->dpms != TDM_OUTPUT_DPMS_ON) {
+                       TDM_ERR("dpms off");
                        return TDM_ERROR_DPMS_OFF;
                }
+       }
 
        w = calloc(1, sizeof *w);
        if (!w) {
@@ -910,11 +915,16 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
        if (!private_vblank->started)
                private_vblank->started = 1;
 
-       if (private_output->watch_output_changes)
-               if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) {
-                       TDM_INFO("dpms off");
+       if (private_output->watch_output_changes && !private_vblank->enable_fake) {
+               if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
+                       TDM_ERR("output disconnected");
+                       return TDM_ERROR_OUTPUT_DISCONNECTED;
+               }
+               if (private_output->dpms != TDM_OUTPUT_DPMS_ON) {
+                       TDM_ERR("dpms off");
                        return TDM_ERROR_DPMS_OFF;
                }
+       }
 
        w = calloc(1, sizeof *w);
        if (!w) {
index 8a2fcd0..175bb45 100644 (file)
@@ -226,6 +226,12 @@ tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms);
 
 /**
  * @brief Create the client vblank object of the given client output
+ * @details
+ * tdm client vblank basically uses the HW vblank resource. Therefore, if HW vblank
+ * is not available for some reasons, such as output disconnection and dpms off,
+ * #tdm_client_vblank_wait will return error. If you want it to work propery in spite
+ * of these reasons, you can use #tdm_client_vblank_set_enable_fake to get SW fake
+ * vblank events.
  * @param[in] output The client output object
  * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value.
  * @return A client vblank object if success. Otherwise, NULL.
@@ -286,8 +292,8 @@ tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms);
 /**
  * @brief Enable/Disable the fake vblank to the client vblank object
  * @details
- * If enable_fake == 0, #tdm_client_vblank_wait will return TDM_ERROR_DPMS_OFF
- * when DPMS off. Otherwise, #tdm_client_vblank_wait will return TDM_ERROR_NONE
+ * If enable_fake == 0, #tdm_client_vblank_wait will return error when HW vblank is
+ * not available. Otherwise, #tdm_client_vblank_wait will return TDM_ERROR_NONE
  * as success. Once #tdm_client_vblank_wait returns TDM_ERROR_NONE, the user client
  * vblank handler(#tdm_client_vblank_handler) SHOULD be called after the given
  * interval of #tdm_client_vblank_wait. Default is @b disable.
@@ -301,7 +307,7 @@ tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable
 /**
  * @brief Wait for a vblank
  * @details
- * This function will return TDM_ERROR_DPMS_OFF when DPMS off. However,
+ * This function will return error when HW vblank resource is not available. However,
  * #tdm_client_vblank_wait will return TDM_ERROR_NONE as success if
  * #tdm_client_vblank_set_enable_fake sets true. Once #tdm_client_vblank_wait
  * returns TDM_ERROR_NONE, the user client vblank handler(#tdm_client_vblank_handler)
@@ -389,7 +395,7 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli
 /**
  * @brief Wait for a vblank with the target sequence number
  * @details
- * This function will return TDM_ERROR_DPMS_OFF when DPMS off. However,
+ * This function will return error when HW vblank resource is not available. However,
  * #tdm_client_vblank_wait will return TDM_ERROR_NONE as success if
  * #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)
index 97deab5..337e7cf 100644 (file)
@@ -54,6 +54,8 @@
  * - use a tdm_event_loop_source object only.
  */
 
+#define TDM_VBLANK_DEFAULT_VREFRESH    30
+
 /* We expact "(unsigned int)(0.0016667 / 0.0016667) = 1". But it becomes 0. */
 #define TDM_TIME_MARGIN     0.0000001
 
@@ -89,12 +91,14 @@ typedef struct _tdm_private_vblank {
 
        tdm_display *dpy;
        tdm_output *output;
+       tdm_output_conn_status connection;
        tdm_output_dpms dpms;
        unsigned int vrefresh;
 
        unsigned int check_HW_or_SW;
        char name[TDM_NAME_LEN];
        unsigned int fps;
+       unsigned int fps_changeable;
        int offset;
        unsigned int enable_fake;
        unsigned int ignore_global_fps;
@@ -308,6 +312,39 @@ _tdm_vblank_free_HW_wait(tdm_private_vblank *private_vblank, tdm_error error, un
 }
 
 static void
+_tdm_vblank_update_output_info(tdm_private_vblank *private_vblank)
+{
+       tdm_output *output = private_vblank->output;
+       tdm_output_conn_status connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+       tdm_output_dpms dpms = TDM_OUTPUT_DPMS_OFF;
+       unsigned int vrefresh = 0;
+
+       tdm_output_get_conn_status(output, &connection);
+
+       if (connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
+               const tdm_output_mode *mode = NULL;
+               tdm_output_get_mode(output, &mode);
+               vrefresh = (mode) ? mode->vrefresh : 0;
+               tdm_output_get_dpms(output, &dpms);
+       }
+
+       if (vrefresh == 0)
+               vrefresh = TDM_VBLANK_DEFAULT_VREFRESH;
+
+       private_vblank->dpms = dpms;
+       private_vblank->connection = connection;
+       private_vblank->vrefresh = vrefresh;
+       private_vblank->HW_vblank_gap = 1.0 / private_vblank->vrefresh;
+
+       if (private_vblank->fps_changeable)
+               private_vblank->fps = vrefresh;
+
+       VDB("dpms(%d) connection(%d) vrefresh(%d) fps(%d)",
+               private_vblank->dpms, private_vblank->connection,
+               private_vblank->vrefresh, private_vblank->fps);
+}
+
+static void
 _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type,
                                                         tdm_value value, void *user_data)
 {
@@ -320,7 +357,7 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type,
                if (private_vblank->dpms == value.u32)
                        break;
                VDB("dpms %s", tdm_dpms_str(value.u32));
-               private_vblank->dpms = value.u32;
+               _tdm_vblank_update_output_info(private_vblank);
                private_vblank->check_HW_or_SW = 1;
                if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON) {
                        if (private_vblank->enable_fake)
@@ -330,9 +367,17 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type,
                }
                break;
        case TDM_OUTPUT_CHANGE_CONNECTION:
+               if (private_vblank->connection == value.u32)
+                       break;
                VDB("output %s", tdm_status_str(value.u32));
-               if (value.u32 == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
-                       _tdm_vblank_free_HW_wait(private_vblank, 0, 0);
+               _tdm_vblank_update_output_info(private_vblank);
+               private_vblank->check_HW_or_SW = 1;
+               if (private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
+                       if (private_vblank->enable_fake)
+                               _tdm_vblank_change_to_SW(private_vblank);
+                       else
+                               _tdm_vblank_free_HW_wait(private_vblank, TDM_ERROR_OUTPUT_DISCONNECTED, 1);
+               }
                break;
        default:
                break;
@@ -410,8 +455,6 @@ EXTERN tdm_vblank *
 tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
 {
        tdm_private_vblank *private_vblank;
-       const tdm_output_mode *mode = NULL;
-       tdm_output_dpms dpms = TDM_OUTPUT_DPMS_ON;
        tdm_error ret;
 
        TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL);
@@ -432,16 +475,6 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
                vblank_list_inited = 1;
        }
 
-       tdm_output_get_mode(output, &mode);
-       if (!mode) {
-               if (error)
-                       *error = TDM_ERROR_OPERATION_FAILED;
-               TDM_ERR("no mode");
-               return NULL;
-       }
-
-       tdm_output_get_dpms(output, &dpms);
-
        private_vblank = calloc(1, sizeof * private_vblank);
        if (!private_vblank) {
                if (error)
@@ -456,12 +489,10 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
        private_vblank->owner_tid = syscall(SYS_gettid);
        private_vblank->dpy = dpy;
        private_vblank->output = output;
-       private_vblank->dpms = dpms;
-       private_vblank->vrefresh = mode->vrefresh;
-       private_vblank->HW_vblank_gap = 1.0 / private_vblank->vrefresh;
-
        private_vblank->check_HW_or_SW = 1;
-       private_vblank->fps = mode->vrefresh;
+       private_vblank->fps_changeable = 1;
+
+       _tdm_vblank_update_output_info(private_vblank);
 
        strncpy(private_vblank->name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN - 1);
        private_vblank->name[TDM_NAME_LEN - 1] = '\0';
@@ -472,8 +503,8 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
        _tdm_vblank_valid_list_add(&private_vblank->valid_link, &valid_vblank_list);
 
        if (tdm_debug_module & TDM_DEBUG_VBLANK)
-               VIN("created. vrefresh(%d) dpms(%d)",
-                       private_vblank->vrefresh, private_vblank->dpms);
+               VIN("created. vrefresh(%d) dpms(%d) connection(%d)",
+                       private_vblank->vrefresh, private_vblank->dpms, private_vblank->connection);
 
        return (tdm_vblank *)private_vblank;
 }
@@ -556,6 +587,7 @@ tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps)
                return TDM_ERROR_NONE;
 
        private_vblank->fps = fps;
+       private_vblank->fps_changeable = 0;
        private_vblank->check_HW_or_SW = 1;
 
        if (tdm_debug_module & TDM_DEBUG_VBLANK)
@@ -1022,9 +1054,15 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
                return TDM_ERROR_BAD_REQUEST;
        }
 
-       if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) {
-               VIN("can't wait a vblank because of DPMS off");
-               return TDM_ERROR_DPMS_OFF;
+       if (!private_vblank->enable_fake) {
+               if (private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
+                       VIN("can't wait a vblank: output disconnected");
+                       return TDM_ERROR_OUTPUT_DISCONNECTED;
+               }
+               if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON) {
+                       VIN("can't wait a vblank: DPMS off");
+                       return TDM_ERROR_DPMS_OFF;
+               }
        }
 
        wait_info = calloc(1, sizeof * wait_info);
@@ -1072,7 +1110,8 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
         */
        if (private_vblank->vrefresh % fps)
                wait_info->type = VBLANK_TYPE_SW;
-       else if (private_vblank->dpms == TDM_OUTPUT_DPMS_OFF)
+       else if (private_vblank->dpms == TDM_OUTPUT_DPMS_OFF ||
+                        private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
                wait_info->type = VBLANK_TYPE_SW_FAKE;
        else if (private_vblank->offset == 0)
                wait_info->type = VBLANK_TYPE_HW;
@@ -1083,7 +1122,7 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
                ret = _tdm_vblank_wait_SW(wait_info);
        else {
                ret = _tdm_vblank_wait_HW(wait_info);
-               if (ret == TDM_ERROR_DPMS_OFF)
+               if (ret == TDM_ERROR_OUTPUT_DISCONNECTED || ret == TDM_ERROR_DPMS_OFF)
                        ret = _tdm_vblank_wait_SW(wait_info);
        }