From 242fc68711eb15837735c52a8b81ec1b41236ea6 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Tue, 16 Oct 2018 21:16:31 +0900 Subject: [PATCH] virtual: share buffer with client - attach buffer - commit buffer - commit done sequence : output commit -> backend call voutput commit func(not output commit handler this time) -> execute voutput attach buffer and commit buffer from voutput commit func(send buffer to client) -> commit done by client -> backend receive commit done so execute output commit handler Change-Id: Ie0dde85f016ead14153c12e71d0d0ae6c2a65459 Signed-off-by: Junkyeong Kim --- src/tdm_layer.c | 7 +- src/tdm_output.c | 212 ++++++++++++++++++++++++++++++++++++++ src/tdm_server.c | 306 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/tdm_thread.c | 1 + 4 files changed, 523 insertions(+), 3 deletions(-) diff --git a/src/tdm_layer.c b/src/tdm_layer.c index d8503a5..0885abb 100644 --- a/src/tdm_layer.c +++ b/src/tdm_layer.c @@ -804,7 +804,7 @@ _tdm_layer_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequ } static unsigned int -_tdm_lauer_get_output_used_layer_count(tdm_private_output *private_output) +_tdm_layer_get_output_used_layer_count(tdm_private_output *private_output) { tdm_private_layer *private_layer = NULL; unsigned int count = 0; @@ -840,7 +840,7 @@ _tdm_layer_commit_possible(tdm_private_layer *private_layer) return 0; } - if (private_output->commit_per_vblank == 1 && _tdm_lauer_get_output_used_layer_count(private_output) > 1) { + if (private_output->commit_per_vblank == 1 && _tdm_layer_get_output_used_layer_count(private_output) > 1) { if (tdm_debug_module & TDM_DEBUG_COMMIT) TDM_INFO("layer(%p,%d) commit: not possible(more than 2 layers)", private_layer, private_layer->index); @@ -944,6 +944,9 @@ _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_da layer_commit_handler->committed_buffer = private_layer->waiting_buffer; private_layer->waiting_buffer = NULL; + if (!private_layer->committing && layer_commit_handler->committed_buffer) + private_layer->commiting_buffer = layer_commit_handler->committed_buffer->buffer; + if (private_layer->committing) TDM_WRN("layer(%p,%d) too many commit", private_layer, private_layer->index); else diff --git a/src/tdm_output.c b/src/tdm_output.c index 9454647..3d6686b 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -135,6 +135,7 @@ tdm_output_init(tdm_private_display *private_display) tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_VBLANK, tdm_display_find_output_stamp); tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_STATUS, tdm_display_find_output_stamp); tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_DPMS, tdm_display_find_output_stamp); + tdm_thread_cb_set_find_func(TDM_THREAD_CB_VOUTPUT_COMMIT, tdm_display_find_private_voutput); return TDM_ERROR_NONE; } @@ -1075,6 +1076,87 @@ _tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence, TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); } +static void +_tdm_voutput_thread_cb_commit(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data) +{ + tdm_thread_cb_voutput_commit *voutput_commit = (tdm_thread_cb_voutput_commit *)cb_base; + tdm_private_voutput_commit_handler *voutput_commit_handler = voutput_commit->base.data; + tdm_private_voutput *private_voutput = object; + tdm_private_output *private_output = NULL; + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + + if (!voutput_commit_handler) + return; + + assert(voutput_commit_handler->owner_tid == syscall(SYS_gettid)); + + tdm_thread_cb_remove(private_voutput, TDM_THREAD_CB_VOUTPUT_COMMIT, voutput_commit_handler, _tdm_voutput_thread_cb_commit, NULL); + + LIST_DEL(&voutput_commit_handler->link); + + private_output = private_voutput->private_output; + if (tdm_debug_module & TDM_DEBUG_COMMIT) { + TDM_INFO("----------------------------------------- voutput(%d) committed", private_output->pipe); + TDM_INFO("handler(%p)", voutput_commit_handler); + } + + if (voutput_commit_handler->func) { + _pthread_mutex_unlock(&private_display->lock); + voutput_commit_handler->func(private_voutput, voutput_commit_handler->user_data); + _pthread_mutex_lock(&private_display->lock); + } + + free(voutput_commit_handler); + + if (tdm_debug_module & TDM_DEBUG_COMMIT) + TDM_INFO("-----------------------------------------..."); +} + +static void +_tdm_voutput_cb_commit(tdm_voutput *voutput_backend, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) +{ + tdm_private_voutput_commit_handler *voutput_commit_handler = NULL; + tdm_private_module *private_module; + tdm_private_voutput *private_voutput = NULL, *v; + tdm_private_output *private_output; + tdm_thread_cb_voutput_commit voutput_commit; + tdm_error ret; + + private_module = tdm_display_get()->virtual_module; + + LIST_FOR_EACH_ENTRY(v, &private_module->voutput_list, link) { + if (v->voutput_backend == voutput_backend) { + private_voutput = v; + break; + } + } + if (!private_voutput) { + TDM_ERR("cannot find voutput"); + return; + } + + LIST_FOR_EACH_ENTRY(voutput_commit_handler, &private_voutput->voutput_commit_handler_list, link) { + if (voutput_commit_handler) break; + } + + private_output = private_voutput->private_output; + + memset(&voutput_commit, 0, sizeof voutput_commit); + voutput_commit.base.type = TDM_THREAD_CB_VOUTPUT_COMMIT; + voutput_commit.base.length = sizeof voutput_commit; + voutput_commit.base.object_stamp = private_output->stamp; + voutput_commit.base.data = voutput_commit_handler; + voutput_commit.base.sync = 0; + voutput_commit.sequence = sequence; + voutput_commit.tv_sec = tv_sec; + voutput_commit.tv_usec = tv_usec; + + ret = tdm_thread_cb_call(private_voutput, &voutput_commit.base, 1); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); +} + /* add_front: To distinguish between the user vblank handlers and the layer * commit vblank handlers. The layer commit handlers will be called * before calling the user vblank handlers. @@ -1301,13 +1383,33 @@ tdm_output_request_mode_set(tdm_output *output, unsigned int index) } } +static void +_voutput_commit_func(tdm_voutput *voutput, tbm_surface_h buffer) +{ + tdm_private_voutput *private_voutput = (tdm_private_voutput *)voutput; + tdm_error ret; + + TDM_RETURN_IF_FAIL(voutput != NULL); + TDM_RETURN_IF_FAIL(buffer != NULL); + + ret = tdm_voutput_attach_buffer(private_voutput, buffer); + TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); + ret = tdm_voutput_commit_buffer(private_voutput); + TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); + + return; +} + INTERN tdm_error tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handler func, void *user_data) { + tdm_private_display *private_display; tdm_private_output *private_output; + tdm_private_voutput *private_voutput; tdm_private_module *private_module; tdm_func_output *func_output; tdm_private_output_commit_handler *output_commit_handler = NULL; + tdm_private_voutput_commit_handler *voutput_commit_handler = NULL; tdm_private_layer *private_layer = NULL; tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_ON; tdm_error ret = TDM_ERROR_NONE; @@ -1316,6 +1418,7 @@ tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handl private_output = (tdm_private_output*)output; private_module = private_output->private_module; + private_display = private_module->private_display; func_output = &private_module->func_output; if (!func_output->output_commit) { @@ -1343,10 +1446,44 @@ tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handl /* LCOV_EXCL_STOP */ } + if (private_module == private_display->virtual_module) { + if (!private_output->private_voutput) { + TDM_ERR("virtual module but don't have voutput"); + free(output_commit_handler); + return TDM_ERROR_BAD_MODULE; + } + private_voutput = private_output->private_voutput; + + if (!private_voutput->regist_commit_cb) { + private_voutput->regist_commit_cb = 1; + ret = tdm_voutput_set_commit_func(private_voutput, _tdm_voutput_cb_commit); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); + } + + voutput_commit_handler = calloc(1, sizeof(tdm_private_voutput_commit_handler)); + if (!voutput_commit_handler) { + /* LCOV_EXCL_START */ + TDM_ERR("failed: alloc memory"); + free(output_commit_handler); + return TDM_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + ret = tdm_thread_cb_add(private_output->private_voutput, TDM_THREAD_CB_VOUTPUT_COMMIT, voutput_commit_handler, _tdm_voutput_thread_cb_commit, NULL); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("tdm_thread_cb_add failed"); + free(voutput_commit_handler); + free(output_commit_handler); + return ret; + } + } + ret = tdm_thread_cb_add(private_output, TDM_THREAD_CB_OUTPUT_COMMIT, output_commit_handler, _tdm_output_thread_cb_commit, NULL); if (ret != TDM_ERROR_NONE) { TDM_ERR("tdm_thread_cb_add failed"); free(output_commit_handler); + if (voutput_commit_handler) + free(voutput_commit_handler); return ret; } @@ -1356,6 +1493,19 @@ tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handl output_commit_handler->user_data = user_data; output_commit_handler->owner_tid = syscall(SYS_gettid); + if (voutput_commit_handler) { + /* voutput use only 1 layer */ + LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { + if (private_layer) break; + } + + LIST_ADDTAIL(&voutput_commit_handler->link, &private_voutput->voutput_commit_handler_list); + voutput_commit_handler->private_voutput = private_voutput; + voutput_commit_handler->func = _voutput_commit_func; + voutput_commit_handler->user_data = private_layer->commiting_buffer; + voutput_commit_handler->owner_tid = syscall(SYS_gettid); + } + ret = func_output->output_commit(private_output->output_backend, sync, output_commit_handler); TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed); @@ -1383,6 +1533,7 @@ tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handl private_layer->committed_buffer = private_layer->waiting_buffer; private_layer->waiting_buffer = NULL; + private_layer->commiting_buffer = NULL; if (tdm_debug_module & TDM_DEBUG_BUFFER) TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)", private_layer, private_layer->waiting_buffer, @@ -1404,6 +1555,11 @@ commit_failed: LIST_DEL(&output_commit_handler->link); free(output_commit_handler); } + if (voutput_commit_handler) { + tdm_thread_cb_remove(private_output->private_voutput, TDM_THREAD_CB_VOUTPUT_COMMIT, voutput_commit_handler, _tdm_voutput_thread_cb_commit, NULL); + LIST_DEL(&voutput_commit_handler->link); + free(voutput_commit_handler); + } return ret; /* LCOV_EXCL_STOP */ } @@ -2071,3 +2227,59 @@ tdm_voutput_disconnect(tdm_voutput *voutput) return ret; } + +/* LCOV_EXCL_START */ +INTERN tdm_error +tdm_voutput_set_commit_func(tdm_voutput *voutput, tdm_voutput_commit_handler func) +{ + 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); + + func_voutput = &private_module->func_voutput; + if (func_voutput->voutput_set_commit_func) + ret = func_voutput->voutput_set_commit_func(private_voutput->voutput_backend, func); + else + ret = TDM_ERROR_NOT_IMPLEMENTED; + + return ret; +} + +INTERN tdm_error +tdm_voutput_commit_done(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_commit_done) + ret = func_voutput->voutput_commit_done(private_voutput->voutput_backend); + else + ret = TDM_ERROR_NOT_IMPLEMENTED; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} +/* LCOV_EXCL_STOP */ diff --git a/src/tdm_server.c b/src/tdm_server.c index d035a1d..d1619d9 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -89,6 +89,10 @@ typedef struct _tdm_server_voutput_info { 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 { @@ -828,13 +832,34 @@ _tdm_voutput_cb_disconnect(struct wl_client *client, struct wl_resource *resourc voutput_info->mmwidth = 0; voutput_info->mmheight = 0; + if (voutput_info->attach_buffer) { + tbm_surface_h buffer = voutput_info->attach_buffer->buffer; + tbm_surface_internal_unref(buffer); + voutput_info->committing = 0; + voutput_info->attach_buffer = NULL; + } + tdm_voutput_disconnect(voutput_info->voutput); } static void _tdm_voutput_cb_commit_done(struct wl_client *client, struct wl_resource *resource) { - /* TODO */ + tdm_server_voutput_info *voutput_info; + tbm_surface_h buffer; + + voutput_info = wl_resource_get_user_data(resource); + if (voutput_info->status != TDM_OUTPUT_CONN_STATUS_CONNECTED) { + TDM_DBG("not connected."); + return; + } + + buffer = voutput_info->attach_buffer->buffer; + tbm_surface_internal_unref(buffer); + voutput_info->committing = 0; + voutput_info->attach_buffer = NULL; + + tdm_voutput_commit_done(voutput_info->voutput); } static const struct wl_tdm_voutput_interface tdm_voutput_implementation = { @@ -847,10 +872,274 @@ static const struct wl_tdm_voutput_interface tdm_voutput_implementation = { _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, *vbb = 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_SAFE(vb, vbb, &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); + LIST_DEL(&vb->link); + 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) { + tbm_surface_internal_ref(vb->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_buffer->link, &voutput_info->buffer_list); + + return voutput_buffer; +} + +tdm_error +tdm_voutput_attach_buffer(tdm_voutput *voutput, 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->voutput == voutput) { + 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; +} + +tdm_error +tdm_voutput_commit_buffer(tdm_voutput *voutput) +{ + 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->voutput == voutput) { + 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); + + tbm_surface_internal_ref(voutput_info->attach_buffer->buffer); + 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; tdm_voutput *voutput; tdm_error ret = TDM_ERROR_NONE; @@ -863,6 +1152,20 @@ tdm_voutput_cb_resource_destroy(struct wl_resource *resource) if (ret != TDM_ERROR_NONE) TDM_ERR("_tdm_voutput_cb_destroy fail"); + if (voutput_info->attach_buffer) { + tbm_surface_h buffer = voutput_info->attach_buffer->buffer; + tbm_surface_internal_unref(buffer); + voutput_info->committing = 0; + voutput_info->attach_buffer = NULL; + } + + LIST_FOR_EACH_ENTRY(vb, &voutput_info->buffer_list, link) { + if (!vb) continue; + + if (vb->wl_buffer) + wl_resource_destroy(vb->wl_buffer); + } + LIST_DEL(&voutput_info->link); /* Do free your own resource */ @@ -933,6 +1236,7 @@ _tdm_server_cb_create_virtual_output(struct wl_client *client, struct wl_resourc voutput_info->resource = voutput_resource; voutput_info->voutput = voutput; voutput_info->output = output; + LIST_INITHEAD(&voutput_info->buffer_list); wl_resource_set_implementation(voutput_resource, &tdm_voutput_implementation, diff --git a/src/tdm_thread.c b/src/tdm_thread.c index d367d4e..40d7859 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -462,6 +462,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) case TDM_THREAD_CB_VBLANK_SW: case TDM_THREAD_CB_VBLANK_CREATE: case TDM_THREAD_CB_HWC_COMMIT: + case TDM_THREAD_CB_VOUTPUT_COMMIT: /* this event comes from other thread. so we don't need to propagate this to other thread */ ret = tdm_thread_cb_call(NULL, base, 0); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); -- 2.7.4