virtual output: Add implementation for client and test case for virtual output. 34/184334/4
authorSeunghun Lee <shiin.lee@samsung.com>
Tue, 17 Jul 2018 08:23:31 +0000 (17:23 +0900)
committerSeunghun Lee <shiin.lee@samsung.com>
Wed, 18 Jul 2018 06:48:43 +0000 (15:48 +0900)
- 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
haltests/src/tc_tdm_client.cpp
protocol/tdm.xml
src/tdm_server.c

index 4023208..8d17c94 100644 (file)
@@ -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;
+}
index 10e122d..20aa27f 100644 (file)
@@ -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 */
index 6434e98..58422cf 100644 (file)
             <arg name="id" type="new_id" interface="wl_tdm_output"/>
         </request>
 
+        <request name="create_voutput">
+            <arg name="name" type="string" summary=""/>
+            <arg name="id" type="new_id" interface="wl_tdm_voutput"/>
+        </request>
+
     </interface>
 
     <interface name="wl_tdm_output" version="1">
 
     </interface>
 
+    <interface name="wl_tdm_voutput" version="1">
+        <description summary="TDM client virtual output object">
+        </description>
+
+        <request name="destroy" type="destructor"/>
+
+        <event name="ack_message">
+            <arg name="msg" type="uint" enum="message" summary=""/>
+        </event>
+        <enum name="message">
+            <entry name="unknown" value="0" summary=""/>
+            <entry name="added" value="1" summary=""/>
+            <entry name="permission_denied" value="2" summary=""/>
+        </enum>
+    </interface>
+
     <interface name="wl_tdm_vblank" version="1">
 
         <event name="stamp">
index 30bb475..d77151c 100644 (file)
@@ -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