From e884340a9a401eb3928ae0e0e6da5c56040f8bbd Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 24 Feb 2022 15:01:35 +0900 Subject: [PATCH 01/16] Add an example of tdm backend Change-Id: I836ba2b5b88d3799c7b095051e255779d653fa10 --- examples/meson.build | 14 ++- examples/tdm-backend.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++++ meson.build | 3 + packaging/libds.spec | 1 + 4 files changed, 261 insertions(+), 5 deletions(-) create mode 100644 examples/tdm-backend.c diff --git a/examples/meson.build b/examples/meson.build index a107a77..530cbdd 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,15 +1,18 @@ -project('libds-samples', 'c', - version : '0.1', - default_options : ['warning_level=3']) - common_deps = [ + dep_libds, dependency('wayland-server', required: true), - dependency('libds', required: true), ] executable('wl-backend', 'wl-backend.c', dependencies: common_deps, + install_dir: libds_bindir, + install : true) + +executable('tdm-backend', + 'tdm-backend.c', + dependencies: common_deps, + install_dir: libds_bindir, install : true) executable('tinyds', @@ -19,4 +22,5 @@ executable('tinyds', dependency('pixman-1', required: true), dependency('libdrm', required: true), ], + install_dir: libds_bindir, install : true) diff --git a/examples/tdm-backend.c b/examples/tdm-backend.c new file mode 100644 index 0000000..15f5711 --- /dev/null +++ b/examples/tdm-backend.c @@ -0,0 +1,248 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define WIDTH 1280 +#define HEIGHT 720 + +struct server +{ + struct ds_backend *backend; + struct ds_output *output; + struct ds_allocator *allocator; + struct ds_swapchain *swapchain; + struct ds_buffer *front_buffer; + + struct wl_display *display; + struct wl_event_source *stdin_source; + + struct wl_listener new_output; + struct wl_listener output_destroy; + struct wl_listener output_frame; + + int width, height; +}; + +struct server _server; + +static void init_server(struct server *server, struct wl_display *display); +static void fini_server(struct server *server); +static void output_handle_destroy(struct wl_listener *listener, void *data); +static void output_handle_frame(struct wl_listener *listener, void *data); +static void draw_output(struct server *server); +static int stdin_dispatch(int fd, uint32_t mask, void *data); + +int +main(void) +{ + struct server *server = &_server; + struct wl_display *display; + + ds_log_init(DS_DBG, NULL); + + display = wl_display_create(); + assert(display); + + server->width = WIDTH; + server->height = HEIGHT; + + init_server(server, display); + + ds_backend_start(server->backend); + + draw_output(server); + + struct wl_event_loop *loop = wl_display_get_event_loop(display); + server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO, + WL_EVENT_READABLE, stdin_dispatch, server); + + wl_display_run(display); + + fini_server(server); + wl_display_destroy(display); + return 0; +} + +static void +backend_handle_new_output(struct wl_listener *listener, void *data) +{ + struct server *server; + struct ds_output *output; + + server = wl_container_of(listener, server, new_output); + output = data; + ds_inf("New output(%p)", output); + + + if (server->output) + return; + + server->output = output; + + server->output_destroy.notify = output_handle_destroy; + ds_output_add_destroy_listener(server->output, + &server->output_destroy); + + server->output_frame.notify = output_handle_frame; + ds_output_add_frame_listener(server->output, + &server->output_frame); +} + +static void +init_server(struct server *server, struct wl_display *display) +{ + server->display = display; + server->front_buffer = NULL; + + server->backend = ds_tdm_backend_create(display); + assert(server->backend); + + + server->new_output.notify = backend_handle_new_output; + ds_backend_add_new_output_listener(server->backend, + &server->new_output); + + server->allocator = ds_tbm_allocator_create(); + assert(server->allocator); + + server->swapchain = ds_swapchain_create(server->allocator, + server->width, server->height, WL_SHM_FORMAT_XRGB8888); + assert(server->swapchain); +} + +static void +fini_server(struct server *server) +{ + wl_list_remove(&server->new_output.link); + wl_list_remove(&server->output_destroy.link); + wl_list_remove(&server->output_frame.link); + if (server->front_buffer) + ds_buffer_unlock(server->front_buffer); + ds_swapchain_destroy(server->swapchain); + ds_allocator_destroy(server->allocator); +} + +static void +output_handle_destroy(struct wl_listener *listener, + void *data __attribute__((unused))) +{ + struct server *server = + wl_container_of(listener, server, output_destroy); + wl_display_terminate(server->display); +} + +static void +paint_pixels(void *image, int padding, int width, int height, uint32_t time) +{ + const int halfh = padding + (height - padding * 2) / 2; + const int halfw = padding + (width - padding * 2) / 2; + int ir, or; + uint32_t *pixel = image; + int y; + + /* squared radii thresholds */ + or = (halfw < halfh ? halfw : halfh) - 8; + ir = or - 32; + or *= or; + ir *= ir; + + pixel += padding * width; + for (y = padding; y < height - padding; y++) { + int x; + int y2 = (y - halfh) * (y - halfh); + + pixel += padding; + for (x = padding; x < width - padding; x++) { + uint32_t v; + + /* squared distance from center */ + int r2 = (x - halfw) * (x - halfw) + y2; + + if (r2 < ir) + v = (r2 / 32 + time / 64) * 0x0080401; + else if (r2 < or) + v = (y + time / 32) * 0x0080401; + else + v = (x + time / 16) * 0x0080401; + v &= 0x00ffffff; + + /* cross if compositor uses X from XRGB as alpha */ + if (abs(x - y) > 6 && abs(x + y - height) > 6) + v |= 0xff000000; + + *pixel++ = v; + } + + pixel += padding; + } +} + +static inline int64_t +timespec_to_msec(const struct timespec *a) +{ + return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; +} + +static void +output_handle_frame(struct wl_listener *listener, + void *data __attribute__((unused))) +{ + struct server *server = + wl_container_of(listener, server, output_frame); + draw_output(server); +} + +static void +draw_output(struct server *server) +{ + struct ds_buffer *buffer; + void *data; + uint32_t format; + size_t stride; + struct timespec now; + uint32_t frame_time_msec; + + ds_dbg("Redraw output"); + + clock_gettime(CLOCK_MONOTONIC, &now); + frame_time_msec = timespec_to_msec(&now); + + buffer = ds_swapchain_acquire(server->swapchain, NULL); + assert(buffer); + + assert(ds_buffer_begin_data_ptr_access(buffer, + 0, &data, &format, &stride) == true); + + paint_pixels(data, 20, server->width, server->height, frame_time_msec); + + ds_buffer_end_data_ptr_access(buffer); + + ds_output_attach_buffer(server->output, buffer); + ds_output_commit(server->output); + + if (server->front_buffer) + ds_buffer_unlock(server->front_buffer); + + server->front_buffer = buffer; +} + +static int +stdin_dispatch(int fd, uint32_t mask, void *data) +{ + struct server *server = data; + + wl_display_terminate(server->display); + + return 1; +} diff --git a/meson.build b/meson.build index 24506b6..36bfda9 100644 --- a/meson.build +++ b/meson.build @@ -15,6 +15,7 @@ libds_version_minor = version_arr[1] libds_version_patch = version_arr[2] dir_prefix = get_option('prefix') +libds_bindir = join_paths(dir_prefix, get_option('bindir')) libds_inc = include_directories('include') common_inc = [ include_directories('.'), libds_inc ] @@ -24,8 +25,10 @@ cdata.set('LIBDS_VERSION_MAJOR', libds_version_major) cdata.set('LIBDS_VERSION_MINOR', libds_version_minor) cdata.set('LIBDS_VERSION_PATCH', libds_version_patch) + subdir('include') subdir('src') +subdir('examples') configure_file(output: 'config.h', install: false, configuration: cdata) diff --git a/packaging/libds.spec b/packaging/libds.spec index aaf79b3..69d58f6 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -57,3 +57,4 @@ ninja -C builddir install %{_includedir}/* %{_libdir}/pkgconfig/libds.pc %{_libdir}/libds.so +%{_bindir}/* -- 2.7.4 From 4675302df43ece109a784a0ddfcf4064eb377955 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 24 Feb 2022 15:59:36 +0900 Subject: [PATCH 02/16] Move ds_backend implementation no functional changes Change-Id: If598451fc62155396478358b3c617c14112c8449 --- src/libds/{backend => }/backend.c | 0 src/libds/backend/meson.build | 4 ---- src/libds/meson.build | 1 + 3 files changed, 1 insertion(+), 4 deletions(-) rename src/libds/{backend => }/backend.c (100%) diff --git a/src/libds/backend/backend.c b/src/libds/backend.c similarity index 100% rename from src/libds/backend/backend.c rename to src/libds/backend.c diff --git a/src/libds/backend/meson.build b/src/libds/backend/meson.build index e095efd..c24f074 100644 --- a/src/libds/backend/meson.build +++ b/src/libds/backend/meson.build @@ -1,6 +1,2 @@ -libds_files += files( - 'backend.c', -) - subdir('wayland') subdir('tdm') diff --git a/src/libds/meson.build b/src/libds/meson.build index 8a88b62..e7f2970 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -19,6 +19,7 @@ libds_files = [ 'xdg_shell/xdg_surface.c', 'xdg_shell/xdg_toplevel.c', 'pixel_format.c', + 'backend.c', ] protocols = { -- 2.7.4 From 16a756160fbfa67eabb7c3880c533fd6607ecbf5 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 24 Feb 2022 17:36:08 +0900 Subject: [PATCH 03/16] Flesh out ds_buffer Change-Id: I3c8bb8706b3a1bfdb05eeb31eb9715fd96933ed5 --- include/libds/buffer.h | 11 ++++++++++ src/libds/buffer.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/include/libds/buffer.h b/include/libds/buffer.h index c91cba7..b3d38fa 100644 --- a/include/libds/buffer.h +++ b/include/libds/buffer.h @@ -33,6 +33,13 @@ struct ds_shm_attributes off_t offset; }; +struct ds_buffer_resource_interface +{ + const char *name; + bool (*is_instance)(struct wl_resource *resource); + struct ds_buffer *(*from_resource)(struct wl_resource *resource); +}; + struct ds_buffer * ds_buffer_from_resource(struct wl_resource *resource); @@ -67,6 +74,10 @@ ds_buffer_begin_data_ptr_access(struct ds_buffer *buffer, void ds_buffer_end_data_ptr_access(struct ds_buffer *buffer); +void +ds_buffer_register_resource_interface( + const struct ds_buffer_resource_interface *iface); + #ifdef __cplusplus } #endif diff --git a/src/libds/buffer.c b/src/libds/buffer.c index 70de23f..167d3a7 100644 --- a/src/libds/buffer.c +++ b/src/libds/buffer.c @@ -6,8 +6,12 @@ #include "libds/log.h" #include "libds/interfaces/buffer.h" +static struct wl_array buffer_resource_interfaces = {0}; + static void buffer_consider_destroy(struct ds_buffer *buffer); static bool ds_resource_is_buffer(struct wl_resource *resource); +static const struct ds_buffer_resource_interface * +get_buffer_resource_iface(struct wl_resource *resource); WL_EXPORT void ds_buffer_init(struct ds_buffer *buffer, const struct ds_buffer_interface *iface, @@ -25,6 +29,7 @@ WL_EXPORT struct ds_buffer * ds_buffer_from_resource(struct wl_resource *resource) { struct ds_buffer *buffer; + const struct ds_buffer_resource_interface *iface; assert(resource && ds_resource_is_buffer(resource)); @@ -39,8 +44,19 @@ ds_buffer_from_resource(struct wl_resource *resource) buffer = ds_buffer_lock(&shm_client_buffer->base); } else { - // TODO; - buffer = NULL; + iface = get_buffer_resource_iface(resource); + if (!iface) { + ds_err("Unknown buffer type"); + return NULL; + } + + buffer = iface->from_resource(resource); + if (!buffer) { + ds_err("Failed to create %s buffer", iface->name); + return NULL; + } + + buffer = ds_buffer_lock(buffer); } return buffer; @@ -129,6 +145,28 @@ ds_buffer_get_size(struct ds_buffer *buffer, int *out_width, int *out_height) *out_height = buffer->height; } +WL_EXPORT void +ds_buffer_register_resource_interface( + const struct ds_buffer_resource_interface *iface) +{ + const struct ds_buffer_resource_interface **iface_ptr; + + assert(iface); + assert(iface->is_instance); + assert(iface->from_resource); + + wl_array_for_each(iface_ptr, &buffer_resource_interfaces) { + if (*iface_ptr == iface) { + ds_dbg("ds_buffer_resource_interface %s has already " + "been registered", iface->name); + return; + } + } + + iface_ptr = wl_array_add(&buffer_resource_interfaces, sizeof(iface)); + *iface_ptr = iface; +} + static void buffer_consider_destroy(struct ds_buffer *buffer) { @@ -147,3 +185,17 @@ ds_resource_is_buffer(struct wl_resource *resource) return strcmp(wl_resource_get_class(resource), wl_buffer_interface.name) == 0; } + +static const struct ds_buffer_resource_interface * +get_buffer_resource_iface(struct wl_resource *resource) +{ + struct ds_buffer_resource_interface **iface_ptr; + + wl_array_for_each(iface_ptr, &buffer_resource_interfaces) { + if ((*iface_ptr)->is_instance(resource)) { + return *iface_ptr; + } + } + + return NULL; +} -- 2.7.4 From 2a4357ef8251e36bfa4f81a83766bb4e05163dad Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 24 Feb 2022 17:36:44 +0900 Subject: [PATCH 04/16] Add tinyds on tdm (wip) Change-Id: I058c8c05db6e6460caf50ad6eee59af2e9d13ff4 --- examples/meson.build | 11 ++ examples/tdm-backend.c | 1 - examples/tinyds-helper.c | 18 ++ examples/tinyds-helper.h | 15 ++ examples/tinyds-tdm.c | 475 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 519 insertions(+), 1 deletion(-) create mode 100644 examples/tinyds-helper.c create mode 100644 examples/tinyds-helper.h create mode 100644 examples/tinyds-tdm.c diff --git a/examples/meson.build b/examples/meson.build index 530cbdd..54f1ba7 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -24,3 +24,14 @@ executable('tinyds', ], install_dir: libds_bindir, install : true) + +executable('tinyds-tdm', + ['tinyds-tdm.c', 'tinyds-helper.c'], + dependencies: [ + common_deps, + dependency('pixman-1', required: true), + dependency('libdrm', required: true), + dependency('libtbm', required: true), + ], + install_dir: libds_bindir, + install : true) diff --git a/examples/tdm-backend.c b/examples/tdm-backend.c index 15f5711..ee39f06 100644 --- a/examples/tdm-backend.c +++ b/examples/tdm-backend.c @@ -108,7 +108,6 @@ init_server(struct server *server, struct wl_display *display) server->backend = ds_tdm_backend_create(display); assert(server->backend); - server->new_output.notify = backend_handle_new_output; ds_backend_add_new_output_listener(server->backend, &server->new_output); diff --git a/examples/tinyds-helper.c b/examples/tinyds-helper.c new file mode 100644 index 0000000..ef077b3 --- /dev/null +++ b/examples/tinyds-helper.c @@ -0,0 +1,18 @@ +#include "tinyds-helper.h" + +#include +#include + +bool +tinyds_renderer_init_display(struct tinyds_renderer *renderer, + struct wl_display *display) +{ + if (wl_display_init_shm(display)) { + ds_err("Could not initialize shm"); + return false; + } + + renderer->dummy = 1; + + return true; +} diff --git a/examples/tinyds-helper.h b/examples/tinyds-helper.h new file mode 100644 index 0000000..44415d6 --- /dev/null +++ b/examples/tinyds-helper.h @@ -0,0 +1,15 @@ +#ifndef TINYDS_HELPER_H +#define TINYDS_HELPER_H + +#include +#include + +struct tinyds_renderer { + int dummy; +}; + +bool +tinyds_renderer_init_display(struct tinyds_renderer *renderer, + struct wl_display *display); + +#endif diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c new file mode 100644 index 0000000..23ff48e --- /dev/null +++ b/examples/tinyds-tdm.c @@ -0,0 +1,475 @@ +#include "tinyds-helper.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TINYDS_UNUSED __attribute__((unused)) + +#define OUTPUT_WIDTH 1280 +#define OUTPUT_HEIGHT 720 + +struct tinyds_output +{ + struct tinyds_server *server; + struct ds_output *ds_output; + struct ds_allocator *allocator; + struct ds_swapchain *swapchain; + struct ds_buffer *front_buffer; + + struct wl_listener output_destroy; + struct wl_listener output_frame; + + int width, height; + + bool drawable; + bool damaged; +}; + +struct tinyds_server +{ + struct wl_display *display; + + struct ds_backend *backend; + struct ds_compositor *compositor; + struct ds_xdg_shell *xdg_shell; + + struct tinyds_output *output; + struct tinyds_renderer renderer; + + struct wl_list views; + + struct wl_listener new_output; + struct wl_listener new_xdg_surface; +}; + +struct tinyds_view +{ + struct tinyds_server *server; + + struct ds_xdg_surface *xdg_surface; + + struct wl_listener xdg_surface_map; + struct wl_listener xdg_surface_unmap; + struct wl_listener xdg_surface_destroy; + struct wl_listener surface_commit; + struct wl_list link; // tinyds_server::views + + int x, y; + bool mapped; +}; + +struct tinyds_server _tinyds; + +static bool init_server(struct tinyds_server *server, struct wl_display *display); +static void output_handle_destroy(struct wl_listener *listener, void *data); +static void output_handle_frame(struct wl_listener *listener, void *data); +static void draw_server(struct tinyds_server *server); +static void draw_server_with_damage(struct tinyds_server *server); +static void draw_output(struct tinyds_output *output); +static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); + +int +main(void) +{ + struct tinyds_server *server = &_tinyds; + struct wl_display *display; + const char *socket; + + ds_log_init(DS_DBG, NULL); + + display = wl_display_create(); + assert(display); + + assert(init_server(server, display) == true); + + assert(tinyds_renderer_init_display(&server->renderer, display)); + + socket = wl_display_add_socket_auto(display); + assert(socket); + + ds_backend_start(server->backend); + + setenv("WAYLAND_DISPLAY", socket, true); + + ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket); + + wl_display_destroy(display); + + return 0; +} + +static void +view_handle_xdg_surface_map(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, xdg_surface_map); + view->mapped = true; +} + +static void +view_handle_xdg_surface_unmap(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, xdg_surface_unmap); + view->mapped = false; +} + +static void +view_handle_xdg_surface_destroy(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, xdg_surface_destroy); + + draw_server_with_damage(view->server); + + wl_list_remove(&view->xdg_surface_destroy.link); + wl_list_remove(&view->xdg_surface_map.link); + wl_list_remove(&view->xdg_surface_unmap.link); + wl_list_remove(&view->surface_commit.link); + wl_list_remove(&view->link); + free(view); +} + +static void +view_handle_surface_commit(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, surface_commit); + draw_server_with_damage(view->server); +} + +static void +server_new_xdg_surface(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct tinyds_view *view; + struct ds_xdg_surface *xdg_surface; + + server = wl_container_of(listener, server, new_xdg_surface); + xdg_surface = data; + + ds_inf("New xdg_surface(%p)", (void *)xdg_surface); + + view = calloc(1, sizeof *view); + view->server = server; + view->xdg_surface = xdg_surface; + + view->xdg_surface_map.notify = view_handle_xdg_surface_map; + ds_xdg_surface_add_map_listener(xdg_surface, + &view->xdg_surface_map); + + view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap; + ds_xdg_surface_add_unmap_listener(xdg_surface, + &view->xdg_surface_unmap); + + view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy; + ds_xdg_surface_add_destroy_listener(xdg_surface, + &view->xdg_surface_destroy); + + view->surface_commit.notify = view_handle_surface_commit; + ds_surface_add_commit_listener( + ds_xdg_surface_get_surface(xdg_surface), + &view->surface_commit); + + wl_list_insert(server->views.prev, &view->link); +} + +static void +backend_handle_new_output(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct tinyds_output *output; + struct ds_output *ds_output; + + server = wl_container_of(listener, server, new_output); + ds_output = data; + + ds_inf("New output(%p)", ds_output); + + if (server->output) + return; + + output = calloc(1, sizeof *output); + if (!output) + return; + + output->server = server; + output->ds_output = ds_output; + + output->output_destroy.notify = output_handle_destroy; + ds_output_add_destroy_listener(ds_output, + &output->output_destroy); + + output->output_frame.notify = output_handle_frame; + ds_output_add_frame_listener(ds_output, + &output->output_frame); + + server->output = output; +} + +static bool +init_server(struct tinyds_server *server, struct wl_display *display) +{ + server->display = display; + + wl_list_init(&server->views); + + if (wl_display_init_shm(display) != 0) + return false; + + server->backend = ds_tdm_backend_create(display); + if (!server->backend) + return false; + + server->new_output.notify = backend_handle_new_output; + ds_backend_add_new_output_listener(server->backend, + &server->new_output); + + server->compositor = ds_compositor_create(display); + if (!server->compositor) { + ds_backend_destroy(server->backend); + return false; + } + + server->xdg_shell = ds_xdg_shell_create(display); + if (!server->xdg_shell) { + ds_backend_destroy(server->backend); + return false; + } + + server->new_xdg_surface.notify = server_new_xdg_surface; + ds_xdg_shell_add_new_surface_listener(server->xdg_shell, + &server->new_xdg_surface); + + return true; +} + +static void +output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED) +{ + struct tinyds_output *output = + wl_container_of(listener, output, output_destroy); + + wl_list_remove(&output->output_destroy.link); + wl_list_remove(&output->output_frame.link); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + + if (output->swapchain) + ds_swapchain_destroy(output->swapchain); + + if (output->allocator) + ds_allocator_destroy(output->allocator); + + wl_display_terminate(output->server->display); + + output->server->output = NULL; + + free(output); +} + +static void +output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED) +{ + struct tinyds_output *output = + wl_container_of(listener, output, output_frame); + +} + +static void +draw_server(struct tinyds_server *server) +{ + draw_output(server->output); +} + +static void +draw_server_with_damage(struct tinyds_server *server) +{ + server->output->damaged = true; + draw_output(server->output); +} + +static void image_fill_color(pixman_image_t *image, + uint8_t r, uint8_t g, uint8_t b); +static pixman_image_t *image_from_buffer(struct ds_buffer *buffer, + enum ds_buffer_data_ptr_access_flag access_flag); +static void view_send_frame_done(struct tinyds_view *view); + +static void +draw_output(struct tinyds_output *output) +{ + struct ds_buffer *output_buffer; + pixman_image_t *output_image; + struct tinyds_view *view; + + if (!output->drawable || !output->damaged) + return; + + output_buffer = ds_swapchain_acquire(output->swapchain, NULL); + if (!output_buffer) + return; + + output_image = image_from_buffer(output_buffer, + DS_BUFFER_DATA_PTR_ACCESS_WRITE); + if (!output_image) { + ds_buffer_unlock(output_buffer); + return; + } + + image_fill_color(output_image, 80, 80, 80); + + wl_list_for_each(view, &output->server->views, link) { + if (!view->mapped) + continue; + draw_view(view, output_image); + } + pixman_image_unref(output_image); + + ds_output_attach_buffer(output->ds_output, output_buffer); + ds_output_commit(output->ds_output); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + output->front_buffer = output_buffer; + + output->drawable = false; + output->damaged = false; +} + +static void +draw_view(struct tinyds_view *view, pixman_image_t *dst_image) +{ + struct ds_buffer *buffer; + pixman_image_t *src_image; + + buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + if (!buffer) + return; + + src_image = image_from_buffer(buffer, + DS_BUFFER_DATA_PTR_ACCESS_READ); + pixman_image_composite32(PIXMAN_OP_OVER, + src_image, + NULL, + dst_image, + 0, 0, 0, 0, 0, 0, + pixman_image_get_width(src_image), + pixman_image_get_height(src_image)); + pixman_image_unref(src_image); + + view_send_frame_done(view); +} + +static pixman_color_t * +color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b) +{ + tmp->alpha = 65535; + tmp->red = (r << 8) + r; + tmp->green = (g << 8) + g; + tmp->blue = (b << 8) +b; + + return tmp; +} + +static void +image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b) +{ + pixman_image_t *color_image; + pixman_color_t color; + + color_rgb888(&color, r, g, b); + color_image = pixman_image_create_solid_fill(&color); + pixman_image_composite32(PIXMAN_OP_SRC, + color_image, + NULL, + image, + 0, 0, 0, 0, 0, 0, + pixman_image_get_width(image), + pixman_image_get_height(image)); + pixman_image_unref(color_image); +} + +static void +destroy_pixman_image(pixman_image_t *image TINYDS_UNUSED, void *data) +{ + struct ds_buffer *buffer = data; + ds_buffer_end_data_ptr_access(buffer); + ds_buffer_unlock(buffer); +} + +static uint32_t +convert_drm_format_to_pixman(uint32_t fmt) +{ + switch (fmt) { + case DRM_FORMAT_XRGB8888: + return PIXMAN_x8r8g8b8; + case DRM_FORMAT_ARGB8888: + return PIXMAN_a8r8g8b8; + default: + assert(0 && "not reached"); + } +} + +static pixman_image_t * +image_from_buffer(struct ds_buffer *buffer, + enum ds_buffer_data_ptr_access_flag access_flag) +{ + pixman_image_t *image; + void *data; + uint32_t format; + size_t stride; + int width, height; + + ds_buffer_get_size(buffer, &width, &height); + + if (!ds_buffer_begin_data_ptr_access(buffer, + access_flag, &data, &format, &stride)) + return NULL; + + format = convert_drm_format_to_pixman(format); + image = pixman_image_create_bits(format, width, height, data, stride); + if (!image) { + ds_buffer_end_data_ptr_access(buffer); + return NULL; + } + + pixman_image_set_destroy_function(image, + destroy_pixman_image, ds_buffer_lock(buffer)); + + return image; +} + +static void +view_send_frame_done(struct tinyds_view *view) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), + &now); +} -- 2.7.4 From e391a44a321ba7962eab3e51029cf3051d05d072 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 2 Mar 2022 11:08:12 +0900 Subject: [PATCH 05/16] Add missing cleanup Change-Id: I4b035f0c5614025355b9d5f213f28424bfdad1a4 --- src/libds/backend/tdm/backend.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libds/backend/tdm/backend.c b/src/libds/backend/tdm/backend.c index 2772f84..c893702 100644 --- a/src/libds/backend/tdm/backend.c +++ b/src/libds/backend/tdm/backend.c @@ -91,6 +91,7 @@ tdm_backend_destroy(struct ds_tdm_backend *tdm) wl_event_source_remove(tdm->tdm_event); close(tdm->fd); tdm_display_deinit(tdm->tdm_display); + ds_backend_finish(&tdm->base); free(tdm); } -- 2.7.4 From ed5099f54173a885b85e81bcf950f5fc1ba2ba2c Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 2 Mar 2022 11:36:44 +0900 Subject: [PATCH 06/16] Add build options of backends Change-Id: I344dd28196280c91f4c3fa064bc60f5a439b3fa2 --- examples/meson.build | 34 ++++++++++++++++++---------------- include/meson.build | 12 +++++++++++- meson.build | 12 +++++------- meson_options.txt | 1 + src/libds/{allocator => }/allocator.c | 0 src/libds/allocator/meson.build | 12 ++++++++++++ src/libds/backend/meson.build | 15 ++++++++++++++- src/libds/backend/tdm/meson.build | 26 +++++++++++++++++++++++++- src/libds/meson.build | 21 +++++++++++++++++---- 9 files changed, 103 insertions(+), 30 deletions(-) create mode 100644 meson_options.txt rename src/libds/{allocator => }/allocator.c (100%) create mode 100644 src/libds/allocator/meson.build diff --git a/examples/meson.build b/examples/meson.build index 54f1ba7..66336f5 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -9,12 +9,6 @@ executable('wl-backend', install_dir: libds_bindir, install : true) -executable('tdm-backend', - 'tdm-backend.c', - dependencies: common_deps, - install_dir: libds_bindir, - install : true) - executable('tinyds', 'tinyds.c', dependencies: [ @@ -25,13 +19,21 @@ executable('tinyds', install_dir: libds_bindir, install : true) -executable('tinyds-tdm', - ['tinyds-tdm.c', 'tinyds-helper.c'], - dependencies: [ - common_deps, - dependency('pixman-1', required: true), - dependency('libdrm', required: true), - dependency('libtbm', required: true), - ], - install_dir: libds_bindir, - install : true) +if features.get('tdm-backend') + executable('tdm-backend', + 'tdm-backend.c', + dependencies: common_deps, + install_dir: libds_bindir, + install : true) + + executable('tinyds-tdm', + ['tinyds-tdm.c', 'tinyds-helper.c'], + dependencies: [ + common_deps, + dependency('pixman-1', required: true), + dependency('libdrm', required: true), + dependency('libtbm', required: true), + ], + install_dir: libds_bindir, + install : true) +endif diff --git a/include/meson.build b/include/meson.build index 731f7d3..f273424 100644 --- a/include/meson.build +++ b/include/meson.build @@ -1,3 +1,13 @@ +exclude_files = [] +if not features.get('tdm-backend') + exclude_files += 'backend/tdm.h' +endif + +if not features.get('tbm-allocator') + exclude_files += 'allocator/tbm.h' +endif + install_subdir('libds', - install_dir: get_option('includedir') + install_dir: get_option('includedir'), + exclude_files: exclude_files, ) diff --git a/meson.build b/meson.build index 36bfda9..2bf1398 100644 --- a/meson.build +++ b/meson.build @@ -25,6 +25,10 @@ cdata.set('LIBDS_VERSION_MAJOR', libds_version_major) cdata.set('LIBDS_VERSION_MINOR', libds_version_minor) cdata.set('LIBDS_VERSION_PATCH', libds_version_patch) +features = { + 'tdm-backend': false, + 'tbm-allocator': false, +} subdir('include') subdir('src') @@ -32,10 +36,4 @@ subdir('examples') configure_file(output: 'config.h', install: false, configuration: cdata) -pkgconfig = import('pkgconfig') -pkgconfig.generate(lib_libds, - version: meson.project_version(), - filebase: meson.project_name(), - name: meson.project_name(), - description: 'Wayland compositor library', -) +summary(features, bool_yn: true) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..02af9b0 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('backends', type: 'array', choices: ['auto', 'tdm'], value: ['auto'], description: 'Select built-in backends') diff --git a/src/libds/allocator/allocator.c b/src/libds/allocator.c similarity index 100% rename from src/libds/allocator/allocator.c rename to src/libds/allocator.c diff --git a/src/libds/allocator/meson.build b/src/libds/allocator/meson.build new file mode 100644 index 0000000..361f96e --- /dev/null +++ b/src/libds/allocator/meson.build @@ -0,0 +1,12 @@ +libds_files += files('shm.c') + +libtbm = dependency( + 'libtbm', + required: false, + not_found_message: 'Required for TBM allocator support.' +) +if libtbm.found() + libds_files += files('tbm.c') + libds_deps += libtbm + features += { 'tbm-allocator': true } +endif diff --git a/src/libds/backend/meson.build b/src/libds/backend/meson.build index c24f074..b1fff87 100644 --- a/src/libds/backend/meson.build +++ b/src/libds/backend/meson.build @@ -1,2 +1,15 @@ +all_backends = ['tdm'] +backends = get_option('backends') +if 'auto' in backends and get_option('auto_features').enabled() + backends = all_backends +elif 'auto' in backends and get_option('auto_features').disabled() + backends = [] +endif + +foreach backend : all_backends + if backend in backends or 'auto' in backends + subdir(backend) + endif +endforeach + subdir('wayland') -subdir('tdm') diff --git a/src/libds/backend/tdm/meson.build b/src/libds/backend/tdm/meson.build index 9a0b041..82eb165 100644 --- a/src/libds/backend/tdm/meson.build +++ b/src/libds/backend/tdm/meson.build @@ -1,8 +1,32 @@ +msg = ['Required for TDM backend support.'] +if 'tdm' in backends + msg += 'Install "libtdm" and "libtbm", or disable the tdm backend' +endif + +libtdm = dependency( + 'libtdm', + required: 'tdm' in backends, + not_found_message: '\n'.join(msg) +) + +libtbm = dependency( + 'libtbm', + required: 'tdm' in backends, + not_found_message: '\n'.join(msg) +) + +if not libtdm.found() or not libtbm.found() + subdir_done() +endif + libds_files += files( 'backend.c', 'output.c', ) libds_deps += [ - dependency('libtdm', required: true), + libtdm, + libtbm ] + +features += { 'tdm-backend': true } diff --git a/src/libds/meson.build b/src/libds/meson.build index e7f2970..ed8c95f 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -2,9 +2,7 @@ libds_files = [ 'log.c', 'addon.c', 'buffer.c', - 'allocator/allocator.c', - 'allocator/shm.c', - 'allocator/tbm.c', + 'allocator.c', 'swapchain.c', 'output.c', 'compositor.c', @@ -52,7 +50,6 @@ math = meson.get_compiler('c').find_library('m') wayland_server = dependency('wayland-server', required: true) pixman = dependency('pixman-1', required: true) libdrm = dependency('libdrm', required: true) -libtbm = dependency('libtbm', required: true) libds_deps = [ math, @@ -62,6 +59,7 @@ libds_deps = [ ] subdir('backend') +subdir('allocator') lib_libds = shared_library('ds', libds_files, dependencies: libds_deps, @@ -70,8 +68,23 @@ lib_libds = shared_library('ds', libds_files, install: true ) +ds_vars = {} +foreach name, have : features + ds_vars += { 'have_' + name.underscorify(): have.to_string() } +endforeach + dep_libds = declare_dependency( link_with: lib_libds, dependencies: libds_deps, include_directories: [ common_inc, include_directories('.') ], + variables: ds_vars, +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds, + version: meson.project_version(), + filebase: meson.project_name(), + name: meson.project_name(), + description: 'Wayland compositor library', + variables: ds_vars, ) -- 2.7.4 From e521d2e449f43cacc36297bfdc794538deefdc1f Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 2 Mar 2022 11:43:09 +0900 Subject: [PATCH 07/16] backend/tdm: Extract buffer code into functions Change-Id: I28a2f6bec27f85f80bcf91f1ce3cad7d4296d940 --- src/libds/backend/tdm/output.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/libds/backend/tdm/output.c b/src/libds/backend/tdm/output.c index 08b56b5..d3317f3 100644 --- a/src/libds/backend/tdm/output.c +++ b/src/libds/backend/tdm/output.c @@ -142,6 +142,31 @@ get_or_create_tdm_buffer(struct ds_tdm_backend *backend, } static void +tdm_buffer_release(struct ds_tdm_buffer *buffer) +{ + buffer->released = true; + ds_buffer_unlock(buffer->buffer); +} + +static void +tdm_output_update_front_buffer(struct ds_tdm_output *output) +{ + if (output->front_buffer) + tdm_buffer_release(output->front_buffer); + output->front_buffer = output->back_buffer; + output->back_buffer = NULL; +} + +static void +tdm_output_attach_back_buffer(struct ds_tdm_output *output, + struct ds_tdm_buffer *buffer) +{ + if (output->back_buffer) + tdm_buffer_release(output->back_buffer); + output->back_buffer = buffer; +} + +static void tdm_output_hwc_commit_handler(tdm_hwc *hwc, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data) { @@ -149,13 +174,7 @@ tdm_output_hwc_commit_handler(tdm_hwc *hwc, unsigned int sequence, output = user_data; - if (output->front_buffer) { - output->front_buffer->released = true; - ds_buffer_unlock(output->front_buffer->buffer); - } - - output->front_buffer = output->back_buffer; - output->back_buffer = NULL; + tdm_output_update_front_buffer(output); wl_signal_emit(&output->base.events.frame, &output->base); } @@ -209,12 +228,7 @@ tdm_output_iface_commit(struct ds_output *ds_output) return false; } - if (output->back_buffer) { - output->back_buffer->released = true; - ds_buffer_unlock(output->back_buffer->buffer); - } - - output->back_buffer = buffer; + tdm_output_attach_back_buffer(output, buffer); ds_dbg("Swap Buffer!!!!!"); } -- 2.7.4 From 7eeb8e9a2c70f7b3d604bf1af1d23bf3cfc097b9 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 2 Mar 2022 18:09:39 +0900 Subject: [PATCH 08/16] Add tdm backend server and client as an example Change-Id: If5305c3ee0ae11d8e0c9d2aed581e4142a2e4c2a --- clients/meson.build | 45 ++++ clients/simple-tbm.c | 502 +++++++++++++++++++++++++++++++++++++++++++ examples/meson.build | 14 +- examples/pixman-helper.c | 89 ++++++++ examples/pixman-helper.h | 15 ++ examples/tbm-server-helper.c | 222 +++++++++++++++++++ examples/tbm-server-helper.h | 35 +++ examples/tinyds-helper.c | 18 -- examples/tinyds-helper.h | 15 -- examples/tinyds-tdm.c | 173 ++++++--------- meson.build | 1 + packaging/libds.spec | 2 + 12 files changed, 988 insertions(+), 143 deletions(-) create mode 100644 clients/meson.build create mode 100644 clients/simple-tbm.c create mode 100644 examples/pixman-helper.c create mode 100644 examples/pixman-helper.h create mode 100644 examples/tbm-server-helper.c create mode 100644 examples/tbm-server-helper.h delete mode 100644 examples/tinyds-helper.c delete mode 100644 examples/tinyds-helper.h diff --git a/clients/meson.build b/clients/meson.build new file mode 100644 index 0000000..360c425 --- /dev/null +++ b/clients/meson.build @@ -0,0 +1,45 @@ +wayland_tbm_client = dependency('wayland-tbm-client', required: false) +libtbm = dependency('libtbm', required: false) + +if not wayland_tbm_client.found() or not libtbm.found() + subdir_done() +endif + +simple_tbm_files = ['simple-tbm.c'] +simple_tbm_deps = [ + dependency('wayland-client', required: true), + wayland_tbm_client, + libtbm, +] + +protocols = { + 'xdg-shell': wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', +} + +protocols_code = {} +protocols_client_header = {} +foreach name, path : protocols + code = custom_target( + name.underscorify() + '_c', + input: path, + output: '@BASENAME@-protocol.c', + command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], + ) + simple_tbm_files += code + + client_header = custom_target( + name.underscorify() + '_client_h', + input: path, + output: '@BASENAME@-client-protocol.h', + command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], + build_by_default: false, + ) + simple_tbm_files += client_header +endforeach + +executable('ds-simple-tbm', + simple_tbm_files, + dependencies: simple_tbm_deps, + install_dir: libds_bindir, + install: true, +) diff --git a/clients/simple-tbm.c b/clients/simple-tbm.c new file mode 100644 index 0000000..f572b60 --- /dev/null +++ b/clients/simple-tbm.c @@ -0,0 +1,502 @@ +/* + * Copyright © 2011 Benjamin Franzke + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "xdg-shell-client-protocol.h" + +static uint64_t buffer_info_key; +#define BUFFER_INFO_KEY (unsigned long)(&buffer_info_key) + +struct display { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct xdg_wm_base *wm_base; + struct wl_shm *shm; + struct wayland_tbm_client *wl_tbm; + bool has_xrgb; +}; + +struct window { + struct display *display; + int width, height; + struct wl_surface *surface; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; + struct wl_callback *callback; + tbm_surface_queue_h surface_queue; + bool wait_for_configure; +}; + +struct buffer_info { + struct window *window; + struct wl_buffer *wl_buffer; +}; + +static int running = 1; + +static void +redraw(void *data, struct wl_callback *callback, uint32_t time); + +static void +handle_xdg_surface_configure(void *data, struct xdg_surface *surface, + uint32_t serial) +{ + struct window *window = data; + + xdg_surface_ack_configure(surface, serial); + + if (window->wait_for_configure) { + redraw(window, NULL, 0); + window->wait_for_configure = false; + } +} + +static const struct xdg_surface_listener xdg_surface_listener = { + handle_xdg_surface_configure, +}; + +static void +handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, + int32_t width, int32_t height, + struct wl_array *state) +{ +} + +static void +handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) +{ + running = 0; +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + handle_xdg_toplevel_configure, + handle_xdg_toplevel_close, +}; + +static struct window * +create_window(struct display *display, int width, int height) +{ + struct window *window; + + window = calloc(1, sizeof *window); + if (!window) + return NULL; + + window->callback = NULL; + window->display = display; + window->width = width; + window->height = height; + window->surface = wl_compositor_create_surface(display->compositor); + + if (display->wm_base) { + window->xdg_surface = + xdg_wm_base_get_xdg_surface(display->wm_base, + window->surface); + assert(window->xdg_surface); + xdg_surface_add_listener(window->xdg_surface, + &xdg_surface_listener, window); + + window->xdg_toplevel = + xdg_surface_get_toplevel(window->xdg_surface); + assert(window->xdg_toplevel); + xdg_toplevel_add_listener(window->xdg_toplevel, + &xdg_toplevel_listener, window); + + xdg_toplevel_set_title(window->xdg_toplevel, "simple-tbm"); + wl_surface_commit(window->surface); + window->wait_for_configure = true; + } else { + assert(0); + } + + window->surface_queue = + wayland_tbm_client_create_surface_queue(display->wl_tbm, + window->surface, + 3, + width, + height, + TBM_FORMAT_XRGB8888); + assert(window->surface_queue); + + return window; +} + +static void +destroy_window(struct window *window) +{ + tbm_surface_queue_destroy(window->surface_queue); + + if (window->callback) + wl_callback_destroy(window->callback); + + if (window->xdg_toplevel) + xdg_toplevel_destroy(window->xdg_toplevel); + if (window->xdg_surface) + xdg_surface_destroy(window->xdg_surface); + wl_surface_destroy(window->surface); + free(window); +} + +static void +paint_pixels(void *image, int padding, int width, int height, uint32_t time) +{ + const int halfh = padding + (height - padding * 2) / 2; + const int halfw = padding + (width - padding * 2) / 2; + int ir, or; + uint32_t *pixel = image; + int y; + + /* squared radii thresholds */ + or = (halfw < halfh ? halfw : halfh) - 8; + ir = or - 32; + or *= or; + ir *= ir; + + pixel += padding * width; + for (y = padding; y < height - padding; y++) { + int x; + int y2 = (y - halfh) * (y - halfh); + + pixel += padding; + for (x = padding; x < width - padding; x++) { + uint32_t v; + + /* squared distance from center */ + int r2 = (x - halfw) * (x - halfw) + y2; + + if (r2 < ir) + v = (r2 / 32 + time / 64) * 0x0080401; + else if (r2 < or) + v = (y + time / 32) * 0x0080401; + else + v = (x + time / 16) * 0x0080401; + v &= 0x00ffffff; + + /* cross if compositor uses X from XRGB as alpha */ + if (abs(x - y) > 6 && abs(x + y - height) > 6) + v |= 0xff000000; + + *pixel++ = v; + } + + pixel += padding; + } +} + +static void +buffer_info_free_cb(void *data) +{ + struct buffer_info *buffer_info = data; + + if (!buffer_info) + return; + + wayland_tbm_client_destroy_buffer(buffer_info->window->display->wl_tbm, + buffer_info->wl_buffer); + free(buffer_info); +} + +static void +buffer_handle_release(void *data, struct wl_buffer *wl_buffer) +{ + tbm_surface_h surface = data; + struct buffer_info *buffer_info; + + tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY, + (void **)&buffer_info); + if (buffer_info) + tbm_surface_queue_release(buffer_info->window->surface_queue, surface); +} + +static const struct wl_buffer_listener buffer_listener = { + .release = buffer_handle_release, +}; + +static const struct wl_callback_listener frame_listener; + +static void +redraw(void *data, struct wl_callback *callback, uint32_t time) +{ + struct window *window = data; + struct buffer_info *buffer_info = NULL; + tbm_surface_h surface = NULL; + tbm_surface_info_s surface_info; + + if (!tbm_surface_queue_can_dequeue(window->surface_queue, 0)) + return; + + tbm_surface_queue_dequeue(window->surface_queue, &surface); + assert(surface); + + tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY, + (void **)&buffer_info); + if (!buffer_info) { + buffer_info = calloc(1, sizeof *buffer_info); + assert(buffer_info); + + tbm_surface_internal_add_user_data(surface, BUFFER_INFO_KEY, buffer_info_free_cb); + tbm_surface_internal_set_user_data(surface, BUFFER_INFO_KEY, buffer_info); + + buffer_info->wl_buffer = + wayland_tbm_client_create_buffer(window->display->wl_tbm, surface); + assert(buffer_info->wl_buffer); + + wl_buffer_add_listener(buffer_info->wl_buffer, &buffer_listener, + surface); + + buffer_info->window = window; + } + + tbm_surface_map(surface, TBM_SURF_OPTION_WRITE, &surface_info); + + paint_pixels(surface_info.planes[0].ptr, 20, + (surface_info.planes[0].stride/4), surface_info.height, time); + + tbm_surface_unmap(surface); + + wl_surface_attach(window->surface, buffer_info->wl_buffer, 0, 0); + wl_surface_damage(window->surface, + 20, 20, window->width - 40, window->height - 40); + + if (callback) + wl_callback_destroy(callback); + + window->callback = wl_surface_frame(window->surface); + wl_callback_add_listener(window->callback, &frame_listener, window); + wl_surface_commit(window->surface); +} + +static const struct wl_callback_listener frame_listener = { + redraw +}; + +static void +shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) +{ + struct display *d = data; + + if (format == WL_SHM_FORMAT_XRGB8888) + d->has_xrgb = true; +} + +struct wl_shm_listener shm_listener = { + shm_format +}; + +static void +xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) +{ + xdg_wm_base_pong(shell, serial); +} + +static const struct xdg_wm_base_listener xdg_wm_base_listener = { + xdg_wm_base_ping, +}; + +static void +registry_handle_global(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t version) +{ + struct display *d = data; + + if (strcmp(interface, "wl_compositor") == 0) { + d->compositor = + wl_registry_bind(registry, + id, &wl_compositor_interface, 1); + } else if (strcmp(interface, "xdg_wm_base") == 0) { + d->wm_base = wl_registry_bind(registry, + id, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d); + } else if (strcmp(interface, "wl_shm") == 0) { + d->shm = wl_registry_bind(registry, + id, &wl_shm_interface, 1); + wl_shm_add_listener(d->shm, &shm_listener, d); + } +} + +static void +registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static struct display * +create_display(void) +{ + struct display *display; + + display = calloc(1, sizeof *display); + if (display == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + display->display = wl_display_connect(NULL); + assert(display->display); + + display->has_xrgb = false; + display->registry = wl_display_get_registry(display->display); + wl_registry_add_listener(display->registry, + ®istry_listener, display); + wl_display_roundtrip(display->display); + if (display->shm == NULL) { + fprintf(stderr, "No wl_shm global\n"); + exit(1); + } + + wl_display_roundtrip(display->display); + + /* + * Why do we need two roundtrips here? + * + * wl_display_get_registry() sends a request to the server, to which + * the server replies by emitting the wl_registry.global events. + * The first wl_display_roundtrip() sends wl_display.sync. The server + * first processes the wl_display.get_registry which includes sending + * the global events, and then processes the sync. Therefore when the + * sync (roundtrip) returns, we are guaranteed to have received and + * processed all the global events. + * + * While we are inside the first wl_display_roundtrip(), incoming + * events are dispatched, which causes registry_handle_global() to + * be called for each global. One of these globals is wl_shm. + * registry_handle_global() sends wl_registry.bind request for the + * wl_shm global. However, wl_registry.bind request is sent after + * the first wl_display.sync, so the reply to the sync comes before + * the initial events of the wl_shm object. + * + * The initial events that get sent as a reply to binding to wl_shm + * include wl_shm.format. These tell us which pixel formats are + * supported, and we need them before we can create buffers. They + * don't change at runtime, so we receive them as part of init. + * + * When the reply to the first sync comes, the server may or may not + * have sent the initial wl_shm events. Therefore we need the second + * wl_display_roundtrip() call here. + * + * The server processes the wl_registry.bind for wl_shm first, and + * the second wl_display.sync next. During our second call to + * wl_display_roundtrip() the initial wl_shm events are received and + * processed. Finally, when the reply to the second wl_display.sync + * arrives, it guarantees we have processed all wl_shm initial events. + * + * This sequence contains two examples on how wl_display_roundtrip() + * can be used to guarantee, that all reply events to a request + * have been received and processed. This is a general Wayland + * technique. + */ + + if (!display->has_xrgb) { + fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n"); + exit(1); + } + + display->wl_tbm = wayland_tbm_client_init(display->display); + if (!display->wl_tbm) { + fprintf(stderr, "failed wayland_tbm_client_init()\n"); + exit(1); + } + + return display; +} + +static void +destroy_display(struct display *display) +{ + if (display->shm) + wl_shm_destroy(display->shm); + + if (display->wm_base) + xdg_wm_base_destroy(display->wm_base); + + if (display->compositor) + wl_compositor_destroy(display->compositor); + + wayland_tbm_client_deinit(display->wl_tbm); + wl_registry_destroy(display->registry); + wl_display_flush(display->display); + wl_display_disconnect(display->display); + free(display); +} + +static void +signal_int(int signum) +{ + running = 0; +} + +int +main(int argc, char **argv) +{ + struct sigaction sigint; + struct display *display; + struct window *window; + int ret = 0; + + display = create_display(); + window = create_window(display, 250, 250); + if (!window) + return 1; + + sigint.sa_handler = signal_int; + sigemptyset(&sigint.sa_mask); + sigint.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sigint, NULL); + + /* Initialise damage to full surface, so the padding gets painted */ + wl_surface_damage(window->surface, 0, 0, + window->width, window->height); + + if (!window->wait_for_configure) + redraw(window, NULL, 0); + + while (running && ret != -1) + ret = wl_display_dispatch(display->display); + + fprintf(stderr, "simple-shm exiting\n"); + + destroy_window(window); + destroy_display(display); + + return 0; +} diff --git a/examples/meson.build b/examples/meson.build index 66336f5..7a841e4 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -24,16 +24,24 @@ if features.get('tdm-backend') 'tdm-backend.c', dependencies: common_deps, install_dir: libds_bindir, - install : true) + install : true + ) + tinyds_tdm_files = [ + 'tinyds-tdm.c', + 'tbm-server-helper.c', + 'pixman-helper.c', + ] executable('tinyds-tdm', - ['tinyds-tdm.c', 'tinyds-helper.c'], + tinyds_tdm_files, dependencies: [ common_deps, dependency('pixman-1', required: true), dependency('libdrm', required: true), dependency('libtbm', required: true), + dependency('wayland-tbm-server', required: true), ], install_dir: libds_bindir, - install : true) + install : true + ) endif diff --git a/examples/pixman-helper.c b/examples/pixman-helper.c new file mode 100644 index 0000000..5d42ec6 --- /dev/null +++ b/examples/pixman-helper.c @@ -0,0 +1,89 @@ +#include "pixman-helper.h" + +#include +#include + +static void destroy_pixman_image(pixman_image_t *image, void *data); +static uint32_t convert_drm_format_to_pixman(uint32_t fmt); +static pixman_color_t *color_rgb888(pixman_color_t *tmp, + uint8_t r, uint8_t g, uint8_t b); + +pixman_image_t * +pixman_image_from_buffer(struct ds_buffer *buffer, + enum ds_buffer_data_ptr_access_flag access_flag) +{ + pixman_image_t *image; + void *data; + uint32_t format; + size_t stride; + int width, height; + + ds_buffer_get_size(buffer, &width, &height); + + if (!ds_buffer_begin_data_ptr_access(buffer, + access_flag, &data, &format, &stride)) + return NULL; + + format = convert_drm_format_to_pixman(format); + image = pixman_image_create_bits(format, width, height, data, stride); + if (!image) { + ds_buffer_end_data_ptr_access(buffer); + return NULL; + } + + pixman_image_set_destroy_function(image, + destroy_pixman_image, ds_buffer_lock(buffer)); + + return image; +} + + +void +pixman_image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b) +{ + pixman_image_t *color_image; + pixman_color_t color; + + color_rgb888(&color, r, g, b); + color_image = pixman_image_create_solid_fill(&color); + pixman_image_composite32(PIXMAN_OP_SRC, + color_image, + NULL, + image, + 0, 0, 0, 0, 0, 0, + pixman_image_get_width(image), + pixman_image_get_height(image)); + pixman_image_unref(color_image); +} + +static pixman_color_t * +color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b) +{ + tmp->alpha = 65535; + tmp->red = (r << 8) + r; + tmp->green = (g << 8) + g; + tmp->blue = (b << 8) +b; + + return tmp; +} + +static uint32_t +convert_drm_format_to_pixman(uint32_t fmt) +{ + switch (fmt) { + case DRM_FORMAT_XRGB8888: + return PIXMAN_x8r8g8b8; + case DRM_FORMAT_ARGB8888: + return PIXMAN_a8r8g8b8; + default: + assert(0 && "not reached"); + } +} + +static void +destroy_pixman_image(pixman_image_t *image, void *data) +{ + struct ds_buffer *buffer = data; + ds_buffer_end_data_ptr_access(buffer); + ds_buffer_unlock(buffer); +} diff --git a/examples/pixman-helper.h b/examples/pixman-helper.h new file mode 100644 index 0000000..aa039ff --- /dev/null +++ b/examples/pixman-helper.h @@ -0,0 +1,15 @@ +#ifndef EXAMPLES_PIXMAN_HELPER_H +#define EXAMPLES_PIXMAN_HELPER_H + +#include +#include + +pixman_image_t * +pixman_image_from_buffer(struct ds_buffer *buffer, + enum ds_buffer_data_ptr_access_flag access_flag); + +void +pixman_image_fill_color(pixman_image_t *image, + uint8_t r, uint8_t g, uint8_t b); + +#endif diff --git a/examples/tbm-server-helper.c b/examples/tbm-server-helper.c new file mode 100644 index 0000000..bd3a34d --- /dev/null +++ b/examples/tbm-server-helper.c @@ -0,0 +1,222 @@ +#include "tbm-server-helper.h" + +#include +#include +#include +#include +#include +#include + +static const struct ds_buffer_resource_interface tbm_buffer_resource_iface; +static void tbm_server_handle_display_destroy(struct wl_listener *listener, + void *data); +static struct tbm_client_buffer * +tbm_client_buffer_create(struct wl_resource *resource); + +bool +tbm_server_init_display(struct tbm_server *tbm, struct wl_display *display) +{ + tbm_bufmgr bufmgr; + + tbm->wl_tbm = wayland_tbm_server_init(display, NULL, -1, 0); + if (!tbm->wl_tbm) { + return false; + } + + bufmgr = wayland_tbm_server_get_bufmgr(tbm->wl_tbm); + if (!bufmgr) { + wayland_tbm_server_deinit(tbm->wl_tbm); + return false; + } + + if (!tbm_bufmgr_bind_native_display(bufmgr, (void *)display)) { + wayland_tbm_server_deinit(tbm->wl_tbm); + return false; + } + + ds_buffer_register_resource_interface(&tbm_buffer_resource_iface); + + tbm->display_destroy.notify = tbm_server_handle_display_destroy; + wl_display_add_destroy_listener(display, &tbm->display_destroy); + + return true; +} + +static void +tbm_server_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct tbm_server *tbm; + + tbm = wl_container_of(listener, tbm, display_destroy); + wayland_tbm_server_deinit(tbm->wl_tbm); +} + +static bool +tbm_buffer_resource_iface_is_instance(struct wl_resource *resource) +{ + return !!wayland_tbm_server_get_surface(NULL, resource); +} + +static void +tbm_client_buffer_handle_resource_destroy(struct wl_listener *listener, + void *data) +{ + struct tbm_client_buffer *buffer; + + buffer = wl_container_of(listener, buffer, resource_destroy); + + buffer->resource = NULL; + buffer->surface = NULL; + wl_list_remove(&buffer->resource_destroy.link); + wl_list_init(&buffer->resource_destroy.link); + + ds_buffer_drop(&buffer->base); +} + +static struct tbm_client_buffer * +tbm_client_buffer_get_or_create(struct wl_resource *resource) +{ + struct tbm_client_buffer *buffer; + struct wl_listener *resource_destroy_listener; + + resource_destroy_listener = wl_resource_get_destroy_listener(resource, + tbm_client_buffer_handle_resource_destroy);; + if (resource_destroy_listener) { + buffer = wl_container_of(resource_destroy_listener, + buffer, resource_destroy); + return buffer; + } + + return tbm_client_buffer_create(resource); +} + +static struct ds_buffer * +tbm_buffer_resource_iface_from_resource(struct wl_resource *resource) +{ + struct tbm_client_buffer *buffer; + + buffer = tbm_client_buffer_get_or_create(resource); + assert(buffer); + + return &buffer->base; +} + +static const struct ds_buffer_resource_interface tbm_buffer_resource_iface = { + .name = "tbm", + .is_instance = tbm_buffer_resource_iface_is_instance, + .from_resource = tbm_buffer_resource_iface_from_resource, +}; + +static const struct ds_buffer_interface tbm_client_buffer_iface; + +static struct tbm_client_buffer * +tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) +{ + assert(ds_buffer->iface == &tbm_client_buffer_iface); + return (struct tbm_client_buffer *)ds_buffer; +} + +static void +tbm_client_buffer_destroy(struct ds_buffer *ds_buffer) +{ + struct tbm_client_buffer *buffer; + + buffer = tbm_client_buffer_from_buffer(ds_buffer); + + ds_inf("Destroy TBM client buffer(%p)", buffer); + + wl_list_remove(&buffer->resource_destroy.link); + wl_list_remove(&buffer->buffer_release.link); + free(buffer); +} + +static bool +tbm_client_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer, + enum ds_buffer_data_ptr_access_flag flags, void **data, + uint32_t *format, size_t *stride) +{ + struct tbm_client_buffer *buffer; + tbm_surface_info_s info; + tbm_bo_access_option op = TBM_OPTION_NONE; + int err; + + buffer = tbm_client_buffer_from_buffer(ds_buffer); + + if (flags & DS_BUFFER_DATA_PTR_ACCESS_READ) + op |= TBM_OPTION_READ; + + if (flags & DS_BUFFER_DATA_PTR_ACCESS_WRITE) + op |= TBM_OPTION_WRITE; + + err = tbm_surface_map(buffer->surface, op, &info); + if (err != TBM_SURFACE_ERROR_NONE) { + ds_err("Failed tbm_surface_map()"); + return false; + } + + *format = DRM_FORMAT_XRGB8888; // FIXME + *stride = info.planes[0].stride; + *data = info.planes[0].ptr; + + return true; +} + +static void +tbm_client_buffer_end_data_ptr_access(struct ds_buffer *ds_buffer) +{ + struct tbm_client_buffer *buffer; + + buffer = tbm_client_buffer_from_buffer(ds_buffer); + + tbm_surface_unmap(buffer->surface); +} + +static const struct ds_buffer_interface tbm_client_buffer_iface = { + .destroy = tbm_client_buffer_destroy, + .begin_data_ptr_access = tbm_client_buffer_begin_data_ptr_access, + .end_data_ptr_access = tbm_client_buffer_end_data_ptr_access, +}; + +static void +tbm_client_buffer_handle_release(struct wl_listener *listener, void *data) +{ + struct tbm_client_buffer *buffer; + + buffer = wl_container_of(listener, buffer, buffer_release); + if (buffer->resource) + wl_buffer_send_release(buffer->resource); +} + +static struct tbm_client_buffer * +tbm_client_buffer_create(struct wl_resource *resource) +{ + struct tbm_client_buffer *buffer; + tbm_surface_h surface; + int32_t width, height; + + surface = wayland_tbm_server_get_surface(NULL, resource); + assert(surface); + + width = tbm_surface_get_width(surface); + height = tbm_surface_get_height(surface); + + buffer = calloc(1, sizeof *buffer); + assert(buffer); + + ds_buffer_init(&buffer->base, &tbm_client_buffer_iface, width, height); + + buffer->resource = resource; + buffer->surface = surface; + buffer->format = tbm_surface_get_format(surface); + + buffer->buffer_release.notify = tbm_client_buffer_handle_release; + ds_buffer_add_release_listener(&buffer->base, &buffer->buffer_release); + + buffer->resource_destroy.notify = + tbm_client_buffer_handle_resource_destroy; + wl_resource_add_destroy_listener(resource, &buffer->resource_destroy); + + ds_inf("TBM client buffer(%p) created", buffer); + + return buffer; +} diff --git a/examples/tbm-server-helper.h b/examples/tbm-server-helper.h new file mode 100644 index 0000000..a82ad5b --- /dev/null +++ b/examples/tbm-server-helper.h @@ -0,0 +1,35 @@ +#ifndef EXAMPLES_TBM_SERVER_H +#define EXAMPLES_TBM_SERVER_H + +#include +#include +#include +#include +#include + +struct tbm_server +{ + struct wayland_tbm_server *wl_tbm; + + struct wl_listener display_destroy; +}; + +struct tbm_client_buffer +{ + struct ds_buffer base; + + tbm_surface_h surface; + struct wl_resource *resource; + + struct wl_listener buffer_release; + struct wl_listener resource_destroy; + + uint32_t format; + size_t stride; +}; + +bool +tbm_server_init_display(struct tbm_server *tbm_server, + struct wl_display *display); + +#endif diff --git a/examples/tinyds-helper.c b/examples/tinyds-helper.c deleted file mode 100644 index ef077b3..0000000 --- a/examples/tinyds-helper.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "tinyds-helper.h" - -#include -#include - -bool -tinyds_renderer_init_display(struct tinyds_renderer *renderer, - struct wl_display *display) -{ - if (wl_display_init_shm(display)) { - ds_err("Could not initialize shm"); - return false; - } - - renderer->dummy = 1; - - return true; -} diff --git a/examples/tinyds-helper.h b/examples/tinyds-helper.h deleted file mode 100644 index 44415d6..0000000 --- a/examples/tinyds-helper.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TINYDS_HELPER_H -#define TINYDS_HELPER_H - -#include -#include - -struct tinyds_renderer { - int dummy; -}; - -bool -tinyds_renderer_init_display(struct tinyds_renderer *renderer, - struct wl_display *display); - -#endif diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c index 23ff48e..4207fb1 100644 --- a/examples/tinyds-tdm.c +++ b/examples/tinyds-tdm.c @@ -1,4 +1,5 @@ -#include "tinyds-helper.h" +#include "tbm-server-helper.h" +#include "pixman-helper.h" #include #include @@ -43,6 +44,8 @@ struct tinyds_output struct tinyds_server { + struct tbm_server tbm_server; + struct wl_display *display; struct ds_backend *backend; @@ -50,7 +53,7 @@ struct tinyds_server struct ds_xdg_shell *xdg_shell; struct tinyds_output *output; - struct tinyds_renderer renderer; + struct wl_event_source *stdin_source; struct wl_list views; @@ -74,12 +77,12 @@ struct tinyds_view bool mapped; }; -struct tinyds_server _tinyds; +struct tinyds_server tinyds; static bool init_server(struct tinyds_server *server, struct wl_display *display); +static int server_dispatch_stdin(int fd, uint32_t mask, void *data); static void output_handle_destroy(struct wl_listener *listener, void *data); static void output_handle_frame(struct wl_listener *listener, void *data); -static void draw_server(struct tinyds_server *server); static void draw_server_with_damage(struct tinyds_server *server); static void draw_output(struct tinyds_output *output); static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); @@ -87,18 +90,22 @@ static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); int main(void) { - struct tinyds_server *server = &_tinyds; + struct tinyds_server *server = &tinyds; struct wl_display *display; + struct wl_event_loop *loop; const char *socket; + bool res; - ds_log_init(DS_DBG, NULL); + ds_log_init(DS_INF, NULL); display = wl_display_create(); assert(display); - assert(init_server(server, display) == true); + res = init_server(server, display); + assert(res); - assert(tinyds_renderer_init_display(&server->renderer, display)); + res = tbm_server_init_display(&server->tbm_server, display); + assert(res); socket = wl_display_add_socket_auto(display); assert(socket); @@ -109,6 +116,13 @@ main(void) ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket); + loop = wl_display_get_event_loop(display); + server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO, + WL_EVENT_READABLE, server_dispatch_stdin, server); + + wl_display_run(display); + + wl_display_destroy_clients(display); wl_display_destroy(display); return 0; @@ -175,6 +189,8 @@ server_new_xdg_surface(struct wl_listener *listener, void *data) ds_inf("New xdg_surface(%p)", (void *)xdg_surface); view = calloc(1, sizeof *view); + assert(view); + view->server = server; view->xdg_surface = xdg_surface; @@ -196,6 +212,9 @@ server_new_xdg_surface(struct wl_listener *listener, void *data) &view->surface_commit); wl_list_insert(server->views.prev, &view->link); + + view->x = rand() % 1000; + view->y = rand() % 500; } static void @@ -217,8 +236,24 @@ backend_handle_new_output(struct wl_listener *listener, void *data) if (!output) return; + output->allocator = ds_tbm_allocator_create(); + if (!output->allocator) { + free(output); + return; + } + + output->swapchain = ds_swapchain_create(output->allocator, + OUTPUT_WIDTH, OUTPUT_HEIGHT, DRM_FORMAT_XRGB8888); // FIXME output mode + if (!output->swapchain) { + ds_allocator_destroy(output->allocator); + free(output); + return; + } + output->server = server; output->ds_output = ds_output; + output->drawable = true; + output->damaged = true; output->output_destroy.notify = output_handle_destroy; ds_output_add_destroy_listener(ds_output, @@ -229,6 +264,8 @@ backend_handle_new_output(struct wl_listener *listener, void *data) &output->output_frame); server->output = output; + + draw_output(output); } static bool @@ -299,12 +336,8 @@ output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED) struct tinyds_output *output = wl_container_of(listener, output, output_frame); -} - -static void -draw_server(struct tinyds_server *server) -{ - draw_output(server->output); + output->drawable = true; + draw_output(output); } static void @@ -314,12 +347,6 @@ draw_server_with_damage(struct tinyds_server *server) draw_output(server->output); } -static void image_fill_color(pixman_image_t *image, - uint8_t r, uint8_t g, uint8_t b); -static pixman_image_t *image_from_buffer(struct ds_buffer *buffer, - enum ds_buffer_data_ptr_access_flag access_flag); -static void view_send_frame_done(struct tinyds_view *view); - static void draw_output(struct tinyds_output *output) { @@ -334,14 +361,14 @@ draw_output(struct tinyds_output *output) if (!output_buffer) return; - output_image = image_from_buffer(output_buffer, + output_image = pixman_image_from_buffer(output_buffer, DS_BUFFER_DATA_PTR_ACCESS_WRITE); if (!output_image) { ds_buffer_unlock(output_buffer); return; } - image_fill_color(output_image, 80, 80, 80); + pixman_image_fill_color(output_image, 80, 80, 80); wl_list_for_each(view, &output->server->views, link) { if (!view->mapped) @@ -362,6 +389,15 @@ draw_output(struct tinyds_output *output) } static void +view_send_frame_done(struct tinyds_view *view) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), + &now); +} + +static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image) { struct ds_buffer *buffer; @@ -372,13 +408,14 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_image) if (!buffer) return; - src_image = image_from_buffer(buffer, + src_image = pixman_image_from_buffer(buffer, DS_BUFFER_DATA_PTR_ACCESS_READ); pixman_image_composite32(PIXMAN_OP_OVER, src_image, NULL, dst_image, - 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + view->x, view->y, pixman_image_get_width(src_image), pixman_image_get_height(src_image)); pixman_image_unref(src_image); @@ -386,90 +423,12 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_image) view_send_frame_done(view); } -static pixman_color_t * -color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b) +static int +server_dispatch_stdin(int fd, uint32_t mask, void *data) { - tmp->alpha = 65535; - tmp->red = (r << 8) + r; - tmp->green = (g << 8) + g; - tmp->blue = (b << 8) +b; + struct tinyds_server *server = data; - return tmp; -} + wl_display_terminate(server->display); -static void -image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b) -{ - pixman_image_t *color_image; - pixman_color_t color; - - color_rgb888(&color, r, g, b); - color_image = pixman_image_create_solid_fill(&color); - pixman_image_composite32(PIXMAN_OP_SRC, - color_image, - NULL, - image, - 0, 0, 0, 0, 0, 0, - pixman_image_get_width(image), - pixman_image_get_height(image)); - pixman_image_unref(color_image); -} - -static void -destroy_pixman_image(pixman_image_t *image TINYDS_UNUSED, void *data) -{ - struct ds_buffer *buffer = data; - ds_buffer_end_data_ptr_access(buffer); - ds_buffer_unlock(buffer); -} - -static uint32_t -convert_drm_format_to_pixman(uint32_t fmt) -{ - switch (fmt) { - case DRM_FORMAT_XRGB8888: - return PIXMAN_x8r8g8b8; - case DRM_FORMAT_ARGB8888: - return PIXMAN_a8r8g8b8; - default: - assert(0 && "not reached"); - } -} - -static pixman_image_t * -image_from_buffer(struct ds_buffer *buffer, - enum ds_buffer_data_ptr_access_flag access_flag) -{ - pixman_image_t *image; - void *data; - uint32_t format; - size_t stride; - int width, height; - - ds_buffer_get_size(buffer, &width, &height); - - if (!ds_buffer_begin_data_ptr_access(buffer, - access_flag, &data, &format, &stride)) - return NULL; - - format = convert_drm_format_to_pixman(format); - image = pixman_image_create_bits(format, width, height, data, stride); - if (!image) { - ds_buffer_end_data_ptr_access(buffer); - return NULL; - } - - pixman_image_set_destroy_function(image, - destroy_pixman_image, ds_buffer_lock(buffer)); - - return image; -} - -static void -view_send_frame_done(struct tinyds_view *view) -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), - &now); + return 1; } diff --git a/meson.build b/meson.build index 2bf1398..445fd6a 100644 --- a/meson.build +++ b/meson.build @@ -33,6 +33,7 @@ features = { subdir('include') subdir('src') subdir('examples') +subdir('clients') configure_file(output: 'config.h', install: false, configuration: cdata) diff --git a/packaging/libds.spec b/packaging/libds.spec index 69d58f6..3b479e2 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -16,6 +16,8 @@ BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(libtdm) BuildRequires: pkgconfig(libtbm) +BuildRequires: pkgconfig(wayland-tbm-server) +BuildRequires: pkgconfig(wayland-tbm-client) %description Wayland Compositor Library -- 2.7.4 From efacbd2b7543333547793715b0e411bd5dc8130f Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 2 Mar 2022 18:14:12 +0900 Subject: [PATCH 09/16] examples: Use pixman helper Change-Id: I22a63f7af7c9b054d2be52f1e6dbbe92291ee96d --- examples/meson.build | 20 +++++++----- examples/tinyds.c | 91 +++------------------------------------------------- 2 files changed, 17 insertions(+), 94 deletions(-) diff --git a/examples/meson.build b/examples/meson.build index 7a841e4..193b4a5 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -10,14 +10,18 @@ executable('wl-backend', install : true) executable('tinyds', - 'tinyds.c', - dependencies: [ - common_deps, - dependency('pixman-1', required: true), - dependency('libdrm', required: true), - ], - install_dir: libds_bindir, - install : true) + [ + 'tinyds.c', + 'pixman-helper.c' + ], + dependencies: [ + common_deps, + dependency('pixman-1', required: true), + dependency('libdrm', required: true), + ], + install_dir: libds_bindir, + install : true +) if features.get('tdm-backend') executable('tdm-backend', diff --git a/examples/tinyds.c b/examples/tinyds.c index 3925014..a4c1042 100644 --- a/examples/tinyds.c +++ b/examples/tinyds.c @@ -1,3 +1,5 @@ +#include "pixman-helper.h" + #include #include #include @@ -361,10 +363,6 @@ draw_server_with_damage(struct tinyds_server *server) } } -static void image_fill_color(pixman_image_t *image, - uint8_t r, uint8_t g, uint8_t b); -static pixman_image_t *image_from_buffer(struct ds_buffer *buffer, - enum ds_buffer_data_ptr_access_flag access_flag); static void view_send_frame_done(struct tinyds_view *view); static void @@ -381,14 +379,14 @@ draw_output(struct tinyds_output *output) if (!output_buffer) return; - output_image = image_from_buffer(output_buffer, + output_image = pixman_image_from_buffer(output_buffer, DS_BUFFER_DATA_PTR_ACCESS_WRITE); if (!output_image) { ds_buffer_unlock(output_buffer); return; } - image_fill_color(output_image, 80, 80, 80); + pixman_image_fill_color(output_image, 80, 80, 80); wl_list_for_each(view, &output->server->views, link) { if (!view->mapped) @@ -419,7 +417,7 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_image) if (!buffer) return; - src_image = image_from_buffer(buffer, + src_image = pixman_image_from_buffer(buffer, DS_BUFFER_DATA_PTR_ACCESS_READ); pixman_image_composite32(PIXMAN_OP_OVER, src_image, @@ -433,85 +431,6 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_image) view_send_frame_done(view); } -static pixman_color_t * -color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b) -{ - tmp->alpha = 65535; - tmp->red = (r << 8) + r; - tmp->green = (g << 8) + g; - tmp->blue = (b << 8) +b; - - return tmp; -} - -static void -image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b) -{ - pixman_image_t *color_image; - pixman_color_t color; - - color_rgb888(&color, r, g, b); - color_image = pixman_image_create_solid_fill(&color); - pixman_image_composite32(PIXMAN_OP_SRC, - color_image, - NULL, - image, - 0, 0, 0, 0, 0, 0, - pixman_image_get_width(image), - pixman_image_get_height(image)); - pixman_image_unref(color_image); -} - -static void -destroy_pixman_image(pixman_image_t *image TINYDS_UNUSED, void *data) -{ - struct ds_buffer *buffer = data; - ds_buffer_end_data_ptr_access(buffer); - ds_buffer_unlock(buffer); -} - -static uint32_t -convert_drm_format_to_pixman(uint32_t fmt) -{ - switch (fmt) { - case DRM_FORMAT_XRGB8888: - return PIXMAN_x8r8g8b8; - case DRM_FORMAT_ARGB8888: - return PIXMAN_a8r8g8b8; - default: - assert(0 && "not reached"); - } -} - -static pixman_image_t * -image_from_buffer(struct ds_buffer *buffer, - enum ds_buffer_data_ptr_access_flag access_flag) -{ - pixman_image_t *image; - void *data; - uint32_t format; - size_t stride; - int width, height; - - ds_buffer_get_size(buffer, &width, &height); - - if (!ds_buffer_begin_data_ptr_access(buffer, - access_flag, &data, &format, &stride)) - return NULL; - - format = convert_drm_format_to_pixman(format); - image = pixman_image_create_bits(format, width, height, data, stride); - if (!image) { - ds_buffer_end_data_ptr_access(buffer); - return NULL; - } - - pixman_image_set_destroy_function(image, - destroy_pixman_image, ds_buffer_lock(buffer)); - - return image; -} - static void view_send_frame_done(struct tinyds_view *view) { -- 2.7.4 From 4ab31108b1d64790047369ba2e58050d1d6fa1ac Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 3 Mar 2022 12:11:03 +0900 Subject: [PATCH 10/16] Move all source code to src directory Change-Id: I55fd4d95d633a2a6d557d7409bbd6aba6b4b8d03 --- meson.build | 2 -- {clients => src/clients}/meson.build | 0 {clients => src/clients}/simple-tbm.c | 0 {examples => src/examples}/meson.build | 0 {examples => src/examples}/pixman-helper.c | 0 {examples => src/examples}/pixman-helper.h | 0 {examples => src/examples}/tbm-server-helper.c | 0 {examples => src/examples}/tbm-server-helper.h | 0 {examples => src/examples}/tdm-backend.c | 0 {examples => src/examples}/tinyds-tdm.c | 0 {examples => src/examples}/tinyds.c | 0 {examples => src/examples}/wl-backend.c | 0 src/meson.build | 2 ++ 13 files changed, 2 insertions(+), 2 deletions(-) rename {clients => src/clients}/meson.build (100%) rename {clients => src/clients}/simple-tbm.c (100%) rename {examples => src/examples}/meson.build (100%) rename {examples => src/examples}/pixman-helper.c (100%) rename {examples => src/examples}/pixman-helper.h (100%) rename {examples => src/examples}/tbm-server-helper.c (100%) rename {examples => src/examples}/tbm-server-helper.h (100%) rename {examples => src/examples}/tdm-backend.c (100%) rename {examples => src/examples}/tinyds-tdm.c (100%) rename {examples => src/examples}/tinyds.c (100%) rename {examples => src/examples}/wl-backend.c (100%) diff --git a/meson.build b/meson.build index 445fd6a..0a91447 100644 --- a/meson.build +++ b/meson.build @@ -32,8 +32,6 @@ features = { subdir('include') subdir('src') -subdir('examples') -subdir('clients') configure_file(output: 'config.h', install: false, configuration: cdata) diff --git a/clients/meson.build b/src/clients/meson.build similarity index 100% rename from clients/meson.build rename to src/clients/meson.build diff --git a/clients/simple-tbm.c b/src/clients/simple-tbm.c similarity index 100% rename from clients/simple-tbm.c rename to src/clients/simple-tbm.c diff --git a/examples/meson.build b/src/examples/meson.build similarity index 100% rename from examples/meson.build rename to src/examples/meson.build diff --git a/examples/pixman-helper.c b/src/examples/pixman-helper.c similarity index 100% rename from examples/pixman-helper.c rename to src/examples/pixman-helper.c diff --git a/examples/pixman-helper.h b/src/examples/pixman-helper.h similarity index 100% rename from examples/pixman-helper.h rename to src/examples/pixman-helper.h diff --git a/examples/tbm-server-helper.c b/src/examples/tbm-server-helper.c similarity index 100% rename from examples/tbm-server-helper.c rename to src/examples/tbm-server-helper.c diff --git a/examples/tbm-server-helper.h b/src/examples/tbm-server-helper.h similarity index 100% rename from examples/tbm-server-helper.h rename to src/examples/tbm-server-helper.h diff --git a/examples/tdm-backend.c b/src/examples/tdm-backend.c similarity index 100% rename from examples/tdm-backend.c rename to src/examples/tdm-backend.c diff --git a/examples/tinyds-tdm.c b/src/examples/tinyds-tdm.c similarity index 100% rename from examples/tinyds-tdm.c rename to src/examples/tinyds-tdm.c diff --git a/examples/tinyds.c b/src/examples/tinyds.c similarity index 100% rename from examples/tinyds.c rename to src/examples/tinyds.c diff --git a/examples/wl-backend.c b/src/examples/wl-backend.c similarity index 100% rename from examples/wl-backend.c rename to src/examples/wl-backend.c diff --git a/src/meson.build b/src/meson.build index 2a6ba37..774c7eb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,3 +12,5 @@ wayland_scanner = find_program( subdir('libds') subdir('tests') +subdir('examples') +subdir('clients') -- 2.7.4 From 00ed279fa8ad331e8628c14909a3cb324c0602d1 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 7 Mar 2022 08:09:00 +0900 Subject: [PATCH 11/16] change the version into 0.1.2 Change-Id: I747595f287cf73a548e03e569c6a18f413837d1b --- meson.build | 2 +- packaging/libds.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 0a91447..db1f43c 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('libds', 'c', license: 'MIT', - version: '0.1.0', + version: '0.1.2', default_options: [ 'warning_level=1', 'c_std=gnu99', diff --git a/packaging/libds.spec b/packaging/libds.spec index 3b479e2..bd38de7 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -1,5 +1,5 @@ Name: libds -Version: 0.0.1 +Version: 0.1.2 Release: 0 Summary: Wayland Compositor Library License: MIT -- 2.7.4 From 704347f05007f8b4f204b1bebcc511f949f6c325 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 7 Mar 2022 08:10:09 +0900 Subject: [PATCH 12/16] Put the extern "C" Without this extern "C", C++ program which uses libds does not recognize the symbols in libds header files. Change-Id: I2b9904c6dd9f50eab4c15f66ce3b6d9328b213b2 --- include/libds/allocator.h | 8 ++++++++ include/libds/allocator/shm.h | 8 ++++++++ include/libds/allocator/tbm.h | 8 ++++++++ include/libds/backend/tdm.h | 8 ++++++++ include/libds/backend/wayland.h | 8 ++++++++ include/libds/output.h | 8 ++++++++ include/libds/swapchain.h | 8 ++++++++ include/libds/xdg_shell.h | 8 ++++++++ 8 files changed, 64 insertions(+) diff --git a/include/libds/allocator.h b/include/libds/allocator.h index d4a6a80..7f26a96 100644 --- a/include/libds/allocator.h +++ b/include/libds/allocator.h @@ -3,6 +3,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_allocator; void @@ -16,4 +20,8 @@ void ds_allocator_add_destroy_listener(struct ds_allocator *alloc, struct wl_listener *listener); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/libds/allocator/shm.h b/include/libds/allocator/shm.h index 1a02338..c151183 100644 --- a/include/libds/allocator/shm.h +++ b/include/libds/allocator/shm.h @@ -3,7 +3,15 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_allocator * ds_shm_allocator_create(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/libds/allocator/tbm.h b/include/libds/allocator/tbm.h index 1457e3f..c02aee3 100644 --- a/include/libds/allocator/tbm.h +++ b/include/libds/allocator/tbm.h @@ -3,10 +3,18 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_allocator * ds_tbm_allocator_create(void); WL_EXPORT void * ds_tbm_buffer_get_surface(struct ds_buffer *ds_buffer); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/libds/backend/tdm.h b/include/libds/backend/tdm.h index ec5f9cc..e697413 100644 --- a/include/libds/backend/tdm.h +++ b/include/libds/backend/tdm.h @@ -3,7 +3,15 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_backend * ds_tdm_backend_create(struct wl_display *display); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/libds/backend/wayland.h b/include/libds/backend/wayland.h index e7f233a..2be8d76 100644 --- a/include/libds/backend/wayland.h +++ b/include/libds/backend/wayland.h @@ -4,10 +4,18 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_backend * ds_wl_backend_create(struct wl_display *display, const char *server_name); struct ds_output * ds_wl_backend_create_output(struct ds_backend *backend); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/libds/output.h b/include/libds/output.h index d2454fc..d56690e 100644 --- a/include/libds/output.h +++ b/include/libds/output.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_output; struct ds_output_mode { @@ -41,4 +45,8 @@ void ds_output_add_commit_listener(struct ds_output *output, struct wl_listener *listener); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/libds/swapchain.h b/include/libds/swapchain.h index d78d428..61d8a68 100644 --- a/include/libds/swapchain.h +++ b/include/libds/swapchain.h @@ -3,6 +3,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_swapchain; struct ds_swapchain * @@ -19,4 +23,8 @@ void ds_swapchain_set_buffer_submitted(struct ds_swapchain *swapchain, struct ds_buffer *buffer); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/libds/xdg_shell.h b/include/libds/xdg_shell.h index e3b386f..624c327 100644 --- a/include/libds/xdg_shell.h +++ b/include/libds/xdg_shell.h @@ -6,6 +6,10 @@ #include "surface.h" +#ifdef __cplusplus +extern "C" { +#endif + struct ds_xdg_shell; struct ds_xdg_surface; @@ -47,4 +51,8 @@ uint32_t ds_xdg_toplevel_set_activated(struct ds_xdg_surface *surface, bool activated); +#ifdef __cplusplus +} +#endif + #endif -- 2.7.4 From 495555a7d8ded2eed157c5a71afaa4b239e1ff43 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 7 Mar 2022 08:28:59 +0900 Subject: [PATCH 13/16] add CODEOWNERS which allow the members to be addded as reviewers when the PR is uploaded. Change-Id: I2baae3daff64061cf4436b91b22c64f42ced740a --- CODEOWNERS | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..2c7fc6d --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,9 @@ +# This is a comment. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. +* @doyoun-kang @gl77-lee @sc1-lim @shiin-lee + -- 2.7.4 From ca59561daf56a995f7a1a39cb353868f41765ecc Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 3 Mar 2022 18:01:14 +0900 Subject: [PATCH 14/16] Annotate a refresh variable Change-Id: I6019b86ea994d8fc4073eaf0cdba318489f844a5 --- include/libds/output.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libds/output.h b/include/libds/output.h index d56690e..35fee14 100644 --- a/include/libds/output.h +++ b/include/libds/output.h @@ -12,7 +12,7 @@ struct ds_output; struct ds_output_mode { int32_t width, height; - int32_t refresh; + int32_t refresh; // mHz bool preferred; struct wl_list link; }; -- 2.7.4 From 976fd811f38ab83a2cc061c216d36881a10ab362 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 3 Mar 2022 18:02:49 +0900 Subject: [PATCH 15/16] backend/tdm: Update output mode Change-Id: I1c23428392249f74376dc40aae5da89011165b17 --- src/libds/backend/tdm/output.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/libds/backend/tdm/output.c b/src/libds/backend/tdm/output.c index d3317f3..06edbf6 100644 --- a/src/libds/backend/tdm/output.c +++ b/src/libds/backend/tdm/output.c @@ -10,6 +10,7 @@ static const struct ds_output_interface tdm_output_iface; static bool tdm_output_init_modes(struct ds_tdm_output *output); static void tdm_output_destroy(struct ds_tdm_output *output); static void tdm_output_init_hwc(struct ds_tdm_output *output); +static bool tdm_output_update_mode(struct ds_tdm_output *output); struct ds_tdm_output * create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output) @@ -188,6 +189,13 @@ tdm_output_iface_commit(struct ds_output *ds_output) output = tdm_output_from_output(ds_output); + if (ds_output->pending.committed & DS_OUTPUT_STATE_MODE) { + if (!tdm_output_update_mode(output)) { + ds_err("Could not update TDM mode"); + return false; + } + } + ds_buffer = ds_output->pending.buffer; buffer = get_or_create_tdm_buffer(output->backend, ds_buffer); if (!buffer) @@ -221,7 +229,8 @@ tdm_output_iface_commit(struct ds_output *ds_output) return false; } - err = tdm_hwc_commit(output->tdm.hwc, 0, tdm_output_hwc_commit_handler, output); + err = tdm_hwc_commit(output->tdm.hwc, 0, tdm_output_hwc_commit_handler, + output); if (err != TDM_ERROR_NONE) { ds_err("Could not hwc commit"); ds_buffer_unlock(buffer->buffer); @@ -295,7 +304,7 @@ tdm_output_init_modes(struct ds_tdm_output *output) if (tdm_mode->type & TDM_OUTPUT_MODE_TYPE_PREFERRED) mode->base.preferred = true; - ds_inf(" %dx%d@%d %s", mode->base.width, mode->base.height, + ds_dbg(" %dx%d@%d %s", mode->base.width, mode->base.height, mode->base.refresh, mode->base.preferred ? "(preferred)" : ""); @@ -303,14 +312,6 @@ tdm_output_init_modes(struct ds_tdm_output *output) wl_list_insert(&output->base.modes, &mode->base.link); else wl_list_insert(output->base.modes.prev, &mode->base.link); - - // FIXME - if (mode->base.preferred) { - err = tdm_output_set_mode(output->tdm.output, tdm_mode); - if (err != TDM_ERROR_NONE) { - ds_err("Could not set mode"); - } - } } return true; @@ -327,3 +328,21 @@ tdm_output_init_hwc(struct ds_tdm_output *output) return; } } + +static bool +tdm_output_update_mode(struct ds_tdm_output *output) +{ + const struct ds_tdm_output_mode *mode; + tdm_error err; + + mode = (struct ds_tdm_output_mode *)output->base.pending.mode; + + ds_inf("TDM output(%p) set mode %dx%d %d mHz", output, + mode->base.width, mode->base.height, mode->base.refresh); + + err = tdm_output_set_mode(output->tdm.output, mode->tdm_mode); + if (err != TDM_ERROR_NONE) + return false; + + return true; +} -- 2.7.4 From 7f7bb930fcef308974d56fb0fd0d2e37e9347ceb Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 3 Mar 2022 18:03:25 +0900 Subject: [PATCH 16/16] examples: Use output mode instead of arbitrary size Change-Id: I46b576bccbd469ed386dc4d284a7a71311e557af --- src/examples/tinyds-tdm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/examples/tinyds-tdm.c b/src/examples/tinyds-tdm.c index 4207fb1..3841b84 100644 --- a/src/examples/tinyds-tdm.c +++ b/src/examples/tinyds-tdm.c @@ -22,9 +22,6 @@ #define TINYDS_UNUSED __attribute__((unused)) -#define OUTPUT_WIDTH 1280 -#define OUTPUT_HEIGHT 720 - struct tinyds_output { struct tinyds_server *server; @@ -223,6 +220,7 @@ backend_handle_new_output(struct wl_listener *listener, void *data) struct tinyds_server *server; struct tinyds_output *output; struct ds_output *ds_output; + const struct ds_output_mode *mode; server = wl_container_of(listener, server, new_output); ds_output = data; @@ -232,6 +230,9 @@ backend_handle_new_output(struct wl_listener *listener, void *data) if (server->output) return; + mode = ds_output_preferred_mode(ds_output); + ds_output_set_mode(ds_output, mode); + output = calloc(1, sizeof *output); if (!output) return; @@ -243,7 +244,7 @@ backend_handle_new_output(struct wl_listener *listener, void *data) } output->swapchain = ds_swapchain_create(output->allocator, - OUTPUT_WIDTH, OUTPUT_HEIGHT, DRM_FORMAT_XRGB8888); // FIXME output mode + mode->width, mode->height, DRM_FORMAT_XRGB8888); if (!output->swapchain) { ds_allocator_destroy(output->allocator); free(output); -- 2.7.4