From 954bff7eca6dc25684bd830c128cfe8fe24de96b Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 23 Nov 2016 13:16:44 +0900 Subject: [PATCH 01/16] check capture capability Change-Id: If3db8bd96f960ddf5ddd8d22f9e9a8ea20ecdc58 --- src/tdm.c | 6 ++++-- src/tdm_capture.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/tdm.c b/src/tdm.c index 4918a22..5d2714c 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -726,8 +726,10 @@ _tdm_display_check_backend_functions(tdm_private_display *private_display) if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) { tdm_func_capture *func_capture = &private_display->func_capture; TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE); - TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE); - TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE); + if (private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT) + TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE); + if (private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_LAYER) + TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE); diff --git a/src/tdm_capture.c b/src/tdm_capture.c index da1a0e5..798f738 100644 --- a/src/tdm_capture.c +++ b/src/tdm_capture.c @@ -164,6 +164,13 @@ tdm_capture_create_output_internal(tdm_private_output *private_output, return NULL; } + if (!(private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT)) { + TDM_ERR("no output capture capability"); + if (error) + *error = TDM_ERROR_NO_CAPABILITY; + return NULL; + } + capture_backend = func_output->output_create_capture( private_output->output_backend, &ret); if (ret != TDM_ERROR_NONE) { @@ -235,6 +242,13 @@ tdm_capture_create_layer_internal(tdm_private_layer *private_layer, return NULL; } + if (!(private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_LAYER)) { + TDM_ERR("no layer capture capability"); + if (error) + *error = TDM_ERROR_NO_CAPABILITY; + return NULL; + } + capture_backend = func_layer->layer_create_capture(private_layer->layer_backend, &ret); if (ret != TDM_ERROR_NONE) -- 2.7.4 From 9ca1c88f3d4353a73f54b560cc4a7015ddcb1be4 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 23 Nov 2016 15:56:00 +0900 Subject: [PATCH 02/16] remove unused helper function Change-Id: I4e996c26aaab61adb0ae10969b39c8871f28296c --- include/tdm_helper.h | 50 --------------- src/tdm_display.c | 25 -------- src/tdm_helper.c | 173 --------------------------------------------------- 3 files changed, 248 deletions(-) diff --git a/include/tdm_helper.h b/include/tdm_helper.h index 459b1b1..3e4459c 100644 --- a/include/tdm_helper.h +++ b/include/tdm_helper.h @@ -120,56 +120,6 @@ int tdm_helper_get_fd(const char *env); void tdm_helper_set_fd(const char *env, int fd); /** - * @brief Start the dump debugging. - * @details - * Start tdm dump. - * Make dump file when tdm_layer_set_buffer() function is called. - * Set the dump count to 1. - * @param[in] dumppath The given dump path - * @param[in] count The dump count number - * @see #tdm_helper_dump_stop() - */ -void -tdm_helper_dump_start(char *dumppath, int *count); - -/** - * @brief Stop the dump debugging. - * @details - * Stop tdm dump. - * Set the dump count to 0. - * @see #tdm_helper_dump_start() - */ -void -tdm_helper_dump_stop(void); - -/** - * @brief The tdm helper capture handler - * @details - * This handler will be called when composit image produced. - * @see #tdm_helper_capture_output() function - */ -typedef void (*tdm_helper_capture_handler)(tbm_surface_h buffer, void *user_data); - -/** - * @brief Make an output's image surface. - * @details Composit specific output's all layer's buffer to dst_buffer surface. - * After composing, tdm_helper_capture_handler func will be called. - * @param[in] output A output object - * @param[in] dst_buffer A surface composite image saved - * @param[in] x A horizontal position of composite image on dst_buffer - * @param[in] y A vertical position of composite image on dst_buffer - * @param[in] w A composite image width - * @param[in] h A composite image height - * @param[in] func A composing done handler - * @param[in] user_data The user data - * @return #TDM_ERROR_NONE if success. Otherwise, error value. - */ -tdm_error -tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer, - int x, int y, int w, int h, - tdm_helper_capture_handler func, void *data); - -/** * @brief Fill the display information to the reply buffer as string. * @param[in] dpy A display object * @param[out] reply the string buffer to be filled by this function. diff --git a/src/tdm_display.c b/src/tdm_display.c index a34daab..8d0cdd2 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -40,7 +40,6 @@ #include "tdm.h" #include "tdm_backend.h" #include "tdm_private.h" -#include "tdm_helper.h" #define COUNT_MAX 10 @@ -1597,26 +1596,6 @@ tdm_layer_get_info(tdm_layer *layer, tdm_info_layer *info) return ret; } -static void -_tdm_layer_dump_buffer(tdm_layer *layer, tbm_surface_h buffer) -{ - tdm_private_layer *private_layer = (tdm_private_layer*)layer; - tdm_private_output *private_output = private_layer->private_output; - unsigned int pipe; - int zpos; - char fname[PATH_MAX]; - - pipe = private_output->pipe; - zpos = private_layer->caps.zpos; - - snprintf(fname, sizeof(fname), "tdm_%d_lyr_%d", pipe, zpos); - - tbm_surface_internal_dump_buffer(buffer, fname); - TDM_DBG("%s dump excute", fname); - - return; -} - EXTERN tdm_error tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) { @@ -1653,10 +1632,6 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) ret = func_layer->layer_set_buffer(private_layer->layer_backend, buffer); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - /* dump buffer */ - if (tdm_dump_enable && !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) - _tdm_layer_dump_buffer(layer, buffer); - if (ret == TDM_ERROR_NONE) { /* FIXME: should save to pending_buffer first. And after committing * successfully, need to move to waiting_buffer. diff --git a/src/tdm_helper.c b/src/tdm_helper.c index f5e39b3..f2fce58 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -398,179 +398,6 @@ tdm_helper_set_fd(const char *env, int fd) } EXTERN void -tdm_helper_dump_start(char *dumppath, int *count) -{ - if (dumppath == NULL || count == NULL) { - TDM_DBG("tdm_helper_dump dumppath or count is null."); - return; - } - - tdm_dump_enable = 1; - - TDM_DBG("tdm_helper_dump start.(path : %s)", dumppath); -} - -EXTERN void -tdm_helper_dump_stop(void) -{ - tdm_dump_enable = 0; - - TDM_DBG("tdm_helper_dump stop."); -} - -static pixman_format_code_t -_tdm_helper_pixman_format_get(tbm_format format) -{ - switch (format) { - case TBM_FORMAT_ARGB8888: - return PIXMAN_a8r8g8b8; - case TBM_FORMAT_XRGB8888: - return PIXMAN_x8r8g8b8; - default: - return 0; - } - - return 0; -} - -static tdm_error -_tdm_helper_buffer_convert(tbm_surface_h srcbuf, tbm_surface_h dstbuf, - int dx, int dy, int dw, int dh, int count) -{ - pixman_image_t *src_img = NULL, *dst_img = NULL; - pixman_format_code_t src_format, dst_format; - pixman_transform_t t; - struct pixman_f_transform ft; - pixman_op_t op; - tbm_surface_info_s src_info = {0, }; - tbm_surface_info_s dst_info = {0, }; - int stride, width; - double scale_x, scale_y; - - TDM_RETURN_VAL_IF_FAIL(srcbuf != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(dstbuf != NULL, TDM_ERROR_INVALID_PARAMETER); - - if (tbm_surface_map(srcbuf, TBM_SURF_OPTION_READ, &src_info) - != TBM_SURFACE_ERROR_NONE) { - TDM_ERR("cannot mmap srcbuf\n"); - return TDM_ERROR_OPERATION_FAILED; - } - - if (tbm_surface_map(dstbuf, TBM_SURF_OPTION_WRITE, &dst_info) - != TBM_SURFACE_ERROR_NONE) { - TDM_ERR("cannot mmap dstbuf\n"); - tbm_surface_unmap(srcbuf); - return TDM_ERROR_OPERATION_FAILED; - } - TDM_GOTO_IF_FAIL(src_info.num_planes == 1, cant_convert); - TDM_GOTO_IF_FAIL(dst_info.num_planes == 1, cant_convert); - - /* src */ - src_format = _tdm_helper_pixman_format_get(src_info.format); - TDM_GOTO_IF_FAIL(src_format > 0, cant_convert); - - width = src_info.planes[0].stride / 4; - stride = src_info.planes[0].stride; - src_img = pixman_image_create_bits(src_format, width, src_info.height, - (uint32_t*)src_info.planes[0].ptr, stride); - TDM_GOTO_IF_FAIL(src_img != NULL, cant_convert); - - /* dst */ - dst_format = _tdm_helper_pixman_format_get(dst_info.format); - TDM_GOTO_IF_FAIL(dst_format > 0, cant_convert); - - width = dst_info.planes[0].stride / 4; - stride = dst_info.planes[0].stride; - dst_img = pixman_image_create_bits(dst_format, width, dst_info.height, - (uint32_t*)dst_info.planes[0].ptr, stride); - TDM_GOTO_IF_FAIL(dst_img != NULL, cant_convert); - - pixman_f_transform_init_identity(&ft); - - scale_x = (double)src_info.width / dw; - scale_y = (double)src_info.height / dh; - - pixman_f_transform_scale(&ft, NULL, scale_x, scale_y); - pixman_f_transform_translate(&ft, NULL, 0, 0); - pixman_transform_from_pixman_f_transform(&t, &ft); - pixman_image_set_transform(src_img, &t); - - if (count == 0) - op = PIXMAN_OP_SRC; - else - op = PIXMAN_OP_OVER; - - pixman_image_composite(op, src_img, NULL, dst_img, - 0, 0, 0, 0, dx, dy, dw, dh); - - if (src_img) - pixman_image_unref(src_img); - if (dst_img) - pixman_image_unref(dst_img); - - tbm_surface_unmap(srcbuf); - tbm_surface_unmap(dstbuf); - - return TDM_ERROR_NONE; - -cant_convert: - if (src_img) - pixman_image_unref(src_img); - - tbm_surface_unmap(srcbuf); - tbm_surface_unmap(dstbuf); - - return TDM_ERROR_OPERATION_FAILED; -} - -EXTERN tdm_error -tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer, - int x, int y, int w, int h, - tdm_helper_capture_handler func, void *data) -{ - tbm_surface_h surface; - tdm_error err; - int i, count, first = 0; - - TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(dst_buffer != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(x >= 0, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(y >= 0, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(w >= 0, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(h >= 0, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(data != NULL, TDM_ERROR_INVALID_PARAMETER); - - err = tdm_output_get_layer_count(output, &count); - if (err != TDM_ERROR_NONE) { - TDM_ERR("tdm_output_get_layer_count fail(%d)\n", err); - return TDM_ERROR_OPERATION_FAILED; - } - if (count <= 0) { - TDM_ERR("tdm_output_get_layer_count err(%d, %d)\n", err, count); - return TDM_ERROR_BAD_MODULE; - } - - for (i = count - 1; i >= 0; i--) { - tdm_layer *layer = tdm_output_get_layer(output, i, NULL); - - surface = tdm_layer_get_displaying_buffer(layer, &err); - if (err != TDM_ERROR_NONE) - continue; - - err = _tdm_helper_buffer_convert(surface, dst_buffer, x, y, w, h, first++); - if (err != TDM_ERROR_NONE) - TDM_DBG("convert fail %d-layer buffer\n", i); - else - TDM_DBG("convert success %d-layer buffer\n", i); - } - - func(dst_buffer, data); - - return TDM_ERROR_NONE; -} - -EXTERN void tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len) { tdm_private_display *private_display; -- 2.7.4 From c1fc4ce4dcdae191b3f90f5237168af67910da1c Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 24 Nov 2016 12:15:05 +0900 Subject: [PATCH 03/16] test the only connected output Change-Id: I482ee9f9dd0e92094cf2e9998adf9ff381f1721f --- tools/tdm_test_server.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/tdm_test_server.c b/tools/tdm_test_server.c index b948a96..e7ee525 100644 --- a/tools/tdm_test_server.c +++ b/tools/tdm_test_server.c @@ -630,6 +630,11 @@ interpret_args(tdm_test_server *data) TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); for (i = 0; i < output_count; i++) { + tdm_output *output = tdm_display_get_output(data->display, i, NULL); + tdm_output_conn_status status; + tdm_output_get_conn_status(output, &status); + if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) + continue; o = calloc(1, sizeof * o); TDM_EXIT_IF_FAIL(o != NULL); o->data = data; -- 2.7.4 From cde7f5a554815a93f1b2503e271d266f13e0305a Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 24 Nov 2016 12:16:37 +0900 Subject: [PATCH 04/16] add punch option to tdm-monitor Change-Id: Ib70965942ed775a421a9465ab3e9f2b38ff40a3e --- include/tdm_helper.h | 17 +++++++++++++ src/tdm_helper.c | 26 +++++++++++++++++--- src/tdm_monitor_server.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 3 deletions(-) diff --git a/include/tdm_helper.h b/include/tdm_helper.h index 3e4459c..3de7da3 100644 --- a/include/tdm_helper.h +++ b/include/tdm_helper.h @@ -76,6 +76,23 @@ void tdm_helper_dump_buffer(tbm_surface_h buffer, const char *file); /** + * @brief fill a buffer with 0 for given pos. + * @details + * This function supports only if a buffer has below formats. + * - TBM_FORMAT_ARGB8888 + * - TBM_FORMAT_XRGB8888 + * - TBM_FORMAT_YVU420 + * - TBM_FORMAT_YUV420 + * - TBM_FORMAT_NV12 + * - TBM_FORMAT_NV21 + * - TBM_FORMAT_YUYV + * - TBM_FORMAT_UYVY + * @param[in] buffer A TDM buffer + */ +void +tdm_helper_clear_buffer_pos(tbm_surface_h buffer, tdm_pos *pos); + +/** * @brief fill a buffer with 0. * @details * This function supports only if a buffer has below formats. diff --git a/src/tdm_helper.c b/src/tdm_helper.c index f2fce58..3e4af9d 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -293,8 +293,8 @@ tdm_helper_dump_buffer(tbm_surface_h buffer, const char *file) TDM_INFO("dump %s", file); } -EXTERN void -tdm_helper_clear_buffer(tbm_surface_h buffer) +void +tdm_helper_clear_buffer_pos(tbm_surface_h buffer, tdm_pos *pos) { tbm_surface_info_s info; int ret; @@ -307,7 +307,19 @@ tdm_helper_clear_buffer(tbm_surface_h buffer) switch (info.format) { case TBM_FORMAT_ARGB8888: case TBM_FORMAT_XRGB8888: - memset(info.planes[0].ptr, 0, info.planes[0].stride * info.height); + if (!pos) { + memset(info.planes[0].ptr, 0, info.planes[0].stride * info.height); + } else { + unsigned char *p; + int x, y; + for (y = pos->y; y <= (pos->y + pos->h); y++) { + p = info.planes[0].ptr + info.planes[0].stride * y; + for (x = pos->x; x <= (pos->x + pos->w); x++) { + int *ibuf = (int*)p; + ibuf[x] = 0x00000000; + } + } + } break; case TBM_FORMAT_YVU420: case TBM_FORMAT_YUV420: @@ -344,6 +356,14 @@ tdm_helper_clear_buffer(tbm_surface_h buffer) tbm_surface_unmap(buffer); } +EXTERN void +tdm_helper_clear_buffer(tbm_surface_h buffer) +{ + TDM_RETURN_IF_FAIL(buffer != NULL); + + tdm_helper_clear_buffer_pos(buffer, NULL); +} + EXTERN int tdm_helper_get_fd(const char *env) { diff --git a/src/tdm_monitor_server.c b/src/tdm_monitor_server.c index 4ea1184..2a1b318 100644 --- a/src/tdm_monitor_server.c +++ b/src/tdm_monitor_server.c @@ -304,6 +304,64 @@ _tdm_monitor_server_dump(unsigned int pid, char *cwd, int argc, char *argv[], ch tdm_display_enable_dump(dpy, (const char*)argv[2], reply, len); } +static void +_tdm_monitor_server_punch(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy) +{ + char *arg, *end; + unsigned int output_id, layer_id; + tdm_output *output; + tdm_layer *layer; + tbm_surface_h buffer; + + arg = argv[2]; + + output_id = strtol(arg, &end, 10); + output = tdm_display_get_output(dpy, output_id, NULL); + if (!output) { + TDM_SNPRINTF(reply, len, "not found output\n"); + return; + } + if (*end != ',') { + TDM_SNPRINTF(reply, len, "not found ','\n"); + return; + } + + arg = end + 1; + layer_id = strtol(arg, &end, 10); + layer = tdm_output_get_layer(output, layer_id, NULL); + if (!layer) { + TDM_SNPRINTF(reply, len, "not found layer\n"); + return; + } + + buffer = tdm_layer_get_displaying_buffer(layer, NULL); + if (!buffer) { + TDM_SNPRINTF(reply, len, "not found buffer\n"); + return; + } + + if (*end == ':') { + tdm_pos pos = {0,}; + + arg = end + 1; + pos.w = strtol(arg, &end, 10); + TDM_EXIT_IF_FAIL(*end == 'x'); + arg = end + 1; + pos.h = strtol(arg, &end, 10); + if (*end == '+') { + arg = end + 1; + pos.x = strtol(arg, &end, 10); + TDM_EXIT_IF_FAIL(*end == '+'); + arg = end + 1; + pos.y = strtol(arg, &end, 10); + } + + tdm_helper_clear_buffer_pos(buffer, &pos); + } + else + tdm_helper_clear_buffer(buffer); +} + static struct { const char *opt; void (*func)(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy); @@ -351,6 +409,12 @@ static struct { "[,[,...]][@]", NULL }, + { + "punch", _tdm_monitor_server_punch, + "punch a layer", + ",[:x[++]]", + NULL + }, }; static void -- 2.7.4 From 64c5c785d86c48dcd94ae43a1976f494ef979c13 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 24 Nov 2016 12:19:30 +0900 Subject: [PATCH 05/16] add tdm_helper_convert_buffer function Change-Id: I4c63d1e3546194229daf19f4a59444b96a33f46c --- include/tdm_helper.h | 14 ++++++ src/tdm_helper.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/include/tdm_helper.h b/include/tdm_helper.h index 3de7da3..a6791aa 100644 --- a/include/tdm_helper.h +++ b/include/tdm_helper.h @@ -110,6 +110,20 @@ void tdm_helper_clear_buffer(tbm_surface_h buffer); /** + * @brief convert the source buffer to the destination buffer with given rectangles + * trannsform + * @details + * This function supports only if buffers have below formats. + * - TBM_FORMAT_ARGB8888 + * - TBM_FORMAT_XRGB8888 + * @param[in] buffer A TDM buffer + */ +tdm_error +tdm_helper_convert_buffer(tbm_surface_h srcbuf, tbm_surface_h dstbuf, + tdm_pos *srcpos, tdm_pos *dstpos, + tdm_transform transform, int over); + +/** * @brief Get a fd from the given enviroment variable. * @details * This function will dup the fd of the given enviroment variable. The Caller diff --git a/src/tdm_helper.c b/src/tdm_helper.c index 3e4af9d..e91033e 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -364,6 +364,134 @@ tdm_helper_clear_buffer(tbm_surface_h buffer) tdm_helper_clear_buffer_pos(buffer, NULL); } +static pixman_format_code_t +_tdm_helper_pixman_format_get(tbm_format format) +{ + switch (format) { + case TBM_FORMAT_ARGB8888: + return PIXMAN_a8r8g8b8; + case TBM_FORMAT_XRGB8888: + return PIXMAN_x8r8g8b8; + default: + return 0; + } + + return 0; +} + +EXTERN tdm_error +tdm_helper_convert_buffer(tbm_surface_h srcbuf, tbm_surface_h dstbuf, + tdm_pos *srcpos, tdm_pos *dstpos, + tdm_transform transform, int over) +{ + tbm_surface_info_s src_info, dst_info; + pixman_image_t *src_img = NULL, *dst_img = NULL; + pixman_format_code_t src_format, dst_format; + double scale_x, scale_y; + int rotate_step, bos; + pixman_transform_t t; + struct pixman_f_transform ft; + pixman_op_t op; + int src_stride, dst_stride; + int buf_width, err; + tdm_error ret = TDM_ERROR_OPERATION_FAILED; + + TDM_RETURN_VAL_IF_FAIL(srcbuf != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(dstbuf != NULL, TDM_ERROR_INVALID_PARAMETER); + + bos = tbm_surface_internal_get_num_bos(srcbuf); + TDM_RETURN_VAL_IF_FAIL(bos == 1, TDM_ERROR_OPERATION_FAILED); + + bos = tbm_surface_internal_get_num_bos(dstbuf); + TDM_RETURN_VAL_IF_FAIL(bos == 1, TDM_ERROR_OPERATION_FAILED); + + err = tbm_surface_map(srcbuf, TBM_OPTION_READ, &src_info); + TDM_RETURN_VAL_IF_FAIL(err == TBM_SURFACE_ERROR_NONE, TDM_ERROR_OPERATION_FAILED); + + err = tbm_surface_map(dstbuf, TBM_OPTION_WRITE, &dst_info); + TDM_GOTO_IF_FAIL(err == TBM_SURFACE_ERROR_NONE, unmap_srcbuf); + + /* not handle buffers which have 2 more gem handles */ + TDM_GOTO_IF_FAIL(src_info.planes[0].ptr != NULL, unmap_dstbuf); + TDM_GOTO_IF_FAIL(dst_info.planes[0].ptr != NULL, unmap_dstbuf); + + src_format = _tdm_helper_pixman_format_get(src_info.format); + TDM_GOTO_IF_FAIL(src_format > 0, unmap_dstbuf); + dst_format = _tdm_helper_pixman_format_get(dst_info.format); + TDM_GOTO_IF_FAIL(dst_format > 0, unmap_dstbuf); + + buf_width = src_info.planes[0].stride >> 2; + src_stride = src_info.planes[0].stride; + src_img = pixman_image_create_bits(src_format, buf_width, src_info.height, + (uint32_t*)src_info.planes[0].ptr, src_stride); + TDM_GOTO_IF_FAIL(src_img, unref_img); + + buf_width = dst_info.planes[0].stride >> 2; + dst_stride = dst_info.planes[0].stride; + dst_img = pixman_image_create_bits(dst_format, buf_width, dst_info.height, + (uint32_t*)dst_info.planes[0].ptr, dst_stride); + TDM_GOTO_IF_FAIL(dst_img, unref_img); + + pixman_f_transform_init_identity(&ft); + + if (transform & TDM_TRANSFORM_FLIPPED) { + pixman_f_transform_scale(&ft, NULL, -1, 1); + pixman_f_transform_translate(&ft, NULL, dstpos->w, 0); + } + + rotate_step = transform & 0x3; + if (rotate_step > 0) { + int c, s, tx = 0, ty = 0; + switch (rotate_step) { + case 1: + c = 0, s = -1, tx = -dstpos->w; + break; + case 2: + c = -1, s = 0, tx = -dstpos->w, ty = -dstpos->h; + break; + case 3: + c = 0, s = 1, ty = -dstpos->h; + break; + default: + break; + } + pixman_f_transform_translate(&ft, NULL, tx, ty); + pixman_f_transform_rotate(&ft, NULL, c, s); + } + + if (rotate_step % 2 == 0) { + scale_x = (double)srcpos->w / dstpos->w; + scale_y = (double)srcpos->h / dstpos->h; + } else { + scale_x = (double)srcpos->w / dstpos->h; + scale_y = (double)srcpos->h / dstpos->w; + } + + pixman_f_transform_scale(&ft, NULL, scale_x, scale_y); + pixman_f_transform_translate(&ft, NULL, srcpos->x, srcpos->y); + pixman_transform_from_pixman_f_transform(&t, &ft); + pixman_image_set_transform(src_img, &t); + + op = (!over) ? PIXMAN_OP_SRC : PIXMAN_OP_OVER; + + pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0, + dstpos->x, dstpos->y, dstpos->w, dstpos->h); + + ret = TDM_ERROR_NONE; + +unref_img: + if (src_img) + pixman_image_unref(src_img); + if (dst_img) + pixman_image_unref(dst_img); +unmap_dstbuf: + tbm_surface_unmap(dstbuf); +unmap_srcbuf: + tbm_surface_unmap(srcbuf); + + return ret; +} + EXTERN int tdm_helper_get_fd(const char *env) { -- 2.7.4 From 275554e2a5425632bf0032adadbfe4df85192afa Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 24 Nov 2016 19:10:13 +0900 Subject: [PATCH 06/16] use mutex for printf output in multithread Change-Id: I6f903828f1e22f7c3dfed074173f9e5e78636011 --- common/tdm_log.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/common/tdm_log.c b/common/tdm_log.c index 5e1ab2c..fc1a8f1 100644 --- a/common/tdm_log.c +++ b/common/tdm_log.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "tdm.h" #include "tdm_log.h" @@ -66,6 +67,9 @@ static unsigned int debug_level = TDM_LOG_LEVEL_INFO; static unsigned int need_check_env = 1; +static unsigned int log_lock_init; +static pthread_mutex_t log_lock; + static void _tdm_log_check_env(void) { @@ -117,6 +121,12 @@ tdm_log_print(int level, const char *fmt, ...) { va_list arg; + if (!log_lock_init) { + log_lock_init = 1; + pthread_mutex_init(&log_lock, NULL); + + } + if (need_check_env) { need_check_env = 0; _tdm_log_check_env(); @@ -153,6 +163,8 @@ tdm_log_print(int level, const char *fmt, ...) clock_gettime(CLOCK_MONOTONIC, &ts); + pthread_mutex_lock(&log_lock); + if (color_enable) printf("%s", color[level]); printf("[%s]", lvl_str[level]); @@ -162,6 +174,8 @@ tdm_log_print(int level, const char *fmt, ...) va_start(arg, fmt); vprintf(fmt, arg); va_end(arg); + + pthread_mutex_unlock(&log_lock); } #ifdef TDM_CONFIG_ASSERT -- 2.7.4 From 6c0cfe32df0a4b601be5cc7be31cfa26be54e897 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 24 Nov 2016 19:10:42 +0900 Subject: [PATCH 07/16] fix wrong format Change-Id: I401e6642b25f8f7b5abfaed046fa1154071ec489 --- src/tdm_thread.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tdm_thread.c b/src/tdm_thread.c index 955c9b4..4659740 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -285,7 +285,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) tdm_output *output_backend = tdm_display_find_output_stamp(private_loop->dpy, output_commit->output_stamp); if (!output_backend) { - TDM_WRN("no output(%ld)", output_commit->output_stamp); + TDM_WRN("no output(%f)", output_commit->output_stamp); break; } tdm_output_cb_commit(output_backend, output_commit->sequence, @@ -298,7 +298,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) tdm_output *output_backend = tdm_display_find_output_stamp(private_loop->dpy, output_vblank->output_stamp); if (!output_backend) { - TDM_WRN("no output(%ld)", output_vblank->output_stamp); + TDM_WRN("no output(%f)", output_vblank->output_stamp); break; } tdm_output_cb_vblank(output_backend, output_vblank->sequence, @@ -311,7 +311,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) tdm_output *output_backend = tdm_display_find_output_stamp(private_loop->dpy, output_status->output_stamp); if (!output_backend) { - TDM_WRN("no output(%ld)", output_status->output_stamp); + TDM_WRN("no output(%f)", output_status->output_stamp); break; } tdm_output_cb_status(output_backend, output_status->status, @@ -323,7 +323,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) tdm_output *output_backend = tdm_display_find_output_stamp(private_loop->dpy, output_dpms->output_stamp); if (!output_backend) { - TDM_WRN("no output(%ld)", output_dpms->output_stamp); + TDM_WRN("no output(%f)", output_dpms->output_stamp); break; } tdm_output_cb_dpms(output_backend, output_dpms->dpms, output_dpms->user_data); @@ -334,7 +334,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) tdm_pp *pp_backend = tdm_pp_find_stamp(private_loop->dpy, pp_done->pp_stamp); if (!pp_backend) { - TDM_WRN("no pp(%ld)", pp_done->pp_stamp); + TDM_WRN("no pp(%f)", pp_done->pp_stamp); break; } tdm_pp_cb_done(pp_backend, pp_done->src, pp_done->dst, pp_done->user_data); @@ -345,7 +345,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) tdm_capture *capture_backend = tdm_capture_find_stamp(private_loop->dpy, capture_done->capture_stamp); if (!capture_backend) { - TDM_WRN("no capture(%ld)", capture_done->capture_stamp); + TDM_WRN("no capture(%f)", capture_done->capture_stamp); break; } tdm_capture_cb_done(capture_backend, capture_done->buffer, capture_done->user_data); -- 2.7.4 From c05870c98be7aa62ae8dbd81f4b64a5ffd637ec6 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 24 Nov 2016 19:41:46 +0900 Subject: [PATCH 08/16] fix memory leak Change-Id: Ia9795dc72428e976af48f789ab288abf7a0149c2 --- src/tdm_pp.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/tdm_pp.c b/src/tdm_pp.c index 1a61d7f..93b7879 100644 --- a/src/tdm_pp.c +++ b/src/tdm_pp.c @@ -266,6 +266,11 @@ tdm_pp_destroy_internal(tdm_private_pp *private_pp) LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->pending_buffer_list, link) { LIST_DEL(&b->link); + _pthread_mutex_unlock(&private_display->lock); + tdm_buffer_unref_backend(b->src); + tdm_buffer_unref_backend(b->dst); + _pthread_mutex_lock(&private_display->lock); + free(b); } } @@ -279,6 +284,7 @@ tdm_pp_destroy_internal(tdm_private_pp *private_pp) tdm_buffer_unref_backend(b->src); tdm_buffer_unref_backend(b->dst); _pthread_mutex_lock(&private_display->lock); + free(b); } } @@ -458,12 +464,17 @@ tdm_pp_commit(tdm_pp *pp) TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); LIST_FOR_EACH_ENTRY_SAFE(b, bb, &commit_buffer_list, commit_link) { + LIST_DEL(&b->commit_link); + if (!_tdm_pp_find_buffer(&private_pp->buffer_list, b)) continue; - LIST_DEL(&b->commit_link); - if (ret != TDM_ERROR_NONE) { + /* Not to call the user release handler when failed. + * Do we have to call this function here really? + * User better use set_done_handler to know when pp is done. Using + * buffer_release_handler is not good. + */ tdm_buffer_remove_release_handler_internal(b->src); tdm_buffer_remove_release_handler_internal(b->dst); -- 2.7.4 From 885404c5e083b39778a939a6b131294d176d7564 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 24 Nov 2016 19:40:35 +0900 Subject: [PATCH 09/16] change tdm capture capbility scale & transform seem the default capability. remove it. tdm backend might support both oneshot and stream dump. And it's possible for backend to support stream dump only. Change-Id: I46b534c432dd15117658296d3eb427a9f004f3d9 --- include/tdm_common.h | 4 ++-- tools/tdm_test_server.c | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/tdm_common.h b/include/tdm_common.h index 1894505..3b9f5fa 100644 --- a/include/tdm_common.h +++ b/include/tdm_common.h @@ -143,8 +143,8 @@ typedef enum { typedef enum { TDM_CAPTURE_CAPABILITY_OUTPUT = (1 << 0), /**< The capture device supports to dump a output */ TDM_CAPTURE_CAPABILITY_LAYER = (1 << 1), /**< The capture device supports to dump a layer */ - TDM_CAPTURE_CAPABILITY_SCALE = (1 << 4), /**< The capture device supports scale operation */ - TDM_CAPTURE_CAPABILITY_TRANSFORM = (1 << 5), /**< The capture device supports transform operation */ + TDM_CAPTURE_CAPABILITY_ONESHOT = (1 << 4), /**< The capture device supports oneshot dump */ + TDM_CAPTURE_CAPABILITY_STREAM = (1 << 5), /**< The capture device supports streamp sump */ } tdm_capture_capability; /** diff --git a/tools/tdm_test_server.c b/tools/tdm_test_server.c index e7ee525..4ea6d11 100644 --- a/tools/tdm_test_server.c +++ b/tools/tdm_test_server.c @@ -105,7 +105,7 @@ static struct optstrings optstrs[] = { }, { OPT_TST, "c", "catpure a output object or a layer object.\n\t\t'-l' is used to show the result on screen.", - "[,]~x[++][,x][@][*]", NULL + "[,]~x[++][,x][@][*][^stream]", NULL }, { OPT_GEN, "w", "set the property of a object", @@ -421,6 +421,13 @@ parse_arg_c(tdm_test_server_capture *c, char *arg) arg = end + 1; capture_info->transform = strtol(arg, &end, 10); } + if (*end == '^') { + arg = end + 1; + if (strtol(arg, &end, 10) > 0) + capture_info->type = TDM_CAPTURE_TYPE_STREAM; + else + capture_info->type = TDM_CAPTURE_TYPE_ONESHOT; + } } static void -- 2.7.4 From b0e33fed70ca1fc25fec654350976ae0d1a3aa53 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 24 Nov 2016 19:42:18 +0900 Subject: [PATCH 10/16] correct capture behavior Change-Id: I9e3a7b4f8f612f7a507f1ceaecf05465d210676e --- src/tdm_buffer.c | 4 +- src/tdm_capture.c | 190 +++++++++++++++++++++++++++++++++++------------- src/tdm_pp.c | 2 +- src/tdm_private.h | 6 ++ tools/tdm_test_server.c | 55 +++++++------- 5 files changed, 177 insertions(+), 80 deletions(-) diff --git a/src/tdm_buffer.c b/src/tdm_buffer.c index f6a5aea..68ca444 100644 --- a/src/tdm_buffer.c +++ b/src/tdm_buffer.c @@ -215,8 +215,8 @@ tdm_buffer_unref_backend(tbm_surface_h buffer) return; } - if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) - TDM_NEVER_GET_HERE(); +// if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) +// TDM_NEVER_GET_HERE(); LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->release_funcs, link) { tbm_surface_internal_ref(buffer); diff --git a/src/tdm_capture.c b/src/tdm_capture.c index 798f738..c532754 100644 --- a/src/tdm_capture.c +++ b/src/tdm_capture.c @@ -52,27 +52,52 @@ private_display = private_capture->private_display; \ func_capture = &private_display->func_capture -static tdm_error -_tdm_capture_check_if_exist(tdm_private_capture *private_capture, - tbm_surface_h buffer) +static void +_tdm_capture_print_list(struct list_head *list) { - tdm_buffer_info *buf_info = NULL; + tdm_capture_private_buffer *b = NULL; + char str[512], *p; + int len = sizeof(str); + + TDM_RETURN_IF_FAIL(list != NULL); + + p = str; + LIST_FOR_EACH_ENTRY(b, list, link) { + if (len > 0) { + int l = snprintf(p, len, " (%p)", b->buffer); + p += l; + len -= l; + } else + break; + } - LIST_FOR_EACH_ENTRY(buf_info, &private_capture->buffer_list, link) { - if (buf_info->buffer == buffer) { - TDM_ERR("%p attached twice", buffer); - return TDM_ERROR_BAD_REQUEST; - } + TDM_INFO("\t %s", str); +} + +static tdm_capture_private_buffer * +_tdm_capture_find_tbm_buffer(struct list_head *list, tbm_surface_h buffer) +{ + tdm_capture_private_buffer *b = NULL, *bb = NULL; + + LIST_FOR_EACH_ENTRY_SAFE(b, bb, list, link) { + if (b->buffer == buffer) + return b; } - LIST_FOR_EACH_ENTRY(buf_info, &private_capture->pending_buffer_list, link) { - if (buf_info->buffer == buffer) { - TDM_ERR("%p attached twice", buffer); - return TDM_ERROR_BAD_REQUEST; - } + return NULL; +} + +static tdm_capture_private_buffer * +_tdm_capture_find_buffer(struct list_head *list, tdm_capture_private_buffer *capture_buffer) +{ + tdm_capture_private_buffer *b = NULL, *bb = NULL; + + LIST_FOR_EACH_ENTRY_SAFE(b, bb, list, link) { + if (b == capture_buffer) + return b; } - return TDM_ERROR_NONE; + return NULL; } INTERN void @@ -81,8 +106,7 @@ tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer, { tdm_private_capture *private_capture = user_data; tdm_private_display *private_display = private_capture->private_display; - tdm_buffer_info *buf_info; - tbm_surface_h first_entry; + tdm_capture_private_buffer *capture_buffer = NULL, *first_entry = NULL; TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); @@ -90,7 +114,7 @@ tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer, tdm_thread_cb_capture_done capture_done; tdm_error ret; - capture_done.base.type = TDM_THREAD_CB_PP_DONE; + capture_done.base.type = TDM_THREAD_CB_CAPTURE_DONE; capture_done.base.length = sizeof capture_done; capture_done.capture_stamp = private_capture->stamp; capture_done.buffer = buffer; @@ -115,18 +139,25 @@ tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer, if (tdm_debug_module & TDM_DEBUG_BUFFER) TDM_INFO("capture(%p) done: %p", private_capture, buffer); - first_entry = tdm_buffer_list_get_first_entry(&private_capture->buffer_list); - if (first_entry != buffer) - TDM_ERR("%p is skipped", first_entry); + if (!LIST_IS_EMPTY(&private_capture->buffer_list)) { + first_entry = container_of((&private_capture->buffer_list)->next, capture_buffer, link); + if (first_entry->buffer != buffer) + TDM_ERR("buffer(%p) is skipped", first_entry->buffer); + } else { + TDM_NEVER_GET_HERE(); + } - if ((buf_info = tdm_buffer_get_info(buffer))) - LIST_DEL(&buf_info->link); + if ((capture_buffer = _tdm_capture_find_tbm_buffer(&private_capture->buffer_list, buffer))) { + LIST_DEL(&capture_buffer->link); - _pthread_mutex_unlock(&private_display->lock); - if (private_capture->done_func) - private_capture->done_func(private_capture, buffer, private_capture->done_user_data); - tdm_buffer_unref_backend(buffer); - _pthread_mutex_lock(&private_display->lock); + _pthread_mutex_unlock(&private_display->lock); + if (private_capture->done_func) + private_capture->done_func(capture_buffer, buffer, private_capture->done_user_data); + tdm_buffer_unref_backend(buffer); + _pthread_mutex_lock(&private_display->lock); + + free(capture_buffer); + } } INTERN tdm_private_capture * @@ -136,7 +167,7 @@ tdm_capture_find_stamp(tdm_private_display *private_display, double stamp) TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL); - LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, link) { + LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, display_link) { if (private_capture->stamp == stamp) return private_capture; } @@ -215,6 +246,8 @@ tdm_capture_create_output_internal(tdm_private_output *private_output, LIST_INITHEAD(&private_capture->pending_buffer_list); LIST_INITHEAD(&private_capture->buffer_list); + TDM_DBG("capture(%p) create", private_capture); + if (error) *error = TDM_ERROR_NONE; @@ -280,6 +313,8 @@ tdm_capture_create_layer_internal(tdm_private_layer *private_layer, LIST_INITHEAD(&private_capture->pending_buffer_list); LIST_INITHEAD(&private_capture->buffer_list); + TDM_DBG("capture(%p) create", private_capture); + if (error) *error = TDM_ERROR_NONE; @@ -308,25 +343,27 @@ tdm_capture_destroy_internal(tdm_private_capture *private_capture) if (!LIST_IS_EMPTY(&private_capture->pending_buffer_list)) { TDM_WRN("capture(%p) not finished:", private_capture); - tdm_buffer_list_dump(&private_capture->pending_buffer_list); + _tdm_capture_print_list(&private_capture->pending_buffer_list); LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) { LIST_DEL(&b->link); _pthread_mutex_unlock(&private_display->lock); tdm_buffer_unref_backend(b->buffer); _pthread_mutex_lock(&private_display->lock); + free(b); } } if (!LIST_IS_EMPTY(&private_capture->buffer_list)) { TDM_WRN("capture(%p) not finished:", private_capture); - tdm_buffer_list_dump(&private_capture->buffer_list); + _tdm_capture_print_list(&private_capture->buffer_list); LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->buffer_list, link) { LIST_DEL(&b->link); _pthread_mutex_unlock(&private_display->lock); tdm_buffer_unref_backend(b->buffer); _pthread_mutex_lock(&private_display->lock); + free(b); } } @@ -343,6 +380,8 @@ tdm_capture_destroy(tdm_capture *capture) if (!private_capture) return; + TDM_DBG("capture(%p) destroy", private_capture); + private_display = private_capture->private_display; _pthread_mutex_lock(&private_display->lock); @@ -356,6 +395,7 @@ tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info) CAPTURE_FUNC_ENTRY(); TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(info->type != 0, TDM_ERROR_INVALID_PARAMETER); _pthread_mutex_lock(&private_display->lock); @@ -365,6 +405,19 @@ tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info) return TDM_ERROR_NOT_IMPLEMENTED; } + if (info->type == TDM_CAPTURE_TYPE_STREAM && info->frequency == 0) { + tdm_private_output *private_output = private_capture->private_output; + info->frequency = private_output->current_mode->vrefresh; + } + + TDM_INFO("capture(%p) info: dst(%dx%d %d,%d %dx%d %c%c%c%c) trans(%d) type(%d) freq(%d) flags(%x)", + private_capture, + info->dst_config.size.h, info->dst_config.size.v, + info->dst_config.pos.x, info->dst_config.pos.y, + info->dst_config.pos.w, info->dst_config.pos.h, + FOURCC_STR(info->dst_config.format), + info->transform, info->type, info->frequency, info->flags); + ret = func_capture->capture_set_info(private_capture->capture_backend, info); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); @@ -402,6 +455,8 @@ tdm_capture_set_done_handler(tdm_capture *capture, tdm_capture_done_handler func EXTERN tdm_error tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer) { + tdm_capture_private_buffer *capture_buffer; + CAPTURE_FUNC_ENTRY(); TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER); @@ -414,25 +469,41 @@ tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer) return TDM_ERROR_NOT_IMPLEMENTED; } - ret = _tdm_capture_check_if_exist(private_capture, buffer); - if (ret != TDM_ERROR_NONE) { + if (tdm_display_check_module_abi(private_display, 1, 2) && + private_display->caps_capture.max_attach_count > 0) { + int length = LIST_LENGTH(&private_capture->pending_buffer_list) + + LIST_LENGTH(&private_capture->buffer_list); + if (length >= private_display->caps_capture.max_attach_count) { + _pthread_mutex_unlock(&private_display->lock); + TDM_DBG("failed: too many attached!! max_attach_count(%d)", + private_display->caps_capture.max_attach_count); + return TDM_ERROR_BAD_REQUEST; + } + } + + capture_buffer = calloc(1, sizeof *capture_buffer); + if (!capture_buffer) { _pthread_mutex_unlock(&private_display->lock); - return ret; + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; } ret = func_capture->capture_attach(private_capture->capture_backend, buffer); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - if (ret == TDM_ERROR_NONE) { - tdm_buffer_info *buf_info; + if (ret != TDM_ERROR_NONE) { + free(capture_buffer); + _pthread_mutex_unlock(&private_display->lock); + TDM_ERR("attach failed"); + return ret; + } - if ((buf_info = tdm_buffer_get_info(buffer))) - LIST_ADDTAIL(&buf_info->link, &private_capture->pending_buffer_list); + LIST_ADDTAIL(&capture_buffer->link, &private_capture->pending_buffer_list); + capture_buffer->buffer = tdm_buffer_ref_backend(buffer); - if (tdm_debug_module & TDM_DEBUG_BUFFER) { - TDM_INFO("capture(%p) attached:", private_capture); - tdm_buffer_list_dump(&private_capture->buffer_list); - } + if (tdm_debug_module & TDM_DEBUG_BUFFER) { + TDM_INFO("capture(%p) attached:", private_capture); + tdm_buffer_list_dump(&private_capture->buffer_list); } _pthread_mutex_unlock(&private_display->lock); @@ -443,8 +514,9 @@ tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer) EXTERN tdm_error tdm_capture_commit(tdm_capture *capture) { - tdm_buffer_info *b = NULL, *bb = NULL; + tdm_capture_private_buffer *b = NULL, *bb = NULL; tdm_private_output *private_output; + struct list_head commit_buffer_list; CAPTURE_FUNC_ENTRY(); @@ -464,18 +536,36 @@ tdm_capture_commit(tdm_capture *capture) return TDM_ERROR_NOT_IMPLEMENTED; } + LIST_INITHEAD(&commit_buffer_list); + + LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) { + LIST_DEL(&b->link); + LIST_ADDTAIL(&b->link, &private_capture->buffer_list); + LIST_ADDTAIL(&b->commit_link, &commit_buffer_list); + } + ret = func_capture->capture_commit(private_capture->capture_backend); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - if (ret == TDM_ERROR_NONE) { - LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) { + LIST_FOR_EACH_ENTRY_SAFE(b, bb, &commit_buffer_list, commit_link) { + LIST_DEL(&b->commit_link); + + if (!_tdm_capture_find_buffer(&private_capture->buffer_list, b)) + continue; + + if (ret != TDM_ERROR_NONE) { + /* Not to call the user release handler when failed. + * Do we have to call this function here really? + * User better use set_done_handler to know when pp is done. Using + * buffer_release_handler is not good. + */ + tdm_buffer_remove_release_handler_internal(b->buffer); + + _pthread_mutex_unlock(&private_display->lock); + tdm_buffer_unref_backend(b->buffer); + _pthread_mutex_lock(&private_display->lock); LIST_DEL(&b->link); - tdm_buffer_ref_backend(b->buffer); - LIST_ADDTAIL(&b->link, &private_capture->buffer_list); } - } else { - LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) - LIST_DEL(&b->link); } _pthread_mutex_unlock(&private_display->lock); diff --git a/src/tdm_pp.c b/src/tdm_pp.c index 93b7879..563ae0d 100644 --- a/src/tdm_pp.c +++ b/src/tdm_pp.c @@ -71,7 +71,7 @@ _tdm_pp_print_list(struct list_head *list) break; } - TDM_INFO("\t %s", str); + TDM_WRN("\t %s", str); } static tdm_pp_private_buffer * diff --git a/src/tdm_private.h b/src/tdm_private.h index eb6f6d6..5749782 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -344,6 +344,12 @@ typedef struct _tdm_pp_private_buffer { struct list_head commit_link; } tdm_pp_private_buffer; +typedef struct _tdm_capture_private_buffer { + tbm_surface_h buffer; + struct list_head link; + struct list_head commit_link; +} tdm_capture_private_buffer; + int tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin); diff --git a/tools/tdm_test_server.c b/tools/tdm_test_server.c index 4ea6d11..d6942a8 100644 --- a/tools/tdm_test_server.c +++ b/tools/tdm_test_server.c @@ -801,14 +801,38 @@ exit_test(int sig) printf("got signal: %d\n", sig); - LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) { - LIST_DEL(&o->link); + LIST_FOR_EACH_ENTRY_SAFE(c, cc, &data->capture_list, link) { + LIST_DEL(&c->link); + tdm_capture_destroy(c->capture); + free(c); + } - LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) { - LIST_DEL(&l->link); + LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) { + tdm_display_lock(data->display); + tdm_event_loop_source_remove(p->timer_source); + tdm_display_unlock(data->display); + + tdm_pp_destroy(p->pp); + } + LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) { + LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) { tdm_layer_unset_buffer(l->layer); + } + tdm_output_commit(o->output, 0, NULL, NULL); + } + + LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) { + LIST_DEL(&p->link); + for (i = 0; i < TDM_ARRAY_SIZE(p->bufs); i++) + tbm_surface_destroy(p->bufs[i]); + free(p); + } + LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) { + LIST_DEL(&o->link); + LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) { + LIST_DEL(&l->link); LIST_FOR_EACH_ENTRY_SAFE(w, ww, &l->prop_list, link) { LIST_DEL(&w->link); free(w); @@ -817,9 +841,6 @@ exit_test(int sig) tbm_surface_destroy(l->bufs[i]); free(l); } - - tdm_output_commit(o->output, 0, NULL, NULL); - LIST_FOR_EACH_ENTRY_SAFE(w, ww, &o->prop_list, link) { LIST_DEL(&w->link); free(w); @@ -828,26 +849,6 @@ exit_test(int sig) free(o); } - - LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) { - LIST_DEL(&p->link); - - tdm_display_lock(data->display); - tdm_event_loop_source_remove(p->timer_source); - tdm_display_unlock(data->display); - - tdm_pp_destroy(p->pp); - for (i = 0; i < TDM_ARRAY_SIZE(p->bufs); i++) - tbm_surface_destroy(p->bufs[i]); - free(p); - } - - LIST_FOR_EACH_ENTRY_SAFE(c, cc, &data->capture_list, link) { - LIST_DEL(&c->link); - tdm_capture_destroy(c->capture); - free(c); - } - if (data->display) tdm_display_deinit(data->display); -- 2.7.4 From 90e3c65a8e76808decffd880febed67e23a17a71 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Sun, 27 Nov 2016 15:56:05 +0900 Subject: [PATCH 11/16] Revert "remove unused helper function" This reverts commit 1f6a03a7b0e0ebc0c3d620f43b27f74adfbcdfc3. Change-Id: I1831a0aff0c9df9a4006cd352943ea0cac3a34f3 --- include/tdm_helper.h | 50 ++++++++++++++++ src/tdm_display.c | 25 ++++++++ src/tdm_helper.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+) diff --git a/include/tdm_helper.h b/include/tdm_helper.h index a6791aa..ba94a66 100644 --- a/include/tdm_helper.h +++ b/include/tdm_helper.h @@ -151,6 +151,56 @@ int tdm_helper_get_fd(const char *env); void tdm_helper_set_fd(const char *env, int fd); /** + * @brief Start the dump debugging. + * @details + * Start tdm dump. + * Make dump file when tdm_layer_set_buffer() function is called. + * Set the dump count to 1. + * @param[in] dumppath The given dump path + * @param[in] count The dump count number + * @see #tdm_helper_dump_stop() + */ +void +tdm_helper_dump_start(char *dumppath, int *count); + +/** + * @brief Stop the dump debugging. + * @details + * Stop tdm dump. + * Set the dump count to 0. + * @see #tdm_helper_dump_start() + */ +void +tdm_helper_dump_stop(void); + +/** + * @brief The tdm helper capture handler + * @details + * This handler will be called when composit image produced. + * @see #tdm_helper_capture_output() function + */ +typedef void (*tdm_helper_capture_handler)(tbm_surface_h buffer, void *user_data); + +/** + * @brief Make an output's image surface. + * @details Composit specific output's all layer's buffer to dst_buffer surface. + * After composing, tdm_helper_capture_handler func will be called. + * @param[in] output A output object + * @param[in] dst_buffer A surface composite image saved + * @param[in] x A horizontal position of composite image on dst_buffer + * @param[in] y A vertical position of composite image on dst_buffer + * @param[in] w A composite image width + * @param[in] h A composite image height + * @param[in] func A composing done handler + * @param[in] user_data The user data + * @return #TDM_ERROR_NONE if success. Otherwise, error value. + */ +tdm_error +tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer, + int x, int y, int w, int h, + tdm_helper_capture_handler func, void *data); + +/** * @brief Fill the display information to the reply buffer as string. * @param[in] dpy A display object * @param[out] reply the string buffer to be filled by this function. diff --git a/src/tdm_display.c b/src/tdm_display.c index 8d0cdd2..a34daab 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -40,6 +40,7 @@ #include "tdm.h" #include "tdm_backend.h" #include "tdm_private.h" +#include "tdm_helper.h" #define COUNT_MAX 10 @@ -1596,6 +1597,26 @@ tdm_layer_get_info(tdm_layer *layer, tdm_info_layer *info) return ret; } +static void +_tdm_layer_dump_buffer(tdm_layer *layer, tbm_surface_h buffer) +{ + tdm_private_layer *private_layer = (tdm_private_layer*)layer; + tdm_private_output *private_output = private_layer->private_output; + unsigned int pipe; + int zpos; + char fname[PATH_MAX]; + + pipe = private_output->pipe; + zpos = private_layer->caps.zpos; + + snprintf(fname, sizeof(fname), "tdm_%d_lyr_%d", pipe, zpos); + + tbm_surface_internal_dump_buffer(buffer, fname); + TDM_DBG("%s dump excute", fname); + + return; +} + EXTERN tdm_error tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) { @@ -1632,6 +1653,10 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) ret = func_layer->layer_set_buffer(private_layer->layer_backend, buffer); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + /* dump buffer */ + if (tdm_dump_enable && !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) + _tdm_layer_dump_buffer(layer, buffer); + if (ret == TDM_ERROR_NONE) { /* FIXME: should save to pending_buffer first. And after committing * successfully, need to move to waiting_buffer. diff --git a/src/tdm_helper.c b/src/tdm_helper.c index e91033e..51b5ddf 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -546,6 +546,164 @@ tdm_helper_set_fd(const char *env, int fd) } EXTERN void +tdm_helper_dump_start(char *dumppath, int *count) +{ + if (dumppath == NULL || count == NULL) { + TDM_DBG("tdm_helper_dump dumppath or count is null."); + return; + } + + tdm_dump_enable = 1; + + TDM_DBG("tdm_helper_dump start.(path : %s)", dumppath); +} + +EXTERN void +tdm_helper_dump_stop(void) +{ + tdm_dump_enable = 0; + + TDM_DBG("tdm_helper_dump stop."); +} + +static tdm_error +_tdm_helper_buffer_convert(tbm_surface_h srcbuf, tbm_surface_h dstbuf, + int dx, int dy, int dw, int dh, int count) +{ + pixman_image_t *src_img = NULL, *dst_img = NULL; + pixman_format_code_t src_format, dst_format; + pixman_transform_t t; + struct pixman_f_transform ft; + pixman_op_t op; + tbm_surface_info_s src_info = {0, }; + tbm_surface_info_s dst_info = {0, }; + int stride, width; + double scale_x, scale_y; + + TDM_RETURN_VAL_IF_FAIL(srcbuf != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(dstbuf != NULL, TDM_ERROR_INVALID_PARAMETER); + + if (tbm_surface_map(srcbuf, TBM_SURF_OPTION_READ, &src_info) + != TBM_SURFACE_ERROR_NONE) { + TDM_ERR("cannot mmap srcbuf\n"); + return TDM_ERROR_OPERATION_FAILED; + } + + if (tbm_surface_map(dstbuf, TBM_SURF_OPTION_WRITE, &dst_info) + != TBM_SURFACE_ERROR_NONE) { + TDM_ERR("cannot mmap dstbuf\n"); + tbm_surface_unmap(srcbuf); + return TDM_ERROR_OPERATION_FAILED; + } + TDM_GOTO_IF_FAIL(src_info.num_planes == 1, cant_convert); + TDM_GOTO_IF_FAIL(dst_info.num_planes == 1, cant_convert); + + /* src */ + src_format = _tdm_helper_pixman_format_get(src_info.format); + TDM_GOTO_IF_FAIL(src_format > 0, cant_convert); + + width = src_info.planes[0].stride / 4; + stride = src_info.planes[0].stride; + src_img = pixman_image_create_bits(src_format, width, src_info.height, + (uint32_t*)src_info.planes[0].ptr, stride); + TDM_GOTO_IF_FAIL(src_img != NULL, cant_convert); + + /* dst */ + dst_format = _tdm_helper_pixman_format_get(dst_info.format); + TDM_GOTO_IF_FAIL(dst_format > 0, cant_convert); + + width = dst_info.planes[0].stride / 4; + stride = dst_info.planes[0].stride; + dst_img = pixman_image_create_bits(dst_format, width, dst_info.height, + (uint32_t*)dst_info.planes[0].ptr, stride); + TDM_GOTO_IF_FAIL(dst_img != NULL, cant_convert); + + pixman_f_transform_init_identity(&ft); + + scale_x = (double)src_info.width / dw; + scale_y = (double)src_info.height / dh; + + pixman_f_transform_scale(&ft, NULL, scale_x, scale_y); + pixman_f_transform_translate(&ft, NULL, 0, 0); + pixman_transform_from_pixman_f_transform(&t, &ft); + pixman_image_set_transform(src_img, &t); + + if (count == 0) + op = PIXMAN_OP_SRC; + else + op = PIXMAN_OP_OVER; + + pixman_image_composite(op, src_img, NULL, dst_img, + 0, 0, 0, 0, dx, dy, dw, dh); + + if (src_img) + pixman_image_unref(src_img); + if (dst_img) + pixman_image_unref(dst_img); + + tbm_surface_unmap(srcbuf); + tbm_surface_unmap(dstbuf); + + return TDM_ERROR_NONE; + +cant_convert: + if (src_img) + pixman_image_unref(src_img); + + tbm_surface_unmap(srcbuf); + tbm_surface_unmap(dstbuf); + + return TDM_ERROR_OPERATION_FAILED; +} + +EXTERN tdm_error +tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer, + int x, int y, int w, int h, + tdm_helper_capture_handler func, void *data) +{ + tbm_surface_h surface; + tdm_error err; + int i, count, first = 0; + + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(dst_buffer != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(x >= 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(y >= 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(w >= 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(h >= 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(data != NULL, TDM_ERROR_INVALID_PARAMETER); + + err = tdm_output_get_layer_count(output, &count); + if (err != TDM_ERROR_NONE) { + TDM_ERR("tdm_output_get_layer_count fail(%d)\n", err); + return TDM_ERROR_OPERATION_FAILED; + } + if (count <= 0) { + TDM_ERR("tdm_output_get_layer_count err(%d, %d)\n", err, count); + return TDM_ERROR_BAD_MODULE; + } + + for (i = count - 1; i >= 0; i--) { + tdm_layer *layer = tdm_output_get_layer(output, i, NULL); + + surface = tdm_layer_get_displaying_buffer(layer, &err); + if (err != TDM_ERROR_NONE) + continue; + + err = _tdm_helper_buffer_convert(surface, dst_buffer, x, y, w, h, first++); + if (err != TDM_ERROR_NONE) + TDM_DBG("convert fail %d-layer buffer\n", i); + else + TDM_DBG("convert success %d-layer buffer\n", i); + } + + func(dst_buffer, data); + + return TDM_ERROR_NONE; +} + +EXTERN void tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len) { tdm_private_display *private_display; -- 2.7.4 From c5412a0eea9b2a40a80dadb902c5b3e45809326b Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 28 Nov 2016 16:19:57 +0900 Subject: [PATCH 12/16] tdm_server: clean up tdm_server_init() This patch cleans up tdm_server_init() not to dereference when private_loop is NULL. Change-Id: I846c47130992264ff39d194e7ca4299e4970bc2c Signed-off-by: YoungJun Cho --- src/tdm_server.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tdm_server.c b/src/tdm_server.c index 4dee110..ca1ef40 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -511,12 +511,12 @@ tdm_server_init(tdm_private_loop *private_loop) { tdm_private_server *private_server; - if (private_loop->private_server) - return TDM_ERROR_NONE; - TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_OPERATION_FAILED); TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display, TDM_ERROR_OPERATION_FAILED); + if (private_loop->private_server) + return TDM_ERROR_NONE; + if (wl_display_add_socket(private_loop->wl_display, "tdm-socket")) { TDM_ERR("createing a tdm-socket failed"); return TDM_ERROR_OPERATION_FAILED; -- 2.7.4 From c8ab3c99a2ff85e94d32a6aec8f616d584a97753 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 28 Nov 2016 16:21:30 +0900 Subject: [PATCH 13/16] tdm_buffer: clean up tdm_buffer_get_info() This patch cleans up tdm_buffer_get_info() not to skip free(buf_info). Change-Id: If2f3cbc4c72aa084d2f10827a14161a0adf68889 Signed-off-by: YoungJun Cho --- src/tdm_buffer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tdm_buffer.c b/src/tdm_buffer.c index 68ca444..8e9f10a 100644 --- a/src/tdm_buffer.c +++ b/src/tdm_buffer.c @@ -100,10 +100,12 @@ tdm_buffer_get_info(tbm_surface_h buffer) if (!tbm_surface_internal_add_user_data(buffer, TDM_BUFFER_KEY, _tdm_buffer_destroy_info)) { TDM_ERR("FAIL to create user_data for surface %p", buffer); + free(buf_info); return NULL; } if (!tbm_surface_internal_set_user_data(buffer, TDM_BUFFER_KEY, buf_info)) { TDM_ERR("FAIL to set user_data for surface %p", buffer); + free(buf_info); return NULL; } -- 2.7.4 From 6491bd933e7fe4fc2ddb6316b2b987dd12c54d87 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 28 Nov 2016 16:23:08 +0900 Subject: [PATCH 14/16] tdm_buffer: clean up tdm_buffer_unref_backend() This patch cleans up tdm_buffer_unref_backend(). The 'buffer' is not changed in buf_info->release_funcs list loop, so does not need to call ref & unref inside. Change-Id: I924bc4abde130be37ee800534e161beee56ae09a Signed-off-by: YoungJun Cho --- src/tdm_buffer.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/tdm_buffer.c b/src/tdm_buffer.c index 8e9f10a..4fa18a3 100644 --- a/src/tdm_buffer.c +++ b/src/tdm_buffer.c @@ -220,11 +220,10 @@ tdm_buffer_unref_backend(tbm_surface_h buffer) // if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) // TDM_NEVER_GET_HERE(); - LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->release_funcs, link) { - tbm_surface_internal_ref(buffer); + tbm_surface_internal_ref(buffer); + LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->release_funcs, link) func_info->release_func(buffer, func_info->user_data); - tbm_surface_internal_unref(buffer); - } + tbm_surface_internal_unref(buffer); tbm_surface_internal_unref(buffer); } -- 2.7.4 From e6c4934378f41098058ba2ab862f46aa4bf84dc0 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Mon, 28 Nov 2016 17:49:49 +0900 Subject: [PATCH 15/16] fix error handling Change-Id: I19915a6f59a219efa701d629a88863c66ca4dd75 --- src/tdm_buffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tdm_buffer.c b/src/tdm_buffer.c index 4fa18a3..e691507 100644 --- a/src/tdm_buffer.c +++ b/src/tdm_buffer.c @@ -105,6 +105,7 @@ tdm_buffer_get_info(tbm_surface_h buffer) } if (!tbm_surface_internal_set_user_data(buffer, TDM_BUFFER_KEY, buf_info)) { TDM_ERR("FAIL to set user_data for surface %p", buffer); + tbm_surface_internal_delete_user_data(buffer, TDM_BUFFER_KEY); free(buf_info); return NULL; } -- 2.7.4 From 0734686074700b40b6cff80d7279a5285d3c0c0f Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 28 Nov 2016 18:04:58 +0900 Subject: [PATCH 16/16] tdm_helper: clean up _tdm_helper_dump_png() This patch cleans up _tdm_helper_dump_png() not to skip resources release. Change-Id: Ic2384c0e5cc1335428f455760efb5c691e3600f9 Signed-off-by: YoungJun Cho --- src/tdm_helper.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/tdm_helper.c b/src/tdm_helper.c index 51b5ddf..95dbe7f 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -128,6 +128,11 @@ _tdm_helper_dump_png(const char *file, const void *data, int width, const int pixel_size = 4; // RGBA png_bytep *row_pointers = png_malloc(pPngStruct, height * sizeof(png_byte *)); + if (!row_pointers) { + png_destroy_write_struct(&pPngStruct, &pPngInfo); + fclose(fp); + return; + } unsigned int *blocks = (unsigned int *)data; int y = 0; @@ -136,6 +141,15 @@ _tdm_helper_dump_png(const char *file, const void *data, int width, for (; y < height; ++y) { png_bytep row = png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size); + if (!row) { + for (x = 0; x < y; x++) + png_free(pPngStruct, row_pointers[x]); + png_free(pPngStruct, row_pointers); + png_destroy_write_struct(&pPngStruct, &pPngInfo); + fclose(fp); + return; + } + row_pointers[y] = (png_bytep)row; for (x = 0; x < width; ++x) { unsigned int curBlock = blocks[y * width + x]; -- 2.7.4