From ef9d531a0c44073ec79179e17280be66c9151f38 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Thu, 16 Aug 2018 21:00:23 +0900 Subject: [PATCH] virtual: add tdm virtual output test to tdm_test with V option 1. execute tdm-test-server with -V option 2. execute tdm-test-client with -V option after voutput connect from client, server send three differnt buffers to client. client make dump commit buffers untill 10 to /tmp/. Change-Id: I65775c8b28ef8d08c34aca9a706b770d99974a11 Signed-off-by: Junkyeong Kim --- tools/tdm_test_client.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++- tools/tdm_test_server.c | 270 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 542 insertions(+), 1 deletion(-) diff --git a/tools/tdm_test_client.c b/tools/tdm_test_client.c index 1031685..bb0ba22 100644 --- a/tools/tdm_test_client.c +++ b/tools/tdm_test_client.c @@ -40,9 +40,11 @@ #include #include #include +#include #include "tdm_client.h" #include "tdm_macro.h" +#include "buffers.h" typedef struct _tdm_test_client_arg { char *output_name; @@ -60,6 +62,7 @@ typedef struct _tdm_test_client { int do_query; int do_vblank; + int do_voutput; int waiting; tdm_client *client; @@ -93,6 +96,7 @@ static struct typestrings typestrs[] = { static struct optstrings optstrs[] = { {OPT_QRY, "qo", "output objects info", "", "primary"}, {OPT_TST, "v", "vblank test", "[,][@][~][+][*fake][^vblank_name]", "primary,0@60~1+0*1^test"}, + {OPT_TST, "V", "virtual output test", NULL, NULL}, }; static void @@ -181,7 +185,7 @@ parse_args(tdm_test_client *data, int argc, char *argv[]) { int i; - if (argc < 3) { + if (argc < 2) { usage(argv[0]); exit(0); } @@ -196,6 +200,8 @@ parse_args(tdm_test_client *data, int argc, char *argv[]) } else if (!strncmp(argv[i] + 1, "v", 1)) { data->do_vblank = 1; parse_arg_v(data, argv[++i]); + } else if (!strncmp(argv[i] + 1, "V", 1)) { + data->do_voutput = 1; } else { usage(argv[0]); exit(0); @@ -374,6 +380,259 @@ done: tdm_client_vblank_destroy(vblank); } +#define PNG_DEPTH 8 + +void +_tdm_client_get_buffer_full_size(tbm_surface_h buffer, int *buffer_w, int *buffer_h) +{ + tbm_surface_info_s info; + int ret; + + TDM_RETURN_IF_FAIL(buffer != NULL); + + ret = tbm_surface_get_info(buffer, &info); + TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE); + + if (buffer_w) { + if (IS_RGB(info.format)) + *buffer_w = info.planes[0].stride >> 2; + else + *buffer_w = info.planes[0].stride; + } + + if (buffer_h) + *buffer_h = info.planes[0].size / info.planes[0].stride; +} + +static void +_tdm_client_dump_png(const char *file, const void *data, int width, + int height) +{ + FILE *fp; + + fp = fopen(file, "wb"); + TDM_RETURN_IF_FAIL(fp != NULL); + + png_structp pPngStruct = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!pPngStruct) { + fclose(fp); + return; + } + + png_infop pPngInfo = png_create_info_struct(pPngStruct); + if (!pPngInfo) { + png_destroy_write_struct(&pPngStruct, NULL); + fclose(fp); + return; + } + + png_init_io(pPngStruct, fp); + png_set_IHDR(pPngStruct, + pPngInfo, + width, + height, + PNG_DEPTH, + PNG_COLOR_TYPE_RGBA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + png_set_bgr(pPngStruct); + png_write_info(pPngStruct, pPngInfo); + + 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; + int x = 0; + + 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]; + row[x * pixel_size] = (curBlock & 0xFF); + row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF; + row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF; + row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF; + } + } + + png_write_image(pPngStruct, row_pointers); + png_write_end(pPngStruct, pPngInfo); + + for (y = 0; y < height; y++) + png_free(pPngStruct, row_pointers[y]); + png_free(pPngStruct, row_pointers); + + png_destroy_write_struct(&pPngStruct, &pPngInfo); + + fclose(fp); +} + +void +_tdm_client_dump_buffer(tbm_surface_h buffer, const char *file) +{ + char temp[TDM_PATH_LEN] = {0,}; + tbm_surface_info_s info; + int len, ret; + const char *ext; + int bo_cnt; + int bw, bh; + char *dot, *p = temp; + const char *file_exts[2] = {"png", "raw"}; + + TDM_RETURN_IF_FAIL(buffer != NULL); + TDM_RETURN_IF_FAIL(file != NULL); + + ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info); + TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE); + + if (IS_RGB(info.format)) + ext = file_exts[0]; + else + ext = file_exts[1]; + + dot = strrchr(file, '.'); + if (!dot || strlen(dot + 1) != 3 || strncmp(dot + 1, ext, 3)) { + len = strnlen(file, TDM_PATH_LEN - 5); + strncat(p, file, len); + p += len; + *(p++) = '.'; + strncat(p, ext, 3); + p += 3; + *p = '\0'; + } else { + len = strnlen(file, TDM_PATH_LEN - 1); + strncat(p, file, len); + p += len; + *p = '\0'; + } + + _tdm_client_get_buffer_full_size(buffer, &bw, &bh); + + bo_cnt = tbm_surface_internal_get_num_bos(buffer); + TDM_DBG("buffer: bo_cnt(%d) %dx%d(%dx%d) %c%c%c%c, plane: (%p+%d, %d,%d) (%p+%d, %d,%d) (%p+%d, %d,%d)", + bo_cnt, bw, bh, info.width, info.height, FOURCC_STR(info.format), + info.planes[0].ptr, info.planes[0].offset, info.planes[0].stride, info.planes[0].size, + info.planes[1].ptr, info.planes[1].offset, info.planes[1].stride, info.planes[1].size, + info.planes[2].ptr, info.planes[2].offset, info.planes[2].stride, info.planes[2].size); + + _tdm_client_dump_png(temp, info.planes[0].ptr, bw, bh); + + tbm_surface_unmap(buffer); + + printf("dump %s", temp); +} + +static void +_dump_buffer(tbm_surface_h buffer, int count) +{ + char temp[TDM_PATH_LEN] = {0,}; + + snprintf(temp, TDM_PATH_LEN, "/tmp/%c%c%c%c_%dx%d_%d", + FOURCC_STR(tbm_surface_get_format(buffer)), + tbm_surface_get_width(buffer), + tbm_surface_get_height(buffer), + count); + _tdm_client_dump_buffer(buffer, temp); +} + +static void +_voutput_commit(tdm_client_voutput *voutput, tbm_surface_h buffer, void *user_data) +{ + tdm_test_client *data = (tdm_test_client *)user_data; + static int count = 0; + + TDM_EXIT_IF_FAIL(data != NULL); + TDM_EXIT_IF_FAIL(buffer != NULL); + + if (count < 11) + _dump_buffer(buffer, count); + count++; + + printf("client: %d commited(%p)\n", count, buffer); + tdm_client_voutput_commit_done(voutput); +} + + static void +_voutput_make_available_mode(tdm_client_output_mode *modes, int count) +{ + int i; + for (i = 0; i < count; i++) { + modes[i].clock = 25200; + modes[i].hdisplay = 640; + modes[i].hsync_start = 656; + modes[i].hsync_end = 752; + modes[i].htotal = 800; + modes[i].hskew = 0; + modes[i].vdisplay = 480; + modes[i].vsync_start = 490; + modes[i].vsync_end = 492; + modes[i].vtotal = 525; + modes[i].vscan = 0; + modes[i].vrefresh = 30; + modes[i].flags = 0; + modes[i].type = 0; + snprintf(modes[i].name, TDM_NAME_LEN, "%dx%d_%d", modes[i].hdisplay, modes[i].vdisplay, i); + } +} + +static void +do_voutput(tdm_test_client *data) +{ + tdm_client_voutput *voutput = NULL; + tdm_client_output *output = NULL; + tdm_client_output_mode modes[2]; + tdm_error ret = TDM_ERROR_NONE; + + printf("virtual output test - client\n"); + + voutput = tdm_client_create_voutput(data->client, "virtual-test", &ret); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + ret = tdm_client_voutput_add_commit_handler(voutput, _voutput_commit, data); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done); + + output = tdm_client_voutput_get_client_output(voutput, &ret); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done); + + ret = tdm_client_voutput_set_physical_size(voutput, 300, 200); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done); + + _voutput_make_available_mode(modes, 2); + ret = tdm_client_voutput_set_available_modes(voutput, modes, 2); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done); + + ret = tdm_client_output_connect(output); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done); + + while (1) { + tdm_client_handle_events_timeout(data->client, 1000); + } + +done: + if (voutput) + tdm_client_voutput_destroy(voutput); +} + static tdm_test_client ttc_data; int @@ -391,6 +650,16 @@ main(int argc, char *argv[]) if (ret != 0) exit(0); } + + /* for tbm_bufmgr_init */ + const char *s = (const char*)getenv("TBM_DISPLAY_SERVER"); + if (!s) { + char buf[32]; + snprintf(buf, sizeof(buf), "1"); + int ret = setenv("TBM_DISPLAY_SERVER", (const char*)buf, 1); + if (ret != 0) + exit(0); + } #endif parse_args(data, argc, argv); @@ -409,6 +678,8 @@ main(int argc, char *argv[]) do_query(data); if (data->do_vblank) do_vblank(data); + if (data->do_voutput) + do_voutput(data); done: if (data->args.output_name) diff --git a/tools/tdm_test_server.c b/tools/tdm_test_server.c index 535462f..b439540 100644 --- a/tools/tdm_test_server.c +++ b/tools/tdm_test_server.c @@ -108,6 +108,10 @@ static struct optstrings optstrs[] = { "[,]~x[++][,x][@][*][^stream]", NULL }, { + OPT_TST, "V", "virtual output test.\n\t\t'-l' is used to show the result on screen.", + NULL, NULL + }, + { OPT_GEN, "w", "set the property of a object", ":", NULL }, @@ -217,6 +221,7 @@ TDM_BIT_NAME_FB(buf_flag) typedef struct _tdm_test_server tdm_test_server; typedef struct _tdm_test_server_layer tdm_test_server_layer; typedef struct _tdm_test_server_capture tdm_test_server_capture; +typedef struct _tdm_test_server_voutput tdm_test_server_voutput; typedef struct _tdm_test_server_prop { /* args */ @@ -300,11 +305,21 @@ struct _tdm_test_server_layer { int buf_idx; }; +struct _tdm_test_server_voutput { + struct list_head link; + tdm_test_server *data; + tdm_output *output; + tdm_layer *layer; + tbm_surface_h bufs[3]; + int buf_idx; +}; + struct _tdm_test_server { /* args */ int do_query; int do_all; int do_vblank; + int do_voutput; int bflags; int b_fill; @@ -312,6 +327,7 @@ struct _tdm_test_server { struct list_head output_list; struct list_head pp_list; struct list_head capture_list; + struct list_head voutput_list; tdm_display *display; }; @@ -320,6 +336,7 @@ static void run_test(tdm_test_server *data); static void output_setup(tdm_test_server_output *o); static void layer_show_buffer(tdm_test_server_layer *l, tbm_surface_h b); static void capture_attach(tdm_test_server_capture *c, tbm_surface_h b); +static void _vlayer_show_buffer(tdm_test_server_voutput *voutput); static char* parse_size(tdm_size *size, char *arg) @@ -596,6 +613,8 @@ parse_args(tdm_test_server *data, int argc, char *argv[]) parse_arg_b(data, argv[++i]); } else if (!strncmp(argv[i] + 1, "v", 1)) { data->do_vblank = 1; + } else if (!strncmp(argv[i] + 1, "V", 1)) { + data->do_voutput = 1; } else { usage(argv[0]); destroy(data); @@ -790,6 +809,238 @@ get_tts_buffer(tbm_surface_h b) } static void +_vlayer_cb_commit(tdm_layer *layer, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) +{ + tdm_test_server_voutput *voutput = (tdm_test_server_voutput *)user_data; + TDM_EXIT_IF_FAIL(voutput != NULL); + tdm_output_conn_status status; + tdm_error ret; + + printf("voutput cb commit:\t %d: l(%p) b(%p)\n", voutput->buf_idx, voutput->layer, voutput->bufs[voutput->buf_idx]); + + ret = tdm_output_get_conn_status(voutput->output, &status); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) return; + + voutput->buf_idx++; + _vlayer_show_buffer(voutput); +} + +static void +_vlayer_show_buffer(tdm_test_server_voutput *voutput) +{ + tdm_error ret; + int index; + if (voutput->buf_idx == 3) + voutput->buf_idx = 0; + + index = voutput->buf_idx; + + ret = tdm_layer_set_buffer(voutput->layer, voutput->bufs[index]); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + ret = tdm_layer_commit(voutput->layer, _vlayer_cb_commit, voutput); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + printf("voutput show:\t %d: l(%p) b(%p)\n", index, voutput->layer, voutput->bufs[index]); +} + +static void +_voutput_buff_init(tdm_test_server_voutput *voutput) +{ + tdm_output *output = voutput->output; + const tdm_output_mode *mode; + tdm_error ret = TDM_ERROR_NONE; + int i; + + ret = tdm_output_get_mode(output, &mode); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + for (i = 0; i < 3; i++) { + tbm_surface_h b = tbm_surface_internal_create_with_flags(mode->hdisplay, mode->vdisplay, DEFAULT_FORMAT, 0); + TDM_EXIT_IF_FAIL(b != NULL); + tdm_test_buffer_fill(b, i); + voutput->bufs[i] = b; + } +} + +static void +_voutput_layer_init(tdm_test_server_voutput *voutput) +{ + tdm_output *output = voutput->output; + const tdm_output_mode *mode; + tdm_info_layer layer_info; + tbm_surface_info_s info; + tdm_error ret = TDM_ERROR_NONE; + + ret = tdm_output_get_mode(output, &mode); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + TDM_ERR("modeinfo : %dx%d %d", mode->hdisplay, mode->vdisplay, mode->vrefresh); + + voutput->layer = tdm_output_get_layer(output, 0, &ret); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + _voutput_buff_init(voutput); + + tbm_surface_get_info(voutput->bufs[0], &info); + memset(&layer_info, 0x0, sizeof(tdm_info_layer)); + if (IS_RGB(info.format)) { + layer_info.src_config.size.h = info.planes[0].stride >> 2; + layer_info.src_config.size.v = info.height; + } else { + layer_info.src_config.size.h = info.planes[0].stride; + layer_info.src_config.size.v = info.height; + } + layer_info.src_config.format = info.format; + + layer_info.src_config.size.h = mode->hdisplay; + layer_info.src_config.size.v = mode->vdisplay; + layer_info.src_config.pos.x = 0; + layer_info.src_config.pos.y = 0; + layer_info.src_config.pos.w = mode->hdisplay; + layer_info.src_config.pos.h = mode->vdisplay; + layer_info.dst_pos.x = 0; + layer_info.dst_pos.y = 0; + layer_info.dst_pos.w = mode->hdisplay; + layer_info.dst_pos.h = mode->vdisplay; + layer_info.transform = TDM_TRANSFORM_NORMAL; + + ret = tdm_layer_set_info(voutput->layer, &layer_info); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); +} + +static void +_voutput_connect(tdm_test_server_voutput *voutput) +{ + tdm_output *output; + const tdm_output_mode *modes, *found = NULL, *best = NULL, *prefer = NULL; + int i, count; + tdm_error ret; + + output = voutput->output; + + ret = tdm_output_get_available_modes(output, &modes, &count); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + for (i = 0; i < count; i++) { + if (!best) + best = &modes[i]; + if (modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED) + prefer = &modes[i]; + } + if (prefer) { + found = prefer; + printf("found prefer mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh); + } + if (!found && best) { + found = best; + printf("found best mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh); + } + if (!found) { + printf("couldn't find any mode\n"); + exit(0); + } + + ret = tdm_output_set_mode(output, found); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + printf("output: %s %d\n", found->name, found->vrefresh); + + ret = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); +} + +static void +_voutput_disconnect(tdm_test_server_voutput *voutput) +{ + tdm_output *output; + tdm_error ret; + + output = voutput->output; + + ret = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); +} + +static void +_tdm_test_server_cb_output_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data) +{ + tdm_test_server_voutput *voutput = NULL; + tdm_output_conn_status status; + + voutput = (tdm_test_server_voutput *)user_data; + TDM_EXIT_IF_FAIL(voutput != NULL); + + switch (type) { + case TDM_OUTPUT_CHANGE_CONNECTION: + status = (tdm_output_conn_status)value.u32; + if (status == TDM_OUTPUT_CONN_STATUS_CONNECTED) { + _voutput_connect(voutput); + _voutput_layer_init(voutput); + _vlayer_show_buffer(voutput); + } else if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + _voutput_disconnect(voutput); + } + break; + default: + break; + } +} + +static void +_tdm_output_cb_destroy_handler(tdm_output *output, void *user_data) +{ + tdm_test_server_voutput *voutput = NULL; + int i; + + voutput = (tdm_test_server_voutput *)user_data; + TDM_EXIT_IF_FAIL(voutput != NULL); + + tdm_output_remove_change_handler(output, _tdm_test_server_cb_output_change, voutput); + tdm_output_remove_destroy_handler(output, _tdm_output_cb_destroy_handler, voutput); + + LIST_DEL(&voutput->link); + + for (i = 0; i < 3; i++) { + tbm_surface_destroy(voutput->bufs[i]); + } + + free(voutput); +} + +static void +_tdm_output_cb_create_handler(tdm_display *dpy, tdm_output *output, void *user_data) +{ + tdm_test_server *data; + tdm_test_server_voutput *voutput = NULL; + tdm_error ret = TDM_ERROR_NONE; + + printf("voutput create call\n"); + + data = (tdm_test_server *)user_data; + TDM_EXIT_IF_FAIL(data != NULL); + + voutput = calloc(1, sizeof *voutput); + TDM_EXIT_IF_FAIL(voutput != NULL); + + ret = tdm_output_add_change_handler(output, _tdm_test_server_cb_output_change, voutput); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + ret = tdm_output_add_destroy_handler(output, _tdm_output_cb_destroy_handler, voutput); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + + voutput->output = output; + voutput->data = data; + + printf("voutput create done\n"); + + LIST_ADDTAIL(&voutput->link, &data->voutput_list); +} + +static void destroy(tdm_test_server *data) { tdm_test_server_output *o = NULL, *oo = NULL; @@ -797,6 +1048,7 @@ destroy(tdm_test_server *data) tdm_test_server_pp *p = NULL, *pp = NULL; tdm_test_server_capture *c = NULL, *cc = NULL; tdm_test_server_prop *w = NULL, *ww = NULL; + tdm_test_server_voutput *v = NULL, *vv = NULL; tdm_error ret; int i; @@ -850,6 +1102,17 @@ destroy(tdm_test_server *data) free(o); } + LIST_FOR_EACH_ENTRY_SAFE(v, vv, &data->voutput_list, link) { + for (int i = 0; i < 3; i++) { + tbm_surface_destroy(v->bufs[i]); + } + LIST_DEL(&v->link); + free(v); + } + + if (data->do_voutput) + tdm_display_remove_output_create_handler(data->display, _tdm_output_cb_create_handler, data); + if (data->display) tdm_display_deinit(data->display); @@ -888,6 +1151,7 @@ main(int argc, char *argv[]) LIST_INITHEAD(&data->output_list); LIST_INITHEAD(&data->pp_list); LIST_INITHEAD(&data->capture_list); + LIST_INITHEAD(&data->voutput_list); /* init value */ data->bflags = TBM_BO_SCANOUT; @@ -905,6 +1169,12 @@ main(int argc, char *argv[]) goto done; } + if (data->do_voutput) { + printf("support virtual output - server\n"); + ret = tdm_display_add_output_create_handler(data->display, _tdm_output_cb_create_handler, data); + TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE); + } + run_test(data); done: -- 2.7.4