* Taeheon Kim <th908.kim@samsung.com>,
* YoungJun Cho <yj44.cho@samsung.com>,
* SooChan Lim <sc1.lim@samsung.com>,
- * Boram Park <sc1.lim@samsung.com>
+ * Boram Park <boram1288.park@samsung.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
#include <tbm_surface.h>
#include <tbm_surface_internal.h>
-#include <tdm.h>
-#include <tdm_log.h>
-#include <tdm_list.h>
-#include <tdm_helper.h>
-#include <tdm_backend.h>
+#include "tdm.h"
+#include "tdm_log.h"
+#include "tdm_list.h"
+#include "tdm_helper.h"
+#include "tdm_backend.h"
#include "tdm_macro.h"
#include "tdm_private.h"
"<output_idx>[,<layer_idx>]~<w>x<h>[+<x>+<y>][,<h>x<v>][@<format>][*<transform>][^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",
"<prop_name>:<value>", NULL
},
printf("\t%s\n", usages[t].desc);
}
printf("\n");
- exit(0);
}
////////////////////////////////////////////////////////////////////////////////
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 */
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;
+ int need_mode_change;
+ int mode_index;
+ tdm_event_loop_source *timer;
+ const tdm_output_mode *current_mode;
+};
+
struct _tdm_test_server {
/* args */
int do_query;
int do_all;
int do_vblank;
+ int do_voutput;
int bflags;
int b_fill;
struct list_head output_list;
struct list_head pp_list;
struct list_head capture_list;
+ struct list_head voutput_list;
tdm_display *display;
};
+static void destroy(tdm_test_server *data);
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 void _voutput_layer_init(tdm_test_server_voutput *voutput);
static char*
parse_size(tdm_size *size, char *arg)
if (argc < 2) {
usage(argv[0]);
+ destroy(data);
exit(0);
}
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);
exit(0);
}
}
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);
+ ret = tdm_output_get_conn_status(output, &status);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
continue;
o = calloc(1, sizeof * o);
}
static void
+_voutput_buff_deinit(tdm_test_server_voutput *voutput)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (!voutput->bufs[i]) continue;
+
+ tbm_surface_destroy(voutput->bufs[i]);
+ voutput->bufs[i] = NULL;
+ }
+}
+
+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
+_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_test_server *data;
+ tdm_output_conn_status status;
+ tdm_error ret;
+
+ printf("voutput cb:\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;
+
+ if (voutput->need_mode_change) {
+ const tdm_output_mode *modes;
+ int count = 0;
+
+ tdm_output_get_available_modes(voutput->output, &modes, &count);
+ if (count > voutput->mode_index) {
+ const tdm_output_mode *mode;
+
+ mode = &modes[voutput->mode_index];
+ data = voutput->data;
+
+ printf("mode change to %d (%dx%d, %d)\n",
+ voutput->mode_index, mode->hdisplay, mode->vdisplay, mode->vrefresh);
+ _voutput_buff_deinit(voutput);
+ _voutput_buff_init(voutput);
+
+ ret = tdm_output_set_mode(voutput->output, mode);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ voutput->current_mode = mode;
+
+ _voutput_layer_init(voutput);
+ voutput->buf_idx = 0;
+
+ tdm_display_lock(data->display);
+ ret = tdm_event_loop_source_timer_update(voutput->timer, 10);
+ tdm_display_unlock(data->display);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+ }
+
+ voutput->need_mode_change = 0;
+ 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_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->current_mode = mode;
+
+ 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;
+
+ printf("output: %p disconnect\n", voutput);
+
+ ret = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+}
+
+static tdm_error
+_voutput_buffer_send(void *user_data)
+{
+ tdm_test_server_voutput *voutput = user_data;
+ tdm_test_server *data = voutput->data;
+
+ tdm_display_unlock(data->display);
+
+ _vlayer_show_buffer(voutput);
+
+ tdm_display_lock(data->display);
+
+ return 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_test_server *data = NULL;
+ const tdm_output_mode *mode;
+ tdm_output_conn_status status;
+ tdm_error ret = TDM_ERROR_NONE;
+
+ voutput = (tdm_test_server_voutput *)user_data;
+ TDM_EXIT_IF_FAIL(voutput != NULL);
+
+ data = voutput->data;
+
+ 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);
+
+ tdm_display_lock(data->display);
+ ret = tdm_event_loop_source_timer_update(voutput->timer, 10);
+ tdm_display_unlock(data->display);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+ } else if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
+ _voutput_disconnect(voutput);
+ } else if (status == TDM_OUTPUT_CONN_STATUS_MODE_SETTED) {
+ ret = tdm_output_get_mode(output, &mode);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ printf("mode setted (%dx%d, %d)\n", mode->hdisplay, mode->vdisplay, mode->vrefresh);
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+_tdm_test_server_cb_output_mode_change(tdm_output *output, unsigned int index, void *user_data)
+{
+ tdm_test_server_voutput *voutput = NULL;
+ const tdm_output_mode *modes, *mode;
+ int count = 0;
+ tdm_error ret;
+
+ voutput = (tdm_test_server_voutput *)user_data;
+ TDM_EXIT_IF_FAIL(voutput != NULL);
+
+ ret = tdm_output_get_available_modes(output, &modes, &count);
+ TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+ TDM_RETURN_IF_FAIL(index < count);
+
+
+ mode = &modes[index];
+
+ if (mode == voutput->current_mode) return;
+
+ voutput->need_mode_change = 1;
+ voutput->mode_index = index;
+
+ printf("request mode change to %d (%dx%d, %d) from (%dx%d, %d)\n",
+ index, mode->hdisplay, mode->vdisplay, mode->vrefresh,
+ voutput->current_mode->hdisplay, voutput->current_mode->vdisplay, voutput->current_mode->vrefresh);
+}
+
+static void
+_tdm_output_cb_destroy_handler(tdm_output *output, void *user_data)
+{
+ tdm_test_server_voutput *voutput = NULL;
+
+ voutput = (tdm_test_server_voutput *)user_data;
+ TDM_EXIT_IF_FAIL(voutput != NULL);
+
+ tdm_output_remove_mode_change_request_handler(output, _tdm_test_server_cb_output_mode_change, voutput);
+ 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);
+
+ _voutput_buff_deinit(voutput);
+
+ printf("voutput: %p destroy\n", voutput);
+
+ 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_mode_change_request_handler(output, _tdm_test_server_cb_output_mode_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;
+
+ tdm_display_lock(data->display);
+ voutput->timer = tdm_event_loop_add_timer_handler(data->display, _voutput_buffer_send, voutput, &ret);
+ tdm_display_unlock(data->display);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ printf("voutput %p create done\n", voutput);
+
+ LIST_ADDTAIL(&voutput->link, &data->voutput_list);
+}
+
+static void
destroy(tdm_test_server *data)
{
tdm_test_server_output *o = NULL, *oo = NULL;
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;
LIST_FOR_EACH_ENTRY_SAFE(c, cc, &data->capture_list, link) {
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);
+ ret = tdm_layer_unset_buffer(l->layer);
+ TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
}
- tdm_layer_commit(l->layer, NULL, NULL);
+ ret = tdm_layer_commit(l->layer, NULL, NULL);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
}
LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) {
free(o);
}
+ LIST_FOR_EACH_ENTRY_SAFE(v, vv, &data->voutput_list, link) {
+ _voutput_buff_deinit(v);
+ 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);
int len = sizeof temp;
tdm_error ret;
+#if 1 /* for testing */
+ const char *s = (const char*)getenv("XDG_RUNTIME_DIR");
+ if (!s) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "/run");
+ int ret = setenv("XDG_RUNTIME_DIR", (const char*)buf, 1);
+ if (ret != 0)
+ exit(0);
+ }
+
+ 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
+
memset(data, 0, sizeof * data);
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;
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:
}
if (!best)
best = &modes[i];
- if (modes[i].flags & TDM_OUTPUT_MODE_TYPE_PREFERRED)
+ if (modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
prefer = &modes[i];
}
if (!found && prefer) {
TDM_EXIT_IF_FAIL(tb != NULL);
tb->in_use = 1;
- tdm_buffer_add_release_handler(b, layer_cb_buffer_release, NULL);
+ ret = tdm_buffer_add_release_handler(b, layer_cb_buffer_release, NULL);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
if (data->do_vblank)
ret = tdm_layer_commit(l->layer, layer_cb_commit, l);
c->info.dst_config.size.v = info.height;
}
c->info.dst_config.format = info.format;
+ c->info.type = TDM_CAPTURE_TYPE_ONESHOT;
ret = tdm_capture_set_info(c->capture, &c->info);
TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
printf("enter test loop\n");
- while (1)
- tdm_display_handle_events(data->display);
+ while (1) {
+ ret = tdm_display_handle_events(data->display);
+ TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+ }
destroy(data);