virtual: implementations for virtual output 83/191083/6
authorJunkyeong Kim <jk0430.kim@samsung.com>
Thu, 11 Oct 2018 07:36:08 +0000 (16:36 +0900)
committerJunkyeong Kim <jk0430.kim@samsung.com>
Thu, 1 Nov 2018 02:31:47 +0000 (02:31 +0000)
 - voutput connect & disconnect
 - set voutput available modes
 - set voutput mode
 - set voutput physical size

Change-Id: I7aae9f5b425dfbdcf0b50843ee5b31e93e7ca353
Signed-off-by: Junkyeong Kim <jk0430.kim@samsung.com>
client/tdm_client.c
src/tdm.c
src/tdm_helper.c
src/tdm_output.c
src/tdm_server.c

index fbb875b..972ae00 100644 (file)
@@ -359,7 +359,7 @@ _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output
 
        private_client = private_output->private_client;
 
-       if (private_output->connection == value)
+       if (private_output->connection == value && value != TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
                return;
 
        private_output->connection = value;
index 30f3c07..886e847 100644 (file)
--- a/src/tdm.c
+++ b/src/tdm.c
@@ -127,6 +127,26 @@ tdm_display_find_output_stamp(tdm_private_display *private_display, double stamp
        return NULL;
 }
 
+INTERN void *
+tdm_display_find_private_voutput(tdm_private_display *private_display, double stamp)
+{
+       tdm_private_module *private_module = NULL;
+       tdm_private_voutput *private_voutput = NULL;
+       tdm_private_output *private_output = NULL;
+
+       private_module = private_display->virtual_module;
+       if (!private_module) return NULL;
+
+       LIST_FOR_EACH_ENTRY(private_voutput, &private_module->voutput_list, link) {
+               if (!private_voutput->private_output) continue;
+               private_output = private_voutput->private_output;
+               if (private_output->stamp == stamp)
+                       return private_voutput;
+       }
+
+       return NULL;
+}
+
 tdm_private_hwc *
 tdm_display_find_private_hwc(tdm_private_display *private_display, tdm_hwc *hwc_backend)
 {
@@ -530,6 +550,7 @@ tdm_display_update_output(tdm_private_module *private_module, tdm_output *output
                LIST_INITHEAD(&private_output->pending_commit_handler_list);
                LIST_INITHEAD(&private_output->destroy_handler_list);
                LIST_INITHEAD(&private_output->change_handler_list);
+               LIST_INITHEAD(&private_output->mode_change_request_handler_list);
 
                if (func_output->output_set_status_handler) {
                        func_output->output_set_status_handler(private_output->output_backend,
@@ -1024,6 +1045,7 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display,
        }
 
        LIST_INITHEAD(&private_module->output_list);
+       LIST_INITHEAD(&private_module->voutput_list);
        LIST_INITHEAD(&private_module->pp_list);
        LIST_INITHEAD(&private_module->capture_list);
 
index afedccd..e9db919 100644 (file)
@@ -947,6 +947,8 @@ _tdm_helper_get_backend_information(tdm_private_module *private_module, char *re
                        }
                }
        }
+       if (LIST_IS_EMPTY(&private_module->output_list))
+               TDM_SNPRINTF(reply, len, "(no layer)\n");
        TDM_SNPRINTF(reply, len, "\n");
 
        if (private_module->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
index 4a96e16..9454647 100644 (file)
@@ -500,6 +500,85 @@ tdm_output_add_change_handler(tdm_output *output,
        return ret;
 }
 
+EXTERN tdm_error
+tdm_output_add_mode_change_request_handler(tdm_output *output,
+                                                                                  tdm_output_mode_change_request_handler func,
+                                                                                  void *user_data)
+{
+       tdm_private_display *private_display;
+       tdm_private_output *private_output;
+       tdm_private_output_mode_change_handler *mode_change_handler = NULL;
+
+       TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
+       TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       private_output = (tdm_private_output*)output;
+       private_display = private_output->private_display;
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       LIST_FOR_EACH_ENTRY(mode_change_handler, &private_output->mode_change_request_handler_list, link) {
+               if (mode_change_handler->func == func && mode_change_handler->user_data == user_data) {
+                       TDM_ERR("can't add twice");
+                       _pthread_mutex_unlock(&private_display->lock);
+                       return TDM_ERROR_BAD_REQUEST;
+               }
+       }
+
+       mode_change_handler = calloc(1, sizeof(tdm_private_output_change_handler));
+       if (!mode_change_handler) {
+               /* LCOV_EXCL_START */
+               TDM_ERR("failed: alloc memory");
+               _pthread_mutex_unlock(&private_display->lock);
+               return TDM_ERROR_OUT_OF_MEMORY;
+               /* LCOV_EXCL_STOP */
+       }
+
+       mode_change_handler->private_output = private_output;
+       mode_change_handler->func = func;
+       mode_change_handler->user_data = user_data;
+
+       LIST_ADDTAIL(&mode_change_handler->link, &private_output->mode_change_request_handler_list);
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return TDM_ERROR_NONE;
+}
+
+EXTERN tdm_error
+tdm_output_remove_mode_change_request_handler(tdm_output *output,
+                                                                                         tdm_output_mode_change_request_handler func,
+                                                                                         void *user_data)
+{
+       tdm_private_display *private_display;
+       tdm_private_output *private_output;
+       tdm_private_output_mode_change_handler *mode_change_handler = NULL, *hh = NULL;
+
+       TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
+       TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       private_output = (tdm_private_output*)output;
+       private_display = private_output->private_display;
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       LIST_FOR_EACH_ENTRY_SAFE(mode_change_handler, hh, &private_output->mode_change_request_handler_list, link) {
+               if (mode_change_handler->func != func || mode_change_handler->user_data != user_data)
+                       continue;
+
+               LIST_DEL(&mode_change_handler->link);
+               free(mode_change_handler);
+
+               _pthread_mutex_unlock(&private_display->lock);
+
+               return TDM_ERROR_NONE;
+       }
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return TDM_ERROR_INVALID_PARAMETER;
+}
+
 EXTERN void
 tdm_output_remove_change_handler(tdm_output *output,
                                                                 tdm_output_change_handler func,
@@ -1206,6 +1285,22 @@ tdm_output_remove_commit_handler(tdm_output *output, tdm_output_commit_handler f
        return ret;
 }
 
+INTERN void
+tdm_output_request_mode_set(tdm_output *output, unsigned int index)
+{
+       tdm_private_output *private_output = (tdm_private_output*)output;
+       tdm_private_output_mode_change_handler *mode_change_handler = NULL;
+
+       TDM_RETURN_IF_FAIL(private_output != NULL);
+
+       if (LIST_IS_EMPTY(&private_output->mode_change_request_handler_list))
+               return;
+
+       LIST_FOR_EACH_ENTRY(mode_change_handler, &private_output->mode_change_request_handler_list, link) {
+               mode_change_handler->func(mode_change_handler->private_output, index, mode_change_handler->user_data);
+       }
+}
+
 INTERN tdm_error
 tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handler func, void *user_data)
 {
@@ -1856,3 +1951,123 @@ tdm_voutput_destroy(tdm_voutput *voutput)
 
        return ret;
 }
+
+INTERN tdm_error
+tdm_voutput_set_available_mode(tdm_voutput *voutput, const tdm_output_mode *modes, int count)
+{
+       tdm_private_display *private_display;
+       tdm_private_module *private_module = NULL;
+       tdm_private_voutput *private_voutput;
+       tdm_func_voutput *func_voutput = NULL;
+       tdm_error ret = TDM_ERROR_NONE;
+
+       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);
+
+       private_voutput = (tdm_private_voutput*)voutput;
+       private_display = private_voutput->private_display;
+       private_module = private_voutput->private_module;
+       TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE);
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       func_voutput = &private_module->func_voutput;
+       if (func_voutput->voutput_set_available_mode)
+               ret = func_voutput->voutput_set_available_mode(private_voutput->voutput_backend, modes, count);
+       else
+               ret = TDM_ERROR_NOT_IMPLEMENTED;
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
+INTERN tdm_error
+tdm_voutput_set_physical_size(tdm_voutput *voutput, unsigned int mmwidth, unsigned int mmheight)
+{
+       tdm_private_display *private_display;
+       tdm_private_module *private_module = NULL;
+       tdm_private_voutput *private_voutput;
+       tdm_func_voutput *func_voutput = NULL;
+       tdm_error ret = TDM_ERROR_NONE;
+
+       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);
+
+       private_voutput = (tdm_private_voutput*)voutput;
+       private_display = private_voutput->private_display;
+       private_module = private_voutput->private_module;
+       TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE);
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       func_voutput = &private_module->func_voutput;
+       if (func_voutput->voutput_set_physical_size)
+               ret = func_voutput->voutput_set_physical_size(private_voutput->voutput_backend, mmwidth, mmheight);
+       else
+               ret = TDM_ERROR_NOT_IMPLEMENTED;
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
+INTERN tdm_error
+tdm_voutput_connect(tdm_voutput *voutput)
+{
+       tdm_private_display *private_display;
+       tdm_private_module *private_module = NULL;
+       tdm_private_voutput *private_voutput;
+       tdm_func_voutput *func_voutput = NULL;
+       tdm_error ret = TDM_ERROR_NONE;
+
+       TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       private_voutput = (tdm_private_voutput*)voutput;
+       private_display = private_voutput->private_display;
+       private_module = private_voutput->private_module;
+       TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE);
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       func_voutput = &private_module->func_voutput;
+       if (func_voutput->voutput_connect)
+               ret = func_voutput->voutput_connect(private_voutput->voutput_backend);
+       else
+               ret = TDM_ERROR_NOT_IMPLEMENTED;
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
+INTERN tdm_error
+tdm_voutput_disconnect(tdm_voutput *voutput)
+{
+       tdm_private_display *private_display;
+       tdm_private_module *private_module = NULL;
+       tdm_private_voutput *private_voutput;
+       tdm_func_voutput *func_voutput = NULL;
+       tdm_error ret = TDM_ERROR_NONE;
+
+       TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       private_voutput = (tdm_private_voutput*)voutput;
+       private_display = private_voutput->private_display;
+       private_module = private_voutput->private_module;
+       TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE);
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       func_voutput = &private_module->func_voutput;
+       if (func_voutput->voutput_disconnect)
+               ret = func_voutput->voutput_disconnect(private_voutput->voutput_backend);
+       else
+               ret = TDM_ERROR_NOT_IMPLEMENTED;
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
index 12896d5..d035a1d 100644 (file)
@@ -196,6 +196,8 @@ _tdm_server_cb_output_change(tdm_output *output, tdm_output_change_type type,
        tdm_server_output_info *output_info = user_data;
        struct wl_client *client;
        pid_t pid = 0;
+       tdm_output_conn_status status;
+       tdm_error ret = TDM_ERROR_NONE;
 
        TDM_RETURN_IF_FAIL(output_info != NULL);
 
@@ -209,13 +211,29 @@ _tdm_server_cb_output_change(tdm_output *output, tdm_output_change_type type,
                return;
        }
 
-       TDM_DBG("send the output changes: %d", (unsigned int)pid);
+       TDM_DBG("send the output changes: %d, type:%d, value:%d", (unsigned int)pid, type, value.u32);
 
        switch (type) {
        case TDM_OUTPUT_CHANGE_DPMS:
                wl_tdm_output_send_dpms(output_info->resource, value.u32, TDM_ERROR_NONE);
                break;
        case TDM_OUTPUT_CHANGE_CONNECTION:
+               status = value.u32;
+               if (status == TDM_OUTPUT_CONN_STATUS_MODE_SETTED) {
+                       const tdm_output_mode *mode = NULL;
+                       unsigned int hdisplay, vdisplay, vrefresh;
+
+                       ret = tdm_output_get_mode(output_info->output, &mode);
+                       if (ret == TDM_ERROR_NONE) {
+                               hdisplay = (mode) ? mode->hdisplay : 0;
+                               vdisplay = (mode) ? mode->vdisplay : 0;
+                               vrefresh = (mode) ? mode->vrefresh : 0;
+
+                               wl_tdm_output_send_mode(output_info->resource, hdisplay, vdisplay, vrefresh, ret);
+                       } else {
+                               wl_tdm_output_send_mode(output_info->resource, 0, 0, 0, ret);
+                       }
+               }
                wl_tdm_output_send_connection(output_info->resource, value.u32, TDM_ERROR_NONE);
                break;
        default:
@@ -718,32 +736,99 @@ _tdm_voutput_cb_set_available_modes(struct wl_client *client,
                                                                        struct wl_resource *resource,
                                                                        struct wl_array *modes)
 {
-       /* TODO */
+       tdm_server_voutput_info *voutput_info;
+       tdm_output_mode *mode;
+       int size, count = 0, i = 0;
+
+       voutput_info = wl_resource_get_user_data(resource);
+
+       voutput_info->available_modes.count = 0;
+       if (voutput_info->available_modes.modes)
+               free(voutput_info->available_modes.modes);
+
+       wl_array_for_each(mode, modes)
+               count++;
+       size = sizeof(tdm_output_mode);
+
+       voutput_info->available_modes.modes = malloc(count * size);
+       voutput_info->available_modes.count = count;
+
+       wl_array_for_each(mode, modes)
+               memcpy(&voutput_info->available_modes.modes[i++], mode, size);
 }
 
 static void
 _tdm_voutput_cb_set_physical_size(struct wl_client *client, struct wl_resource *resource,
                                                                  unsigned int mmwidth, unsigned int mmheight)
 {
-       /* TODO */
+       tdm_server_voutput_info *voutput_info;
+
+       voutput_info = wl_resource_get_user_data(resource);
+
+       voutput_info->mmwidth = mmwidth;
+       voutput_info->mmheight = mmheight;
 }
 
 static void
 _tdm_voutput_cb_set_mode(struct wl_client *client, struct wl_resource *resource, unsigned int index)
 {
-       /* TODO */
+       tdm_server_voutput_info *voutput_info = NULL;
+       tdm_output *output = NULL;
+       tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+       const tdm_output_mode *modes, *mode;
+
+       int count = 0;
+       tdm_error ret;
+
+       voutput_info = wl_resource_get_user_data(resource);
+       TDM_RETURN_IF_FAIL(voutput_info != NULL);
+       output = voutput_info->output;
+
+       ret = tdm_output_get_conn_status(output, &status);
+       TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+       TDM_RETURN_IF_FAIL(status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED);
+
+       ret = tdm_output_get_available_modes(output, &modes, &count);
+       TDM_RETURN_IF_FAIL(index < count);
+
+       mode = &modes[index];
+       TDM_DBG("mode set request to index:%d (%dx%d, %d)", index, mode->hdisplay, mode->vdisplay, mode->vrefresh);
+
+       ret = tdm_output_set_mode(output, mode);
+       TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       tdm_output_request_mode_set(voutput_info->output, index);
 }
 
 static void
 _tdm_voutput_cb_connect(struct wl_client *client, struct wl_resource *resource)
 {
-       /* TODO */
+       tdm_server_voutput_info *voutput_info;
+
+       voutput_info = wl_resource_get_user_data(resource);
+       voutput_info->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
+
+       tdm_voutput_set_physical_size(voutput_info->voutput, voutput_info->mmwidth, voutput_info->mmheight);
+       tdm_voutput_set_available_mode(voutput_info->voutput, voutput_info->available_modes.modes, voutput_info->available_modes.count);
+       tdm_voutput_connect(voutput_info->voutput);
 }
 
 static void
 _tdm_voutput_cb_disconnect(struct wl_client *client, struct wl_resource *resource)
 {
-       /* TODO */
+       tdm_server_voutput_info *voutput_info;
+
+       voutput_info = wl_resource_get_user_data(resource);
+       voutput_info->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+
+       /* Do free resources when it's being disconnected */
+       free(voutput_info->available_modes.modes);
+       voutput_info->available_modes.modes = NULL;
+       voutput_info->available_modes.count = 0;
+       voutput_info->mmwidth = 0;
+       voutput_info->mmheight = 0;
+
+       tdm_voutput_disconnect(voutput_info->voutput);
 }
 
 static void