From a542ccbcbbee734a35d5de1cd3feae2493097dda Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Fri, 24 Nov 2017 14:43:42 +0200 Subject: [PATCH 01/16] add excluding coverage comments for tdm.c and tdm_thread.c As we test only API's funcs add excluding coverage comments for all static func in the tdm.c file. Add excluding coverage comments for tdm_thread.c for the folowing code: - TDM_THREAD_CB_OUTPUT_STATUS(it is not supported by all targets) - TDM_THREAD_CB_OUTPUT_DPMS(it is not supported by all targets) Change-Id: I8f404184774589c27f8c0dfe21574755434a75c8 Signed-off-by: Konstantin Drabeniuk --- src/tdm.c | 12 ++++++++++++ src/tdm_thread.c | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/tdm.c b/src/tdm.c index 7c36041..418010c 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -50,6 +50,7 @@ int tdm_mutex_lock_line; const char *tdm_mutex_unlock_func; int tdm_mutex_unlock_line; +/* LCOV_EXCL_START */ static tdm_private_layer * _tdm_display_find_private_layer(tdm_private_output *private_output, tdm_layer *layer_backend) @@ -652,6 +653,7 @@ failed_update: _tdm_display_destroy_private_display(private_display); return ret; } +/* LCOV_EXCL_STOP */ EXTERN tdm_error tdm_display_update(tdm_display *dpy) @@ -681,6 +683,7 @@ int tdm_debug_dump; static tdm_private_display *g_private_display; static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER; +/* LCOV_EXCL_START */ static tdm_error _tdm_display_check_module(tdm_backend_module *module) { @@ -909,6 +912,7 @@ _tdm_display_unload_module(tdm_private_display *private_display) private_display->module_data = NULL; private_display->module = NULL; } +/* LCOV_EXCL_STOP */ EXTERN tdm_display * tdm_display_init(tdm_error *error) @@ -932,9 +936,11 @@ tdm_display_init(tdm_error *error) private_display = calloc(1, sizeof(tdm_private_display)); if (!private_display) { + /* LCOV_EXCL_START */ ret = TDM_ERROR_OUT_OF_MEMORY; TDM_ERR("'private_display != NULL' failed"); goto failed_alloc; + /* LCOV_EXCL_STOP */ } str = getenv("TDM_DEBUG_MODULE"); @@ -950,9 +956,11 @@ tdm_display_init(tdm_error *error) tdm_display_enable_path(str); if (pthread_mutex_init(&private_display->lock, NULL)) { + /* LCOV_EXCL_START */ ret = TDM_ERROR_OPERATION_FAILED; TDM_ERR("mutex init failed: %m"); goto failed_mutex_init; + /* LCOV_EXCL_STOP */ } _pthread_mutex_lock(&private_display->lock); @@ -1043,6 +1051,7 @@ tdm_display_init(tdm_error *error) return (tdm_display *)private_display; +/* LCOV_EXCL_START */ failed_update: _tdm_display_unload_module(private_display); failed_load: @@ -1058,6 +1067,7 @@ failed_alloc: *error = ret; pthread_mutex_unlock(&gLock); return NULL; +/* LCOV_EXCL_STOP */ } EXTERN void @@ -1109,6 +1119,7 @@ tdm_display_deinit(tdm_display *dpy) TDM_INFO("done"); } +/* LCOV_EXCL_START */ INTERN int tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin) { @@ -1359,3 +1370,4 @@ tdm_display_enable_fps(tdm_private_display *private_display, int enable) return TDM_ERROR_NONE; } +/* LCOV_EXCL_STOP */ diff --git a/src/tdm_thread.c b/src/tdm_thread.c index 8f624e1..ed5d049 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -307,6 +307,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) break; } case TDM_THREAD_CB_OUTPUT_STATUS: { + /* LCOV_EXCL_START */ tdm_thread_cb_output_status *output_status = (tdm_thread_cb_output_status*)base; tdm_output *output_backend = tdm_display_find_output_stamp(private_loop->dpy, output_status->output_stamp); @@ -317,8 +318,10 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) tdm_output_cb_status(output_backend, output_status->status, output_status->user_data); break; + /* LCOV_EXCL_STOP */ } case TDM_THREAD_CB_OUTPUT_DPMS: { + /* LCOV_EXCL_START */ tdm_thread_cb_output_dpms *output_dpms = (tdm_thread_cb_output_dpms*)base; tdm_output *output_backend = tdm_display_find_output_stamp(private_loop->dpy, output_dpms->output_stamp); @@ -328,6 +331,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) } tdm_output_cb_dpms(output_backend, output_dpms->dpms, output_dpms->user_data); break; + /* LCOV_EXCL_STOP */ } case TDM_THREAD_CB_PP_DONE: { tdm_thread_cb_pp_done *pp_done = (tdm_thread_cb_pp_done*)base; -- 2.7.4 From c82ff146433678e371da26fcf96ab8b613f1a7a1 Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Fri, 24 Nov 2017 15:19:45 +0200 Subject: [PATCH 02/16] add excluding coverage comments for tdm_vblank.c add excluding coverage comments for tdm_vblank.c for the folowing code: - _tdm_vblank_cb_output_change; - pthread's fail; - calloc's fail; - tdm_event_loop_source_timer_update() func's fail; - _tdm_vblank_sw_timer_update() func's fail; - funcs for tdm_monitor. Change-Id: I67a22c38fd1ed19fde6ebf12a08681c60554f16c Signed-off-by: Konstantin Drabeniuk --- src/tdm_vblank.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 462eaf5..39eeca6 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -352,6 +352,7 @@ _tdm_vblank_update_output_info(tdm_private_vblank *private_vblank) private_vblank->vrefresh, private_vblank->fps, private_vblank->fps_changeable); } +/* LCOV_EXCL_START */ static void _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data) @@ -388,6 +389,7 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, break; } } +/* LCOV_EXCL_STOP */ EXTERN tdm_error tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps) @@ -470,10 +472,12 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) if (!vblank_list_inited) { if (pthread_mutex_init(&valid_list_lock, NULL)) { + /* LCOV_EXCL_START */ TDM_ERR("mutex init failed: %m"); if (error) *error = TDM_ERROR_OPERATION_FAILED; return NULL; + /* LCOV_EXCL_STOP */ } LIST_INITHEAD(&valid_vblank_list); LIST_INITHEAD(&valid_wait_list); @@ -482,10 +486,12 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) private_vblank = calloc(1, sizeof * private_vblank); if (!private_vblank) { + /* LCOV_EXCL_START */ if (error) *error = TDM_ERROR_OUT_OF_MEMORY; VER("alloc failed"); return NULL; + /* LCOV_EXCL_STOP */ } tdm_output_add_change_handler(output, _tdm_vblank_cb_output_change, private_vblank); @@ -740,9 +746,11 @@ _tdm_vblank_sw_timer_update(tdm_private_vblank *private_vblank) ret = tdm_event_loop_source_timer_update(private_vblank->SW_timer, ms_delay); if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ tdm_display_unlock(private_vblank->dpy); VER("couldn't update timer"); return ret; + /* LCOV_EXCL_STOP */ } tdm_display_unlock(private_vblank->dpy); @@ -1038,9 +1046,11 @@ _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info) ret = _tdm_vblank_sw_timer_update(private_vblank); if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ LIST_DEL(&wait_info->link); VER("couldn't update sw timer"); return ret; + /* LCOV_EXCL_STOP */ } return TDM_ERROR_NONE; @@ -1079,8 +1089,10 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, wait_info = calloc(1, sizeof * wait_info); if (!wait_info) { + /* LCOV_EXCL_START */ VER("alloc failed"); return TDM_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ } /* set request time to current time if 0. This function seems to be called in server side. */ @@ -1139,6 +1151,7 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, } if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ LIST_DEL(&wait_info->link); _tdm_vblank_valid_list_del(&wait_info->valid_link); @@ -1148,6 +1161,7 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, free(wait_info); return ret; + /* LCOV_EXCL_STOP */ } return TDM_ERROR_NONE; @@ -1204,6 +1218,7 @@ tdm_vblank_wait_seq(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_u return tdm_vblank_wait(vblank, req_sec, req_usec, interval, func, user_data); } +/* LCOV_EXCL_START */ INTERN tdm_error tdm_vblank_set_add_front(tdm_vblank *vblank, unsigned int add_front) { @@ -1220,6 +1235,7 @@ tdm_vblank_set_add_front(tdm_vblank *vblank, unsigned int add_front) return TDM_ERROR_NONE; } +/* LCOV_EXCL_STOP */ INTERN tdm_error tdm_vblank_set_resource(tdm_vblank *vblank, struct wl_resource *resource) @@ -1244,6 +1260,7 @@ tdm_vblank_get_stamp(tdm_vblank *vblank) return private_vblank->stamp; } +/* LCOV_EXCL_START */ INTERN void tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) { @@ -1276,4 +1293,5 @@ tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) TDM_SNPRINTF(reply, len, "\n"); } +/* LCOV_EXCL_STOP */ -- 2.7.4 From e4f0f3446d7beefed462cdc445e655b418907df5 Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Fri, 24 Nov 2017 16:28:41 +0200 Subject: [PATCH 03/16] utest: Add 10 test cases for tdm_event_loop.c Change-Id: If7286f39557388dd2fedd8f11d32fa015cb23338 Signed-off-by: Roman Marchenko --- utests/Makefile.am | 1 + utests/src/ut_tdm_event_loop.cpp | 198 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 utests/src/ut_tdm_event_loop.cpp diff --git a/utests/Makefile.am b/utests/Makefile.am index eee9511..eab6e26 100644 --- a/utests/Makefile.am +++ b/utests/Makefile.am @@ -10,6 +10,7 @@ tdm_utests_SOURCES = \ src/ut_tdm_buffer.cpp \ src/ut_tdm_helper.cpp \ src/ut_tdm_layer.cpp \ + src/ut_tdm_event_loop.cpp \ src/ut_tdm_vblank.cpp tdm_utests_CXXFLAGS = \ diff --git a/utests/src/ut_tdm_event_loop.cpp b/utests/src/ut_tdm_event_loop.cpp new file mode 100644 index 0000000..62b9165 --- /dev/null +++ b/utests/src/ut_tdm_event_loop.cpp @@ -0,0 +1,198 @@ +#include "gtest/gtest.h" +#include "ut_common.h" +#include "stdint.h" +#include "fcntl.h" + +extern "C" { +#include "tdm.h" +#include "tdm_backend.h" +#include "tbm_bufmgr.h" +#include "tbm_surface.h" +#include "tbm_surface_internal.h" +#include "tbm_drm_helper.h" +} + +class TDMEventLoop: public ::testing::Test +{ +protected: + static tdm_display *dpy; + tdm_error error; + tdm_event_loop_source *loop_src; + int fd; + + static void SetEnv(void) + { + setenv("TDM_DEBUG_MODULE", "all", 1); + setenv("TDM_DEBUG", "1", 1); + setenv("TDM_THREAD", "0", 1); + setenv("XDG_RUNTIME_DIR", "/run", 1); + setenv("TBM_DISPLAY_SERVER", "1", 1); + } + + static void UnsetEnv(void) + { + unsetenv("TDM_DEBUG_MODULE"); + unsetenv("TDM_DEBUG"); + unsetenv("TDM_THREAD"); + unsetenv("XDG_RUNTIME_DIR"); + unsetenv("TBM_DISPLAY_SERVER"); + } + + static void SetUpTestCase() + { + tdm_error error; + SetEnv(); + dpy = tdm_display_init(&error); + ASSERT_NE(NULL, dpy); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + static void TearDownTestCase() + { + tdm_display_deinit(dpy); + UnsetEnv(); + } + + int GetFd() + { + if (fd == -1) + fd = tbm_drm_helper_get_master_fd(); + return fd; + } + + void SetUp() + { + loop_src = NULL; + fd = -1; + } + + void TearDown() + { + if (loop_src) + tdm_event_loop_source_remove(loop_src); + if (fd >= 0) + close(fd); + } +}; + +tdm_display *TDMEventLoop::dpy = NULL; + +static int handler_is_called = 0; +static tdm_error timer_handler(void *user_data) +{ + if (user_data == &handler_is_called) + handler_is_called = 1; + return TDM_ERROR_NONE; +} + +static tdm_error fd_handler(int fd, tdm_event_loop_mask mask, void *user_data) +{ + if (user_data == &handler_is_called) + handler_is_called = 1; + return TDM_ERROR_NONE; +} + +/*void tdm_event_loop_source_remove(tdm_event_loop_source *source); */ +TEST_F(TDMEventLoop, SourceRemoveFailNULL) +{ + tdm_event_loop_source_remove(NULL); +} + +/* tdm_event_loop_source* tdm_event_loop_add_timer_handler(tdm_display *dpy, + tdm_event_loop_timer_handler func, + void *user_data, tdm_error *error); */ +TEST_F(TDMEventLoop, AddTimerHandlerFailNULL) +{ + loop_src = tdm_event_loop_add_timer_handler(NULL, timer_handler, &handler_is_called, &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, loop_src); + + loop_src = tdm_event_loop_add_timer_handler(dpy, NULL, &handler_is_called, &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, loop_src); + + loop_src = tdm_event_loop_add_timer_handler(dpy, NULL, &handler_is_called, NULL); + ASSERT_EQ(NULL, loop_src); +} + +TEST_F(TDMEventLoop, AddTimerHandlerSuccessful) +{ + loop_src = tdm_event_loop_add_timer_handler(dpy, timer_handler, &handler_is_called, &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, loop_src); +} + +/* tdm_error tdm_event_loop_source_timer_update(tdm_event_loop_source *source, unsigned int ms_delay); */ +TEST_F(TDMEventLoop, SourceTimerUpdateFailNULL) +{ + error = tdm_event_loop_source_timer_update(NULL, 0); + ASSERT_NE(TDM_ERROR_NONE, error); +} +TEST_F(TDMEventLoop, SourceTimerUpdateSuccessful) +{ + loop_src = tdm_event_loop_add_timer_handler(dpy, timer_handler, &handler_is_called, &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, loop_src); + + error = tdm_event_loop_source_timer_update(loop_src, 10); + ASSERT_EQ(TDM_ERROR_NONE, error); +} + +/* tdm_event_loop_source* tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask, + tdm_event_loop_fd_handler func, void *user_data, + tdm_error *error); */ +TEST_F(TDMEventLoop, AddFdHandlerFailNULL) +{ + loop_src = tdm_event_loop_add_fd_handler(NULL, 0, TDM_EVENT_LOOP_READABLE, + fd_handler, &handler_is_called, &error); + ASSERT_EQ(NULL, loop_src); + ASSERT_NE(TDM_ERROR_NONE, error); + + loop_src = tdm_event_loop_add_fd_handler(dpy, 0, TDM_EVENT_LOOP_READABLE, + NULL, &handler_is_called, &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, loop_src); +} + +TEST_F(TDMEventLoop, AddFdHandlerFailInvalidFd) +{ + loop_src = tdm_event_loop_add_fd_handler(dpy, -1, TDM_EVENT_LOOP_READABLE, + fd_handler, &handler_is_called, &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, loop_src); +} + +TEST_F(TDMEventLoop, AddFdHandlerSuccessful) +{ + int fd = GetFd(); + ASSERT_NE(-1, fd); + + loop_src = tdm_event_loop_add_fd_handler(dpy, fd, TDM_EVENT_LOOP_READABLE, + fd_handler, &handler_is_called, &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, loop_src); +} + +/* tdm_error tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask); */ +TEST_F(TDMEventLoop, SourceFdUpdateFailNULL) +{ + error = tdm_event_loop_source_fd_update(NULL, TDM_EVENT_LOOP_READABLE); +} + +TEST_F(TDMEventLoop, SourceFdUpdateSuccessful) +{ + int fd; + tdm_event_loop_mask flag = TDM_EVENT_LOOP_WRITABLE; + + fd = GetFd(); + ASSERT_NE(-1, fd); + + loop_src = tdm_event_loop_add_fd_handler(dpy, fd, flag, + fd_handler, &handler_is_called, &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, loop_src); + + error = tdm_event_loop_source_fd_update(loop_src, TDM_EVENT_LOOP_READABLE); + ASSERT_EQ(TDM_ERROR_NONE, error); +} + -- 2.7.4 From 802f43a791f330e67fad0873b3efcd022e01dfd8 Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Fri, 24 Nov 2017 18:00:41 +0200 Subject: [PATCH 04/16] add excluding coverage comments for tdm_event_loop.c for folowing code: - inner functions Change-Id: Ic3065fa1a0f3e81bff1332b7721d4866a2635286 Signed-off-by: Roman Marchenko --- src/tdm_event_loop.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tdm_event_loop.c b/src/tdm_event_loop.c index 1c88685..bb0ed57 100644 --- a/src/tdm_event_loop.c +++ b/src/tdm_event_loop.c @@ -472,6 +472,7 @@ tdm_event_loop_source_remove(tdm_event_loop_source *source) free(source); } +/* LCOV_EXCL_START */ static void _trace_cb_client_destroy(struct wl_listener *listener, void *data) { @@ -658,3 +659,4 @@ tdm_event_loop_trace_enable(tdm_private_display * private_display, return TDM_ERROR_NONE; } +/* LCOV_EXCL_STOP */ -- 2.7.4 From 6beeb1293d6ed6d6680e956849dd025c00e35379 Mon Sep 17 00:00:00 2001 From: Sergey Sizonov Date: Fri, 24 Nov 2017 15:40:16 +0300 Subject: [PATCH 05/16] utest: Add 62 tests cases for tdm_client Change-Id: If704891c1c2754baacfafdd6f327a94bb5fdc937 Signed-off-by: Sergey Sizonov --- utests/Makefile.am | 5 +- utests/src/ut_tdm_client.cpp | 1097 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1101 insertions(+), 1 deletion(-) create mode 100644 utests/src/ut_tdm_client.cpp diff --git a/utests/Makefile.am b/utests/Makefile.am index eab6e26..fe1e8b5 100644 --- a/utests/Makefile.am +++ b/utests/Makefile.am @@ -11,13 +11,15 @@ tdm_utests_SOURCES = \ src/ut_tdm_helper.cpp \ src/ut_tdm_layer.cpp \ src/ut_tdm_event_loop.cpp \ - src/ut_tdm_vblank.cpp + src/ut_tdm_vblank.cpp \ + src/ut_tdm_client.cpp tdm_utests_CXXFLAGS = \ $(CXXFLAGS) \ $(TDM_CFLAGS) \ -I../src \ -I../include \ + -I../client \ -I./src \ -I$(includedir)/gtest \ -fpermissive \ @@ -31,6 +33,7 @@ tdm_utests_LDFLAGS = \ ${LDFLAGS} \ $(TDM_LIBS) \ $(top_builddir)/src/libtdm.la \ + $(top_builddir)/client/libtdm-client.la \ -lgtest check: diff --git a/utests/src/ut_tdm_client.cpp b/utests/src/ut_tdm_client.cpp new file mode 100644 index 0000000..a8e695e --- /dev/null +++ b/utests/src/ut_tdm_client.cpp @@ -0,0 +1,1097 @@ +/************************************************************************** + * + * Copyright 2017 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: Konstantin Drabeniuk + * Contact: Andrii Sokolenko + * Contact: Roman Marchenko + * Contact: Sergey Sizonov + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * +**************************************************************************/ + +#include "gtest/gtest.h" +#include "ut_common.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" +{ +#include "tdm.h" +#include "tdm_client.h" + +#include "tbm_surface.h" + +#include "wayland-client.h" +} + +class tdm_client_test_prepare +{ +public: + tdm_client_test_prepare() + { + /* we have to deal with a named semaphore to protect an access to tdm across several instances + * of servers */ + semaphore = sem_open(semaphore_name.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR, 1); + if (semaphore == SEM_FAILED) + { + if (errno == EEXIST) + sem_unlink(semaphore_name.c_str()); + else + { + std::cout << "can't create semaphore(1): " << semaphore_name << ", errno: " << errno << ".\n"; + exit(EXIT_FAILURE); + } + } else { + return; + } + + semaphore = sem_open(semaphore_name.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR, 1); + if (semaphore == SEM_FAILED) + { + std::cout << "can't create semaphore(2): " << semaphore_name << ", errno: " << errno << ".\n"; + exit(EXIT_FAILURE); + } + } + + ~tdm_client_test_prepare() + { + sem_close(semaphore); + sem_unlink(semaphore_name.c_str()); + } + + static sem_t *semaphore; + + /* /dev/shm/sem.tdm-client-utests */ + static const std::string semaphore_name; +}; + +sem_t *tdm_client_test_prepare::semaphore; +const std::string tdm_client_test_prepare::semaphore_name = "/tdm-client-utests"; + +/* global object is created before main() */ +tdm_client_test_prepare dont_use_it; + +/* real mess, sorry... */ +class TDMClientTest : public ::testing::Test +{ +protected: + TDMClientTest() : error(TDM_ERROR_NONE), server_pid(0), cl_serv_lock_fd(-1), + dsp(nullptr), output(nullptr), layer(nullptr), buffer(nullptr), is_server_stopped(false) + { + set_env_vars(); + start_server(); /* as a separate process */ + wait_till_server_ready(); + } + + ~TDMClientTest() + { + _stop_server(); + unset_env_vars(); + } + + void send_request_to_server(int req) + { + switch(req) + { + case ChangeDPMS: + send_request(ChangeDPMS); + break; + + default: + break; + } + } + + /* to stop server by user demand */ + void stop_server(void) + { + _stop_server(); + wait_till_serv_is_over(); + + /* TODO: maybe it makes a sense to use this approach in the dtor too */ + } + + enum + { + ChangeDPMS, + }; + +private: + void set_env_vars(void) + { + setenv("XDG_RUNTIME_DIR", "/run", 1); + setenv("TBM_DISPLAY_SERVER", "1", 1); + } + + void unset_env_vars(void) + { + unsetenv("TBM_DISPLAY_SERVER"); + unsetenv("XDG_RUNTIME_DIR"); + } + + void start_server(void) + { + cl_serv_lock_fd = eventfd(0, 0); + socketpair(AF_UNIX, SOCK_STREAM, 0, reinterpret_cast(&socks_pair)); + + server_pid = fork(); + + if (server_pid) + { + close(socks_pair.server_socket); + return; + } + + close(socks_pair.client_socket); + + wait_till_serv_resources_available(); + run_server(); + } + + void _stop_server(void) + { + if (is_server_stopped) return; + + close(socks_pair.client_socket); + close(cl_serv_lock_fd); + kill(server_pid, SIGINT); + + is_server_stopped = true; + } + + void wait_till_server_ready(void) + { + uint64_t val; + + if (read(cl_serv_lock_fd, &val, sizeof val) < 0) + std::cout << "error while trying to read from cl_serv_lock_fd eventfd object.\n"; + } + + void notify_server_ready(void) + { + uint64_t val; + + val = 1; + + if (write(cl_serv_lock_fd, &val, sizeof val) < 0) + std::cout << "error while trying to write to cl_serv_lock_fd evenfd object.\n"; + } + + void wait_till_serv_resources_available(void) + { + while (1) + { + int ret; + + ret = sem_wait(tdm_client_test_prepare::semaphore); + if (ret < 0 && errno == EINTR) + continue; + else + break; + } + } + + void notify_serv_resources_available(void) + { + sem_post(tdm_client_test_prepare::semaphore); + + sem_close(tdm_client_test_prepare::semaphore); + sem_unlink(tdm_client_test_prepare::semaphore_name.c_str()); + } + + void wait_till_serv_is_over(void) + { + wait_till_serv_resources_available(); + sem_post(tdm_client_test_prepare::semaphore); + } + + void send_request(int req) + { + send(socks_pair.client_socket, &req, sizeof req, 0); + } + + void handle_client_request() + { + int req; + + recv(socks_pair.server_socket, &req, sizeof req, 0); + + switch(req) + { + case ChangeDPMS: + change_dpms_request_handler(); + break; + + default: + break; + } + } + + void run_server(void) + { + sigset_t mask; + int signal_fd; + int tdm_fd; + pollfd work_fds[3]; + + /* ask kernel to notify us about parent's die via SIGHUP signal */ + prctl(PR_SET_PDEATHSIG, SIGHUP); + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGHUP); + + sigprocmask(SIG_BLOCK, &mask, NULL); + + signal_fd = signalfd(-1, &mask, 0); + + init_tdm(); + tdm_display_get_fd(dsp, &tdm_fd); + + std::memset(&work_fds, 0, sizeof work_fds); + + work_fds[0].fd = signal_fd; + work_fds[0].events = POLLIN; + + work_fds[1].fd = tdm_fd; + work_fds[1].events = POLLIN; + + work_fds[2].fd = socks_pair.server_socket; + work_fds[2].events = POLLIN; + + notify_server_ready(); + + while (1) + { + int ret; + + ret = poll(work_fds, 3, -1); + if (ret < 0 && errno == EINTR) continue; + + if (work_fds[0].revents == POLLIN) + { + signal_hndl(); + exit(EXIT_SUCCESS); + } + + if(work_fds[1].revents == POLLIN) + tdm_display_handle_events(dsp); + + if(work_fds[2].revents == POLLIN) + handle_client_request(); + } + } + + void signal_hndl(void) + { + close(socks_pair.server_socket); + close(cl_serv_lock_fd); + + deinit_tdm(); + notify_serv_resources_available(); + } + + void init_tdm(void); + void deinit_tdm(void); + + void set_layer_geometry(int w, int h); + void set_image_on_screen(int w, int h); + + void change_dpms_request_handler(void); + + struct sockets_pair + { + sockets_pair() : server_socket(0), client_socket(0) {} + int server_socket; + int client_socket; + }; + +protected: + tdm_error error; + +private: + pid_t server_pid; + int cl_serv_lock_fd; + sockets_pair socks_pair; + + tdm_display *dsp; + tdm_output *output; + tdm_layer *layer; + + tbm_surface_h buffer; + + bool is_server_stopped; +}; + +class TDMClientTestClient : public TDMClientTest +{ +protected: + TDMClientTestClient() : TDMClientTest() + { + tdm_cl = tdm_client_create(nullptr); + } + ~TDMClientTestClient() + { + tdm_client_destroy(tdm_cl); + } + +protected: + tdm_client *tdm_cl; +}; + +class TDMClientTestClientOutput : public TDMClientTestClient +{ +protected: + TDMClientTestClientOutput() : TDMClientTestClient() + { + cl_output = tdm_client_get_output(tdm_cl, const_cast("primary"), nullptr); + } + ~TDMClientTestClientOutput() + { + } + +protected: + tdm_client_output* cl_output; +}; + +class TDMClientTestVblank : public TDMClientTestClientOutput +{ +protected: + TDMClientTestVblank() : TDMClientTestClientOutput() + { + cl_vblank = tdm_client_output_create_vblank(cl_output, nullptr); + } + ~TDMClientTestVblank() + { + tdm_client_vblank_destroy(cl_vblank); + } + +protected: + tdm_client_vblank* cl_vblank; +}; + +typedef TDMClientTest TDMClientTestDeathTest; +typedef TDMClientTestClient TDMClientTestClientDeathTest; +typedef TDMClientTestClientOutput TDMClientTestClientOutputDeathTest; +typedef TDMClientTestVblank TDMClientTestVblankDeathTest; + + +void TDMClientTest::set_layer_geometry(int w, int h) +{ + tdm_info_layer layer_info; + + std::memset(&layer_info, 0, sizeof(tdm_info_layer)); + + layer_info.src_config.size.h = w; + layer_info.src_config.size.v = h; + layer_info.src_config.pos.x = 0; + layer_info.src_config.pos.y = 0; + layer_info.src_config.pos.w = w; + layer_info.src_config.pos.h = h; + layer_info.src_config.format = TBM_FORMAT_ARGB8888; + layer_info.dst_pos.x = 0; + layer_info.dst_pos.y = 0; + layer_info.dst_pos.w = w; + layer_info.dst_pos.h = h; + layer_info.transform = TDM_TRANSFORM_NORMAL; + + tdm_layer_set_info(layer, &layer_info); +} + +void TDMClientTest::set_image_on_screen(int w, int h) +{ + tbm_surface_info_s tbm_surface_info; + + /* to have a hw vblank we have to make at least one tdm_commit */ + buffer = tbm_surface_create(w, h, TBM_FORMAT_ARGB8888); + + std::memset(&tbm_surface_info, 0, sizeof(tbm_surface_info_s)); + + tbm_surface_map(buffer, TBM_SURF_OPTION_WRITE, &tbm_surface_info); + + int *img = (int *)tbm_surface_info.planes[0].ptr; + + for (uint32_t i = 0; i < tbm_surface_info.height; i++) + for (uint32_t j = 0; j < tbm_surface_info.planes[0].stride / 4; j++) + *img++ = 0x0000000; + + tbm_surface_unmap(buffer); + + set_layer_geometry(w, h); + tdm_layer_set_buffer(layer, buffer); + tdm_output_commit(output, 0, nullptr, nullptr); +} + +void TDMClientTest::init_tdm(void) +{ + int outputs_cnt = 0; + tdm_output_type tdm_output_type; + + int output_modes_cnt = 0; + const tdm_output_mode* output_modes; + const tdm_output_mode* preferred_mode = NULL; + + int layers_cnt = 0; + tdm_layer_capability tdm_layer_capability; + + dsp = tdm_display_init(nullptr); + + tdm_display_get_output_count(dsp, &outputs_cnt); + + /* this part is hardware dependent, how to resolve this issue ? */ + for (int i = 0; i < outputs_cnt; i++) + { + output = tdm_display_get_output(dsp, i, nullptr); + tdm_output_get_output_type(output, &tdm_output_type); + + /* we're not interesting about other outputs */ + if (tdm_output_type != TDM_OUTPUT_TYPE_VIRTUAL && + tdm_output_type != TDM_OUTPUT_TYPE_HDMIA) + break; + } + + /* get output's preferred mode to obtain width & height we'll use later to create surface */ + tdm_output_get_available_modes(output, &output_modes, &output_modes_cnt); + + /* look for output's preferred mode */ + for (int i = 0; i < output_modes_cnt; i++) + { + if (output_modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED) + { + preferred_mode = &output_modes[i]; + break; + } + } + + tdm_output_set_mode(output, preferred_mode); + + tdm_output_get_layer_count(output, &layers_cnt); + + /* it supposed that output always has primary & graphic layer */ + for (int i = 0; i < layers_cnt; i++) + { + layer = tdm_output_get_layer(output, i, nullptr); + tdm_layer_get_capabilities(layer, &tdm_layer_capability); + + if ((tdm_layer_capability & TDM_LAYER_CAPABILITY_PRIMARY) && + (tdm_layer_capability & TDM_LAYER_CAPABILITY_GRAPHIC)) + break; + } + + tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON); + + set_image_on_screen(preferred_mode->hdisplay, preferred_mode->vdisplay); +} + +void TDMClientTest::deinit_tdm(void) +{ + if (layer) + { + tdm_layer_unset_buffer(layer); + tdm_output_commit(output, 1, nullptr, nullptr); + } + + if (buffer) + tbm_surface_internal_unref(buffer); + + if (dsp) + tdm_display_deinit(dsp); +} + +void TDMClientTest::change_dpms_request_handler(void) +{ + std::cout << "tdm_output_set_dpms.\n"; + tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF); +} + +TEST_F(TDMClientTest, TdmClientCreateSuccessfulCheckClient) +{ + tdm_client *tdm_cl = tdm_client_create(nullptr); + ASSERT_TRUE(nullptr != tdm_cl); + + tdm_client_destroy(tdm_cl); +} + +TEST_F(TDMClientTest, TdmClientCreateSuccessfulCheckError) +{ + tdm_client* tdm_cl = tdm_client_create(&error); + ASSERT_TRUE(TDM_ERROR_NONE == error); + + tdm_client_destroy(tdm_cl); +} + +TEST_F(TDMClientTest, TdmClientCreateFailServerStoppedCheckError) +{ + stop_server(); + + tdm_client_create(&error); + ASSERT_TRUE(TDM_ERROR_OPERATION_FAILED == error); +} + +TEST_F(TDMClientTest, TdmClientCreateFailServerStopped) +{ + stop_server(); + + tdm_client *tdm_cl = tdm_client_create(nullptr); + ASSERT_TRUE(nullptr == tdm_cl); +} + +TEST_F(TDMClientTestDeathTest, TdmClientDestroySuccessful) +{ + ASSERT_EXIT( + { + tdm_client_destroy(nullptr); + + exit(EXIT_SUCCESS); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(TDMClientTestDeathTest, TdmClientDestroySuccessfulServerStopped) +{ + ASSERT_EXIT( + { + tdm_client *tdm_cl = tdm_client_create(nullptr); + + stop_server(); + + tdm_client_destroy(tdm_cl); + + exit(EXIT_SUCCESS); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(TDMClientTestClient, TdmClientGetFdSuccessful) +{ + int fd; + + tdm_client_get_fd(tdm_cl, &fd); + ASSERT_TRUE(0 < fd); +} + +TEST_F(TDMClientTestClient, TdmClientGetFdSuccessfulCheckError) +{ + int fd; + + error = tdm_client_get_fd(tdm_cl, &fd); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestClient, TdmClientGetFdFailNullTdmClient) +{ + int fd; + + error = tdm_client_get_fd(nullptr, &fd); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClient, TdmClientGetFdFailNullFd) +{ + error = tdm_client_get_fd(nullptr, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClient, DISABLED_TdmClientHandleEventsSuccessful) +{ + ASSERT_EXIT( + { + pollfd work_fds[2]; + itimerspec times_up; + + std::memset(&work_fds, 0, sizeof work_fds); + std::memset(×_up, 0, sizeof times_up); + + tdm_client_get_fd(tdm_cl, &work_fds[0].fd); + work_fds[0].events = POLLIN; + + work_fds[1].fd = timerfd_create(CLOCK_MONOTONIC, 0); + work_fds[1].events = POLLIN; + + times_up.it_value.tv_nsec = 100000000; /* 100ms */ + timerfd_settime(work_fds[1].fd, 0, ×_up, nullptr); + + while (1) + { + int ret; + + ret = poll(work_fds, 2, -1); + if (ret < 0 && errno == EINTR) continue; + + if (work_fds[0].revents == POLLIN) + { + tdm_client_handle_events(tdm_cl); + std::cout << "ha.\n"; + } + + if(work_fds[1].revents == POLLIN) + exit(EXIT_SUCCESS); + } + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(TDMClientTestClient, TdmClientHandleEventsFailNullTDMClient) +{ + error = tdm_client_handle_events(nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessful) +{ + tdm_client_output* cl_output; + + cl_output = tdm_client_get_output(tdm_cl, const_cast("primary"), nullptr); + ASSERT_TRUE(nullptr != cl_output); +} + +TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulCallTwice) +{ + tdm_client_output* cl_output_1, *cl_output_2; + + cl_output_1 = tdm_client_get_output(tdm_cl, const_cast("primary"), nullptr); + cl_output_2 = tdm_client_get_output(tdm_cl, const_cast("primary"), nullptr); + ASSERT_TRUE(cl_output_1 == cl_output_2); +} + +TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulCheckError) +{ + tdm_client_get_output(tdm_cl, const_cast("primary"), &error); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulNullName) +{ + tdm_client_output* cl_output; + + cl_output = tdm_client_get_output(tdm_cl, nullptr, nullptr); + ASSERT_TRUE(nullptr != cl_output); +} + +TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulNullNameCheckError) +{ + tdm_client_get_output(tdm_cl, nullptr, &error); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestClient, TdmClientGetOutputFailNullTdmClient) +{ + tdm_client_output* cl_output; + + cl_output = tdm_client_get_output(nullptr, const_cast("primary"), nullptr); + ASSERT_TRUE(nullptr == cl_output); +} + +TEST_F(TDMClientTestClient, TdmClientGetOutputFailNullTdmClientCheckError) +{ + tdm_client_get_output(nullptr, const_cast("primary"), &error); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutput, DISABLED_TdmClientOutputAddChangeHandlerSuccessful) +{ + static bool got_an_event = false; + wl_display *wl_dsp; + + /* is this function implemented fully? */ + tdm_client_output_add_change_handler(cl_output, [] (tdm_client_output *output, + tdm_output_change_type type, + tdm_value value, + void *user_data) { got_an_event = true; }, nullptr); + + /* force a requests flush */ + wl_dsp = wl_display_connect("tdm-socket"); + wl_display_flush(wl_dsp); + wl_display_roundtrip(wl_dsp); + wl_display_disconnect(wl_dsp); + + send_request_to_server(TDMClientTest::ChangeDPMS); + tdm_client_handle_events(tdm_cl); + + ASSERT_TRUE(true == got_an_event); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputAddChangeHandlerFailNullOutput) +{ + error = tdm_client_output_add_change_handler(nullptr, [] (tdm_client_output *output, + tdm_output_change_type type, + tdm_value value, + void *user_data) {}, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputAddChangeHandlerFailNullHandler) +{ + error = tdm_client_output_add_change_handler(cl_output, nullptr, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerSuccessful) +{ + ASSERT_EXIT( + { + auto func = [] (tdm_client_output *output, tdm_output_change_type type, tdm_value value, + void *user_data) {}; + + tdm_client_output_add_change_handler(cl_output, func, nullptr); + + tdm_client_output_remove_change_handler(cl_output, func, nullptr); + + exit(EXIT_SUCCESS); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerSuccessfulInvalidHandler) +{ + ASSERT_EXIT( + { + auto func = [] (tdm_client_output *output, tdm_output_change_type type, tdm_value value, + void *user_data) {}; + + tdm_client_output_remove_change_handler(cl_output, func, nullptr); + + exit(EXIT_SUCCESS); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerFailNullOutput) +{ + ASSERT_EXIT( + { + auto func = [] (tdm_client_output *output, tdm_output_change_type type, tdm_value value, + void *user_data) {}; + + tdm_client_output_remove_change_handler(nullptr, func, nullptr); + + exit(EXIT_SUCCESS); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerFailNullHandler) +{ + ASSERT_EXIT( + { + tdm_client_output_remove_change_handler(cl_output, nullptr, nullptr); + + exit(EXIT_SUCCESS); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputGetRefreshRateSuccessful) +{ + uint32_t refresh_rate; + + error = tdm_client_output_get_refresh_rate(cl_output, &refresh_rate); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputGetRefreshRateFailNullOutput) +{ + uint32_t refresh_rate; + + error = tdm_client_output_get_refresh_rate(nullptr, &refresh_rate); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputGetRefreshRateFailNullRefreshRate) +{ + error = tdm_client_output_get_refresh_rate(cl_output, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputGetConnectionStatusSuccessful) +{ + tdm_output_conn_status conn_status; + + error = tdm_client_output_get_conn_status(cl_output, &conn_status); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputGetConnectionStatusFailNullOutput) +{ + tdm_output_conn_status conn_status; + + error = tdm_client_output_get_conn_status(nullptr, &conn_status); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutput, TTdmClientOutputGetConnectionStatusFailNullConnState) +{ + error = tdm_client_output_get_conn_status(cl_output, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputGetDpmsSuccessful) +{ + tdm_output_dpms dpms_val; + + error = tdm_client_output_get_dpms(cl_output, &dpms_val); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputGetDpmsFailNullOutput) +{ + tdm_output_dpms dpms_val; + + error = tdm_client_output_get_dpms(nullptr, &dpms_val); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputGetDpmsFailNullDpmsArg) +{ + error = tdm_client_output_get_dpms(cl_output, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankSuccessful) +{ + tdm_client_vblank* cl_vblank; + + cl_vblank = tdm_client_output_create_vblank(cl_output, nullptr); + ASSERT_TRUE(nullptr != cl_vblank); + + tdm_client_vblank_destroy(cl_vblank); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankSuccessfulCheckError) +{ + tdm_client_vblank* cl_vblank; + + cl_vblank = tdm_client_output_create_vblank(cl_output, &error); + ASSERT_TRUE(TDM_ERROR_NONE == error); + + tdm_client_vblank_destroy(cl_vblank); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankFailNullOutput) +{ + tdm_client_vblank* cl_vblank; + + cl_vblank = tdm_client_output_create_vblank(nullptr, nullptr); + ASSERT_TRUE(nullptr == cl_vblank); +} + +TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankFailNullOutputCheckError) +{ + tdm_client_output_create_vblank(nullptr, &error); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestClientOutputDeathTest, TdmClientDestroyVblankSuccessful) +{ + ASSERT_EXIT( + { + tdm_client_vblank *cl_vblank = tdm_client_output_create_vblank(cl_output, nullptr); + + tdm_client_vblank_destroy(cl_vblank); + exit(EXIT_SUCCESS); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(TDMClientTestClientOutputDeathTest, TdmClientDestroyVblankFailNoClientVblankArg) +{ + ASSERT_EXIT( + { + tdm_client_vblank_destroy(nullptr); + exit(EXIT_SUCCESS); + }, + ::testing::ExitedWithCode(EXIT_SUCCESS), ""); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetNameSuccessful) +{ + error = tdm_client_vblank_set_name(cl_vblank, "wassup"); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetNameSuccessfulNoExplicitName) +{ + error = tdm_client_vblank_set_name(cl_vblank, nullptr); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetNameFailNullClientVblank) +{ + error = tdm_client_vblank_set_name(nullptr, "wassup"); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetSyncSuccessful) +{ + error = tdm_client_vblank_set_sync(cl_vblank, 0); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetSyncFailNullClientVblank) +{ + error = tdm_client_vblank_set_sync(nullptr, 0); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsSuccessful) +{ + error = tdm_client_vblank_set_fps(cl_vblank, 60); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsSuccessfulSetTwice) +{ + tdm_client_vblank_set_fps(cl_vblank, 60); + error = tdm_client_vblank_set_fps(cl_vblank, 60); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsFailNullClientVblank) +{ + error = tdm_client_vblank_set_fps(nullptr, 60); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsFailInvalidFpsArg) +{ + error = tdm_client_vblank_set_fps(cl_vblank, 0); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetOffsetSuccessful) +{ + error = tdm_client_vblank_set_offset(cl_vblank, 10); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetOffsetSuccessfulSetTwice) +{ + tdm_client_vblank_set_offset(cl_vblank, 10); + error = tdm_client_vblank_set_offset(cl_vblank, 10); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetOffsetFailNullClientVblank) +{ + error = tdm_client_vblank_set_offset(nullptr, 10); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeSuccessfulEnableFake) +{ + error = tdm_client_vblank_set_enable_fake(cl_vblank, 1); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeSuccessfulDisableFake) +{ + error = tdm_client_vblank_set_enable_fake(cl_vblank, 0); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeSuccessfulSetTwice) +{ + tdm_client_vblank_set_enable_fake(cl_vblank, 0); + error = tdm_client_vblank_set_enable_fake(cl_vblank, 0); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeFailNullClientVblank) +{ + error = tdm_client_vblank_set_enable_fake(nullptr, 0); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankWaitSuccessful) +{ + auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) {}; + + tdm_client_vblank_set_sync(cl_vblank, 0); + tdm_client_vblank_set_enable_fake(cl_vblank, 1); + + error = tdm_client_vblank_wait(cl_vblank, 1, func, nullptr); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankWaitFailNullClientVblank) +{ + auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) {}; + + error = tdm_client_vblank_wait(nullptr, 1, func, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankWaitFailNullHandler) +{ + error = tdm_client_vblank_wait(cl_vblank, 1, nullptr, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankWaitFailInvalidInterval) +{ + auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) {}; + + error = tdm_client_vblank_wait(cl_vblank, 0, func, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankWaitSequencySuccessful) +{ + auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) {}; + + tdm_client_vblank_set_sync(cl_vblank, 0); + tdm_client_vblank_set_enable_fake(cl_vblank, 1); + + error = tdm_client_vblank_wait_seq(cl_vblank, 100, func, nullptr); + ASSERT_TRUE(TDM_ERROR_NONE == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankWaitSequencyFailNullClientVblank) +{ + auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) {}; + + error = tdm_client_vblank_wait_seq(nullptr, 1, func, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + +TEST_F(TDMClientTestVblank, TdmClientVblankWaitSequencyFailNullHandler) +{ + error = tdm_client_vblank_wait_seq(cl_vblank, 1, nullptr, nullptr); + ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error); +} + -- 2.7.4 From ee372d00fb3da283d88a8d1b25b12ce87c31bf04 Mon Sep 17 00:00:00 2001 From: Sergey Sizonov Date: Mon, 27 Nov 2017 12:35:10 +0300 Subject: [PATCH 06/16] fix svace warnings Change-Id: I4835f45443a7c38353cfc01f0fa3c897cc6d5f04 Signed-off-by: Sergey Sizonov --- utests/src/ut_tdm_client.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/utests/src/ut_tdm_client.cpp b/utests/src/ut_tdm_client.cpp index a8e695e..3c88875 100644 --- a/utests/src/ut_tdm_client.cpp +++ b/utests/src/ut_tdm_client.cpp @@ -493,6 +493,14 @@ void TDMClientTest::init_tdm(void) } } + if (!preferred_mode) + { + std::cout << "no preferred mode, server's gonna be stopped.\n"; + + deinit_tdm(); + exit(EXIT_FAILURE); + } + tdm_output_set_mode(output, preferred_mode); tdm_output_get_layer_count(output, &layers_cnt); -- 2.7.4 From d39a0db0af66d6ca74734df9ddcbe892b5a5398e Mon Sep 17 00:00:00 2001 From: Boram Park Date: Mon, 27 Nov 2017 17:44:18 +0900 Subject: [PATCH 07/16] output: add debug log Change-Id: I36f24f5c2e53f56c8568888bd6e305a62dd6eb1b --- src/tdm_output.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tdm_output.c b/src/tdm_output.c index 855c352..7449637 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -1073,8 +1073,11 @@ tdm_output_set_mode(tdm_output *output, const tdm_output_mode *mode) } ret = func_output->output_set_mode(private_output->output_backend, mode); - if (ret == TDM_ERROR_NONE) + if (ret == TDM_ERROR_NONE) { private_output->current_mode = mode; + TDM_INFO("mode: %dx%d %dhz", mode->hdisplay, mode->vdisplay, mode->vrefresh); + } + _pthread_mutex_unlock(&private_display->lock); return ret; -- 2.7.4 From 8494d02d00769b90a00a38dc4049bbbf891895c9 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Mon, 27 Nov 2017 17:44:40 +0900 Subject: [PATCH 08/16] tools: fix syntax error Change-Id: I0d857f566ed34dcd415939b7b2fe4b4062320f7f --- tools/tdm_test_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tdm_test_server.c b/tools/tdm_test_server.c index ff7b542..af3c303 100644 --- a/tools/tdm_test_server.c +++ b/tools/tdm_test_server.c @@ -930,7 +930,7 @@ output_setup(tdm_test_server_output *o) } if (!best) best = &modes[i]; - if (modes[i].flags & TDM_OUTPUT_MODE_TYPE_PREFERRED) + if (modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED) prefer = &modes[i]; } if (!found && prefer) { -- 2.7.4 From 4be48914071e24d20b0b26598012239f79504055 Mon Sep 17 00:00:00 2001 From: Sergey Sizonov Date: Wed, 29 Nov 2017 09:07:50 +0300 Subject: [PATCH 09/16] add excluding coverage comments for tdm_client.c/tdm_server.c Change-Id: I02a2e61c0a944879a6936d784545f731b161e23e Signed-off-by: Sergey Sizonov --- client/tdm_client.c | 48 ++++++++++++++++++++++++ src/tdm_server.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) diff --git a/client/tdm_client.c b/client/tdm_client.c index e576c3d..3e9176a 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -135,6 +135,7 @@ _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uin private_vblank->stamp = stamp; } +/* LCOV_EXCL_START */ static void _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t req_id, uint32_t sequence, uint32_t tv_sec, @@ -171,7 +172,9 @@ _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank, return; } } +/* LCOV_EXCL_STOP */ +/* LCOV_EXCL_START */ static void _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable) { @@ -181,6 +184,7 @@ _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, ui private_vblank->enable_ttrace = enable; } +/* LCOV_EXCL_STOP */ static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = { _tdm_client_vblank_cb_stamp, @@ -312,10 +316,12 @@ _tdm_client_cb_global(void *data, struct wl_registry *registry, } } +/* LCOV_EXCL_START */ static void _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name) { } +/* LCOV_EXCL_STOP */ static const struct wl_registry_listener tdm_client_registry_listener = { _tdm_client_cb_global, @@ -329,10 +335,14 @@ tdm_client_create(tdm_error *error) private_client = calloc(1, sizeof *private_client); if (!private_client) { + /* LCOV_EXCL_START */ + TDM_ERR("alloc failed"); if (error) *error = TDM_ERROR_OUT_OF_MEMORY; return NULL; + + /* LCOV_EXCL_STOP */ } LIST_INITHEAD(&private_client->output_list); @@ -411,11 +421,13 @@ tdm_client_handle_events(tdm_client *client) TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER); + /* LCOV_EXCL_START */ private_client = (tdm_private_client*)client; wl_display_dispatch(private_client->display); return TDM_ERROR_NONE; + /* LCOV_EXCL_STOP */ } typedef struct _tdm_client_vblank_temp { @@ -423,6 +435,7 @@ typedef struct _tdm_client_vblank_temp { void *user_data; } tdm_client_vblank_temp; +/* LCOV_EXCL_START */ static void _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data) @@ -436,7 +449,9 @@ _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsi free(vblank_temp); } +/* LCOV_EXCL_STOP */ +/* LCOV_EXCL_START */ /* deprecated */ tdm_error tdm_client_wait_vblank(tdm_client *client, char *name, int sw_timer, int interval, int sync, @@ -470,6 +485,7 @@ tdm_client_wait_vblank(tdm_client *client, char *name, return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp); } +/* LCOV_EXCL_STOP */ tdm_client_output* tdm_client_get_output(tdm_client *client, char *name, tdm_error *error) @@ -499,10 +515,14 @@ tdm_client_get_output(tdm_client *client, char *name, tdm_error *error) private_output = calloc(1, sizeof *private_output); if (!private_output) { + /* LCOV_EXCL_START */ + TDM_ERR("alloc failed"); if (error) *error = TDM_ERROR_OUT_OF_MEMORY; return NULL; + + /* LCOV_EXCL_STOP */ } private_output->private_client = private_client; @@ -510,11 +530,15 @@ tdm_client_get_output(tdm_client *client, char *name, tdm_error *error) snprintf(private_output->name, TDM_NAME_LEN, "%s", name); private_output->output = wl_tdm_create_output(private_client->tdm, private_output->name); if (!private_output->output) { + /* LCOV_EXCL_START */ + TDM_ERR("couldn't create output resource"); free(private_output); if (error) *error = TDM_ERROR_OUT_OF_MEMORY; return NULL; + + /* LCOV_EXCL_STOP */ } LIST_INITHEAD(&private_output->vblank_list); @@ -701,21 +725,29 @@ tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error) private_vblank = calloc(1, sizeof *private_vblank); if (!private_vblank) { + /* LCOV_EXCL_START */ + TDM_ERR("alloc failed"); if (error) *error = TDM_ERROR_OUT_OF_MEMORY; return NULL; + + /* LCOV_EXCL_STOP */ } private_vblank->private_output = private_output; private_vblank->vblank = wl_tdm_output_create_vblank(private_output->output); if (!private_vblank->vblank) { + /* LCOV_EXCL_START */ + TDM_ERR("couldn't create vblank resource"); free(private_vblank); if (error) *error = TDM_ERROR_OUT_OF_MEMORY; return NULL; + + /* LCOV_EXCL_STOP */ } /* initial value */ @@ -882,8 +914,12 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli w = calloc(1, sizeof *w); if (!w) { + /* LCOV_EXCL_START */ + TDM_ERR("alloc failed"); return TDM_ERROR_OUT_OF_MEMORY; + + /* LCOV_EXCL_STOP */ } w->private_vblank = private_vblank; @@ -918,6 +954,8 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli return TDM_ERROR_NONE; } + /* LCOV_EXCL_START */ + while (ret != -1 && !w->need_free) ret = wl_display_dispatch(private_client->display); @@ -930,6 +968,8 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli free(w); return TDM_ERROR_NONE; + + /* LCOV_EXCL_STOP */ } tdm_error @@ -967,8 +1007,12 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, w = calloc(1, sizeof *w); if (!w) { + /* LCOV_EXCL_START */ + TDM_ERR("alloc failed"); return TDM_ERROR_OUT_OF_MEMORY; + + /* LCOV_EXCL_STOP */ } w->private_vblank = private_vblank; @@ -1003,6 +1047,8 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, return TDM_ERROR_NONE; } + /* LCOV_EXCL_START */ + while (ret != -1 && !w->need_free) ret = wl_display_dispatch(private_client->display); @@ -1015,4 +1061,6 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, free(w); return TDM_ERROR_NONE; + + /* LCOV_EXCL_STOP */ } diff --git a/src/tdm_server.c b/src/tdm_server.c index f56b1ad..3932819 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -162,6 +162,7 @@ _tdm_server_find_output(tdm_private_server *private_server, const char *name) return found; } +/* LCOV_EXCL_START */ static void _tdm_server_send_done(tdm_server_wait_info *wait_info, tdm_error error, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec) @@ -193,14 +194,18 @@ _tdm_server_send_done(tdm_server_wait_info *wait_info, tdm_error error, destroy_wait(wait_info); } +/* LCOV_EXCL_STOP */ +/* LCOV_EXCL_START */ static void _tdm_server_cb_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data) { _tdm_server_send_done((tdm_server_wait_info*)user_data, error, sequence, tv_sec, tv_usec); } +/* LCOV_EXCL_STOP */ +/* LCOV_EXCL_START */ static void _tdm_server_cb_output_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data) @@ -234,6 +239,7 @@ _tdm_server_cb_output_change(tdm_output *output, tdm_output_change_type type, break; } } +/* LCOV_EXCL_STOP */ static void destroy_wait(tdm_server_wait_info *wait_info) @@ -263,12 +269,15 @@ destroy_vblank_callback(struct wl_resource *resource) free(vblank_info); } +/* LCOV_EXCL_START */ static void _tdm_server_vblank_cb_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } +/* LCOV_EXCL_STOP */ +/* LCOV_EXCL_START */ static void _tdm_server_vblank_cb_set_name(struct wl_client *client, struct wl_resource *resource, const char *name) { @@ -276,7 +285,9 @@ _tdm_server_vblank_cb_set_name(struct wl_client *client, struct wl_resource *res tdm_vblank_set_name(vblank_info->vblank, name); } +/* LCOV_EXCL_STOP */ +/* LCOV_EXCL_START */ static void _tdm_server_vblank_cb_set_fps(struct wl_client *client, struct wl_resource *resource, uint32_t fps) { @@ -284,7 +295,9 @@ _tdm_server_vblank_cb_set_fps(struct wl_client *client, struct wl_resource *reso tdm_vblank_set_fps(vblank_info->vblank, fps); } +/* LCOV_EXCL_STOP */ +/* LCOV_EXCL_START */ static void _tdm_server_vblank_cb_set_offset(struct wl_client *client, struct wl_resource *resource, int32_t offset) { @@ -292,6 +305,7 @@ _tdm_server_vblank_cb_set_offset(struct wl_client *client, struct wl_resource *r tdm_vblank_set_offset(vblank_info->vblank, offset); } +/* LCOV_EXCL_STOP */ static void _tdm_server_vblank_cb_set_enable_fake(struct wl_client *client, struct wl_resource *resource, uint32_t enable_fake) @@ -315,9 +329,13 @@ _tdm_server_vblank_cb_wait_vblank(struct wl_client *client, struct wl_resource * wait_info = calloc(1, sizeof * wait_info); if (!wait_info) { + /* LCOV_EXCL_START */ + TDM_ERR("alloc failed"); ret = TDM_ERROR_OUT_OF_MEMORY; goto wait_failed; + + /* LCOV_EXCL_STOP */ } LIST_ADDTAIL(&wait_info->link, &private_server->wait_list); @@ -342,9 +360,13 @@ _tdm_server_vblank_cb_wait_vblank(struct wl_client *client, struct wl_resource * return; wait_failed: + /* LCOV_EXCL_START */ + wl_tdm_vblank_send_done(vblank_info->resource, req_id, 0, 0, 0, ret); if (wait_info) destroy_wait(wait_info); + + /* LCOV_EXCL_STOP */ } static void @@ -361,9 +383,13 @@ _tdm_server_vblank_cb_wait_vblank_seq(struct wl_client *client, struct wl_resour wait_info = calloc(1, sizeof * wait_info); if (!wait_info) { + /* LCOV_EXCL_START */ + TDM_ERR("alloc failed"); ret = TDM_ERROR_OUT_OF_MEMORY; goto wait_failed; + + /* LCOV_EXCL_STOP */ } LIST_ADDTAIL(&wait_info->link, &private_server->wait_list); @@ -388,9 +414,13 @@ _tdm_server_vblank_cb_wait_vblank_seq(struct wl_client *client, struct wl_resour return; wait_failed: + /* LCOV_EXCL_START */ + wl_tdm_vblank_send_done(vblank_info->resource, req_id, 0, 0, 0, ret); if (wait_info) destroy_wait(wait_info); + + /* LCOV_EXCL_STOP */ } static const struct wl_tdm_vblank_interface tdm_vblank_implementation = { @@ -403,11 +433,13 @@ static const struct wl_tdm_vblank_interface tdm_vblank_implementation = { _tdm_server_vblank_cb_wait_vblank_seq, }; +/* LCOV_EXCL_START */ static void _tdm_server_output_cb_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } +/* LCOV_EXCL_STOP */ static void _tdm_server_output_cb_create_vblank(struct wl_client *client, struct wl_resource *resource, uint32_t id) @@ -423,26 +455,38 @@ _tdm_server_output_cb_create_vblank(struct wl_client *client, struct wl_resource wl_resource_create(client, &wl_tdm_vblank_interface, wl_resource_get_version(resource), id); if (!vblank_resource) { + /* LCOV_EXCL_START */ + wl_resource_post_no_memory(resource); TDM_ERR("wl_resource_create failed"); return; + + /* LCOV_EXCL_STOP */ } vblank = tdm_vblank_create(private_loop->dpy, output_info->output, NULL); if (!vblank) { + /* LCOV_EXCL_START */ + wl_resource_post_no_memory(resource); wl_resource_destroy(vblank_resource); TDM_ERR("tdm_vblank_create failed"); return; + + /* LCOV_EXCL_STOP */ } vblank_info = calloc(1, sizeof * vblank_info); if (!vblank_info) { + /* LCOV_EXCL_START */ + wl_resource_post_no_memory(resource); wl_resource_destroy(vblank_resource); tdm_vblank_destroy(vblank); TDM_ERR("alloc failed"); return; + + /* LCOV_EXCL_STOP */ } LIST_ADDTAIL(&vblank_info->link, &output_info->vblank_list); @@ -461,6 +505,7 @@ _tdm_server_output_cb_create_vblank(struct wl_client *client, struct wl_resource return; } +/* LCOV_EXCL_START */ static void _tdm_server_output_cb_watch_output_changes(struct wl_client *client, struct wl_resource *resource, unsigned int enable) { @@ -470,6 +515,7 @@ _tdm_server_output_cb_watch_output_changes(struct wl_client *client, struct wl_r output_info->watch_output_changes = enable; } +/* LCOV_EXCL_STOP */ static void _tdm_server_output_cb_get_connection(struct wl_client *client, struct wl_resource *resource) @@ -594,27 +640,39 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou output = _tdm_server_find_output(private_server, name); if (!output) { + /* LCOV_EXCL_START */ + TDM_ERR("There is no '%s' output", name); wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "There is no '%s' output", name); return; + + /* LCOV_EXCL_STOP */ } output_resource = wl_resource_create(client, &wl_tdm_output_interface, wl_resource_get_version(resource), id); if (!output_resource) { + /* LCOV_EXCL_START */ + wl_resource_post_no_memory(resource); TDM_ERR("wl_resource_create failed"); return; + + /* LCOV_EXCL_STOP */ } output_info = calloc(1, sizeof * output_info); if (!output_info) { + /* LCOV_EXCL_START */ + wl_resource_post_no_memory(resource); wl_resource_destroy(output_resource); TDM_ERR("alloc failed"); return; + + /* LCOV_EXCL_STOP */ } LIST_ADDTAIL(&output_info->link, &private_server->output_list); @@ -650,6 +708,7 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou } } +/* LCOV_EXCL_START */ static void _tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, const char *options) { @@ -689,7 +748,9 @@ _tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, con wl_tdm_send_debug_done(resource); } +/* LCOV_EXCL_STOP */ +/* LCOV_EXCL_START */ static void _tdm_server_cb_set_client_vblank_fps(struct wl_client *client, struct wl_resource *resource, unsigned int pid, const char *name, unsigned int fps) @@ -699,6 +760,7 @@ _tdm_server_cb_set_client_vblank_fps(struct wl_client *client, struct wl_resourc TDM_INFO("'%s' vblank fps(PID: '%u'): %u", name, pid, fps); } +/* LCOV_EXCL_STOP */ static const struct wl_tdm_interface tdm_implementation = { _tdm_server_cb_debug, @@ -733,15 +795,23 @@ _tdm_server_bind(struct wl_client *client, void *data, resource = wl_resource_create(client, &wl_tdm_interface, version, id); if (!resource) { + /* LCOV_EXCL_START */ + wl_client_post_no_memory(client); return; + + /* LCOV_EXCL_STOP */ } cinfo = calloc(1, sizeof(tdm_server_client_info)); if (!cinfo) { + /* LCOV_EXCL_START */ + wl_client_post_no_memory(client); wl_resource_destroy(resource); return; + + /* LCOV_EXCL_STOP */ } cinfo->resource = resource; @@ -798,12 +868,16 @@ _tdm_getgrnam_r(const char *name) return id; failed: + /* LCOV_EXCL_START */ + if (buf) free(buf); if (grp) free(grp); return -1; + + /* LCOV_EXCL_STOP */ } static void @@ -817,8 +891,12 @@ _tdm_socket_init(tdm_private_loop *private_loop) dir = getenv("XDG_RUNTIME_DIR"); if (!dir) { + /* LCOV_EXCL_START */ + TDM_WRN("getting XDG_RUNTIME_DIR failed"); return; + + /* LCOV_EXCL_STOP */ } strncpy(socket_path, dir, TDM_NAME_LEN - 1); @@ -829,28 +907,44 @@ _tdm_socket_init(tdm_private_loop *private_loop) ret = chmod(socket_path, 509); if (ret < 0) { + /* LCOV_EXCL_START */ + TDM_WRN("changing modes of socket file failed:%s (%m)", socket_path); return; + + /* LCOV_EXCL_STOP */ } ret = _tdm_getgrnam_r("root"); if (ret < 0) { + /* LCOV_EXCL_START */ + TDM_WRN("getting uid failed"); return; + + /* LCOV_EXCL_STOP */ } uid = ret; ret = _tdm_getgrnam_r("display"); if (ret < 0) { + /* LCOV_EXCL_START */ + TDM_WRN("getting gid failed"); return; + + /* LCOV_EXCL_STOP */ } gid = ret; ret = chown(socket_path, uid, gid); if (ret < 0) { + /* LCOV_EXCL_START */ + TDM_WRN("changing owner of socket file failed:%s (%m)", socket_path); return; + + /* LCOV_EXCL_STOP */ } } @@ -866,8 +960,12 @@ tdm_server_init(tdm_private_loop *private_loop) return TDM_ERROR_NONE; if (wl_display_add_socket(private_loop->wl_display, "tdm-socket")) { + /* LCOV_EXCL_START */ + TDM_ERR("createing a tdm-socket failed"); return TDM_ERROR_OPERATION_FAILED; + + /* LCOV_EXCL_STOP */ } _tdm_socket_init(private_loop); @@ -883,9 +981,13 @@ tdm_server_init(tdm_private_loop *private_loop) if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1, private_server, _tdm_server_bind)) { + /* LCOV_EXCL_START */ + TDM_ERR("creating a global resource failed"); free(private_server); return TDM_ERROR_OUT_OF_MEMORY; + + /* LCOV_EXCL_STOP */ } private_server->private_loop = private_loop; @@ -927,6 +1029,7 @@ tdm_server_deinit(tdm_private_loop *private_loop) keep_private_server = NULL; } +/* LCOV_EXCL_START */ INTERN const char* tdm_server_get_client_name(pid_t pid) { @@ -939,7 +1042,9 @@ tdm_server_get_client_name(pid_t pid) return NULL; } +/* LCOV_EXCL_STOP */ +/* LCOV_EXCL_START */ INTERN tdm_error tdm_server_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable) { @@ -966,3 +1071,4 @@ tdm_server_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable return TDM_ERROR_NONE; } +/* LCOV_EXCL_STOP */ -- 2.7.4 From f7547c59e1cb13eff9445f91b132e354d88b7de2 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 28 Nov 2017 17:13:27 +0900 Subject: [PATCH 10/16] output: add debug logs Change-Id: I70c3bce41875176fb01c741e3b8b470dafb128c3 --- src/tdm_vblank.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 39eeca6..2701456 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -1142,12 +1142,20 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, else wait_info->type = VBLANK_TYPE_HW_SW; - if (wait_info->type == VBLANK_TYPE_SW || wait_info->type == VBLANK_TYPE_SW_FAKE) + if (wait_info->type == VBLANK_TYPE_SW || wait_info->type == VBLANK_TYPE_SW_FAKE) { ret = _tdm_vblank_wait_SW(wait_info); - else { + if (ret != TDM_ERROR_NONE) + TDM_ERR("_tdm_vblank_wait_SW failed: ret(%d)", ret); + } else { ret = _tdm_vblank_wait_HW(wait_info); - if (ret == TDM_ERROR_OUTPUT_DISCONNECTED || ret == TDM_ERROR_DPMS_OFF) + if (ret != TDM_ERROR_NONE) + TDM_ERR("_tdm_vblank_wait_HW failed: ret(%d)", ret); + + if (ret == TDM_ERROR_OUTPUT_DISCONNECTED || ret == TDM_ERROR_DPMS_OFF) { ret = _tdm_vblank_wait_SW(wait_info); + if (ret != TDM_ERROR_NONE) + TDM_ERR("_tdm_vblank_wait_SW failed: ret(%d)", ret); + } } if (ret != TDM_ERROR_NONE) { -- 2.7.4 From c2c4980b27f69239b3e7af5aa7102d652223a4f5 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 28 Nov 2017 11:08:49 +0900 Subject: [PATCH 11/16] dpms: add more description Change-Id: Ic8f325d92cdf57cac88f11e0436a378d238fb9c9 --- include/tdm_common.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/tdm_common.h b/include/tdm_common.h index 637d883..f353216 100644 --- a/include/tdm_common.h +++ b/include/tdm_common.h @@ -214,10 +214,10 @@ typedef enum { * @details bit compatible with the libdrm definitions. */ typedef enum { - TDM_OUTPUT_DPMS_ON, /**< On */ - TDM_OUTPUT_DPMS_STANDBY, /**< StandBy */ - TDM_OUTPUT_DPMS_SUSPEND, /**< Suspend */ - TDM_OUTPUT_DPMS_OFF, /**< Off */ + TDM_OUTPUT_DPMS_ON, /**< On, Vsync On */ + TDM_OUTPUT_DPMS_STANDBY, /**< StandBy, Vsync On */ + TDM_OUTPUT_DPMS_SUSPEND, /**< Suspend, Vsync Off */ + TDM_OUTPUT_DPMS_OFF, /**< Off, Vsync Off */ } tdm_output_dpms; /** -- 2.7.4 From 3bcc94eb47f4f3472cee98da566029d01129d1e5 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 28 Nov 2017 15:48:45 +0900 Subject: [PATCH 12/16] dpms: allow setting the same value twice Change-Id: I2a039987785c20cacb88be254ced2948cf23cbef --- src/tdm_output.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/tdm_output.c b/src/tdm_output.c index 7449637..34fb0c6 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -1181,11 +1181,6 @@ tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) return TDM_ERROR_BAD_REQUEST; } - if (private_output->current_dpms_value == dpms_value) { - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_NONE; - } - /** Use timer to call the output change callback of the sub-thread. * The output change callback of tdm_server and tdm_vblank was called * in the main thread. And it made the multi thread issue. If we use @@ -1267,11 +1262,6 @@ tdm_output_set_dpms_async(tdm_output *output, tdm_output_dpms dpms_value) return TDM_ERROR_BAD_REQUEST; } - if (private_output->current_dpms_value == dpms_value) { - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_NONE; - } - func_output = &private_display->func_output; if (!func_output->output_set_dpms_handler) { TDM_ERR("not implemented: output_set_dpms_handler"); -- 2.7.4 From be04ecdb64268497ae8cf66c8e04ae9e3faeb7b3 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 28 Nov 2017 17:04:54 +0900 Subject: [PATCH 13/16] dpms: update current_dpms_value if failed to set Change-Id: I3de160985a6631c058d0e0fac59bcad673abd43e --- src/tdm_output.c | 104 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 40 deletions(-) diff --git a/src/tdm_output.c b/src/tdm_output.c index 34fb0c6..2e0b705 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -1114,6 +1114,45 @@ _tdm_output_dpms_changed_timeout(void *user_data) return TDM_ERROR_NONE; } +static tdm_error +tdm_output_call_dpms_change_handler(tdm_output *output) +{ + tdm_private_output *private_output = (tdm_private_output*)output; + tdm_value value; + + /** Use timer to call the output change callback of the sub-thread. + * The output change callback of tdm_server and tdm_vblank was called + * in the main thread. And it made the multi thread issue. If we use + * the timer, we can call the sub-thread's output change callback in + * sub-thread. + */ + if (!private_output->dpms_changed_timer) { + private_output->dpms_changed_timer = + tdm_event_loop_add_timer_handler(private_output->private_display, + _tdm_output_dpms_changed_timeout, private_output, NULL); + if (!private_output->dpms_changed_timer) { + /* LCOV_EXCL_START */ + TDM_ERR("can't create dpms timer!!"); + return TDM_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + } + + value.u32 = private_output->current_dpms_value; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_main, + TDM_OUTPUT_CHANGE_DPMS, + value, 0); + + if (!LIST_IS_EMPTY(&private_output->change_handler_list_sub)) { + tdm_error ret = tdm_event_loop_source_timer_update(private_output->dpms_changed_timer, 1); + if (ret != TDM_ERROR_NONE) + TDM_NEVER_GET_HERE(); + } + + return TDM_ERROR_NONE; +} + /* LCOV_EXCL_START */ INTERN void tdm_output_cb_dpms(tdm_output *output_backend, tdm_output_dpms dpms, void *user_data) @@ -1181,25 +1220,6 @@ tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) return TDM_ERROR_BAD_REQUEST; } - /** Use timer to call the output change callback of the sub-thread. - * The output change callback of tdm_server and tdm_vblank was called - * in the main thread. And it made the multi thread issue. If we use - * the timer, we can call the sub-thread's output change callback in - * sub-thread. - */ - if (!private_output->dpms_changed_timer) { - private_output->dpms_changed_timer = - tdm_event_loop_add_timer_handler(private_output->private_display, - _tdm_output_dpms_changed_timeout, private_output, NULL); - if (!private_output->dpms_changed_timer) { - /* LCOV_EXCL_START */ - TDM_ERR("can't create dpms timer!!"); - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_OUT_OF_MEMORY; - /* LCOV_EXCL_STOP */ - } - } - func_output = &private_display->func_output; TDM_INFO("output(%d) dpms '%s'", private_output->pipe, tdm_dpms_str(dpms_value)); @@ -1216,22 +1236,18 @@ tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) done: if (ret == TDM_ERROR_NONE) { - tdm_value value; - - private_output->current_dpms_value = dpms_value; - TDM_INFO("output(%d) dpms '%s' done", private_output->pipe, tdm_dpms_str(dpms_value)); + if (private_output->current_dpms_value != dpms_value) { + private_output->current_dpms_value = dpms_value; + TDM_INFO("output(%d) dpms '%s' done", private_output->pipe, tdm_dpms_str(dpms_value)); + tdm_output_call_dpms_change_handler(output); + } + } else { + tdm_output_dpms temp = TDM_OUTPUT_DPMS_OFF; - value.u32 = dpms_value; - tdm_output_call_change_handler_internal(private_output, - &private_output->change_handler_list_main, - TDM_OUTPUT_CHANGE_DPMS, - value, 0); + /* update current_dpms_value forcely */ + tdm_output_get_dpms_internal(output, &temp); - if (!LIST_IS_EMPTY(&private_output->change_handler_list_sub)) { - ret = tdm_event_loop_source_timer_update(private_output->dpms_changed_timer, 1); - if (ret != TDM_ERROR_NONE) - TDM_NEVER_GET_HERE(); - } + TDM_ERR("output(%d) set_dpms failed: dpms '%s'", private_output->pipe, tdm_dpms_str(temp)); } _pthread_mutex_unlock(&private_display->lock); @@ -1293,6 +1309,13 @@ tdm_output_set_dpms_async(tdm_output *output, tdm_output_dpms dpms_value) if (ret == TDM_ERROR_NONE) { private_output->waiting_dpms_change = 1; TDM_INFO("output(%d) dpms async '%s' waiting", private_output->pipe, tdm_dpms_str(dpms_value)); + } else { + tdm_output_dpms temp = TDM_OUTPUT_DPMS_OFF; + + /* update current_dpms_value forcely */ + tdm_output_get_dpms_internal(output, &temp); + + TDM_ERR("output(%d) set_dpms_async failed: dpms '%s'", private_output->pipe, tdm_dpms_str(temp)); } _pthread_mutex_unlock(&private_display->lock); @@ -1337,13 +1360,14 @@ tdm_output_get_dpms_internal(tdm_output *output, tdm_output_dpms *dpms_value) /* LCOV_EXCL_STOP */ } - /* TODO: this is ugly. But we have to check if all backends's DPMS operation has no problem. */ - if (private_output->commit_per_vblank) - if (*dpms_value != private_output->current_dpms_value) { - private_output->current_dpms_value = *dpms_value; - TDM_ERR("output(%d) dpms changed suddenly: %s", - private_output->pipe, tdm_dpms_str(*dpms_value)); - } + /* checking with backend's value */ + if (*dpms_value != private_output->current_dpms_value) { + TDM_ERR("output(%d) dpms changed suddenly: %s -> %s", + private_output->pipe, private_output->current_dpms_value, + tdm_dpms_str(*dpms_value)); + private_output->current_dpms_value = *dpms_value; + tdm_output_call_dpms_change_handler(output); + } return ret; } -- 2.7.4 From 5ba1ef1e99fb076f54d6a92cd4997ab13c381835 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 28 Nov 2017 11:47:13 +0900 Subject: [PATCH 14/16] dpms: add macro to check dpms status Change-Id: I5b3f14d081203395c4fd7e781f216f4871a16bf6 --- client/tdm_client.c | 8 ++++---- src/tdm_capture.c | 4 +++- src/tdm_layer.c | 8 ++++---- src/tdm_macro.h | 6 ++++++ src/tdm_output.c | 18 ++++++------------ src/tdm_vblank.c | 8 ++++---- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 3e9176a..6153187 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -906,8 +906,8 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli TDM_ERR("output disconnected"); return TDM_ERROR_OUTPUT_DISCONNECTED; } - if (private_output->dpms != TDM_OUTPUT_DPMS_ON) { - TDM_ERR("dpms off"); + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) { + TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms)); return TDM_ERROR_DPMS_OFF; } } @@ -999,8 +999,8 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, TDM_ERR("output disconnected"); return TDM_ERROR_OUTPUT_DISCONNECTED; } - if (private_output->dpms != TDM_OUTPUT_DPMS_ON) { - TDM_ERR("dpms off"); + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) { + TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms)); return TDM_ERROR_DPMS_OFF; } } diff --git a/src/tdm_capture.c b/src/tdm_capture.c index 751056b..bfb9e40 100644 --- a/src/tdm_capture.c +++ b/src/tdm_capture.c @@ -561,7 +561,9 @@ tdm_capture_commit(tdm_capture *capture) _pthread_mutex_lock(&private_display->lock); private_output = private_capture->private_output; - if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + + /* TODO: possible when standby mode? can't decide it yet. no scenario. */ + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) { TDM_ERR("output(%d) dpms: %s", private_output->pipe, tdm_dpms_str(private_output->current_dpms_value)); _pthread_mutex_unlock(&private_display->lock); diff --git a/src/tdm_layer.c b/src/tdm_layer.c index cca078e..5d3d1c9 100644 --- a/src/tdm_layer.c +++ b/src/tdm_layer.c @@ -595,7 +595,7 @@ _tdm_layer_got_output_vblank(tdm_private_output *private_output, unsigned int se if (tdm_debug_module & TDM_DEBUG_COMMIT) TDM_INFO("layer commit: output(%d) commit", private_output->pipe); - if (private_output->current_dpms_value == TDM_OUTPUT_DPMS_ON) { + if (!TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) { /* tdm_vblank APIs is for server. it should be called in unlock status*/ if (!private_output->layer_waiting_vblank) { _pthread_mutex_unlock(&private_display->lock); @@ -614,8 +614,8 @@ _tdm_layer_got_output_vblank(tdm_private_output *private_output, unsigned int se LIST_ADDTAIL(&lm->link, &private_output->layer_commit_handler_list); } - if (private_output->current_dpms_value != TDM_OUTPUT_DPMS_ON) { - TDM_WRN("TDM_OUTPUT_DPMS_OFF. Directly call vblank callback."); + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) { + TDM_WRN("dpms %s. Directly call vblank callback.", tdm_dpms_str(private_output->current_dpms_value)); _pthread_mutex_unlock(&private_display->lock); _tdm_layer_cb_wait_vblank(private_output->vblank, 0, 0, 0, 0, private_output); _pthread_mutex_lock(&private_display->lock); @@ -934,7 +934,7 @@ tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_dat private_output->commit_type = TDM_COMMIT_TYPE_LAYER; } - if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) { TDM_ERR("layer(%p)'s output(%d) dpms: %s", layer, private_output->pipe, tdm_dpms_str(private_output->current_dpms_value)); _pthread_mutex_unlock(&private_display->lock); diff --git a/src/tdm_macro.h b/src/tdm_macro.h index 504315a..775354e 100644 --- a/src/tdm_macro.h +++ b/src/tdm_macro.h @@ -159,6 +159,12 @@ extern "C" { #define TDM_SWAP(a, b) ({ int t; t = a; a = b; b = t; }) #define TDM_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +/* can't export VSYNC macro because we can't define the exact meaning of vsync off + * at this time. Does committing in standy mode work? Doesn't committing in suspend mode work? + */ +#define TDM_OUTPUT_DPMS_VSYNC_OFF_MASK 0x2 +#define TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms) ((dpms) & TDM_OUTPUT_DPMS_VSYNC_OFF_MASK) + struct tdm_type_name { int type; const char *name; diff --git a/src/tdm_output.c b/src/tdm_output.c index 2e0b705..42dfe87 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -814,7 +814,7 @@ tdm_output_wait_vblank(tdm_output *output, int interval, int sync, _pthread_mutex_lock(&private_display->lock); - if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) { TDM_WRN("output(%d) dpms: %s", private_output->pipe, tdm_dpms_str(private_output->current_dpms_value)); _pthread_mutex_unlock(&private_display->lock); @@ -837,7 +837,7 @@ tdm_output_wait_vblank_add_front(tdm_output *output, int interval, int sync, _pthread_mutex_lock(&private_display->lock); - if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) { TDM_WRN("output(%d) dpms: %s", private_output->pipe, tdm_dpms_str(private_output->current_dpms_value)); _pthread_mutex_unlock(&private_display->lock); @@ -940,7 +940,7 @@ tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handl ret = tdm_output_get_dpms_internal(output, &dpms_value); TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); - if (dpms_value == TDM_OUTPUT_DPMS_ON) { + if (!TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms_value)) { if (func) { if (!private_output->regist_commit_cb) { private_output->regist_commit_cb = 1; @@ -988,8 +988,8 @@ tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handl private_layer->committed_buffer->buffer); } - if (dpms_value != TDM_OUTPUT_DPMS_ON) { - TDM_WRN("TDM_OUTPUT_DPMS_OFF. Directly call commit handler instead of commit."); + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms_value)) { + TDM_WRN("dpms %s. Directly call commit handler instead of commit.", tdm_dpms_str(dpms_value)); if (func) func(output, 0, 0, 0, user_data); } @@ -1030,7 +1030,7 @@ tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func, return TDM_ERROR_BAD_REQUEST; } - if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) { TDM_ERR("output(%d) dpms: %s", private_output->pipe, tdm_dpms_str(private_output->current_dpms_value)); _pthread_mutex_unlock(&private_display->lock); @@ -1209,9 +1209,6 @@ tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) tdm_func_output *func_output; OUTPUT_FUNC_ENTRY(); - if (dpms_value > TDM_OUTPUT_DPMS_OFF) - dpms_value = TDM_OUTPUT_DPMS_OFF; - _pthread_mutex_lock(&private_display->lock); if (private_output->waiting_dpms_change) { @@ -1267,9 +1264,6 @@ tdm_output_set_dpms_async(tdm_output *output, tdm_output_dpms dpms_value) return TDM_ERROR_BAD_REQUEST; } - if (dpms_value > TDM_OUTPUT_DPMS_OFF) - dpms_value = TDM_OUTPUT_DPMS_OFF; - _pthread_mutex_lock(&private_display->lock); if (private_output->waiting_dpms_change) { diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 2701456..e7b79b5 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -365,7 +365,7 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, case TDM_OUTPUT_CHANGE_DPMS: VIN("dpms %s", tdm_dpms_str(value.u32)); private_vblank->check_HW_or_SW = 1; - if (value.u32 != TDM_OUTPUT_DPMS_ON) { + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(value.u32)) { if (private_vblank->enable_fake) _tdm_vblank_change_to_SW(private_vblank); else @@ -1081,8 +1081,8 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, VER("can't wait a vblank: output disconnected"); return TDM_ERROR_OUTPUT_DISCONNECTED; } - if (dpms != TDM_OUTPUT_DPMS_ON) { - VER("can't wait a vblank: DPMS off"); + if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms)) { + VER("can't wait a vblank: DPMS %s", tdm_dpms_str(dpms)); return TDM_ERROR_DPMS_OFF; } } @@ -1134,7 +1134,7 @@ 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 (dpms == TDM_OUTPUT_DPMS_OFF || + else if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms) || private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) wait_info->type = VBLANK_TYPE_SW_FAKE; else if (private_vblank->offset == 0) -- 2.7.4 From eecb74a2f3a111578d833ade42f33f5d21e540d3 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 29 Nov 2017 15:20:28 +0900 Subject: [PATCH 15/16] dpms: handling extended DPMS modes Change-Id: Ic847321b932625daa6b357ffd435ec719d140ad9 --- client/tdm_client.c | 7 +++++++ include/tdm_common.h | 6 +++++- src/tdm_macro.h | 1 + src/tdm_output.c | 26 ++++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 6153187..a855e8f 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -274,6 +274,13 @@ _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint TDM_RETURN_IF_FAIL(private_output != NULL); + /* If value is extended value, we handle it as DPMS on in client side + * The extended DPMS value is valid only in server side. + * Or, need to export to client side also? + */ + if (value > TDM_OUTPUT_DPMS_OFF) + value = TDM_OUTPUT_DPMS_ON; + if (private_output->dpms == value) return; diff --git a/include/tdm_common.h b/include/tdm_common.h index f353216..d087fc8 100644 --- a/include/tdm_common.h +++ b/include/tdm_common.h @@ -87,11 +87,15 @@ typedef enum { /** * @brief The output capability enumeration * @details - * @remark + * If a backend module provides #TDM_OUTPUT_CAPABILITY_EXTENDED_DPMS, we can set + * an extended DPMS mode to an output which a backend module supports. + * Don't use the low-4bit for an extended DPMS mode value. It's used for default + * DPMS modes. */ typedef enum { TDM_OUTPUT_CAPABILITY_ASYNC_DPMS = (1 << 0), /**< if a outupt supports asynchronous DPMS operation */ TDM_OUTPUT_CAPABILITY_HWC = (1 << 1), /**< if a outupt supports hwc operation @since 2.0.0*/ + TDM_OUTPUT_CAPABILITY_EXTENDED_DPMS = (1 << 2), /**< if a outupt supports extended DPMS operation @since 2.0.0 */ } tdm_output_capability; /** diff --git a/src/tdm_macro.h b/src/tdm_macro.h index 775354e..9a99ae3 100644 --- a/src/tdm_macro.h +++ b/src/tdm_macro.h @@ -162,6 +162,7 @@ extern "C" { /* can't export VSYNC macro because we can't define the exact meaning of vsync off * at this time. Does committing in standy mode work? Doesn't committing in suspend mode work? */ +#define TDM_OUTPUT_DPMS_DEFAULT_MASK 0xF #define TDM_OUTPUT_DPMS_VSYNC_OFF_MASK 0x2 #define TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms) ((dpms) & TDM_OUTPUT_DPMS_VSYNC_OFF_MASK) diff --git a/src/tdm_output.c b/src/tdm_output.c index 42dfe87..9188c9c 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -1209,6 +1209,19 @@ tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) tdm_func_output *func_output; OUTPUT_FUNC_ENTRY(); + if (dpms_value > TDM_OUTPUT_DPMS_OFF) { + if (dpms_value & TDM_OUTPUT_DPMS_DEFAULT_MASK) { + TDM_ERR("Don't use the low-4bit for an extended DPMS mode: dpms_value(%x)", dpms_value); + return TDM_ERROR_BAD_REQUEST; + } + + if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_EXTENDED_DPMS)) { + TDM_ERR("output(%d) doesn't support the extended DPMS control: '%s'", + private_output->pipe, tdm_dpms_str(dpms_value)); + return TDM_ERROR_BAD_REQUEST; + } + } + _pthread_mutex_lock(&private_display->lock); if (private_output->waiting_dpms_change) { @@ -1264,6 +1277,19 @@ tdm_output_set_dpms_async(tdm_output *output, tdm_output_dpms dpms_value) return TDM_ERROR_BAD_REQUEST; } + if (dpms_value > TDM_OUTPUT_DPMS_OFF) { + if (dpms_value & TDM_OUTPUT_DPMS_DEFAULT_MASK) { + TDM_ERR("Don't use the low-4bit for an extended DPMS mode: dpms_value(%x)", dpms_value); + return TDM_ERROR_BAD_REQUEST; + } + + if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_EXTENDED_DPMS)) { + TDM_ERR("output(%d) doesn't support the extended DPMS control: '%s'", + private_output->pipe, tdm_dpms_str(dpms_value)); + return TDM_ERROR_BAD_REQUEST; + } + } + _pthread_mutex_lock(&private_display->lock); if (private_output->waiting_dpms_change) { -- 2.7.4 From 6b18d4c8ac640ade23492994b6f58c8dd9ca00f4 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 29 Nov 2017 15:20:50 +0900 Subject: [PATCH 16/16] dpms: add AOD dpms mode Change-Id: I5cd2bda61b7366fdb91e5867bfaa3e58158fccd5 --- include/tdm_common.h | 1 + src/tdm_macro.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/tdm_common.h b/include/tdm_common.h index d087fc8..b170c48 100644 --- a/include/tdm_common.h +++ b/include/tdm_common.h @@ -222,6 +222,7 @@ typedef enum { TDM_OUTPUT_DPMS_STANDBY, /**< StandBy, Vsync On */ TDM_OUTPUT_DPMS_SUSPEND, /**< Suspend, Vsync Off */ TDM_OUTPUT_DPMS_OFF, /**< Off, Vsync Off */ + TDM_OUTPUT_DPMS_AOD = 0x10, /**< AOD, Vsync On, extended DPMS mode */ } tdm_output_dpms; /** diff --git a/src/tdm_macro.h b/src/tdm_macro.h index 9a99ae3..a55251e 100644 --- a/src/tdm_macro.h +++ b/src/tdm_macro.h @@ -187,6 +187,7 @@ static struct tdm_type_name tdm_dpms_names[] = { { TDM_OUTPUT_DPMS_STANDBY, "standby" }, { TDM_OUTPUT_DPMS_SUSPEND, "suspend" }, { TDM_OUTPUT_DPMS_OFF, "off" }, + { TDM_OUTPUT_DPMS_AOD, "aod" }, }; TDM_TYPE_NAME_FN(dpms) -- 2.7.4