From 385484a21dcc7b743d2f3887c1d14ded4be64aab Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 17 Jul 2018 17:23:31 +0900 Subject: [PATCH] virtual output: Add implementation for client and test case for virtual output. - Added implementation for creation of virtual output. - Added definition for the rest of client's api of virtual output. - Added TC for client's Virtual Output API. Change-Id: Ic6959e852ec12fed4c8f7ba77c4cf3a360ce855a --- client/tdm_client.c | 227 +++++++++++++++++++++++++++++++++++++++++ haltests/src/tc_tdm_client.cpp | 210 +++++++++++++++++++++++++++++++++++++- protocol/tdm.xml | 21 ++++ src/tdm_server.c | 22 ++++ 4 files changed, 479 insertions(+), 1 deletion(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 4023208..8d17c94 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -89,6 +89,12 @@ typedef struct _tdm_private_client_output { struct list_head link; } tdm_private_client_output; +typedef struct _tdm_private_client_voutput { + tdm_private_client_output base; + struct wl_tdm_voutput *wl_voutput; + uint32_t msg; +} tdm_private_client_voutput; + struct _tdm_private_client_vblank { tdm_private_client_output *private_output; @@ -1591,3 +1597,224 @@ tdm_client_vblank_is_waiting(tdm_client_vblank *vblank) return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0; } + +void +tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg) +{ + tdm_private_client_voutput *private_voutput = data; + + private_voutput->msg = msg; +} + +static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = { + tdm_client_voutput_cb_ack_message +}; + +tdm_client_voutput * +tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error) +{ + tdm_private_client *private_client; + tdm_private_client_output *private_output; + tdm_private_client_voutput *private_voutput; + struct wl_proxy *wrapper; + + if (error) + *error = TDM_ERROR_NONE; + + if (!client) { + TDM_ERR("'!client' failed"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + if (!name) { + TDM_ERR("'!name' failed"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + private_client = (tdm_private_client *)client; + + pthread_mutex_lock(&private_client->lock); + + if (CHECK_WL_PROTOCOL_ERROR(private_client)) { + if (error) + *error = TDM_ERROR_PROTOCOL_ERROR; + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + + LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) { + if (!strncmp(private_output->name, name, TDM_NAME_LEN)) { + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type. + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + } + + wrapper = wl_proxy_create_wrapper(private_client->tdm); + if (!wrapper) { + TDM_ERR("create virtual output wrapper failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + + wl_proxy_set_queue(wrapper, private_client->queue); + + private_voutput = calloc(1, sizeof *private_voutput); + if (!private_voutput) { + /* LOCV_EXCL_START */ + wl_proxy_wrapper_destroy(wrapper); + TDM_ERR("alloc failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + /* LOCV_EXCL_STOP */ + } + + private_voutput->base.private_client = private_client; + + snprintf(private_voutput->base.name, TDM_NAME_LEN, "%s", name); + private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, private_voutput->base.name); + wl_proxy_wrapper_destroy(wrapper); + if (!private_voutput->wl_voutput) { + /* LCOV_EXCL_START */ + TDM_ERR("couldn't create voutput resource"); + free(private_voutput); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + pthread_mutex_unlock(&private_client->lock); + return NULL; + /* LCOV_EXCL_STOP */ + } + + wl_tdm_voutput_add_listener(private_voutput->wl_voutput, + &tdm_client_voutput_lisntener, private_voutput); + wl_display_roundtrip_queue(private_client->display, private_client->queue); + + wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL); + + if (CHECK_WL_PROTOCOL_ERROR(private_client)) { + wl_tdm_voutput_destroy(private_voutput->wl_voutput); + free(private_voutput); + if (error) + *error = TDM_ERROR_PROTOCOL_ERROR; + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + + if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED) + { + wl_tdm_voutput_destroy(private_voutput->wl_voutput); + free(private_voutput); + if (error) + *error = TDM_ERROR_PROTOCOL_ERROR; // FIXME add new error type. + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + + pthread_mutex_unlock(&private_client->lock); + + return (tdm_client_voutput *)private_voutput; +} + +void +tdm_client_voutput_destroy(tdm_client_voutput *voutput) +{ + tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput; + + if (!private_voutput) + return; + + free(private_voutput); +} + +tdm_error +tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count) +{ + TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(count > 0, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, int mmWidth, int mmHeight) +{ + TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(mmWidth > 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(mmHeight > 0, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_client_output * +tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error) +{ + tdm_private_client_voutput *private_voutput; + + if (error) + *error = TDM_ERROR_NONE; + + if (!voutput) + { + TDM_ERR("'!voutput' failed"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + private_voutput = (tdm_private_client_voutput *)voutput; + + return &private_voutput->base; +} + +tdm_error +tdm_client_output_set_buffer_queue(tdm_client_output *output, void *queue, void *func) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(queue != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_output_set_mode(tdm_client_output *output, const tdm_client_output_mode *mode) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_output_connect(tdm_client_output *output) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_output_disconnect(tdm_client_output *output) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + return TDM_ERROR_NONE; +} diff --git a/haltests/src/tc_tdm_client.cpp b/haltests/src/tc_tdm_client.cpp index 10e122d..20aa27f 100644 --- a/haltests/src/tc_tdm_client.cpp +++ b/haltests/src/tc_tdm_client.cpp @@ -66,6 +66,7 @@ public: tdm_client *client; tdm_client_output *output; tdm_client_vblank *vblank; + tdm_client_voutput *voutput; double vrefresh_interval, start, end; @@ -1358,6 +1359,213 @@ TEST_P(TDMClient, ClientVblankIsWaitingNullObject) ASSERT_EQ(waiting, 0); } +TEST_P(TDMClient, ClientCreateVOutput) +{ + tdm_error ret; + const char name[TDM_NAME_LEN] = "Virtual Output"; + + ASSERT_EQ(PrepareClient(), true); + + voutput = tdm_client_create_voutput(client, name, &ret); + ASSERT_EQ(ret, TDM_ERROR_NONE); + ASSERT_NE(voutput, NULL); + + tdm_client_voutput_destroy(voutput); +} + +class TDMVirtualOutput : public ::testing::Test +{ +public: + TDMVirtualOutput() {}; + ~TDMVirtualOutput() {}; + + static void SetUpTestCase(); + static void TearDownTestCase(); + static bool PrepareVOutput(void); + +protected: + static tdm_client *client; + static tdm_client_voutput *voutput; + const int MODE_COUNT = 1; + +private: + static pid_t server_pid; + + /* 0: read, 1: write */ + static int pipe_parent[2]; + static int pipe_child[2]; + + static void ServerFork(void); + static void ServerKill(void); +}; + +pid_t TDMVirtualOutput::server_pid = -1; +int TDMVirtualOutput::pipe_parent[2] = {-1, -1}; +int TDMVirtualOutput::pipe_child[2] = {-1, -1}; +tdm_client* TDMVirtualOutput::client = nullptr; +tdm_client_voutput* TDMVirtualOutput::voutput = nullptr; + +void TDMVirtualOutput::ServerKill(void) +{ + if (pipe_child[0] >= 0) + close(pipe_child[0]); + if (pipe_child[1] >= 0) { + if (server_pid > 0) { + bool ret = _tc_tdm_pipe_write_msg(pipe_child[1], pipe_parent[0], TDM_UT_PIPE_MSG_TERMINATE_SERVER); + if (ret) { + if (waitpid(server_pid, NULL, 0) == server_pid) + TDM_INFO("*** server terminated ***"); + else + TDM_ERR("*** failed to terminate server ***"); + } else { + if (kill(server_pid, 9) < 0) + TDM_ERR("*** failed to kill server ***"); + } + } + close(pipe_child[1]); + } + + if (pipe_parent[0] >= 0) + close(pipe_parent[0]); + if (pipe_parent[1] >= 0) + close(pipe_parent[1]); + + server_pid = -1; + pipe_parent[0] = pipe_parent[1] = -1; + pipe_child[0] = pipe_child[1] = -1; +} + +void TDMVirtualOutput::ServerFork(void) +{ + if (server_pid > 0) + return; + + server_pid = _tc_tdm_client_server_fork(pipe_parent, pipe_child); + ASSERT_GT(server_pid, 0); +} + +void TDMVirtualOutput::SetUpTestCase(void) +{ + setenv("XDG_RUNTIME_DIR", "/run", 1); + setenv("TBM_DISPLAY_SERVER", "1", 1); + + if (server_pid == -1) + ServerFork(); + + ASSERT_EQ(PrepareVOutput(), true); +} + +void TDMVirtualOutput::TearDownTestCase(void) +{ + if (voutput) + tdm_client_voutput_destroy(voutput); + + if (client) + tdm_client_destroy(client); + + ServerKill(); + + unsetenv("XDG_RUNTIME_DIR"); + unsetenv("TBM_DISPLAY_SERVER"); +} + +bool TDMVirtualOutput::PrepareVOutput(void) +{ + tdm_error ret; + const char name[TDM_NAME_LEN] = "Virtual Output"; + + client = tdm_client_create(&ret); + TDM_UT_RETURN_FALSE_IF_FAIL(ret == TDM_ERROR_NONE); + TDM_UT_RETURN_FALSE_IF_FAIL(client != NULL); + + voutput = tdm_client_create_voutput(client, name, &ret); + TDM_UT_RETURN_FALSE_IF_FAIL(ret == TDM_ERROR_NONE); + TDM_UT_RETURN_FALSE_IF_FAIL(voutput != NULL); + return true; +} + +TEST_F(TDMVirtualOutput, SetAvailableModes) +{ + tdm_error ret; + tdm_client_output_mode modes[this->MODE_COUNT]; + int i, count = this->MODE_COUNT; + + for (i = 0; i < count; i++) + { + modes[i].mmHeight = 1234; + modes[i].mmWidth = 1234; + modes[i].mode_count = 0; + modes[i].prop_count = 0; + modes[i].subpixel = 0; + snprintf(modes[i].name, TDM_NAME_LEN, "TestModeSetting"); + } + + ret = tdm_client_voutput_set_available_modes(this->voutput, modes, count); + ASSERT_EQ(ret, TDM_ERROR_NONE); +} + +TEST_F(TDMVirtualOutput, FailTestSetAvailableModes) +{ + tdm_error ret; + tdm_client_output_mode modes[this->MODE_COUNT]; + int count = this->MODE_COUNT; + + ret = tdm_client_voutput_set_available_modes(NULL, modes, count); + ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); + + ret = tdm_client_voutput_set_available_modes(this->voutput, NULL, count); + ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); + + ret = tdm_client_voutput_set_available_modes(this->voutput, modes, 0); + ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); +} + +TEST_F(TDMVirtualOutput, SetPhysicalSize) +{ + tdm_error ret; + int mmWidth = 1234, mmHeight = 1234; + + ret = tdm_client_voutput_set_physical_size(this->voutput, mmWidth, mmHeight); + ASSERT_EQ(ret, TDM_ERROR_NONE); +} + +TEST_F(TDMVirtualOutput, FailTestSetPhysicalSize) +{ + tdm_error ret; + int invalid_mmWidth = -1, invalid_mmHeight = -1; + + ret = tdm_client_voutput_set_physical_size(this->voutput, invalid_mmWidth, invalid_mmHeight); + ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); +} + +TEST_F(TDMVirtualOutput, GetClientOutput) +{ + tdm_error ret; + tdm_client_output *output; + + output = tdm_client_voutput_get_client_output(this->voutput, &ret); + ASSERT_EQ(ret, TDM_ERROR_NONE); + ASSERT_NE(output, NULL); +} + +#if 0 +TEST_F(TDMVirtualOutput, FailTestGetClientOutput) +{ + tdm_error ret; +} + +TEST_F(TDMVirtualOutput, SetBufferQueue) +{ + tdm_error ret; +} + +TEST_F(TDMVirtualOutput, FailTestSetBufferQueue) +{ + tdm_error ret; +} + +#endif + #ifdef TDM_UT_TEST_WITH_PARAMS INSTANTIATE_TEST_CASE_P(TDMClientParams, TDMClient, @@ -1368,4 +1576,4 @@ INSTANTIATE_TEST_CASE_P(TDMClientParams, Values(TDM_DEFAULT_MODULE)); #endif -/* LCOV_EXCL_END */ \ No newline at end of file +/* LCOV_EXCL_END */ diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 6434e98..58422cf 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -23,6 +23,11 @@ + + + + + @@ -66,6 +71,22 @@ + + + + + + + + + + + + + + + + diff --git a/src/tdm_server.c b/src/tdm_server.c index 30bb475..d77151c 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -682,6 +682,27 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou } } +static void +_tdm_server_cb_create_virtual_output(struct wl_client *client, struct wl_resource *resource, const char *name, uint32_t id) +{ + struct wl_resource *voutput_resource = NULL; + + voutput_resource = + wl_resource_create(client, &wl_tdm_voutput_interface, + wl_resource_get_version(resource), id); + if (!voutput_resource) { + /* LCOV_EXCL_START */ + + wl_resource_post_no_memory(resource); + TDM_ERR("wl_resource_create failed"); + return; + + /* LCOV_EXCL_STOP */ + } + + wl_tdm_voutput_send_ack_message(voutput_resource, WL_TDM_VOUTPUT_MESSAGE_ADDED); +} + /* LCOV_EXCL_START */ static void _tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, const char *options) @@ -727,6 +748,7 @@ _tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, con static const struct wl_tdm_interface tdm_implementation = { _tdm_server_cb_debug, _tdm_server_cb_create_output, + _tdm_server_cb_create_virtual_output }; static void -- 2.7.4