X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftdm_server.c;h=aa546e6444b15a59b5602f8d57cf81576e841b75;hb=b86fd8a4f6e17ca00edd5345b862aa8c08756331;hp=f5e222a79c051f15b151435cb672cc3519fcf58e;hpb=45c4c5c6af9816df36118a51341e3d0a618c0a6e;p=platform%2Fcore%2Fuifw%2Flibtdm.git diff --git a/src/tdm_server.c b/src/tdm_server.c index f5e222a..aa546e6 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -9,7 +9,7 @@ * Taeheon Kim , * YoungJun Cho , * SooChan Lim , - * Boram Park + * Boram Park * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -37,6 +37,8 @@ #include "config.h" #endif +#define WL_HIDE_DEPRECATED + #include #include "tdm_private.h" @@ -53,6 +55,7 @@ struct _tdm_private_server { tdm_private_loop *private_loop; struct list_head output_list; + struct list_head voutput_list; struct list_head wait_list; }; @@ -65,6 +68,34 @@ typedef struct _tdm_server_output_info { unsigned int watch_output_changes; } tdm_server_output_info; +typedef struct _tdm_server_voutput_buffer { + struct list_head link; + struct wl_resource *wl_buffer; + tbm_surface_h buffer; +} tdm_server_voutput_buffer; + +typedef struct _tdm_server_voutput_info { + struct list_head link; + tdm_private_server *private_server; + struct wl_resource *resource; + tdm_output *output; + struct list_head output_list; + + tdm_output_conn_status status; + struct + { + int count; + tdm_output_mode *modes; + } available_modes; + + unsigned int mmwidth; + unsigned int mmheight; + + struct list_head buffer_list; + tdm_server_voutput_buffer *attach_buffer; + int committing; +} tdm_server_voutput_info; + typedef struct _tdm_server_vblank_info { struct list_head link; tdm_server_output_info *output_info; @@ -239,8 +270,10 @@ static void _tdm_server_vblank_cb_set_name(struct wl_client *client, struct wl_resource *resource, const char *name) { tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource); + tdm_error ret; - tdm_vblank_set_name(vblank_info->vblank, name); + ret = tdm_vblank_set_name(vblank_info->vblank, name); + TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); } /* LCOV_EXCL_STOP */ @@ -249,8 +282,10 @@ static void _tdm_server_vblank_cb_set_fps(struct wl_client *client, struct wl_resource *resource, uint32_t fps) { tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource); + tdm_error ret; - tdm_vblank_set_fps(vblank_info->vblank, fps); + ret = tdm_vblank_set_fps(vblank_info->vblank, fps); + TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); } /* LCOV_EXCL_STOP */ @@ -259,8 +294,10 @@ static void _tdm_server_vblank_cb_set_offset(struct wl_client *client, struct wl_resource *resource, int32_t offset) { tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource); + tdm_error ret; - tdm_vblank_set_offset(vblank_info->vblank, offset); + ret = tdm_vblank_set_offset(vblank_info->vblank, offset); + TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); } /* LCOV_EXCL_STOP */ @@ -268,8 +305,10 @@ static void _tdm_server_vblank_cb_set_enable_fake(struct wl_client *client, struct wl_resource *resource, uint32_t enable_fake) { tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource); + tdm_error ret; - tdm_vblank_set_enable_fake(vblank_info->vblank, enable_fake); + ret = tdm_vblank_set_enable_fake(vblank_info->vblank, enable_fake); + TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); } static void @@ -674,6 +713,467 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou } } +static void _tdm_voutput_cb_destroy(struct wl_client *client, struct wl_resource *resource) +{ + tdm_server_voutput_info *voutput_info; + tdm_private_server *private_server; + tdm_output *output; + tdm_error ret = TDM_ERROR_NONE; + + voutput_info = wl_resource_get_user_data(resource); + + private_server = voutput_info->private_server; + output = voutput_info->output; + + if (output) + ret = tdm_display_destroy_output(private_server->private_loop->dpy, output); + + if (ret != TDM_ERROR_NONE) + TDM_ERR("_tdm_voutput_cb_destroy fail"); + + wl_resource_destroy(resource); +} + +static void +_tdm_voutput_cb_set_available_modes(struct wl_client *client, + struct wl_resource *resource, + struct wl_array *modes) +{ + 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) +{ + 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_connect(struct wl_client *client, struct wl_resource *resource) +{ + tdm_server_voutput_info *voutput_info; + + voutput_info = wl_resource_get_user_data(resource); + voutput_info->status = TDM_OUTPUT_CONN_STATUS_CONNECTED; + + tdm_output_set_physical_size(voutput_info->output, voutput_info->mmwidth, voutput_info->mmheight); + tdm_output_set_available_mode(voutput_info->output, voutput_info->available_modes.modes, voutput_info->available_modes.count); + tdm_output_set_connect(voutput_info->output); +} + +static void +_tdm_voutput_cb_disconnect(struct wl_client *client, struct wl_resource *resource) +{ + 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_output_set_disconnect(voutput_info->output); +} + +static void +_tdm_voutput_cb_commit_done(struct wl_client *client, struct wl_resource *resource) +{ + tdm_server_voutput_info *voutput_info; + + voutput_info = wl_resource_get_user_data(resource); + if (voutput_info->status != TDM_OUTPUT_CONN_STATUS_CONNECTED) + { + // handle error + return; + } +// tdm_output_commit_done(voutput_info->output, voutput_info->attach_buffer->buffer); + voutput_info->committing = 0; + voutput_info->attach_buffer = NULL; +} + +static const struct wl_tdm_voutput_interface tdm_voutput_implementation = { + _tdm_voutput_cb_destroy, + _tdm_voutput_cb_set_available_modes, + _tdm_voutput_cb_set_physical_size, + _tdm_voutput_cb_connect, + _tdm_voutput_cb_disconnect, + _tdm_voutput_cb_commit_done +}; + +static void +_tdm_voutput_wl_buffer_destroy(struct wl_client *client, struct wl_resource *wl_buffer) +{ + wl_resource_destroy(wl_buffer); +} + +static const struct wl_buffer_interface _tdm_voutput_buffer_impementation = { + _tdm_voutput_wl_buffer_destroy +}; + +static void +_tdm_voutput_buffer_destory(struct wl_resource *wl_buffer) +{ + tdm_server_voutput_info *voutput_info = NULL; + tdm_server_voutput_buffer *vb = NULL; + + voutput_info = (tdm_server_voutput_info *)wl_resource_get_user_data(wl_buffer); + TDM_RETURN_IF_FAIL(voutput_info != NULL); + + LIST_FOR_EACH_ENTRY(vb, &voutput_info->buffer_list, link) { + if (vb->wl_buffer == wl_buffer) { + tbm_surface_internal_unref(vb->buffer); + wl_resource_set_user_data(wl_buffer, NULL); + free(vb); + } + } +} + +struct wl_resource * +_tdm_voutput_create_wl_buffer(tdm_server_voutput_info *voutput_info) +{ + struct wl_client *wl_client; + struct wl_resource *wl_buffer = NULL; + + wl_client = wl_resource_get_client(voutput_info->resource); + + /* create a wl_buffer resource */ + wl_buffer = wl_resource_create(wl_client, &wl_buffer_interface, 1, 0); + TDM_RETURN_VAL_IF_FAIL(wl_buffer != NULL, NULL); + + wl_resource_set_implementation(wl_buffer, + (void (**)(void)) &_tdm_voutput_buffer_impementation, + voutput_info, _tdm_voutput_buffer_destory); + + return wl_buffer; +} + +struct wl_resource * +_tdm_voutput_export_buffer(tdm_server_voutput_info *voutput_info, + tbm_surface_h buffer) +{ + int bufs[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1}; + struct wl_resource *wl_buffer = NULL; + int num_buf, is_fd = -1, i; + tbm_surface_info_s info; + uint32_t flags = 0; + struct wl_array plane_buf_idx, plane_offset, plane_stride, plane_size; + int *p; + + TDM_RETURN_VAL_IF_FAIL(voutput_info != NULL, NULL); + TDM_RETURN_VAL_IF_FAIL(buffer != NULL, NULL); + + if (tbm_surface_get_info(buffer, &info) != TBM_SURFACE_ERROR_NONE) { + TDM_ERR("Failed to create buffer from surface"); + return NULL; + } + + if (info.num_planes > 3) { + TDM_ERR("invalid num_planes(%d)", info.num_planes); + return NULL; + } + + num_buf = tbm_surface_internal_get_num_bos(buffer); + if (num_buf == 0) { + TDM_ERR("surface doesn't have any bo."); + return NULL; + } + + for (i = 0; i < num_buf; i++) { + tbm_bo bo = tbm_surface_internal_get_bo(buffer, i); + if (bo == NULL) { + TDM_ERR("Failed to get bo from surface"); + goto err; + } + + /* try to get fd first */ + if (is_fd == -1 || is_fd == 1) { + bufs[i] = tbm_bo_export_fd(bo); + if (is_fd == -1 && bufs[i] >= 0) + is_fd = 1; + } + + /* if fail to get fd, try to get name second */ + if (is_fd == -1 || is_fd == 0) { + bufs[i] = tbm_bo_export(bo); + if (is_fd == -1 && bufs[i] > 0) + is_fd = 0; + } + + if (is_fd == -1 || + (is_fd == 1 && bufs[i] < 0) || + (is_fd == 0 && bufs[i] <= 0)) { + TDM_ERR("Failed to export(is_fd:%d, bufs:%d)", is_fd, bufs[i]); + goto err; + } + } + + wl_buffer = _tdm_voutput_create_wl_buffer(voutput_info); + if (!wl_buffer) { + TDM_ERR("Failed to create wl_buffer"); + goto err; + } + + wl_array_init(&plane_buf_idx); + wl_array_init(&plane_offset); + wl_array_init(&plane_stride); + wl_array_init(&plane_size); + + for (i = 0; i < 3; i++) { + p = wl_array_add(&plane_buf_idx, sizeof(int)); + *p = tbm_surface_internal_get_plane_bo_idx(buffer, i); + p = wl_array_add(&plane_offset, sizeof(int)); + *p = info.planes[i].offset; + p = wl_array_add(&plane_stride, sizeof(int)); + *p = info.planes[i].stride; + p = wl_array_add(&plane_size, sizeof(int)); + *p = info.planes[i].size; + } + + if (is_fd == 1) + wl_tdm_voutput_send_buffer_set_with_fd(voutput_info->resource, + wl_buffer, + info.width, info.height, info.format, info.bpp, info.size, info.num_planes, + &plane_buf_idx, &plane_offset, &plane_stride, &plane_size, + flags, num_buf, bufs[0], + (bufs[1] == -1) ? bufs[0] : bufs[1], + (bufs[2] == -1) ? bufs[0] : bufs[2]); + else + wl_tdm_voutput_send_buffer_set_with_id(voutput_info->resource, + wl_buffer, + info.width, info.height, info.format, info.bpp, info.size, info.num_planes, + &plane_buf_idx, &plane_offset, &plane_stride, &plane_size, + flags, + num_buf, bufs[0], bufs[1], bufs[2]); + + wl_array_release(&plane_buf_idx); + wl_array_release(&plane_offset); + wl_array_release(&plane_stride); + wl_array_release(&plane_size); + + for (i = 0; i < TBM_SURF_PLANE_MAX; i++) { + if (is_fd == 1 && (bufs[i] >= 0)) + close(bufs[i]); + } + + return wl_buffer; + +err: + for (i = 0; i < TBM_SURF_PLANE_MAX; i++) { + if (is_fd == 1 && (bufs[i] >= 0)) + close(bufs[i]); + } + + return NULL; +} + +tdm_server_voutput_buffer * +_tdm_output_get_voutput_buffer(tdm_server_voutput_info *voutput_info, tbm_surface_h buffer) +{ + tdm_server_voutput_buffer *voutput_buffer = NULL, *vb = NULL; + + LIST_FOR_EACH_ENTRY(vb, &voutput_info->buffer_list, link) { + if (vb && vb->buffer == buffer) + return vb; + } + + tbm_surface_internal_ref(buffer); + voutput_buffer = calloc(1, sizeof *voutput_buffer); + if (!voutput_buffer) { + /* LCOV_EXCL_START */ + + TDM_ERR("fail calloc"); + tbm_surface_internal_unref(buffer); + return NULL; + + /* LCOV_EXCL_STOP */ + } + + voutput_buffer->wl_buffer = _tdm_voutput_export_buffer(voutput_info, buffer); + if (!voutput_buffer->wl_buffer) { + /* LCOV_EXCL_START */ + + TDM_ERR("fail export buffer"); + free(voutput_buffer); + tbm_surface_internal_unref(buffer); + return NULL; + + /* LCOV_EXCL_STOP */ + } + + voutput_buffer->buffer = buffer; + LIST_ADDTAIL(&voutput_info->link, &voutput_info->buffer_list); + + return voutput_buffer; +} + +INTERN tdm_error +tdm_output_send_buffer(tdm_output *output, tbm_surface_h buffer) +{ + tdm_private_server *private_server = keep_private_server; + tdm_server_voutput_info *voutput_info = NULL, *vo = NULL; + tdm_server_voutput_buffer *voutput_buffer = NULL; + + TDM_RETURN_VAL_IF_FAIL(keep_private_server != NULL, TDM_ERROR_OPERATION_FAILED); + + LIST_FOR_EACH_ENTRY(vo, &private_server->voutput_list, link) { + if (vo && vo->output == output) { + voutput_info = vo; + break; + } + } + TDM_RETURN_VAL_IF_FAIL(voutput_info != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(voutput_info->attach_buffer == NULL, TDM_ERROR_OPERATION_FAILED); + + voutput_buffer = _tdm_output_get_voutput_buffer(voutput_info, buffer); + TDM_RETURN_VAL_IF_FAIL(voutput_buffer != NULL, TDM_ERROR_OUT_OF_MEMORY); + + voutput_info->attach_buffer = voutput_buffer; + + wl_tdm_voutput_send_attach_buffer(voutput_info->resource, voutput_buffer->wl_buffer); + + return TDM_ERROR_NONE; +} + +INTERN tdm_error +tdm_output_commit_buffer(tdm_output *output) +{ + tdm_private_server *private_server = keep_private_server; + tdm_server_voutput_info *voutput_info = NULL, *vo = NULL; + + TDM_RETURN_VAL_IF_FAIL(keep_private_server != NULL, TDM_ERROR_OPERATION_FAILED); + + LIST_FOR_EACH_ENTRY(vo, &private_server->voutput_list, link) { + if (vo && vo->output == output) { + voutput_info = vo; + break; + } + } + TDM_RETURN_VAL_IF_FAIL(voutput_info != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(voutput_info->attach_buffer != NULL, TDM_ERROR_OPERATION_FAILED); + TDM_RETURN_VAL_IF_FAIL(voutput_info->committing == 0, TDM_ERROR_OPERATION_FAILED); + + voutput_info->committing = 1; + + wl_tdm_voutput_send_commit(voutput_info->resource); + + return TDM_ERROR_NONE; +} + +void +tdm_voutput_cb_resource_destroy(struct wl_resource *resource) +{ + tdm_server_voutput_info *voutput_info = wl_resource_get_user_data(resource); + tdm_server_voutput_buffer *vb, *vbb; + TDM_RETURN_IF_FAIL(voutput_info != NULL); + + LIST_FOR_EACH_ENTRY_SAFE(vb, vbb, &voutput_info->buffer_list, link) { + if (!vb) continue; + + LIST_DEL(&vb->link); + + if (vb->wl_buffer) + wl_resource_destroy(vb->wl_buffer); + } + + LIST_DEL(&voutput_info->link); + + /* Do free your own resource */ + free(voutput_info); +} + +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; + tdm_private_server *private_server = wl_resource_get_user_data(resource); + tdm_server_voutput_info *voutput_info; + tdm_output *output; + tdm_error ret; + + output = tdm_display_find_output(private_server->private_loop->dpy, name, NULL); + if (output) { + TDM_ERR("There is '%s' output, cannot create.", name); + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "There is '%s' output", name); + return; + } + + output = tdm_display_create_output(private_server->private_loop->dpy, name, &ret); + if (!output) { + TDM_ERR("output creation fail(%s)(%d).", name, ret); + wl_resource_post_error(resource, WL_DISPLAY_ERROR_NO_MEMORY, + "%s output creation fail", name); + return; + } + + 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 */ + } + + voutput_info = calloc(1, sizeof * voutput_info); + if (!voutput_info) { + /* LCOV_EXCL_START */ + + wl_resource_post_no_memory(resource); + wl_resource_destroy(voutput_resource); + TDM_ERR("alloc failed"); + return; + + /* LCOV_EXCL_STOP */ + } + + LIST_ADDTAIL(&voutput_info->link, &private_server->voutput_list); + voutput_info->private_server = private_server; + voutput_info->resource = voutput_resource; + voutput_info->output = output; + LIST_INITHEAD(&voutput_info->output_list); + LIST_INITHEAD(&voutput_info->buffer_list); + + wl_resource_set_implementation(voutput_resource, + &tdm_voutput_implementation, + voutput_info, + tdm_voutput_cb_resource_destroy); + + 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) @@ -719,6 +1219,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 @@ -803,6 +1304,7 @@ tdm_server_init(tdm_private_loop *private_loop) } LIST_INITHEAD(&private_server->output_list); + LIST_INITHEAD(&private_server->voutput_list); LIST_INITHEAD(&private_server->wait_list); if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1, @@ -829,6 +1331,7 @@ INTERN void tdm_server_deinit(tdm_private_loop *private_loop) { tdm_server_output_info *o = NULL, *oo = NULL; + tdm_server_voutput_info *vo = NULL, *voo = NULL; tdm_server_wait_info *w = NULL, *ww = NULL; tdm_server_client_info *c = NULL, *cc = NULL; tdm_private_server *private_server; @@ -846,6 +1349,10 @@ tdm_server_deinit(tdm_private_loop *private_loop) wl_resource_destroy(o->resource); } + LIST_FOR_EACH_ENTRY_SAFE(vo, voo, &private_server->voutput_list, link) { + wl_resource_destroy(vo->resource); + } + LIST_FOR_EACH_ENTRY_SAFE(c, cc, &client_list, link) { wl_resource_destroy(c->resource); }