From eca0e8c8a3a8b1a4b27823a87a35f81044f10a77 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Wed, 18 Jul 2018 11:51:46 +0900 Subject: [PATCH] virtual:add virtual backend copy dummy backend. load virtual backend module default. Change-Id: If130aa455e28ecf01a5674ae87d8247554144a09 Signed-off-by: Junkyeong Kim --- backends/Makefile.am | 2 +- backends/virtual/Makefile.am | 14 + backends/virtual/tdm_virtual.c | 134 +++++++ backends/virtual/tdm_virtual.h | 76 ++++ backends/virtual/tdm_virtual_display.c | 636 +++++++++++++++++++++++++++++++++ configure.ac | 1 + packaging/libtdm.spec | 1 + src/tdm.c | 8 + src/tdm_macro.h | 1 + src/tdm_private_types.h | 1 + 10 files changed, 873 insertions(+), 1 deletion(-) create mode 100644 backends/virtual/Makefile.am create mode 100644 backends/virtual/tdm_virtual.c create mode 100644 backends/virtual/tdm_virtual.h create mode 100644 backends/virtual/tdm_virtual_display.c diff --git a/backends/Makefile.am b/backends/Makefile.am index 4a66860..f841dd0 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -1 +1 @@ -SUBDIRS = dummy +SUBDIRS = dummy virtual diff --git a/backends/virtual/Makefile.am b/backends/virtual/Makefile.am new file mode 100644 index 0000000..099b71e --- /dev/null +++ b/backends/virtual/Makefile.am @@ -0,0 +1,14 @@ +AM_CFLAGS = \ + $(CFLAGS) \ + $(TDM_CFLAGS) \ + -I$(top_srcdir)/include + +libtdm_virtual_la_LTLIBRARIES = libtdm-virtual.la +libtdm_virtual_ladir = $(TDM_MODULE_PATH) +libtdm_virtual_la_LDFLAGS = -module -avoid-version +libtdm_virtual_la_LIBADD = $(TDM_LIBS) $(top_builddir)/src/libtdm.la + +libtdm_virtual_la_SOURCES = \ + tdm_virtual_display.c \ + tdm_virtual.c + diff --git a/backends/virtual/tdm_virtual.c b/backends/virtual/tdm_virtual.c new file mode 100644 index 0000000..f890829 --- /dev/null +++ b/backends/virtual/tdm_virtual.c @@ -0,0 +1,134 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm_virtual.h" + +static tdm_virtual_data *virtual_data; + +void +tdm_virtual_deinit(tdm_backend_data *bdata) +{ + if (virtual_data != bdata) + return; + + TDM_INFO("deinit"); + + tdm_virtual_display_destroy_output_list(virtual_data); + + if (virtual_data->pipe[0] >= 0) + close(virtual_data->pipe[0]); + if (virtual_data->pipe[1] >= 0) + close(virtual_data->pipe[1]); + + free(virtual_data); + virtual_data = NULL; +} + +tdm_backend_data * +tdm_virtual_init(tdm_display *dpy, tdm_error *error) +{ + tdm_func_display virtual_func_display; + tdm_func_output virtual_func_output; + tdm_func_layer virtual_func_layer; + tdm_error ret; + + if (!dpy) { + TDM_ERR("display is null"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + if (virtual_data) { + TDM_ERR("failed: init twice"); + if (error) + *error = TDM_ERROR_BAD_REQUEST; + return NULL; + } + + virtual_data = calloc(1, sizeof(tdm_virtual_data)); + if (!virtual_data) { + TDM_ERR("alloc failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + LIST_INITHEAD(&virtual_data->output_list); + LIST_INITHEAD(&virtual_data->buffer_list); + + memset(&virtual_func_display, 0, sizeof(virtual_func_display)); + virtual_func_display.display_get_capability = virtual_display_get_capability; + virtual_func_display.display_get_outputs = virtual_display_get_outputs; + virtual_func_display.display_get_fd = virtual_display_get_fd; + virtual_func_display.display_handle_events = virtual_display_handle_events; + + memset(&virtual_func_output, 0, sizeof(virtual_func_output)); + virtual_func_output.output_get_capability = virtual_output_get_capability; + virtual_func_output.output_get_layers = virtual_output_get_layers; + virtual_func_output.output_wait_vblank = virtual_output_wait_vblank; + virtual_func_output.output_set_vblank_handler = virtual_output_set_vblank_handler; + virtual_func_output.output_commit = virtual_output_commit; + virtual_func_output.output_set_commit_handler = virtual_output_set_commit_handler; + virtual_func_output.output_set_mode = virtual_output_set_mode; + virtual_func_output.output_get_mode = virtual_output_get_mode; + + memset(&virtual_func_layer, 0, sizeof(virtual_func_layer)); + virtual_func_layer.layer_get_capability = virtual_layer_get_capability; + virtual_func_layer.layer_set_info = virtual_layer_set_info; + virtual_func_layer.layer_get_info = virtual_layer_get_info; + virtual_func_layer.layer_set_buffer = virtual_layer_set_buffer; + virtual_func_layer.layer_unset_buffer = virtual_layer_unset_buffer; + + ret = tdm_backend_register_func_display(dpy, &virtual_func_display); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_backend_register_func_output(dpy, &virtual_func_output); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_backend_register_func_layer(dpy, &virtual_func_layer); + if (ret != TDM_ERROR_NONE) + goto failed; + + virtual_data->dpy = dpy; + + if (pipe(virtual_data->pipe) < 0) { + TDM_ERR("failed get pipe: %m"); + ret = TDM_ERROR_OPERATION_FAILED; + goto failed; + } + + ret = tdm_virtual_display_create_output_list(virtual_data); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_virtual_display_create_layer_list(virtual_data); + if (ret != TDM_ERROR_NONE) + goto failed; + + if (error) + *error = TDM_ERROR_NONE; + + TDM_INFO("init success!"); + + return (tdm_backend_data *)virtual_data; +failed: + if (error) + *error = ret; + + tdm_virtual_deinit(virtual_data); + + TDM_ERR("init failed!"); + return NULL; +} + +tdm_backend_module tdm_backend_module_data = { + "Virtual", + "Samsung", + TDM_BACKEND_SET_ABI_VERSION(1, 1), + tdm_virtual_init, + tdm_virtual_deinit +}; diff --git a/backends/virtual/tdm_virtual.h b/backends/virtual/tdm_virtual.h new file mode 100644 index 0000000..2a25ab6 --- /dev/null +++ b/backends/virtual/tdm_virtual.h @@ -0,0 +1,76 @@ +#ifndef _TDM_VIRTUAL_H_ +#define _TDM_VIRTUAL_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* virtual backend functions (display) */ +tdm_error virtual_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps); +tdm_output** virtual_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error); +tdm_error virtual_display_get_fd(tdm_backend_data *bdata, int *fd); +tdm_error virtual_display_handle_events(tdm_backend_data *bdata); + +tdm_error virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps); +tdm_layer** virtual_output_get_layers(tdm_output *output, int *count, tdm_error *error); +tdm_error virtual_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data); +tdm_error virtual_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func); +tdm_error virtual_output_commit(tdm_output *output, int sync, void *user_data); +tdm_error virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func); +tdm_error virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode); +tdm_error virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode); + +tdm_error virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps); +tdm_error virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info); +tdm_error virtual_layer_get_info(tdm_layer *layer, tdm_info_layer *info); +tdm_error virtual_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer); +tdm_error virtual_layer_unset_buffer(tdm_layer *layer); + +#define RETURN_VAL_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + return val;\ + }\ +} + +#define GOTO_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + goto val;\ + }\ +} + +typedef struct _tdm_virtual_data +{ + tdm_display *dpy; + + int pipe[2]; + + struct list_head output_list; + struct list_head buffer_list; +} tdm_virtual_data; + +tdm_error tdm_virtual_display_create_output_list(tdm_virtual_data *virtual_data); +void tdm_virtual_display_destroy_output_list(tdm_virtual_data *virtual_data); +tdm_error tdm_virtual_display_create_layer_list(tdm_virtual_data *virtual_data); + +#endif /* _TDM_VIRTUAL_H_ */ diff --git a/backends/virtual/tdm_virtual_display.c b/backends/virtual/tdm_virtual_display.c new file mode 100644 index 0000000..185f10d --- /dev/null +++ b/backends/virtual/tdm_virtual_display.c @@ -0,0 +1,636 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm_virtual.h" + +typedef struct _tdm_virtual_output_data tdm_virtual_output_data; +typedef struct _tdm_virtual_layer_data tdm_virtual_layer_data; +typedef struct _tdm_virtual_event_data tdm_virtual_event_data; + +typedef enum { + TDM_VIRTUAL_EVENT_TYPE_WAIT, + TDM_VIRTUAL_EVENT_TYPE_COMMIT, +} tdm_virtual_event_type; + +struct _tdm_virtual_event_data { + struct list_head link; + + tdm_virtual_event_type type; + tdm_virtual_output_data *output_data; + void *user_data; +}; + +struct _tdm_virtual_output_data { + struct list_head link; + + /* data which are fixed at initializing */ + tdm_virtual_data *virtual_data; + + uint32_t pipe; + tdm_output_mode *output_mode; + tdm_output_type connector_type; + struct list_head layer_list; + tdm_virtual_layer_data *primary_layer; + + /* not fixed data below */ + tdm_output_vblank_handler vblank_func; + tdm_output_commit_handler commit_func; + + tdm_output_conn_status status; + + int mode_changed; + const tdm_output_mode *current_mode; + + tdm_event_loop_source *timer; + unsigned int timer_waiting; + struct list_head timer_event_list; +}; + +struct _tdm_virtual_layer_data { + struct list_head link; + + /* data which are fixed at initializing */ + tdm_virtual_data *virtual_data; + tdm_virtual_output_data *output_data; + tdm_layer_capability capabilities; + int zpos; + + /* not fixed data below */ + tdm_info_layer info; + int info_changed; + + tbm_surface_h display_buffer; + int display_buffer_changed; +}; + +static void +_tdm_virtual_display_cb_event(tdm_virtual_output_data *output_data, tdm_virtual_event_data *event_data, + unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec) +{ + switch (event_data->type) { + case TDM_VIRTUAL_EVENT_TYPE_WAIT: + if (output_data->vblank_func) + output_data->vblank_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data); + break; + case TDM_VIRTUAL_EVENT_TYPE_COMMIT: + if (output_data->commit_func) + output_data->commit_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data); + break; + default: + break; + } +} + +static tdm_error +_tdm_virtual_display_cb_timeout(void *user_data) +{ + tdm_virtual_output_data *output_data = user_data; + tdm_virtual_event_data *e = NULL, *ee = NULL; + unsigned int tv_sec, tv_usec; + static unsigned int sequence = 0; + struct timespec tp; + + sequence++; + + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) { + tv_sec = tp.tv_sec; + tv_usec = tp.tv_nsec / 1000; + } else { + tv_sec = tv_usec = 0; + } + + LIST_FOR_EACH_ENTRY_SAFE(e, ee, &output_data->timer_event_list, link) { + LIST_DEL(&e->link); + _tdm_virtual_display_cb_event(output_data, e, sequence, tv_sec, tv_usec); + free(e); + } + + return TDM_ERROR_NONE; +} + +static tdm_error +_tdm_virtual_display_wait_vblank(tdm_virtual_output_data *output_data, int interval, tdm_virtual_event_data *event_data) +{ + tdm_error ret; + unsigned int ms; + + RETURN_VAL_IF_FAIL(output_data->timer != NULL, TDM_ERROR_OPERATION_FAILED); + RETURN_VAL_IF_FAIL(output_data->output_mode->vrefresh > 0, TDM_ERROR_OPERATION_FAILED); + + if (output_data->timer_waiting) { + LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list); + return TDM_ERROR_NONE; + } + + ms = ((double)1000.0 / output_data->output_mode->vrefresh) * interval; + + ret = tdm_event_loop_source_timer_update(output_data->timer, ms); + if (ret != TDM_ERROR_NONE) + return ret; + + LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list); + + return TDM_ERROR_NONE; +} + +static void +_tdm_virtual_display_destroy_layer_list(tdm_virtual_data *virtual_data) +{ + tdm_virtual_output_data *o = NULL; + + LIST_FOR_EACH_ENTRY(o, &virtual_data->output_list, link) { + tdm_virtual_layer_data *l = NULL, *ll = NULL; + LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) { + LIST_DEL(&l->link); + free(l); + } + } +} + +tdm_error +tdm_virtual_display_create_layer_list(tdm_virtual_data *virtual_data) +{ + tdm_virtual_output_data *output_data = NULL; + tdm_error ret = TDM_ERROR_NONE; + + if (LIST_IS_EMPTY(&virtual_data->output_list)) { + TDM_ERR("no output"); + return TDM_ERROR_OPERATION_FAILED; + } + + /* The TDM virtual backend only support one output. */ + LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link) { + tdm_virtual_layer_data *layer_data = calloc(1, sizeof(tdm_virtual_layer_data)); + if (!layer_data) { + TDM_ERR("alloc failed"); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed; + } + + layer_data->virtual_data = virtual_data; + layer_data->output_data = output_data; + layer_data->zpos = 0; + + layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC; + output_data->primary_layer = layer_data; + + LIST_ADDTAIL(&layer_data->link, &output_data->layer_list); + } + + return TDM_ERROR_NONE; +failed: + _tdm_virtual_display_destroy_layer_list(virtual_data); + return ret; +} + +void +tdm_virtual_display_destroy_output_list(tdm_virtual_data *virtual_data) +{ + tdm_virtual_output_data *o = NULL, *oo = NULL; + + if (LIST_IS_EMPTY(&virtual_data->output_list)) + return; + + _tdm_virtual_display_destroy_layer_list(virtual_data); + + LIST_FOR_EACH_ENTRY_SAFE(o, oo, &virtual_data->output_list, link) { + LIST_DEL(&o->link); + + if (!LIST_IS_EMPTY(&o->timer_event_list)) { + tdm_virtual_event_data *e = NULL, *ee = NULL; + LIST_FOR_EACH_ENTRY_SAFE(e, ee, &o->timer_event_list, link) { + LIST_DEL(&e->link); + free(e); + } + } + + if (o->timer) + tdm_event_loop_source_remove(o->timer); + + free(o->output_mode); + free(o); + } +} + +tdm_error +tdm_virtual_display_create_output_list(tdm_virtual_data *virtual_data) +{ + tdm_virtual_output_data *output_data; + tdm_error ret; + + RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&virtual_data->output_list), TDM_ERROR_OPERATION_FAILED); + + output_data = calloc(1, sizeof(tdm_virtual_output_data)); + if (!output_data) { + TDM_ERR("alloc failed"); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_create; + } + + LIST_INITHEAD(&output_data->layer_list); + + output_data->virtual_data = virtual_data; + output_data->pipe = 0; + output_data->connector_type = TDM_OUTPUT_TYPE_Unknown; + output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED; + + output_data->output_mode = calloc(1, sizeof(tdm_output_mode)); + if (!output_data->output_mode) { + TDM_ERR("alloc failed"); + free(output_data); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_create; + } + + snprintf(output_data->output_mode->name, TDM_NAME_LEN, "640x480"); + output_data->output_mode->vrefresh = 30; + output_data->output_mode->clock = 25200; + output_data->output_mode->hdisplay = 640; + output_data->output_mode->hsync_start = 656; + output_data->output_mode->hsync_end = 752; + output_data->output_mode->htotal = 800; + output_data->output_mode->hskew = 0; + output_data->output_mode->vdisplay = 480; + output_data->output_mode->vsync_start = 490; + output_data->output_mode->vsync_end = 492; + output_data->output_mode->vtotal = 525; + output_data->output_mode->vscan = 0; + output_data->output_mode->flags = 0; + output_data->output_mode->type = 0; + + output_data->timer = tdm_event_loop_add_timer_handler(virtual_data->dpy, + _tdm_virtual_display_cb_timeout, + output_data, + &ret); + if (!output_data->timer) { + free(output_data); + return ret; + } + + LIST_INITHEAD(&output_data->timer_event_list); + + LIST_ADDTAIL(&output_data->link, &virtual_data->output_list); + + return TDM_ERROR_NONE; +failed_create: + tdm_virtual_display_destroy_output_list(virtual_data); + return ret; +} + +tdm_error +virtual_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps) +{ + RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER); + + caps->max_layer_count = -1; /* not defined */ + + return TDM_ERROR_NONE; +} + +tdm_output ** +virtual_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error) +{ + tdm_virtual_data *virtual_data = bdata; + tdm_virtual_output_data *output_data = NULL; + tdm_output **outputs; + tdm_error ret; + int i; + + RETURN_VAL_IF_FAIL(virtual_data, NULL); + RETURN_VAL_IF_FAIL(count, NULL); + + *count = 0; + LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link) + (*count)++; + + if (*count == 0) { + ret = TDM_ERROR_NONE; + goto failed_get; + } + + /* will be freed in frontend */ + outputs = calloc(*count, sizeof(tdm_virtual_output_data *)); + if (!outputs) { + TDM_ERR("failed: alloc memory"); + *count = 0; + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_get; + } + + i = 0; + LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link) + outputs[i++] = output_data; + + if (error) + *error = TDM_ERROR_NONE; + + return outputs; +failed_get: + if (error) + *error = ret; + return NULL; +} + +tdm_error +virtual_display_get_fd(tdm_backend_data *bdata, int *fd) +{ + tdm_virtual_data *virtual_data = bdata; + + RETURN_VAL_IF_FAIL(virtual_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER); + + *fd = virtual_data->pipe[0]; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_display_handle_events(tdm_backend_data *bdata) +{ + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps) +{ + tdm_virtual_output_data *output_data = output; + tdm_error ret; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER); + + memset(caps, 0, sizeof(tdm_caps_output)); + + snprintf(caps->maker, TDM_NAME_LEN, "virtual"); + snprintf(caps->model, TDM_NAME_LEN, "virtual"); + snprintf(caps->name, TDM_NAME_LEN, "virtual"); + + caps->status = output_data->status; + caps->type = output_data->connector_type; + caps->type_id = 0; + + caps->mode_count = 1; + caps->modes = calloc(1, sizeof(tdm_output_mode)); + if (!caps->modes) { + ret = TDM_ERROR_OUT_OF_MEMORY; + TDM_ERR("alloc failed\n"); + goto failed_get; + } + + *caps->modes = *output_data->output_mode; + + caps->mmWidth = 640; + caps->mmHeight = 480; + caps->subpixel = 1; + + caps->min_w = -1; + caps->min_h = -1; + caps->max_w = -1; + caps->max_h = -1; + caps->preferred_align = -1; + + caps->prop_count = 0; + + return TDM_ERROR_NONE; +failed_get: + memset(caps, 0, sizeof(tdm_caps_output)); + return ret; +} + +tdm_layer ** +virtual_output_get_layers(tdm_output *output, int *count, tdm_error *error) +{ + tdm_virtual_output_data *output_data = output; + tdm_virtual_layer_data *layer_data = NULL; + tdm_layer **layers; + tdm_error ret; + int i; + + RETURN_VAL_IF_FAIL(output_data, NULL); + RETURN_VAL_IF_FAIL(count, NULL); + + *count = 0; + LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) + (*count)++; + + if (*count == 0) { + ret = TDM_ERROR_NONE; + goto failed_get; + } + + /* will be freed in frontend */ + layers = calloc(*count, sizeof(tdm_virtual_layer_data *)); + if (!layers) { + TDM_ERR("failed: alloc memory"); + *count = 0; + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_get; + } + + i = 0; + LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) + layers[i++] = layer_data; + + if (error) + *error = TDM_ERROR_NONE; + + return layers; +failed_get: + if (error) + *error = ret; + return NULL; +} + +tdm_error +virtual_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data) +{ + tdm_virtual_output_data *output_data = output; + tdm_virtual_event_data *event_data; + tdm_error ret; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + + event_data = calloc(1, sizeof(tdm_virtual_event_data)); + if (!event_data) { + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + event_data->type = TDM_VIRTUAL_EVENT_TYPE_WAIT; + event_data->output_data = output_data; + event_data->user_data = user_data; + + ret = _tdm_virtual_display_wait_vblank(output_data, interval, event_data); + if (ret != TDM_ERROR_NONE) { + free(event_data); + return ret; + } + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER); + + output_data->vblank_func = func; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_commit(tdm_output *output, int sync, void *user_data) +{ + tdm_virtual_output_data *output_data = output; + tdm_virtual_event_data *event_data; + tdm_error ret; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + + event_data = calloc(1, sizeof(tdm_virtual_event_data)); + if (!event_data) { + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + event_data->type = TDM_VIRTUAL_EVENT_TYPE_COMMIT; + event_data->output_data = output_data; + event_data->user_data = user_data; + + ret = _tdm_virtual_display_wait_vblank(output_data, 1, event_data); + if (ret != TDM_ERROR_NONE) { + free(event_data); + return ret; + } + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER); + + output_data->commit_func = func; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER); + + output_data->current_mode = mode; + output_data->mode_changed = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER); + + *mode = output_data->current_mode; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER); + + memset(caps, 0, sizeof(tdm_caps_layer)); + + caps->capabilities = layer_data->capabilities; + caps->zpos = layer_data->zpos; + + caps->format_count = 2; + caps->formats = calloc(caps->format_count, sizeof(tbm_format)); + if (!caps->formats) { + TDM_ERR("alloc failed\n"); + free(caps->formats); + memset(caps, 0, sizeof(tdm_caps_layer)); + return TDM_ERROR_OUT_OF_MEMORY; + } + + caps->formats[0] = TBM_FORMAT_ARGB8888; + caps->formats[1] = TBM_FORMAT_XRGB8888; + + caps->prop_count = 0; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER); + + layer_data->info = *info; + layer_data->info_changed = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_get_info(tdm_layer *layer, tdm_info_layer *info) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER); + + *info = layer_data->info; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER); + + layer_data->display_buffer = buffer; + layer_data->display_buffer_changed = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_unset_buffer(tdm_layer *layer) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + + layer_data->display_buffer = NULL; + layer_data->display_buffer_changed = 1; + + return TDM_ERROR_NONE; +} diff --git a/configure.ac b/configure.ac index 3d13ec7..81d3828 100644 --- a/configure.ac +++ b/configure.ac @@ -100,6 +100,7 @@ AC_OUTPUT([ src/Makefile backends/Makefile backends/dummy/Makefile + backends/virtual/Makefile client/libtdm-client.pc client/Makefile tools/Makefile diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 5bcae43..c915e01 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -114,6 +114,7 @@ rm -f %{_unitdir_user}/basic.target.wants/tdm-socket-user.path %license COPYING %{_libdir}/libtdm.so.* %{_libdir}/tdm/libtdm-dummy.so +%{_libdir}/tdm/libtdm-virtual.so %attr(750,root,root) %{_bindir}/tdm-monitor %{_unitdir_user}/tdm-socket-user.path %{_unitdir_user}/tdm-socket-user.service diff --git a/src/tdm.c b/src/tdm.c index 3bbd6c3..6999b9e 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -797,6 +797,11 @@ _tdm_display_setup(tdm_private_display *private_display) } } + TDM_INFO("loading a %s backend", TDM_VIRTUAL_MODULE); + ret = _tdm_display_load_module_with_file(private_display, TDM_VIRTUAL_MODULE); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, failed_update); + TDM_GOTO_IF_FAIL(private_display->virtual_module != NULL, failed_update); + return TDM_ERROR_NONE; failed_update: @@ -1010,6 +1015,9 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display, if (!strncmp(file, TDM_DUMMY_MODULE, TDM_NAME_LEN)) private_display->dummy_module = private_module; + if (!strncmp(file, TDM_VIRTUAL_MODULE, TDM_NAME_LEN)) + private_display->virtual_module = private_module; + private_module->bdata = bdata; if (ret != TDM_ERROR_NONE) { diff --git a/src/tdm_macro.h b/src/tdm_macro.h index 24899c3..d831146 100644 --- a/src/tdm_macro.h +++ b/src/tdm_macro.h @@ -86,6 +86,7 @@ extern "C" { /* common backend names *****************************************************/ #define TDM_DEFAULT_MODULE "libtdm-default.so" #define TDM_DUMMY_MODULE "libtdm-dummy.so" +#define TDM_VIRTUAL_MODULE "libtdm-virtual.so" /* dump directory ***********************************************************/ #define TDM_DUMP_DIR "/tmp" diff --git a/src/tdm_private_types.h b/src/tdm_private_types.h index 365ea7d..d74f4f2 100644 --- a/src/tdm_private_types.h +++ b/src/tdm_private_types.h @@ -166,6 +166,7 @@ struct _tdm_private_display { struct list_head module_list; tdm_private_module *dummy_module; + tdm_private_module *virtual_module; tdm_private_module *current_module; //setted only when loading tdm_private_module *pp_module; //pp-support backend tdm_private_module *capture_module; //TODO: remove later -- 2.7.4