implement for sync fo tdm_client_wait_vblank 87/67587/1
authorBoram Park <boram1288.park@samsung.com>
Wed, 27 Apr 2016 09:45:51 +0000 (18:45 +0900)
committerBoram Park <boram1288.park@samsung.com>
Wed, 27 Apr 2016 10:03:33 +0000 (19:03 +0900)
Change-Id: I6dd440473571e8cf717a3c74b784a036ee009da4

client/tdm_client.c
client/tdm_client.h
protocol/tdm.xml
src/tdm_display.c
src/tdm_private.h
src/tdm_server.c
tools/tdm_test_client.c

index 9c34864..4a39714 100644 (file)
@@ -65,6 +65,7 @@ typedef struct _tdm_client_vblank_info {
        unsigned int req_sec;
        unsigned int req_usec;
        void *user_data;
+       int need_free;
 } tdm_client_vblank_info;
 
 static void
@@ -212,8 +213,12 @@ _tdm_client_cb_vblank_done(void *data, struct wl_tdm_vblank *vblank,
                vblank_info->func(sequence, tv_sec, tv_usec, vblank_info->user_data);
        }
 
-       LIST_DEL(&vblank_info->link);
-       free(vblank_info);
+       if (vblank_info->need_free) {
+               LIST_DEL(&vblank_info->link);
+               free(vblank_info);
+       } else {
+               vblank_info->need_free = 1;
+       }
 }
 
 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
@@ -228,6 +233,7 @@ tdm_client_wait_vblank(tdm_client *client, char *name,
        tdm_private_client *private_client = (tdm_private_client*)client;
        tdm_client_vblank_info *vblank_info;
        struct timespec tp;
+       int ret = 0;
 
        TDM_RETURN_VAL_IF_FAIL(name != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
        TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_CLIENT_ERROR_INVALID_PARAMETER);
@@ -245,6 +251,7 @@ tdm_client_wait_vblank(tdm_client *client, char *name,
 
        vblank_info->req_sec = (unsigned int)tp.tv_sec;
        vblank_info->req_usec = (unsigned int)(tp.tv_nsec/1000L);
+       vblank_info->need_free = (sync) ? 0 : 1;
 
        vblank_info->vblank =
                wl_tdm_wait_vblank(private_client->tdm, name, sw_timer, interval,
@@ -265,10 +272,21 @@ tdm_client_wait_vblank(tdm_client *client, char *name,
        vblank_info->user_data = user_data;
        LIST_ADDTAIL(&vblank_info->link, &private_client->vblank_list);
 
-       if (sync)
-               wl_display_roundtrip(private_client->display);
-       else
+       if (!sync) {
                wl_display_flush(private_client->display);
+               return TDM_CLIENT_ERROR_NONE;
+       }
+
+       while (ret != -1 && !vblank_info->need_free)
+               ret = wl_display_dispatch(private_client->display);
+
+       clock_gettime(CLOCK_MONOTONIC, &tp);
+       TDM_DBG("block during %d us",
+               ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec/1000L))
+               - (vblank_info->req_sec * 1000000 + vblank_info->req_usec));
+
+       LIST_DEL(&vblank_info->link);
+       free(vblank_info);
 
        return TDM_CLIENT_ERROR_NONE;
 }
index bceecc1..06e2c9b 100644 (file)
@@ -59,6 +59,7 @@ typedef enum
        TDM_CLIENT_ERROR_INVALID_PARAMETER     = -2, /**< wrong input parameter */
        TDM_CLIENT_ERROR_PERMISSION_DENIED     = -3, /**< access denied */
        TDM_CLIENT_ERROR_OUT_OF_MEMORY         = -4, /**< no free memory */
+       TDM_CLIENT_ERROR_DPMS_OFF              = -5, /**< dpms off */
 } tdm_client_error;
 
 /**
@@ -142,8 +143,8 @@ tdm_client_handle_events(tdm_client *client);
 /**
  * @brief Wait for VBLANK
  * @details After interval vblanks, a client vblank handler will be called.
- * If 'sw_timer' param is 1, TDM will use the SW timer and call a client vblank
- * handler when DPMS off.
+ * If 'sw_timer' param is 1 in case of DPMS off, TDM will use the SW timer and
+ * call a client vblank handler. Otherwise, this function will return error.
  * @param[in] client A TDM client object
  * @param[in] name The name of a TDM output
  * @param[in] sw_timer 0: not using SW timer, 1: using SW timer
index 29f741d..6d79462 100644 (file)
@@ -17,6 +17,7 @@
         <enum name="error">
             <entry name="invalid_name" value="0"/>
             <entry name="operation_failed" value="1"/>
+            <entry name="dpms_off" value="2"/>
         </enum>
 
         <request name="wait_vblank">
index 0d6e274..6d02fd9 100644 (file)
@@ -136,6 +136,12 @@ struct type_name status_names[] = {
 
 INTERN type_name_fn(status)
 
+INTERN const char*
+tdm_get_dpms_str(tdm_output_dpms dpms_value)
+{
+       return dpms_str(dpms_value);
+}
+
 EXTERN tdm_error
 tdm_display_get_capabilities(tdm_display *dpy,
                              tdm_display_capability *capabilities)
index 8002366..fd7c368 100644 (file)
@@ -303,6 +303,9 @@ typedef struct _tdm_buffer_info {
        struct list_head link;
 } tdm_buffer_info;
 
+const char*
+tdm_get_dpms_str(tdm_output_dpms dpms_value);
+
 tdm_private_output *
 tdm_display_find_output_stamp(tdm_private_display *private_display,
                               unsigned long stamp);
index 69abc20..034a65c 100644 (file)
@@ -110,11 +110,19 @@ _tdm_server_cb_wait_vblank(struct wl_client *client,
        tdm_server_vblank_info *vblank_info;
        struct wl_resource *vblank_resource;
        tdm_output *found = NULL;
+       tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_ON;
        int count = 0, i;
        tdm_error ret;
 
        TDM_DBG("The tdm client requests vblank");
 
+       if (tdm_debug_server) {
+               unsigned long curr = tdm_helper_get_time_in_micros();
+               unsigned long reqtime = (req_sec * 1000000) + req_usec;
+               if (curr - reqtime > 1000) /* 1ms */
+                       TDM_WRN("delay(req): %d us", (int)(curr - reqtime));
+       }
+
        tdm_display_get_output_count(private_loop->dpy, &count);
 
        for (i = 0; i < count; i++) {
@@ -144,20 +152,17 @@ _tdm_server_cb_wait_vblank(struct wl_client *client,
                return;
        }
 
-       /* TODO: need to implement things related with sw_timer */
+       tdm_output_get_dpms(found, &dpms_value);
 
-       vblank_resource =
-               wl_resource_create(client, &wl_tdm_vblank_interface,
-                                  wl_resource_get_version(resource), id);
-       if (!vblank_resource) {
-               wl_resource_post_no_memory(resource);
-               TDM_ERR("wl_resource_create failed");
+       if (dpms_value != TDM_OUTPUT_DPMS_ON && !sw_timer) {
+               wl_resource_post_error(resource, WL_TDM_ERROR_DPMS_OFF,
+                                      "dpms '%s'", tdm_get_dpms_str(dpms_value));
+               TDM_ERR("dpms '%s'", tdm_get_dpms_str(dpms_value));
                return;
        }
 
        vblank_info = calloc(1, sizeof *vblank_info);
        if (!vblank_info) {
-               wl_resource_destroy(vblank_resource);
                wl_resource_post_no_memory(resource);
                TDM_ERR("alloc failed");
                return;
@@ -165,22 +170,37 @@ _tdm_server_cb_wait_vblank(struct wl_client *client,
 
        TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval);
 
-       ret = tdm_output_wait_vblank(found, interval, 0,
-                                    _tdm_server_cb_output_vblank, vblank_info);
-       if (ret != TDM_ERROR_NONE) {
-               wl_resource_destroy(vblank_resource);
-               free(vblank_info);
-               wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
-                                      "couldn't wait vblank for %s", name);
-               TDM_ERR("couldn't wait vblank for %s", name);
-               return;
+       vblank_resource =
+               wl_resource_create(client, &wl_tdm_vblank_interface,
+                                  wl_resource_get_version(resource), id);
+       if (!vblank_resource) {
+               wl_resource_post_no_memory(resource);
+               TDM_ERR("wl_resource_create failed");
+               goto free_info;
        }
 
-       if (tdm_debug_server) {
-               unsigned long curr = tdm_helper_get_time_in_micros();
-               unsigned long reqtime = (req_sec * 1000000) + req_usec;
-               if (curr - reqtime > 1000) /* 1ms */
-                       TDM_WRN("delay(req): %d us", (int)(curr - reqtime));
+       if (dpms_value == TDM_OUTPUT_DPMS_ON) {
+               ret = tdm_output_wait_vblank(found, interval, 0,
+                                            _tdm_server_cb_output_vblank, vblank_info);
+               if (ret != TDM_ERROR_NONE) {
+                       wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
+                                              "couldn't wait vblank for %s", name);
+                       TDM_ERR("couldn't wait vblank for %s", name);
+                       goto destroy_resource;
+               }
+       } else if (sw_timer) {
+               /* TODO: need to implement things related with sw_timer */
+               if (ret != TDM_ERROR_NONE) {
+                       wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
+                                              "not implemented yet");
+                       TDM_ERR("not implemented yet");
+                       goto destroy_resource;
+               }
+       } else {
+               wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
+                                      "bad implementation");
+               TDM_NEVER_GET_HERE();
+               goto destroy_resource;
        }
 
        vblank_info->resource = vblank_resource;
@@ -190,6 +210,11 @@ _tdm_server_cb_wait_vblank(struct wl_client *client,
                                       destroy_vblank_callback);
 
        LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list);
+       return;
+destroy_resource:
+       wl_resource_destroy(vblank_resource);
+free_info:
+       free(vblank_info);
 }
 
 static const struct wl_tdm_interface tdm_implementation = {
index fcedae5..5e1f1bb 100644 (file)
@@ -75,6 +75,16 @@ main(int argc, char *argv[])
        tdm_client_error error;
        int fd = -1;
        struct pollfd fds;
+       int sync;
+
+       if (argc < 2) {
+               printf("Usage: %s\n", argv[0]);
+               printf("\t%s 0 : non-sync\n", argv[0]);
+               printf("\t%s 1 : sync\n", argv[0]);
+               exit(1);
+       }
+
+       sync = atoi(argv[1]);
 
        client = tdm_client_create(&error);
        if (error != TDM_CLIENT_ERROR_NONE) {
@@ -95,26 +105,28 @@ main(int argc, char *argv[])
        while (1) {
                int ret;
 
-               error = tdm_client_wait_vblank(client, "unknown-0", 1, 1, 0,
+               error = tdm_client_wait_vblank(client, "unknown-0", 1, 1, sync,
                                               _client_vblank_handler, NULL);
                if (error != TDM_CLIENT_ERROR_NONE) {
                        printf("tdm_client_wait_vblank failed\n");
                        goto done;
                }
 
-               ret = poll(&fds, 1, -1);
-               if (ret < 0) {
-                       if (errno == EBUSY)  /* normal case */
-                               continue;
-                       else {
-                               printf("poll failed: %m\n");
-                               goto done;
+               if (!sync) {
+                       ret = poll(&fds, 1, -1);
+                       if (ret < 0) {
+                               if (errno == EBUSY)  /* normal case */
+                                       continue;
+                               else {
+                                       printf("poll failed: %m\n");
+                                       goto done;
+                               }
                        }
-               }
 
-               error = tdm_client_handle_events(client);
-               if (error != TDM_CLIENT_ERROR_NONE)
-                       printf("tdm_client_handle_events failed\n");
+                       error = tdm_client_handle_events(client);
+                       if (error != TDM_CLIENT_ERROR_NONE)
+                               printf("tdm_client_handle_events failed\n");
+               }
        }
 
 done: