From 2484b6ea5e66518ee179e1c780793cbf8b5e885b Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 3 Feb 2017 15:46:46 +0900 Subject: [PATCH 01/16] package version up to 1.6.4 Change-Id: I4977e0ec9ca0a2e4726ee2c7f9b0f8850466fabc --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 8d130e8..8da5446 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %bcond_with utest Name: libtdm -Version: 1.6.3 +Version: 1.6.4 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From f3fbadb25240c816fafded9c4ebbb59b729e71db Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 8 Feb 2017 19:19:32 +0900 Subject: [PATCH 02/16] list: add a new item in the end of a list Change-Id: Id2606821f49de083ab698f201cc9b01bae18328b --- src/tdm_buffer.c | 4 ++-- src/tdm_display.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tdm_buffer.c b/src/tdm_buffer.c index e3f4107..6037dc2 100644 --- a/src/tdm_buffer.c +++ b/src/tdm_buffer.c @@ -136,7 +136,7 @@ tdm_buffer_add_release_handler(tbm_surface_h buffer, func_info->release_func = func; func_info->user_data = user_data; - LIST_ADD(&func_info->link, &buf_info->release_funcs); + LIST_ADDTAIL(&func_info->link, &buf_info->release_funcs); return TDM_ERROR_NONE; } @@ -248,7 +248,7 @@ tdm_buffer_add_destroy_handler(tbm_surface_h buffer, func_info->destroy_func = func; func_info->user_data = user_data; - LIST_ADD(&func_info->link, &buf_info->destroy_funcs); + LIST_ADDTAIL(&func_info->link, &buf_info->destroy_funcs); return TDM_ERROR_NONE; } diff --git a/src/tdm_display.c b/src/tdm_display.c index 53b1c7c..e223161 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -597,9 +597,9 @@ tdm_output_add_change_handler(tdm_output *output, change_handler->owner_tid = syscall(SYS_gettid); if (!tdm_thread_in_display_thread(change_handler->owner_tid)) - LIST_ADD(&change_handler->link, &private_output->change_handler_list_sub); + LIST_ADDTAIL(&change_handler->link, &private_output->change_handler_list_sub); else - LIST_ADD(&change_handler->link, &private_output->change_handler_list_main); + LIST_ADDTAIL(&change_handler->link, &private_output->change_handler_list_main); _pthread_mutex_unlock(&private_display->lock); @@ -1211,7 +1211,7 @@ _tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func, return TDM_ERROR_OUT_OF_MEMORY; } - LIST_ADD(&output_commit_handler->link, &private_output->output_commit_handler_list); + LIST_ADDTAIL(&output_commit_handler->link, &private_output->output_commit_handler_list); output_commit_handler->private_output = private_output; output_commit_handler->func = func; output_commit_handler->user_data = user_data; @@ -2110,7 +2110,7 @@ _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_da if (!private_display->commit_per_vblank) { TDM_GOTO_IF_FAIL(private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT, commit_failed); - LIST_ADD(&layer_commit_handler->link, &private_output->layer_commit_handler_list); + LIST_ADDTAIL(&layer_commit_handler->link, &private_output->layer_commit_handler_list); ret = _tdm_output_commit(private_layer->private_output, 0, _tdm_layer_cb_output_commit, layer_commit_handler); TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); @@ -2126,7 +2126,7 @@ _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_da if (_tdm_layer_commit_possible(private_layer)) { /* add to layer_commit_handler_list */ - LIST_ADD(&layer_commit_handler->link, &private_output->layer_commit_handler_list); + LIST_ADDTAIL(&layer_commit_handler->link, &private_output->layer_commit_handler_list); ret = _tdm_output_commit(private_layer->private_output, 0, NULL, NULL); TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); @@ -2135,7 +2135,7 @@ _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_da TDM_INFO("layer(%p) commit: output", private_layer); } else { /* add to pending_commit_handler_list. It will be commited when a vblank occurs */ - LIST_ADD(&layer_commit_handler->link, &private_output->pending_commit_handler_list); + LIST_ADDTAIL(&layer_commit_handler->link, &private_output->pending_commit_handler_list); if (tdm_debug_module & TDM_DEBUG_COMMIT) TDM_INFO("layer(%p) commit: pending", private_layer); -- 2.7.4 From 612db86a65a50cbddd2682c68783ef5e02e103f4 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 8 Feb 2017 19:51:39 +0900 Subject: [PATCH 03/16] commit: fix the double registration for layer vblank handler Change-Id: I5154539f0b6f0f7656035aff9d54d6178be058e2 --- src/tdm_display.c | 31 ++++++++++++++++++------------- src/tdm_private.h | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/tdm_display.c b/src/tdm_display.c index e223161..762a933 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -991,6 +991,9 @@ tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence, LIST_ADDTAIL(&v->link, &clone_list); } + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("-----------------------------------------"); + _pthread_mutex_unlock(&private_display->lock); LIST_FOR_EACH_ENTRY_SAFE(v, vv, &clone_list, link) { if (tdm_debug_module & TDM_DEBUG_COMMIT) @@ -1002,6 +1005,9 @@ tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence, free(v); } _pthread_mutex_lock(&private_display->lock); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("-----------------------------------------..."); } INTERN void @@ -1881,8 +1887,6 @@ _tdm_layer_committed(tdm_private_layer *private_layer) tdm_private_output *private_output = private_layer->private_output; tdm_private_display *private_display = private_output->private_display; - private_layer->committing = 0; - if (private_display->print_fps) { double curr = tdm_helper_get_time(); private_layer->fps_count++; @@ -1934,18 +1938,20 @@ _tdm_layer_got_output_vblank(tdm_private_output *private_output, unsigned int se private_display = private_output->private_display; - private_output->waiting_vblank = 0; + private_output->layer_waiting_vblank = 0; LIST_INITHEAD(&clone_list); LIST_INITHEAD(&pending_clone_list); LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) { LIST_DEL(&lm->link); + lm->private_layer->committing = 0; LIST_ADDTAIL(&lm->link, &clone_list); } LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) { LIST_DEL(&lm->link); + lm->private_layer->committing = 0; LIST_ADDTAIL(&lm->link, &pending_clone_list); } @@ -1974,11 +1980,13 @@ _tdm_layer_got_output_vblank(tdm_private_output *private_output, unsigned int se TDM_INFO("layer commit: output(%d) commit", private_output->pipe); /* tdm_vblank APIs is for server. it should be called in unlock status*/ - _pthread_mutex_unlock(&private_display->lock); - ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output); - _pthread_mutex_lock(&private_display->lock); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); - private_output->waiting_vblank = 1; + if (!private_output->layer_waiting_vblank) { + _pthread_mutex_unlock(&private_display->lock); + ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output); + _pthread_mutex_lock(&private_display->lock); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); + private_output->layer_waiting_vblank = 1; + } if (tdm_debug_module & TDM_DEBUG_COMMIT) TDM_INFO("layer commit: output(%d) wait vblank", private_output->pipe); @@ -2147,18 +2155,15 @@ _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_da private_output->vblank = tdm_vblank_create(private_display, private_output, NULL); _pthread_mutex_lock(&private_display->lock); TDM_GOTO_IF_FAIL(private_output->vblank != NULL, commit_failed); - - /* to call the frontend's internal vblank handlers before the extern vblank handlers */ - tdm_vblank_set_add_front(private_output->vblank, 1); } - if (!private_output->waiting_vblank) { + if (!private_output->layer_waiting_vblank) { /* tdm_vblank APIs is for server. it should be called in unlock status*/ _pthread_mutex_unlock(&private_display->lock); ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output); _pthread_mutex_lock(&private_display->lock); TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); - private_output->waiting_vblank = 1; + private_output->layer_waiting_vblank = 1; if (tdm_debug_module & TDM_DEBUG_COMMIT) TDM_INFO("layer(%p) commit: wait vblank", private_layer); diff --git a/src/tdm_private.h b/src/tdm_private.h index 0d4cfda..cd7405d 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -206,7 +206,7 @@ struct _tdm_private_output { struct list_head layer_commit_handler_list; struct list_head pending_commit_handler_list; tdm_vblank *vblank; - int waiting_vblank; + int layer_waiting_vblank; /* seperate list for multi-thread*/ struct list_head change_handler_list_main; -- 2.7.4 From a769c97ef85ca359d5bd0c15705ac5eb65d5e078 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 8 Feb 2017 20:23:06 +0900 Subject: [PATCH 04/16] package version up to 1.6.5 Change-Id: I41c28ddc3a78c58e8914ab86530f0c1f526c63c2 --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 8da5446..9e2fba3 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %bcond_with utest Name: libtdm -Version: 1.6.4 +Version: 1.6.5 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From da7ffd3c21144e76ac0a150948cb66d75419d50a Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 8 Feb 2017 12:39:16 +0900 Subject: [PATCH 05/16] vblank: add set_vblank_fps functionality for the given PID Change-Id: I28a8b5ca1e585f68817da6f887aed13f188b64f0 --- client/tdm_client.c | 40 ++++++++++++++ client/tdm_client.h | 20 +++++++ include/tdm.h | 45 ++++++++++++++-- include/tdm_common.h | 1 + protocol/tdm.xml | 16 +++++- src/tdm_monitor_server.c | 62 ++++++++++++++++++++++ src/tdm_private.h | 4 ++ src/tdm_server.c | 134 +++++++++++++++++++++++++++++++++++++++++++++-- src/tdm_vblank.c | 73 ++++++++++++++++++++++++-- tools/tdm_test_client.c | 73 +++++++++++++++++++++++--- 10 files changed, 450 insertions(+), 18 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index c9b312c..bdab4c0 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -86,6 +86,7 @@ struct _tdm_private_client_vblank { struct wl_tdm_vblank *vblank; struct list_head wait_list; + char name[TDM_NAME_LEN]; unsigned int sync; unsigned int fps; int offset; @@ -425,6 +426,25 @@ tdm_client_wait_vblank(tdm_client *client, char *name, return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp); } +tdm_error +tdm_client_set_client_vblank_fps(tdm_client *client, pid_t pid, const char *name, unsigned int fps) +{ + tdm_private_client *private_client = (tdm_private_client*)client; + + TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(pid > 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); + + if (!name) + name = TDM_VBLANK_DEFAULT_NAME; + + wl_tdm_set_client_vblank_fps(private_client->tdm, pid, name, fps); + + wl_display_flush(private_client->display); + + return TDM_ERROR_NONE; +} + tdm_client_output* tdm_client_get_output(tdm_client *client, char *name, tdm_error *error) { @@ -647,6 +667,26 @@ tdm_client_vblank_destroy(tdm_client_vblank *vblank) } tdm_error +tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name) +{ + tdm_private_client_vblank *private_vblank; + + TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER); + + private_vblank = vblank; + + if (!name) + name = TDM_VBLANK_DEFAULT_NAME; + + strncpy(private_vblank->name, name, TDM_NAME_LEN - 1); + private_vblank->name[TDM_NAME_LEN - 1] = '\0'; + + wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name); + + return TDM_ERROR_NONE; +} + +tdm_error tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync) { tdm_private_client_vblank *private_vblank; diff --git a/client/tdm_client.h b/client/tdm_client.h index e7df780..5cb1cce 100644 --- a/client/tdm_client.h +++ b/client/tdm_client.h @@ -138,6 +138,17 @@ tdm_client_wait_vblank(tdm_client *client, char *name, tdm_client_vblank_handler2 func, void *user_data); /** + * @brief Set the client vblank fps for the given PID and name. + * @param[in] client A TDM client object + * @param[in] pid The process ID + * @param[in] name The client vblank name + * @param[in] fps The client vblank fps + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_client_set_client_vblank_fps(tdm_client *client, pid_t pid, const char *name, unsigned int fps); + +/** * @brief Get the client output object which has the given name. * @details * The client output name can be @b 'primary' or @b 'default' to get the main output. @@ -241,6 +252,15 @@ void tdm_client_vblank_destroy(tdm_client_vblank *vblank); /** + * @brief Set the name to the client vblank object + * @param[in] vblank The client vblank object + * @param[in] name The client vblank name + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name); + +/** * @brief Set the sync value to the client vblank object * @details * If sync == 1, the user client vblank handler of #tdm_client_vblank_wait diff --git a/include/tdm.h b/include/tdm.h index 3a066c1..ebb8f4f 100644 --- a/include/tdm.h +++ b/include/tdm.h @@ -903,6 +903,26 @@ void tdm_vblank_destroy(tdm_vblank *vblank); /** + * @brief Set the name to a vblank object + * @details The default name is "unknown" + * @param[in] vblank A vblank object + * @param[in] name vblank name + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_vblank_set_name(tdm_vblank *vblank, const char *name); + +/** + * @brief Get the name for a vblank object + * @details The default name is "unknown" + * @param[in] vblank A vblank object + * @param[out] name vblank name + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +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. * @param[in] vblank A vblank object @@ -913,6 +933,15 @@ tdm_error tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps); /** + * @brief Get the fps for a vblank object + * @param[in] vblank A vblank object + * @param[out] fps over 0 + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_vblank_get_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 @@ -923,6 +952,15 @@ tdm_error tdm_vblank_set_offset(tdm_vblank *vblank, int offset); /** + * @brief Get the offset(milli-second) for a vblank object + * @param[in] vblank A vblank object + * @param[out] offset the offset(milli-second) + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_vblank_get_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 @@ -938,10 +976,11 @@ 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. + * @param[out] enable_fake 1:enable, 0:disable + * @return #TDM_ERROR_NONE if success. Otherwise, error value. */ -unsigned int -tdm_vblank_get_enable_fake(tdm_vblank *vblank); +tdm_error +tdm_vblank_get_enable_fake(tdm_vblank *vblank, unsigned int *enable_fake); /** * @brief Wait for a vblank diff --git a/include/tdm_common.h b/include/tdm_common.h index 3b9f5fa..dc33494 100644 --- a/include/tdm_common.h +++ b/include/tdm_common.h @@ -44,6 +44,7 @@ extern "C" { #define TDM_NAME_LEN 64 #define TDM_PATH_LEN 1024 +#define TDM_VBLANK_DEFAULT_NAME "Unknown" /** * @file tdm_common.h diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 3f98fd1..0a157e0 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -12,13 +12,19 @@ + + + + - - + + + + @@ -61,8 +67,14 @@ + + + + + + diff --git a/src/tdm_monitor_server.c b/src/tdm_monitor_server.c index 0d18743..1916e4a 100644 --- a/src/tdm_monitor_server.c +++ b/src/tdm_monitor_server.c @@ -241,6 +241,56 @@ _tdm_monitor_server_fps(unsigned int pid, char *cwd, int argc, char *argv[], cha } static void +_tdm_monitor_server_vblank_list(unsigned int pid, char *cwd, int argc, char *argv[], + char *reply, int *len, tdm_display *dpy) +{ + tdm_server_get_vblank_list_information(dpy, reply, len); +} + +static void +_tdm_monitor_server_vblank_fps(unsigned int pid, char *cwd, int argc, char *argv[], + char *reply, int *len, tdm_display *dpy) +{ + unsigned int target_pid, fps; + char *arg; + char *end; + char name[TDM_NAME_LEN]; + tdm_error ret; + + if (argc < 3) { + _tdm_monitor_server_usage(argv[0], reply, len); + return; + } + + arg = argv[2]; + target_pid = strtol(arg, &end, 10); + + if (*end == ',') { + arg = end + 1; + end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM); + } else { + strncpy(name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN - 1); + name[TDM_NAME_LEN - 1] = '\0'; + } + + if (*end != '@') { + TDM_SNPRINTF(reply, len, "failed: no fps value\n"); + return; + } + + arg = end + 1; + fps = strtol(arg, &end, 10); + + ret = tdm_server_set_client_vblank_fps(target_pid, name, fps); + if (ret != TDM_ERROR_NONE) { + TDM_SNPRINTF(reply, len, "can't set '%u' fps to '%s' client vblank(PID:%u)\n", fps, name, target_pid); + return; + } + + TDM_SNPRINTF(reply, len, "success: '%u' fps for '%s' client vblank(PID:%u)\n", fps, name, target_pid); +} + +static void _tdm_monitor_server_prop(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy) { tdm_output *output; @@ -446,6 +496,18 @@ static struct { "0 or 1" }, { + "vblank_list", _tdm_monitor_server_vblank_list, + "print the client vblank list", + NULL, + NULL + }, + { + "vblank_fps", _tdm_monitor_server_vblank_fps, + "set the client vblank fps for the given process ID and client vblank name", + "[,]@", + NULL + }, + { "prop", _tdm_monitor_server_prop, "set the property of a output or a layer", "[,]:,", diff --git a/src/tdm_private.h b/src/tdm_private.h index cd7405d..c7a08d8 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -554,6 +554,10 @@ tdm_error tdm_server_init(tdm_private_loop *private_loop); void tdm_server_deinit(tdm_private_loop *private_loop); +tdm_error +tdm_server_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps); +void +tdm_server_get_vblank_list_information(tdm_display *dpy, char *reply, int *len); char * tdm_helper_dump_make_directory(const char *path, char *reply, int *len); diff --git a/src/tdm_server.c b/src/tdm_server.c index 914b1da..bb2a7c3 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -67,6 +67,8 @@ typedef struct _tdm_server_output_info { typedef struct _tdm_server_vblank_info { struct list_head link; + struct list_head valid_link; + tdm_server_output_info *output_info; struct wl_resource *resource; @@ -81,6 +83,7 @@ typedef struct _tdm_server_wait_info { } tdm_server_wait_info; static tdm_private_server *keep_private_server; +static struct list_head valid_vblank_list; static void destroy_wait(tdm_server_wait_info *wait_info); @@ -202,6 +205,8 @@ destroy_vblank_callback(struct wl_resource *resource) } LIST_DEL(&vblank_info->link); + LIST_DEL(&vblank_info->valid_link); + free(vblank_info); } @@ -212,6 +217,14 @@ _tdm_server_vblank_cb_destroy(struct wl_client *client, struct wl_resource *reso } static void +_tdm_server_vblank_cb_set_name(struct wl_client *client, struct wl_resource *resource, const char *name) +{ + tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource); + + tdm_vblank_set_name(vblank_info->vblank, name); +} + +static void _tdm_server_vblank_cb_set_fps(struct wl_client *client, struct wl_resource *resource, uint32_t fps) { tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource); @@ -243,6 +256,7 @@ _tdm_server_vblank_cb_wait_vblank(struct wl_client *client, struct wl_resource * tdm_server_output_info *output_info = vblank_info->output_info; tdm_private_server *private_server = output_info->private_server; tdm_server_wait_info *wait_info; + unsigned int enable_fake = 0; tdm_error ret; TDM_TRACE_COUNT(ServerWaitVBlank, req_id); @@ -263,7 +277,8 @@ _tdm_server_vblank_cb_wait_vblank(struct wl_client *client, struct wl_resource * ret = tdm_vblank_wait(vblank_info->vblank, req_sec, req_usec, interval, _tdm_server_cb_vblank, wait_info); - if (!tdm_vblank_get_enable_fake(vblank_info->vblank) && ret == TDM_ERROR_DPMS_OFF) + tdm_vblank_get_enable_fake(vblank_info->vblank, &enable_fake); + if (!enable_fake && ret == TDM_ERROR_DPMS_OFF) goto wait_failed; TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); @@ -283,6 +298,7 @@ _tdm_server_vblank_cb_wait_vblank_seq(struct wl_client *client, struct wl_resour tdm_server_output_info *output_info = vblank_info->output_info; tdm_private_server *private_server = output_info->private_server; tdm_server_wait_info *wait_info; + unsigned int enable_fake = 0; tdm_error ret; TDM_TRACE_COUNT(ServerWaitVBlank, req_id); @@ -303,7 +319,8 @@ _tdm_server_vblank_cb_wait_vblank_seq(struct wl_client *client, struct wl_resour ret = tdm_vblank_wait_seq(vblank_info->vblank, req_sec, req_usec, sequence, _tdm_server_cb_vblank, wait_info); - if (!tdm_vblank_get_enable_fake(vblank_info->vblank) && ret == TDM_ERROR_DPMS_OFF) + tdm_vblank_get_enable_fake(vblank_info->vblank, &enable_fake); + if (!enable_fake && ret == TDM_ERROR_DPMS_OFF) goto wait_failed; TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); @@ -317,6 +334,7 @@ wait_failed: static const struct wl_tdm_vblank_interface tdm_vblank_implementation = { _tdm_server_vblank_cb_destroy, + _tdm_server_vblank_cb_set_name, _tdm_server_vblank_cb_set_fps, _tdm_server_vblank_cb_set_offset, _tdm_server_vblank_cb_set_enable_fake, @@ -367,6 +385,8 @@ _tdm_server_output_cb_create_vblank(struct wl_client *client, struct wl_resource } LIST_ADDTAIL(&vblank_info->link, &output_info->vblank_list); + LIST_ADDTAIL(&vblank_info->valid_link, &valid_vblank_list); + vblank_info->output_info = output_info; vblank_info->resource = vblank_resource; vblank_info->vblank = vblank; @@ -486,9 +506,20 @@ _tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, con wl_tdm_send_debug_done(resource, message); } +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_server_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); +} + static const struct wl_tdm_interface tdm_implementation = { - _tdm_server_cb_create_output, _tdm_server_cb_debug, + _tdm_server_cb_create_output, + _tdm_server_cb_set_client_vblank_fps, }; static void @@ -538,6 +569,8 @@ tdm_server_init(tdm_private_loop *private_loop) return TDM_ERROR_OUT_OF_MEMORY; } + LIST_INITHEAD(&valid_vblank_list); + private_server->private_loop = private_loop; private_loop->private_server = private_server; keep_private_server = private_server; @@ -569,3 +602,98 @@ tdm_server_deinit(tdm_private_loop *private_loop) private_loop->private_server = NULL; keep_private_server = NULL; } + +INTERN tdm_error +tdm_server_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps) +{ + tdm_server_vblank_info *v; + + TDM_RETURN_VAL_IF_FAIL(pid > 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); + + LIST_FOR_EACH_ENTRY(v, &valid_vblank_list, valid_link) { + struct wl_client *client = wl_resource_get_client(v->resource); + pid_t client_pid = 0; + const char *vblank_name = NULL; + + if (!client) + continue; + + wl_client_get_credentials(client, &client_pid, NULL, NULL); + + if (client_pid != pid) + continue; + + if (name && strncmp(name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN)) { + tdm_vblank_get_name(v->vblank, &vblank_name); + if (strncmp(vblank_name, name, TDM_NAME_LEN)) + continue; + } + + tdm_vblank_set_fps(v->vblank, fps); + } + + return TDM_ERROR_NONE; +} + +static void +_tdm_server_get_process_name(pid_t pid, char *name, unsigned int size) +{ + char proc[TDM_NAME_LEN], pname[TDM_NAME_LEN]; + FILE *h; + size_t len; + + snprintf(proc, TDM_NAME_LEN, "/proc/%d/cmdline", pid); + h = fopen(proc, "r"); + if (!h) + return; + + len = fread(pname, sizeof(char), TDM_NAME_LEN, h); + if (len == 0) { + char *p = strncpy(pname, "NO NAME", sizeof(pname) - 1); + len = p - pname; + } + pname[len - 1] = '\0'; + + strncpy(name, pname, size - 1); + name[size - 1] = '\0'; + + fclose(h); +} + +INTERN void +tdm_server_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) +{ + tdm_server_vblank_info *v; + + TDM_SNPRINTF(reply, len, "[Client Vblank List]\n"); + TDM_SNPRINTF(reply, len, "---------------------------------------------------------------\n"); + TDM_SNPRINTF(reply, len, "name fps offset fake process\n"); + TDM_SNPRINTF(reply, len, "---------------------------------------------------------------\n"); + + LIST_FOR_EACH_ENTRY(v, &valid_vblank_list, valid_link) { + struct wl_client *client = wl_resource_get_client(v->resource); + const char *vbl_name = NULL; + char proc_name[TDM_NAME_LEN]; + unsigned int fps = 0, fake = 0; + int offset = 0; + pid_t pid = 0; + + tdm_vblank_get_name(v->vblank, &vbl_name); + tdm_vblank_get_fps(v->vblank, &fps); + tdm_vblank_get_offset(v->vblank, &offset); + tdm_vblank_get_enable_fake(v->vblank, &fake); + + snprintf(proc_name, TDM_NAME_LEN, "Unknown"); + if (client) { + wl_client_get_credentials(client, &pid, NULL, NULL); + _tdm_server_get_process_name(pid, proc_name, TDM_NAME_LEN); + } + + TDM_SNPRINTF(reply, len, "%-12s %u %d %u %s (pid: %u)\n", + vbl_name, fps, offset, fake, proc_name, pid); + } + + TDM_SNPRINTF(reply, len, "\n"); +} + diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 0e3c1aa..b9ce1ab 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -91,6 +91,7 @@ typedef struct _tdm_private_vblank { unsigned int vrefresh; unsigned int check_HW_or_SW; + char name[TDM_NAME_LEN]; unsigned int fps; int offset; unsigned int enable_fake; @@ -378,6 +379,9 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) private_vblank->check_HW_or_SW = 1; private_vblank->fps = mode->vrefresh; + strncpy(private_vblank->name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN - 1); + private_vblank->name[TDM_NAME_LEN - 1] = '\0'; + LIST_INITHEAD(&private_vblank->HW_wait_list); LIST_INITHEAD(&private_vblank->SW_wait_list); @@ -425,6 +429,38 @@ tdm_vblank_destroy(tdm_vblank *vblank) } EXTERN tdm_error +tdm_vblank_set_name(tdm_vblank *vblank, const char *name) +{ + tdm_private_vblank *private_vblank = vblank; + + TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER); + + if (!name) + name = TDM_VBLANK_DEFAULT_NAME; + + strncpy(private_vblank->name, name, TDM_NAME_LEN - 1); + private_vblank->name[TDM_NAME_LEN - 1] = '\0'; + + if (tdm_debug_module & TDM_DEBUG_VBLANK) + VIN("name(%s)", name); + + return TDM_ERROR_NONE; +} + +EXTERN tdm_error +tdm_vblank_get_name(tdm_vblank *vblank, const char **name) +{ + tdm_private_vblank *private_vblank = vblank; + + TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(name != NULL, TDM_ERROR_INVALID_PARAMETER); + + *name = (const char*)private_vblank->name; + + return TDM_ERROR_NONE; +} + +EXTERN tdm_error tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) { tdm_private_vblank *private_vblank = vblank; @@ -445,6 +481,19 @@ tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) } EXTERN tdm_error +tdm_vblank_get_fps(tdm_vblank *vblank, unsigned int *fps) +{ + tdm_private_vblank *private_vblank = vblank; + + TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(fps != NULL, TDM_ERROR_INVALID_PARAMETER); + + *fps = private_vblank->fps; + + return TDM_ERROR_NONE; +} + +EXTERN tdm_error tdm_vblank_set_offset(tdm_vblank *vblank, int offset) { tdm_private_vblank *private_vblank = vblank; @@ -464,6 +513,19 @@ tdm_vblank_set_offset(tdm_vblank *vblank, int offset) } EXTERN tdm_error +tdm_vblank_get_offset(tdm_vblank *vblank, int *offset) +{ + tdm_private_vblank *private_vblank = vblank; + + TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(offset != NULL, TDM_ERROR_INVALID_PARAMETER); + + *offset = private_vblank->offset; + + return TDM_ERROR_NONE; +} + +EXTERN tdm_error tdm_vblank_set_enable_fake(tdm_vblank *vblank, unsigned int enable_fake) { tdm_private_vblank *private_vblank = vblank; @@ -481,14 +543,17 @@ tdm_vblank_set_enable_fake(tdm_vblank *vblank, unsigned int enable_fake) return TDM_ERROR_NONE; } -EXTERN unsigned int -tdm_vblank_get_enable_fake(tdm_vblank *vblank) +EXTERN tdm_error +tdm_vblank_get_enable_fake(tdm_vblank *vblank, unsigned int *enable_fake) { tdm_private_vblank *private_vblank = vblank; - TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, 0); + TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(enable_fake != NULL, TDM_ERROR_INVALID_PARAMETER); + + *enable_fake = private_vblank->enable_fake; - return private_vblank->enable_fake; + return TDM_ERROR_NONE; } static tdm_error diff --git a/tools/tdm_test_client.c b/tools/tdm_test_client.c index fb371f5..1ec8f93 100644 --- a/tools/tdm_test_client.c +++ b/tools/tdm_test_client.c @@ -45,12 +45,14 @@ #include "tdm_macro.h" typedef struct _tdm_test_client_arg { - char output_name[512]; + char *output_name; int fps; int sync; int interval; int offset; int enable_fake; + int pid; + char *vblank_name; } tdm_test_client_arg; typedef struct _tdm_test_client { @@ -58,6 +60,7 @@ typedef struct _tdm_test_client { int do_query; int do_vblank; + int do_set_fps; int waiting; tdm_client *client; @@ -90,7 +93,8 @@ static struct typestrings typestrs[] = { static struct optstrings optstrs[] = { {OPT_QRY, "qo", "output objects info", "", "primary"}, - {OPT_TST, "v", "vblank test", "[,][@][~][+][*fake]", "primary,0@60~1+0*1"}, + {OPT_TST, "v", "vblank test", "[,][@][~][+][*fake][^vblank_name]", "primary,0@60~1+0*1^test"}, + {OPT_TST, "f", "fps setting test", "[,]@", "@60"}, }; static void @@ -126,7 +130,9 @@ usage(char *app_name) static void parse_arg_qo(tdm_test_client *data, char *arg) { - strtostr(data->args.output_name, 512, arg, TDM_DELIM); + char name[TDM_NAME_LEN]; + strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM); + data->args.output_name = strndup(name, TDM_NAME_LEN); } //"[,][@][~][+][*fake]" @@ -134,8 +140,10 @@ static void parse_arg_v(tdm_test_client *data, char *arg) { char *end = arg; + char name[TDM_NAME_LEN]; - end = strtostr(data->args.output_name, 512, arg, TDM_DELIM); + end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM); + data->args.output_name = strndup(name, TDM_NAME_LEN); if (*end == ',') { arg = end + 1; @@ -161,6 +169,37 @@ parse_arg_v(tdm_test_client *data, char *arg) arg = end + 1; data->args.enable_fake = strtol(arg, &end, 10); } + + if (*end == '^') { + char name[TDM_NAME_LEN]; + arg = end + 1; + end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM); + data->args.vblank_name = strndup(name, TDM_NAME_LEN); + } +} + +//"@" +static void +parse_arg_f(tdm_test_client *data, char *arg) +{ + char *end = arg; + + data->args.pid = strtol(arg, &end, 10); + + if (*end == ',') { + char name[TDM_NAME_LEN]; + arg = end + 1; + end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM); + data->args.vblank_name = strndup(name, TDM_NAME_LEN); + } + + if (*end != '@') { + printf("failed: no fps value\n"); + exit(0); + } + + arg = end + 1; + data->args.fps = strtol(arg, &end, 10); } static void @@ -183,6 +222,9 @@ parse_args(tdm_test_client *data, int argc, char *argv[]) } else if (!strncmp(argv[i] + 1, "v", 1)) { data->do_vblank = 1; parse_arg_v(data, argv[++i]); + } else if (!strncmp(argv[i] + 1, "f", 1)) { + data->do_set_fps = 1; + parse_arg_f(data, argv[++i]); } else { usage(argv[0]); exit(0); @@ -293,6 +335,7 @@ do_vblank(tdm_test_client *data) return; } + tdm_client_vblank_set_name(vblank, data->args.vblank_name); tdm_client_vblank_set_enable_fake(vblank, data->args.enable_fake); tdm_client_vblank_set_sync(vblank, data->args.sync); if (data->args.fps > 0) @@ -350,6 +393,18 @@ done: tdm_client_vblank_destroy(vblank); } +static void +do_set_fps(tdm_test_client *data) +{ + tdm_error error; + + error = tdm_client_set_client_vblank_fps(data->client, data->args.pid, data->args.vblank_name, data->args.fps); + if (error != TDM_ERROR_NONE) { + printf("tdm_client_set_client_vblank_fps failed\n"); + return; + } +} + static tdm_test_client ttc_data; int @@ -371,9 +426,9 @@ main(int argc, char *argv[]) parse_args(data, argc, argv); - printf("sync(%d) fps(%d) interval(%d) offset(%d) enable_fake(%d)\n", + printf("sync(%d) fps(%d) interval(%d) offset(%d) enable_fake(%d) pid(%d)\n", data->args.sync, data->args.fps, data->args.interval, - data->args.offset, data->args.enable_fake); + data->args.offset, data->args.enable_fake, data->args.pid); data->client = tdm_client_create(&error); if (error != TDM_ERROR_NONE) { @@ -385,8 +440,14 @@ main(int argc, char *argv[]) do_query(data); if (data->do_vblank) do_vblank(data); + if (data->do_set_fps) + do_set_fps(data); done: + if (data->args.output_name) + free(data->args.output_name); + if (data->args.vblank_name) + free(data->args.vblank_name); if (data->client) tdm_client_destroy(data->client); -- 2.7.4 From a6d32a99522a904f35e9d5db9d9f5849b520b958 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 9 Feb 2017 14:19:50 +0900 Subject: [PATCH 06/16] display: correct fps count Change-Id: I0cbe1789db617f4c8ffc81735b33628048f2d6a7 --- src/tdm_display.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tdm_display.c b/src/tdm_display.c index 762a933..e468b0d 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -1887,24 +1887,24 @@ _tdm_layer_committed(tdm_private_layer *private_layer) tdm_private_output *private_output = private_layer->private_output; tdm_private_display *private_display = private_output->private_display; + if (!private_layer->waiting_buffer) + return; + if (private_display->print_fps) { double curr = tdm_helper_get_time(); - private_layer->fps_count++; if (private_layer->fps_stamp == 0) { private_layer->fps_stamp = curr; } else if ((curr - private_layer->fps_stamp) > 1.0) { - TDM_INFO("output(%d) layer(%d) fps: %d", private_output->index, private_layer->index, private_layer->fps_count - 1); - private_layer->fps_count = 1; + TDM_INFO("output(%d) layer(%d) fps: %d", private_output->index, private_layer->index, private_layer->fps_count); + private_layer->fps_count = 0; private_layer->fps_stamp = curr; - } + } else + private_layer->fps_count++; } else if (private_layer->fps_stamp != 0) { private_layer->fps_stamp = 0; private_layer->fps_count = 0; } - if (!private_layer->waiting_buffer) - return; - if (private_layer->showing_buffer) { _pthread_mutex_unlock(&private_display->lock); tdm_buffer_unref_backend(private_layer->showing_buffer); -- 2.7.4 From 1743c69979d1f1e726f009d1fdf5793174c1c865 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 9 Feb 2017 20:25:38 +0900 Subject: [PATCH 07/16] buffer: use tdm_private_layer_buffer structure for layer buffers Change-Id: I45b5e8842328da77e9fd78bce811d018f3229431 --- src/tdm.c | 4 +- src/tdm_display.c | 133 +++++++++++++++++++++++++----------------------------- src/tdm_helper.c | 11 +++-- src/tdm_private.h | 12 +++-- 4 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/tdm.c b/src/tdm.c index 041d4c2..924c54c 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -1168,8 +1168,10 @@ tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_s char str[TDM_PATH_LEN]; if (l->usable || l->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO) continue; + if (!l->showing_buffer) + continue; snprintf(str, TDM_PATH_LEN, "layer_%d_%d", o->index, l->index); - tdm_helper_dump_buffer_str(l->showing_buffer, path, str); + tdm_helper_dump_buffer_str(l->showing_buffer->buffer, path, str); } } diff --git a/src/tdm_display.c b/src/tdm_display.c index e468b0d..bae364e 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -105,6 +105,8 @@ static void _tdm_layer_committed(tdm_private_layer *private_layer); static void _tdm_layer_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data); +static void _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data); +static void _tbm_layer_queue_destroy_cb(tbm_surface_queue_h surface_queue, void *data); EXTERN tdm_error tdm_display_get_capabilities(tdm_display *dpy, @@ -1758,6 +1760,7 @@ EXTERN tdm_error tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) { tdm_func_layer *func_layer; + tdm_private_layer_buffer *layer_buffer; LAYER_FUNC_ENTRY(); @@ -1787,6 +1790,13 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) return TDM_ERROR_NOT_IMPLEMENTED; } + layer_buffer = calloc(1, sizeof * layer_buffer); + if (!layer_buffer) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + ret = func_layer->layer_set_buffer(private_layer->layer_backend, buffer); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); @@ -1800,15 +1810,18 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) */ if (private_layer->waiting_buffer) { _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer); + tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); _pthread_mutex_lock(&private_display->lock); + free(private_layer->waiting_buffer); } - private_layer->waiting_buffer = tdm_buffer_ref_backend(buffer); + private_layer->waiting_buffer = layer_buffer; + private_layer->waiting_buffer->buffer = tdm_buffer_ref_backend(buffer); if (tdm_debug_module & TDM_DEBUG_BUFFER) TDM_INFO("layer(%p) waiting_buffer(%p)", - private_layer, private_layer->waiting_buffer); - } + private_layer, private_layer->waiting_buffer->buffer); + } else + free(layer_buffer); _pthread_mutex_unlock(&private_display->lock); @@ -1826,10 +1839,21 @@ tdm_layer_unset_buffer(tdm_layer *layer) func_layer = &private_display->func_layer; + if (private_layer->buffer_queue) { + if (private_layer->waiting_buffer) + tbm_surface_queue_release(private_layer->buffer_queue, private_layer->waiting_buffer->buffer); + if (private_layer->showing_buffer) + tbm_surface_queue_release(private_layer->buffer_queue, private_layer->showing_buffer->buffer); + tbm_surface_queue_remove_acquirable_cb(private_layer->buffer_queue, _tbm_layer_queue_acquirable_cb, layer); + tbm_surface_queue_remove_destroy_cb(private_layer->buffer_queue, _tbm_layer_queue_destroy_cb, layer); + private_layer->buffer_queue = NULL; + } + if (private_layer->waiting_buffer) { _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer); + tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); _pthread_mutex_lock(&private_display->lock); + free(private_layer->waiting_buffer); private_layer->waiting_buffer = NULL; if (tdm_debug_module & TDM_DEBUG_BUFFER) @@ -1839,8 +1863,9 @@ tdm_layer_unset_buffer(tdm_layer *layer) if (private_layer->showing_buffer) { _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->showing_buffer); + tdm_buffer_unref_backend(private_layer->showing_buffer->buffer); _pthread_mutex_lock(&private_display->lock); + free(private_layer->showing_buffer); private_layer->showing_buffer = NULL; if (tdm_debug_module & TDM_DEBUG_BUFFER) @@ -1907,13 +1932,13 @@ _tdm_layer_committed(tdm_private_layer *private_layer) if (private_layer->showing_buffer) { _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->showing_buffer); + tdm_buffer_unref_backend(private_layer->showing_buffer->buffer); _pthread_mutex_lock(&private_display->lock); if (private_layer->buffer_queue) { _pthread_mutex_unlock(&private_display->lock); tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->showing_buffer); + private_layer->showing_buffer->buffer); _pthread_mutex_lock(&private_display->lock); } } @@ -1924,7 +1949,7 @@ _tdm_layer_committed(tdm_private_layer *private_layer) if (tdm_debug_module & TDM_DEBUG_BUFFER) TDM_INFO("layer(%p) waiting_buffer(%p) showing_buffer(%p)", private_layer, private_layer->waiting_buffer, - private_layer->showing_buffer); + (private_layer->showing_buffer) ? private_layer->showing_buffer->buffer : NULL); } static void @@ -2236,7 +2261,7 @@ tdm_layer_get_displaying_buffer(tdm_layer *layer, tdm_error *error) *error = TDM_ERROR_NONE; if (private_layer->showing_buffer) { - buffer = private_layer->showing_buffer; + buffer = private_layer->showing_buffer->buffer; } else { if (error) *error = TDM_ERROR_OPERATION_FAILED; @@ -2256,6 +2281,7 @@ _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data) tdm_layer *layer = data; tdm_func_layer *func_layer; tbm_surface_h surface = NULL; + tdm_private_layer_buffer *layer_buffer; LAYER_FUNC_ENTRY_VOID_RETURN(); _pthread_mutex_lock(&private_display->lock); @@ -2266,11 +2292,19 @@ _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data) return; } + layer_buffer = calloc(1, sizeof * layer_buffer); + if (!layer_buffer) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("alloc failed"); + return; + } + if (TBM_SURFACE_QUEUE_ERROR_NONE != tbm_surface_queue_acquire(private_layer->buffer_queue, &surface) || surface == NULL) { TDM_ERR("layer(%p) tbm_surface_queue_acquire() failed surface:%p", private_layer, surface); _pthread_mutex_unlock(&private_display->lock); + free(layer_buffer); return; } @@ -2279,19 +2313,21 @@ _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data) if (ret == TDM_ERROR_NONE) { if (private_layer->waiting_buffer) { - TDM_DBG("layer(%p) drop waiting_buffer(%p)", private_layer, private_layer->waiting_buffer); + TDM_DBG("layer(%p) drop waiting_buffer(%p)", private_layer, private_layer->waiting_buffer->buffer); _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer); + tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->waiting_buffer); + private_layer->waiting_buffer->buffer); _pthread_mutex_lock(&private_display->lock); + free(private_layer->waiting_buffer); } - private_layer->waiting_buffer = tdm_buffer_ref_backend(surface); + private_layer->waiting_buffer = layer_buffer; + private_layer->waiting_buffer->buffer = tdm_buffer_ref_backend(surface); if (tdm_debug_module & TDM_DEBUG_BUFFER) TDM_INFO("layer(%p) waiting_buffer(%p)", - private_layer, private_layer->waiting_buffer); + private_layer, private_layer->waiting_buffer->buffer); if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) { ret = _tdm_output_commit(private_layer->private_output, 0, NULL, NULL); @@ -2304,7 +2340,8 @@ _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data) } else { TDM_NEVER_GET_HERE(); } - } + } else + free(layer_buffer); _pthread_mutex_unlock(&private_display->lock); } @@ -2321,10 +2358,12 @@ _tbm_layer_queue_destroy_cb(tbm_surface_queue_h surface_queue, void *data) if (private_layer->waiting_buffer) { _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer); + tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->waiting_buffer); + private_layer->waiting_buffer->buffer); _pthread_mutex_lock(&private_display->lock); + free(private_layer->waiting_buffer); + private_layer->waiting_buffer = NULL; } private_layer->buffer_queue = NULL; @@ -2362,9 +2401,10 @@ tdm_layer_set_buffer_queue(tdm_layer *layer, tbm_surface_queue_h buffer_queue) if (private_layer->waiting_buffer) { _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer); + tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->waiting_buffer); + private_layer->waiting_buffer->buffer); + free(private_layer->waiting_buffer); private_layer->waiting_buffer = NULL; _pthread_mutex_lock(&private_display->lock); @@ -2388,58 +2428,7 @@ tdm_layer_set_buffer_queue(tdm_layer *layer, tbm_surface_queue_h buffer_queue) EXTERN tdm_error tdm_layer_unset_buffer_queue(tdm_layer *layer) { - tdm_func_layer *func_layer; - LAYER_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - - if (private_layer->waiting_buffer) { - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer); - tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->waiting_buffer); - private_layer->waiting_buffer = NULL; - _pthread_mutex_lock(&private_display->lock); - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) waiting_buffer(%p)", - private_layer, private_layer->waiting_buffer); - } - - if (private_layer->showing_buffer) { - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->showing_buffer); - tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->showing_buffer); - _pthread_mutex_lock(&private_display->lock); - private_layer->showing_buffer = NULL; - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) showing_buffer(%p)", - private_layer, private_layer->showing_buffer); - } - - tbm_surface_queue_remove_acquirable_cb(private_layer->buffer_queue, _tbm_layer_queue_acquirable_cb, layer); - tbm_surface_queue_remove_destroy_cb(private_layer->buffer_queue, _tbm_layer_queue_destroy_cb, layer); - private_layer->buffer_queue = NULL; - private_layer->usable = 1; - - if (private_layer->usable) - TDM_INFO("layer(%p) now usable", private_layer); - - if (!func_layer->layer_unset_buffer) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_layer->layer_unset_buffer(private_layer->layer_backend); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; + return tdm_layer_unset_buffer(layer); } EXTERN tdm_error diff --git a/src/tdm_helper.c b/src/tdm_helper.c index 06ecba4..4873d12 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -838,14 +838,17 @@ tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len) ret = func_layer->layer_get_info(private_layer->layer_backend, &info); TDM_DBG_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, unlock); - format = tbm_surface_get_format(private_layer->showing_buffer); - tbm_surface_get_info(private_layer->showing_buffer, &buf_info); + if (!private_layer->showing_buffer) + continue; + + format = tbm_surface_get_format(private_layer->showing_buffer->buffer); + tbm_surface_get_info(private_layer->showing_buffer->buffer, &buf_info); if (IS_RGB(format)) size.h = buf_info.planes[0].stride >> 2; else size.h = buf_info.planes[0].stride; - size.v = tbm_surface_get_height(private_layer->showing_buffer); + size.v = tbm_surface_get_height(private_layer->showing_buffer->buffer); if (info.src_config.format) format = (info.src_config.format) ? : format; @@ -854,7 +857,7 @@ tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len) private_layer->index, private_output->index, private_layer->caps.zpos, - private_layer->showing_buffer, FOURCC_STR(format), size.h, size.v, + private_layer->showing_buffer->buffer, FOURCC_STR(format), size.h, size.v, info.src_config.pos.w, info.src_config.pos.h, info.src_config.pos.x, info.src_config.pos.y, info.dst_pos.w, info.dst_pos.h, info.dst_pos.x, info.dst_pos.y, tdm_transform_str(info.transform)); diff --git a/src/tdm_private.h b/src/tdm_private.h index c7a08d8..5631377 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -130,6 +130,7 @@ typedef struct _tdm_private_vblank_handler tdm_private_vblank_handler; typedef struct _tdm_private_output_commit_handler tdm_private_output_commit_handler; typedef struct _tdm_private_layer_commit_handler tdm_private_layer_commit_handler; typedef struct _tdm_private_change_handler tdm_private_change_handler; +typedef struct _tdm_private_layer_buffer tdm_private_layer_buffer; struct _tdm_private_display { pthread_mutex_t lock; @@ -229,9 +230,9 @@ struct _tdm_private_layer { tdm_caps_layer caps; tdm_layer *layer_backend; - tbm_surface_h pending_buffer; - tbm_surface_h waiting_buffer; - tbm_surface_h showing_buffer; + tdm_private_layer_buffer *pending_buffer; + tdm_private_layer_buffer *waiting_buffer; + tdm_private_layer_buffer *showing_buffer; tbm_surface_queue_h buffer_queue; struct list_head capture_list; @@ -358,6 +359,11 @@ struct _tdm_private_change_handler { pid_t owner_tid; }; +struct _tdm_private_layer_buffer { + tbm_surface_h buffer; + struct list_head link; +}; + typedef struct _tdm_buffer_info { tbm_surface_h buffer; -- 2.7.4 From 0f937a6a9a1cf72b6453a59533bef45c38955d9e Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 10 Feb 2017 09:09:35 +0900 Subject: [PATCH 08/16] buffer: correct the buffer management Change-Id: Ica59998a4739b95727e0cf19bad8a5387c795d3a --- src/tdm_display.c | 275 +++++++++++++++++++++++++++++++----------------------- src/tdm_private.h | 8 +- 2 files changed, 166 insertions(+), 117 deletions(-) diff --git a/src/tdm_display.c b/src/tdm_display.c index bae364e..5238471 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -102,7 +102,8 @@ private_output = private_layer->private_output; \ private_display = private_output->private_display -static void _tdm_layer_committed(tdm_private_layer *private_layer); +static void _tdm_layer_free_buffer(tdm_private_layer *private_layer, tdm_private_layer_buffer *layer_buffer); +static void _tdm_layer_committed(tdm_private_layer *private_layer, tdm_private_layer_buffer **committed_buffer); static void _tdm_layer_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data); static void _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data); @@ -994,12 +995,12 @@ tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence, } if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("-----------------------------------------"); + TDM_INFO("----------------------------------------- output(%d) got vblank", private_output->pipe); _pthread_mutex_unlock(&private_display->lock); LIST_FOR_EACH_ENTRY_SAFE(v, vv, &clone_list, link) { if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("output(%d) got vblank: handler(%p)", private_output->pipe, v); + TDM_INFO("handler(%p)", v); if (v->func) v->func(v->private_output, sequence, tv_sec, tv_usec, v->user_data); @@ -1047,10 +1048,16 @@ tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence, return; } + if (tdm_debug_module & TDM_DEBUG_COMMIT) { + TDM_INFO("----------------------------------------- output(%d) committed", private_output->pipe); + TDM_INFO("handler(%p)", output_commit_handler); + } + if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) { /* In case of layer commit, the below will be handled in the layer commit callback */ LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { - _tdm_layer_committed(private_layer); + if (private_layer->committed_buffer) + _tdm_layer_committed(private_layer, &private_layer->committed_buffer); } } @@ -1063,6 +1070,9 @@ tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence, LIST_DEL(&output_commit_handler->link); free(output_commit_handler); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("-----------------------------------------..."); } /* add_front: To distinguish between the user vblank handlers and the layer @@ -1196,6 +1206,8 @@ _tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func, { tdm_func_output *func_output; tdm_private_output_commit_handler *output_commit_handler = NULL; + tdm_private_layer *private_layer = NULL; + OUTPUT_FUNC_ENTRY(); func_output = &private_display->func_output; @@ -1231,7 +1243,19 @@ _tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func, TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("output(%d) backend commit", private_output->pipe); + TDM_INFO("output(%d) backend commit: handle(%p)", private_output->pipe, output_commit_handler); + + LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { + if (!private_layer->waiting_buffer) + continue; + + private_layer->committed_buffer = private_layer->waiting_buffer; + private_layer->waiting_buffer = NULL; + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)", + private_layer, private_layer->waiting_buffer, + private_layer->committed_buffer->buffer); + } return ret; @@ -1756,6 +1780,96 @@ _tdm_layer_dump_buffer(tdm_layer *layer, tbm_surface_h buffer) return; } +static void +_tdm_layer_free_buffer(tdm_private_layer *private_layer, tdm_private_layer_buffer *layer_buffer) +{ + tdm_private_display *private_display; + + if (!layer_buffer) + return; + + private_display = private_layer->private_output->private_display; + + LIST_DEL(&layer_buffer->link); + if (layer_buffer->buffer) { + _pthread_mutex_unlock(&private_display->lock); + tdm_buffer_unref_backend(layer_buffer->buffer); + if (private_layer->buffer_queue) + tbm_surface_queue_release(private_layer->buffer_queue, layer_buffer->buffer); + _pthread_mutex_lock(&private_display->lock); + } + free(layer_buffer); +} + +static void +_tdm_layer_free_all_buffers(tdm_private_layer *private_layer) +{ + tdm_private_output *private_output = private_layer->private_output; + tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL; + struct list_head clone_list; + + LIST_INITHEAD(&clone_list); + + if (private_layer->waiting_buffer) { + _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); + private_layer->waiting_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) waiting_buffer(%p)", + private_layer, private_layer->waiting_buffer); + } + + if (private_layer->committed_buffer) { + _tdm_layer_free_buffer(private_layer, private_layer->committed_buffer); + private_layer->committed_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) committed_buffer(%p)", + private_layer, private_layer->committed_buffer); + } + + if (private_layer->showing_buffer) { + _tdm_layer_free_buffer(private_layer, private_layer->showing_buffer); + private_layer->showing_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) showing_buffer(%p)", + private_layer, private_layer->showing_buffer); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) { + if (lm->private_layer != private_layer) + continue; + LIST_DEL(&lm->link); + LIST_ADDTAIL(&lm->link, &clone_list); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) { + LIST_DEL(&lm->link); + _tdm_layer_free_buffer(private_layer, lm->committed_buffer); + free(lm); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) { + if (lm->private_layer != private_layer) + continue; + LIST_DEL(&lm->link); + LIST_ADDTAIL(&lm->link, &clone_list); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) { + LIST_DEL(&lm->link); + _tdm_layer_free_buffer(private_layer, lm->committed_buffer); + free(lm); + } + + if (private_layer->buffer_queue) { + tbm_surface_queue_remove_acquirable_cb(private_layer->buffer_queue, _tbm_layer_queue_acquirable_cb, private_layer); + tbm_surface_queue_remove_destroy_cb(private_layer->buffer_queue, _tbm_layer_queue_destroy_cb, private_layer); + private_layer->buffer_queue = NULL; + } +} + EXTERN tdm_error tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) { @@ -1790,12 +1904,13 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) return TDM_ERROR_NOT_IMPLEMENTED; } - layer_buffer = calloc(1, sizeof * layer_buffer); + layer_buffer = calloc(1, sizeof(tdm_private_layer_buffer)); if (!layer_buffer) { _pthread_mutex_unlock(&private_display->lock); TDM_ERR("alloc failed"); return TDM_ERROR_OUT_OF_MEMORY; } + LIST_INITHEAD(&layer_buffer->link); ret = func_layer->layer_set_buffer(private_layer->layer_backend, buffer); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); @@ -1805,15 +1920,8 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) _tdm_layer_dump_buffer(layer, buffer); if (ret == TDM_ERROR_NONE) { - /* FIXME: should save to pending_buffer first. And after committing - * successfully, need to move to waiting_buffer. - */ - if (private_layer->waiting_buffer) { - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); - _pthread_mutex_lock(&private_display->lock); - free(private_layer->waiting_buffer); - } + if (private_layer->waiting_buffer) + _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); private_layer->waiting_buffer = layer_buffer; private_layer->waiting_buffer->buffer = tdm_buffer_ref_backend(buffer); @@ -1821,7 +1929,7 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) TDM_INFO("layer(%p) waiting_buffer(%p)", private_layer, private_layer->waiting_buffer->buffer); } else - free(layer_buffer); + _tdm_layer_free_buffer(private_layer, layer_buffer); _pthread_mutex_unlock(&private_display->lock); @@ -1831,7 +1939,6 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) EXTERN tdm_error tdm_layer_unset_buffer(tdm_layer *layer) { - tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL; tdm_func_layer *func_layer; LAYER_FUNC_ENTRY(); @@ -1839,53 +1946,7 @@ tdm_layer_unset_buffer(tdm_layer *layer) func_layer = &private_display->func_layer; - if (private_layer->buffer_queue) { - if (private_layer->waiting_buffer) - tbm_surface_queue_release(private_layer->buffer_queue, private_layer->waiting_buffer->buffer); - if (private_layer->showing_buffer) - tbm_surface_queue_release(private_layer->buffer_queue, private_layer->showing_buffer->buffer); - tbm_surface_queue_remove_acquirable_cb(private_layer->buffer_queue, _tbm_layer_queue_acquirable_cb, layer); - tbm_surface_queue_remove_destroy_cb(private_layer->buffer_queue, _tbm_layer_queue_destroy_cb, layer); - private_layer->buffer_queue = NULL; - } - - if (private_layer->waiting_buffer) { - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); - _pthread_mutex_lock(&private_display->lock); - free(private_layer->waiting_buffer); - private_layer->waiting_buffer = NULL; - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) waiting_buffer(%p)", - private_layer, private_layer->waiting_buffer); - } - - if (private_layer->showing_buffer) { - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->showing_buffer->buffer); - _pthread_mutex_lock(&private_display->lock); - free(private_layer->showing_buffer); - private_layer->showing_buffer = NULL; - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) showing_buffer(%p)", - private_layer, private_layer->showing_buffer); - } - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) { - if (lm->private_layer != private_layer) - continue; - LIST_DEL(&lm->link); - free(lm); - } - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) { - if (lm->private_layer != private_layer) - continue; - LIST_DEL(&lm->link); - free(lm); - } + _tdm_layer_free_all_buffers(private_layer); private_layer->usable = 1; @@ -1907,14 +1968,11 @@ tdm_layer_unset_buffer(tdm_layer *layer) } static void -_tdm_layer_committed(tdm_private_layer *private_layer) +_tdm_layer_committed(tdm_private_layer *private_layer, tdm_private_layer_buffer **committed_buffer) { tdm_private_output *private_output = private_layer->private_output; tdm_private_display *private_display = private_output->private_display; - if (!private_layer->waiting_buffer) - return; - if (private_display->print_fps) { double curr = tdm_helper_get_time(); if (private_layer->fps_stamp == 0) { @@ -1930,25 +1988,15 @@ _tdm_layer_committed(tdm_private_layer *private_layer) private_layer->fps_count = 0; } - if (private_layer->showing_buffer) { - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->showing_buffer->buffer); - _pthread_mutex_lock(&private_display->lock); - - if (private_layer->buffer_queue) { - _pthread_mutex_unlock(&private_display->lock); - tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->showing_buffer->buffer); - _pthread_mutex_lock(&private_display->lock); - } - } + if (private_layer->showing_buffer) + _tdm_layer_free_buffer(private_layer, private_layer->showing_buffer); - private_layer->showing_buffer = private_layer->waiting_buffer; - private_layer->waiting_buffer = NULL; + private_layer->showing_buffer = *committed_buffer; + *committed_buffer = NULL; if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) waiting_buffer(%p) showing_buffer(%p)", - private_layer, private_layer->waiting_buffer, + TDM_INFO("layer(%p) committed_buffer(%p) showing_buffer(%p)", + private_layer, *committed_buffer, (private_layer->showing_buffer) ? private_layer->showing_buffer->buffer : NULL); } @@ -1982,14 +2030,17 @@ _tdm_layer_got_output_vblank(tdm_private_output *private_output, unsigned int se LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) { if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) committed. handle(%p)", lm->private_layer, (lm)?:NULL); + TDM_INFO("layer(%p) committed. handle(%p) commited_buffer(%p)", + lm->private_layer, lm, (lm->committed_buffer) ? lm->committed_buffer->buffer : NULL); - _tdm_layer_committed(lm->private_layer); + LIST_DEL(&lm->link); + _tdm_layer_committed(lm->private_layer, &lm->committed_buffer); _pthread_mutex_unlock(&private_display->lock); if (lm->func) lm->func(lm->private_layer, sequence, tv_sec, tv_usec, lm->user_data); _pthread_mutex_lock(&private_display->lock); - LIST_DEL(&lm->link); + if (lm->committed_buffer) + _tdm_layer_free_buffer(lm->private_layer, lm->committed_buffer); free(lm); } @@ -2025,6 +2076,7 @@ _tdm_layer_got_output_vblank(tdm_private_output *private_output, unsigned int se wait_failed: LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &pending_clone_list, link) { LIST_DEL(&lm->link); + _tdm_layer_free_buffer(lm->private_layer, lm->committed_buffer); free(lm); } return; @@ -2059,11 +2111,11 @@ _tdm_layer_cb_output_commit(tdm_output *output, unsigned int sequence, if (tdm_debug_module & TDM_DEBUG_COMMIT) TDM_INFO("layer(%p) commit: output(%d) committed. handle(%p)", - private_layer, private_output->pipe, (layer_commit_handler)?:NULL); + private_layer, private_output->pipe, layer_commit_handler); _pthread_mutex_lock(&private_display->lock); - _tdm_layer_committed(private_layer); + _tdm_layer_committed(private_layer, &layer_commit_handler->committed_buffer); if (layer_commit_handler->func) { _pthread_mutex_unlock(&private_display->lock); @@ -2140,6 +2192,14 @@ _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_da layer_commit_handler->func = func; layer_commit_handler->user_data = user_data; + layer_commit_handler->committed_buffer = private_layer->waiting_buffer; + private_layer->waiting_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)", + private_layer, private_layer->waiting_buffer, + (layer_commit_handler->committed_buffer) ? layer_commit_handler->committed_buffer->buffer : NULL); + if (!private_display->commit_per_vblank) { TDM_GOTO_IF_FAIL(private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT, commit_failed); @@ -2160,7 +2220,6 @@ _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_da if (_tdm_layer_commit_possible(private_layer)) { /* add to layer_commit_handler_list */ LIST_ADDTAIL(&layer_commit_handler->link, &private_output->layer_commit_handler_list); - ret = _tdm_output_commit(private_layer->private_output, 0, NULL, NULL); TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); @@ -2199,6 +2258,7 @@ _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_da commit_failed: if (layer_commit_handler) { + private_layer->waiting_buffer = layer_commit_handler->committed_buffer; LIST_DEL(&layer_commit_handler->link); free(layer_commit_handler); } @@ -2292,12 +2352,13 @@ _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data) return; } - layer_buffer = calloc(1, sizeof * layer_buffer); + layer_buffer = calloc(1, sizeof(tdm_private_layer_buffer)); if (!layer_buffer) { _pthread_mutex_unlock(&private_display->lock); TDM_ERR("alloc failed"); return; } + LIST_INITHEAD(&layer_buffer->link); if (TBM_SURFACE_QUEUE_ERROR_NONE != tbm_surface_queue_acquire(private_layer->buffer_queue, &surface) || surface == NULL) { @@ -2314,12 +2375,7 @@ _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data) if (ret == TDM_ERROR_NONE) { if (private_layer->waiting_buffer) { TDM_DBG("layer(%p) drop waiting_buffer(%p)", private_layer, private_layer->waiting_buffer->buffer); - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); - tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->waiting_buffer->buffer); - _pthread_mutex_lock(&private_display->lock); - free(private_layer->waiting_buffer); + _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); } private_layer->waiting_buffer = layer_buffer; @@ -2341,7 +2397,7 @@ _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data) TDM_NEVER_GET_HERE(); } } else - free(layer_buffer); + _tdm_layer_free_buffer(private_layer, layer_buffer); _pthread_mutex_unlock(&private_display->lock); } @@ -2356,18 +2412,10 @@ _tbm_layer_queue_destroy_cb(tbm_surface_queue_h surface_queue, void *data) _pthread_mutex_lock(&private_display->lock); - if (private_layer->waiting_buffer) { - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); - tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->waiting_buffer->buffer); - _pthread_mutex_lock(&private_display->lock); - free(private_layer->waiting_buffer); - private_layer->waiting_buffer = NULL; - } - private_layer->buffer_queue = NULL; + _tdm_layer_free_all_buffers(private_layer); + _pthread_mutex_unlock(&private_display->lock); } @@ -2400,13 +2448,8 @@ tdm_layer_set_buffer_queue(tdm_layer *layer, tbm_surface_queue_h buffer_queue) } if (private_layer->waiting_buffer) { - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(private_layer->waiting_buffer->buffer); - tbm_surface_queue_release(private_layer->buffer_queue, - private_layer->waiting_buffer->buffer); - free(private_layer->waiting_buffer); + _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); private_layer->waiting_buffer = NULL; - _pthread_mutex_lock(&private_display->lock); if (tdm_debug_module & TDM_DEBUG_BUFFER) TDM_INFO("layer(%p) waiting_buffer(%p)", @@ -2416,10 +2459,10 @@ tdm_layer_set_buffer_queue(tdm_layer *layer, tbm_surface_queue_h buffer_queue) private_layer->buffer_queue = buffer_queue; tbm_surface_queue_add_acquirable_cb(private_layer->buffer_queue, _tbm_layer_queue_acquirable_cb, - layer); + private_layer); tbm_surface_queue_add_destroy_cb(private_layer->buffer_queue, _tbm_layer_queue_destroy_cb, - layer); + private_layer); _pthread_mutex_unlock(&private_display->lock); return ret; diff --git a/src/tdm_private.h b/src/tdm_private.h index 5631377..3e64429 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -230,8 +230,12 @@ struct _tdm_private_layer { tdm_caps_layer caps; tdm_layer *layer_backend; - tdm_private_layer_buffer *pending_buffer; + /* When a buffer is set to a layer, it will be stored to waiting_buffer. + * And when a layer is committed, it will be moved to committed_buffer. + * Finally when a commit handler is called, it will be moved to showing_buffer. + */ tdm_private_layer_buffer *waiting_buffer; + tdm_private_layer_buffer *committed_buffer; /* for output_commit */ tdm_private_layer_buffer *showing_buffer; tbm_surface_queue_h buffer_queue; @@ -347,6 +351,8 @@ struct _tdm_private_layer_commit_handler { tdm_private_layer *private_layer; tdm_layer_commit_handler func; void *user_data; + + tdm_private_layer_buffer *committed_buffer; /* for layer_commit */ }; struct _tdm_private_change_handler { -- 2.7.4 From da433679e3c965986e74badcb4f5ac175a05eede Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 10 Feb 2017 14:32:35 +0900 Subject: [PATCH 09/16] display: separate output & layer part from display tdm_display.c had more than 2000 lines. To increase readability, separate output & layer part from display Change-Id: I06493e50fbd931a006bef0cf402f02fb7f3d4a0e --- src/Makefile.am | 2 + src/tdm_display.c | 2164 ----------------------------------------------------- src/tdm_layer.c | 1086 +++++++++++++++++++++++++++ src/tdm_output.c | 1166 +++++++++++++++++++++++++++++ src/tdm_private.h | 4 + 5 files changed, 2258 insertions(+), 2164 deletions(-) create mode 100644 src/tdm_layer.c create mode 100644 src/tdm_output.c diff --git a/src/Makefile.am b/src/Makefile.am index 2d6f458..87169ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,6 +20,8 @@ libtdm_la_SOURCES = \ tdm_helper.c \ tdm_buffer.c \ tdm_display.c \ + tdm_output.c \ + tdm_layer.c \ tdm_pp.c \ tdm_capture.c \ tdm_monitor_server.c \ diff --git a/src/tdm_display.c b/src/tdm_display.c index 5238471..0e3aadc 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -56,59 +56,6 @@ TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \ private_display = (tdm_private_display*)dpy; -#define OUTPUT_FUNC_ENTRY() \ - tdm_private_display *private_display; \ - tdm_private_output *private_output; \ - tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ - TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); \ - private_output = (tdm_private_output*)output; \ - private_display = private_output->private_display - -#define OUTPUT_FUNC_ENTRY_ERROR() \ - tdm_private_display *private_display; \ - tdm_private_output *private_output; \ - tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ - TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(output != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \ - private_output = (tdm_private_output*)output; \ - private_display = private_output->private_display - -#define LAYER_FUNC_ENTRY() \ - tdm_private_display *private_display; \ - tdm_private_output *private_output; \ - tdm_private_layer *private_layer; \ - tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ - TDM_RETURN_VAL_IF_FAIL(layer != NULL, TDM_ERROR_INVALID_PARAMETER); \ - private_layer = (tdm_private_layer*)layer; \ - private_output = private_layer->private_output; \ - private_display = private_output->private_display - -#define LAYER_FUNC_ENTRY_ERROR() \ - tdm_private_display *private_display; \ - tdm_private_output *private_output; \ - tdm_private_layer *private_layer; \ - tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ - TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(layer != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \ - private_layer = (tdm_private_layer*)layer; \ - private_output = private_layer->private_output; \ - private_display = private_output->private_display - -#define LAYER_FUNC_ENTRY_VOID_RETURN() \ - tdm_private_display *private_display; \ - tdm_private_output *private_output; \ - tdm_private_layer *private_layer; \ - tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ - TDM_RETURN_IF_FAIL(layer != NULL); \ - private_layer = (tdm_private_layer*)layer; \ - private_output = private_layer->private_output; \ - private_display = private_output->private_display - -static void _tdm_layer_free_buffer(tdm_private_layer *private_layer, tdm_private_layer_buffer *layer_buffer); -static void _tdm_layer_committed(tdm_private_layer *private_layer, tdm_private_layer_buffer **committed_buffer); -static void _tdm_layer_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence, - unsigned int tv_sec, unsigned int tv_usec, void *user_data); -static void _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data); -static void _tbm_layer_queue_destroy_cb(tbm_surface_queue_h surface_queue, void *data); - EXTERN tdm_error tdm_display_get_capabilities(tdm_display *dpy, tdm_display_capability *capabilities) @@ -446,2114 +393,3 @@ tdm_display_create_pp(tdm_display *dpy, tdm_error *error) return pp; } - -EXTERN tdm_error -tdm_output_get_model_info(tdm_output *output, const char **maker, - const char **model, const char **name) -{ - OUTPUT_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - if (maker) - *maker = private_output->caps.maker; - if (model) - *model = private_output->caps.model; - if (name) - *name = private_output->caps.name; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_capabilities(tdm_output *output, tdm_output_capability *capabilities) -{ - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *capabilities = private_output->caps.capabilities; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_conn_status(tdm_output *output, tdm_output_conn_status *status) -{ - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *status = private_output->caps.status; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -static unsigned int -_tdm_output_used_layer_count(tdm_private_output *private_output) -{ - tdm_private_layer *private_layer = NULL; - unsigned int count = 0; - - LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { - if (!private_layer->usable) - count++; - } - - return count; -} - -static void -_tdm_output_update(tdm_output *output_backend, void *user_data) -{ - tdm_private_display *private_display; - tdm_private_output *private_output = user_data; - tdm_error ret; - - TDM_RETURN_IF_FAIL(private_output); - - private_display = private_output->private_display; - - ret = tdm_display_update_output(private_display, output_backend, private_output->pipe); - TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); -} - -INTERN void -tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status, - void *user_data) -{ - tdm_private_display *private_display; - tdm_private_output *private_output = user_data; - tdm_value value; - - TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); - TDM_RETURN_IF_FAIL(private_output); - - private_display = private_output->private_display; - - if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { - tdm_thread_cb_output_status output_status; - tdm_error ret; - - _tdm_output_update(output_backend, user_data); - - output_status.base.type = TDM_THREAD_CB_OUTPUT_STATUS; - output_status.base.length = sizeof output_status; - output_status.output_stamp = private_output->stamp; - output_status.status = status; - output_status.user_data = user_data; - - value.u32 = status; - tdm_output_call_change_handler_internal(private_output, - &private_output->change_handler_list_sub, - TDM_OUTPUT_CHANGE_CONNECTION, - value, 0); - - ret = tdm_thread_send_cb(private_display->private_loop, &output_status.base); - TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - - return; - } - - if (!tdm_thread_is_running()) - _tdm_output_update(output_backend, user_data); - - value.u32 = status; - tdm_output_call_change_handler_internal(private_output, - &private_output->change_handler_list_main, - TDM_OUTPUT_CHANGE_CONNECTION, - value, 0); -} - -EXTERN tdm_error -tdm_output_add_change_handler(tdm_output *output, - tdm_output_change_handler func, - void *user_data) -{ - tdm_private_change_handler *change_handler; - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); - - pthread_mutex_lock(&private_display->lock); - - change_handler = calloc(1, sizeof(tdm_private_change_handler)); - if (!change_handler) { - TDM_ERR("failed: alloc memory"); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_OUT_OF_MEMORY; - } - - change_handler->private_output = private_output; - change_handler->func = func; - change_handler->user_data = user_data; - change_handler->owner_tid = syscall(SYS_gettid); - - if (!tdm_thread_in_display_thread(change_handler->owner_tid)) - LIST_ADDTAIL(&change_handler->link, &private_output->change_handler_list_sub); - else - LIST_ADDTAIL(&change_handler->link, &private_output->change_handler_list_main); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN void -tdm_output_remove_change_handler(tdm_output *output, - tdm_output_change_handler func, - void *user_data) -{ - tdm_private_display *private_display; - tdm_private_output *private_output; - tdm_private_change_handler *h = NULL, *hh = NULL; - - TDM_RETURN_IF_FAIL(output != NULL); - TDM_RETURN_IF_FAIL(func != NULL); - - private_output = (tdm_private_output*)output; - private_display = private_output->private_display; - - _pthread_mutex_lock(&private_display->lock); - - LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) { - if (h->func != func || h->user_data != user_data) - continue; - - LIST_DEL(&h->link); - free(h); - - _pthread_mutex_unlock(&private_display->lock); - - return; - } - - LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) { - if (h->func != func || h->user_data != user_data) - continue; - - LIST_DEL(&h->link); - free(h); - - _pthread_mutex_unlock(&private_display->lock); - - return; - } - - _pthread_mutex_unlock(&private_display->lock); -} - -EXTERN tdm_error -tdm_output_get_output_type(tdm_output *output, tdm_output_type *type) -{ - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(type != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *type = private_output->caps.type; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_layer_count(tdm_output *output, int *count) -{ - tdm_private_layer *private_layer = NULL; - - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *count = 0; - LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) - (*count)++; - if (*count == 0) { - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_NONE; - } - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - - -EXTERN tdm_layer * -tdm_output_get_layer(tdm_output *output, int index, tdm_error *error) -{ - tdm_private_layer *private_layer = NULL; - - OUTPUT_FUNC_ENTRY_ERROR(); - - _pthread_mutex_lock(&private_display->lock); - - if (error) - *error = TDM_ERROR_NONE; - - LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { - if (private_layer->index == index) { - _pthread_mutex_unlock(&private_display->lock); - return private_layer; - } - } - - _pthread_mutex_unlock(&private_display->lock); - - return NULL; -} - -EXTERN tdm_error -tdm_output_get_available_properties(tdm_output *output, const tdm_prop **props, - int *count) -{ - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *props = (const tdm_prop *)private_output->caps.props; - *count = private_output->caps.prop_count; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_available_modes(tdm_output *output, - const tdm_output_mode **modes, int *count) -{ - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *modes = (const tdm_output_mode *)private_output->caps.modes; - *count = private_output->caps.mode_count; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_available_size(tdm_output *output, int *min_w, int *min_h, - int *max_w, int *max_h, int *preferred_align) -{ - OUTPUT_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - if (min_w) - *min_w = TDM_FRONT_VALUE(private_output->caps.min_w); - if (min_h) - *min_h = TDM_FRONT_VALUE(private_output->caps.min_h); - if (max_w) - *max_w = TDM_FRONT_VALUE(private_output->caps.max_w); - if (max_h) - *max_h = TDM_FRONT_VALUE(private_output->caps.max_h); - if (preferred_align) - *preferred_align = TDM_FRONT_VALUE(private_output->caps.preferred_align); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_cursor_available_size(tdm_output *output, int *min_w, int *min_h, - int *max_w, int *max_h, int *preferred_align) -{ - OUTPUT_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - if (!tdm_display_check_module_abi(private_display, 1, 5)) { - - if (min_w) - *min_w = -1; - if (min_h) - *min_h = -1; - if (max_w) - *max_w = -1; - if (max_h) - *max_h = -1; - if (preferred_align) - *preferred_align = -1; - - _pthread_mutex_unlock(&private_display->lock); - - return TDM_ERROR_BAD_MODULE; - } - - if (min_w) - *min_w = TDM_FRONT_VALUE(private_output->caps.cursor_min_w); - if (min_h) - *min_h = TDM_FRONT_VALUE(private_output->caps.cursor_min_h); - if (max_w) - *max_w = TDM_FRONT_VALUE(private_output->caps.cursor_max_w); - if (max_h) - *max_h = TDM_FRONT_VALUE(private_output->caps.cursor_max_h); - if (preferred_align) - *preferred_align = TDM_FRONT_VALUE(private_output->caps.cursor_preferred_align); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_physical_size(tdm_output *output, unsigned int *mmWidth, - unsigned int *mmHeight) -{ - OUTPUT_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - if (mmWidth) - *mmWidth = private_output->caps.mmWidth; - if (mmHeight) - *mmHeight = private_output->caps.mmHeight; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_subpixel(tdm_output *output, unsigned int *subpixel) -{ - OUTPUT_FUNC_ENTRY(); - TDM_RETURN_VAL_IF_FAIL(subpixel != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *subpixel = private_output->caps.subpixel; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_pipe(tdm_output *output, unsigned int *pipe) -{ - OUTPUT_FUNC_ENTRY(); - TDM_RETURN_VAL_IF_FAIL(pipe != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *pipe = private_output->pipe; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_primary_index(tdm_output *output, int *index) -{ - tdm_private_layer *private_layer = NULL; - - OUTPUT_FUNC_ENTRY(); - TDM_RETURN_VAL_IF_FAIL(index != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { - if (private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_PRIMARY) { - *index = private_layer->index; - break; - } - } - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_set_property(tdm_output *output, unsigned int id, tdm_value value) -{ - tdm_func_output *func_output; - OUTPUT_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - func_output = &private_display->func_output; - - if (!func_output->output_set_property) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_output->output_set_property(private_output->output_backend, id, - value); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value) -{ - tdm_func_output *func_output; - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(value != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - func_output = &private_display->func_output; - - if (!func_output->output_get_property) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_output->output_get_property(private_output->output_backend, id, - value); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -INTERN void -tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence, - unsigned int tv_sec, unsigned int tv_usec, void *user_data) -{ - tdm_private_vblank_handler *vblank_handler = user_data; - tdm_private_vblank_handler *v = NULL, *vv = NULL; - tdm_private_output *private_output; - tdm_private_display *private_display; - struct list_head clone_list; - int interval, sync; - pid_t tid = syscall(SYS_gettid); - - TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); - TDM_RETURN_IF_FAIL(vblank_handler); - - private_output = vblank_handler->private_output; - private_display = private_output->private_display; - - if (vblank_handler->owner_tid != tid) { - tdm_thread_cb_output_vblank output_vblank; - tdm_error ret; - - output_vblank.base.type = TDM_THREAD_CB_OUTPUT_VBLANK; - output_vblank.base.length = sizeof output_vblank; - output_vblank.output_stamp = vblank_handler->private_output->stamp; - output_vblank.sequence = sequence; - output_vblank.tv_sec = tv_sec; - output_vblank.tv_usec = tv_usec; - output_vblank.user_data = user_data; - - ret = tdm_thread_send_cb(private_display->private_loop, &output_vblank.base); - TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - - return; - } - - if (vblank_handler->owner_tid != tid) - TDM_NEVER_GET_HERE(); - - interval = vblank_handler->interval; - sync = vblank_handler->sync; - - LIST_INITHEAD(&clone_list); - - LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) { - if (v->interval != interval || v->sync != sync || v->owner_tid != tid) - continue; - - LIST_DEL(&v->link); - LIST_ADDTAIL(&v->link, &clone_list); - } - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("----------------------------------------- output(%d) got vblank", private_output->pipe); - - _pthread_mutex_unlock(&private_display->lock); - LIST_FOR_EACH_ENTRY_SAFE(v, vv, &clone_list, link) { - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("handler(%p)", v); - - if (v->func) - v->func(v->private_output, sequence, tv_sec, tv_usec, v->user_data); - LIST_DEL(&v->link); - free(v); - } - _pthread_mutex_lock(&private_display->lock); - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("-----------------------------------------..."); -} - -INTERN void -tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence, - unsigned int tv_sec, unsigned int tv_usec, void *user_data) -{ - tdm_private_output_commit_handler *output_commit_handler = user_data; - tdm_private_display *private_display; - tdm_private_output *private_output; - tdm_private_layer *private_layer = NULL; - - TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); - - if (!output_commit_handler) - return; - - private_output = output_commit_handler->private_output; - private_display = private_output->private_display; - - if (output_commit_handler->owner_tid != syscall(SYS_gettid)) { - tdm_thread_cb_output_commit output_commit; - tdm_error ret; - - output_commit.base.type = TDM_THREAD_CB_OUTPUT_COMMIT; - output_commit.base.length = sizeof output_commit; - output_commit.output_stamp = private_output->stamp; - output_commit.sequence = sequence; - output_commit.tv_sec = tv_sec; - output_commit.tv_usec = tv_usec; - output_commit.user_data = user_data; - - ret = tdm_thread_send_cb(private_display->private_loop, &output_commit.base); - TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - - return; - } - - if (tdm_debug_module & TDM_DEBUG_COMMIT) { - TDM_INFO("----------------------------------------- output(%d) committed", private_output->pipe); - TDM_INFO("handler(%p)", output_commit_handler); - } - - if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) { - /* In case of layer commit, the below will be handled in the layer commit callback */ - LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { - if (private_layer->committed_buffer) - _tdm_layer_committed(private_layer, &private_layer->committed_buffer); - } - } - - if (output_commit_handler->func) { - _pthread_mutex_unlock(&private_display->lock); - output_commit_handler->func(private_output, sequence, - tv_sec, tv_usec, output_commit_handler->user_data); - _pthread_mutex_lock(&private_display->lock); - } - - LIST_DEL(&output_commit_handler->link); - free(output_commit_handler); - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("-----------------------------------------..."); -} - -/* add_front: To distinguish between the user vblank handlers and the layer - * commit vblank handlers. The layer commit handlers will be called - * before calling the user vblank handlers. - */ -static tdm_error -_tdm_output_wait_vblank(tdm_output *output, int interval, int sync, - tdm_output_vblank_handler func, void *user_data, - unsigned int add_front) -{ - tdm_func_output *func_output; - tdm_private_vblank_handler *vblank_handler = NULL, *v = NULL; - unsigned int skip_request = 0; - pid_t tid = syscall(SYS_gettid); - - OUTPUT_FUNC_ENTRY(); - - func_output = &private_display->func_output; - - /* interval SHOULD be at least 1 */ - if (interval <= 0) - interval = 1; - - if (!func_output->output_wait_vblank) { - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - if (!private_output->regist_vblank_cb) { - private_output->regist_vblank_cb = 1; - ret = func_output->output_set_vblank_handler(private_output->output_backend, - tdm_output_cb_vblank); - } - - vblank_handler = calloc(1, sizeof(tdm_private_vblank_handler)); - if (!vblank_handler) { - TDM_ERR("failed: alloc memory"); - return TDM_ERROR_OUT_OF_MEMORY; - } - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("output(%d) wait_vblank: handler(%p)", private_output->pipe, vblank_handler); - - LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) { - if (v->interval == interval && v->sync == sync && v->owner_tid == tid) { - skip_request = 1; - break; - } - } - - if (add_front) - LIST_ADD(&vblank_handler->link, &private_output->vblank_handler_list); - else - LIST_ADDTAIL(&vblank_handler->link, &private_output->vblank_handler_list); - - vblank_handler->private_output = private_output; - vblank_handler->interval = interval; - vblank_handler->sync = sync; - vblank_handler->func = func; - vblank_handler->user_data = user_data; - vblank_handler->owner_tid = tid; - - /* If there is the previous request, we can skip to call output_wait_vblank() */ - if (!skip_request) { - ret = func_output->output_wait_vblank(private_output->output_backend, interval, - sync, vblank_handler); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("output(%d) backend wait_vblank", private_output->pipe); - } - - return ret; - -wait_failed: - if (vblank_handler) { - LIST_DEL(&vblank_handler->link); - free(vblank_handler); - } - return ret; -} - -EXTERN tdm_error -tdm_output_wait_vblank(tdm_output *output, int interval, int sync, - tdm_output_vblank_handler func, void *user_data) -{ - OUTPUT_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { - TDM_WRN("output(%d) dpms: %s", private_output->pipe, - tdm_dpms_str(private_output->current_dpms_value)); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_DPMS_OFF; - } - - ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 0); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_wait_vblank_add_front(tdm_output *output, int interval, int sync, - tdm_output_vblank_handler func, void *user_data) -{ - OUTPUT_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { - TDM_WRN("output(%d) dpms: %s", private_output->pipe, - tdm_dpms_str(private_output->current_dpms_value)); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_DPMS_OFF; - } - - ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 1); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -static tdm_error -_tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func, - void *user_data) -{ - tdm_func_output *func_output; - tdm_private_output_commit_handler *output_commit_handler = NULL; - tdm_private_layer *private_layer = NULL; - - OUTPUT_FUNC_ENTRY(); - - func_output = &private_display->func_output; - - if (!func_output->output_commit) { - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - if (func) { - if (!private_output->regist_commit_cb) { - private_output->regist_commit_cb = 1; - ret = func_output->output_set_commit_handler(private_output->output_backend, - tdm_output_cb_commit); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); - } - - output_commit_handler = calloc(1, sizeof(tdm_private_output_commit_handler)); - if (!output_commit_handler) { - TDM_ERR("failed: alloc memory"); - return TDM_ERROR_OUT_OF_MEMORY; - } - - LIST_ADDTAIL(&output_commit_handler->link, &private_output->output_commit_handler_list); - output_commit_handler->private_output = private_output; - output_commit_handler->func = func; - output_commit_handler->user_data = user_data; - output_commit_handler->owner_tid = syscall(SYS_gettid); - } - - ret = func_output->output_commit(private_output->output_backend, sync, - output_commit_handler); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("output(%d) backend commit: handle(%p)", private_output->pipe, output_commit_handler); - - LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { - if (!private_layer->waiting_buffer) - continue; - - private_layer->committed_buffer = private_layer->waiting_buffer; - private_layer->waiting_buffer = NULL; - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)", - private_layer, private_layer->waiting_buffer, - private_layer->committed_buffer->buffer); - } - - return ret; - -commit_failed: - if (output_commit_handler) { - LIST_DEL(&output_commit_handler->link); - free(output_commit_handler); - } - return ret; -} - -EXTERN tdm_error -tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func, - void *user_data) -{ - OUTPUT_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - if (private_display->commit_type == TDM_COMMIT_TYPE_NONE) - private_display->commit_type = TDM_COMMIT_TYPE_OUTPUT; - else if (private_display->commit_type == TDM_COMMIT_TYPE_LAYER) { - TDM_ERR("Can't supported. Use tdm_layer_commit"); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_BAD_REQUEST; - } - - if (private_display->commit_per_vblank) { - TDM_ERR("Use tdm_layer_commit"); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_BAD_REQUEST; - } - - if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { - TDM_ERR("output(%d) dpms: %s", private_output->pipe, - tdm_dpms_str(private_output->current_dpms_value)); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_DPMS_OFF; - } - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("output(%d) commit", private_output->pipe); - - ret = _tdm_output_commit(output, sync, func, user_data); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_set_mode(tdm_output *output, const tdm_output_mode *mode) -{ - tdm_func_output *func_output; - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - func_output = &private_display->func_output; - - if (!func_output->output_set_mode) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_output->output_set_mode(private_output->output_backend, mode); - if (ret == TDM_ERROR_NONE) - private_output->current_mode = mode; - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_mode(tdm_output *output, const tdm_output_mode **mode) -{ - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *mode = private_output->current_mode; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -static tdm_error -_tdm_output_dpms_changed_timeout(void *user_data) -{ - tdm_private_output *private_output = user_data; - tdm_value value; - - value.u32 = private_output->current_dpms_value; - tdm_output_call_change_handler_internal(private_output, - &private_output->change_handler_list_sub, - TDM_OUTPUT_CHANGE_DPMS, - value, 0); - - return TDM_ERROR_NONE; -} - -INTERN void -tdm_output_cb_dpms(tdm_output *output_backend, tdm_output_dpms dpms, void *user_data) -{ - tdm_private_display *private_display; - tdm_private_output *private_output = user_data; - tdm_value value; - - TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); - TDM_RETURN_IF_FAIL(private_output); - - private_display = private_output->private_display; - - if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { - tdm_thread_cb_output_dpms output_dpms; - tdm_error ret; - - _tdm_output_update(output_backend, user_data); - - output_dpms.base.type = TDM_THREAD_CB_OUTPUT_DPMS; - output_dpms.base.length = sizeof output_dpms; - output_dpms.output_stamp = private_output->stamp; - output_dpms.dpms = dpms; - output_dpms.user_data = user_data; - - value.u32 = dpms; - tdm_output_call_change_handler_internal(private_output, - &private_output->change_handler_list_sub, - TDM_OUTPUT_CHANGE_DPMS, - value, 0); - - ret = tdm_thread_send_cb(private_display->private_loop, &output_dpms.base); - TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - - return; - } - - private_output->current_dpms_value = dpms; - - value.u32 = dpms; - tdm_output_call_change_handler_internal(private_output, - &private_output->change_handler_list_main, - TDM_OUTPUT_CHANGE_DPMS, - value, 0); -} - -EXTERN tdm_error -tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) -{ - tdm_func_output *func_output; - OUTPUT_FUNC_ENTRY(); - - if (dpms_value > TDM_OUTPUT_DPMS_OFF) - dpms_value = TDM_OUTPUT_DPMS_OFF; - - _pthread_mutex_lock(&private_display->lock); - - if (private_output->current_dpms_value == dpms_value) { - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_NONE; - } - - /** Use timer to call the output change callback of the sub-thread. - * The output change callback of tdm_server and tdm_vblank was called - * in the main thread. And it made the multi thread issue. If we use - * the timer, we can call the sub-thread's output change callback in - * sub-thread. - */ - if (!private_output->dpms_changed_timer) { - private_output->dpms_changed_timer = - tdm_event_loop_add_timer_handler(private_output->private_display, - _tdm_output_dpms_changed_timeout, private_output, NULL); - if (!private_output->dpms_changed_timer) { - TDM_ERR("can't create dpms timer!!"); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_OUT_OF_MEMORY; - } - } - - func_output = &private_display->func_output; - - if (!func_output->output_set_dpms) { - _pthread_mutex_unlock(&private_display->lock); - private_output->current_dpms_value = dpms_value; - TDM_WRN("not implemented!!"); - return TDM_ERROR_NONE; - } - - if (func_output->output_set_dpms_handler) { - if (!private_output->regist_dpms_cb) { - private_output->regist_dpms_cb = 1; - ret = func_output->output_set_dpms_handler(private_output->output_backend, - tdm_output_cb_dpms, private_output); - if (ret != TDM_ERROR_NONE) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("Can't set the dpms handler!!"); - return ret; - } - } - } - - ret = func_output->output_set_dpms(private_output->output_backend, dpms_value); - - if (ret == TDM_ERROR_NONE && !func_output->output_set_dpms_handler) { - tdm_value value; - - private_output->current_dpms_value = dpms_value; - - value.u32 = dpms_value; - tdm_output_call_change_handler_internal(private_output, - &private_output->change_handler_list_main, - TDM_OUTPUT_CHANGE_DPMS, - value, 0); - - if (!LIST_IS_EMPTY(&private_output->change_handler_list_sub)) { - ret = tdm_event_loop_source_timer_update(private_output->dpms_changed_timer, 1); - if (ret != TDM_ERROR_NONE) - TDM_NEVER_GET_HERE(); - } - } - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value) -{ - tdm_func_output *func_output; - OUTPUT_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(dpms_value != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - func_output = &private_display->func_output; - - if (!func_output->output_get_dpms) { - *dpms_value = private_output->current_dpms_value; - _pthread_mutex_unlock(&private_display->lock); - TDM_WRN("not implemented!!"); - return TDM_ERROR_NONE; - } - - ret = func_output->output_get_dpms(private_output->output_backend, dpms_value); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_capture * -tdm_output_create_capture(tdm_output *output, tdm_error *error) -{ - tdm_capture *capture = NULL; - - OUTPUT_FUNC_ENTRY_ERROR(); - - _pthread_mutex_lock(&private_display->lock); - - capture = (tdm_capture *)tdm_capture_create_output_internal(private_output, error); - - _pthread_mutex_unlock(&private_display->lock); - - return capture; -} - -INTERN void -tdm_output_call_change_handler_internal(tdm_private_output *private_output, - struct list_head *change_handler_list, - tdm_output_change_type type, - tdm_value value, - int no_check_thread_id) -{ - tdm_private_display *private_display; - tdm_private_change_handler *change_handler = NULL; - - TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); - TDM_RETURN_IF_FAIL(private_output); - - private_display = private_output->private_display; - if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { - if (type & TDM_OUTPUT_CHANGE_CONNECTION) - TDM_INFO("output(%d) changed: %s (%d)", - private_output->pipe, tdm_status_str(value.u32), value.u32); - if (type & TDM_OUTPUT_CHANGE_DPMS) - TDM_INFO("output(%d) changed: dpms %s (%d)", - private_output->pipe, tdm_dpms_str(value.u32), value.u32); - } - - if (LIST_IS_EMPTY(change_handler_list)) - return; - - LIST_FOR_EACH_ENTRY(change_handler, change_handler_list, link) { - if (!no_check_thread_id && change_handler->owner_tid != syscall(SYS_gettid)) - TDM_NEVER_GET_HERE(); - - _pthread_mutex_unlock(&private_display->lock); - change_handler->func(private_output, type, - value, change_handler->user_data); - _pthread_mutex_lock(&private_display->lock); - } -} - -EXTERN tdm_error -tdm_layer_get_capabilities(tdm_layer *layer, tdm_layer_capability *capabilities) -{ - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *capabilities = private_layer->caps.capabilities; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_get_available_formats(tdm_layer *layer, const tbm_format **formats, int *count) -{ - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *formats = (const tbm_format *)private_layer->caps.formats; - *count = private_layer->caps.format_count; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_get_available_properties(tdm_layer *layer, const tdm_prop **props, int *count) -{ - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *props = (const tdm_prop *)private_layer->caps.props; - *count = private_layer->caps.prop_count; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_get_zpos(tdm_layer *layer, int *zpos) -{ - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(zpos != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *zpos = private_layer->caps.zpos; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value) -{ - tdm_func_layer *func_layer; - LAYER_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - - if (private_layer->usable) - TDM_INFO("layer(%d) not usable", private_layer->index); - - private_layer->usable = 0; - - if (!func_layer->layer_set_property) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_layer->layer_set_property(private_layer->layer_backend, id, value); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value) -{ - tdm_func_layer *func_layer; - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(value != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - - if (!func_layer->layer_get_property) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_layer->layer_get_property(private_layer->layer_backend, id, value); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_set_info(tdm_layer *layer, tdm_info_layer *info) -{ - tdm_func_layer *func_layer; - char fmtstr[128]; - - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - - if (private_layer->usable) - TDM_INFO("layer(%p) not usable", private_layer); - - private_layer->usable = 0; - - if (!func_layer->layer_set_info) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - if (info->src_config.format) - snprintf(fmtstr, 128, "%c%c%c%c", FOURCC_STR(info->src_config.format)); - else - snprintf(fmtstr, 128, "NONE"); - - TDM_INFO("layer(%p) info: src(%dx%d %d,%d %dx%d %s) dst(%d,%d %dx%d) trans(%d)", - private_layer, info->src_config.size.h, info->src_config.size.v, - info->src_config.pos.x, info->src_config.pos.y, - info->src_config.pos.w, info->src_config.pos.h, - fmtstr, - info->dst_pos.x, info->dst_pos.y, - info->dst_pos.w, info->dst_pos.h, - info->transform); - - ret = func_layer->layer_set_info(private_layer->layer_backend, info); - TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_get_info(tdm_layer *layer, tdm_info_layer *info) -{ - tdm_func_layer *func_layer; - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - - if (!func_layer->layer_get_info) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_layer->layer_get_info(private_layer->layer_backend, info); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -static void -_tdm_layer_dump_buffer(tdm_layer *layer, tbm_surface_h buffer) -{ - tdm_private_layer *private_layer = (tdm_private_layer*)layer; - tdm_private_output *private_output = private_layer->private_output; - unsigned int pipe; - int zpos; - char fname[PATH_MAX]; - - pipe = private_output->pipe; - zpos = private_layer->caps.zpos; - - snprintf(fname, sizeof(fname), "tdm_%d_lyr_%d", pipe, zpos); - - tbm_surface_internal_dump_buffer(buffer, fname); - TDM_DBG("%s dump excute", fname); - - return; -} - -static void -_tdm_layer_free_buffer(tdm_private_layer *private_layer, tdm_private_layer_buffer *layer_buffer) -{ - tdm_private_display *private_display; - - if (!layer_buffer) - return; - - private_display = private_layer->private_output->private_display; - - LIST_DEL(&layer_buffer->link); - if (layer_buffer->buffer) { - _pthread_mutex_unlock(&private_display->lock); - tdm_buffer_unref_backend(layer_buffer->buffer); - if (private_layer->buffer_queue) - tbm_surface_queue_release(private_layer->buffer_queue, layer_buffer->buffer); - _pthread_mutex_lock(&private_display->lock); - } - free(layer_buffer); -} - -static void -_tdm_layer_free_all_buffers(tdm_private_layer *private_layer) -{ - tdm_private_output *private_output = private_layer->private_output; - tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL; - struct list_head clone_list; - - LIST_INITHEAD(&clone_list); - - if (private_layer->waiting_buffer) { - _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); - private_layer->waiting_buffer = NULL; - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) waiting_buffer(%p)", - private_layer, private_layer->waiting_buffer); - } - - if (private_layer->committed_buffer) { - _tdm_layer_free_buffer(private_layer, private_layer->committed_buffer); - private_layer->committed_buffer = NULL; - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) committed_buffer(%p)", - private_layer, private_layer->committed_buffer); - } - - if (private_layer->showing_buffer) { - _tdm_layer_free_buffer(private_layer, private_layer->showing_buffer); - private_layer->showing_buffer = NULL; - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) showing_buffer(%p)", - private_layer, private_layer->showing_buffer); - } - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) { - if (lm->private_layer != private_layer) - continue; - LIST_DEL(&lm->link); - LIST_ADDTAIL(&lm->link, &clone_list); - } - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) { - LIST_DEL(&lm->link); - _tdm_layer_free_buffer(private_layer, lm->committed_buffer); - free(lm); - } - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) { - if (lm->private_layer != private_layer) - continue; - LIST_DEL(&lm->link); - LIST_ADDTAIL(&lm->link, &clone_list); - } - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) { - LIST_DEL(&lm->link); - _tdm_layer_free_buffer(private_layer, lm->committed_buffer); - free(lm); - } - - if (private_layer->buffer_queue) { - tbm_surface_queue_remove_acquirable_cb(private_layer->buffer_queue, _tbm_layer_queue_acquirable_cb, private_layer); - tbm_surface_queue_remove_destroy_cb(private_layer->buffer_queue, _tbm_layer_queue_destroy_cb, private_layer); - private_layer->buffer_queue = NULL; - } -} - -EXTERN tdm_error -tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) -{ - tdm_func_layer *func_layer; - tdm_private_layer_buffer *layer_buffer; - - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - if (tdm_debug_dump & TDM_DUMP_FLAG_LAYER && - !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) { - char str[TDM_PATH_LEN]; - static int i; - snprintf(str, TDM_PATH_LEN, "layer_%d_%d_%03d", - private_output->index, private_layer->index, i++); - tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str); - } - - func_layer = &private_display->func_layer; - - if (private_layer->usable) - TDM_INFO("layer(%p) not usable", private_layer); - - private_layer->usable = 0; - - if (!func_layer->layer_set_buffer) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - layer_buffer = calloc(1, sizeof(tdm_private_layer_buffer)); - if (!layer_buffer) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("alloc failed"); - return TDM_ERROR_OUT_OF_MEMORY; - } - LIST_INITHEAD(&layer_buffer->link); - - ret = func_layer->layer_set_buffer(private_layer->layer_backend, buffer); - TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - - /* dump buffer */ - if (tdm_dump_enable && !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) - _tdm_layer_dump_buffer(layer, buffer); - - if (ret == TDM_ERROR_NONE) { - if (private_layer->waiting_buffer) - _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); - - private_layer->waiting_buffer = layer_buffer; - private_layer->waiting_buffer->buffer = tdm_buffer_ref_backend(buffer); - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) waiting_buffer(%p)", - private_layer, private_layer->waiting_buffer->buffer); - } else - _tdm_layer_free_buffer(private_layer, layer_buffer); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_unset_buffer(tdm_layer *layer) -{ - tdm_func_layer *func_layer; - LAYER_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - - _tdm_layer_free_all_buffers(private_layer); - - private_layer->usable = 1; - - if (private_layer->usable) - TDM_INFO("layer(%p) now usable", private_layer); - - if (!func_layer->layer_unset_buffer) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_layer->layer_unset_buffer(private_layer->layer_backend); - TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -static void -_tdm_layer_committed(tdm_private_layer *private_layer, tdm_private_layer_buffer **committed_buffer) -{ - tdm_private_output *private_output = private_layer->private_output; - tdm_private_display *private_display = private_output->private_display; - - if (private_display->print_fps) { - double curr = tdm_helper_get_time(); - if (private_layer->fps_stamp == 0) { - private_layer->fps_stamp = curr; - } else if ((curr - private_layer->fps_stamp) > 1.0) { - TDM_INFO("output(%d) layer(%d) fps: %d", private_output->index, private_layer->index, private_layer->fps_count); - private_layer->fps_count = 0; - private_layer->fps_stamp = curr; - } else - private_layer->fps_count++; - } else if (private_layer->fps_stamp != 0) { - private_layer->fps_stamp = 0; - private_layer->fps_count = 0; - } - - if (private_layer->showing_buffer) - _tdm_layer_free_buffer(private_layer, private_layer->showing_buffer); - - private_layer->showing_buffer = *committed_buffer; - *committed_buffer = NULL; - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) committed_buffer(%p) showing_buffer(%p)", - private_layer, *committed_buffer, - (private_layer->showing_buffer) ? private_layer->showing_buffer->buffer : NULL); -} - -static void -_tdm_layer_got_output_vblank(tdm_private_output *private_output, unsigned int sequence, - unsigned int tv_sec, unsigned int tv_usec) -{ - tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL; - tdm_private_display *private_display; - struct list_head clone_list, pending_clone_list; - tdm_error ret; - - private_display = private_output->private_display; - - private_output->layer_waiting_vblank = 0; - - LIST_INITHEAD(&clone_list); - LIST_INITHEAD(&pending_clone_list); - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) { - LIST_DEL(&lm->link); - lm->private_layer->committing = 0; - LIST_ADDTAIL(&lm->link, &clone_list); - } - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) { - LIST_DEL(&lm->link); - lm->private_layer->committing = 0; - LIST_ADDTAIL(&lm->link, &pending_clone_list); - } - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) { - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) committed. handle(%p) commited_buffer(%p)", - lm->private_layer, lm, (lm->committed_buffer) ? lm->committed_buffer->buffer : NULL); - - LIST_DEL(&lm->link); - _tdm_layer_committed(lm->private_layer, &lm->committed_buffer); - _pthread_mutex_unlock(&private_display->lock); - if (lm->func) - lm->func(lm->private_layer, sequence, tv_sec, tv_usec, lm->user_data); - _pthread_mutex_lock(&private_display->lock); - if (lm->committed_buffer) - _tdm_layer_free_buffer(lm->private_layer, lm->committed_buffer); - free(lm); - } - - if (LIST_IS_EMPTY(&pending_clone_list)) - return; - - TDM_GOTO_IF_FAIL(private_output->vblank != NULL, wait_failed); - - ret = _tdm_output_commit(private_output, 0, NULL, NULL); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer commit: output(%d) commit", private_output->pipe); - - /* tdm_vblank APIs is for server. it should be called in unlock status*/ - if (!private_output->layer_waiting_vblank) { - _pthread_mutex_unlock(&private_display->lock); - ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output); - _pthread_mutex_lock(&private_display->lock); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); - private_output->layer_waiting_vblank = 1; - } - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer commit: output(%d) wait vblank", private_output->pipe); - - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &pending_clone_list, link) { - LIST_DEL(&lm->link); - LIST_ADDTAIL(&lm->link, &private_output->layer_commit_handler_list); - } - - return; -wait_failed: - LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &pending_clone_list, link) { - LIST_DEL(&lm->link); - _tdm_layer_free_buffer(lm->private_layer, lm->committed_buffer); - free(lm); - } - return; -} - -static void -_tdm_layer_cb_output_commit(tdm_output *output, unsigned int sequence, - unsigned int tv_sec, unsigned int tv_usec, void *user_data) -{ - tdm_private_layer_commit_handler *layer_commit_handler = user_data; - tdm_private_layer_commit_handler *lm = NULL; - tdm_private_display *private_display; - tdm_private_output *private_output = output; - tdm_private_layer *private_layer; - int found = 0; - - TDM_RETURN_IF_FAIL(layer_commit_handler != NULL); - - private_display = private_output->private_display; - - LIST_FOR_EACH_ENTRY(lm, &private_output->layer_commit_handler_list, link) { - if (layer_commit_handler == lm) { - found = 1; - break; - } - } - - if (!found) - return; - - private_layer = layer_commit_handler->private_layer; - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) commit: output(%d) committed. handle(%p)", - private_layer, private_output->pipe, layer_commit_handler); - - _pthread_mutex_lock(&private_display->lock); - - _tdm_layer_committed(private_layer, &layer_commit_handler->committed_buffer); - - if (layer_commit_handler->func) { - _pthread_mutex_unlock(&private_display->lock); - layer_commit_handler->func(private_output, sequence, - tv_sec, tv_usec, layer_commit_handler->user_data); - _pthread_mutex_lock(&private_display->lock); - } - - LIST_DEL(&layer_commit_handler->link); - free(layer_commit_handler); - - _pthread_mutex_unlock(&private_display->lock); -} - -static void -_tdm_layer_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence, - unsigned int tv_sec, unsigned int tv_usec, void *user_data) -{ - tdm_private_output *private_output = user_data; - tdm_private_display *private_display; - - TDM_RETURN_IF_FAIL(private_output != NULL); - - private_display = private_output->private_display; - - _pthread_mutex_lock(&private_display->lock); - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer commit: output(%d) got vblank", private_output->pipe); - - _tdm_layer_got_output_vblank(private_output, sequence, tv_sec, tv_usec); - - _pthread_mutex_unlock(&private_display->lock); -} - -static int -_tdm_layer_commit_possible(tdm_private_layer *private_layer) -{ - tdm_private_output *private_output = private_layer->private_output; - tdm_private_display *private_display = private_output->private_display; - - if (private_display->commit_per_vblank == 1 && _tdm_output_used_layer_count(private_output) == 1) { - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) commit: 1 layer", private_layer); - return 1; - } - - if (private_display->commit_per_vblank == 2 && LIST_IS_EMPTY(&private_output->layer_commit_handler_list)) { - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) commit: non previous commit", private_layer); - return 1; - } - - return 0; -} - -static tdm_error -_tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data) -{ - tdm_private_layer_commit_handler *layer_commit_handler; - LAYER_FUNC_ENTRY(); - - layer_commit_handler = calloc(1, sizeof(tdm_private_layer_commit_handler)); - if (!layer_commit_handler) { - TDM_ERR("failed: alloc memory"); - return TDM_ERROR_OUT_OF_MEMORY; - } - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) commit: handle(%p)", private_layer, layer_commit_handler); - - LIST_INITHEAD(&layer_commit_handler->link); - layer_commit_handler->private_layer = private_layer; - layer_commit_handler->func = func; - layer_commit_handler->user_data = user_data; - - layer_commit_handler->committed_buffer = private_layer->waiting_buffer; - private_layer->waiting_buffer = NULL; - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)", - private_layer, private_layer->waiting_buffer, - (layer_commit_handler->committed_buffer) ? layer_commit_handler->committed_buffer->buffer : NULL); - - if (!private_display->commit_per_vblank) { - TDM_GOTO_IF_FAIL(private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT, commit_failed); - - LIST_ADDTAIL(&layer_commit_handler->link, &private_output->layer_commit_handler_list); - ret = _tdm_output_commit(private_layer->private_output, 0, _tdm_layer_cb_output_commit, layer_commit_handler); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) commit: no commit-per-vblank", private_layer); - } else { - TDM_GOTO_IF_FAIL(private_display->commit_type == TDM_COMMIT_TYPE_LAYER, commit_failed); - - if (private_layer->committing) - TDM_WRN("layer(%d) too many commit", private_layer->index); - else - private_layer->committing = 1; - - if (_tdm_layer_commit_possible(private_layer)) { - /* add to layer_commit_handler_list */ - LIST_ADDTAIL(&layer_commit_handler->link, &private_output->layer_commit_handler_list); - ret = _tdm_output_commit(private_layer->private_output, 0, NULL, NULL); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) commit: output", private_layer); - } else { - /* add to pending_commit_handler_list. It will be commited when a vblank occurs */ - LIST_ADDTAIL(&layer_commit_handler->link, &private_output->pending_commit_handler_list); - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) commit: pending", private_layer); - } - - if (!private_output->vblank) { - /* tdm_vblank APIs is for server. it should be called in unlock status*/ - _pthread_mutex_unlock(&private_display->lock); - private_output->vblank = tdm_vblank_create(private_display, private_output, NULL); - _pthread_mutex_lock(&private_display->lock); - TDM_GOTO_IF_FAIL(private_output->vblank != NULL, commit_failed); - } - - if (!private_output->layer_waiting_vblank) { - /* tdm_vblank APIs is for server. it should be called in unlock status*/ - _pthread_mutex_unlock(&private_display->lock); - ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output); - _pthread_mutex_lock(&private_display->lock); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); - private_output->layer_waiting_vblank = 1; - - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("layer(%p) commit: wait vblank", private_layer); - } - } - - return ret; - -commit_failed: - if (layer_commit_handler) { - private_layer->waiting_buffer = layer_commit_handler->committed_buffer; - LIST_DEL(&layer_commit_handler->link); - free(layer_commit_handler); - } - return ret; -} - -EXTERN tdm_error -tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data) -{ - LAYER_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - if (private_display->commit_type == TDM_COMMIT_TYPE_NONE) { - if (!private_display->commit_per_vblank) - private_display->commit_type = TDM_COMMIT_TYPE_OUTPUT; - else - private_display->commit_type = TDM_COMMIT_TYPE_LAYER; - } - - if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { - TDM_ERR("layer(%p)'s output(%d) dpms: %s", layer, private_output->pipe, - tdm_dpms_str(private_output->current_dpms_value)); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_DPMS_OFF; - } - - ret = _tdm_layer_commit(private_layer, func, user_data); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_is_committing(tdm_layer *layer, unsigned int *committing) -{ - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(committing != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *committing = private_layer->committing; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tbm_surface_h -tdm_layer_get_displaying_buffer(tdm_layer *layer, tdm_error *error) -{ - tbm_surface_h buffer; - LAYER_FUNC_ENTRY_ERROR(); - - _pthread_mutex_lock(&private_display->lock); - - if (error) - *error = TDM_ERROR_NONE; - - if (private_layer->showing_buffer) { - buffer = private_layer->showing_buffer->buffer; - } else { - if (error) - *error = TDM_ERROR_OPERATION_FAILED; - _pthread_mutex_unlock(&private_display->lock); - TDM_DBG("layer(%p) showing_buffer is null", private_layer); - return NULL; - } - _pthread_mutex_unlock(&private_display->lock); - - return buffer; -} - -static void -_tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data) -{ - TDM_RETURN_IF_FAIL(data != NULL); - tdm_layer *layer = data; - tdm_func_layer *func_layer; - tbm_surface_h surface = NULL; - tdm_private_layer_buffer *layer_buffer; - LAYER_FUNC_ENTRY_VOID_RETURN(); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - if (!func_layer->layer_set_buffer) { - _pthread_mutex_unlock(&private_display->lock); - return; - } - - layer_buffer = calloc(1, sizeof(tdm_private_layer_buffer)); - if (!layer_buffer) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("alloc failed"); - return; - } - LIST_INITHEAD(&layer_buffer->link); - - if (TBM_SURFACE_QUEUE_ERROR_NONE != tbm_surface_queue_acquire(private_layer->buffer_queue, &surface) || - surface == NULL) { - TDM_ERR("layer(%p) tbm_surface_queue_acquire() failed surface:%p", - private_layer, surface); - _pthread_mutex_unlock(&private_display->lock); - free(layer_buffer); - return; - } - - ret = func_layer->layer_set_buffer(private_layer->layer_backend, surface); - TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - - if (ret == TDM_ERROR_NONE) { - if (private_layer->waiting_buffer) { - TDM_DBG("layer(%p) drop waiting_buffer(%p)", private_layer, private_layer->waiting_buffer->buffer); - _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); - } - - private_layer->waiting_buffer = layer_buffer; - private_layer->waiting_buffer->buffer = tdm_buffer_ref_backend(surface); - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) waiting_buffer(%p)", - private_layer, private_layer->waiting_buffer->buffer); - - if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) { - ret = _tdm_output_commit(private_layer->private_output, 0, NULL, NULL); - if (ret != TDM_ERROR_NONE) - TDM_ERR("_tdm_output_commit() is fail"); - } else if (private_display->commit_type == TDM_COMMIT_TYPE_LAYER) { - ret = _tdm_layer_commit(private_layer, NULL, NULL); - if (ret != TDM_ERROR_NONE) - TDM_ERR("layer(%p) _tdm_layer_commit() is fail", private_layer); - } else { - TDM_NEVER_GET_HERE(); - } - } else - _tdm_layer_free_buffer(private_layer, layer_buffer); - - _pthread_mutex_unlock(&private_display->lock); -} - -static void -_tbm_layer_queue_destroy_cb(tbm_surface_queue_h surface_queue, void *data) -{ - TDM_RETURN_IF_FAIL(data != NULL); - tdm_layer *layer = data; - LAYER_FUNC_ENTRY_VOID_RETURN(); - TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); - - _pthread_mutex_lock(&private_display->lock); - - private_layer->buffer_queue = NULL; - - _tdm_layer_free_all_buffers(private_layer); - - _pthread_mutex_unlock(&private_display->lock); -} - -EXTERN tdm_error -tdm_layer_set_buffer_queue(tdm_layer *layer, tbm_surface_queue_h buffer_queue) -{ - tdm_func_layer *func_layer; - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(buffer_queue != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - - if (private_layer->usable) - TDM_INFO("layer(%p) not usable", private_layer); - - private_layer->usable = 0; - - if (!func_layer->layer_set_buffer) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - if (buffer_queue == private_layer->buffer_queue) { - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_NONE; - } - - if (private_layer->waiting_buffer) { - _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); - private_layer->waiting_buffer = NULL; - - if (tdm_debug_module & TDM_DEBUG_BUFFER) - TDM_INFO("layer(%p) waiting_buffer(%p)", - private_layer, private_layer->waiting_buffer); - } - - private_layer->buffer_queue = buffer_queue; - tbm_surface_queue_add_acquirable_cb(private_layer->buffer_queue, - _tbm_layer_queue_acquirable_cb, - private_layer); - tbm_surface_queue_add_destroy_cb(private_layer->buffer_queue, - _tbm_layer_queue_destroy_cb, - private_layer); - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_unset_buffer_queue(tdm_layer *layer) -{ - return tdm_layer_unset_buffer(layer); -} - -EXTERN tdm_error -tdm_layer_is_usable(tdm_layer *layer, unsigned int *usable) -{ - LAYER_FUNC_ENTRY(); - - TDM_RETURN_VAL_IF_FAIL(usable != NULL, TDM_ERROR_INVALID_PARAMETER); - - _pthread_mutex_lock(&private_display->lock); - - *usable = private_layer->usable; - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_error -tdm_layer_set_video_pos(tdm_layer *layer, int zpos) -{ - tdm_func_layer *func_layer; - LAYER_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - - if (!(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) { - TDM_ERR("layer(%p) is not video layer", private_layer); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_INVALID_PARAMETER; - } - - if (!func_layer->layer_set_video_pos) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_layer->layer_set_video_pos(private_layer->layer_backend, zpos); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} - -EXTERN tdm_capture * -tdm_layer_create_capture(tdm_layer *layer, tdm_error *error) -{ - tdm_capture *capture = NULL; - - LAYER_FUNC_ENTRY_ERROR(); - - _pthread_mutex_lock(&private_display->lock); - - capture = (tdm_capture *)tdm_capture_create_layer_internal(private_layer, error); - - _pthread_mutex_unlock(&private_display->lock); - - return capture; -} - -EXTERN tdm_error -tdm_layer_get_buffer_flags(tdm_layer *layer, unsigned int *flags) -{ - tdm_func_layer *func_layer; - LAYER_FUNC_ENTRY(); - - _pthread_mutex_lock(&private_display->lock); - - func_layer = &private_display->func_layer; - - if (!func_layer->layer_get_buffer_flags) { - _pthread_mutex_unlock(&private_display->lock); - TDM_ERR("not implemented!!"); - return TDM_ERROR_NOT_IMPLEMENTED; - } - - ret = func_layer->layer_get_buffer_flags(private_layer->layer_backend, flags); - - _pthread_mutex_unlock(&private_display->lock); - - return ret; -} diff --git a/src/tdm_layer.c b/src/tdm_layer.c new file mode 100644 index 0000000..d677f16 --- /dev/null +++ b/src/tdm_layer.c @@ -0,0 +1,1086 @@ +/************************************************************************** + * + * libtdm + * + * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: Eunchul Kim , + * JinYoung Jeon , + * Taeheon Kim , + * YoungJun Cho , + * SooChan Lim , + * Boram Park + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm.h" +#include "tdm_backend.h" +#include "tdm_private.h" +#include "tdm_helper.h" + +#define COUNT_MAX 10 + +#define LAYER_FUNC_ENTRY() \ + tdm_private_display *private_display; \ + tdm_private_output *private_output; \ + tdm_private_layer *private_layer; \ + tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ + TDM_RETURN_VAL_IF_FAIL(layer != NULL, TDM_ERROR_INVALID_PARAMETER); \ + private_layer = (tdm_private_layer*)layer; \ + private_output = private_layer->private_output; \ + private_display = private_output->private_display + +#define LAYER_FUNC_ENTRY_ERROR() \ + tdm_private_display *private_display; \ + tdm_private_output *private_output; \ + tdm_private_layer *private_layer; \ + tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(layer != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \ + private_layer = (tdm_private_layer*)layer; \ + private_output = private_layer->private_output; \ + private_display = private_output->private_display + +#define LAYER_FUNC_ENTRY_VOID_RETURN() \ + tdm_private_display *private_display; \ + tdm_private_output *private_output; \ + tdm_private_layer *private_layer; \ + tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ + TDM_RETURN_IF_FAIL(layer != NULL); \ + private_layer = (tdm_private_layer*)layer; \ + private_output = private_layer->private_output; \ + private_display = private_output->private_display + +static void _tdm_layer_free_buffer(tdm_private_layer *private_layer, tdm_private_layer_buffer *layer_buffer); +static void _tdm_layer_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data); +static void _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data); +static void _tbm_layer_queue_destroy_cb(tbm_surface_queue_h surface_queue, void *data); + +EXTERN tdm_error +tdm_layer_get_capabilities(tdm_layer *layer, tdm_layer_capability *capabilities) +{ + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *capabilities = private_layer->caps.capabilities; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_get_available_formats(tdm_layer *layer, const tbm_format **formats, int *count) +{ + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *formats = (const tbm_format *)private_layer->caps.formats; + *count = private_layer->caps.format_count; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_get_available_properties(tdm_layer *layer, const tdm_prop **props, int *count) +{ + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *props = (const tdm_prop *)private_layer->caps.props; + *count = private_layer->caps.prop_count; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_get_zpos(tdm_layer *layer, int *zpos) +{ + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(zpos != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *zpos = private_layer->caps.zpos; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value) +{ + tdm_func_layer *func_layer; + LAYER_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + func_layer = &private_display->func_layer; + + if (private_layer->usable) + TDM_INFO("layer(%d) not usable", private_layer->index); + + private_layer->usable = 0; + + if (!func_layer->layer_set_property) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_layer->layer_set_property(private_layer->layer_backend, id, value); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value) +{ + tdm_func_layer *func_layer; + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(value != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + func_layer = &private_display->func_layer; + + if (!func_layer->layer_get_property) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_layer->layer_get_property(private_layer->layer_backend, id, value); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_set_info(tdm_layer *layer, tdm_info_layer *info) +{ + tdm_func_layer *func_layer; + char fmtstr[128]; + + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + func_layer = &private_display->func_layer; + + if (private_layer->usable) + TDM_INFO("layer(%p) not usable", private_layer); + + private_layer->usable = 0; + + if (!func_layer->layer_set_info) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + if (info->src_config.format) + snprintf(fmtstr, 128, "%c%c%c%c", FOURCC_STR(info->src_config.format)); + else + snprintf(fmtstr, 128, "NONE"); + + TDM_INFO("layer(%p) info: src(%dx%d %d,%d %dx%d %s) dst(%d,%d %dx%d) trans(%d)", + private_layer, info->src_config.size.h, info->src_config.size.v, + info->src_config.pos.x, info->src_config.pos.y, + info->src_config.pos.w, info->src_config.pos.h, + fmtstr, + info->dst_pos.x, info->dst_pos.y, + info->dst_pos.w, info->dst_pos.h, + info->transform); + + ret = func_layer->layer_set_info(private_layer->layer_backend, info); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_get_info(tdm_layer *layer, tdm_info_layer *info) +{ + tdm_func_layer *func_layer; + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + func_layer = &private_display->func_layer; + + if (!func_layer->layer_get_info) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_layer->layer_get_info(private_layer->layer_backend, info); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +static void +_tdm_layer_dump_buffer(tdm_layer *layer, tbm_surface_h buffer) +{ + tdm_private_layer *private_layer = (tdm_private_layer*)layer; + tdm_private_output *private_output = private_layer->private_output; + unsigned int pipe; + int zpos; + char fname[PATH_MAX]; + + pipe = private_output->pipe; + zpos = private_layer->caps.zpos; + + snprintf(fname, sizeof(fname), "tdm_%d_lyr_%d", pipe, zpos); + + tbm_surface_internal_dump_buffer(buffer, fname); + TDM_DBG("%s dump excute", fname); + + return; +} + +static void +_tdm_layer_free_buffer(tdm_private_layer *private_layer, tdm_private_layer_buffer *layer_buffer) +{ + tdm_private_display *private_display; + + if (!layer_buffer) + return; + + private_display = private_layer->private_output->private_display; + + LIST_DEL(&layer_buffer->link); + if (layer_buffer->buffer) { + _pthread_mutex_unlock(&private_display->lock); + tdm_buffer_unref_backend(layer_buffer->buffer); + if (private_layer->buffer_queue) + tbm_surface_queue_release(private_layer->buffer_queue, layer_buffer->buffer); + _pthread_mutex_lock(&private_display->lock); + } + free(layer_buffer); +} + +static void +_tdm_layer_free_all_buffers(tdm_private_layer *private_layer) +{ + tdm_private_output *private_output = private_layer->private_output; + tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL; + struct list_head clone_list; + + LIST_INITHEAD(&clone_list); + + if (private_layer->waiting_buffer) { + _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); + private_layer->waiting_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) waiting_buffer(%p)", + private_layer, private_layer->waiting_buffer); + } + + if (private_layer->committed_buffer) { + _tdm_layer_free_buffer(private_layer, private_layer->committed_buffer); + private_layer->committed_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) committed_buffer(%p)", + private_layer, private_layer->committed_buffer); + } + + if (private_layer->showing_buffer) { + _tdm_layer_free_buffer(private_layer, private_layer->showing_buffer); + private_layer->showing_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) showing_buffer(%p)", + private_layer, private_layer->showing_buffer); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) { + if (lm->private_layer != private_layer) + continue; + LIST_DEL(&lm->link); + LIST_ADDTAIL(&lm->link, &clone_list); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) { + LIST_DEL(&lm->link); + _tdm_layer_free_buffer(private_layer, lm->committed_buffer); + free(lm); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) { + if (lm->private_layer != private_layer) + continue; + LIST_DEL(&lm->link); + LIST_ADDTAIL(&lm->link, &clone_list); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) { + LIST_DEL(&lm->link); + _tdm_layer_free_buffer(private_layer, lm->committed_buffer); + free(lm); + } + + if (private_layer->buffer_queue) { + tbm_surface_queue_remove_acquirable_cb(private_layer->buffer_queue, _tbm_layer_queue_acquirable_cb, private_layer); + tbm_surface_queue_remove_destroy_cb(private_layer->buffer_queue, _tbm_layer_queue_destroy_cb, private_layer); + private_layer->buffer_queue = NULL; + } +} + +EXTERN tdm_error +tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) +{ + tdm_func_layer *func_layer; + tdm_private_layer_buffer *layer_buffer; + + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + if (tdm_debug_dump & TDM_DUMP_FLAG_LAYER && + !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) { + char str[TDM_PATH_LEN]; + static int i; + snprintf(str, TDM_PATH_LEN, "layer_%d_%d_%03d", + private_output->index, private_layer->index, i++); + tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str); + } + + func_layer = &private_display->func_layer; + + if (private_layer->usable) + TDM_INFO("layer(%p) not usable", private_layer); + + private_layer->usable = 0; + + if (!func_layer->layer_set_buffer) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + layer_buffer = calloc(1, sizeof(tdm_private_layer_buffer)); + if (!layer_buffer) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + LIST_INITHEAD(&layer_buffer->link); + + ret = func_layer->layer_set_buffer(private_layer->layer_backend, buffer); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + /* dump buffer */ + if (tdm_dump_enable && !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) + _tdm_layer_dump_buffer(layer, buffer); + + if (ret == TDM_ERROR_NONE) { + if (private_layer->waiting_buffer) + _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); + + private_layer->waiting_buffer = layer_buffer; + private_layer->waiting_buffer->buffer = tdm_buffer_ref_backend(buffer); + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) waiting_buffer(%p)", + private_layer, private_layer->waiting_buffer->buffer); + } else + _tdm_layer_free_buffer(private_layer, layer_buffer); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_unset_buffer(tdm_layer *layer) +{ + tdm_func_layer *func_layer; + LAYER_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + func_layer = &private_display->func_layer; + + _tdm_layer_free_all_buffers(private_layer); + + private_layer->usable = 1; + + if (private_layer->usable) + TDM_INFO("layer(%p) now usable", private_layer); + + if (!func_layer->layer_unset_buffer) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_layer->layer_unset_buffer(private_layer->layer_backend); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +INTERN void +tdm_layer_committed(tdm_private_layer *private_layer, tdm_private_layer_buffer **committed_buffer) +{ + tdm_private_output *private_output = private_layer->private_output; + tdm_private_display *private_display = private_output->private_display; + + if (private_display->print_fps) { + double curr = tdm_helper_get_time(); + if (private_layer->fps_stamp == 0) { + private_layer->fps_stamp = curr; + } else if ((curr - private_layer->fps_stamp) > 1.0) { + TDM_INFO("output(%d) layer(%d) fps: %d", private_output->index, private_layer->index, private_layer->fps_count); + private_layer->fps_count = 0; + private_layer->fps_stamp = curr; + } else + private_layer->fps_count++; + } else if (private_layer->fps_stamp != 0) { + private_layer->fps_stamp = 0; + private_layer->fps_count = 0; + } + + if (private_layer->showing_buffer) + _tdm_layer_free_buffer(private_layer, private_layer->showing_buffer); + + private_layer->showing_buffer = *committed_buffer; + *committed_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) committed_buffer(%p) showing_buffer(%p)", + private_layer, *committed_buffer, + (private_layer->showing_buffer) ? private_layer->showing_buffer->buffer : NULL); +} + +static void +_tdm_layer_got_output_vblank(tdm_private_output *private_output, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec) +{ + tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL; + tdm_private_display *private_display; + struct list_head clone_list, pending_clone_list; + tdm_error ret; + + private_display = private_output->private_display; + + private_output->layer_waiting_vblank = 0; + + LIST_INITHEAD(&clone_list); + LIST_INITHEAD(&pending_clone_list); + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) { + LIST_DEL(&lm->link); + lm->private_layer->committing = 0; + LIST_ADDTAIL(&lm->link, &clone_list); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) { + LIST_DEL(&lm->link); + lm->private_layer->committing = 0; + LIST_ADDTAIL(&lm->link, &pending_clone_list); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) { + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer(%p) committed. handle(%p) commited_buffer(%p)", + lm->private_layer, lm, (lm->committed_buffer) ? lm->committed_buffer->buffer : NULL); + + LIST_DEL(&lm->link); + tdm_layer_committed(lm->private_layer, &lm->committed_buffer); + _pthread_mutex_unlock(&private_display->lock); + if (lm->func) + lm->func(lm->private_layer, sequence, tv_sec, tv_usec, lm->user_data); + _pthread_mutex_lock(&private_display->lock); + if (lm->committed_buffer) + _tdm_layer_free_buffer(lm->private_layer, lm->committed_buffer); + free(lm); + } + + if (LIST_IS_EMPTY(&pending_clone_list)) + return; + + TDM_GOTO_IF_FAIL(private_output->vblank != NULL, wait_failed); + + ret = tdm_output_commit_internal(private_output, 0, NULL, NULL); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer commit: output(%d) commit", private_output->pipe); + + /* tdm_vblank APIs is for server. it should be called in unlock status*/ + if (!private_output->layer_waiting_vblank) { + _pthread_mutex_unlock(&private_display->lock); + ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output); + _pthread_mutex_lock(&private_display->lock); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); + private_output->layer_waiting_vblank = 1; + } + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer commit: output(%d) wait vblank", private_output->pipe); + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &pending_clone_list, link) { + LIST_DEL(&lm->link); + LIST_ADDTAIL(&lm->link, &private_output->layer_commit_handler_list); + } + + return; +wait_failed: + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &pending_clone_list, link) { + LIST_DEL(&lm->link); + _tdm_layer_free_buffer(lm->private_layer, lm->committed_buffer); + free(lm); + } + return; +} + +static void +_tdm_layer_cb_output_commit(tdm_output *output, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) +{ + tdm_private_layer_commit_handler *layer_commit_handler = user_data; + tdm_private_layer_commit_handler *lm = NULL; + tdm_private_display *private_display; + tdm_private_output *private_output = output; + tdm_private_layer *private_layer; + int found = 0; + + TDM_RETURN_IF_FAIL(layer_commit_handler != NULL); + + private_display = private_output->private_display; + + LIST_FOR_EACH_ENTRY(lm, &private_output->layer_commit_handler_list, link) { + if (layer_commit_handler == lm) { + found = 1; + break; + } + } + + if (!found) + return; + + private_layer = layer_commit_handler->private_layer; + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer(%p) commit: output(%d) committed. handle(%p)", + private_layer, private_output->pipe, layer_commit_handler); + + _pthread_mutex_lock(&private_display->lock); + + tdm_layer_committed(private_layer, &layer_commit_handler->committed_buffer); + + if (layer_commit_handler->func) { + _pthread_mutex_unlock(&private_display->lock); + layer_commit_handler->func(private_output, sequence, + tv_sec, tv_usec, layer_commit_handler->user_data); + _pthread_mutex_lock(&private_display->lock); + } + + LIST_DEL(&layer_commit_handler->link); + free(layer_commit_handler); + + _pthread_mutex_unlock(&private_display->lock); +} + +static void +_tdm_layer_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) +{ + tdm_private_output *private_output = user_data; + tdm_private_display *private_display; + + TDM_RETURN_IF_FAIL(private_output != NULL); + + private_display = private_output->private_display; + + _pthread_mutex_lock(&private_display->lock); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer commit: output(%d) got vblank", private_output->pipe); + + _tdm_layer_got_output_vblank(private_output, sequence, tv_sec, tv_usec); + + _pthread_mutex_unlock(&private_display->lock); +} + +static unsigned int +_tdm_lauer_get_output_used_layer_count(tdm_private_output *private_output) +{ + tdm_private_layer *private_layer = NULL; + unsigned int count = 0; + + LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { + if (!private_layer->usable) + count++; + } + + return count; +} + +static int +_tdm_layer_commit_possible(tdm_private_layer *private_layer) +{ + tdm_private_output *private_output = private_layer->private_output; + tdm_private_display *private_display = private_output->private_display; + + if (private_display->commit_per_vblank == 1 && _tdm_lauer_get_output_used_layer_count(private_output) == 1) { + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer(%p) commit: 1 layer", private_layer); + return 1; + } + + if (private_display->commit_per_vblank == 2 && LIST_IS_EMPTY(&private_output->layer_commit_handler_list)) { + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer(%p) commit: non previous commit", private_layer); + return 1; + } + + return 0; +} + +static tdm_error +_tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data) +{ + tdm_private_layer_commit_handler *layer_commit_handler; + LAYER_FUNC_ENTRY(); + + layer_commit_handler = calloc(1, sizeof(tdm_private_layer_commit_handler)); + if (!layer_commit_handler) { + TDM_ERR("failed: alloc memory"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer(%p) commit: handle(%p)", private_layer, layer_commit_handler); + + LIST_INITHEAD(&layer_commit_handler->link); + layer_commit_handler->private_layer = private_layer; + layer_commit_handler->func = func; + layer_commit_handler->user_data = user_data; + + layer_commit_handler->committed_buffer = private_layer->waiting_buffer; + private_layer->waiting_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)", + private_layer, private_layer->waiting_buffer, + (layer_commit_handler->committed_buffer) ? layer_commit_handler->committed_buffer->buffer : NULL); + + if (!private_display->commit_per_vblank) { + TDM_GOTO_IF_FAIL(private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT, commit_failed); + + LIST_ADDTAIL(&layer_commit_handler->link, &private_output->layer_commit_handler_list); + ret = tdm_output_commit_internal(private_layer->private_output, 0, _tdm_layer_cb_output_commit, layer_commit_handler); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer(%p) commit: no commit-per-vblank", private_layer); + } else { + TDM_GOTO_IF_FAIL(private_display->commit_type == TDM_COMMIT_TYPE_LAYER, commit_failed); + + if (private_layer->committing) + TDM_WRN("layer(%d) too many commit", private_layer->index); + else + private_layer->committing = 1; + + if (_tdm_layer_commit_possible(private_layer)) { + /* add to layer_commit_handler_list */ + LIST_ADDTAIL(&layer_commit_handler->link, &private_output->layer_commit_handler_list); + ret = tdm_output_commit_internal(private_layer->private_output, 0, NULL, NULL); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer(%p) commit: output", private_layer); + } else { + /* add to pending_commit_handler_list. It will be commited when a vblank occurs */ + LIST_ADDTAIL(&layer_commit_handler->link, &private_output->pending_commit_handler_list); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer(%p) commit: pending", private_layer); + } + + if (!private_output->vblank) { + /* tdm_vblank APIs is for server. it should be called in unlock status*/ + _pthread_mutex_unlock(&private_display->lock); + private_output->vblank = tdm_vblank_create(private_display, private_output, NULL); + _pthread_mutex_lock(&private_display->lock); + TDM_GOTO_IF_FAIL(private_output->vblank != NULL, commit_failed); + } + + if (!private_output->layer_waiting_vblank) { + /* tdm_vblank APIs is for server. it should be called in unlock status*/ + _pthread_mutex_unlock(&private_display->lock); + ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output); + _pthread_mutex_lock(&private_display->lock); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); + private_output->layer_waiting_vblank = 1; + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("layer(%p) commit: wait vblank", private_layer); + } + } + + return ret; + +commit_failed: + if (layer_commit_handler) { + private_layer->waiting_buffer = layer_commit_handler->committed_buffer; + LIST_DEL(&layer_commit_handler->link); + free(layer_commit_handler); + } + return ret; +} + +EXTERN tdm_error +tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data) +{ + LAYER_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + if (private_display->commit_type == TDM_COMMIT_TYPE_NONE) { + if (!private_display->commit_per_vblank) + private_display->commit_type = TDM_COMMIT_TYPE_OUTPUT; + else + private_display->commit_type = TDM_COMMIT_TYPE_LAYER; + } + + if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + TDM_ERR("layer(%p)'s output(%d) dpms: %s", layer, private_output->pipe, + tdm_dpms_str(private_output->current_dpms_value)); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_DPMS_OFF; + } + + ret = _tdm_layer_commit(private_layer, func, user_data); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_is_committing(tdm_layer *layer, unsigned int *committing) +{ + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(committing != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *committing = private_layer->committing; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tbm_surface_h +tdm_layer_get_displaying_buffer(tdm_layer *layer, tdm_error *error) +{ + tbm_surface_h buffer; + LAYER_FUNC_ENTRY_ERROR(); + + _pthread_mutex_lock(&private_display->lock); + + if (error) + *error = TDM_ERROR_NONE; + + if (private_layer->showing_buffer) { + buffer = private_layer->showing_buffer->buffer; + } else { + if (error) + *error = TDM_ERROR_OPERATION_FAILED; + _pthread_mutex_unlock(&private_display->lock); + TDM_DBG("layer(%p) showing_buffer is null", private_layer); + return NULL; + } + _pthread_mutex_unlock(&private_display->lock); + + return buffer; +} + +static void +_tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data) +{ + TDM_RETURN_IF_FAIL(data != NULL); + tdm_layer *layer = data; + tdm_func_layer *func_layer; + tbm_surface_h surface = NULL; + tdm_private_layer_buffer *layer_buffer; + LAYER_FUNC_ENTRY_VOID_RETURN(); + + _pthread_mutex_lock(&private_display->lock); + + func_layer = &private_display->func_layer; + if (!func_layer->layer_set_buffer) { + _pthread_mutex_unlock(&private_display->lock); + return; + } + + layer_buffer = calloc(1, sizeof(tdm_private_layer_buffer)); + if (!layer_buffer) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("alloc failed"); + return; + } + LIST_INITHEAD(&layer_buffer->link); + + if (TBM_SURFACE_QUEUE_ERROR_NONE != tbm_surface_queue_acquire(private_layer->buffer_queue, &surface) || + surface == NULL) { + TDM_ERR("layer(%p) tbm_surface_queue_acquire() failed surface:%p", + private_layer, surface); + _pthread_mutex_unlock(&private_display->lock); + free(layer_buffer); + return; + } + + ret = func_layer->layer_set_buffer(private_layer->layer_backend, surface); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + if (ret == TDM_ERROR_NONE) { + if (private_layer->waiting_buffer) { + TDM_DBG("layer(%p) drop waiting_buffer(%p)", private_layer, private_layer->waiting_buffer->buffer); + _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); + } + + private_layer->waiting_buffer = layer_buffer; + private_layer->waiting_buffer->buffer = tdm_buffer_ref_backend(surface); + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) waiting_buffer(%p)", + private_layer, private_layer->waiting_buffer->buffer); + + if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) { + ret = tdm_output_commit_internal(private_layer->private_output, 0, NULL, NULL); + if (ret != TDM_ERROR_NONE) + TDM_ERR("tdm_output_commit_internal() is fail"); + } else if (private_display->commit_type == TDM_COMMIT_TYPE_LAYER) { + ret = _tdm_layer_commit(private_layer, NULL, NULL); + if (ret != TDM_ERROR_NONE) + TDM_ERR("layer(%p) _tdm_layer_commit() is fail", private_layer); + } else { + TDM_NEVER_GET_HERE(); + } + } else + _tdm_layer_free_buffer(private_layer, layer_buffer); + + _pthread_mutex_unlock(&private_display->lock); +} + +static void +_tbm_layer_queue_destroy_cb(tbm_surface_queue_h surface_queue, void *data) +{ + TDM_RETURN_IF_FAIL(data != NULL); + tdm_layer *layer = data; + LAYER_FUNC_ENTRY_VOID_RETURN(); + TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); + + _pthread_mutex_lock(&private_display->lock); + + private_layer->buffer_queue = NULL; + + _tdm_layer_free_all_buffers(private_layer); + + _pthread_mutex_unlock(&private_display->lock); +} + +EXTERN tdm_error +tdm_layer_set_buffer_queue(tdm_layer *layer, tbm_surface_queue_h buffer_queue) +{ + tdm_func_layer *func_layer; + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(buffer_queue != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + func_layer = &private_display->func_layer; + + if (private_layer->usable) + TDM_INFO("layer(%p) not usable", private_layer); + + private_layer->usable = 0; + + if (!func_layer->layer_set_buffer) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + if (buffer_queue == private_layer->buffer_queue) { + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_NONE; + } + + if (private_layer->waiting_buffer) { + _tdm_layer_free_buffer(private_layer, private_layer->waiting_buffer); + private_layer->waiting_buffer = NULL; + + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) waiting_buffer(%p)", + private_layer, private_layer->waiting_buffer); + } + + private_layer->buffer_queue = buffer_queue; + tbm_surface_queue_add_acquirable_cb(private_layer->buffer_queue, + _tbm_layer_queue_acquirable_cb, + private_layer); + tbm_surface_queue_add_destroy_cb(private_layer->buffer_queue, + _tbm_layer_queue_destroy_cb, + private_layer); + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_unset_buffer_queue(tdm_layer *layer) +{ + return tdm_layer_unset_buffer(layer); +} + +EXTERN tdm_error +tdm_layer_is_usable(tdm_layer *layer, unsigned int *usable) +{ + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(usable != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *usable = private_layer->usable; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_layer_set_video_pos(tdm_layer *layer, int zpos) +{ + tdm_func_layer *func_layer; + LAYER_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + func_layer = &private_display->func_layer; + + if (!(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) { + TDM_ERR("layer(%p) is not video layer", private_layer); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_INVALID_PARAMETER; + } + + if (!func_layer->layer_set_video_pos) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_layer->layer_set_video_pos(private_layer->layer_backend, zpos); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_capture * +tdm_layer_create_capture(tdm_layer *layer, tdm_error *error) +{ + tdm_capture *capture = NULL; + + LAYER_FUNC_ENTRY_ERROR(); + + _pthread_mutex_lock(&private_display->lock); + + capture = (tdm_capture *)tdm_capture_create_layer_internal(private_layer, error); + + _pthread_mutex_unlock(&private_display->lock); + + return capture; +} + +EXTERN tdm_error +tdm_layer_get_buffer_flags(tdm_layer *layer, unsigned int *flags) +{ + tdm_func_layer *func_layer; + LAYER_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + func_layer = &private_display->func_layer; + + if (!func_layer->layer_get_buffer_flags) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_layer->layer_get_buffer_flags(private_layer->layer_backend, flags); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} diff --git a/src/tdm_output.c b/src/tdm_output.c new file mode 100644 index 0000000..3f077c2 --- /dev/null +++ b/src/tdm_output.c @@ -0,0 +1,1166 @@ +/************************************************************************** + * + * libtdm + * + * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: Eunchul Kim , + * JinYoung Jeon , + * Taeheon Kim , + * YoungJun Cho , + * SooChan Lim , + * Boram Park + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm.h" +#include "tdm_backend.h" +#include "tdm_private.h" +#include "tdm_helper.h" + +#define COUNT_MAX 10 + +#define OUTPUT_FUNC_ENTRY() \ + tdm_private_display *private_display; \ + tdm_private_output *private_output; \ + tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); \ + private_output = (tdm_private_output*)output; \ + private_display = private_output->private_display + +#define OUTPUT_FUNC_ENTRY_ERROR() \ + tdm_private_display *private_display; \ + tdm_private_output *private_output; \ + tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\ + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(output != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \ + private_output = (tdm_private_output*)output; \ + private_display = private_output->private_display + +EXTERN tdm_error +tdm_output_get_model_info(tdm_output *output, const char **maker, + const char **model, const char **name) +{ + OUTPUT_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + if (maker) + *maker = private_output->caps.maker; + if (model) + *model = private_output->caps.model; + if (name) + *name = private_output->caps.name; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_capabilities(tdm_output *output, tdm_output_capability *capabilities) +{ + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *capabilities = private_output->caps.capabilities; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_conn_status(tdm_output *output, tdm_output_conn_status *status) +{ + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *status = private_output->caps.status; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +static void +_tdm_output_update(tdm_output *output_backend, void *user_data) +{ + tdm_private_display *private_display; + tdm_private_output *private_output = user_data; + tdm_error ret; + + TDM_RETURN_IF_FAIL(private_output); + + private_display = private_output->private_display; + + ret = tdm_display_update_output(private_display, output_backend, private_output->pipe); + TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); +} + +INTERN void +tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status, + void *user_data) +{ + tdm_private_display *private_display; + tdm_private_output *private_output = user_data; + tdm_value value; + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + TDM_RETURN_IF_FAIL(private_output); + + private_display = private_output->private_display; + + if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { + tdm_thread_cb_output_status output_status; + tdm_error ret; + + _tdm_output_update(output_backend, user_data); + + output_status.base.type = TDM_THREAD_CB_OUTPUT_STATUS; + output_status.base.length = sizeof output_status; + output_status.output_stamp = private_output->stamp; + output_status.status = status; + output_status.user_data = user_data; + + value.u32 = status; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_sub, + TDM_OUTPUT_CHANGE_CONNECTION, + value, 0); + + ret = tdm_thread_send_cb(private_display->private_loop, &output_status.base); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + return; + } + + if (!tdm_thread_is_running()) + _tdm_output_update(output_backend, user_data); + + value.u32 = status; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_main, + TDM_OUTPUT_CHANGE_CONNECTION, + value, 0); +} + +EXTERN tdm_error +tdm_output_add_change_handler(tdm_output *output, + tdm_output_change_handler func, + void *user_data) +{ + tdm_private_change_handler *change_handler; + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + + pthread_mutex_lock(&private_display->lock); + + change_handler = calloc(1, sizeof(tdm_private_change_handler)); + if (!change_handler) { + TDM_ERR("failed: alloc memory"); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_OUT_OF_MEMORY; + } + + change_handler->private_output = private_output; + change_handler->func = func; + change_handler->user_data = user_data; + change_handler->owner_tid = syscall(SYS_gettid); + + if (!tdm_thread_in_display_thread(change_handler->owner_tid)) + LIST_ADDTAIL(&change_handler->link, &private_output->change_handler_list_sub); + else + LIST_ADDTAIL(&change_handler->link, &private_output->change_handler_list_main); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN void +tdm_output_remove_change_handler(tdm_output *output, + tdm_output_change_handler func, + void *user_data) +{ + tdm_private_display *private_display; + tdm_private_output *private_output; + tdm_private_change_handler *h = NULL, *hh = NULL; + + TDM_RETURN_IF_FAIL(output != NULL); + TDM_RETURN_IF_FAIL(func != NULL); + + private_output = (tdm_private_output*)output; + private_display = private_output->private_display; + + _pthread_mutex_lock(&private_display->lock); + + LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) { + if (h->func != func || h->user_data != user_data) + continue; + + LIST_DEL(&h->link); + free(h); + + _pthread_mutex_unlock(&private_display->lock); + + return; + } + + LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) { + if (h->func != func || h->user_data != user_data) + continue; + + LIST_DEL(&h->link); + free(h); + + _pthread_mutex_unlock(&private_display->lock); + + return; + } + + _pthread_mutex_unlock(&private_display->lock); +} + +EXTERN tdm_error +tdm_output_get_output_type(tdm_output *output, tdm_output_type *type) +{ + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(type != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *type = private_output->caps.type; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_layer_count(tdm_output *output, int *count) +{ + tdm_private_layer *private_layer = NULL; + + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *count = 0; + LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) + (*count)++; + if (*count == 0) { + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_NONE; + } + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + + +EXTERN tdm_layer * +tdm_output_get_layer(tdm_output *output, int index, tdm_error *error) +{ + tdm_private_layer *private_layer = NULL; + + OUTPUT_FUNC_ENTRY_ERROR(); + + _pthread_mutex_lock(&private_display->lock); + + if (error) + *error = TDM_ERROR_NONE; + + LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { + if (private_layer->index == index) { + _pthread_mutex_unlock(&private_display->lock); + return private_layer; + } + } + + _pthread_mutex_unlock(&private_display->lock); + + return NULL; +} + +EXTERN tdm_error +tdm_output_get_available_properties(tdm_output *output, const tdm_prop **props, + int *count) +{ + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *props = (const tdm_prop *)private_output->caps.props; + *count = private_output->caps.prop_count; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_available_modes(tdm_output *output, + const tdm_output_mode **modes, int *count) +{ + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *modes = (const tdm_output_mode *)private_output->caps.modes; + *count = private_output->caps.mode_count; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_available_size(tdm_output *output, int *min_w, int *min_h, + int *max_w, int *max_h, int *preferred_align) +{ + OUTPUT_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + if (min_w) + *min_w = TDM_FRONT_VALUE(private_output->caps.min_w); + if (min_h) + *min_h = TDM_FRONT_VALUE(private_output->caps.min_h); + if (max_w) + *max_w = TDM_FRONT_VALUE(private_output->caps.max_w); + if (max_h) + *max_h = TDM_FRONT_VALUE(private_output->caps.max_h); + if (preferred_align) + *preferred_align = TDM_FRONT_VALUE(private_output->caps.preferred_align); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_cursor_available_size(tdm_output *output, int *min_w, int *min_h, + int *max_w, int *max_h, int *preferred_align) +{ + OUTPUT_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + if (!tdm_display_check_module_abi(private_display, 1, 5)) { + + if (min_w) + *min_w = -1; + if (min_h) + *min_h = -1; + if (max_w) + *max_w = -1; + if (max_h) + *max_h = -1; + if (preferred_align) + *preferred_align = -1; + + _pthread_mutex_unlock(&private_display->lock); + + return TDM_ERROR_BAD_MODULE; + } + + if (min_w) + *min_w = TDM_FRONT_VALUE(private_output->caps.cursor_min_w); + if (min_h) + *min_h = TDM_FRONT_VALUE(private_output->caps.cursor_min_h); + if (max_w) + *max_w = TDM_FRONT_VALUE(private_output->caps.cursor_max_w); + if (max_h) + *max_h = TDM_FRONT_VALUE(private_output->caps.cursor_max_h); + if (preferred_align) + *preferred_align = TDM_FRONT_VALUE(private_output->caps.cursor_preferred_align); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_physical_size(tdm_output *output, unsigned int *mmWidth, + unsigned int *mmHeight) +{ + OUTPUT_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + if (mmWidth) + *mmWidth = private_output->caps.mmWidth; + if (mmHeight) + *mmHeight = private_output->caps.mmHeight; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_subpixel(tdm_output *output, unsigned int *subpixel) +{ + OUTPUT_FUNC_ENTRY(); + TDM_RETURN_VAL_IF_FAIL(subpixel != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *subpixel = private_output->caps.subpixel; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_pipe(tdm_output *output, unsigned int *pipe) +{ + OUTPUT_FUNC_ENTRY(); + TDM_RETURN_VAL_IF_FAIL(pipe != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *pipe = private_output->pipe; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_primary_index(tdm_output *output, int *index) +{ + tdm_private_layer *private_layer = NULL; + + OUTPUT_FUNC_ENTRY(); + TDM_RETURN_VAL_IF_FAIL(index != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { + if (private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_PRIMARY) { + *index = private_layer->index; + break; + } + } + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_set_property(tdm_output *output, unsigned int id, tdm_value value) +{ + tdm_func_output *func_output; + OUTPUT_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + func_output = &private_display->func_output; + + if (!func_output->output_set_property) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_output->output_set_property(private_output->output_backend, id, + value); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value) +{ + tdm_func_output *func_output; + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(value != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + func_output = &private_display->func_output; + + if (!func_output->output_get_property) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_output->output_get_property(private_output->output_backend, id, + value); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +INTERN void +tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) +{ + tdm_private_vblank_handler *vblank_handler = user_data; + tdm_private_vblank_handler *v = NULL, *vv = NULL; + tdm_private_output *private_output; + tdm_private_display *private_display; + struct list_head clone_list; + int interval, sync; + pid_t tid = syscall(SYS_gettid); + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + TDM_RETURN_IF_FAIL(vblank_handler); + + private_output = vblank_handler->private_output; + private_display = private_output->private_display; + + if (vblank_handler->owner_tid != tid) { + tdm_thread_cb_output_vblank output_vblank; + tdm_error ret; + + output_vblank.base.type = TDM_THREAD_CB_OUTPUT_VBLANK; + output_vblank.base.length = sizeof output_vblank; + output_vblank.output_stamp = vblank_handler->private_output->stamp; + output_vblank.sequence = sequence; + output_vblank.tv_sec = tv_sec; + output_vblank.tv_usec = tv_usec; + output_vblank.user_data = user_data; + + ret = tdm_thread_send_cb(private_display->private_loop, &output_vblank.base); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + return; + } + + if (vblank_handler->owner_tid != tid) + TDM_NEVER_GET_HERE(); + + interval = vblank_handler->interval; + sync = vblank_handler->sync; + + LIST_INITHEAD(&clone_list); + + LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) { + if (v->interval != interval || v->sync != sync || v->owner_tid != tid) + continue; + + LIST_DEL(&v->link); + LIST_ADDTAIL(&v->link, &clone_list); + } + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("----------------------------------------- output(%d) got vblank", private_output->pipe); + + _pthread_mutex_unlock(&private_display->lock); + LIST_FOR_EACH_ENTRY_SAFE(v, vv, &clone_list, link) { + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("handler(%p)", v); + + if (v->func) + v->func(v->private_output, sequence, tv_sec, tv_usec, v->user_data); + LIST_DEL(&v->link); + free(v); + } + _pthread_mutex_lock(&private_display->lock); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("-----------------------------------------..."); +} + +INTERN void +tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) +{ + tdm_private_output_commit_handler *output_commit_handler = user_data; + tdm_private_display *private_display; + tdm_private_output *private_output; + tdm_private_layer *private_layer = NULL; + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + + if (!output_commit_handler) + return; + + private_output = output_commit_handler->private_output; + private_display = private_output->private_display; + + if (output_commit_handler->owner_tid != syscall(SYS_gettid)) { + tdm_thread_cb_output_commit output_commit; + tdm_error ret; + + output_commit.base.type = TDM_THREAD_CB_OUTPUT_COMMIT; + output_commit.base.length = sizeof output_commit; + output_commit.output_stamp = private_output->stamp; + output_commit.sequence = sequence; + output_commit.tv_sec = tv_sec; + output_commit.tv_usec = tv_usec; + output_commit.user_data = user_data; + + ret = tdm_thread_send_cb(private_display->private_loop, &output_commit.base); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + return; + } + + if (tdm_debug_module & TDM_DEBUG_COMMIT) { + TDM_INFO("----------------------------------------- output(%d) committed", private_output->pipe); + TDM_INFO("handler(%p)", output_commit_handler); + } + + if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) { + /* In case of layer commit, the below will be handled in the layer commit callback */ + LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { + if (private_layer->committed_buffer) + tdm_layer_committed(private_layer, &private_layer->committed_buffer); + } + } + + if (output_commit_handler->func) { + _pthread_mutex_unlock(&private_display->lock); + output_commit_handler->func(private_output, sequence, + tv_sec, tv_usec, output_commit_handler->user_data); + _pthread_mutex_lock(&private_display->lock); + } + + LIST_DEL(&output_commit_handler->link); + free(output_commit_handler); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("-----------------------------------------..."); +} + +/* add_front: To distinguish between the user vblank handlers and the layer + * commit vblank handlers. The layer commit handlers will be called + * before calling the user vblank handlers. + */ +static tdm_error +_tdm_output_wait_vblank(tdm_output *output, int interval, int sync, + tdm_output_vblank_handler func, void *user_data, + unsigned int add_front) +{ + tdm_func_output *func_output; + tdm_private_vblank_handler *vblank_handler = NULL, *v = NULL; + unsigned int skip_request = 0; + pid_t tid = syscall(SYS_gettid); + + OUTPUT_FUNC_ENTRY(); + + func_output = &private_display->func_output; + + /* interval SHOULD be at least 1 */ + if (interval <= 0) + interval = 1; + + if (!func_output->output_wait_vblank) { + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + if (!private_output->regist_vblank_cb) { + private_output->regist_vblank_cb = 1; + ret = func_output->output_set_vblank_handler(private_output->output_backend, + tdm_output_cb_vblank); + } + + vblank_handler = calloc(1, sizeof(tdm_private_vblank_handler)); + if (!vblank_handler) { + TDM_ERR("failed: alloc memory"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("output(%d) wait_vblank: handler(%p)", private_output->pipe, vblank_handler); + + LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) { + if (v->interval == interval && v->sync == sync && v->owner_tid == tid) { + skip_request = 1; + break; + } + } + + if (add_front) + LIST_ADD(&vblank_handler->link, &private_output->vblank_handler_list); + else + LIST_ADDTAIL(&vblank_handler->link, &private_output->vblank_handler_list); + + vblank_handler->private_output = private_output; + vblank_handler->interval = interval; + vblank_handler->sync = sync; + vblank_handler->func = func; + vblank_handler->user_data = user_data; + vblank_handler->owner_tid = tid; + + /* If there is the previous request, we can skip to call output_wait_vblank() */ + if (!skip_request) { + ret = func_output->output_wait_vblank(private_output->output_backend, interval, + sync, vblank_handler); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("output(%d) backend wait_vblank", private_output->pipe); + } + + return ret; + +wait_failed: + if (vblank_handler) { + LIST_DEL(&vblank_handler->link); + free(vblank_handler); + } + return ret; +} + +EXTERN tdm_error +tdm_output_wait_vblank(tdm_output *output, int interval, int sync, + tdm_output_vblank_handler func, void *user_data) +{ + OUTPUT_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + TDM_WRN("output(%d) dpms: %s", private_output->pipe, + tdm_dpms_str(private_output->current_dpms_value)); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_DPMS_OFF; + } + + ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 0); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_wait_vblank_add_front(tdm_output *output, int interval, int sync, + tdm_output_vblank_handler func, void *user_data) +{ + OUTPUT_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + TDM_WRN("output(%d) dpms: %s", private_output->pipe, + tdm_dpms_str(private_output->current_dpms_value)); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_DPMS_OFF; + } + + ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 1); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +INTERN tdm_error +tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handler func, void *user_data) +{ + tdm_func_output *func_output; + tdm_private_output_commit_handler *output_commit_handler = NULL; + tdm_private_layer *private_layer = NULL; + + OUTPUT_FUNC_ENTRY(); + + func_output = &private_display->func_output; + + if (!func_output->output_commit) { + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + if (func) { + if (!private_output->regist_commit_cb) { + private_output->regist_commit_cb = 1; + ret = func_output->output_set_commit_handler(private_output->output_backend, + tdm_output_cb_commit); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); + } + + output_commit_handler = calloc(1, sizeof(tdm_private_output_commit_handler)); + if (!output_commit_handler) { + TDM_ERR("failed: alloc memory"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + LIST_ADDTAIL(&output_commit_handler->link, &private_output->output_commit_handler_list); + output_commit_handler->private_output = private_output; + output_commit_handler->func = func; + output_commit_handler->user_data = user_data; + output_commit_handler->owner_tid = syscall(SYS_gettid); + } + + ret = func_output->output_commit(private_output->output_backend, sync, + output_commit_handler); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("output(%d) backend commit: handle(%p)", private_output->pipe, output_commit_handler); + + LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { + if (!private_layer->waiting_buffer) + continue; + + private_layer->committed_buffer = private_layer->waiting_buffer; + private_layer->waiting_buffer = NULL; + if (tdm_debug_module & TDM_DEBUG_BUFFER) + TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)", + private_layer, private_layer->waiting_buffer, + private_layer->committed_buffer->buffer); + } + + return ret; + +commit_failed: + if (output_commit_handler) { + LIST_DEL(&output_commit_handler->link); + free(output_commit_handler); + } + return ret; +} + +EXTERN tdm_error +tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func, + void *user_data) +{ + OUTPUT_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + if (private_display->commit_type == TDM_COMMIT_TYPE_NONE) + private_display->commit_type = TDM_COMMIT_TYPE_OUTPUT; + else if (private_display->commit_type == TDM_COMMIT_TYPE_LAYER) { + TDM_ERR("Can't supported. Use tdm_layer_commit"); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_BAD_REQUEST; + } + + if (private_display->commit_per_vblank) { + TDM_ERR("Use tdm_layer_commit"); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_BAD_REQUEST; + } + + if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + TDM_ERR("output(%d) dpms: %s", private_output->pipe, + tdm_dpms_str(private_output->current_dpms_value)); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_DPMS_OFF; + } + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("output(%d) commit", private_output->pipe); + + ret = tdm_output_commit_internal(output, sync, func, user_data); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_set_mode(tdm_output *output, const tdm_output_mode *mode) +{ + tdm_func_output *func_output; + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + func_output = &private_display->func_output; + + if (!func_output->output_set_mode) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_output->output_set_mode(private_output->output_backend, mode); + if (ret == TDM_ERROR_NONE) + private_output->current_mode = mode; + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_mode(tdm_output *output, const tdm_output_mode **mode) +{ + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + *mode = private_output->current_mode; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +static tdm_error +_tdm_output_dpms_changed_timeout(void *user_data) +{ + tdm_private_output *private_output = user_data; + tdm_value value; + + value.u32 = private_output->current_dpms_value; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_sub, + TDM_OUTPUT_CHANGE_DPMS, + value, 0); + + return TDM_ERROR_NONE; +} + +INTERN void +tdm_output_cb_dpms(tdm_output *output_backend, tdm_output_dpms dpms, void *user_data) +{ + tdm_private_display *private_display; + tdm_private_output *private_output = user_data; + tdm_value value; + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + TDM_RETURN_IF_FAIL(private_output); + + private_display = private_output->private_display; + + if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { + tdm_thread_cb_output_dpms output_dpms; + tdm_error ret; + + _tdm_output_update(output_backend, user_data); + + output_dpms.base.type = TDM_THREAD_CB_OUTPUT_DPMS; + output_dpms.base.length = sizeof output_dpms; + output_dpms.output_stamp = private_output->stamp; + output_dpms.dpms = dpms; + output_dpms.user_data = user_data; + + value.u32 = dpms; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_sub, + TDM_OUTPUT_CHANGE_DPMS, + value, 0); + + ret = tdm_thread_send_cb(private_display->private_loop, &output_dpms.base); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + return; + } + + private_output->current_dpms_value = dpms; + + value.u32 = dpms; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_main, + TDM_OUTPUT_CHANGE_DPMS, + value, 0); +} + +EXTERN tdm_error +tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) +{ + tdm_func_output *func_output; + OUTPUT_FUNC_ENTRY(); + + if (dpms_value > TDM_OUTPUT_DPMS_OFF) + dpms_value = TDM_OUTPUT_DPMS_OFF; + + _pthread_mutex_lock(&private_display->lock); + + if (private_output->current_dpms_value == dpms_value) { + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_NONE; + } + + /** Use timer to call the output change callback of the sub-thread. + * The output change callback of tdm_server and tdm_vblank was called + * in the main thread. And it made the multi thread issue. If we use + * the timer, we can call the sub-thread's output change callback in + * sub-thread. + */ + if (!private_output->dpms_changed_timer) { + private_output->dpms_changed_timer = + tdm_event_loop_add_timer_handler(private_output->private_display, + _tdm_output_dpms_changed_timeout, private_output, NULL); + if (!private_output->dpms_changed_timer) { + TDM_ERR("can't create dpms timer!!"); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_OUT_OF_MEMORY; + } + } + + func_output = &private_display->func_output; + + if (!func_output->output_set_dpms) { + _pthread_mutex_unlock(&private_display->lock); + private_output->current_dpms_value = dpms_value; + TDM_WRN("not implemented!!"); + return TDM_ERROR_NONE; + } + + if (func_output->output_set_dpms_handler) { + if (!private_output->regist_dpms_cb) { + private_output->regist_dpms_cb = 1; + ret = func_output->output_set_dpms_handler(private_output->output_backend, + tdm_output_cb_dpms, private_output); + if (ret != TDM_ERROR_NONE) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("Can't set the dpms handler!!"); + return ret; + } + } + } + + ret = func_output->output_set_dpms(private_output->output_backend, dpms_value); + + if (ret == TDM_ERROR_NONE && !func_output->output_set_dpms_handler) { + tdm_value value; + + private_output->current_dpms_value = dpms_value; + + value.u32 = dpms_value; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_main, + TDM_OUTPUT_CHANGE_DPMS, + value, 0); + + if (!LIST_IS_EMPTY(&private_output->change_handler_list_sub)) { + ret = tdm_event_loop_source_timer_update(private_output->dpms_changed_timer, 1); + if (ret != TDM_ERROR_NONE) + TDM_NEVER_GET_HERE(); + } + } + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value) +{ + tdm_func_output *func_output; + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(dpms_value != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + func_output = &private_display->func_output; + + if (!func_output->output_get_dpms) { + *dpms_value = private_output->current_dpms_value; + _pthread_mutex_unlock(&private_display->lock); + TDM_WRN("not implemented!!"); + return TDM_ERROR_NONE; + } + + ret = func_output->output_get_dpms(private_output->output_backend, dpms_value); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_capture * +tdm_output_create_capture(tdm_output *output, tdm_error *error) +{ + tdm_capture *capture = NULL; + + OUTPUT_FUNC_ENTRY_ERROR(); + + _pthread_mutex_lock(&private_display->lock); + + capture = (tdm_capture *)tdm_capture_create_output_internal(private_output, error); + + _pthread_mutex_unlock(&private_display->lock); + + return capture; +} + +INTERN void +tdm_output_call_change_handler_internal(tdm_private_output *private_output, + struct list_head *change_handler_list, + tdm_output_change_type type, + tdm_value value, + int no_check_thread_id) +{ + tdm_private_display *private_display; + tdm_private_change_handler *change_handler = NULL; + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + TDM_RETURN_IF_FAIL(private_output); + + private_display = private_output->private_display; + if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { + if (type & TDM_OUTPUT_CHANGE_CONNECTION) + TDM_INFO("output(%d) changed: %s (%d)", + private_output->pipe, tdm_status_str(value.u32), value.u32); + if (type & TDM_OUTPUT_CHANGE_DPMS) + TDM_INFO("output(%d) changed: dpms %s (%d)", + private_output->pipe, tdm_dpms_str(value.u32), value.u32); + } + + if (LIST_IS_EMPTY(change_handler_list)) + return; + + LIST_FOR_EACH_ENTRY(change_handler, change_handler_list, link) { + if (!no_check_thread_id && change_handler->owner_tid != syscall(SYS_gettid)) + TDM_NEVER_GET_HERE(); + + _pthread_mutex_unlock(&private_display->lock); + change_handler->func(private_output, type, + value, change_handler->user_data); + _pthread_mutex_lock(&private_display->lock); + } +} diff --git a/src/tdm_private.h b/src/tdm_private.h index 3e64429..6d9f7c9 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -421,6 +421,10 @@ tdm_output_cb_dpms(tdm_output *output_backend, tdm_output_dpms dpms, tdm_error tdm_output_wait_vblank_add_front(tdm_output *output, int interval, int sync, tdm_output_vblank_handler func, void *user_data); +tdm_error +tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handler func, void *user_data); +void +tdm_layer_committed(tdm_private_layer *private_layer, tdm_private_layer_buffer **committed_buffer); void tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst, -- 2.7.4 From 6bc6f9f27ff2d1aebd7d770c496d4cfdafe78bd6 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 10 Feb 2017 14:43:05 +0900 Subject: [PATCH 10/16] package version up to 1.6.6 Change-Id: If839d522bcc6a67723cc2eafd5941634d8bfda9c --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 9e2fba3..1433b20 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %bcond_with utest Name: libtdm -Version: 1.6.5 +Version: 1.6.6 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From 0ac6c1319b8381fafff61433a5033d097d0d1d08 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 15 Feb 2017 16:26:24 +0900 Subject: [PATCH 11/16] debug: enhance debug information for mutex lock/unlock Change-Id: I0ec99252d2a71d5f770fe3ecb8ce803df74c1c75 --- src/tdm.c | 2 ++ src/tdm_private.h | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/tdm.c b/src/tdm.c index 924c54c..242910a 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -46,6 +46,8 @@ pthread_mutex_t tdm_mutex_check_lock = PTHREAD_MUTEX_INITIALIZER; int tdm_mutex_locked; const char *tdm_mutex_lock_func; int tdm_mutex_lock_line; +const char *tdm_mutex_unlock_func; +int tdm_mutex_unlock_line; static tdm_private_layer * _tdm_display_find_private_layer(tdm_private_output *private_output, diff --git a/src/tdm_private.h b/src/tdm_private.h index 6d9f7c9..6fb44fd 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -586,6 +586,8 @@ extern pthread_mutex_t tdm_mutex_check_lock; extern int tdm_mutex_locked; extern const char *tdm_mutex_lock_func; extern int tdm_mutex_lock_line; +extern const char *tdm_mutex_unlock_func; +extern int tdm_mutex_unlock_line; extern int tdm_dump_enable; extern char *tdm_debug_dump_dir; @@ -597,6 +599,8 @@ extern char *tdm_debug_dump_dir; tdm_mutex_locked = 0; \ tdm_mutex_lock_func = NULL; \ tdm_mutex_lock_line = 0; \ + tdm_mutex_unlock_func = __FUNCTION__; \ + tdm_mutex_unlock_line = __LINE__; \ pthread_mutex_unlock(&tdm_mutex_check_lock); \ pthread_mutex_unlock(l); \ } while (0) @@ -618,6 +622,8 @@ extern char *tdm_debug_dump_dir; tdm_mutex_locked = 1; \ tdm_mutex_lock_func = __FUNCTION__; \ tdm_mutex_lock_line = __LINE__; \ + tdm_mutex_unlock_func = NULL; \ + tdm_mutex_unlock_line = 0; \ pthread_mutex_unlock(&tdm_mutex_check_lock); \ } \ } while (0) @@ -631,6 +637,8 @@ extern char *tdm_debug_dump_dir; tdm_mutex_locked = 1; \ tdm_mutex_lock_func = __FUNCTION__; \ tdm_mutex_lock_line = __LINE__; \ + tdm_mutex_unlock_func = NULL; \ + tdm_mutex_unlock_line = 0; \ pthread_mutex_unlock(&tdm_mutex_check_lock); \ } while (0) #endif //TDM_CONFIG_MUTEX_TIMEOUT -- 2.7.4 From 91aae257ad384e82b6ce6ad38e0ba61048fb9ae1 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 15 Feb 2017 16:29:05 +0900 Subject: [PATCH 12/16] mutex: don't use the tdm macros for gLock variable. When _pthread_mutex_unlock macro, tdm_mutex_locked becomes 0. Then, TDM_MUTEX_IS_LOCKED return 0 even though display->lock is locked. TDM_MUTEX_IS_LOCKED actually is for display->lock. Change-Id: Idd4f638b84c0d244de61404e08ee4dfcf81921a2 --- src/tdm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tdm.c b/src/tdm.c index 242910a..9baace2 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -891,11 +891,11 @@ tdm_display_init(tdm_error *error) tdm_error ret; double stamp1, stamp2, start; - _pthread_mutex_lock(&gLock); + pthread_mutex_lock(&gLock); if (g_private_display) { g_private_display->init_count++; - _pthread_mutex_unlock(&gLock); + pthread_mutex_unlock(&gLock); if (error) *error = TDM_ERROR_NONE; return g_private_display; @@ -997,7 +997,7 @@ tdm_display_init(tdm_error *error) *error = TDM_ERROR_NONE; _pthread_mutex_unlock(&private_display->lock); - _pthread_mutex_unlock(&gLock); + pthread_mutex_unlock(&gLock); TDM_INFO("init time: %.3f ms", (tdm_helper_get_time() - start) * 1000.0); @@ -1015,7 +1015,7 @@ failed_mutex_init: failed_alloc: if (error) *error = ret; - _pthread_mutex_unlock(&gLock); + pthread_mutex_unlock(&gLock); return NULL; } @@ -1027,11 +1027,11 @@ tdm_display_deinit(tdm_display *dpy) if (!private_display) return; - _pthread_mutex_lock(&gLock); + pthread_mutex_lock(&gLock); private_display->init_count--; if (private_display->init_count > 0) { - _pthread_mutex_unlock(&gLock); + pthread_mutex_unlock(&gLock); return; } @@ -1062,7 +1062,7 @@ tdm_display_deinit(tdm_display *dpy) tdm_debug_dump_dir = NULL; } - _pthread_mutex_unlock(&gLock); + pthread_mutex_unlock(&gLock); TDM_INFO("done"); } -- 2.7.4 From 9595289e9edc0cac2662282a5cf3dac8eac9fd36 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 15 Feb 2017 21:09:46 +0900 Subject: [PATCH 13/16] vblank: move the set-client-vblank-fps function to server function Change-Id: Iaca45f4daa29c1d070f976f011633a10f2e3483d --- client/tdm_client.c | 19 -------- client/tdm_client.h | 11 ----- include/tdm.h | 10 ++++ src/tdm_monitor_server.c | 4 +- src/tdm_private.h | 11 +++-- src/tdm_server.c | 107 ++----------------------------------------- src/tdm_vblank.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++- tools/tdm_test_client.c | 43 ------------------ 8 files changed, 136 insertions(+), 185 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index bdab4c0..504c119 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -426,25 +426,6 @@ tdm_client_wait_vblank(tdm_client *client, char *name, return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp); } -tdm_error -tdm_client_set_client_vblank_fps(tdm_client *client, pid_t pid, const char *name, unsigned int fps) -{ - tdm_private_client *private_client = (tdm_private_client*)client; - - TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(pid > 0, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); - - if (!name) - name = TDM_VBLANK_DEFAULT_NAME; - - wl_tdm_set_client_vblank_fps(private_client->tdm, pid, name, fps); - - wl_display_flush(private_client->display); - - return TDM_ERROR_NONE; -} - tdm_client_output* tdm_client_get_output(tdm_client *client, char *name, tdm_error *error) { diff --git a/client/tdm_client.h b/client/tdm_client.h index 5cb1cce..8a2fcd0 100644 --- a/client/tdm_client.h +++ b/client/tdm_client.h @@ -138,17 +138,6 @@ tdm_client_wait_vblank(tdm_client *client, char *name, tdm_client_vblank_handler2 func, void *user_data); /** - * @brief Set the client vblank fps for the given PID and name. - * @param[in] client A TDM client object - * @param[in] pid The process ID - * @param[in] name The client vblank name - * @param[in] fps The client vblank fps - * @return #TDM_ERROR_NONE if success. Otherwise, error value. - */ -tdm_error -tdm_client_set_client_vblank_fps(tdm_client *client, pid_t pid, const char *name, unsigned int fps); - -/** * @brief Get the client output object which has the given name. * @details * The client output name can be @b 'primary' or @b 'default' to get the main output. diff --git a/include/tdm.h b/include/tdm.h index ebb8f4f..91cabef 100644 --- a/include/tdm.h +++ b/include/tdm.h @@ -884,6 +884,16 @@ typedef void (*tdm_vblank_handler)(tdm_vblank *vblank, tdm_error error, unsigned unsigned int tv_sec, unsigned int tv_usec, void *user_data); /** + * @brief Set the vblank fps for the given PID and name. + * @param[in] pid The process ID + * @param[in] name The client vblank name + * @param[in] fps The client vblank fps + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps); + +/** * @brief Create a vblank object * @param[in] dpy A display object * @param[in] output A output object diff --git a/src/tdm_monitor_server.c b/src/tdm_monitor_server.c index 1916e4a..d12a9eb 100644 --- a/src/tdm_monitor_server.c +++ b/src/tdm_monitor_server.c @@ -244,7 +244,7 @@ static void _tdm_monitor_server_vblank_list(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy) { - tdm_server_get_vblank_list_information(dpy, reply, len); + tdm_vblank_get_vblank_list_information(dpy, reply, len); } static void @@ -281,7 +281,7 @@ _tdm_monitor_server_vblank_fps(unsigned int pid, char *cwd, int argc, char *argv arg = end + 1; fps = strtol(arg, &end, 10); - ret = tdm_server_set_client_vblank_fps(target_pid, name, fps); + ret = tdm_vblank_set_client_vblank_fps(target_pid, name, fps); if (ret != TDM_ERROR_NONE) { TDM_SNPRINTF(reply, len, "can't set '%u' fps to '%s' client vblank(PID:%u)\n", fps, name, target_pid); return; diff --git a/src/tdm_private.h b/src/tdm_private.h index 6fb44fd..8279903 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -54,6 +54,7 @@ #include #include +#include #include #include @@ -436,6 +437,12 @@ tdm_error tdm_vblank_cb_vblank_SW(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); +tdm_error +tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps); +void +tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len); void tdm_output_call_change_handler_internal(tdm_private_output *private_output, @@ -570,10 +577,6 @@ tdm_error tdm_server_init(tdm_private_loop *private_loop); void tdm_server_deinit(tdm_private_loop *private_loop); -tdm_error -tdm_server_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps); -void -tdm_server_get_vblank_list_information(tdm_display *dpy, char *reply, int *len); char * tdm_helper_dump_make_directory(const char *path, char *reply, int *len); diff --git a/src/tdm_server.c b/src/tdm_server.c index bb2a7c3..f803a0b 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -67,8 +67,6 @@ typedef struct _tdm_server_output_info { typedef struct _tdm_server_vblank_info { struct list_head link; - struct list_head valid_link; - tdm_server_output_info *output_info; struct wl_resource *resource; @@ -83,7 +81,6 @@ typedef struct _tdm_server_wait_info { } tdm_server_wait_info; static tdm_private_server *keep_private_server; -static struct list_head valid_vblank_list; static void destroy_wait(tdm_server_wait_info *wait_info); @@ -205,8 +202,6 @@ destroy_vblank_callback(struct wl_resource *resource) } LIST_DEL(&vblank_info->link); - LIST_DEL(&vblank_info->valid_link); - free(vblank_info); } @@ -385,12 +380,12 @@ _tdm_server_output_cb_create_vblank(struct wl_client *client, struct wl_resource } LIST_ADDTAIL(&vblank_info->link, &output_info->vblank_list); - LIST_ADDTAIL(&vblank_info->valid_link, &valid_vblank_list); - vblank_info->output_info = output_info; vblank_info->resource = vblank_resource; vblank_info->vblank = vblank; + tdm_vblank_set_resource(vblank, vblank_resource); + wl_resource_set_implementation(vblank_resource, &tdm_vblank_implementation, vblank_info, destroy_vblank_callback); @@ -510,7 +505,7 @@ 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_server_set_client_vblank_fps(pid, name, 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); @@ -569,8 +564,6 @@ tdm_server_init(tdm_private_loop *private_loop) return TDM_ERROR_OUT_OF_MEMORY; } - LIST_INITHEAD(&valid_vblank_list); - private_server->private_loop = private_loop; private_loop->private_server = private_server; keep_private_server = private_server; @@ -603,97 +596,3 @@ tdm_server_deinit(tdm_private_loop *private_loop) keep_private_server = NULL; } -INTERN tdm_error -tdm_server_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps) -{ - tdm_server_vblank_info *v; - - TDM_RETURN_VAL_IF_FAIL(pid > 0, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); - - LIST_FOR_EACH_ENTRY(v, &valid_vblank_list, valid_link) { - struct wl_client *client = wl_resource_get_client(v->resource); - pid_t client_pid = 0; - const char *vblank_name = NULL; - - if (!client) - continue; - - wl_client_get_credentials(client, &client_pid, NULL, NULL); - - if (client_pid != pid) - continue; - - if (name && strncmp(name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN)) { - tdm_vblank_get_name(v->vblank, &vblank_name); - if (strncmp(vblank_name, name, TDM_NAME_LEN)) - continue; - } - - tdm_vblank_set_fps(v->vblank, fps); - } - - return TDM_ERROR_NONE; -} - -static void -_tdm_server_get_process_name(pid_t pid, char *name, unsigned int size) -{ - char proc[TDM_NAME_LEN], pname[TDM_NAME_LEN]; - FILE *h; - size_t len; - - snprintf(proc, TDM_NAME_LEN, "/proc/%d/cmdline", pid); - h = fopen(proc, "r"); - if (!h) - return; - - len = fread(pname, sizeof(char), TDM_NAME_LEN, h); - if (len == 0) { - char *p = strncpy(pname, "NO NAME", sizeof(pname) - 1); - len = p - pname; - } - pname[len - 1] = '\0'; - - strncpy(name, pname, size - 1); - name[size - 1] = '\0'; - - fclose(h); -} - -INTERN void -tdm_server_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) -{ - tdm_server_vblank_info *v; - - TDM_SNPRINTF(reply, len, "[Client Vblank List]\n"); - TDM_SNPRINTF(reply, len, "---------------------------------------------------------------\n"); - TDM_SNPRINTF(reply, len, "name fps offset fake process\n"); - TDM_SNPRINTF(reply, len, "---------------------------------------------------------------\n"); - - LIST_FOR_EACH_ENTRY(v, &valid_vblank_list, valid_link) { - struct wl_client *client = wl_resource_get_client(v->resource); - const char *vbl_name = NULL; - char proc_name[TDM_NAME_LEN]; - unsigned int fps = 0, fake = 0; - int offset = 0; - pid_t pid = 0; - - tdm_vblank_get_name(v->vblank, &vbl_name); - tdm_vblank_get_fps(v->vblank, &fps); - tdm_vblank_get_offset(v->vblank, &offset); - tdm_vblank_get_enable_fake(v->vblank, &fake); - - snprintf(proc_name, TDM_NAME_LEN, "Unknown"); - if (client) { - wl_client_get_credentials(client, &pid, NULL, NULL); - _tdm_server_get_process_name(pid, proc_name, TDM_NAME_LEN); - } - - TDM_SNPRINTF(reply, len, "%-12s %u %d %u %s (pid: %u)\n", - vbl_name, fps, offset, fake, proc_name, pid); - } - - TDM_SNPRINTF(reply, len, "\n"); -} - diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index b9ce1ab..c3c1c23 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -42,9 +42,11 @@ #include "tdm_list.h" /* CAUTION: - * tdm vblank doesn't care about thread things. + * Basically tdm vblank doesn't care about thread things. * However, to use tdm_event_loop_xxx functions, have to use the internal function. - * So need to lock/unlock the mutex of private_display. + * So need to lock/unlock the mutex of private_display. And valid_vblank_list and + * valid_wait_list should be protected by valid_list_lock because tdm_vblank can + * be used in multi-thread. */ /* TDM vblank @@ -103,6 +105,7 @@ typedef struct _tdm_private_vblank { double last_time; unsigned int add_front; + struct wl_resource *resource; /* for HW */ double HW_vblank_gap; @@ -322,6 +325,47 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, } } +EXTERN tdm_error +tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps) +{ + tdm_private_vblank *v; + + TDM_RETURN_VAL_IF_FAIL(pid > 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); + + TDM_INFO("pid: %u, name: %s, fps: %d", pid, name, fps); + + pthread_mutex_lock(&valid_list_lock); + LIST_FOR_EACH_ENTRY(v, &valid_vblank_list, valid_link) { + struct wl_client *client; + pid_t client_pid = 0; + + if (!v->resource) + continue; + + client = wl_resource_get_client(v->resource); + if (!client) + continue; + + wl_client_get_credentials(client, &client_pid, NULL, NULL); + + if (client_pid != pid) + continue; + + if (name && strncmp(name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN)) { + if (strncmp(v->name, name, TDM_NAME_LEN)) + continue; + } + + tdm_vblank_set_fps(v, fps); + + TDM_INFO("(pid:%u) '%s' fps changed: %d", pid, v->name, fps); + } + pthread_mutex_unlock(&valid_list_lock); + + return TDM_ERROR_NONE; +} + EXTERN tdm_vblank * tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) { @@ -1046,3 +1090,71 @@ tdm_vblank_set_add_front(tdm_vblank *vblank, unsigned int add_front) return TDM_ERROR_NONE; } +INTERN tdm_error +tdm_vblank_set_resource(tdm_vblank *vblank, struct wl_resource *resource) +{ + tdm_private_vblank *private_vblank = vblank; + + TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(private_vblank->resource == NULL, TDM_ERROR_OPERATION_FAILED); + + private_vblank->resource = resource; + + return TDM_ERROR_NONE; +} + +static void +_tdm_vblank_get_process_name(pid_t pid, char *name, unsigned int size) +{ + char proc[TDM_NAME_LEN], pname[TDM_NAME_LEN]; + FILE *h; + size_t len; + + snprintf(proc, TDM_NAME_LEN, "/proc/%d/cmdline", pid); + h = fopen(proc, "r"); + if (!h) + return; + + len = fread(pname, sizeof(char), TDM_NAME_LEN, h); + if (len == 0) { + char *p = strncpy(pname, "NO NAME", sizeof(pname) - 1); + len = p - pname; + } + pname[len - 1] = '\0'; + + strncpy(name, pname, size - 1); + name[size - 1] = '\0'; + + fclose(h); +} + +INTERN void +tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) +{ + tdm_private_vblank *v; + + TDM_SNPRINTF(reply, len, "[Client Vblank List]\n"); + TDM_SNPRINTF(reply, len, "---------------------------------------------------------------\n"); + TDM_SNPRINTF(reply, len, "name fps offset fake process\n"); + TDM_SNPRINTF(reply, len, "---------------------------------------------------------------\n"); + + pthread_mutex_lock(&valid_list_lock); + LIST_FOR_EACH_ENTRY(v, &valid_vblank_list, valid_link) { + struct wl_client *client = wl_resource_get_client(v->resource); + char proc_name[TDM_NAME_LEN]; + pid_t pid = 0; + + snprintf(proc_name, TDM_NAME_LEN, "Unknown"); + if (client) { + wl_client_get_credentials(client, &pid, NULL, NULL); + _tdm_vblank_get_process_name(pid, proc_name, TDM_NAME_LEN); + } + + TDM_SNPRINTF(reply, len, "%-12s %u %d %u %s (pid: %u)\n", + v->name, v->fps, v->offset, v->enable_fake, proc_name, pid); + } + pthread_mutex_unlock(&valid_list_lock); + + TDM_SNPRINTF(reply, len, "\n"); +} + diff --git a/tools/tdm_test_client.c b/tools/tdm_test_client.c index 1ec8f93..879668e 100644 --- a/tools/tdm_test_client.c +++ b/tools/tdm_test_client.c @@ -60,7 +60,6 @@ typedef struct _tdm_test_client { int do_query; int do_vblank; - int do_set_fps; int waiting; tdm_client *client; @@ -94,7 +93,6 @@ static struct typestrings typestrs[] = { static struct optstrings optstrs[] = { {OPT_QRY, "qo", "output objects info", "", "primary"}, {OPT_TST, "v", "vblank test", "[,][@][~][+][*fake][^vblank_name]", "primary,0@60~1+0*1^test"}, - {OPT_TST, "f", "fps setting test", "[,]@", "@60"}, }; static void @@ -178,30 +176,6 @@ parse_arg_v(tdm_test_client *data, char *arg) } } -//"@" -static void -parse_arg_f(tdm_test_client *data, char *arg) -{ - char *end = arg; - - data->args.pid = strtol(arg, &end, 10); - - if (*end == ',') { - char name[TDM_NAME_LEN]; - arg = end + 1; - end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM); - data->args.vblank_name = strndup(name, TDM_NAME_LEN); - } - - if (*end != '@') { - printf("failed: no fps value\n"); - exit(0); - } - - arg = end + 1; - data->args.fps = strtol(arg, &end, 10); -} - static void parse_args(tdm_test_client *data, int argc, char *argv[]) { @@ -222,9 +196,6 @@ parse_args(tdm_test_client *data, int argc, char *argv[]) } else if (!strncmp(argv[i] + 1, "v", 1)) { data->do_vblank = 1; parse_arg_v(data, argv[++i]); - } else if (!strncmp(argv[i] + 1, "f", 1)) { - data->do_set_fps = 1; - parse_arg_f(data, argv[++i]); } else { usage(argv[0]); exit(0); @@ -393,18 +364,6 @@ done: tdm_client_vblank_destroy(vblank); } -static void -do_set_fps(tdm_test_client *data) -{ - tdm_error error; - - error = tdm_client_set_client_vblank_fps(data->client, data->args.pid, data->args.vblank_name, data->args.fps); - if (error != TDM_ERROR_NONE) { - printf("tdm_client_set_client_vblank_fps failed\n"); - return; - } -} - static tdm_test_client ttc_data; int @@ -440,8 +399,6 @@ main(int argc, char *argv[]) do_query(data); if (data->do_vblank) do_vblank(data); - if (data->do_set_fps) - do_set_fps(data); done: if (data->args.output_name) -- 2.7.4 From 4de35d73325445ad360276826dba2061f5b517f4 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 15 Feb 2017 21:45:38 +0900 Subject: [PATCH 14/16] package version up to 1.6.7 Change-Id: Iee6a3cb8506ac95b5d94eaadef9cfe6cba6f847c --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 1433b20..28edf31 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %bcond_with utest Name: libtdm -Version: 1.6.6 +Version: 1.6.7 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From c7506ee00525b85f4e59e3adf8a588249a2236c1 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Tue, 21 Feb 2017 14:08:09 +0900 Subject: [PATCH 15/16] set null init for tdm_private_vblank *v Change-Id: Iac60a6f0330a28b7bc82248748967bdc8f5e9441 Signed-off-by: Junkyeong Kim --- src/tdm_vblank.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index c3c1c23..1ecb5ca 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -328,7 +328,7 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, EXTERN tdm_error tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps) { - tdm_private_vblank *v; + tdm_private_vblank *v = NULL; TDM_RETURN_VAL_IF_FAIL(pid > 0, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); @@ -1131,7 +1131,7 @@ _tdm_vblank_get_process_name(pid_t pid, char *name, unsigned int size) INTERN void tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) { - tdm_private_vblank *v; + tdm_private_vblank *v = NULL; TDM_SNPRINTF(reply, len, "[Client Vblank List]\n"); TDM_SNPRINTF(reply, len, "---------------------------------------------------------------\n"); -- 2.7.4 From bd4b00a9f0b9a11c189b87bcffb870ae53c70ecb Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 3 Mar 2017 17:20:36 +0900 Subject: [PATCH 16/16] output: call the output commit handler immediately when dpms off Change-Id: I33264947381669d3104c37c99f41b88b961b4c3f --- src/tdm_output.c | 69 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/src/tdm_output.c b/src/tdm_output.c index 3f077c2..8fa2fab 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -805,6 +805,7 @@ tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handl tdm_func_output *func_output; tdm_private_output_commit_handler *output_commit_handler = NULL; tdm_private_layer *private_layer = NULL; + tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_ON; OUTPUT_FUNC_ENTRY(); @@ -815,33 +816,46 @@ tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handl return TDM_ERROR_NOT_IMPLEMENTED; } - if (func) { - if (!private_output->regist_commit_cb) { - private_output->regist_commit_cb = 1; - ret = func_output->output_set_commit_handler(private_output->output_backend, - tdm_output_cb_commit); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); + if (!func_output->output_get_dpms) { + dpms_value = private_output->current_dpms_value; + } else { + ret = func_output->output_get_dpms(private_output->output_backend, &dpms_value); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("output_get_dpms failed"); + dpms_value = TDM_OUTPUT_DPMS_OFF; } + } - output_commit_handler = calloc(1, sizeof(tdm_private_output_commit_handler)); - if (!output_commit_handler) { - TDM_ERR("failed: alloc memory"); - return TDM_ERROR_OUT_OF_MEMORY; - } + if (dpms_value == TDM_OUTPUT_DPMS_ON) { + if (func) { + if (!private_output->regist_commit_cb) { + private_output->regist_commit_cb = 1; + ret = func_output->output_set_commit_handler(private_output->output_backend, + tdm_output_cb_commit); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); + } - LIST_ADDTAIL(&output_commit_handler->link, &private_output->output_commit_handler_list); - output_commit_handler->private_output = private_output; - output_commit_handler->func = func; - output_commit_handler->user_data = user_data; - output_commit_handler->owner_tid = syscall(SYS_gettid); - } + output_commit_handler = calloc(1, sizeof(tdm_private_output_commit_handler)); + if (!output_commit_handler) { + TDM_ERR("failed: alloc memory"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + LIST_ADDTAIL(&output_commit_handler->link, &private_output->output_commit_handler_list); + output_commit_handler->private_output = private_output; + output_commit_handler->func = func; + output_commit_handler->user_data = user_data; + output_commit_handler->owner_tid = syscall(SYS_gettid); + } - ret = func_output->output_commit(private_output->output_backend, sync, - output_commit_handler); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); + ret = func_output->output_commit(private_output->output_backend, sync, + output_commit_handler); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); - if (tdm_debug_module & TDM_DEBUG_COMMIT) - TDM_INFO("output(%d) backend commit: handle(%p)", private_output->pipe, output_commit_handler); + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("output(%d) backend commit: handle(%p) func(%p) user_data(%p)", + private_output->pipe, output_commit_handler, func, user_data); + } LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { if (!private_layer->waiting_buffer) @@ -855,6 +869,12 @@ tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handl private_layer->committed_buffer->buffer); } + if (dpms_value != TDM_OUTPUT_DPMS_ON) { + TDM_WRN("TDM_OUTPUT_DPMS_OFF. Directly call commit handler instead of commit."); + if (func) + func(output, 0, 0, 0, user_data); + } + return ret; commit_failed: @@ -1107,6 +1127,11 @@ tdm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value) ret = func_output->output_get_dpms(private_output->output_backend, dpms_value); + if (*dpms_value != private_output->current_dpms_value) { + private_output->current_dpms_value = *dpms_value; + TDM_WRN("current_dpms_value changed: %s", tdm_dpms_str(*dpms_value)); + } + _pthread_mutex_unlock(&private_display->lock); return ret; -- 2.7.4