export tdm vblank functions 09/86909/5
authorBoram Park <boram1288.park@samsung.com>
Mon, 5 Sep 2016 11:18:35 +0000 (20:18 +0900)
committerBoram Park <boram1288.park@samsung.com>
Sat, 24 Sep 2016 07:47:48 +0000 (16:47 +0900)
Change-Id: I3ec641732606e5f682a69b6207444da93c055bad

include/tdm.h
include/tdm_types.h
src/tdm_private.h
src/tdm_thread.c
src/tdm_vblank.c

index 4fa6e21..ee7b160 100644 (file)
@@ -820,6 +820,106 @@ void
 tdm_buffer_remove_release_handler(tbm_surface_h buffer,
                                                                  tdm_buffer_release_handler func, void *user_data);
 
+/**
+ * @brief The handler of a vblank object
+ * @see #tdm_vblank_wait, #tdm_vblank_wait_seq
+ */
+typedef void (*tdm_vblank_handler)(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
+                                                                  unsigned int tv_sec, unsigned int tv_usec, void *user_data);
+
+/**
+ * @brief Create a vblank object
+ * @param[in] dpy A display object
+ * @param[in] output A output object
+ * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value.
+ * @return A vblank object
+ * @see #tdm_vblank_destroy
+ */
+tdm_vblank*
+tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error);
+
+/**
+ * @brief Destroy a vblank object
+ * @param[in] vblank A vblank object
+ * @see #tdm_vblank_create
+ */
+void
+tdm_vblank_destroy(tdm_vblank *vblank);
+
+/**
+ * @brief Set the fps to a vblank object
+ * @details Default is the @b vertical @b refresh @b rate of the given output.
+ * @param[in] vblank A vblank object
+ * @param[in] fps over 0
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps);
+
+/**
+ * @brief Set the offset(milli-second) to a vblank object
+ * @details Default is @b 0.
+ * @param[in] vblank A vblank object
+ * @param[in] offset the offset(milli-second)
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_vblank_set_offset(tdm_vblank *vblank, int offset);
+
+/**
+ * @brief Enable/Disable the fake vblank to a vblank object
+ * @details
+ * If enable_fake == 0, #tdm_vblank_wait will return TDM_ERROR_DPMS_OFF
+ * when DPMS off. Otherwise, #tdm_vblank_wait will return TDM_ERROR_NONE
+ * as success.
+ * @param[in] vblank A vblank object
+ * @param[in] enable_fake 1:enable, 0:disable
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_vblank_set_enable_fake(tdm_vblank *vblank, unsigned int enable_fake);
+
+/**
+ * @brief Get the fake vblank
+ * @param[in] vblank A vblank object
+ * @return 1 if enable. Otherwise, 0.
+ */
+unsigned int
+tdm_vblank_get_enable_fake(tdm_vblank *vblank);
+
+/**
+ * @brief Wait for a vblank
+ * @details
+ * Once #tdm_vblank_wait returns TDM_ERROR_NONE, the user vblank handler(#tdm_vblank_handler)
+ * SHOULD be called after the given interval. \n
+ * The sequence value of tdm_vblank_handler is the relative value of fps.
+ * If fps = 10, this sequence value should be increased by 10 during 1 second.
+ * @param[in] vblank A vblank object
+ * @param[in] req_sec The vblank request time(second)
+ * @param[in] req_usec The vblank request time(micro-second)
+ * @param[in] interval The vblank interval
+ * @param[in] func The user vblank handler
+ * @param[in] user_data The user data
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
+                               unsigned int interval, tdm_vblank_handler func, void *user_data);
+
+/**
+ * @brief Wait for a vblank with the target sequence number
+ * @param[in] vblank A vblank object
+ * @param[in] req_sec The vblank request time(second)
+ * @param[in] req_usec The vblank request time(micro-second)
+ * @param[in] sequence The target sequence number
+ * @param[in] func The user client vblank handler
+ * @param[in] user_data The user data
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_vblank_wait_seq(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
+                                       unsigned int sequence, tdm_vblank_handler func, void *user_data);
+
 #ifdef __cplusplus
 }
 #endif
index b11b3f5..fd446cd 100644 (file)
@@ -153,6 +153,11 @@ typedef void tdm_capture;
 typedef void tdm_pp;
 
 /**
+ * @brief The tdm vblank object
+ */
+typedef void tdm_vblank;
+
+/**
  * @brief The vblank handler
  * @see output_set_vblank_handler() function of #tdm_func_display
  */
index 37f753e..eb6f6d6 100644 (file)
@@ -372,6 +372,8 @@ tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
 void
 tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
                                        void *user_data);
+tdm_error
+tdm_vblank_cb_vblank_SW(tdm_vblank *vblank, double vblank_stamp);
 
 void
 tdm_output_call_change_handler_internal(tdm_private_output *private_output,
@@ -427,6 +429,7 @@ typedef enum {
        TDM_THREAD_CB_OUTPUT_DPMS,
        TDM_THREAD_CB_PP_DONE,
        TDM_THREAD_CB_CAPTURE_DONE,
+       TDM_THREAD_CB_VBLANK_SW,
 } tdm_thread_cb_type;
 
 typedef struct _tdm_thread_cb_base tdm_thread_cb_base;
@@ -436,6 +439,7 @@ typedef struct _tdm_thread_cb_output_status tdm_thread_cb_output_status;
 typedef struct _tdm_thread_cb_output_dpms tdm_thread_cb_output_dpms;
 typedef struct _tdm_thread_cb_pp_done tdm_thread_cb_pp_done;
 typedef struct _tdm_thread_cb_capture_done tdm_thread_cb_capture_done;
+typedef struct _tdm_thread_cb_vblank_sw tdm_thread_cb_vblank_sw;
 
 struct _tdm_thread_cb_base {
        tdm_thread_cb_type type;
@@ -480,6 +484,11 @@ struct _tdm_thread_cb_capture_done {
        void *user_data;
 };
 
+struct _tdm_thread_cb_vblank_sw {
+       tdm_thread_cb_base base;
+       double vblank_stamp;
+};
+
 tdm_error
 tdm_thread_init(tdm_private_loop *private_loop);
 void
@@ -579,33 +588,6 @@ tdm_display_enable_path(const char *path);
 tdm_error
 tdm_display_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable);
 
-/**
- * @brief The tdm vblank object
- */
-typedef void tdm_vblank;
-
-typedef void (*tdm_vblank_handler)(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
-                                                                  unsigned int tv_sec, unsigned int tv_usec, void *user_data);
-
-tdm_vblank*
-tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error);
-void
-tdm_vblank_destroy(tdm_vblank *vblank);
-tdm_error
-tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps);
-tdm_error
-tdm_vblank_set_offset(tdm_vblank *vblank, int offset);
-tdm_error
-tdm_vblank_set_enable_fake(tdm_vblank *vblank, unsigned int enable_fake);
-unsigned int
-tdm_vblank_get_enable_fake(tdm_vblank *vblank);
-tdm_error
-tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
-                               unsigned int interval, tdm_vblank_handler func, void *user_data);
-tdm_error
-tdm_vblank_wait_seq(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
-                                       unsigned int sequence, tdm_vblank_handler func, void *user_data);
-
 void
 tdm_monitor_server_command(tdm_display *dpy, const char *options, char *reply, int *len);
 
index 7c1067c..955c9b4 100644 (file)
@@ -351,6 +351,11 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop)
                        tdm_capture_cb_done(capture_backend, capture_done->buffer, capture_done->user_data);
                        break;
                }
+               case TDM_THREAD_CB_VBLANK_SW: {
+                       tdm_thread_cb_vblank_sw *vblank_sw = (tdm_thread_cb_vblank_sw*)base;
+                       tdm_vblank_cb_vblank_SW(NULL, vblank_sw->vblank_stamp);
+                       break;
+               }
                default:
                        break;
                }
index bba2240..6696d78 100644 (file)
@@ -82,6 +82,9 @@ typedef struct _tdm_vblank_wait_info tdm_vblank_wait_info;
 typedef struct _tdm_private_vblank {
        struct list_head link;
 
+       double stamp;
+       pid_t owner_tid;
+
        tdm_display *dpy;
        tdm_output *output;
        tdm_output_dpms dpms;
@@ -111,7 +114,7 @@ struct _tdm_vblank_wait_info {
        struct list_head link;
        struct list_head valid_link;
 
-       unsigned int stamp;
+       double stamp;
 
        double req_time;
        unsigned int interval;
@@ -126,10 +129,11 @@ struct _tdm_vblank_wait_info {
        unsigned int target_seq;
 };
 
+static pthread_mutex_t vblank_list_lock;
 static struct list_head vblank_list;
 static struct list_head valid_wait_list;
 static unsigned int vblank_list_inited;
-static unsigned int stamp = 0;
+static double stamp = 0;
 
 static tdm_error _tdm_vblank_cb_vblank_SW(void *user_data);
 static tdm_error _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info);
@@ -147,8 +151,28 @@ _print_list(struct list_head *list)
 }
 #endif
 
+static inline tdm_private_vblank*
+_tdm_vblank_find(double vblank_stamp)
+{
+       tdm_private_vblank *v = NULL;
+
+       if (!vblank_stamp)
+               return 0;
+
+       pthread_mutex_lock(&vblank_list_lock);
+       LIST_FOR_EACH_ENTRY(v, &vblank_list, link) {
+               if (v->stamp == vblank_stamp) {
+                       pthread_mutex_unlock(&vblank_list_lock);
+                       return v;
+               }
+       }
+       pthread_mutex_unlock(&vblank_list_lock);
+
+       return 0;
+}
+
 static inline unsigned int
-_tdm_vblank_check_valid(tdm_vblank_wait_info *wait_info)
+_tdm_vblank_check_valid_wait(tdm_vblank_wait_info *wait_info)
 {
        tdm_vblank_wait_info *w = NULL;
 
@@ -272,7 +296,7 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type,
        }
 }
 
-tdm_vblank*
+EXTERN tdm_vblank*
 tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
 {
        tdm_private_vblank *private_vblank;
@@ -287,6 +311,12 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
                *error = TDM_ERROR_NONE;
 
        if (!vblank_list_inited) {
+               if (pthread_mutex_init(&vblank_list_lock, NULL)) {
+                       TDM_ERR("mutex init failed: %m");
+                       if (error)
+                               *error = TDM_ERROR_OPERATION_FAILED;
+                       return NULL;
+               }
                LIST_INITHEAD(&vblank_list);
                LIST_INITHEAD(&valid_wait_list);
                vblank_list_inited = 1;
@@ -312,6 +342,8 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
 
        tdm_output_add_change_handler(output, _tdm_vblank_cb_output_change, private_vblank);
 
+       private_vblank->stamp = ++stamp;
+       private_vblank->owner_tid = syscall(SYS_gettid);
        private_vblank->dpy = dpy;
        private_vblank->output = output;
        private_vblank->dpms = dpms;
@@ -324,7 +356,9 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
        LIST_INITHEAD(&private_vblank->HW_wait_list);
        LIST_INITHEAD(&private_vblank->SW_wait_list);
 
+       pthread_mutex_lock(&vblank_list_lock);
        LIST_ADD(&private_vblank->link, &vblank_list);
+       pthread_mutex_unlock(&vblank_list_lock);
 
        if (tdm_debug_module & TDM_DEBUG_VBLANK)
                VIN("created. vrefresh(%d) dpms(%d)",
@@ -333,7 +367,7 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
        return (tdm_vblank*)private_vblank;
 }
 
-void
+EXTERN void
 tdm_vblank_destroy(tdm_vblank *vblank)
 {
        tdm_private_vblank *private_vblank = vblank;
@@ -342,7 +376,9 @@ tdm_vblank_destroy(tdm_vblank *vblank)
        if (!private_vblank)
                return;
 
+       pthread_mutex_lock(&vblank_list_lock);
        LIST_DEL(&private_vblank->link);
+       pthread_mutex_unlock(&vblank_list_lock);
 
        if (private_vblank->SW_timer) {
                tdm_display_lock(private_vblank->dpy);
@@ -367,7 +403,7 @@ tdm_vblank_destroy(tdm_vblank *vblank)
        free(private_vblank);
 }
 
-tdm_error
+EXTERN tdm_error
 tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps)
 {
        tdm_private_vblank *private_vblank = vblank;
@@ -387,7 +423,7 @@ tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps)
        return TDM_ERROR_NONE;
 }
 
-tdm_error
+EXTERN tdm_error
 tdm_vblank_set_offset(tdm_vblank *vblank, int offset)
 {
        tdm_private_vblank *private_vblank = vblank;
@@ -406,7 +442,7 @@ tdm_vblank_set_offset(tdm_vblank *vblank, int offset)
        return TDM_ERROR_NONE;
 }
 
-tdm_error
+EXTERN tdm_error
 tdm_vblank_set_enable_fake(tdm_vblank *vblank, unsigned int enable_fake)
 {
        tdm_private_vblank *private_vblank = vblank;
@@ -424,7 +460,7 @@ tdm_vblank_set_enable_fake(tdm_vblank *vblank, unsigned int enable_fake)
        return TDM_ERROR_NONE;
 }
 
-unsigned int
+EXTERN unsigned int
 tdm_vblank_get_enable_fake(tdm_vblank *vblank)
 {
        tdm_private_vblank *private_vblank = vblank;
@@ -501,7 +537,7 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence,
        tdm_vblank_wait_info *wait_info = user_data;
        tdm_private_vblank *private_vblank;
 
-       if (!_tdm_vblank_check_valid(wait_info)) {
+       if (!_tdm_vblank_check_valid_wait(wait_info)) {
                TDM_DBG("can't find wait(%p) from valid_wait_list", wait_info);
                return;
        }
@@ -625,10 +661,45 @@ static tdm_error
 _tdm_vblank_cb_vblank_SW(void *user_data)
 {
        tdm_private_vblank *private_vblank = user_data;
-       tdm_vblank_wait_info *first_wait_info = NULL, *w = NULL, *ww = NULL;
 
        TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_OPERATION_FAILED);
 
+       return tdm_vblank_cb_vblank_SW(private_vblank, 0);
+}
+
+INTERN tdm_error
+tdm_vblank_cb_vblank_SW(tdm_vblank *vblank, double vblank_stamp)
+{
+       tdm_private_vblank *private_vblank;
+       tdm_vblank_wait_info *first_wait_info = NULL, *w = NULL, *ww = NULL;
+
+       TDM_RETURN_VAL_IF_FAIL(vblank || vblank_stamp > 0, TDM_ERROR_INVALID_PARAMETER);
+
+       if (vblank)
+               private_vblank = vblank;
+       else {
+               private_vblank = _tdm_vblank_find(vblank_stamp);
+               if (!private_vblank) {
+                       TDM_DBG("can't find vblank(%.0f) from valid_list", vblank_stamp);
+                       return TDM_ERROR_NONE;
+               }
+       }
+
+       if (private_vblank->owner_tid != syscall(SYS_gettid)) {
+               tdm_thread_cb_vblank_sw vblank_sw;
+               tdm_private_display *private_display = private_vblank->dpy;
+               tdm_error ret;
+
+               vblank_sw.base.type = TDM_THREAD_CB_VBLANK_SW;
+               vblank_sw.base.length = sizeof vblank_sw;
+               vblank_sw.vblank_stamp = private_vblank->stamp;
+
+               ret = tdm_thread_send_cb(private_display->private_loop, &vblank_sw.base);
+               TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               return TDM_ERROR_NONE;
+       }
+
        if (LIST_IS_EMPTY(&private_vblank->SW_wait_list)) {
                VER("no wait_info");
                return TDM_ERROR_OPERATION_FAILED;
@@ -653,10 +724,13 @@ _tdm_vblank_cb_vblank_SW(void *user_data)
                LIST_DEL(&w->link);
                LIST_DEL(&w->valid_link);
 
-               if (w->func)
+               if (w->func) {
+                       tdm_display_unlock(private_vblank->dpy);
                        w->func(private_vblank, TDM_ERROR_NONE, w->target_seq,
                                        TDM_TIME_SEC(w->target_time), TDM_TIME_USEC(w->target_time),
                                        w->user_data);
+                       tdm_display_lock(private_vblank->dpy);
+               }
 
                free(w);
        }
@@ -720,7 +794,7 @@ _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info)
        return TDM_ERROR_NONE;
 }
 
-tdm_error
+EXTERN tdm_error
 tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
                                unsigned int interval, tdm_vblank_handler func, void *user_data)
 {
@@ -731,6 +805,11 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
        TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
        TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
 
+       if (private_vblank->owner_tid != syscall(SYS_gettid)) {
+               TDM_ERR("SHOULD be called in the owner thread");
+               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;
@@ -797,7 +876,7 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
        return TDM_ERROR_NONE;
 }
 
-tdm_error
+EXTERN tdm_error
 tdm_vblank_wait_seq(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
                                        unsigned int sequence, tdm_vblank_handler func, void *user_data)
 {