From 2dcbbdaeb989750e1fce697f02205f57602a2066 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 23 Feb 2022 13:39:35 +0900 Subject: [PATCH 01/16] First draft for tdm backend Change-Id: I2f0deeeb9990495907f9e805e6e43401fb28e008 --- include/libds/interfaces/output.h | 13 ++- include/libds/output.h | 14 ++++ packaging/libds.spec | 2 + src/libds/backend/meson.build | 1 + src/libds/backend/tdm/backend.c | 162 ++++++++++++++++++++++++++++++++++++++ src/libds/backend/tdm/meson.build | 8 ++ src/libds/backend/tdm/output.c | 145 ++++++++++++++++++++++++++++++++++ src/libds/backend/tdm/tdm.h | 53 +++++++++++++ src/libds/output.c | 33 ++++++++ 9 files changed, 423 insertions(+), 8 deletions(-) create mode 100644 src/libds/backend/tdm/backend.c create mode 100644 src/libds/backend/tdm/meson.build create mode 100644 src/libds/backend/tdm/output.c create mode 100644 src/libds/backend/tdm/tdm.h diff --git a/include/libds/interfaces/output.h b/include/libds/interfaces/output.h index cacb927..9b95db1 100644 --- a/include/libds/interfaces/output.h +++ b/include/libds/interfaces/output.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -28,18 +29,11 @@ struct ds_output_interface bool (*commit)(struct ds_output *output); }; -struct ds_output_mode { - struct wl_list link; - int32_t width, height; - int32_t refresh; - bool preferred; -}; - struct ds_output_state { enum ds_output_state_field committed; struct ds_buffer *buffer; - struct ds_output_mode *mode; + const struct ds_output_mode *mode; bool enabled; }; @@ -54,8 +48,11 @@ struct ds_output struct wl_global *global; struct ds_buffer *back_buffer, *front_buffer; + const struct ds_output_mode *current_mode; struct ds_output_state pending; + struct wl_list modes; + struct wl_listener display_destroy; struct { diff --git a/include/libds/output.h b/include/libds/output.h index ea8e276..d2454fc 100644 --- a/include/libds/output.h +++ b/include/libds/output.h @@ -6,6 +6,13 @@ struct ds_output; +struct ds_output_mode { + int32_t width, height; + int32_t refresh; + bool preferred; + struct wl_list link; +}; + void ds_output_destroy(struct ds_output *output); @@ -15,6 +22,13 @@ ds_output_commit(struct ds_output *output); void ds_output_attach_buffer(struct ds_output *output, struct ds_buffer *buffer); +const struct ds_output_mode * +ds_output_preferred_mode(struct ds_output *output); + +void +ds_output_set_mode(struct ds_output *output, + const struct ds_output_mode *mode); + void ds_output_add_destroy_listener(struct ds_output *output, struct wl_listener *listener); diff --git a/packaging/libds.spec b/packaging/libds.spec index 8b7c5a7..f68b266 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -14,6 +14,8 @@ BuildRequires: pkgconfig(wayland-protocols) BuildRequires: pkgconfig(pixman-1) BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(libtdm) + %description Wayland Compositor Library diff --git a/src/libds/backend/meson.build b/src/libds/backend/meson.build index b135534..e095efd 100644 --- a/src/libds/backend/meson.build +++ b/src/libds/backend/meson.build @@ -3,3 +3,4 @@ libds_files += files( ) subdir('wayland') +subdir('tdm') diff --git a/src/libds/backend/tdm/backend.c b/src/libds/backend/tdm/backend.c new file mode 100644 index 0000000..582fe62 --- /dev/null +++ b/src/libds/backend/tdm/backend.c @@ -0,0 +1,162 @@ +#include +#include + +#include "libds/log.h" +#include "tdm.h" + +static const struct ds_backend_interface tdm_backend_iface; +static void tdm_backend_handle_display_destroy(struct wl_listener *listener, + void *data); +static void tdm_backend_destroy(struct ds_tdm_backend *tdm); +static int tdm_backend_handle_tdm_event(int fd, uint32_t mask, void *data); + +WL_EXPORT struct ds_backend * +ds_tdm_backend_create(struct wl_display *display) +{ + struct ds_tdm_backend *tdm; + struct wl_event_loop *loop; + tdm_error err; + + ds_inf("Initializing TDM backend"); + + tdm = calloc(1, sizeof *tdm); + if (!tdm) + return NULL; + + ds_backend_init(&tdm->base, &tdm_backend_iface); + + tdm->wl_display = display; + tdm->clock = CLOCK_MONOTONIC; // FIXME + wl_list_init(&tdm->outputs); + + tdm->tdm_display = tdm_display_init(&err); + if (err != TDM_ERROR_NONE) { + ds_err("Could not initialize tdm_display"); + goto err_display; + } + + err = tdm_display_get_fd(tdm->tdm_display, &tdm->fd); + if (err != TDM_ERROR_NONE || tdm->fd < 0) { + ds_err("Could not get fd from tdm_display: err(%d)", err); + goto err_fd; + } + + loop = wl_display_get_event_loop(display); + tdm->tdm_event = wl_event_loop_add_fd(loop, tdm->fd, WL_EVENT_READABLE, + tdm_backend_handle_tdm_event, tdm); + if (!tdm->tdm_event) { + ds_err("could not add fd event handler for tdm event"); + goto err_event; + } + + tdm->display_destroy.notify = tdm_backend_handle_display_destroy; + wl_display_add_destroy_listener(display, &tdm->display_destroy); + + return &tdm->base; + +err_event: + close(tdm->fd); +err_fd: + tdm_display_deinit(tdm->tdm_display); +err_display: + free(tdm); + + return NULL; +} + +struct ds_tdm_backend * +tdm_backend_from_backend(struct ds_backend *backend) +{ + assert(backend->iface == &tdm_backend_iface); + return (struct ds_tdm_backend *)backend; +} + +static void +tdm_backend_destroy(struct ds_tdm_backend *tdm) +{ + wl_list_remove(&tdm->display_destroy.link); + wl_event_source_remove(tdm->tdm_event); + close(tdm->fd); + tdm_display_deinit(tdm->tdm_display); + free(tdm); +} + +static bool +tdm_backend_scan_outputs(struct ds_tdm_backend *tdm) +{ + struct ds_tdm_output *output; + tdm_output *tdm_output; + tdm_error err; + int num_outputs, i; + + err = tdm_display_get_output_count(tdm->tdm_display, &num_outputs); + if (err != TDM_ERROR_NONE) { + ds_err("Could not get number of outputs: err(%d)", err); + return false; + } + + for (i = 0; i < num_outputs; i++) { + tdm_output = tdm_display_get_output(tdm->tdm_display, i, &err); + if (err != TDM_ERROR_NONE || !tdm_output) { + ds_err("Could not get output from tdm_display: index(%d) err(%d)", + i, err); + continue; + } + + output = create_tdm_output(tdm, tdm_output); + if (!output) { + ds_err("Could not create output: index(%d)", i); + continue; + } + + wl_list_insert(&tdm->outputs, &output->link); + + wl_signal_emit(&tdm->base.events.new_output, &output->base); + } + + return true; +} + +static bool +tdm_backend_iface_start(struct ds_backend *backend) +{ + struct ds_tdm_backend *tdm; + + tdm = tdm_backend_from_backend(backend); + return tdm_backend_scan_outputs(tdm); +} + +static void +tdm_backend_iface_destroy(struct ds_backend *backend) +{ + struct ds_tdm_backend *tdm; + + tdm = tdm_backend_from_backend(backend); + tdm_backend_destroy(tdm); +} + +static const struct ds_backend_interface tdm_backend_iface = { + .start = tdm_backend_iface_start, + .destroy = tdm_backend_iface_destroy, + .get_drm_fd = NULL, +}; + +static void +tdm_backend_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tdm_backend *tdm; + + tdm = wl_container_of(listener, tdm, display_destroy); + tdm_backend_destroy(tdm); +} + +static int +tdm_backend_handle_tdm_event(int fd, uint32_t mask, void *data) +{ + struct ds_tdm_backend *tdm; + + tdm = data; + tdm_display_handle_events(tdm->tdm_display); + + return 0; +} diff --git a/src/libds/backend/tdm/meson.build b/src/libds/backend/tdm/meson.build new file mode 100644 index 0000000..9a0b041 --- /dev/null +++ b/src/libds/backend/tdm/meson.build @@ -0,0 +1,8 @@ +libds_files += files( + 'backend.c', + 'output.c', +) + +libds_deps += [ + dependency('libtdm', required: true), +] diff --git a/src/libds/backend/tdm/output.c b/src/libds/backend/tdm/output.c new file mode 100644 index 0000000..74a0e29 --- /dev/null +++ b/src/libds/backend/tdm/output.c @@ -0,0 +1,145 @@ +#include +#include + +#include "libds/log.h" +#include "tdm.h" + +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); + +struct ds_tdm_output * +create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output) +{ + struct ds_tdm_output *output; + tdm_output_conn_status conn; + tdm_error err; + + output = calloc(1, sizeof *output); + if (!output) + return NULL; + + ds_output_init(&output->base, &tdm->base, &tdm_output_iface, + tdm->wl_display); + + output->tdm = tdm; + output->tdm_output = tdm_output; + + err = tdm_output_get_conn_status(tdm_output, &conn); + if (err != TDM_ERROR_NONE) { + ds_err("Could not get connection status of tdm output(%p): err(%d)", + tdm_output, err); + goto err_status; + } + + if (conn == TDM_OUTPUT_CONN_STATUS_CONNECTED) { + output->status = DS_TDM_OUTPUT_CONNECTED; + + if (!tdm_output_init_modes(output)) { + ds_err("Could not initialize modes of tdm output(%p)", + tdm_output); + goto err_status; + } + } + else if (conn == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + output->status = DS_TDM_OUTPUT_DISCONNECTED; + } + + ds_inf("TDM output(%p) created.", output); + + return output; + +err_status: + free(output); + + return NULL; +} + +static struct ds_tdm_output * +tdm_output_from_output(struct ds_output *ds_output) +{ + assert(ds_output->iface == &tdm_output_iface); + return (struct ds_tdm_output *)ds_output; +} + +static void +tdm_output_iface_destroy(struct ds_output *ds_output) +{ + struct ds_tdm_output *output; + + output = tdm_output_from_output(ds_output); + tdm_output_destroy(output); +} + +static bool +tdm_output_iface_commit(struct ds_output *ds_output) +{ + // TODO + return true; +} + +static const struct ds_output_interface tdm_output_iface = +{ + .destroy = tdm_output_iface_destroy, + .commit = tdm_output_iface_commit, +}; + +static void +tdm_output_destroy(struct ds_tdm_output *output) +{ + struct ds_tdm_output_mode *mode, *mode_tmp; + + wl_list_for_each_safe(mode, mode_tmp, &output->base.modes, base.link) { + wl_list_remove(&mode->base.link); + free(mode); + } + + free(output); +} + +static bool +tdm_output_init_modes(struct ds_tdm_output *output) +{ + struct ds_tdm_output_mode *mode; + const tdm_output_mode *tdm_modes, *tdm_mode; + tdm_error err; + int num_modes, i; + + err = tdm_output_get_available_modes(output->tdm_output, &tdm_modes, + &num_modes); + if (err != TDM_ERROR_NONE) { + ds_err("Could not get available modes: output(%p)", output); + return false; + } + + ds_inf("Detected modes:"); + + for (i = 0; i < num_modes; i++) { + tdm_mode = &tdm_modes[i]; + + mode = calloc(1, sizeof *mode); + if (!mode) { + ds_err("Could not allocate memory"); + continue; + } + + mode->tdm_mode = tdm_mode; + mode->base.width = tdm_mode->hdisplay; + mode->base.height = tdm_mode->vdisplay; + mode->base.refresh = (int32_t)tdm_mode->vrefresh; // FIXME + + 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, + mode->base.refresh, + mode->base.preferred ? "(preferred)" : ""); + + if (tdm_mode->type & TDM_OUTPUT_MODE_TYPE_DEFAULT) + wl_list_insert(&output->base.modes, &mode->base.link); + else + wl_list_insert(output->base.modes.prev, &mode->base.link); + } + + return true; +} diff --git a/src/libds/backend/tdm/tdm.h b/src/libds/backend/tdm/tdm.h new file mode 100644 index 0000000..3a8990b --- /dev/null +++ b/src/libds/backend/tdm/tdm.h @@ -0,0 +1,53 @@ +#ifndef DS_BACKEND_TDM_H +#define DS_BACKEND_TDM_H + +#include +#include + +#include "libds/interfaces/backend.h" +#include "libds/interfaces/output.h" + +enum ds_tdm_output_status { + DS_TDM_OUTPUT_DISCONNECTED, + DS_TDM_OUTPUT_CONNECTED, +}; + +struct ds_tdm_output_mode { + struct ds_output_mode base; + const tdm_output_mode *tdm_mode; +}; + +struct ds_tdm_backend +{ + struct ds_backend base; + + tdm_display *tdm_display; + struct wl_display *wl_display; + struct wl_event_source *tdm_event; + + struct wl_list outputs; // ds_tdm_output.link + + struct wl_listener display_destroy; + + clockid_t clock; + int fd; +}; + +struct ds_tdm_output +{ + struct ds_output base; + + struct ds_tdm_backend *tdm; + tdm_output *tdm_output; + + struct wl_list link; + + enum ds_tdm_output_status status; +}; + +struct ds_tdm_backend *tdm_backend_from_backend(struct ds_backend *backend); + +struct ds_tdm_output *create_tdm_output(struct ds_tdm_backend *tdm, + tdm_output *tdm_output); + +#endif diff --git a/src/libds/output.c b/src/libds/output.c index 21d4ff8..f5cd356 100644 --- a/src/libds/output.c +++ b/src/libds/output.c @@ -20,6 +20,8 @@ ds_output_init(struct ds_output *output, struct ds_backend *backend, output->iface = iface; output->display = display; + wl_list_init(&output->modes); + wl_signal_init(&output->events.destroy); wl_signal_init(&output->events.frame); wl_signal_init(&output->events.commit); @@ -65,6 +67,37 @@ ds_output_attach_buffer(struct ds_output *output, struct ds_buffer *buffer) output->pending.buffer = ds_buffer_lock(buffer); } +WL_EXPORT const struct ds_output_mode * +ds_output_preferred_mode(struct ds_output *output) +{ + struct ds_output_mode *mode; + + if (wl_list_empty(&output->modes)) + return NULL; + + wl_list_for_each(mode, &output->modes, link) { + if (mode->preferred) + return mode; + } + + // No preferred mode, choose the first one + return wl_container_of(output->modes.next, mode, link); +} + +WL_EXPORT void +ds_output_set_mode(struct ds_output *output, const struct ds_output_mode *mode) +{ + output->pending.mode = NULL; + output->pending.committed &= ~DS_OUTPUT_STATE_MODE; + + if (output->current_mode == mode) { + return; + } + + output->pending.committed |= DS_OUTPUT_STATE_MODE; + output->pending.mode = mode; +} + WL_EXPORT void ds_output_add_destroy_listener(struct ds_output *output, struct wl_listener *listener) -- 2.7.4 From ac2ee055e3e93cd8eddf8eadec090a7c6b850ca0 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 24 Feb 2022 14:58:44 +0900 Subject: [PATCH 02/16] Add tbm allocator Change-Id: If58f8810ce84cd6ac6fe5cb36127fce6f2e3e655 --- include/libds/allocator/tbm.h | 12 +++ packaging/libds.spec | 1 + src/libds/allocator/tbm.c | 177 ++++++++++++++++++++++++++++++++++++++++++ src/libds/meson.build | 2 + 4 files changed, 192 insertions(+) create mode 100644 include/libds/allocator/tbm.h create mode 100644 src/libds/allocator/tbm.c diff --git a/include/libds/allocator/tbm.h b/include/libds/allocator/tbm.h new file mode 100644 index 0000000..1457e3f --- /dev/null +++ b/include/libds/allocator/tbm.h @@ -0,0 +1,12 @@ +#ifndef LIBDS_ALLOCATOR_TBM_H +#define LIBDS_ALLOCATOR_TBM_H + +#include + +struct ds_allocator * +ds_tbm_allocator_create(void); + +WL_EXPORT void * +ds_tbm_buffer_get_surface(struct ds_buffer *ds_buffer); + +#endif diff --git a/packaging/libds.spec b/packaging/libds.spec index f68b266..aaf79b3 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -15,6 +15,7 @@ BuildRequires: pkgconfig(pixman-1) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(libtdm) +BuildRequires: pkgconfig(libtbm) %description Wayland Compositor Library diff --git a/src/libds/allocator/tbm.c b/src/libds/allocator/tbm.c new file mode 100644 index 0000000..f4d0702 --- /dev/null +++ b/src/libds/allocator/tbm.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include + +#include +#include + +#include "libds/interfaces/allocator.h" +#include "libds/interfaces/buffer.h" +#include "libds/log.h" + +struct ds_tbm_allocator +{ + struct ds_allocator base; + tbm_bufmgr bufmgr; +}; + +struct ds_tbm_buffer +{ + struct ds_buffer base; + tbm_surface_h surface; +}; + +static const struct ds_allocator_interface tbm_allocator_iface; +static struct ds_tbm_buffer *tbm_buffer_from_buffer(struct ds_buffer *buffer); + +WL_EXPORT struct ds_allocator * +ds_tbm_allocator_create(void) +{ + struct ds_tbm_allocator *alloc; + + alloc = calloc(1, sizeof *alloc); + if (!alloc) + return NULL; + + alloc->bufmgr = tbm_bufmgr_init(-1); + if (!alloc->bufmgr) { + ds_err("Could not initialize tbm_bufmgr"); + free(alloc); + return NULL; + } + + ds_allocator_init(&alloc->base, &tbm_allocator_iface, + DS_BUFFER_CAP_DATA_PTR); + + ds_inf("TBM allocator(%p) created", alloc); + + return &alloc->base; +} + +WL_EXPORT void * +ds_tbm_buffer_get_surface(struct ds_buffer *ds_buffer) +{ + struct ds_tbm_buffer *buffer; + + buffer = tbm_buffer_from_buffer(ds_buffer); + if (!buffer) + return NULL; + + return buffer->surface; +} + +static struct ds_tbm_allocator * +tbm_allocator_from_allocator(struct ds_allocator *ds_allocator) +{ + assert(ds_allocator->iface == &tbm_allocator_iface); + return (struct ds_tbm_allocator *)ds_allocator; +} + +static const struct ds_buffer_interface tbm_buffer_iface; + +static struct ds_tbm_buffer * +tbm_buffer_from_buffer(struct ds_buffer *buffer) +{ + assert(buffer->iface == &tbm_buffer_iface); + return (struct ds_tbm_buffer *)buffer; +} + +static void +tbm_buffer_destroy(struct ds_buffer *ds_buffer) +{ + struct ds_tbm_buffer *buffer; + + buffer = tbm_buffer_from_buffer(ds_buffer); + + ds_dbg("Destroy tbm buffer(%p)", buffer); + + tbm_surface_destroy(buffer->surface); + free(buffer); +} + +static bool +tbm_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer, uint32_t flags, + void **data, uint32_t *format, size_t *stride) +{ + struct ds_tbm_buffer *buffer; + tbm_surface_info_s info; + int tbm_access_flags = 0; + int ret; + + buffer = tbm_buffer_from_buffer(ds_buffer); + + if (flags & DS_BUFFER_DATA_PTR_ACCESS_READ) + tbm_access_flags |= TBM_OPTION_READ; + else if (flags & DS_BUFFER_DATA_PTR_ACCESS_WRITE) + tbm_access_flags |= TBM_OPTION_WRITE; + + ret = tbm_surface_map(buffer->surface, tbm_access_flags, &info); + if (ret != TBM_SURFACE_ERROR_NONE) { + ds_err("Could not map tbm_surface of buffer(%p)", buffer); + return false; + } + + *data = info.planes[0].ptr; + *format = info.format; + *stride = info.planes[0].stride; + + return true; +} + +static void +tbm_buffer_end_data_ptr_access(struct ds_buffer *ds_buffer) +{ + struct ds_tbm_buffer *buffer; + + buffer = tbm_buffer_from_buffer(ds_buffer); + + tbm_surface_unmap(buffer->surface); +} + +static const struct ds_buffer_interface tbm_buffer_iface = +{ + .destroy = tbm_buffer_destroy, + .begin_data_ptr_access = tbm_buffer_begin_data_ptr_access, + .end_data_ptr_access = tbm_buffer_end_data_ptr_access, +}; + + +static void +tbm_allocator_destroy(struct ds_allocator *ds_allocator) +{ + struct ds_tbm_allocator *alloc; + + alloc = tbm_allocator_from_allocator(ds_allocator); + + ds_inf("Destroy TBM allocator(%p)", alloc); + + tbm_bufmgr_deinit(alloc->bufmgr); + free(alloc); +} + +static struct ds_buffer * +tbm_allocator_create_buffer(struct ds_allocator *ds_allocator, + int width, int height, uint32_t format) +{ + static int num_buffers = 0; + struct ds_tbm_buffer *buffer; + + buffer = calloc(1, sizeof *buffer); + if (!buffer) + return NULL; + + ds_buffer_init(&buffer->base, &tbm_buffer_iface, width, height); + + buffer->surface = tbm_surface_create(width, height, TBM_FORMAT_XRGB8888); + + ds_dbg("tbm buffer(%p) created: size(%dx%d) number of buffers: %d", + buffer, width, height, ++num_buffers); + + return &buffer->base; +} + +static const struct ds_allocator_interface tbm_allocator_iface = { + .destroy = tbm_allocator_destroy, + .create_buffer = tbm_allocator_create_buffer, +}; diff --git a/src/libds/meson.build b/src/libds/meson.build index 2d09a91..8a88b62 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -4,6 +4,7 @@ libds_files = [ 'buffer.c', 'allocator/allocator.c', 'allocator/shm.c', + 'allocator/tbm.c', 'swapchain.c', 'output.c', 'compositor.c', @@ -50,6 +51,7 @@ 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, -- 2.7.4 From d89f28c7e44df10f3c70f5097acf44014601266e Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 24 Feb 2022 15:01:07 +0900 Subject: [PATCH 03/16] Flesh out tdm backend Change-Id: Idf59ff423465f1f44102058ff017c12b5f54f042 --- include/libds/backend/tdm.h | 9 ++ src/libds/backend/tdm/backend.c | 13 +++ src/libds/backend/tdm/output.c | 180 ++++++++++++++++++++++++++++++++++++++-- src/libds/backend/tdm/tdm.h | 23 ++++- 4 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 include/libds/backend/tdm.h diff --git a/include/libds/backend/tdm.h b/include/libds/backend/tdm.h new file mode 100644 index 0000000..ec5f9cc --- /dev/null +++ b/include/libds/backend/tdm.h @@ -0,0 +1,9 @@ +#ifndef LIBDS_BACKEND_TDM_H +#define LIBDS_BACKEND_TDM_H + +#include + +struct ds_backend * +ds_tdm_backend_create(struct wl_display *display); + +#endif diff --git a/src/libds/backend/tdm/backend.c b/src/libds/backend/tdm/backend.c index 582fe62..2772f84 100644 --- a/src/libds/backend/tdm/backend.c +++ b/src/libds/backend/tdm/backend.c @@ -27,7 +27,9 @@ ds_tdm_backend_create(struct wl_display *display) tdm->wl_display = display; tdm->clock = CLOCK_MONOTONIC; // FIXME + wl_list_init(&tdm->outputs); + wl_list_init(&tdm->buffers); tdm->tdm_display = tdm_display_init(&err); if (err != TDM_ERROR_NONE) { @@ -74,6 +76,17 @@ tdm_backend_from_backend(struct ds_backend *backend) static void tdm_backend_destroy(struct ds_tdm_backend *tdm) { + struct ds_tdm_output *output, *tmp_output; + struct ds_tdm_buffer *buffer, *tmp_buffer; + + wl_list_for_each_safe(output, tmp_output, &tdm->outputs, link) { + ds_output_destroy(&output->base); + } + + wl_list_for_each_safe(buffer, tmp_buffer, &tdm->buffers, link) { + destroy_tdm_buffer(buffer); + } + wl_list_remove(&tdm->display_destroy.link); wl_event_source_remove(tdm->tdm_event); close(tdm->fd); diff --git a/src/libds/backend/tdm/output.c b/src/libds/backend/tdm/output.c index 74a0e29..08b56b5 100644 --- a/src/libds/backend/tdm/output.c +++ b/src/libds/backend/tdm/output.c @@ -2,11 +2,14 @@ #include #include "libds/log.h" +#include "libds/allocator/tbm.h" #include "tdm.h" +#include 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); struct ds_tdm_output * create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output) @@ -22,8 +25,8 @@ create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output) ds_output_init(&output->base, &tdm->base, &tdm_output_iface, tdm->wl_display); - output->tdm = tdm; - output->tdm_output = tdm_output; + output->backend = tdm; + output->tdm.output = tdm_output; err = tdm_output_get_conn_status(tdm_output, &conn); if (err != TDM_ERROR_NONE) { @@ -45,7 +48,10 @@ create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output) output->status = DS_TDM_OUTPUT_DISCONNECTED; } - ds_inf("TDM output(%p) created.", output); + if (tdm_output_get_hwc(output->tdm.output, NULL) != NULL) + tdm_output_init_hwc(output); + + ds_inf("TDM output(%p) created: hwc(%p)", output, output->tdm.hwc); return output; @@ -71,10 +77,148 @@ tdm_output_iface_destroy(struct ds_output *ds_output) tdm_output_destroy(output); } +void +destroy_tdm_buffer(struct ds_tdm_buffer *buffer) +{ + if (buffer == NULL) + return; + + wl_list_remove(&buffer->buffer_destroy.link); + wl_list_remove(&buffer->link); + free(buffer); +} + +static void +buffer_handle_buffer_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tdm_buffer *buffer; + + buffer = wl_container_of(listener, buffer, buffer_destroy); + destroy_tdm_buffer(buffer); +} + +static struct ds_tdm_buffer * +create_tdm_buffer(struct ds_tdm_backend *backend, struct ds_buffer *ds_buffer) +{ + struct ds_tdm_buffer *buffer; + tbm_surface_h surface; + + surface = ds_tbm_buffer_get_surface(ds_buffer); + if (!surface) { + ds_err("Could not get tbm_surface_h"); + return NULL; + } + + buffer = calloc(1, sizeof *buffer); + if (!buffer) { + return NULL; + } + + buffer->surface = surface; + buffer->buffer = ds_buffer_lock(ds_buffer); + wl_list_insert(&backend->buffers, &buffer->link); + + buffer->buffer_destroy.notify = buffer_handle_buffer_destroy; + ds_buffer_add_destroy_listener(ds_buffer, &buffer->buffer_destroy); + + return buffer; +} + +static struct ds_tdm_buffer * +get_or_create_tdm_buffer(struct ds_tdm_backend *backend, + struct ds_buffer *ds_buffer) +{ + struct ds_tdm_buffer *buffer; + + wl_list_for_each(buffer, &backend->buffers, link) { + if (buffer->buffer == ds_buffer && buffer->released) { + buffer->released = false; + ds_buffer_lock(buffer->buffer); + return buffer; + } + } + + return create_tdm_buffer(backend, ds_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) +{ + struct ds_tdm_output *output; + + 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; + + wl_signal_emit(&output->base.events.frame, &output->base); +} + static bool tdm_output_iface_commit(struct ds_output *ds_output) { - // TODO + struct ds_tdm_output *output; + struct ds_tdm_buffer *buffer; + struct ds_buffer *ds_buffer; + + output = tdm_output_from_output(ds_output); + + ds_buffer = ds_output->pending.buffer; + buffer = get_or_create_tdm_buffer(output->backend, ds_buffer); + if (!buffer) + return false; + + if (ds_output->pending.committed & DS_OUTPUT_STATE_BUFFER) { + tdm_region fb_damage; + tdm_error err; + uint32_t num_changes; + + memset(&fb_damage, 0, sizeof(fb_damage)); + err = tdm_hwc_set_client_target_buffer(output->tdm.hwc, + buffer->surface, fb_damage); + if (err != TDM_ERROR_NONE) { + ds_err("Could not set hwc client target buffer"); + ds_buffer_unlock(buffer->buffer); + return false; + } + + err = tdm_hwc_validate(output->tdm.hwc, NULL, 0, &num_changes); + if (err != TDM_ERROR_NONE) { + ds_err("Could not hwc validate"); + ds_buffer_unlock(buffer->buffer); + return false; + } + + err = tdm_hwc_accept_validation(output->tdm.hwc); + if (err != TDM_ERROR_NONE) { + ds_err("Could not hwc accept validation"); + ds_buffer_unlock(buffer->buffer); + return false; + } + + 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); + return false; + } + + if (output->back_buffer) { + output->back_buffer->released = true; + ds_buffer_unlock(output->back_buffer->buffer); + } + + output->back_buffer = buffer; + + ds_dbg("Swap Buffer!!!!!"); + } + return true; } @@ -94,6 +238,12 @@ tdm_output_destroy(struct ds_tdm_output *output) free(mode); } + if (output->back_buffer) + ds_buffer_unlock(output->back_buffer->buffer); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer->buffer); + free(output); } @@ -105,7 +255,7 @@ tdm_output_init_modes(struct ds_tdm_output *output) tdm_error err; int num_modes, i; - err = tdm_output_get_available_modes(output->tdm_output, &tdm_modes, + err = tdm_output_get_available_modes(output->tdm.output, &tdm_modes, &num_modes); if (err != TDM_ERROR_NONE) { ds_err("Could not get available modes: output(%p)", output); @@ -139,7 +289,27 @@ 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; } + +static void +tdm_output_init_hwc(struct ds_tdm_output *output) +{ + tdm_error err; + + output->tdm.hwc = tdm_output_get_hwc(output->tdm.output, &err); + if (err != TDM_ERROR_NONE || !output->tdm.hwc) { + ds_err("Could not get tdm_hwc: output(%p)", output); + return; + } +} diff --git a/src/libds/backend/tdm/tdm.h b/src/libds/backend/tdm/tdm.h index 3a8990b..2b1c1e4 100644 --- a/src/libds/backend/tdm/tdm.h +++ b/src/libds/backend/tdm/tdm.h @@ -26,6 +26,7 @@ struct ds_tdm_backend struct wl_event_source *tdm_event; struct wl_list outputs; // ds_tdm_output.link + struct wl_list buffers; // ds_tdm_buffer.link struct wl_listener display_destroy; @@ -37,17 +38,35 @@ struct ds_tdm_output { struct ds_output base; - struct ds_tdm_backend *tdm; - tdm_output *tdm_output; + struct ds_tdm_backend *backend; + struct ds_tdm_buffer *front_buffer, *back_buffer; + + struct { + tdm_output *output; + tdm_hwc *hwc; + } tdm; struct wl_list link; enum ds_tdm_output_status status; }; +struct ds_tdm_buffer +{ + struct ds_buffer *buffer; + tbm_surface_h surface; + struct wl_list link; // ds_wl_backend.buffers + struct wl_listener buffer_destroy; + + bool released; +}; + struct ds_tdm_backend *tdm_backend_from_backend(struct ds_backend *backend); struct ds_tdm_output *create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output); +void destroy_tdm_buffer(struct ds_tdm_buffer *buffer); + + #endif -- 2.7.4 From e884340a9a401eb3928ae0e0e6da5c56040f8bbd Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 24 Feb 2022 15:01:35 +0900 Subject: [PATCH 04/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 05/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 06/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 07/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 08/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 09/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 10/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 11/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 12/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 13/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 14/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 15/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 16/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