From 08b18c4d1fb77ec2d9e425ef9d72806f28d97c7d Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 20 Dec 2017 15:57:19 +0900 Subject: [PATCH 01/16] package version up to 1.10.2 Change-Id: Ib6012f1b570ac89fa4b3f8d4c5588d08e9045750 --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 52e7015..ec545de 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %define UTEST_PACKAGE 1 Name: libtdm -Version: 1.10.1 +Version: 1.10.2 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From 6bf42e11db58d7cc9b10e741877382dba99a9210 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Tue, 26 Dec 2017 09:44:48 +0900 Subject: [PATCH 02/16] utest: fix the memory leak Change-Id: Ib5c0b7dc96b19fefb93889b330b444f937490eac --- utests/src/ut_tdm.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/utests/src/ut_tdm.cpp b/utests/src/ut_tdm.cpp index 33a968f..2ba98ca 100644 --- a/utests/src/ut_tdm.cpp +++ b/utests/src/ut_tdm.cpp @@ -309,6 +309,7 @@ TEST_F(TDMInit, DisplayDeinitFailRepeatWithSameDpy) tdm_display_deinit(dpy2); tdm_display_deinit(dpy); tdm_display_deinit(dpy2); + free(dpy2); exit(0); }, ::testing::ExitedWithCode(0), ""); } -- 2.7.4 From 964ba2123eae047eaecd4cb957022974ab55dbcf Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Tue, 26 Dec 2017 09:45:27 +0900 Subject: [PATCH 03/16] utest: fix the dereference of null pointer Change-Id: I4e3fca3eca89c03a6aa886cc657d90b17dc3b0b3 --- utests/src/ut_tdm_client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/utests/src/ut_tdm_client.cpp b/utests/src/ut_tdm_client.cpp index 67db93a..a793bc7 100644 --- a/utests/src/ut_tdm_client.cpp +++ b/utests/src/ut_tdm_client.cpp @@ -755,6 +755,7 @@ TEST_F(TDMClientTestClientOutput, TdmClientOutputAddChangeHandlerSuccessful) /* force a requests flush */ wl_dsp = wl_display_connect("tdm-socket"); + ASSERT_TRUE(nullptr != wl_dsp); wl_display_flush(wl_dsp); wl_display_roundtrip(wl_dsp); wl_display_disconnect(wl_dsp); -- 2.7.4 From 9bb62b38d63546443a667cdc72e36ae3ff4b8330 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 26 Dec 2017 18:34:52 +0900 Subject: [PATCH 04/16] server: remove unused request Change-Id: I0aa949b4d9ae69464538f178d733223f43c342d9 --- protocol/tdm.xml | 6 ------ src/tdm_server.c | 13 ------------- 2 files changed, 19 deletions(-) diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 24c603e..6434e98 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -23,12 +23,6 @@ - - - - - - diff --git a/src/tdm_server.c b/src/tdm_server.c index 5f88332..e4a3e75 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -740,22 +740,9 @@ _tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, con } /* LCOV_EXCL_STOP */ -/* LCOV_EXCL_START */ -static void -_tdm_server_cb_set_client_vblank_fps(struct wl_client *client, struct wl_resource *resource, - unsigned int pid, const char *name, unsigned int fps) -{ - tdm_error ret = tdm_vblank_set_client_vblank_fps(pid, name, fps); - TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); - - TDM_INFO("'%s' vblank fps(PID: '%u'): %u", name, pid, fps); -} -/* LCOV_EXCL_STOP */ - static const struct wl_tdm_interface tdm_implementation = { _tdm_server_cb_debug, _tdm_server_cb_create_output, - _tdm_server_cb_set_client_vblank_fps, }; static void -- 2.7.4 From afbef371013e66c1bd9d5037581bda76eccc7d4e Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 28 Dec 2017 13:13:25 +0900 Subject: [PATCH 05/16] package version up to 1.10.3 Change-Id: I843294f115afe16868502b16c61b35ad3fbb6195 --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index ec545de..bdf1567 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %define UTEST_PACKAGE 1 Name: libtdm -Version: 1.10.2 +Version: 1.10.3 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From f845022d7c9b40e4713449564af6ba0fcaf23017 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 27 Dec 2017 14:56:48 +0900 Subject: [PATCH 06/16] vblank: trace the vblank object creation. We don't allow adding a create handler in sub-thread because tdm_vblank_create() can be called in both threads and tdm_thread_send_cb supports only one-way communication now. Change-Id: I2c2b90cc29348aa9b24f5882369d94435a358e52 --- include/tdm.h | 22 +++++++ include/tdm_types.h | 5 ++ src/tdm.c | 7 +++ src/tdm_private.h | 13 ++++ src/tdm_thread.c | 5 ++ src/tdm_vblank.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 213 insertions(+), 14 deletions(-) diff --git a/include/tdm.h b/include/tdm.h index 2c0ba6a..9f8ea82 100644 --- a/include/tdm.h +++ b/include/tdm.h @@ -1281,6 +1281,28 @@ tdm_error tdm_vblank_enable_global_fps(unsigned int enable, unsigned int fps); /** + * @brief Add the vblank create handler. + * @param[in] dpy A display object + * @param[in] func The user vblank create handler + * @param[in] user_data The user data + * @details + * The user vblank create handler will be called when new vblank object created. + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_vblank_add_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data); + +/** + * @brief Remove the vblank create handler. + * @param[in] dpy A display object + * @param[in] func The user vblank create handler + * @param[in] user_data The user data + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +void +tdm_vblank_remove_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data); + +/** * @brief Create a vblank object * @param[in] dpy A display object * @param[in] output A output object diff --git a/include/tdm_types.h b/include/tdm_types.h index 75cb920..ebb8291 100644 --- a/include/tdm_types.h +++ b/include/tdm_types.h @@ -261,6 +261,11 @@ typedef void (*tdm_capture_done_handler)(tdm_capture *capture, tbm_surface_h buffer, void *user_data); /** + * @brief The create handler of a vblank object + */ +typedef void (*tdm_vblank_create_handler)(tdm_vblank *vblank, void *user_data); + +/** * @brief The 'need to validate' handler of an output object * @since 2.0.0 */ diff --git a/src/tdm.c b/src/tdm.c index 53f1547..9492336 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -977,6 +977,10 @@ tdm_display_init(tdm_error *error) TDM_DBG("prepare init time: %.3f ms", (stamp2 - stamp1) * 1000.0); stamp1 = stamp2; + ret = tdm_vblank_init(private_display); + if (ret != TDM_ERROR_NONE) + goto failed_vblank; + ret = tdm_event_loop_init(private_display); if (ret != TDM_ERROR_NONE) goto failed_event; @@ -1065,6 +1069,8 @@ failed_load: tdm_event_loop_stop(private_display); tdm_event_loop_deinit(private_display); failed_event: + tdm_vblank_deinit(private_display); +failed_vblank: _pthread_mutex_unlock(&private_display->lock); pthread_mutex_destroy(&private_display->lock); failed_mutex_init: @@ -1106,6 +1112,7 @@ tdm_display_deinit(tdm_display *dpy) _pthread_mutex_unlock(&private_display->lock); tdm_event_loop_deinit(private_display); + tdm_vblank_deinit(private_display); #ifdef INIT_BUFMGR if (private_display->bufmgr) diff --git a/src/tdm_private.h b/src/tdm_private.h index b7cb0a3..6d9c95f 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -511,8 +511,14 @@ void tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer, void *user_data); tdm_error +tdm_vblank_init(tdm_display *dpy); +void +tdm_vblank_deinit(tdm_display *dpy); +tdm_error tdm_vblank_cb_vblank_SW(tdm_vblank *vblank, double vblank_stamp); tdm_error +tdm_vblank_cb_vblank_create(tdm_vblank *vblank, double vblank_stamp); +tdm_error tdm_vblank_set_add_front(tdm_vblank *vblank, unsigned int add_front); tdm_error tdm_vblank_set_resource(tdm_vblank *vblank, struct wl_resource *resource); @@ -587,6 +593,7 @@ typedef enum { TDM_THREAD_CB_PP_DONE, TDM_THREAD_CB_CAPTURE_DONE, TDM_THREAD_CB_VBLANK_SW, + TDM_THREAD_CB_VBLANK_CREATE, TDM_THREAD_CB_NEED_VALIDATE, } tdm_thread_cb_type; @@ -598,6 +605,7 @@ 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; +typedef struct _tdm_thread_cb_vblank_create tdm_thread_cb_vblank_create; typedef struct _tdm_thread_cb_need_validate tdm_thread_cb_need_validate; struct _tdm_thread_cb_base { @@ -648,6 +656,11 @@ struct _tdm_thread_cb_vblank_sw { double vblank_stamp; }; +struct _tdm_thread_cb_vblank_create { + tdm_thread_cb_base base; + double vblank_stamp; +}; + struct _tdm_thread_cb_need_validate { tdm_thread_cb_base base; tdm_private_output *o; diff --git a/src/tdm_thread.c b/src/tdm_thread.c index ed5d049..a775690 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -360,6 +360,11 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) tdm_vblank_cb_vblank_SW(NULL, vblank_sw->vblank_stamp); break; } + case TDM_THREAD_CB_VBLANK_CREATE: { + tdm_thread_cb_vblank_create *vblank_create = (tdm_thread_cb_vblank_create*)base; + tdm_vblank_cb_vblank_create(NULL, vblank_create->vblank_stamp); + break; + } case TDM_THREAD_CB_NEED_VALIDATE: { tdm_thread_cb_need_validate *ev = (tdm_thread_cb_need_validate*)base; tdm_output_cb_need_validate(ev->o); diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 24dd991..bb62f42 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -40,6 +40,7 @@ #include "tdm.h" #include "tdm_private.h" #include "tdm_list.h" +#include "tdm_macro.h" /* CAUTION: * Basically tdm vblank doesn't care about thread things. @@ -108,6 +109,7 @@ typedef struct _tdm_private_vblank { int offset; unsigned int enable_fake; unsigned int ignore_global_fps; + unsigned int in_create_handler; double vblank_gap; unsigned int quotient; @@ -146,12 +148,20 @@ struct _tdm_vblank_wait_info { unsigned int target_seq; }; +typedef struct _tdm_vblank_create_handler_info { + struct list_head link; + + tdm_vblank_create_handler func; + void *user_data; +} tdm_vblank_create_handler_info; + /* valid_vblank_list and valid_wait_list should be protected by valid_list_lock because * tdm_vblank can be used in multi-thread. */ static pthread_mutex_t valid_list_lock; static struct list_head valid_vblank_list; static struct list_head valid_wait_list; +static struct list_head create_handler_list; static unsigned int vblank_list_inited; static unsigned int vblank_global_fps; static double stamp = 0; @@ -479,6 +489,143 @@ tdm_vblank_enable_global_fps(unsigned int enable, unsigned int fps) return TDM_ERROR_NONE; } +INTERN tdm_error +tdm_vblank_cb_vblank_create(tdm_vblank *vblank, double vblank_stamp) +{ + tdm_private_vblank *private_vblank; + tdm_vblank_create_handler_info *ch_info = NULL, *hh = 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 (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { + tdm_thread_cb_vblank_create vblank_create; + tdm_private_display *private_display = private_vblank->dpy; + tdm_error ret; + + vblank_create.base.type = TDM_THREAD_CB_VBLANK_CREATE; + vblank_create.base.length = sizeof vblank_create; + vblank_create.vblank_stamp = private_vblank->stamp; + + ret = tdm_thread_send_cb(private_display->private_loop, &vblank_create.base); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + return TDM_ERROR_NONE; + } + + LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) { + private_vblank->in_create_handler = 1; + ch_info->func(private_vblank, ch_info->user_data); + private_vblank->in_create_handler = 0; + } + + return TDM_ERROR_NONE; +} + +EXTERN tdm_error +tdm_vblank_add_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data) +{ + tdm_vblank_create_handler_info *ch_info; + + TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + + /* we don't allow adding a create handler in sub-thread because tdm_vblank_create() + * can be called in both threads and tdm_thread_send_cb supports only one-way + * communication now. + */ + if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { + TDM_ERR("add_create_handler should be called in main thread"); + return TDM_ERROR_BAD_REQUEST; + } + + ch_info = calloc(1, sizeof *ch_info); + TDM_RETURN_VAL_IF_FAIL(ch_info != NULL, TDM_ERROR_OUT_OF_MEMORY); + + ch_info->func = func; + ch_info->user_data = user_data; + + LIST_ADDTAIL(&ch_info->link, &create_handler_list); + + return TDM_ERROR_NONE; +} + +EXTERN void +tdm_vblank_remove_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data) +{ + tdm_vblank_create_handler_info *ch_info = NULL, *hh = NULL; + + /* we don't allow adding a create handler in sub-thread because tdm_vblank_create() + * can be called in both threads and tdm_thread_send_cb supports only one-way + * communication now. + */ + if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { + TDM_ERR("remove_create_handler should be called in main thread"); + return; + } + + LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) { + if (ch_info->func != func && ch_info->user_data != user_data) + continue; + + LIST_DEL(&ch_info->link); + free(ch_info); + return; + } +} + +INTERN tdm_error +tdm_vblank_init(tdm_display *dpy) +{ + if (vblank_list_inited) + return TDM_ERROR_NONE; + + if (pthread_mutex_init(&valid_list_lock, NULL)) { + TDM_ERR("mutex init failed: %m"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + LIST_INITHEAD(&valid_vblank_list); + LIST_INITHEAD(&valid_wait_list); + LIST_INITHEAD(&create_handler_list); + + vblank_list_inited = 1; + + return TDM_ERROR_NONE; +} + +INTERN void +tdm_vblank_deinit(tdm_display *dpy) +{ + tdm_vblank_create_handler_info *ch_info = NULL, *hh = NULL; + + if (!vblank_list_inited) + return; + + if (!LIST_IS_EMPTY(&valid_vblank_list)) + TDM_NEVER_GET_HERE(); + + if (!LIST_IS_EMPTY(&valid_wait_list)) + TDM_NEVER_GET_HERE(); + + LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) { + LIST_DEL(&ch_info->link); + free(ch_info); + } + + pthread_mutex_destroy(&valid_list_lock); + + vblank_list_inited = 0; +} + EXTERN tdm_vblank * tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) { @@ -491,20 +638,6 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) if (error) *error = TDM_ERROR_NONE; - if (!vblank_list_inited) { - if (pthread_mutex_init(&valid_list_lock, NULL)) { - /* LCOV_EXCL_START */ - TDM_ERR("mutex init failed: %m"); - if (error) - *error = TDM_ERROR_OPERATION_FAILED; - return NULL; - /* LCOV_EXCL_STOP */ - } - LIST_INITHEAD(&valid_vblank_list); - LIST_INITHEAD(&valid_wait_list); - vblank_list_inited = 1; - } - private_vblank = calloc(1, sizeof * private_vblank); if (!private_vblank) { /* LCOV_EXCL_START */ @@ -537,6 +670,10 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) VIN("created. vrefresh(%d) connection(%d)", private_vblank->vrefresh, private_vblank->connection); + tdm_display_lock(private_vblank->dpy); + tdm_vblank_cb_vblank_create(NULL, private_vblank->stamp); + tdm_display_unlock(private_vblank->dpy); + return (tdm_vblank *)private_vblank; } @@ -548,6 +685,11 @@ tdm_vblank_destroy(tdm_vblank *vblank) TDM_RETURN_IF_FAIL(tdm_vblank_is_valid(vblank)); + if (private_vblank->in_create_handler) { + TDM_ERR("NOT allowed to be called in a create handler"); + return; + } + _tdm_vblank_valid_list_del(&private_vblank->valid_link); if (private_vblank->SW_timer) { @@ -1085,6 +1227,11 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + if (private_vblank->in_create_handler) { + TDM_ERR("NOT allowed to be called in a create handler"); + return TDM_ERROR_BAD_REQUEST; + } + if (private_vblank->owner_tid != syscall(SYS_gettid)) { TDM_ERR("SHOULD be called in the owner thread(%d)", (int)private_vblank->owner_tid); return TDM_ERROR_BAD_REQUEST; -- 2.7.4 From ab5e79a4ff96ac99dde25f76782066c4c181d3ca Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 27 Dec 2017 14:57:36 +0900 Subject: [PATCH 07/16] vblank: get the client pid of a vblank object. Change-Id: I7fa29f1b03720ec93344893ea8a8bf3e0c8a6c72 --- include/tdm.h | 10 ++++++++++ src/tdm_vblank.c | 25 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/tdm.h b/include/tdm.h index 9f8ea82..c843eef 100644 --- a/include/tdm.h +++ b/include/tdm.h @@ -37,6 +37,7 @@ #define _TDM_H_ #include +#include #include #include #include @@ -1322,6 +1323,15 @@ void tdm_vblank_destroy(tdm_vblank *vblank); /** + * @brief Get the client PID for a vblank object + * @param[in] vblank A vblank object + * @param[out] pid PID of vblank's client + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_vblank_get_client_pid(tdm_vblank *vblank, pid_t *pid); + +/** * @brief Set the name to a vblank object * @details The default name is "unknown" * @param[in] vblank A vblank object diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index bb62f42..91d04f4 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -715,6 +715,31 @@ tdm_vblank_destroy(tdm_vblank *vblank) } EXTERN tdm_error +tdm_vblank_get_client_pid(tdm_vblank *vblank, pid_t *pid) +{ + tdm_private_vblank *private_vblank = vblank; + struct wl_client *client; + + TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(pid != NULL, TDM_ERROR_INVALID_PARAMETER); + + if (!private_vblank->resource) { + *pid = 0; + return TDM_ERROR_NONE; + } + + client = wl_resource_get_client(private_vblank->resource); + if (!client) { + *pid = 0; + return TDM_ERROR_NONE; + } + + wl_client_get_credentials(client, pid, NULL, NULL); + + return TDM_ERROR_NONE; +} + +EXTERN tdm_error tdm_vblank_set_name(tdm_vblank *vblank, const char *name) { tdm_private_vblank *private_vblank = vblank; -- 2.7.4 From e16d8ab596926a9bf4bd2d7019e41c6b77da8e78 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 27 Dec 2017 14:58:21 +0900 Subject: [PATCH 08/16] vblank: set the fixed fps to a vblank object The vblank fps by setting with tdm_vblank_set_fixed_fps can't be changed with tdm_vblank_set_fps. But it could be changed with tdm_vblank_enable_global_fps. Change-Id: Iee25d749c1ebde51546810cb0baee1a0fc08ddef --- include/tdm.h | 12 ++++++++++++ src/tdm_vblank.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/include/tdm.h b/include/tdm.h index c843eef..3812842 100644 --- a/include/tdm.h +++ b/include/tdm.h @@ -1354,6 +1354,7 @@ tdm_vblank_get_name(tdm_vblank *vblank, const char **name); /** * @brief Set the fps to a vblank object * @details Default is the @b vertical @b refresh @b rate of the given output. + * It could be ignored when the fixed fps is set by #tdm_vblank_set_fixed_fps * @param[in] vblank A vblank object * @param[in] fps over 0 * @return #TDM_ERROR_NONE if success. Otherwise, error value. @@ -1371,6 +1372,17 @@ tdm_error tdm_vblank_get_fps(tdm_vblank *vblank, unsigned int *fps); /** + * @brief Set the fixed fps to a vblank object + * @details + * It could be ignored when the global fps is set by #tdm_vblank_enable_global_fps + * @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_fixed_fps(tdm_vblank *vblank, unsigned int fps); + +/** * @brief Ignore the vblank global fps * @details * The global fps will be applied to all client's vblanks for all outputs. diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 91d04f4..e0ca079 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -106,6 +106,7 @@ typedef struct _tdm_private_vblank { char name[TDM_NAME_LEN]; unsigned int fps; unsigned int fps_changeable; + unsigned int fps_fixed; int offset; unsigned int enable_fake; unsigned int ignore_global_fps; @@ -778,8 +779,10 @@ tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); - if (private_vblank->fps != fps || private_vblank->fps_changeable) - VIN("fps(%d) fps_changeable(0)", fps); + if (private_vblank->fps_fixed) { + VIN("fps(%d) can't be changed", private_vblank->fps); + return TDM_ERROR_NONE; + } private_vblank->fps_changeable = 0; @@ -789,6 +792,8 @@ tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) private_vblank->fps = fps; private_vblank->check_HW_or_SW = 1; + VIN("fps(%d) changed", fps); + return TDM_ERROR_NONE; } @@ -806,6 +811,28 @@ tdm_vblank_get_fps(tdm_vblank *vblank, unsigned int *fps) } EXTERN tdm_error +tdm_vblank_set_fixed_fps(tdm_vblank *vblank, unsigned int fps) +{ + tdm_private_vblank *private_vblank = vblank; + + TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); + + private_vblank->fps_changeable = 0; + private_vblank->fps_fixed = 1; + + if (private_vblank->fps == fps) + return TDM_ERROR_NONE; + + private_vblank->fps = fps; + private_vblank->check_HW_or_SW = 1; + + VIN("fps(%d) fixed", fps); + + return TDM_ERROR_NONE; +} + +EXTERN tdm_error tdm_vblank_ignore_global_fps(tdm_vblank *vblank, unsigned int ignore) { tdm_private_vblank *private_vblank = vblank; -- 2.7.4 From ebd79885bfada70507deece190c62ebd4879502e Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 28 Dec 2017 16:43:25 +0900 Subject: [PATCH 09/16] package version up to 1.11.0 Change-Id: Icb9e4537235985803b85c5b2f2d284c09c663d20 --- configure.ac | 2 +- doc/tdm_doc.h | 2 +- packaging/libtdm.spec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index c55f3fe..739c1b7 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ([2.60]) m4_define([tdm_major_version], [1]) -m4_define([tdm_minor_version], [7]) +m4_define([tdm_minor_version], [11]) m4_define([tdm_micro_version], [0]) m4_define([tdm_version], [tdm_major_version.tdm_minor_version.tdm_micro_version]) diff --git a/doc/tdm_doc.h b/doc/tdm_doc.h index 1d3e915..02d418c 100644 --- a/doc/tdm_doc.h +++ b/doc/tdm_doc.h @@ -39,7 +39,7 @@ /** * @mainpage TDM * @author Boram Park, boram1288.park@samsung.com - * @version 1.7.0 + * @version 1.11.0 * @par Introduction * TDM stands for Tizen Display Manager. It's the display HAL layer for tizen * display server. It offers the frontend APIs(@ref tdm.h) for a frontend user diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index bdf1567..ffaa123 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %define UTEST_PACKAGE 1 Name: libtdm -Version: 1.10.3 +Version: 1.11.0 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From dc1e81c0f4f0c6e6c4c0d4d553cf8ba730dfb4f5 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 3 Jan 2018 20:16:25 +0900 Subject: [PATCH 10/16] vblank: return TDM_ERROR_TIMEOUT when timeout occurs If a vblank callback isn't called in 2000ms, tdm vblank will return TDM_ERROR_TIMEOUT to client. Change-Id: Ib5cd14dddd8bef051e01664c52021f57c7099f48 --- include/tdm_common.h | 1 + src/tdm_vblank.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 140 insertions(+), 9 deletions(-) diff --git a/include/tdm_common.h b/include/tdm_common.h index b170c48..cfc031c 100644 --- a/include/tdm_common.h +++ b/include/tdm_common.h @@ -68,6 +68,7 @@ typedef enum { TDM_ERROR_NO_CAPABILITY = -9, /**< no capability */ TDM_ERROR_DPMS_OFF = -10, /**< dpms off */ TDM_ERROR_OUTPUT_DISCONNECTED = -11, /**< output disconnected */ + TDM_ERROR_TIMEOUT = -12, /**< timeout */ } tdm_error; /** diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index e0ca079..99cb744 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -128,6 +128,9 @@ typedef struct _tdm_private_vblank { /* for SW */ tdm_event_loop_source *SW_timer; struct list_head SW_wait_list; + + /* for timeout */ + tdm_event_loop_source *timeout_timer; } tdm_private_vblank; struct _tdm_vblank_wait_info { @@ -172,6 +175,9 @@ static tdm_error _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info); static void _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data); +static void _tdm_vblank_timeout_timer_update(tdm_private_vblank *private_vblank, int ms_delay); +static void _tdm_vblank_get_client_information(tdm_private_vblank *private_vblank, + pid_t *pid, const char **name); #if 0 static void @@ -332,6 +338,13 @@ _tdm_vblank_free_HW_wait(tdm_private_vblank *private_vblank, tdm_error error, un { tdm_vblank_wait_info *w = NULL, *ww = NULL; + if (!LIST_IS_EMPTY(&private_vblank->SW_wait_list)) + TDM_NEVER_GET_HERE(); + + tdm_display_lock(private_vblank->dpy); + _tdm_vblank_timeout_timer_update(private_vblank, 0); + tdm_display_unlock(private_vblank->dpy); + LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->HW_wait_list, link) { LIST_DEL(&w->link); _tdm_vblank_valid_list_del(&w->valid_link); @@ -702,14 +715,20 @@ tdm_vblank_destroy(tdm_vblank *vblank) tdm_output_remove_change_handler(private_vblank->output, _tdm_vblank_cb_output_change, private_vblank); - _tdm_vblank_free_HW_wait(private_vblank, 0, 0); - LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->SW_wait_list, link) { LIST_DEL(&w->link); _tdm_vblank_valid_list_del(&w->valid_link); free(w); } + _tdm_vblank_free_HW_wait(private_vblank, 0, 0); + + if (private_vblank->timeout_timer) { + tdm_display_lock(private_vblank->dpy); + tdm_event_loop_source_remove(private_vblank->timeout_timer); + tdm_display_unlock(private_vblank->dpy); + } + VIN("destroyed"); free(private_vblank); @@ -912,6 +931,84 @@ tdm_vblank_get_enable_fake(tdm_vblank *vblank, unsigned int *enable_fake) } static tdm_error +_tdm_vblank_timeout_timer_cb(void *user_data) +{ + tdm_private_vblank *private_vblank = user_data; + tdm_vblank_wait_info *w = NULL, *ww = NULL; + tdm_error error = TDM_ERROR_TIMEOUT; + pid_t pid; + const char *proc_name; + + TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(private_vblank), TDM_ERROR_OPERATION_FAILED); + + _tdm_vblank_get_client_information(private_vblank, &pid, &proc_name); + + if (!LIST_IS_EMPTY(&private_vblank->HW_wait_list)) { + + VER("HW vblank TIMEOUT!! (pid: %u, name: %s)", pid, proc_name); + + LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->HW_wait_list, link) { + LIST_DEL(&w->link); + _tdm_vblank_valid_list_del(&w->valid_link); + + tdm_output_remove_vblank_handler_internal(private_vblank->output, _tdm_vblank_cb_vblank_HW, w); + + if (w->func) + w->func(private_vblank, error, 0, 0, 0, w->user_data); + + free(w); + } + } + + if (!LIST_IS_EMPTY(&private_vblank->SW_wait_list)) { + + VER("SW vblank TIMEOUT!! (pid: %u, name: %s)", pid, proc_name); + + LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->SW_wait_list, link) { + LIST_DEL(&w->link); + _tdm_vblank_valid_list_del(&w->valid_link); + + if (w->func) + w->func(private_vblank, error, 0, 0, 0, w->user_data); + + free(w); + } + } + + return TDM_ERROR_NONE; +} + +static void +_tdm_vblank_timeout_timer_update(tdm_private_vblank *private_vblank, int ms_delay) +{ + tdm_error ret; + + if (!private_vblank->timeout_timer) { + private_vblank->timeout_timer = + tdm_event_loop_add_timer_handler(private_vblank->dpy, + _tdm_vblank_timeout_timer_cb, + private_vblank, + &ret); + if (!private_vblank->timeout_timer) { + VER("couldn't add timer"); + return; + } + VIN("Create Timeout timer"); + } + + ret = tdm_event_loop_source_timer_update(private_vblank->timeout_timer, ms_delay); + if (ret != TDM_ERROR_NONE) { + VER("couldn't update timer"); + return; + } + + if (ms_delay != 0) + VDB("timeout timer updated"); + else + VDB("timeout timer disabled"); +} + +static tdm_error _tdm_vblank_sw_timer_update(tdm_private_vblank *private_vblank) { tdm_vblank_wait_info *first_wait_info = NULL; @@ -1017,6 +1114,13 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence, VWR("couldn't update sw timer"); } + if (!LIST_IS_EMPTY(&private_vblank->SW_wait_list)) + TDM_NEVER_GET_HERE(); + + tdm_display_lock(private_vblank->dpy); + _tdm_vblank_timeout_timer_update(private_vblank, 0); + tdm_display_unlock(private_vblank->dpy); + LIST_DEL(&wait_info->link); _tdm_vblank_valid_list_del(&wait_info->valid_link); @@ -1168,6 +1272,11 @@ tdm_vblank_cb_vblank_SW(tdm_vblank *vblank, double vblank_stamp) return TDM_ERROR_OPERATION_FAILED; } + if (!LIST_IS_EMPTY(&private_vblank->HW_wait_list)) + TDM_NEVER_GET_HERE(); + + _tdm_vblank_timeout_timer_update(private_vblank, 0); + first_wait_info = container_of(private_vblank->SW_wait_list.next, first_wait_info, link); TDM_RETURN_VAL_IF_FAIL(first_wait_info != NULL, TDM_ERROR_OPERATION_FAILED); @@ -1387,6 +1496,10 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, /* LCOV_EXCL_STOP */ } + tdm_display_lock(private_vblank->dpy); + _tdm_vblank_timeout_timer_update(private_vblank, 2000); + tdm_display_unlock(private_vblank->dpy); + return TDM_ERROR_NONE; } @@ -1483,6 +1596,29 @@ tdm_vblank_get_stamp(tdm_vblank *vblank) return private_vblank->stamp; } +static void +_tdm_vblank_get_client_information(tdm_private_vblank *private_vblank, pid_t *pid, const char **name) +{ + struct wl_client *client; + + if (!private_vblank->resource) + goto no_client; + + client = wl_resource_get_client(private_vblank->resource); + if (!client) + goto no_client; + + wl_client_get_credentials(client, pid, NULL, NULL); + *name = tdm_server_get_client_name(*pid); + + return; + +no_client: + *pid = 0; + *name = NULL; + return; +} + /* LCOV_EXCL_START */ INTERN void tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) @@ -1500,13 +1636,7 @@ tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) const char *proc_name = NULL; pid_t pid = 0; - if (v->resource) { - struct wl_client *client = wl_resource_get_client(v->resource); - if (client) { - wl_client_get_credentials(client, &pid, NULL, NULL); - proc_name = tdm_server_get_client_name(pid); - } - } + _tdm_vblank_get_client_information(v, &pid, &proc_name); TDM_SNPRINTF(reply, len, "%-12s %u %u %d %u %s (pid: %u)\n", v->name, v->fps, v->ignore_global_fps, v->offset, v->enable_fake, -- 2.7.4 From bffe73c130b6d94bb96333b7434b101c5ca3819d Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 3 Jan 2018 20:29:58 +0900 Subject: [PATCH 11/16] package version up to 1.11.1 Change-Id: Ie5ab819303b054ae192e31d81ca01e653888c20a --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index ffaa123..895c21e 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %define UTEST_PACKAGE 1 Name: libtdm -Version: 1.11.0 +Version: 1.11.1 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From 2439a9bfda0fa139819211de1fec578ca46352fd Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 4 Jan 2018 10:48:28 +0900 Subject: [PATCH 12/16] utest: check the return value. Change-Id: I24e639bbf8a5894cbd2aa8efe6ee6693c4cc6465 --- utests/src/ut_tdm_client.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/utests/src/ut_tdm_client.cpp b/utests/src/ut_tdm_client.cpp index a793bc7..678269b 100644 --- a/utests/src/ut_tdm_client.cpp +++ b/utests/src/ut_tdm_client.cpp @@ -467,6 +467,7 @@ void TDMClientTest::init_tdm(void) { int outputs_cnt = 0; tdm_output_type tdm_output_type; + tdm_error error; int output_modes_cnt = 0; const tdm_output_mode* output_modes; @@ -488,7 +489,12 @@ void TDMClientTest::init_tdm(void) deinit_tdm(); exit(EXIT_FAILURE); } - tdm_output_get_output_type(output, &tdm_output_type); + error = tdm_output_get_output_type(output, &tdm_output_type); + if (error != TDM_ERROR_NONE) { + std::cout << "tdm_output_get_output_type faild, server's gonna be stopped.\n"; + deinit_tdm(); + exit(EXIT_FAILURE); + } /* we're not interesting about other outputs */ if (tdm_output_type != TDM_OUTPUT_TYPE_VIRTUAL && -- 2.7.4 From f5f7565573119e47cfc3c132953097fc5b4158f1 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 4 Jan 2018 10:52:55 +0900 Subject: [PATCH 13/16] utest: initialize the damage variables Change-Id: I9adf1c96dcd5781e816ff74c258135884c132931 --- utests/src/ut_tdm_hwc_window.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/utests/src/ut_tdm_hwc_window.cpp b/utests/src/ut_tdm_hwc_window.cpp index 544ddff..9a5c171 100644 --- a/utests/src/ut_tdm_hwc_window.cpp +++ b/utests/src/ut_tdm_hwc_window.cpp @@ -306,7 +306,7 @@ TEST_F(TDMOutputHwc, SetClientTargetBufferFailNullOutput) TEST_F(TDMOutputHwcWithoutHwcCap, SetClientTargetBufferFailNoHwc) { - tdm_hwc_region damage; + tdm_hwc_region damage = {.num_rects = 0, .rects = NULL}; for (int i = 0; i < output_count; i++) { tbm_surface_h target_buff = CreateBufferForOutput(i); @@ -320,7 +320,7 @@ TEST_F(TDMOutputHwcWithoutHwcCap, SetClientTargetBufferFailNoHwc) TEST_F(TDMOutputHwc, SetClientTargetBufferSuccessfulSetBuff) { - tdm_hwc_region damage; + tdm_hwc_region damage = {.num_rects = 0, .rects = NULL}; for (int i = 0; i < output_count; i++) { tbm_surface_h target_buff = CreateBufferForOutput(i); @@ -494,7 +494,8 @@ TEST_F(TDMHwcWindow, SetCompositionTypeFailInvalieCompositionType) /* tdm_error tdm_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage); */ TEST_F(TDMHwcWindow, SetBufferDamageFailNullHwcWindow) { - tdm_hwc_region damage; + tdm_hwc_region damage = {.num_rects = 0, .rects = NULL}; + error = tdm_hwc_window_set_buffer_damage(NULL, damage); ASSERT_NE(TDM_ERROR_NONE, error); } -- 2.7.4 From 7cc6f639e01e1121f2522cf560bf42e9892af21d Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Thu, 4 Jan 2018 11:40:25 +0900 Subject: [PATCH 14/16] utest: cactch GoogleTestFailureException Change-Id: Ia137c1ba715b29ac7385f55218d51ca880f62fcc --- utests/src/ut_main.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/utests/src/ut_main.cpp b/utests/src/ut_main.cpp index 6443f33..c056a2f 100644 --- a/utests/src/ut_main.cpp +++ b/utests/src/ut_main.cpp @@ -32,6 +32,8 @@ int main(int argc, char **argv) { + auto AllTestSuccess = false; + try { ::testing::InitGoogleTest(&argc, argv); ::testing::FLAGS_gtest_death_test_style = "fast"; @@ -39,5 +41,14 @@ int main(int argc, char **argv) std::cout << "error while trying to init google tests.\n"; exit(EXIT_FAILURE); } - return RUN_ALL_TESTS(); -} + + try { + AllTestSuccess = RUN_ALL_TESTS() == 0 ? true : false; + } catch (const ::testing::internal::GoogleTestFailureException& e) { + AllTestSuccess = false; + std::cout << "GoogleTestFailureException was thrown:"<< e.what() << std::endl; + std::cout << "\n"; + } + + return AllTestSuccess; +} \ No newline at end of file -- 2.7.4 From e67997b3e6f2aacf7655006556a8a7e0d481e4ad Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Sun, 7 Jan 2018 10:20:04 +0900 Subject: [PATCH 15/16] hwc: allow Device Candidate to set composition type. Change-Id: I3aab482dcc9d037c91cacba9704586ffcd6f1390 --- src/tdm_hwc_window.c | 1 - utests/src/ut_tdm_hwc_window.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/tdm_hwc_window.c b/src/tdm_hwc_window.c index 1605f58..88a8e9d 100644 --- a/src/tdm_hwc_window.c +++ b/src/tdm_hwc_window.c @@ -140,7 +140,6 @@ tdm_hwc_window_set_composition_type(tdm_hwc_window *hwc_window, HWC_WINDOW_FUNC_ENTRY(); TDM_RETURN_VAL_IF_FAIL(composition_type >= TDM_COMPOSITION_NONE, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(composition_type <= TDM_COMPOSITION_CURSOR, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(composition_type != TDM_COMPOSITION_DEVICE_CANDIDATE, TDM_ERROR_INVALID_PARAMETER); _pthread_mutex_lock(&private_display->lock); diff --git a/utests/src/ut_tdm_hwc_window.cpp b/utests/src/ut_tdm_hwc_window.cpp index 9a5c171..ffea35f 100644 --- a/utests/src/ut_tdm_hwc_window.cpp +++ b/utests/src/ut_tdm_hwc_window.cpp @@ -484,8 +484,6 @@ TEST_F(TDMHwcWindow, SetCompositionTypeSuccessful) TEST_F(TDMHwcWindow, SetCompositionTypeFailInvalieCompositionType) { for (int i = 0; i < hwc_count; i++) { - error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_DEVICE_CANDIDATE); - ASSERT_NE(TDM_ERROR_NONE, error); error = tdm_hwc_window_set_composition_type(hwc_wins[i], tdm_hwc_window_composition(TDM_COMPOSITION_NONE-1)); ASSERT_NE(TDM_ERROR_NONE, error); } -- 2.7.4 From 9da2a08b569429675c2071c19fc90e88106aee96 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 8 Jan 2018 10:46:03 +0900 Subject: [PATCH 16/16] package version up to 1.11.2 Change-Id: I7e57059690f019afdefdf3c0d329172b9b41107c --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 895c21e..0a99efd 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %define UTEST_PACKAGE 1 Name: libtdm -Version: 1.11.1 +Version: 1.11.2 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4