From 224add70bc00208471268a44ff1a49a0ad9daaec Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 22 Aug 2017 13:24:19 +0900 Subject: [PATCH 01/16] add tdm_helper_clear_buffer_color function Change-Id: I033f2212eb057b9896cb5d37e0d6eacb059994a5 --- include/tdm_helper.h | 11 +++++++++++ src/tdm_helper.c | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/tdm_helper.h b/include/tdm_helper.h index 176279b..1459e72 100644 --- a/include/tdm_helper.h +++ b/include/tdm_helper.h @@ -87,6 +87,17 @@ void tdm_helper_clear_buffer_pos(tbm_surface_h buffer, tdm_pos *pos); /** + * @brief fill a buffer with 0 for given pos. + * @details + * This function supports only if a buffer has below formats. + * - TBM_FORMAT_ARGB8888 + * - TBM_FORMAT_XRGB8888 + * @param[in] buffer A TDM buffer + */ +void +tdm_helper_clear_buffer_color(tbm_surface_h buffer, tdm_pos *pos, unsigned int color); + +/** * @brief fill a buffer with 0. * @details * This function supports only if a buffer has below formats. diff --git a/src/tdm_helper.c b/src/tdm_helper.c index 947d41e..fc271fb 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -350,8 +350,8 @@ tdm_helper_dump_buffer(tbm_surface_h buffer, const char *file) TDM_INFO("dump %s", file); } -void -tdm_helper_clear_buffer_pos(tbm_surface_h buffer, tdm_pos *pos) +EXTERN void +tdm_helper_clear_buffer_color(tbm_surface_h buffer, tdm_pos *pos, unsigned int color) { tbm_surface_info_s info; int ret; @@ -372,8 +372,8 @@ tdm_helper_clear_buffer_pos(tbm_surface_h buffer, tdm_pos *pos) for (y = pos->y; y <= (pos->y + pos->h); y++) { p = info.planes[0].ptr + info.planes[0].stride * y; for (x = pos->x; x <= (pos->x + pos->w); x++) { - int *ibuf = (int*)p; - ibuf[x] = 0x00000000; + unsigned int *ibuf = (unsigned int*)p; + ibuf[x] = color; } } } @@ -414,6 +414,14 @@ tdm_helper_clear_buffer_pos(tbm_surface_h buffer, tdm_pos *pos) } EXTERN void +tdm_helper_clear_buffer_pos(tbm_surface_h buffer, tdm_pos *pos) +{ + TDM_RETURN_IF_FAIL(buffer != NULL); + + tdm_helper_clear_buffer_color(buffer, pos, 0); +} + +EXTERN void tdm_helper_clear_buffer(tbm_surface_h buffer) { TDM_RETURN_IF_FAIL(buffer != NULL); -- 2.7.4 From 2f78ce60d7d46d28f5cbbe6ef4dcc6ff2d8e5061 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 22 Aug 2017 13:25:48 +0900 Subject: [PATCH 02/16] dump layer when calling tdm_layer_set_buffer To dump all buffers of a layer, set_buffer function is much better than layer_committed function. Change-Id: I51c3daf926490a23764067e4a75fa6a12cab5f18 --- src/tdm_layer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tdm_layer.c b/src/tdm_layer.c index 1488e28..c6128a8 100644 --- a/src/tdm_layer.c +++ b/src/tdm_layer.c @@ -441,6 +441,10 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) 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); @@ -516,10 +520,6 @@ tdm_layer_committed(tdm_private_layer *private_layer, tdm_private_layer_buffer * private_layer->showing_buffer = *committed_buffer; *committed_buffer = NULL; - /* dump buffer */ - if (tdm_dump_enable && !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO) && private_layer->showing_buffer) - _tdm_layer_dump_buffer(private_layer, private_layer->showing_buffer->buffer); - if (tdm_debug_module & TDM_DEBUG_BUFFER) TDM_INFO("layer(%p) committed_buffer(%p) showing_buffer(%p)", private_layer, *committed_buffer, -- 2.7.4 From 33bb942033e5e34a5e56bd7bf2454dd1dcd8e49c Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 22 Aug 2017 15:14:06 +0900 Subject: [PATCH 03/16] package version up to 1.7.7 Change-Id: I523415f93746816f933806d07f6c1d2f03088895 --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 1003c6a..8c78b8b 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %bcond_with utest Name: libtdm -Version: 1.7.6 +Version: 1.7.7 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From cc83dac60da6c4960a9e740ac5a74cde8197b685 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 31 Aug 2017 14:31:56 +0900 Subject: [PATCH 04/16] tdm-monitor: fix big message issue Wayland has the 4096 message size restriction. So if tdm debug message is bigger than that, the message will be devided. Change-Id: I3ba57801bb149c489577ad1adff2c8befc69e69f --- client/tdm_monitor.c | 32 ++++++++++++++++++++++++++------ protocol/tdm.xml | 4 +++- src/tdm_macro.h | 4 ++++ src/tdm_server.c | 27 +++++++++++++++++++++++---- src/tdm_vblank.c | 10 ++++++---- 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/client/tdm_monitor.c b/client/tdm_monitor.c index fe69cce..cdfa1f7 100644 --- a/client/tdm_monitor.c +++ b/client/tdm_monitor.c @@ -54,20 +54,36 @@ typedef struct _tdm_monitor_info { struct wl_display *display; struct wl_registry *registry; struct wl_tdm *tdm; + + struct { + int done; + char message[TDM_SERVER_REPLY_MSG_LEN]; + char *m; + int len; + int *l; + } debug; } tdm_monitor_info; static tdm_monitor_info td_info; -static int done; static void -_tdm_monitor_cb_debug_done(void *data, struct wl_tdm *wl_tdm, const char *message) +_tdm_monitor_cb_debug_message(void *data, struct wl_tdm *wl_tdm, const char *message) { - printf("%s", message); + tdm_monitor_info *info = data; + TDM_SNPRINTF(info->debug.m, info->debug.l, "%s", message); +} - done = 1; +static void +_tdm_monitor_cb_debug_done(void *data, struct wl_tdm *wl_tdm) +{ + tdm_monitor_info *info = data; + info->debug.done = 1; + *(info->debug.m) = '\0'; + printf("%s", info->debug.message); } static const struct wl_tdm_listener tdm_monitor_listener = { + _tdm_monitor_cb_debug_message, _tdm_monitor_cb_debug_done, }; @@ -137,11 +153,15 @@ main(int argc, char ** argv) for (i = 0; i < argc; i++) TDM_SNPRINTF(str_buf, len_buf, "%s ", argv[i]); - done = 0; + info->debug.done = 0; + info->debug.message[0] = '\0'; + info->debug.len = sizeof(info->debug.message); + info->debug.m = info->debug.message; + info->debug.l = &info->debug.len; wl_tdm_debug(info->tdm, options); - while (!done && ret >= 0) + while (!info->debug.done && ret >= 0) ret = wl_display_dispatch(info->display); if (info->tdm) diff --git a/protocol/tdm.xml b/protocol/tdm.xml index bd5ed89..47e6536 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -8,10 +8,12 @@ TDM uses the wayland protocol to communicate between tdm client and tdm server. - + + + diff --git a/src/tdm_macro.h b/src/tdm_macro.h index 6da02b4..504315a 100644 --- a/src/tdm_macro.h +++ b/src/tdm_macro.h @@ -49,6 +49,7 @@ extern "C" { #endif #define TDM_SERVER_REPLY_MSG_LEN 8192 +#define TDM_DEBUG_REPLY_MSG_LEN 2048 #undef EXTERN #undef DEPRECATED @@ -138,6 +139,9 @@ extern "C" { #define TDM_NOT_DEFINED_VALUE (-1) #define TDM_FRONT_VALUE(n) (((n) > 0) ? (n) : TDM_NOT_DEFINED_VALUE) +#define TDM_MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define TDM_MIN(x, y) (((x) < (y)) ? (x) : (y)) + #define TDM_TIME(sec, usec) ((double)(sec) + ((double)(usec)) / 1000000.0) #define TDM_TIME_SEC(time) ((unsigned int)(time)) #define TDM_TIME_USEC(time) (unsigned int)(((time) - (unsigned int)(time)) * 1000000.0) diff --git a/src/tdm_server.c b/src/tdm_server.c index bd9cd9f..b69926b 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -546,19 +546,38 @@ _tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, con tdm_private_server *private_server = wl_resource_get_user_data(resource); tdm_private_loop *private_loop = private_server->private_loop; char message[TDM_SERVER_REPLY_MSG_LEN]; - int size = sizeof(message); + char *m; + int len = sizeof(message), size; uid_t uid; wl_client_get_credentials(client, NULL, &uid, NULL); if (uid != 0) { - snprintf(message, size, "tdm-monitor: SHOULD be a superuser.\n"); + snprintf(message, len, "tdm-monitor: SHOULD be a superuser.\n"); TDM_ERR("%s", message); } else { - tdm_monitor_server_command(private_loop->dpy, options, message, &size); + tdm_monitor_server_command(private_loop->dpy, options, message, &len); } - wl_tdm_send_debug_done(resource, message); + size = sizeof(message) - len; + m = message; + + wl_client_flush(wl_resource_get_client(resource)); + + while (size > 0) { + char buffer[TDM_DEBUG_REPLY_MSG_LEN]; + int copylen = TDM_MIN(size, sizeof(buffer) - 1); + + strncpy(buffer, m, copylen); + m += copylen; + size -= copylen; + + buffer[copylen] = '\0'; + + wl_tdm_send_debug_message(resource, buffer); + } + + wl_tdm_send_debug_done(resource); } static void diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 0cff134..97deab5 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -1196,13 +1196,15 @@ tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) 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); const char *proc_name = NULL; pid_t pid = 0; - if (client) { - wl_client_get_credentials(client, &pid, NULL, NULL); - proc_name = tdm_server_get_client_name(pid); + if (v->resource) { + struct wl_client *client = wl_resource_get_client(v->resource); + if (client) { + wl_client_get_credentials(client, &pid, NULL, NULL); + proc_name = tdm_server_get_client_name(pid); + } } TDM_SNPRINTF(reply, len, "%-12s %u %u %d %u %s (pid: %u)\n", -- 2.7.4 From 0ffceb298b9a177f773475c5211d79d1c1a91d75 Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Wed, 6 Sep 2017 14:20:39 +0300 Subject: [PATCH 05/16] hwc_window: add the buffer dump Change-Id: I3cc26e6e02af28a0e620527a99c128c0729ae7f5 Signed-off-by: Konstantin Drabeniuk --- include/tdm_backend.h | 1 + src/tdm.c | 2 ++ src/tdm_hwc_window.c | 33 +++++++++++++++++++++++++++++++++ src/tdm_output.c | 27 +++++++++++++++++++++++++++ src/tdm_private.h | 2 ++ 5 files changed, 65 insertions(+) diff --git a/include/tdm_backend.h b/include/tdm_backend.h index 3ecdf92..490bef2 100644 --- a/include/tdm_backend.h +++ b/include/tdm_backend.h @@ -37,6 +37,7 @@ #define _TDM_BACKEND_H_ #include +#include #include "tdm_types.h" diff --git a/src/tdm.c b/src/tdm.c index e17b3f3..6ae0cc5 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -1204,6 +1204,8 @@ tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_s tdm_debug_dump |= TDM_DUMP_FLAG_PP; } else if (!strncmp(arg, "capture", 7)) { tdm_debug_dump |= TDM_DUMP_FLAG_CAPTURE; + } else if (!strncmp(arg, "window", 6)) { + tdm_debug_dump |= TDM_DUMP_FLAG_WINDOW; } else goto done; diff --git a/src/tdm_hwc_window.c b/src/tdm_hwc_window.c index 94ac7a2..ca64d65 100644 --- a/src/tdm_hwc_window.c +++ b/src/tdm_hwc_window.c @@ -118,6 +118,8 @@ tdm_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos) } ret = func_hwc_window->hwc_window_set_zpos(private_hwc_window->hwc_window_backend, zpos); + if (ret == TDM_ERROR_NONE) + private_hwc_window->zpos = zpos; _pthread_mutex_unlock(&private_display->lock); @@ -215,6 +217,26 @@ tdm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info) return ret; } +static void +_tdm_window_dump_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer) +{ + tdm_private_hwc_window *private_window = (tdm_private_hwc_window *)hwc_window; + tdm_private_output *private_output = private_window->private_output; + unsigned int pipe; + uint32_t zpos; + char fname[PATH_MAX]; + + pipe = private_output->pipe; + zpos = private_window->zpos; + + snprintf(fname, sizeof(fname), "tdm_%d_win_%d", pipe, zpos); + + tbm_surface_internal_dump_buffer(buffer, fname); + TDM_DBG("%s dump excute", fname); + + return; +} + EXTERN tdm_error tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer) { @@ -224,6 +246,13 @@ tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer) _pthread_mutex_lock(&private_display->lock); + if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) { + char str[TDM_PATH_LEN]; + static int i; + snprintf(str, TDM_PATH_LEN, "window_%d_%d_%03d", + private_output->index, private_hwc_window->zpos, i++); + tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str); + } func_hwc_window = &private_display->func_hwc_window; @@ -233,6 +262,10 @@ tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer) return TDM_ERROR_NOT_IMPLEMENTED; } + /* dump buffer */ + if (tdm_dump_enable) + _tdm_window_dump_buffer(hwc_window, buffer); + ret = func_hwc_window->hwc_window_set_buffer(private_hwc_window->hwc_window_backend, buffer); _pthread_mutex_unlock(&private_display->lock); diff --git a/src/tdm_output.c b/src/tdm_output.c index ab2d991..043074a 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -1431,6 +1431,22 @@ tdm_output_get_target_surface_queue(tdm_output *output, tdm_error *error) return queue; } +static void +_tdm_target_window_dump_buffer(tdm_private_output *private_output, tbm_surface_h buffer) +{ + unsigned int pipe; + char fname[PATH_MAX]; + + pipe = private_output->pipe; + + snprintf(fname, sizeof(fname), "tdm_%d_target_win", pipe); + + tbm_surface_internal_dump_buffer(buffer, fname); + TDM_DBG("%s dump excute", fname); + + return; +} + EXTERN tdm_error tdm_output_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer, tdm_hwc_region damage) @@ -1441,6 +1457,13 @@ tdm_output_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer, _pthread_mutex_lock(&private_display->lock); + if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) { + char str[TDM_PATH_LEN]; + static int i; + snprintf(str, TDM_PATH_LEN, "target_window_%d_%03d", + private_output->index, i++); + tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str); + } func_output = &private_display->func_output; @@ -1450,6 +1473,10 @@ tdm_output_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer, return TDM_ERROR_NOT_IMPLEMENTED; } + /* dump buffer */ + if (tdm_dump_enable) + _tdm_target_window_dump_buffer((tdm_private_output *)output, buffer); + ret = func_output->output_set_client_target_buffer(private_output->output_backend, buffer, damage); _pthread_mutex_unlock(&private_display->lock); diff --git a/src/tdm_private.h b/src/tdm_private.h index 347e501..4b23a4a 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -110,6 +110,7 @@ enum { TDM_DUMP_FLAG_LAYER = (1 << 0), TDM_DUMP_FLAG_PP = (1 << 1), TDM_DUMP_FLAG_CAPTURE = (1 << 2), + TDM_DUMP_FLAG_WINDOW = (1 << 3), }; #define TDM_DUMP_DIR "/tmp" @@ -259,6 +260,7 @@ struct _tdm_private_hwc_window { struct list_head link; int index; + uint32_t zpos; tdm_private_display *private_display; tdm_private_output *private_output; -- 2.7.4 From d2014e64bf637ccf6399aed6abc1f91ed30d820b Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 8 Sep 2017 11:07:43 +0900 Subject: [PATCH 06/16] add get_dpms, get_connection, get_mode request If a client adds the change_handler, we might be able to guess that the client will watch the tdm client's fd and handle tdm events in event loop. Otherwise, we CAN'T make sure if a client has event loop which handles tdm events. Change-Id: I49685d7eb3b88cda59b167f5ae66a7e9501a2315 --- client/tdm_client.c | 66 +++++++++++++++++++++++++---- protocol/tdm.xml | 6 +++ src/tdm_server.c | 120 +++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 167 insertions(+), 25 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 858e4f5..04c9d2f 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -76,6 +76,7 @@ typedef struct _tdm_private_client_output { struct list_head change_handler_list; unsigned int req_id; + unsigned int watch_output_changes; struct list_head link; } tdm_private_client_output; @@ -508,9 +509,18 @@ tdm_client_output_add_change_handler(tdm_client_output *output, h = calloc(1, sizeof *h); TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY); - if (LIST_IS_EMPTY(&private_output->change_handler_list)) + if (LIST_IS_EMPTY(&private_output->change_handler_list)) { wl_tdm_output_watch_output_changes(private_output->output, 1); + /* TODO: this is very tricky. + * If a client adds the change_handler, we might be able to guess that + * the client will watch the tdm client's fd and handle tdm events in + * event loop. Otherwise, we CAN'T make sure if a client has event loop + * which handles tdm events. + */ + private_output->watch_output_changes = 1; + } + h->private_output = private_output; h->func = func; h->user_data = user_data; @@ -550,12 +560,24 @@ tdm_error tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh) { tdm_private_client_output *private_output; + tdm_private_client *private_client; TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER); private_output = (tdm_private_client_output*)output; + if (private_output->watch_output_changes) { + *refresh = private_output->refresh; + return TDM_ERROR_NONE; + } + + private_client = private_output->private_client; + TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER); + + wl_tdm_output_get_mode(private_output->output); + wl_display_roundtrip(private_client->display); + *refresh = private_output->refresh; return TDM_ERROR_NONE; @@ -565,12 +587,24 @@ tdm_error tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status) { tdm_private_client_output *private_output; + tdm_private_client *private_client; TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER); private_output = (tdm_private_client_output*)output; + if (private_output->watch_output_changes) { + *status = private_output->connection; + return TDM_ERROR_NONE; + } + + private_client = private_output->private_client; + TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER); + + wl_tdm_output_get_connection(private_output->output); + wl_display_roundtrip(private_client->display); + *status = private_output->connection; return TDM_ERROR_NONE; @@ -580,12 +614,24 @@ tdm_error tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms) { tdm_private_client_output *private_output; + tdm_private_client *private_client; TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER); private_output = (tdm_private_client_output*)output; + if (private_output->watch_output_changes) { + *dpms = private_output->dpms; + return TDM_ERROR_NONE; + } + + private_client = private_output->private_client; + TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER); + + wl_tdm_output_get_dpms(private_output->output); + wl_display_roundtrip(private_client->display); + *dpms = private_output->dpms; return TDM_ERROR_NONE; @@ -778,10 +824,11 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli if (!private_vblank->started) private_vblank->started = 1; - if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { - TDM_INFO("dpms off"); - return TDM_ERROR_DPMS_OFF; - } + if (private_output->watch_output_changes) + if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { + TDM_INFO("dpms off"); + return TDM_ERROR_DPMS_OFF; + } w = calloc(1, sizeof *w); if (!w) { @@ -854,10 +901,11 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, if (!private_vblank->started) private_vblank->started = 1; - if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { - TDM_INFO("dpms off"); - return TDM_ERROR_DPMS_OFF; - } + if (private_output->watch_output_changes) + if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { + TDM_INFO("dpms off"); + return TDM_ERROR_DPMS_OFF; + } w = calloc(1, sizeof *w); if (!w) { diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 47e6536..dcd99ed 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -61,6 +61,12 @@ + + + + + + diff --git a/src/tdm_server.c b/src/tdm_server.c index b69926b..c49e9db 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -451,10 +451,94 @@ _tdm_server_output_cb_watch_output_changes(struct wl_client *client, struct wl_r output_info->watch_output_changes = enable; } +static void +_tdm_server_output_cb_get_connection(struct wl_client *client, struct wl_resource *resource) +{ + tdm_server_output_info *output_info = wl_resource_get_user_data(resource); + tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + tdm_error ret; + + TDM_RETURN_IF_FAIL(output_info != NULL); + + ret = tdm_output_get_conn_status(output_info->output, &status); + TDM_GOTO_IF_FAIL(ret != TDM_ERROR_NONE, failed); + + wl_tdm_output_send_connection(output_info->resource, status); + + return; + +failed: + wl_tdm_output_send_connection(output_info->resource, TDM_OUTPUT_CONN_STATUS_DISCONNECTED); +} + +static void +_tdm_server_output_cb_get_mode(struct wl_client *client, struct wl_resource *resource) +{ + tdm_server_output_info *output_info = wl_resource_get_user_data(resource); + tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + tdm_error ret; + + TDM_RETURN_IF_FAIL(output_info != NULL); + + ret = tdm_output_get_conn_status(output_info->output, &status); + TDM_GOTO_IF_FAIL(ret != TDM_ERROR_NONE, failed); + + if (status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + const tdm_output_mode *mode = NULL; + unsigned int hdisplay, vdisplay, vrefresh; + + ret = tdm_output_get_mode(output_info->output, &mode); + TDM_GOTO_IF_FAIL(ret != TDM_ERROR_NONE, failed); + + hdisplay = (mode) ? mode->hdisplay : 0; + vdisplay = (mode) ? mode->vdisplay : 0; + vrefresh = (mode) ? mode->vrefresh : 0; + + wl_tdm_output_send_mode(output_info->resource, hdisplay, vdisplay, vrefresh); + } else { + wl_tdm_output_send_mode(output_info->resource, 0, 0, 0); + } + + return; +failed: + wl_tdm_output_send_mode(output_info->resource, 0, 0, 0); +} + +static void +_tdm_server_output_cb_get_dpms(struct wl_client *client, struct wl_resource *resource) +{ + tdm_server_output_info *output_info = wl_resource_get_user_data(resource); + tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + tdm_error ret; + + TDM_RETURN_IF_FAIL(output_info != NULL); + + ret = tdm_output_get_conn_status(output_info->output, &status); + TDM_GOTO_IF_FAIL(ret != TDM_ERROR_NONE, failed); + + if (status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_OFF; + + ret = tdm_output_get_dpms(output_info->output, &dpms_value); + TDM_GOTO_IF_FAIL(ret != TDM_ERROR_NONE, failed); + + wl_tdm_output_send_dpms(output_info->resource, dpms_value); + } else { + wl_tdm_output_send_dpms(output_info->resource, TDM_OUTPUT_DPMS_OFF); + } + + return; +failed: + wl_tdm_output_send_dpms(output_info->resource, TDM_OUTPUT_DPMS_OFF); +} + static const struct wl_tdm_output_interface tdm_output_implementation = { _tdm_server_output_cb_destroy, _tdm_server_output_cb_create_vblank, _tdm_server_output_cb_watch_output_changes, + _tdm_server_output_cb_get_connection, + _tdm_server_output_cb_get_mode, + _tdm_server_output_cb_get_dpms, }; static void @@ -484,9 +568,7 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou tdm_server_output_info *output_info; struct wl_resource *output_resource = NULL; tdm_output *output; - const tdm_output_mode *mode = NULL; - tdm_output_dpms dpms_value; - tdm_output_conn_status status; + tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; output = _tdm_server_find_output(private_server, name); if (!output) { @@ -496,17 +578,6 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou return; } - tdm_output_get_mode(output, &mode); - if (!mode) { - TDM_ERR("no mode for '%s' output", name); - wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "no mode for '%s' output", name); - return; - } - - tdm_output_get_dpms(output, &dpms_value); - tdm_output_get_conn_status(output, &status); - output_resource = wl_resource_create(client, &wl_tdm_output_interface, wl_resource_get_version(resource), id); @@ -535,9 +606,26 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou wl_resource_set_implementation(output_resource, &tdm_output_implementation, output_info, destroy_output_callback); - wl_tdm_output_send_mode(output_resource, mode->hdisplay, mode->vdisplay, mode->vrefresh); - wl_tdm_output_send_dpms(output_resource, dpms_value); + tdm_output_get_conn_status(output, &status); wl_tdm_output_send_connection(output_resource, status); + + if (status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_OFF; + const tdm_output_mode *mode = NULL; + unsigned int hdisplay, vdisplay, vrefresh; + + tdm_output_get_mode(output, &mode); + hdisplay = (mode) ? mode->hdisplay : 0; + vdisplay = (mode) ? mode->vdisplay : 0; + vrefresh = (mode) ? mode->vrefresh : 0; + wl_tdm_output_send_mode(output_resource, hdisplay, vdisplay, vrefresh); + + tdm_output_get_dpms(output, &dpms_value); + wl_tdm_output_send_dpms(output_resource, dpms_value); + } else { + wl_tdm_output_send_mode(output_resource, 0, 0, 0); + wl_tdm_output_send_dpms(output_resource, TDM_OUTPUT_DPMS_OFF); + } } static void -- 2.7.4 From db326e629f76e9470f540d2719675c28dea2a26a Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 8 Sep 2017 11:57:25 +0900 Subject: [PATCH 07/16] add error type for output disconnection Change-Id: I7450a453217d138cb73e8be289e72682a13bf768 --- include/tdm_common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/tdm_common.h b/include/tdm_common.h index dfb3f8e..054cb5e 100644 --- a/include/tdm_common.h +++ b/include/tdm_common.h @@ -67,6 +67,7 @@ typedef enum { TDM_ERROR_NOT_IMPLEMENTED = -8, /**< not implemented */ TDM_ERROR_NO_CAPABILITY = -9, /**< no capability */ TDM_ERROR_DPMS_OFF = -10, /**< dpms off */ + TDM_ERROR_OUTPUT_DISCONNECTED = -11, /**< output disconnected */ } tdm_error; /** -- 2.7.4 From 0c3bbb663d3e83b39a1f7cdd6dcda2caedec6738 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 8 Sep 2017 11:58:28 +0900 Subject: [PATCH 08/16] add error information to protocol Change-Id: Ieba9ce9235eb815528228b6b656d12531af7e746 --- client/tdm_client.c | 15 ++++++++++++--- protocol/tdm.xml | 3 +++ src/tdm_server.c | 37 +++++++++++++++++++------------------ 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 04c9d2f..6ab849d 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -188,7 +188,7 @@ _tdm_client_output_destroy(tdm_private_client_output *private_output) static void _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output, - uint32_t width, uint32_t height, uint32_t refresh) + uint32_t width, uint32_t height, uint32_t refresh, uint32_t error) { tdm_private_client_output *private_output = (tdm_private_client_output*)data; @@ -198,13 +198,16 @@ _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output, private_output->height = height; private_output->refresh = refresh; + if (error != TDM_ERROR_NONE) + TDM_INFO("mode event error: %d", error); + TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)", private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output), width, height, refresh); } static void -_tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value) +_tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error) { tdm_private_client_output *private_output = (tdm_private_client_output*)data; tdm_client_output_handler_info *h = NULL; @@ -217,6 +220,9 @@ _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output private_output->connection = value; + if (error != TDM_ERROR_NONE) + TDM_INFO("connection event error: %d", error); + TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)", private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output), @@ -230,7 +236,7 @@ _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output } static void -_tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value) +_tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error) { tdm_private_client_output *private_output = (tdm_private_client_output*)data; tdm_client_output_handler_info *h = NULL; @@ -243,6 +249,9 @@ _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint private_output->dpms = value; + if (error != TDM_ERROR_NONE) + TDM_INFO("dpms event error: %d", error); + TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)", private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output), diff --git a/protocol/tdm.xml b/protocol/tdm.xml index dcd99ed..22328ac 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -41,14 +41,17 @@ + + + diff --git a/src/tdm_server.c b/src/tdm_server.c index c49e9db..ca994ce 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -217,10 +217,10 @@ _tdm_server_cb_output_change(tdm_output *output, tdm_output_change_type type, switch (type) { case TDM_OUTPUT_CHANGE_DPMS: - wl_tdm_output_send_dpms(output_info->resource, value.u32); + wl_tdm_output_send_dpms(output_info->resource, value.u32, TDM_ERROR_NONE); break; case TDM_OUTPUT_CHANGE_CONNECTION: - wl_tdm_output_send_connection(output_info->resource, value.u32); + wl_tdm_output_send_connection(output_info->resource, value.u32, TDM_ERROR_NONE); break; default: break; @@ -463,12 +463,12 @@ _tdm_server_output_cb_get_connection(struct wl_client *client, struct wl_resourc ret = tdm_output_get_conn_status(output_info->output, &status); TDM_GOTO_IF_FAIL(ret != TDM_ERROR_NONE, failed); - wl_tdm_output_send_connection(output_info->resource, status); + wl_tdm_output_send_connection(output_info->resource, status, ret); return; failed: - wl_tdm_output_send_connection(output_info->resource, TDM_OUTPUT_CONN_STATUS_DISCONNECTED); + wl_tdm_output_send_connection(output_info->resource, TDM_OUTPUT_CONN_STATUS_DISCONNECTED, ret); } static void @@ -494,14 +494,14 @@ _tdm_server_output_cb_get_mode(struct wl_client *client, struct wl_resource *res vdisplay = (mode) ? mode->vdisplay : 0; vrefresh = (mode) ? mode->vrefresh : 0; - wl_tdm_output_send_mode(output_info->resource, hdisplay, vdisplay, vrefresh); + wl_tdm_output_send_mode(output_info->resource, hdisplay, vdisplay, vrefresh, ret); } else { - wl_tdm_output_send_mode(output_info->resource, 0, 0, 0); + wl_tdm_output_send_mode(output_info->resource, 0, 0, 0, TDM_ERROR_OUTPUT_DISCONNECTED); } return; failed: - wl_tdm_output_send_mode(output_info->resource, 0, 0, 0); + wl_tdm_output_send_mode(output_info->resource, 0, 0, 0, ret); } static void @@ -522,14 +522,14 @@ _tdm_server_output_cb_get_dpms(struct wl_client *client, struct wl_resource *res ret = tdm_output_get_dpms(output_info->output, &dpms_value); TDM_GOTO_IF_FAIL(ret != TDM_ERROR_NONE, failed); - wl_tdm_output_send_dpms(output_info->resource, dpms_value); + wl_tdm_output_send_dpms(output_info->resource, dpms_value, ret); } else { - wl_tdm_output_send_dpms(output_info->resource, TDM_OUTPUT_DPMS_OFF); + wl_tdm_output_send_dpms(output_info->resource, TDM_OUTPUT_DPMS_OFF, TDM_ERROR_OUTPUT_DISCONNECTED); } return; failed: - wl_tdm_output_send_dpms(output_info->resource, TDM_OUTPUT_DPMS_OFF); + wl_tdm_output_send_dpms(output_info->resource, TDM_OUTPUT_DPMS_OFF, ret); } static const struct wl_tdm_output_interface tdm_output_implementation = { @@ -569,6 +569,7 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou struct wl_resource *output_resource = NULL; tdm_output *output; tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + tdm_error ret; output = _tdm_server_find_output(private_server, name); if (!output) { @@ -606,25 +607,25 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou wl_resource_set_implementation(output_resource, &tdm_output_implementation, output_info, destroy_output_callback); - tdm_output_get_conn_status(output, &status); - wl_tdm_output_send_connection(output_resource, status); + ret = tdm_output_get_conn_status(output, &status); + wl_tdm_output_send_connection(output_resource, status, ret); if (status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_OFF; const tdm_output_mode *mode = NULL; unsigned int hdisplay, vdisplay, vrefresh; - tdm_output_get_mode(output, &mode); + ret = tdm_output_get_mode(output, &mode); hdisplay = (mode) ? mode->hdisplay : 0; vdisplay = (mode) ? mode->vdisplay : 0; vrefresh = (mode) ? mode->vrefresh : 0; - wl_tdm_output_send_mode(output_resource, hdisplay, vdisplay, vrefresh); + wl_tdm_output_send_mode(output_resource, hdisplay, vdisplay, vrefresh, ret); - tdm_output_get_dpms(output, &dpms_value); - wl_tdm_output_send_dpms(output_resource, dpms_value); + ret = tdm_output_get_dpms(output, &dpms_value); + wl_tdm_output_send_dpms(output_resource, dpms_value, ret); } else { - wl_tdm_output_send_mode(output_resource, 0, 0, 0); - wl_tdm_output_send_dpms(output_resource, TDM_OUTPUT_DPMS_OFF); + wl_tdm_output_send_mode(output_resource, 0, 0, 0, TDM_ERROR_OUTPUT_DISCONNECTED); + wl_tdm_output_send_dpms(output_resource, TDM_OUTPUT_DPMS_OFF, TDM_ERROR_OUTPUT_DISCONNECTED); } } -- 2.7.4 From 73d36c4236a06e50377974ffc0ec51b9d8c9317b Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Fri, 8 Sep 2017 09:51:42 +0300 Subject: [PATCH 09/16] hwc_window: add flags Change-Id: I51e3cb8ac46189a66ced6783a2335ed29999123f Signed-off-by: Konstantin Drabeniuk --- include/tdm.h | 20 +++++++++++++++++++- include/tdm_backend.h | 20 +++++++++++++++++++- include/tdm_common.h | 7 +++++++ src/tdm_hwc_window.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/include/tdm.h b/include/tdm.h index d10b691..47180b9 100644 --- a/include/tdm.h +++ b/include/tdm.h @@ -965,7 +965,7 @@ tdm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info); * @brief Set a TBM buffer to a window object * @details A TBM buffer will be applied when the output object of a layer * object is committed. - * @param[in] hwc_window A layer object + * @param[in] hwc_window A window object * @param[in] buffer A TDM buffer * @return #TDM_ERROR_NONE if success. Otherwise, error value. */ @@ -973,6 +973,24 @@ tdm_error tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer); /** + * @brief Set a flags to a window object + * @param[in] hwc_window A window object + * @param[in] flags A hwc_window flags + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_hwc_window_set_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags); + +/** + * @brief Unset a flags from a window object + * @param[in] hwc_window A window object + * @param[in] flags A hwc_window flags + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_hwc_window_unset_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags); + +/** * @brief Destroy a pp object * @param[in] pp A pp object * @see tdm_display_create_pp diff --git a/include/tdm_backend.h b/include/tdm_backend.h index 490bef2..1e5c362 100644 --- a/include/tdm_backend.h +++ b/include/tdm_backend.h @@ -837,12 +837,30 @@ typedef struct _tdm_func_window { * @brief Set a TDM buffer to a window object * @details A TDM buffer will be applied when the output object * of a layer object is committed. - * @param[in] hwc_window A layer object + * @param[in] hwc_window A window object * @param[in] buffer A TDM buffer * @return #TDM_ERROR_NONE if success. Otherwise, error value. */ tdm_error (*hwc_window_set_buffer)(tdm_hwc_window *hwc_window, tbm_surface_h buffer); + + /** + * @brief Set a flags to a window object + * @param[in] hwc_window A window object + * @param[in] flags A hwc_window flags + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ + tdm_error (*hwc_window_set_flags)(tdm_hwc_window *hwc_window, + tdm_hwc_window_flag flags); + + /** + * @brief Unset a flags from a window object + * @param[in] hwc_window A window object + * @param[in] flags A hwc_window flags + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ + tdm_error (*hwc_window_unset_flags)(tdm_hwc_window *hwc_window, + tdm_hwc_window_flag flags); } tdm_func_hwc_window; /** diff --git a/include/tdm_common.h b/include/tdm_common.h index d7a10b5..7df7ed7 100644 --- a/include/tdm_common.h +++ b/include/tdm_common.h @@ -289,6 +289,13 @@ typedef union { uint64_t u64; } tdm_value; +/** + * @brief The hwc window flag enumeration + */ +typedef enum { + TDM_HWC_WINDOW_FLAG_SKIP = (1 << 0), +} tdm_hwc_window_flag; + #ifdef __cplusplus } #endif diff --git a/src/tdm_hwc_window.c b/src/tdm_hwc_window.c index ca64d65..e35574a 100644 --- a/src/tdm_hwc_window.c +++ b/src/tdm_hwc_window.c @@ -339,3 +339,51 @@ tdm_hwc_window_destroy_internal(tdm_private_hwc_window * private_hwc_window) free(private_hwc_window); return TDM_ERROR_NONE; } + +EXTERN tdm_error +tdm_hwc_window_set_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags) +{ + tdm_func_hwc_window *func_hwc_window = NULL; + + HWC_WINDOW_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + func_hwc_window = &private_display->func_hwc_window; + + if (!func_hwc_window->hwc_window_set_flags) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_hwc_window->hwc_window_set_flags(private_hwc_window->hwc_window_backend, flags); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN tdm_error +tdm_hwc_window_unset_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags) +{ + tdm_func_hwc_window *func_hwc_window = NULL; + + HWC_WINDOW_FUNC_ENTRY(); + + _pthread_mutex_lock(&private_display->lock); + + func_hwc_window = &private_display->func_hwc_window; + + if (!func_hwc_window->hwc_window_unset_flags) { + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("not implemented!!"); + return TDM_ERROR_NOT_IMPLEMENTED; + } + + ret = func_hwc_window->hwc_window_unset_flags(private_hwc_window->hwc_window_backend, flags); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} -- 2.7.4 From 5c085284e4ee58080f4a67f6dc9914ac9c2e49cf Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 8 Sep 2017 14:35:40 +0900 Subject: [PATCH 10/16] use SW timer when output disconnected If enable_fake == 1, use SW timer when output disconnected as well as DPMS off. Change-Id: I9e528b6eb6749d099c6b8f7ff765ce46a7728f5a --- client/tdm_client.c | 22 +++++++++---- client/tdm_client.h | 14 +++++--- src/tdm_vblank.c | 93 +++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 92 insertions(+), 37 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 6ab849d..d80100d 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -833,11 +833,16 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli if (!private_vblank->started) private_vblank->started = 1; - if (private_output->watch_output_changes) - if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { - TDM_INFO("dpms off"); + if (private_output->watch_output_changes && !private_vblank->enable_fake) { + if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + TDM_ERR("output disconnected"); + return TDM_ERROR_OUTPUT_DISCONNECTED; + } + if (private_output->dpms != TDM_OUTPUT_DPMS_ON) { + TDM_ERR("dpms off"); return TDM_ERROR_DPMS_OFF; } + } w = calloc(1, sizeof *w); if (!w) { @@ -910,11 +915,16 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, if (!private_vblank->started) private_vblank->started = 1; - if (private_output->watch_output_changes) - if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { - TDM_INFO("dpms off"); + if (private_output->watch_output_changes && !private_vblank->enable_fake) { + if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + TDM_ERR("output disconnected"); + return TDM_ERROR_OUTPUT_DISCONNECTED; + } + if (private_output->dpms != TDM_OUTPUT_DPMS_ON) { + TDM_ERR("dpms off"); return TDM_ERROR_DPMS_OFF; } + } w = calloc(1, sizeof *w); if (!w) { diff --git a/client/tdm_client.h b/client/tdm_client.h index 8a2fcd0..175bb45 100644 --- a/client/tdm_client.h +++ b/client/tdm_client.h @@ -226,6 +226,12 @@ tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms); /** * @brief Create the client vblank object of the given client output + * @details + * tdm client vblank basically uses the HW vblank resource. Therefore, if HW vblank + * is not available for some reasons, such as output disconnection and dpms off, + * #tdm_client_vblank_wait will return error. If you want it to work propery in spite + * of these reasons, you can use #tdm_client_vblank_set_enable_fake to get SW fake + * vblank events. * @param[in] output The client output object * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value. * @return A client vblank object if success. Otherwise, NULL. @@ -286,8 +292,8 @@ tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms); /** * @brief Enable/Disable the fake vblank to the client vblank object * @details - * If enable_fake == 0, #tdm_client_vblank_wait will return TDM_ERROR_DPMS_OFF - * when DPMS off. Otherwise, #tdm_client_vblank_wait will return TDM_ERROR_NONE + * If enable_fake == 0, #tdm_client_vblank_wait will return error when HW vblank is + * not available. Otherwise, #tdm_client_vblank_wait will return TDM_ERROR_NONE * as success. Once #tdm_client_vblank_wait returns TDM_ERROR_NONE, the user client * vblank handler(#tdm_client_vblank_handler) SHOULD be called after the given * interval of #tdm_client_vblank_wait. Default is @b disable. @@ -301,7 +307,7 @@ tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable /** * @brief Wait for a vblank * @details - * This function will return TDM_ERROR_DPMS_OFF when DPMS off. However, + * This function will return error when HW vblank resource is not available. However, * #tdm_client_vblank_wait will return TDM_ERROR_NONE as success if * #tdm_client_vblank_set_enable_fake sets true. Once #tdm_client_vblank_wait * returns TDM_ERROR_NONE, the user client vblank handler(#tdm_client_vblank_handler) @@ -389,7 +395,7 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli /** * @brief Wait for a vblank with the target sequence number * @details - * This function will return TDM_ERROR_DPMS_OFF when DPMS off. However, + * This function will return error when HW vblank resource is not available. However, * #tdm_client_vblank_wait will return TDM_ERROR_NONE as success if * #tdm_client_vblank_set_enable_fake sets true. Once #tdm_client_vblank_wait_seq * returns TDM_ERROR_NONE, the user client vblank handler(#tdm_client_vblank_handler) diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 97deab5..337e7cf 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -54,6 +54,8 @@ * - use a tdm_event_loop_source object only. */ +#define TDM_VBLANK_DEFAULT_VREFRESH 30 + /* We expact "(unsigned int)(0.0016667 / 0.0016667) = 1". But it becomes 0. */ #define TDM_TIME_MARGIN 0.0000001 @@ -89,12 +91,14 @@ typedef struct _tdm_private_vblank { tdm_display *dpy; tdm_output *output; + tdm_output_conn_status connection; tdm_output_dpms dpms; unsigned int vrefresh; unsigned int check_HW_or_SW; char name[TDM_NAME_LEN]; unsigned int fps; + unsigned int fps_changeable; int offset; unsigned int enable_fake; unsigned int ignore_global_fps; @@ -308,6 +312,39 @@ _tdm_vblank_free_HW_wait(tdm_private_vblank *private_vblank, tdm_error error, un } static void +_tdm_vblank_update_output_info(tdm_private_vblank *private_vblank) +{ + tdm_output *output = private_vblank->output; + tdm_output_conn_status connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + tdm_output_dpms dpms = TDM_OUTPUT_DPMS_OFF; + unsigned int vrefresh = 0; + + tdm_output_get_conn_status(output, &connection); + + if (connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + const tdm_output_mode *mode = NULL; + tdm_output_get_mode(output, &mode); + vrefresh = (mode) ? mode->vrefresh : 0; + tdm_output_get_dpms(output, &dpms); + } + + if (vrefresh == 0) + vrefresh = TDM_VBLANK_DEFAULT_VREFRESH; + + private_vblank->dpms = dpms; + private_vblank->connection = connection; + private_vblank->vrefresh = vrefresh; + private_vblank->HW_vblank_gap = 1.0 / private_vblank->vrefresh; + + if (private_vblank->fps_changeable) + private_vblank->fps = vrefresh; + + VDB("dpms(%d) connection(%d) vrefresh(%d) fps(%d)", + private_vblank->dpms, private_vblank->connection, + private_vblank->vrefresh, private_vblank->fps); +} + +static void _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data) { @@ -320,7 +357,7 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, if (private_vblank->dpms == value.u32) break; VDB("dpms %s", tdm_dpms_str(value.u32)); - private_vblank->dpms = value.u32; + _tdm_vblank_update_output_info(private_vblank); private_vblank->check_HW_or_SW = 1; if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON) { if (private_vblank->enable_fake) @@ -330,9 +367,17 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, } break; case TDM_OUTPUT_CHANGE_CONNECTION: + if (private_vblank->connection == value.u32) + break; VDB("output %s", tdm_status_str(value.u32)); - if (value.u32 == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) - _tdm_vblank_free_HW_wait(private_vblank, 0, 0); + _tdm_vblank_update_output_info(private_vblank); + private_vblank->check_HW_or_SW = 1; + if (private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + if (private_vblank->enable_fake) + _tdm_vblank_change_to_SW(private_vblank); + else + _tdm_vblank_free_HW_wait(private_vblank, TDM_ERROR_OUTPUT_DISCONNECTED, 1); + } break; default: break; @@ -410,8 +455,6 @@ EXTERN tdm_vblank * tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) { tdm_private_vblank *private_vblank; - const tdm_output_mode *mode = NULL; - tdm_output_dpms dpms = TDM_OUTPUT_DPMS_ON; tdm_error ret; TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); @@ -432,16 +475,6 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) vblank_list_inited = 1; } - tdm_output_get_mode(output, &mode); - if (!mode) { - if (error) - *error = TDM_ERROR_OPERATION_FAILED; - TDM_ERR("no mode"); - return NULL; - } - - tdm_output_get_dpms(output, &dpms); - private_vblank = calloc(1, sizeof * private_vblank); if (!private_vblank) { if (error) @@ -456,12 +489,10 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) private_vblank->owner_tid = syscall(SYS_gettid); private_vblank->dpy = dpy; private_vblank->output = output; - private_vblank->dpms = dpms; - private_vblank->vrefresh = mode->vrefresh; - private_vblank->HW_vblank_gap = 1.0 / private_vblank->vrefresh; - private_vblank->check_HW_or_SW = 1; - private_vblank->fps = mode->vrefresh; + private_vblank->fps_changeable = 1; + + _tdm_vblank_update_output_info(private_vblank); strncpy(private_vblank->name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN - 1); private_vblank->name[TDM_NAME_LEN - 1] = '\0'; @@ -472,8 +503,8 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) _tdm_vblank_valid_list_add(&private_vblank->valid_link, &valid_vblank_list); if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("created. vrefresh(%d) dpms(%d)", - private_vblank->vrefresh, private_vblank->dpms); + VIN("created. vrefresh(%d) dpms(%d) connection(%d)", + private_vblank->vrefresh, private_vblank->dpms, private_vblank->connection); return (tdm_vblank *)private_vblank; } @@ -556,6 +587,7 @@ tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) return TDM_ERROR_NONE; private_vblank->fps = fps; + private_vblank->fps_changeable = 0; private_vblank->check_HW_or_SW = 1; if (tdm_debug_module & TDM_DEBUG_VBLANK) @@ -1022,9 +1054,15 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, return TDM_ERROR_BAD_REQUEST; } - if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { - VIN("can't wait a vblank because of DPMS off"); - return TDM_ERROR_DPMS_OFF; + if (!private_vblank->enable_fake) { + if (private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + VIN("can't wait a vblank: output disconnected"); + return TDM_ERROR_OUTPUT_DISCONNECTED; + } + if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON) { + VIN("can't wait a vblank: DPMS off"); + return TDM_ERROR_DPMS_OFF; + } } wait_info = calloc(1, sizeof * wait_info); @@ -1072,7 +1110,8 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, */ if (private_vblank->vrefresh % fps) wait_info->type = VBLANK_TYPE_SW; - else if (private_vblank->dpms == TDM_OUTPUT_DPMS_OFF) + else if (private_vblank->dpms == TDM_OUTPUT_DPMS_OFF || + private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) wait_info->type = VBLANK_TYPE_SW_FAKE; else if (private_vblank->offset == 0) wait_info->type = VBLANK_TYPE_HW; @@ -1083,7 +1122,7 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, ret = _tdm_vblank_wait_SW(wait_info); else { ret = _tdm_vblank_wait_HW(wait_info); - if (ret == TDM_ERROR_DPMS_OFF) + if (ret == TDM_ERROR_OUTPUT_DISCONNECTED || ret == TDM_ERROR_DPMS_OFF) ret = _tdm_vblank_wait_SW(wait_info); } -- 2.7.4 From a053f094985bf7814ee8f4b1bf51f9af6321dd99 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 8 Sep 2017 15:24:28 +0900 Subject: [PATCH 11/16] add debugging logs Change-Id: I3aae4e23b3d6b24f8638ea58673a63e844acb5fa --- src/tdm_server.c | 6 +-- src/tdm_vblank.c | 111 ++++++++++++++++++++++++++++++------------------------- 2 files changed, 64 insertions(+), 53 deletions(-) diff --git a/src/tdm_server.c b/src/tdm_server.c index ca994ce..a8f7175 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -176,7 +176,7 @@ _tdm_server_send_done(tdm_server_wait_info *wait_info, tdm_error error, } if (tdm_debug_module & TDM_DEBUG_VBLANK) - TDM_INFO("req_id(%d) done", wait_info->req_id); + TDM_DBG("req_id(%d) done", wait_info->req_id); TDM_TRACE_COUNT(ServerDoneVBlank, wait_info->req_id); @@ -317,7 +317,7 @@ _tdm_server_vblank_cb_wait_vblank(struct wl_client *client, struct wl_resource * wait_info->req_id = req_id; if (tdm_debug_module & TDM_DEBUG_VBLANK) - TDM_INFO("req_id(%d) wait", req_id); + TDM_DBG("req_id(%d) wait", req_id); ret = tdm_vblank_wait(vblank_info->vblank, req_sec, req_usec, interval, _tdm_server_cb_vblank, wait_info); @@ -359,7 +359,7 @@ _tdm_server_vblank_cb_wait_vblank_seq(struct wl_client *client, struct wl_resour wait_info->req_id = req_id; if (tdm_debug_module & TDM_DEBUG_VBLANK) - TDM_INFO("req_id(%d) wait", req_id); + TDM_DBG("req_id(%d) wait", req_id); ret = tdm_vblank_wait_seq(vblank_info->vblank, req_sec, req_usec, sequence, _tdm_server_cb_vblank, wait_info); diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 337e7cf..2c5eca4 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -71,8 +71,8 @@ #define VER(fmt, arg...) TDM_ERR("[%p] "fmt, private_vblank, ##arg) #define VWR(fmt, arg...) TDM_WRN("[%p] "fmt, private_vblank, ##arg) -#define VIN(fmt, arg...) TDM_INFO("[%p] "fmt, private_vblank, ##arg) -#define VDB(fmt, arg...) TDM_DBG("[%p] "fmt, private_vblank, ##arg) +#define VIN(fmt, arg...) do { if (tdm_debug_module & TDM_DEBUG_VBLANK) TDM_INFO("[%p] "fmt, private_vblank, ##arg); } while (0) +#define VDB(fmt, arg...) do { if (tdm_debug_module & TDM_DEBUG_VBLANK) TDM_DBG("[%p] "fmt, private_vblank, ##arg); } while (0) typedef enum { VBLANK_TYPE_SW, @@ -81,6 +81,12 @@ typedef enum { VBLANK_TYPE_HW_SW, } tdm_vblank_wait_type; +typedef enum { + VBLANK_EVENT_TYPE_NONE, + VBLANK_EVENT_TYPE_SW, + VBLANK_EVENT_TYPE_HW, +} tdm_vblank_event_type; + typedef struct _tdm_vblank_wait_info tdm_vblank_wait_info; typedef struct _tdm_private_vblank { @@ -95,6 +101,7 @@ typedef struct _tdm_private_vblank { tdm_output_dpms dpms; unsigned int vrefresh; + tdm_vblank_event_type last_type; unsigned int check_HW_or_SW; char name[TDM_NAME_LEN]; unsigned int fps; @@ -324,12 +331,17 @@ _tdm_vblank_update_output_info(tdm_private_vblank *private_vblank) if (connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { const tdm_output_mode *mode = NULL; tdm_output_get_mode(output, &mode); - vrefresh = (mode) ? mode->vrefresh : 0; + if (mode) + vrefresh = mode->vrefresh; + else + VWR("mode not setted!!!"); tdm_output_get_dpms(output, &dpms); } - if (vrefresh == 0) + if (vrefresh == 0) { + VWR("vrefresh can't be zero !!!"); vrefresh = TDM_VBLANK_DEFAULT_VREFRESH; + } private_vblank->dpms = dpms; private_vblank->connection = connection; @@ -339,9 +351,9 @@ _tdm_vblank_update_output_info(tdm_private_vblank *private_vblank) if (private_vblank->fps_changeable) private_vblank->fps = vrefresh; - VDB("dpms(%d) connection(%d) vrefresh(%d) fps(%d)", + VIN("dpms(%d) connection(%d) vrefresh(%d) fps(%d) fps_changeable(%d)", private_vblank->dpms, private_vblank->connection, - private_vblank->vrefresh, private_vblank->fps); + private_vblank->vrefresh, private_vblank->fps, private_vblank->fps_changeable); } static void @@ -356,7 +368,7 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, case TDM_OUTPUT_CHANGE_DPMS: if (private_vblank->dpms == value.u32) break; - VDB("dpms %s", tdm_dpms_str(value.u32)); + VIN("dpms %s", tdm_dpms_str(value.u32)); _tdm_vblank_update_output_info(private_vblank); private_vblank->check_HW_or_SW = 1; if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON) { @@ -369,7 +381,7 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, case TDM_OUTPUT_CHANGE_CONNECTION: if (private_vblank->connection == value.u32) break; - VDB("output %s", tdm_status_str(value.u32)); + VIN("output %s", tdm_status_str(value.u32)); _tdm_vblank_update_output_info(private_vblank); private_vblank->check_HW_or_SW = 1; if (private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { @@ -502,9 +514,8 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) _tdm_vblank_valid_list_add(&private_vblank->valid_link, &valid_vblank_list); - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("created. vrefresh(%d) dpms(%d) connection(%d)", - private_vblank->vrefresh, private_vblank->dpms, private_vblank->connection); + VIN("created. vrefresh(%d) dpms(%d) connection(%d)", + private_vblank->vrefresh, private_vblank->dpms, private_vblank->connection); return (tdm_vblank *)private_vblank; } @@ -537,8 +548,7 @@ tdm_vblank_destroy(tdm_vblank *vblank) free(w); } - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("destroyed"); + VIN("destroyed"); free(private_vblank); } @@ -556,8 +566,7 @@ tdm_vblank_set_name(tdm_vblank *vblank, const char *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); + VIN("name(%s)", name); return TDM_ERROR_NONE; } @@ -583,16 +592,17 @@ tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); + if (private_vblank->fps != fps || private_vblank->fps_changeable) + VIN("fps(%d) fps_changeable(0)", fps); + + private_vblank->fps_changeable = 0; + if (private_vblank->fps == fps) return TDM_ERROR_NONE; private_vblank->fps = fps; - private_vblank->fps_changeable = 0; private_vblank->check_HW_or_SW = 1; - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("fps(%d)", private_vblank->fps); - return TDM_ERROR_NONE; } @@ -622,8 +632,7 @@ tdm_vblank_ignore_global_fps(tdm_vblank *vblank, unsigned int ignore) private_vblank->ignore_global_fps = ignore; private_vblank->check_HW_or_SW = 1; - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("ignore_global_fps(%d)", private_vblank->ignore_global_fps); + VIN("ignore_global_fps(%d)", private_vblank->ignore_global_fps); return TDM_ERROR_NONE; } @@ -641,8 +650,7 @@ tdm_vblank_set_offset(tdm_vblank *vblank, int offset) private_vblank->offset = offset; private_vblank->check_HW_or_SW = 1; - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("offset(%d)", private_vblank->offset); + VIN("offset(%d)", private_vblank->offset); return TDM_ERROR_NONE; } @@ -672,8 +680,7 @@ tdm_vblank_set_enable_fake(tdm_vblank *vblank, unsigned int enable_fake) private_vblank->enable_fake = enable_fake; - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("enable_fake(%d)", private_vblank->enable_fake); + VIN("enable_fake(%d)", private_vblank->enable_fake); return TDM_ERROR_NONE; } @@ -719,8 +726,8 @@ _tdm_vblank_sw_timer_update(tdm_private_vblank *private_vblank) if (ms_delay > 5000) VER("wait(%p) curr(%.6f) target(%.6f) ms_delay(%d)", first_wait_info, curr, target, ms_delay); - else if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("wait(%p) curr(%.6f) target(%.6f) ms_delay(%d)", first_wait_info, curr, target, ms_delay); + else + VDB("wait(%p) curr(%.6f) target(%.6f) ms_delay(%d)", first_wait_info, curr, target, ms_delay); tdm_display_lock(private_vblank->dpy); @@ -735,7 +742,7 @@ _tdm_vblank_sw_timer_update(tdm_private_vblank *private_vblank) VER("couldn't add timer"); return ret; } - VIN("Use SW vblank"); + VIN("Create SW timer"); } ret = tdm_event_loop_source_timer_update(private_vblank->SW_timer, ms_delay); @@ -788,8 +795,7 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence, /* wait_info will be freed in _tdm_vblank_cb_vblank_SW() */ if (ret == TDM_ERROR_NONE) { - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("wait(%p) SW timer", wait_info); + VDB("wait(%p) SW timer", wait_info); return; } @@ -810,8 +816,7 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence, private_vblank->last_seq = wait_info->target_seq; private_vblank->last_time = TDM_TIME(tv_sec, tv_usec); - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("wait(%p) last(%.6f) sequence(%u) done", wait_info, private_vblank->last_time, wait_info->target_seq); + VDB("wait(%p) last(%.6f) sequence(%u) done", wait_info, private_vblank->last_time, wait_info->target_seq); if (wait_info->func) wait_info->func(private_vblank, TDM_ERROR_NONE, wait_info->target_seq, @@ -829,6 +834,11 @@ _tdm_vblank_wait_HW(tdm_vblank_wait_info *wait_info) int hw_interval; tdm_error ret; + if (private_vblank->last_type != VBLANK_EVENT_TYPE_HW) { + VIN("Use HW vblank"); + private_vblank->last_type = VBLANK_EVENT_TYPE_HW; + } + _tdm_vblank_insert_wait(wait_info, &private_vblank->HW_wait_list); hw_interval = wait_info->interval * private_vblank->quotient; @@ -840,9 +850,9 @@ _tdm_vblank_wait_HW(tdm_vblank_wait_info *wait_info) /* +1 ms to call the handler ASAP at the first. no matter for SW timer. */ wait_info->target_seq = 1; - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("wait(%p) last(%.6f) hw_itvl(%d) targ_seq(%u)", - wait_info, private_vblank->last_time, hw_interval, wait_info->target_seq); + + VDB("wait(%p) last(%.6f) hw_itvl(%d) targ_seq(%u)", + wait_info, private_vblank->last_time, hw_interval, wait_info->target_seq); } else { double last, prev, req, curr, target; unsigned int skip; @@ -871,8 +881,8 @@ _tdm_vblank_wait_HW(tdm_vblank_wait_info *wait_info) VER("wait(%p) last(%.6f) req(%.6f) prev(%.6f) curr(%.6f) targ(%.6f,%.6f) skip(%u) hw_itvl(%d) targ_seq(%u)", wait_info, last, req - last, prev - last, curr - last, target, target - last, skip, hw_interval, wait_info->target_seq); - else if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("wait(%p) last(%.6f) req(%.6f) prev(%.6f) curr(%.6f) targ(%.6f,%.6f) skip(%u) hw_itvl(%d) targ_seq(%u)", + else + VDB("wait(%p) last(%.6f) req(%.6f) prev(%.6f) curr(%.6f) targ(%.6f,%.6f) skip(%u) hw_itvl(%d) targ_seq(%u)", wait_info, last, req - last, prev - last, curr - last, target, target - last, skip, hw_interval, wait_info->target_seq); } @@ -889,8 +899,7 @@ _tdm_vblank_wait_HW(tdm_vblank_wait_info *wait_info) return ret; } - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("wait(%p) waiting", wait_info); + VDB("wait(%p) waiting", wait_info); return TDM_ERROR_NONE; } @@ -952,8 +961,7 @@ tdm_vblank_cb_vblank_SW(tdm_vblank *vblank, double vblank_stamp) private_vblank->last_seq = first_wait_info->target_seq; private_vblank->last_time = first_wait_info->target_time; - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("wait(%p) last(%.6f) sequence(%u) done", first_wait_info, private_vblank->last_time, first_wait_info->target_seq); + VDB("wait(%p) last(%.6f) sequence(%u) done", first_wait_info, private_vblank->last_time, first_wait_info->target_seq); LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->SW_wait_list, link) { if (w->target_time != first_wait_info->target_time) @@ -982,6 +990,11 @@ _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info) tdm_private_vblank *private_vblank = wait_info->private_vblank; tdm_error ret; + if (private_vblank->last_type != VBLANK_EVENT_TYPE_SW) { + VIN("Use SW vblank"); + private_vblank->last_type = VBLANK_EVENT_TYPE_SW; + } + if (private_vblank->last_time == 0) { /* SW vblank starts from now. SW vblank doesn't need to be aligned with HW vblank. */ private_vblank->last_seq = 0; @@ -991,9 +1004,8 @@ _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info) wait_info->target_seq = 1; wait_info->target_time = private_vblank->last_time + 0.001; - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("wait(%p) last(%.6f) target(%.6f) target sequence(%u)", - wait_info, private_vblank->last_time, wait_info->target_time, wait_info->target_seq); + VDB("wait(%p) last(%.6f) target(%.6f) target sequence(%u)", + wait_info, private_vblank->last_time, wait_info->target_time, wait_info->target_seq); } else { double last, prev, req, curr, target; unsigned int skip; @@ -1019,10 +1031,9 @@ _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info) wait_info->target_time = target; - if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("wait(%p) last(%.6f) req(%.6f) prev(%.6f) curr(%.6f) targ(%.6f,%.6f) skip(%u) targ_seq(%u)", - wait_info, last, req - last, prev - last, curr - last, - target, target - last, skip, wait_info->target_seq); + VDB("wait(%p) last(%.6f) req(%.6f) prev(%.6f) curr(%.6f) targ(%.6f,%.6f) skip(%u) targ_seq(%u)", + wait_info, last, req - last, prev - last, curr - last, + target, target - last, skip, wait_info->target_seq); } _tdm_vblank_insert_wait(wait_info, &private_vblank->SW_wait_list); @@ -1056,11 +1067,11 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, if (!private_vblank->enable_fake) { if (private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { - VIN("can't wait a vblank: output disconnected"); + VER("can't wait a vblank: output disconnected"); return TDM_ERROR_OUTPUT_DISCONNECTED; } if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON) { - VIN("can't wait a vblank: DPMS off"); + VER("can't wait a vblank: DPMS off"); return TDM_ERROR_DPMS_OFF; } } -- 2.7.4 From cf1e6c471a5cb12ab99fd3ab7e9273c8c7fbc414 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 8 Sep 2017 16:43:44 +0900 Subject: [PATCH 12/16] package vesion up to 1.7.8 Change-Id: Iaeeff325761e15d591326dbf73ce63be53bedb9f --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 8c78b8b..32c0e1c 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,7 +1,7 @@ %bcond_with utest Name: libtdm -Version: 1.7.7 +Version: 1.7.8 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From c53ac731efd168cf1dc70f673e8c6555baabe978 Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Fri, 1 Sep 2017 11:34:46 +0300 Subject: [PATCH 13/16] HWC: unlock mutex before return Change-Id: I1f1cdf0b9b054bb7d0def96e97ff33aa2fc097a7 Signed-off-by: Roman Marchenko --- src/tdm_output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tdm_output.c b/src/tdm_output.c index 043074a..75a4e46 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -300,6 +300,7 @@ tdm_output_get_layer_count(tdm_output *output, int *count) if (private_display->hwc_enable) { *count = 0; + _pthread_mutex_unlock(&private_display->lock); return TDM_ERROR_NONE; } -- 2.7.4 From dbf220bc30ca25a0cd05cb0d1d8626215d7470a7 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 13 Sep 2017 16:12:54 +0900 Subject: [PATCH 14/16] load a dummy module if failed to load a default module Change-Id: I29efec59122b4e6b4a9666b901edf214fd09221b --- src/tdm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tdm.c b/src/tdm.c index 7723018..a27247b 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -659,7 +659,8 @@ tdm_display_update(tdm_display *dpy) } #define SUFFIX_MODULE ".so" -#define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE +#define TDM_DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE +#define TDM_DUMMY_MODULE "libtdm-dummy"SUFFIX_MODULE int tdm_debug_module; int tdm_debug_dump; @@ -844,13 +845,18 @@ _tdm_display_load_module(tdm_private_display *private_display) module_name = getenv("TDM_MODULE"); if (!module_name) - module_name = DEFAULT_MODULE; + module_name = TDM_DEFAULT_MODULE; /* load bufmgr priv from default lib */ ret = _tdm_display_load_module_with_file(private_display, module_name); if (ret == TDM_ERROR_NONE) return TDM_ERROR_NONE; + /* load bufmgr priv from dummy lib */ + ret = _tdm_display_load_module_with_file(private_display, TDM_DUMMY_MODULE); + if (ret == TDM_ERROR_NONE) + return TDM_ERROR_NONE; + /* load bufmgr priv from configured path */ n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort); if (n < 0) { -- 2.7.4 From daa2f47914cf0fbba3cc20359fc95b5fec77ade7 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 13 Sep 2017 12:41:19 +0900 Subject: [PATCH 15/16] backend: add dummy backend. Change-Id: I5829d55e3f14d531c55adab3fde9bcaf145464cd --- Makefile.am | 4 +- backends/Makefile.am | 1 + backends/dummy/Makefile.am | 14 + backends/dummy/tdm_dummy.c | 134 ++++++++ backends/dummy/tdm_dummy.h | 76 +++++ backends/dummy/tdm_dummy_display.c | 636 +++++++++++++++++++++++++++++++++++++ configure.ac | 3 + packaging/libtdm.spec | 1 + 8 files changed, 867 insertions(+), 2 deletions(-) create mode 100644 backends/Makefile.am create mode 100644 backends/dummy/Makefile.am create mode 100644 backends/dummy/tdm_dummy.c create mode 100644 backends/dummy/tdm_dummy.h create mode 100644 backends/dummy/tdm_dummy_display.c diff --git a/Makefile.am b/Makefile.am index 292911f..8b6604d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,8 +1,8 @@ if HAVE_UTEST -SUBDIRS = . include protocol common src client tools ut +SUBDIRS = . include protocol common src backends client tools ut else -SUBDIRS = . include protocol common src client tools +SUBDIRS = . include protocol common src backends client tools endif pkgconfigdir = $(libdir)/pkgconfig diff --git a/backends/Makefile.am b/backends/Makefile.am new file mode 100644 index 0000000..4a66860 --- /dev/null +++ b/backends/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = dummy diff --git a/backends/dummy/Makefile.am b/backends/dummy/Makefile.am new file mode 100644 index 0000000..459ffe1 --- /dev/null +++ b/backends/dummy/Makefile.am @@ -0,0 +1,14 @@ +AM_CFLAGS = \ + $(CFLAGS) \ + $(TDM_CFLAGS) \ + -I$(top_srcdir)/include + +libtdm_dummy_la_LTLIBRARIES = libtdm-dummy.la +libtdm_dummy_ladir = $(TDM_MODULE_PATH) +libtdm_dummy_la_LDFLAGS = -module -avoid-version +libtdm_dummy_la_LIBADD = $(TDM_LIBS) $(top_builddir)/src/libtdm.la + +libtdm_dummy_la_SOURCES = \ + tdm_dummy_display.c \ + tdm_dummy.c + diff --git a/backends/dummy/tdm_dummy.c b/backends/dummy/tdm_dummy.c new file mode 100644 index 0000000..a39f579 --- /dev/null +++ b/backends/dummy/tdm_dummy.c @@ -0,0 +1,134 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm_dummy.h" + +static tdm_dummy_data *dummy_data; + +void +tdm_dummy_deinit(tdm_backend_data *bdata) +{ + if (dummy_data != bdata) + return; + + TDM_INFO("deinit"); + + tdm_dummy_display_destroy_output_list(dummy_data); + + if (dummy_data->pipe[0] >= 0) + close(dummy_data->pipe[0]); + if (dummy_data->pipe[1] >= 0) + close(dummy_data->pipe[1]); + + free(dummy_data); + dummy_data = NULL; +} + +tdm_backend_data * +tdm_dummy_init(tdm_display *dpy, tdm_error *error) +{ + tdm_func_display dummy_func_display; + tdm_func_output dummy_func_output; + tdm_func_layer dummy_func_layer; + tdm_error ret; + + if (!dpy) { + TDM_ERR("display is null"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + if (dummy_data) { + TDM_ERR("failed: init twice"); + if (error) + *error = TDM_ERROR_BAD_REQUEST; + return NULL; + } + + dummy_data = calloc(1, sizeof(tdm_dummy_data)); + if (!dummy_data) { + TDM_ERR("alloc failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + LIST_INITHEAD(&dummy_data->output_list); + LIST_INITHEAD(&dummy_data->buffer_list); + + memset(&dummy_func_display, 0, sizeof(dummy_func_display)); + dummy_func_display.display_get_capability = dummy_display_get_capability; + dummy_func_display.display_get_outputs = dummy_display_get_outputs; + dummy_func_display.display_get_fd = dummy_display_get_fd; + dummy_func_display.display_handle_events = dummy_display_handle_events; + + memset(&dummy_func_output, 0, sizeof(dummy_func_output)); + dummy_func_output.output_get_capability = dummy_output_get_capability; + dummy_func_output.output_get_layers = dummy_output_get_layers; + dummy_func_output.output_wait_vblank = dummy_output_wait_vblank; + dummy_func_output.output_set_vblank_handler = dummy_output_set_vblank_handler; + dummy_func_output.output_commit = dummy_output_commit; + dummy_func_output.output_set_commit_handler = dummy_output_set_commit_handler; + dummy_func_output.output_set_mode = dummy_output_set_mode; + dummy_func_output.output_get_mode = dummy_output_get_mode; + + memset(&dummy_func_layer, 0, sizeof(dummy_func_layer)); + dummy_func_layer.layer_get_capability = dummy_layer_get_capability; + dummy_func_layer.layer_set_info = dummy_layer_set_info; + dummy_func_layer.layer_get_info = dummy_layer_get_info; + dummy_func_layer.layer_set_buffer = dummy_layer_set_buffer; + dummy_func_layer.layer_unset_buffer = dummy_layer_unset_buffer; + + ret = tdm_backend_register_func_display(dpy, &dummy_func_display); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_backend_register_func_output(dpy, &dummy_func_output); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_backend_register_func_layer(dpy, &dummy_func_layer); + if (ret != TDM_ERROR_NONE) + goto failed; + + dummy_data->dpy = dpy; + + if (pipe(dummy_data->pipe) < 0) { + TDM_ERR("failed get pipe: %m"); + ret = TDM_ERROR_OPERATION_FAILED; + goto failed; + } + + ret = tdm_dummy_display_create_output_list(dummy_data); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_dummy_display_create_layer_list(dummy_data); + if (ret != TDM_ERROR_NONE) + goto failed; + + if (error) + *error = TDM_ERROR_NONE; + + TDM_INFO("init success!"); + + return (tdm_backend_data *)dummy_data; +failed: + if (error) + *error = ret; + + tdm_dummy_deinit(dummy_data); + + TDM_ERR("init failed!"); + return NULL; +} + +tdm_backend_module tdm_backend_module_data = { + "Dummy", + "Samsung", + TDM_BACKEND_SET_ABI_VERSION(1, 1), + tdm_dummy_init, + tdm_dummy_deinit +}; diff --git a/backends/dummy/tdm_dummy.h b/backends/dummy/tdm_dummy.h new file mode 100644 index 0000000..a55f4c4 --- /dev/null +++ b/backends/dummy/tdm_dummy.h @@ -0,0 +1,76 @@ +#ifndef _TDM_DUMMY_H_ +#define _TDM_DUMMY_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* dummy backend functions (display) */ +tdm_error dummy_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps); +tdm_output** dummy_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error); +tdm_error dummy_display_get_fd(tdm_backend_data *bdata, int *fd); +tdm_error dummy_display_handle_events(tdm_backend_data *bdata); + +tdm_error dummy_output_get_capability(tdm_output *output, tdm_caps_output *caps); +tdm_layer** dummy_output_get_layers(tdm_output *output, int *count, tdm_error *error); +tdm_error dummy_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data); +tdm_error dummy_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func); +tdm_error dummy_output_commit(tdm_output *output, int sync, void *user_data); +tdm_error dummy_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func); +tdm_error dummy_output_set_mode(tdm_output *output, const tdm_output_mode *mode); +tdm_error dummy_output_get_mode(tdm_output *output, const tdm_output_mode **mode); + +tdm_error dummy_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps); +tdm_error dummy_layer_set_info(tdm_layer *layer, tdm_info_layer *info); +tdm_error dummy_layer_get_info(tdm_layer *layer, tdm_info_layer *info); +tdm_error dummy_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer); +tdm_error dummy_layer_unset_buffer(tdm_layer *layer); + +#define RETURN_VAL_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + return val;\ + }\ +} + +#define GOTO_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + goto val;\ + }\ +} + +typedef struct _tdm_dummy_data +{ + tdm_display *dpy; + + int pipe[2]; + + struct list_head output_list; + struct list_head buffer_list; +} tdm_dummy_data; + +tdm_error tdm_dummy_display_create_output_list(tdm_dummy_data *dummy_data); +void tdm_dummy_display_destroy_output_list(tdm_dummy_data *dummy_data); +tdm_error tdm_dummy_display_create_layer_list(tdm_dummy_data *dummy_data); + +#endif /* _TDM_DUMMY_H_ */ diff --git a/backends/dummy/tdm_dummy_display.c b/backends/dummy/tdm_dummy_display.c new file mode 100644 index 0000000..5e64fb3 --- /dev/null +++ b/backends/dummy/tdm_dummy_display.c @@ -0,0 +1,636 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm_dummy.h" + +typedef struct _tdm_dummy_output_data tdm_dummy_output_data; +typedef struct _tdm_dummy_layer_data tdm_dummy_layer_data; +typedef struct _tdm_dummy_event_data tdm_dummy_event_data; + +typedef enum { + TDM_DUMMY_EVENT_TYPE_WAIT, + TDM_DUMMY_EVENT_TYPE_COMMIT, +} tdm_dummy_event_type; + +struct _tdm_dummy_event_data { + struct list_head link; + + tdm_dummy_event_type type; + tdm_dummy_output_data *output_data; + void *user_data; +}; + +struct _tdm_dummy_output_data { + struct list_head link; + + /* data which are fixed at initializing */ + tdm_dummy_data *dummy_data; + + uint32_t pipe; + tdm_output_mode *output_mode; + tdm_output_type connector_type; + struct list_head layer_list; + tdm_dummy_layer_data *primary_layer; + + /* not fixed data below */ + tdm_output_vblank_handler vblank_func; + tdm_output_commit_handler commit_func; + + tdm_output_conn_status status; + + int mode_changed; + const tdm_output_mode *current_mode; + + tdm_event_loop_source *timer; + unsigned int timer_waiting; + struct list_head timer_event_list; +}; + +struct _tdm_dummy_layer_data { + struct list_head link; + + /* data which are fixed at initializing */ + tdm_dummy_data *dummy_data; + tdm_dummy_output_data *output_data; + tdm_layer_capability capabilities; + int zpos; + + /* not fixed data below */ + tdm_info_layer info; + int info_changed; + + tbm_surface_h display_buffer; + int display_buffer_changed; +}; + +static void +_tdm_dummy_display_cb_event(tdm_dummy_output_data *output_data, tdm_dummy_event_data *event_data, + unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec) +{ + switch (event_data->type) { + case TDM_DUMMY_EVENT_TYPE_WAIT: + if (output_data->vblank_func) + output_data->vblank_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data); + break; + case TDM_DUMMY_EVENT_TYPE_COMMIT: + if (output_data->commit_func) + output_data->commit_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data); + break; + default: + break; + } +} + +static tdm_error +_tdm_dummy_display_cb_timeout(void *user_data) +{ + tdm_dummy_output_data *output_data = user_data; + tdm_dummy_event_data *e = NULL, *ee = NULL; + unsigned int tv_sec, tv_usec; + static unsigned int sequence = 0; + struct timespec tp; + + sequence++; + + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) { + tv_sec = tp.tv_sec; + tv_usec = tp.tv_nsec / 1000; + } else { + tv_sec = tv_usec = 0; + } + + LIST_FOR_EACH_ENTRY_SAFE(e, ee, &output_data->timer_event_list, link) { + LIST_DEL(&e->link); + _tdm_dummy_display_cb_event(output_data, e, sequence, tv_sec, tv_usec); + free(e); + } + + return TDM_ERROR_NONE; +} + +static tdm_error +_tdm_dummy_display_wait_vblank(tdm_dummy_output_data *output_data, tdm_dummy_event_data *event_data) +{ + tdm_error ret; + unsigned int ms; + + RETURN_VAL_IF_FAIL(output_data->timer != NULL, TDM_ERROR_OPERATION_FAILED); + RETURN_VAL_IF_FAIL(output_data->output_mode->vrefresh > 0, TDM_ERROR_OPERATION_FAILED); + + if (output_data->timer_waiting) { + LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list); + return TDM_ERROR_NONE; + } + + ms = 1000 / output_data->output_mode->vrefresh; + + ret = tdm_event_loop_source_timer_update(output_data->timer, ms); + if (ret != TDM_ERROR_NONE) + return ret; + + LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list); + + return TDM_ERROR_NONE; +} + +static void +_tdm_dummy_display_destroy_layer_list(tdm_dummy_data *dummy_data) +{ + tdm_dummy_output_data *o = NULL; + + LIST_FOR_EACH_ENTRY(o, &dummy_data->output_list, link) { + tdm_dummy_layer_data *l = NULL, *ll = NULL; + LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) { + LIST_DEL(&l->link); + free(l); + } + } +} + +tdm_error +tdm_dummy_display_create_layer_list(tdm_dummy_data *dummy_data) +{ + tdm_dummy_output_data *output_data = NULL; + tdm_error ret = TDM_ERROR_NONE; + + if (LIST_IS_EMPTY(&dummy_data->output_list)) { + TDM_ERR("no output"); + return TDM_ERROR_OPERATION_FAILED; + } + + /* The TDM dummy backend only support one output. */ + LIST_FOR_EACH_ENTRY(output_data, &dummy_data->output_list, link) { + tdm_dummy_layer_data *layer_data = calloc(1, sizeof(tdm_dummy_layer_data)); + if (!layer_data) { + TDM_ERR("alloc failed"); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed; + } + + layer_data->dummy_data = dummy_data; + layer_data->output_data = output_data; + layer_data->zpos = 0; + + layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC; + output_data->primary_layer = layer_data; + + LIST_ADDTAIL(&layer_data->link, &output_data->layer_list); + } + + return TDM_ERROR_NONE; +failed: + _tdm_dummy_display_destroy_layer_list(dummy_data); + return ret; +} + +void +tdm_dummy_display_destroy_output_list(tdm_dummy_data *dummy_data) +{ + tdm_dummy_output_data *o = NULL, *oo = NULL; + + if (LIST_IS_EMPTY(&dummy_data->output_list)) + return; + + _tdm_dummy_display_destroy_layer_list(dummy_data); + + LIST_FOR_EACH_ENTRY_SAFE(o, oo, &dummy_data->output_list, link) { + LIST_DEL(&o->link); + + if (!LIST_IS_EMPTY(&o->timer_event_list)) { + tdm_dummy_event_data *e = NULL, *ee = NULL; + LIST_FOR_EACH_ENTRY_SAFE(e, ee, &o->timer_event_list, link) { + LIST_DEL(&e->link); + free(e); + } + } + + if (o->timer) + tdm_event_loop_source_remove(o->timer); + + free(o->output_mode); + free(o); + } +} + +tdm_error +tdm_dummy_display_create_output_list(tdm_dummy_data *dummy_data) +{ + tdm_dummy_output_data *output_data; + tdm_error ret; + + RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&dummy_data->output_list), TDM_ERROR_OPERATION_FAILED); + + output_data = calloc(1, sizeof(tdm_dummy_output_data)); + if (!output_data) { + TDM_ERR("alloc failed"); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_create; + } + + LIST_INITHEAD(&output_data->layer_list); + + output_data->dummy_data = dummy_data; + output_data->pipe = 0; + output_data->connector_type = TDM_OUTPUT_TYPE_Unknown; + output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED; + + output_data->output_mode = calloc(1, sizeof(tdm_output_mode)); + if (!output_data->output_mode) { + TDM_ERR("alloc failed"); + free(output_data); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_create; + } + + snprintf(output_data->output_mode->name, TDM_NAME_LEN, "640x480"); + output_data->output_mode->vrefresh = 30; + output_data->output_mode->clock = 25200; + output_data->output_mode->hdisplay = 640; + output_data->output_mode->hsync_start = 656; + output_data->output_mode->hsync_end = 752; + output_data->output_mode->htotal = 800; + output_data->output_mode->hskew = 0; + output_data->output_mode->vdisplay = 480; + output_data->output_mode->vsync_start = 490; + output_data->output_mode->vsync_end = 492; + output_data->output_mode->vtotal = 525; + output_data->output_mode->vscan = 0; + output_data->output_mode->flags = 0; + output_data->output_mode->type = 0; + + output_data->timer = tdm_event_loop_add_timer_handler(dummy_data->dpy, + _tdm_dummy_display_cb_timeout, + output_data, + &ret); + if (!output_data->timer) { + free(output_data); + return ret; + } + + LIST_INITHEAD(&output_data->timer_event_list); + + LIST_ADDTAIL(&output_data->link, &dummy_data->output_list); + + return TDM_ERROR_NONE; +failed_create: + tdm_dummy_display_destroy_output_list(dummy_data); + return ret; +} + +tdm_error +dummy_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps) +{ + RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER); + + caps->max_layer_count = -1; /* not defined */ + + return TDM_ERROR_NONE; +} + +tdm_output ** +dummy_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error) +{ + tdm_dummy_data *dummy_data = bdata; + tdm_dummy_output_data *output_data = NULL; + tdm_output **outputs; + tdm_error ret; + int i; + + RETURN_VAL_IF_FAIL(dummy_data, NULL); + RETURN_VAL_IF_FAIL(count, NULL); + + *count = 0; + LIST_FOR_EACH_ENTRY(output_data, &dummy_data->output_list, link) + (*count)++; + + if (*count == 0) { + ret = TDM_ERROR_NONE; + goto failed_get; + } + + /* will be freed in frontend */ + outputs = calloc(*count, sizeof(tdm_dummy_output_data *)); + if (!outputs) { + TDM_ERR("failed: alloc memory"); + *count = 0; + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_get; + } + + i = 0; + LIST_FOR_EACH_ENTRY(output_data, &dummy_data->output_list, link) + outputs[i++] = output_data; + + if (error) + *error = TDM_ERROR_NONE; + + return outputs; +failed_get: + if (error) + *error = ret; + return NULL; +} + +tdm_error +dummy_display_get_fd(tdm_backend_data *bdata, int *fd) +{ + tdm_dummy_data *dummy_data = bdata; + + RETURN_VAL_IF_FAIL(dummy_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER); + + *fd = dummy_data->pipe[0]; + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_display_handle_events(tdm_backend_data *bdata) +{ + return TDM_ERROR_NONE; +} + +tdm_error +dummy_output_get_capability(tdm_output *output, tdm_caps_output *caps) +{ + tdm_dummy_output_data *output_data = output; + tdm_error ret; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER); + + memset(caps, 0, sizeof(tdm_caps_output)); + + snprintf(caps->maker, TDM_NAME_LEN, "dummy"); + snprintf(caps->model, TDM_NAME_LEN, "dummy"); + snprintf(caps->name, TDM_NAME_LEN, "dummy"); + + caps->status = output_data->status; + caps->type = output_data->connector_type; + caps->type_id = 0; + + caps->mode_count = 1; + caps->modes = calloc(1, sizeof(tdm_output_mode)); + if (!caps->modes) { + ret = TDM_ERROR_OUT_OF_MEMORY; + TDM_ERR("alloc failed\n"); + goto failed_get; + } + + *caps->modes = *output_data->output_mode; + + caps->mmWidth = 640; + caps->mmHeight = 480; + caps->subpixel = 1; + + caps->min_w = -1; + caps->min_h = -1; + caps->max_w = -1; + caps->max_h = -1; + caps->preferred_align = -1; + + caps->prop_count = 0; + + return TDM_ERROR_NONE; +failed_get: + memset(caps, 0, sizeof(tdm_caps_output)); + return ret; +} + +tdm_layer ** +dummy_output_get_layers(tdm_output *output, int *count, tdm_error *error) +{ + tdm_dummy_output_data *output_data = output; + tdm_dummy_layer_data *layer_data = NULL; + tdm_layer **layers; + tdm_error ret; + int i; + + RETURN_VAL_IF_FAIL(output_data, NULL); + RETURN_VAL_IF_FAIL(count, NULL); + + *count = 0; + LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) + (*count)++; + + if (*count == 0) { + ret = TDM_ERROR_NONE; + goto failed_get; + } + + /* will be freed in frontend */ + layers = calloc(*count, sizeof(tdm_dummy_layer_data *)); + if (!layers) { + TDM_ERR("failed: alloc memory"); + *count = 0; + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_get; + } + + i = 0; + LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) + layers[i++] = layer_data; + + if (error) + *error = TDM_ERROR_NONE; + + return layers; +failed_get: + if (error) + *error = ret; + return NULL; +} + +tdm_error +dummy_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data) +{ + tdm_dummy_output_data *output_data = output; + tdm_dummy_event_data *event_data; + tdm_error ret; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + + event_data = calloc(1, sizeof(tdm_dummy_event_data)); + if (!event_data) { + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + event_data->type = TDM_DUMMY_EVENT_TYPE_WAIT; + event_data->output_data = output_data; + event_data->user_data = user_data; + + ret = _tdm_dummy_display_wait_vblank(output_data, event_data); + if (ret != TDM_ERROR_NONE) { + free(event_data); + return ret; + } + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func) +{ + tdm_dummy_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER); + + output_data->vblank_func = func; + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_output_commit(tdm_output *output, int sync, void *user_data) +{ + tdm_dummy_output_data *output_data = output; + tdm_dummy_event_data *event_data; + tdm_error ret; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + + event_data = calloc(1, sizeof(tdm_dummy_event_data)); + if (!event_data) { + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + event_data->type = TDM_DUMMY_EVENT_TYPE_COMMIT; + event_data->output_data = output_data; + event_data->user_data = user_data; + + ret = _tdm_dummy_display_wait_vblank(output_data, event_data); + if (ret != TDM_ERROR_NONE) { + free(event_data); + return ret; + } + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func) +{ + tdm_dummy_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER); + + output_data->commit_func = func; + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_output_set_mode(tdm_output *output, const tdm_output_mode *mode) +{ + tdm_dummy_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER); + + output_data->current_mode = mode; + output_data->mode_changed = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_output_get_mode(tdm_output *output, const tdm_output_mode **mode) +{ + tdm_dummy_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER); + + *mode = output_data->current_mode; + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps) +{ + tdm_dummy_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER); + + memset(caps, 0, sizeof(tdm_caps_layer)); + + caps->capabilities = layer_data->capabilities; + caps->zpos = layer_data->zpos; + + caps->format_count = 2; + caps->formats = calloc(caps->format_count, sizeof(tbm_format)); + if (!caps->formats) { + TDM_ERR("alloc failed\n"); + free(caps->formats); + memset(caps, 0, sizeof(tdm_caps_layer)); + return TDM_ERROR_OUT_OF_MEMORY; + } + + caps->formats[0] = TBM_FORMAT_ARGB8888; + caps->formats[1] = TBM_FORMAT_XRGB8888; + + caps->prop_count = 0; + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_layer_set_info(tdm_layer *layer, tdm_info_layer *info) +{ + tdm_dummy_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER); + + layer_data->info = *info; + layer_data->info_changed = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_layer_get_info(tdm_layer *layer, tdm_info_layer *info) +{ + tdm_dummy_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER); + + *info = layer_data->info; + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) +{ + tdm_dummy_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER); + + layer_data->display_buffer = buffer; + layer_data->display_buffer_changed = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +dummy_layer_unset_buffer(tdm_layer *layer) +{ + tdm_dummy_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + + layer_data->display_buffer = NULL; + layer_data->display_buffer_changed = 1; + + return TDM_ERROR_NONE; +} diff --git a/configure.ac b/configure.ac index a4cb6b8..40a3816 100644 --- a/configure.ac +++ b/configure.ac @@ -70,6 +70,7 @@ AC_ARG_WITH(tdm-module-path, AS_HELP_STRING([--with-tdm-module-path=PATH], [tdm [ TDM_MODULE_PATH="$withval" ], [ TDM_MODULE_PATH="${DEFAULT_TDM_MODULE_PATH}" ]) AC_DEFINE_UNQUOTED(TDM_MODULE_PATH, "${TDM_MODULE_PATH}", [Directory for the modules of tdm]) +AC_SUBST(TDM_MODULE_PATH) AC_SUBST([TDM_MAJOR_VERSION], [tdm_major_version]) AC_SUBST([TDM_MINOR_VERSION], [tdm_minor_version]) @@ -89,6 +90,8 @@ AC_OUTPUT([ protocol/Makefile common/Makefile src/Makefile + backends/Makefile + backends/dummy/Makefile client/libtdm-client.pc client/Makefile tools/Makefile diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 32c0e1c..60fd5ed 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -101,6 +101,7 @@ rm -f %{_unitdir_user}/basic.target.wants/tdm-socket-user.path %defattr(-,root,root,-) %license COPYING %{_libdir}/libtdm.so.* +%{_libdir}/tdm/libtdm-dummy.so %attr(750,root,root) %{_bindir}/tdm-monitor %{_unitdir_user}/tdm-socket-user.path %{_unitdir_user}/tdm-socket-user.service -- 2.7.4 From 8b2428d14d113872f51c5f02b29c1996d7566524 Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Wed, 20 Sep 2017 15:52:52 +0300 Subject: [PATCH 16/16] hwc: unlock mutex before return Change-Id: I25618928beadacc26000e1b215c864144ebcf1d5 Signed-off-by: Konstantin Drabeniuk --- src/tdm_output.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tdm_output.c b/src/tdm_output.c index 3bafd32..1d84a1c 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -331,7 +331,9 @@ tdm_output_get_layer(tdm_output *output, int index, tdm_error *error) *error = TDM_ERROR_NONE; if (private_display->hwc_enable) { - *error = TDM_ERROR_INVALID_PARAMETER; + _pthread_mutex_unlock(&private_display->lock); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; return NULL; } -- 2.7.4