- 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
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;
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;
+}
tdm_client *client;
tdm_client_output *output;
tdm_client_vblank *vblank;
+ tdm_client_voutput *voutput;
double vrefresh_interval, start, end;
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,
Values(TDM_DEFAULT_MODULE));
#endif
-/* LCOV_EXCL_END */
\ No newline at end of file
+/* LCOV_EXCL_END */
<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">
}
}
+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)
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