From 7d45a0322bbbc455c9fd8b9582e01b15e2de96df Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 8 Mar 2022 16:21:28 +0900 Subject: [PATCH 01/16] Build 'include' subdir after 'src' A variable 'features' referred from 'include' subdir is set during build of 'src'. Change-Id: I541215320de7100e22d9c0a1a7eed4100c021397 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index db1f43c..0e4e5c0 100644 --- a/meson.build +++ b/meson.build @@ -30,8 +30,8 @@ features = { 'tbm-allocator': false, } -subdir('include') subdir('src') +subdir('include') configure_file(output: 'config.h', install: false, configuration: cdata) -- 2.7.4 From 97cd1fa2babc9a6bc5ab30afcbc5a5621d7f3c5f Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 16 Mar 2022 11:43:49 +0900 Subject: [PATCH 02/16] Add directories for tizen features Change-Id: Ia3a389e793d6ecb3a20e783059fd301e432f73bc --- include/{libds => libds-tizen}/allocator/tbm.h | 4 +-- include/{libds => libds-tizen}/backend/tdm.h | 4 +-- include/meson.build | 16 +++++------- meson.build | 7 ------ meson_options.txt | 2 +- packaging/libds.spec | 25 +++++++++++++++--- src/examples/meson.build | 4 ++- src/examples/tdm-backend.c | 4 +-- src/examples/tinyds-tdm.c | 4 +-- src/libds-tizen/allocator/meson.build | 2 ++ src/{libds => libds-tizen}/allocator/tbm.c | 0 src/libds-tizen/backend/meson.build | 1 + src/{libds => libds-tizen}/backend/tdm/backend.c | 0 src/libds-tizen/backend/tdm/meson.build | 12 +++++++++ src/{libds => libds-tizen}/backend/tdm/output.c | 2 +- src/{libds => libds-tizen}/backend/tdm/tdm.h | 4 +-- src/libds-tizen/meson.build | 29 +++++++++++++++++++++ src/libds/allocator/meson.build | 11 -------- src/libds/backend/meson.build | 14 ----------- src/libds/backend/tdm/meson.build | 32 ------------------------ src/libds/meson.build | 7 ------ src/meson.build | 3 +++ 22 files changed, 90 insertions(+), 97 deletions(-) rename include/{libds => libds-tizen}/allocator/tbm.h (76%) rename include/{libds => libds-tizen}/backend/tdm.h (72%) create mode 100644 src/libds-tizen/allocator/meson.build rename src/{libds => libds-tizen}/allocator/tbm.c (100%) create mode 100644 src/libds-tizen/backend/meson.build rename src/{libds => libds-tizen}/backend/tdm/backend.c (100%) create mode 100644 src/libds-tizen/backend/tdm/meson.build rename src/{libds => libds-tizen}/backend/tdm/output.c (99%) rename src/{libds => libds-tizen}/backend/tdm/tdm.h (95%) create mode 100644 src/libds-tizen/meson.build delete mode 100644 src/libds/backend/tdm/meson.build diff --git a/include/libds/allocator/tbm.h b/include/libds-tizen/allocator/tbm.h similarity index 76% rename from include/libds/allocator/tbm.h rename to include/libds-tizen/allocator/tbm.h index c02aee3..3febb10 100644 --- a/include/libds/allocator/tbm.h +++ b/include/libds-tizen/allocator/tbm.h @@ -1,5 +1,5 @@ -#ifndef LIBDS_ALLOCATOR_TBM_H -#define LIBDS_ALLOCATOR_TBM_H +#ifndef LIBDS_TIZEN_ALLOCATOR_TBM_H +#define LIBDS_TIZEN_ALLOCATOR_TBM_H #include diff --git a/include/libds/backend/tdm.h b/include/libds-tizen/backend/tdm.h similarity index 72% rename from include/libds/backend/tdm.h rename to include/libds-tizen/backend/tdm.h index e697413..d2785b2 100644 --- a/include/libds/backend/tdm.h +++ b/include/libds-tizen/backend/tdm.h @@ -1,5 +1,5 @@ -#ifndef LIBDS_BACKEND_TDM_H -#define LIBDS_BACKEND_TDM_H +#ifndef LIBDS_TIZEN_BACKEND_TDM_H +#define LIBDS_TIZEN_BACKEND_TDM_H #include diff --git a/include/meson.build b/include/meson.build index f273424..0975c5d 100644 --- a/include/meson.build +++ b/include/meson.build @@ -1,13 +1,9 @@ -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'), - exclude_files: exclude_files, ) + +if get_option('tizen') + install_subdir('libds-tizen', + install_dir: get_option('includedir'), + ) +endif diff --git a/meson.build b/meson.build index 0e4e5c0..d3d2df0 100644 --- a/meson.build +++ b/meson.build @@ -25,14 +25,7 @@ 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('src') subdir('include') configure_file(output: 'config.h', install: false, configuration: cdata) - -summary(features, bool_yn: true) diff --git a/meson_options.txt b/meson_options.txt index 02af9b0..6ef6c8e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1 @@ -option('backends', type: 'array', choices: ['auto', 'tdm'], value: ['auto'], description: 'Select built-in backends') +option('tizen', type: 'boolean', value: false, description: 'Build Tizen features') diff --git a/packaging/libds.spec b/packaging/libds.spec index bd38de7..879a87d 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -30,6 +30,12 @@ Requires: %{name} = %{version}-%{release} %description devel Development package of Wayland Compositor Library +%package tizen-devel +Summary: Wayland Compositor development package on Tizen + +%description tizen-devel +Wayland Compositor development library for Tizen platform + %prep %setup -q cp %{SOURCE1001} . @@ -39,7 +45,8 @@ meson setup \ --prefix /usr \ --libdir %{_libdir} \ --bindir %{_bindir} \ - builddir + builddir \ + -Dtizen=true ninja -C builddir all %install @@ -56,7 +63,19 @@ ninja -C builddir install %manifest %{name}.manifest %defattr(-,root,root,-) %license LICENSE -%{_includedir}/* +%{_includedir}/libds/* %{_libdir}/pkgconfig/libds.pc %{_libdir}/libds.so -%{_bindir}/* +%{_bindir}/wl-backend +%{_bindir}/tinyds + +%files tizen-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/* +%{_libdir}/pkgconfig/libds-tizen.pc +%{_libdir}/libds-tizen.so +%{_bindir}/tdm-backend +%{_bindir}/tinyds-tdm +%{_bindir}/ds-simple-tbm diff --git a/src/examples/meson.build b/src/examples/meson.build index 193b4a5..f95bd50 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -23,7 +23,9 @@ executable('tinyds', install : true ) -if features.get('tdm-backend') +if get_option('tizen') + common_deps += dep_libds_tizen + executable('tdm-backend', 'tdm-backend.c', dependencies: common_deps, diff --git a/src/examples/tdm-backend.c b/src/examples/tdm-backend.c index ee39f06..ba3fecb 100644 --- a/src/examples/tdm-backend.c +++ b/src/examples/tdm-backend.c @@ -8,10 +8,10 @@ #include #include #include -#include -#include #include #include +#include +#include #define WIDTH 1280 #define HEIGHT 720 diff --git a/src/examples/tinyds-tdm.c b/src/examples/tinyds-tdm.c index 2c91a66..143d53e 100644 --- a/src/examples/tinyds-tdm.c +++ b/src/examples/tinyds-tdm.c @@ -14,11 +14,11 @@ #include #include #include -#include -#include #include #include #include +#include +#include #define TINYDS_UNUSED __attribute__((unused)) diff --git a/src/libds-tizen/allocator/meson.build b/src/libds-tizen/allocator/meson.build new file mode 100644 index 0000000..fe869bd --- /dev/null +++ b/src/libds-tizen/allocator/meson.build @@ -0,0 +1,2 @@ +libds_tizen_files += files('tbm.c') +libds_tizen_deps += dependency('libtbm', required: true) diff --git a/src/libds/allocator/tbm.c b/src/libds-tizen/allocator/tbm.c similarity index 100% rename from src/libds/allocator/tbm.c rename to src/libds-tizen/allocator/tbm.c diff --git a/src/libds-tizen/backend/meson.build b/src/libds-tizen/backend/meson.build new file mode 100644 index 0000000..8a05e13 --- /dev/null +++ b/src/libds-tizen/backend/meson.build @@ -0,0 +1 @@ +subdir('tdm') diff --git a/src/libds/backend/tdm/backend.c b/src/libds-tizen/backend/tdm/backend.c similarity index 100% rename from src/libds/backend/tdm/backend.c rename to src/libds-tizen/backend/tdm/backend.c diff --git a/src/libds-tizen/backend/tdm/meson.build b/src/libds-tizen/backend/tdm/meson.build new file mode 100644 index 0000000..39ffceb --- /dev/null +++ b/src/libds-tizen/backend/tdm/meson.build @@ -0,0 +1,12 @@ +libds_tizen_files += files( + 'backend.c', + 'output.c', +) + +libtdm = dependency('libtdm', required: true) +libtbm = dependency('libtbm', required: true) + +libds_tizen_deps += [ + libtdm, + libtbm +] diff --git a/src/libds/backend/tdm/output.c b/src/libds-tizen/backend/tdm/output.c similarity index 99% rename from src/libds/backend/tdm/output.c rename to src/libds-tizen/backend/tdm/output.c index 5148853..f6b6250 100644 --- a/src/libds/backend/tdm/output.c +++ b/src/libds-tizen/backend/tdm/output.c @@ -4,7 +4,7 @@ #include #include "libds/log.h" -#include "libds/allocator/tbm.h" +#include "libds-tizen/allocator/tbm.h" #include "tdm.h" diff --git a/src/libds/backend/tdm/tdm.h b/src/libds-tizen/backend/tdm/tdm.h similarity index 95% rename from src/libds/backend/tdm/tdm.h rename to src/libds-tizen/backend/tdm/tdm.h index 1c80ef9..275089c 100644 --- a/src/libds/backend/tdm/tdm.h +++ b/src/libds-tizen/backend/tdm/tdm.h @@ -1,5 +1,5 @@ -#ifndef DS_BACKEND_TDM_H -#define DS_BACKEND_TDM_H +#ifndef DS_TIZEN_BACKEND_TDM_H +#define DS_TIZEN_BACKEND_TDM_H #include diff --git a/src/libds-tizen/meson.build b/src/libds-tizen/meson.build new file mode 100644 index 0000000..e9ca734 --- /dev/null +++ b/src/libds-tizen/meson.build @@ -0,0 +1,29 @@ +libds_tizen_files = [] + +libds_tizen_deps = [ + dep_libds, +] + +subdir('allocator') +subdir('backend') + +lib_libds_tizen = shared_library('ds-tizen', libds_tizen_files, + dependencies: libds_tizen_deps, + include_directories: [ common_inc, include_directories('.') ], + version: meson.project_version(), + install: true +) + +dep_libds_tizen = declare_dependency( + link_with: lib_libds_tizen, + dependencies: libds_tizen_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen, + version: meson.project_version(), + filebase: 'libds-tizen', + name: 'libds-tizen', + description: 'extension of libds for tizen platform', +) diff --git a/src/libds/allocator/meson.build b/src/libds/allocator/meson.build index 361f96e..173c219 100644 --- a/src/libds/allocator/meson.build +++ b/src/libds/allocator/meson.build @@ -1,12 +1 @@ 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 b1fff87..895ffca 100644 --- a/src/libds/backend/meson.build +++ b/src/libds/backend/meson.build @@ -1,15 +1 @@ -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') diff --git a/src/libds/backend/tdm/meson.build b/src/libds/backend/tdm/meson.build deleted file mode 100644 index 82eb165..0000000 --- a/src/libds/backend/tdm/meson.build +++ /dev/null @@ -1,32 +0,0 @@ -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 += [ - libtdm, - libtbm -] - -features += { 'tdm-backend': true } diff --git a/src/libds/meson.build b/src/libds/meson.build index ed8c95f..50f7962 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -68,16 +68,10 @@ 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') @@ -86,5 +80,4 @@ pkgconfig.generate(lib_libds, filebase: meson.project_name(), name: meson.project_name(), description: 'Wayland compositor library', - variables: ds_vars, ) diff --git a/src/meson.build b/src/meson.build index 774c7eb..d739bfe 100644 --- a/src/meson.build +++ b/src/meson.build @@ -11,6 +11,9 @@ wayland_scanner = find_program( ) subdir('libds') +if get_option('tizen') + subdir('libds-tizen') +endif subdir('tests') subdir('examples') subdir('clients') -- 2.7.4 From aa3d710937ec336e6fc7962f2927397d22e768e0 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 16 Mar 2022 13:18:21 +0900 Subject: [PATCH 03/16] libds-tizen: Add ds_tdm_buffer_queue A ds_tdm_buffer_queue is a buffer queue that is able to be acquired from ds_tdm_output. A ds_tdm_buffer_queue provides a handle of native queue to a user and the user may pass it to a renderer. The renderer then should think of native queue as tbm_surface_queue_h. With the tbm_surface_queue_h, the renderer may dequeue a surface from it and draw on the dequeued buffer. After finish drawing on the buffer, the renderer should enqueue it to the tbm_surface_queue_h. As soon as the renderer enqueues buffer to the tbm_surface_queue_h, the user can recieve a notification that the buffer can be acquired from the ds_tbm_buffer_queue using ds_tdm_buffer_queue_add_acquirable_listener(). Then user may acquire a buffer from the ds_tdm_buffer_queue and attach it to a ds_output. Note that although the renderer may enqueue a buffer on different thread from the thread working on libds, but libds will call a callback function which is registered using ds_tdm_buffer_queue_add_acquirable_listener() on the thread working on libds. Change-Id: Ia5c477ceabda7e85f6441a73e76884b95eafa6fb --- include/libds-tizen/backend/tdm.h | 21 ++ src/libds-tizen/backend/tdm/meson.build | 1 + src/libds-tizen/backend/tdm/output.c | 107 +++++++-- src/libds-tizen/backend/tdm/tdm.h | 5 +- src/libds-tizen/backend/tdm/tdm_buffer_queue.c | 311 +++++++++++++++++++++++++ src/libds-tizen/backend/tdm/tdm_buffer_queue.h | 45 ++++ 6 files changed, 464 insertions(+), 26 deletions(-) create mode 100644 src/libds-tizen/backend/tdm/tdm_buffer_queue.c create mode 100644 src/libds-tizen/backend/tdm/tdm_buffer_queue.h diff --git a/include/libds-tizen/backend/tdm.h b/include/libds-tizen/backend/tdm.h index d2785b2..8c5c605 100644 --- a/include/libds-tizen/backend/tdm.h +++ b/include/libds-tizen/backend/tdm.h @@ -2,14 +2,35 @@ #define LIBDS_TIZEN_BACKEND_TDM_H #include +#include #ifdef __cplusplus extern "C" { #endif +struct ds_tdm_output; + +struct ds_tdm_buffer_queue; + struct ds_backend * ds_tdm_backend_create(struct wl_display *display); +struct ds_tdm_output * +ds_tdm_output_from_output(struct ds_output *ds_output); + +struct ds_tdm_buffer_queue * +ds_tdm_output_get_buffer_queue(struct ds_tdm_output *output); + +void * +ds_tdm_buffer_queue_get_native_queue(struct ds_tdm_buffer_queue *queue); + +struct ds_buffer * +ds_tdm_buffer_queue_acquire(struct ds_tdm_buffer_queue *queue); + +void +ds_tdm_buffer_queue_add_acquirable_listener(struct ds_tdm_buffer_queue *queue, + struct wl_listener *listener); + #ifdef __cplusplus } #endif diff --git a/src/libds-tizen/backend/tdm/meson.build b/src/libds-tizen/backend/tdm/meson.build index 39ffceb..932559f 100644 --- a/src/libds-tizen/backend/tdm/meson.build +++ b/src/libds-tizen/backend/tdm/meson.build @@ -1,6 +1,7 @@ libds_tizen_files += files( 'backend.c', 'output.c', + 'tdm_buffer_queue.c', ) libtdm = dependency('libtdm', required: true) diff --git a/src/libds-tizen/backend/tdm/output.c b/src/libds-tizen/backend/tdm/output.c index f6b6250..10b9666 100644 --- a/src/libds-tizen/backend/tdm/output.c +++ b/src/libds-tizen/backend/tdm/output.c @@ -7,6 +7,7 @@ #include "libds-tizen/allocator/tbm.h" #include "tdm.h" +#include "tdm_buffer_queue.h" static const struct ds_output_interface tdm_output_iface; static bool output_init_modes(struct ds_tdm_output *output); @@ -17,6 +18,32 @@ static bool output_set_pending_fb(struct ds_tdm_output *output, struct ds_buffer *ds_buffer); static bool output_hwc_commit(struct ds_tdm_output *output); +WL_EXPORT struct ds_tdm_output * +ds_tdm_output_from_output(struct ds_output *ds_output) +{ + if (ds_output->iface != &tdm_output_iface) { + ds_err("Given ds_output is not for ds_tdm_output"); + return NULL; + } + + return (struct ds_tdm_output *)ds_output; +} + +WL_EXPORT struct ds_tdm_buffer_queue * +ds_tdm_output_get_buffer_queue(struct ds_tdm_output *output) +{ + if (output->queue) + return output->queue; + + output->queue = create_buffer_queue(output); + if (!output->queue) { + ds_err("Could not create tbm_queue with output(%p)", output); + return NULL; + } + + return output->queue; +} + struct ds_tdm_output * create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output) { @@ -89,12 +116,25 @@ destroy_tdm_buffer(struct ds_tdm_buffer *buffer) if (buffer == NULL) return; + if (!buffer->released) + wl_list_remove(&buffer->buffer_release.link); + wl_list_remove(&buffer->buffer_destroy.link); wl_list_remove(&buffer->link); free(buffer); } static void +buffer_handle_buffer_release(struct wl_listener *listener, void *data) +{ + struct ds_tdm_buffer *buffer; + + buffer = wl_container_of(listener, buffer, buffer_release); + wl_list_remove(&buffer->buffer_release.link); + buffer->released = true; +} + +static void buffer_handle_buffer_destroy(struct wl_listener *listener, void *data) { struct ds_tdm_buffer *buffer; @@ -120,7 +160,7 @@ create_tdm_buffer(struct ds_tdm_backend *backend, struct ds_buffer *ds_buffer) return NULL; buffer->surface = surface; - buffer->buffer = ds_buffer_lock(ds_buffer); + buffer->buffer = ds_buffer; wl_list_insert(&backend->buffers, &buffer->link); buffer->buffer_destroy.notify = buffer_handle_buffer_destroy; @@ -137,37 +177,38 @@ get_or_create_tdm_buffer(struct ds_tdm_backend *backend, 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; + goto out; } } - return create_tdm_buffer(backend, ds_buffer); -} + buffer = create_tdm_buffer(backend, ds_buffer); -static void -tdm_buffer_release(struct ds_tdm_buffer *buffer) -{ - buffer->released = true; - ds_buffer_unlock(buffer->buffer); +out: + buffer->released = false; + + buffer->buffer_release.notify = buffer_handle_buffer_release; + ds_buffer_add_release_listener(ds_buffer, &buffer->buffer_release); + + ds_buffer_lock(buffer->buffer); + + return buffer; } static void output_update_front_buffer(struct ds_tdm_output *output) { if (output->front_buffer) - tdm_buffer_release(output->front_buffer); + ds_buffer_unlock(output->front_buffer); output->front_buffer = output->back_buffer; output->back_buffer = NULL; } static void output_attach_back_buffer(struct ds_tdm_output *output, - struct ds_tdm_buffer *buffer) + struct ds_buffer *buffer) { if (output->back_buffer) - tdm_buffer_release(output->back_buffer); + ds_buffer_unlock(output->back_buffer); output->back_buffer = buffer; } @@ -192,9 +233,8 @@ output_iface_commit(struct ds_output *ds_output) if (!output_hwc_commit(output)) { ds_err("Could not commit tdm output"); - if (output->back_buffer) { - tdm_buffer_release(output->back_buffer); - } + if (output->back_buffer) + ds_buffer_unlock(output->back_buffer); } return true; @@ -217,10 +257,13 @@ output_destroy(struct ds_tdm_output *output) } if (output->back_buffer) - ds_buffer_unlock(output->back_buffer->buffer); + ds_buffer_unlock(output->back_buffer); if (output->front_buffer) - ds_buffer_unlock(output->front_buffer->buffer); + ds_buffer_unlock(output->front_buffer); + + if (output->queue) + buffer_queue_destroy(output->queue); free(output); } @@ -306,24 +349,38 @@ static bool output_set_pending_fb(struct ds_tdm_output *output, struct ds_buffer *ds_buffer) { + struct ds_tdm_queue_buffer *queue_buffer; struct ds_tdm_buffer *buffer; + tbm_surface_h surface = NULL; tdm_region fb_damage; tdm_error err; - buffer = get_or_create_tdm_buffer(output->backend, ds_buffer); - if (!buffer) - return false; + if (output->queue) { + queue_buffer = buffer_queue_find_buffer(output->queue, ds_buffer); + if (queue_buffer) { + ds_buffer_lock(ds_buffer); + surface = queue_buffer->surface; + } + } + + if (!surface) { + buffer = get_or_create_tdm_buffer(output->backend, ds_buffer); + if (!buffer) + return false; + + surface = buffer->surface; + } memset(&fb_damage, 0, sizeof(fb_damage)); err = tdm_hwc_set_client_target_buffer(output->tdm.hwc, - buffer->surface, fb_damage); + surface, fb_damage); if (err != TDM_ERROR_NONE) { ds_err("Could not set hwc client target buffer"); - ds_buffer_unlock(buffer->buffer); + ds_buffer_unlock(ds_buffer); return false; } - output_attach_back_buffer(output, buffer); + output_attach_back_buffer(output, ds_buffer); return true; } diff --git a/src/libds-tizen/backend/tdm/tdm.h b/src/libds-tizen/backend/tdm/tdm.h index 275089c..f19483f 100644 --- a/src/libds-tizen/backend/tdm/tdm.h +++ b/src/libds-tizen/backend/tdm/tdm.h @@ -40,7 +40,8 @@ struct ds_tdm_output struct ds_output base; struct ds_tdm_backend *backend; - struct ds_tdm_buffer *front_buffer, *back_buffer; + struct ds_tdm_buffer_queue *queue; + struct ds_buffer *front_buffer, *back_buffer; struct { tdm_output *output; @@ -57,6 +58,8 @@ struct ds_tdm_buffer struct ds_buffer *buffer; tbm_surface_h surface; struct wl_list link; // ds_wl_backend.buffers + + struct wl_listener buffer_release; struct wl_listener buffer_destroy; bool released; diff --git a/src/libds-tizen/backend/tdm/tdm_buffer_queue.c b/src/libds-tizen/backend/tdm/tdm_buffer_queue.c new file mode 100644 index 0000000..7a2a1aa --- /dev/null +++ b/src/libds-tizen/backend/tdm/tdm_buffer_queue.c @@ -0,0 +1,311 @@ +#include +#include +#include +#include + +#include "libds/log.h" +#include "libds/interfaces/buffer.h" + +#include "tdm.h" +#include "tdm_buffer_queue.h" + +static void +buffer_queue_handle_acquirable(tbm_surface_queue_h surface_queue, + void *data); +static struct ds_tdm_queue_buffer * +create_queue_buffer(struct ds_tdm_buffer_queue *queue, + tbm_surface_h surface); +static void queue_buffer_destroy(struct ds_tdm_queue_buffer *buffer); +static void queue_buffer_drop(struct ds_tdm_queue_buffer *buffer); +static struct ds_buffer * +queue_buffer_acquire(struct ds_tdm_queue_buffer *buffer); +static int buffer_queue_handle_acquirable_efd(int fd, uint32_t mask, + void *data); + +WL_EXPORT void * +ds_tdm_buffer_queue_get_native_queue(struct ds_tdm_buffer_queue *queue) +{ + return (void *)queue->tbm_surface_queue; +} + +WL_EXPORT struct ds_buffer * +ds_tdm_buffer_queue_acquire(struct ds_tdm_buffer_queue *queue) +{ + struct ds_tdm_queue_buffer *buffer; + tbm_surface_h surface; + tbm_surface_queue_error_e err; + + if (!tbm_surface_queue_can_acquire(queue->tbm_surface_queue, 0)) + return NULL; + + err = tbm_surface_queue_acquire(queue->tbm_surface_queue, &surface); + if (err != TBM_SURFACE_QUEUE_ERROR_NONE || + surface == NULL) { + ds_err("Could not acquire tbm_surface from queue(%p)", queue); + return NULL; + } + + wl_list_for_each(buffer, &queue->buffers, link) { + if (buffer->surface == surface) + return queue_buffer_acquire(buffer); + } + + buffer = create_queue_buffer(queue, surface); + if (!buffer) { + ds_err("Could not create tbm_queue_buffer with queue(%p)", queue); + return NULL; + } + + wl_list_insert(&queue->buffers, &buffer->link); + + return queue_buffer_acquire(buffer); +} + +WL_EXPORT void +ds_tdm_buffer_queue_add_acquirable_listener(struct ds_tdm_buffer_queue *queue, + struct wl_listener *listener) +{ + wl_signal_add(&queue->events.acquirable, listener); +} + +struct ds_tdm_buffer_queue * +create_buffer_queue(struct ds_tdm_output *output) +{ + struct ds_tdm_buffer_queue *queue; + tdm_error err; + + queue = calloc(1, sizeof *queue); + if (!queue) + return NULL; + + wl_list_init(&queue->buffers); + + wl_signal_init(&queue->events.acquirable); + + queue->tbm_surface_queue = + tdm_hwc_get_client_target_buffer_queue(output->tdm.hwc, &err); + if (err != TDM_ERROR_NONE || + queue->tbm_surface_queue == NULL) { + ds_err("Could not get target buffer queue: err(%d)", err); + free(queue); + return NULL; + } + + tbm_surface_queue_reset(queue->tbm_surface_queue, + output->base.pending.mode->width, + output->base.pending.mode->height, + tbm_surface_queue_get_format(queue->tbm_surface_queue)); + + /* The callback function for tbm_surface_queue_add_acquirable_cb() may be + * called on different thread. This eventfd is to emit a signal of + * events.acquirable on the thread getting this buffer queue. */ + queue->acquirable_efd = eventfd(0, EFD_NONBLOCK); + if (queue->acquirable_efd < 0) { + ds_log_errno(DS_ERR, + "Could not create eventfd for acquirable callback"); + free(queue); + return NULL; + } + + queue->acquirable_source = wl_event_loop_add_fd( + wl_display_get_event_loop(output->backend->wl_display), + queue->acquirable_efd, + WL_EVENT_READABLE, + buffer_queue_handle_acquirable_efd, + queue); + + tbm_surface_queue_add_acquirable_cb(queue->tbm_surface_queue, + buffer_queue_handle_acquirable, (void *)queue); + + return queue; +} + +void +buffer_queue_destroy(struct ds_tdm_buffer_queue *queue) +{ + struct ds_tdm_queue_buffer *buffer, *buffer_tmp; + + wl_list_for_each_safe(buffer, buffer_tmp, &queue->buffers, link) + queue_buffer_drop(buffer); + + wl_event_source_remove(queue->acquirable_source); + close(queue->acquirable_efd); + tbm_surface_queue_destroy(queue->tbm_surface_queue); + free(queue); +} + +struct ds_tdm_queue_buffer * +buffer_queue_find_buffer(struct ds_tdm_buffer_queue *queue, + struct ds_buffer *ds_buffer) +{ + struct ds_tdm_queue_buffer *buffer; + + wl_list_for_each(buffer, &queue->buffers, link) { + if (&buffer->base == ds_buffer) + return buffer; + } + + return NULL; +} + +static void +buffer_queue_handle_acquirable(tbm_surface_queue_h surface_queue, void *data) +{ + struct ds_tdm_buffer_queue *queue = data; + uint64_t acquirable = 1; + int ret; + + ret = write(queue->acquirable_efd, &acquirable, sizeof(acquirable)); + if (ret < 0) + ds_log_errno(DS_ERR, "Could not write eventfd for acquirable buffer"); +} + +static const struct ds_buffer_interface queue_buffer_iface; + +static struct ds_tdm_queue_buffer * +create_queue_buffer(struct ds_tdm_buffer_queue *queue, tbm_surface_h surface) +{ + struct ds_tdm_queue_buffer *buffer; + + buffer = calloc(1, sizeof *buffer); + if (!buffer) + return NULL; + + ds_buffer_init(&buffer->base, &queue_buffer_iface, + tbm_surface_get_width(surface), + tbm_surface_get_height(surface)); + + buffer->queue = queue; + buffer->surface = surface; + + return buffer; +} + +static void +queue_buffer_destroy(struct ds_tdm_queue_buffer *buffer) +{ + free(buffer); +} + +static struct ds_tdm_queue_buffer * +queue_buffer_from_buffer(struct ds_buffer *ds_buffer) +{ + assert(ds_buffer->iface == &queue_buffer_iface); + return (struct ds_tdm_queue_buffer *)ds_buffer; +} + +static void +queue_buffer_iface_destroy(struct ds_buffer *ds_buffer) +{ + struct ds_tdm_queue_buffer *buffer; + + buffer = queue_buffer_from_buffer(ds_buffer); + queue_buffer_destroy(buffer); +} + +static bool +queue_buffer_iface_begin_data_ptr_access(struct ds_buffer *ds_buffer, + uint32_t flags, void **data, uint32_t *format, size_t *stride) +{ + struct ds_tdm_queue_buffer *buffer; + tbm_surface_info_s info; + int tbm_access_flags = 0; + int ret; + + buffer = queue_buffer_from_buffer(ds_buffer); + + if (!buffer->surface) { + ds_err("No tbm_surface. It's a dropped buffer(%p)", buffer); + return false; + } + + 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 +queue_buffer_iface_end_data_ptr_access(struct ds_buffer *ds_buffer) +{ + struct ds_tdm_queue_buffer *buffer; + + buffer = queue_buffer_from_buffer(ds_buffer); + if (!buffer->surface) { + ds_err("No tbm_surface. It's a dropped buffer(%p)", buffer); + return; + } + + tbm_surface_unmap(buffer->surface); +} + +static const struct ds_buffer_interface queue_buffer_iface = +{ + .destroy = queue_buffer_iface_destroy, + .begin_data_ptr_access = queue_buffer_iface_begin_data_ptr_access, + .end_data_ptr_access = queue_buffer_iface_end_data_ptr_access, +}; + +static void +queue_buffer_handle_buffer_release(struct wl_listener *listener, void *data) +{ + struct ds_tdm_queue_buffer *buffer; + + buffer = wl_container_of(listener, buffer, buffer_release); + + wl_list_remove(&buffer->buffer_release.link); + buffer->acquired = false; + + tbm_surface_queue_release(buffer->queue->tbm_surface_queue, + buffer->surface); +} + +static void +queue_buffer_drop(struct ds_tdm_queue_buffer *buffer) +{ + if (buffer->acquired) + wl_list_remove(&buffer->buffer_release.link); + + wl_list_remove(&buffer->link); + ds_buffer_drop(&buffer->base); + buffer->surface = NULL; +} + +static struct ds_buffer * +queue_buffer_acquire(struct ds_tdm_queue_buffer *buffer) +{ + assert(!buffer->acquired); + + buffer->acquired = true; + buffer->buffer_release.notify = queue_buffer_handle_buffer_release; + ds_buffer_add_release_listener(&buffer->base, &buffer->buffer_release); + + return ds_buffer_lock(&buffer->base); +} + +static int +buffer_queue_handle_acquirable_efd(int fd, uint32_t mask, void *data) +{ + struct ds_tdm_buffer_queue *queue = data; + uint64_t acquirable_event; + + if (read(fd, &acquirable_event, sizeof(acquirable_event)) < 0 && + errno != EAGAIN) + return -1; + + wl_signal_emit(&queue->events.acquirable, queue); + + return 0; +} diff --git a/src/libds-tizen/backend/tdm/tdm_buffer_queue.h b/src/libds-tizen/backend/tdm/tdm_buffer_queue.h new file mode 100644 index 0000000..774b7c3 --- /dev/null +++ b/src/libds-tizen/backend/tdm/tdm_buffer_queue.h @@ -0,0 +1,45 @@ +#ifndef DS_TIZEN_BACKEND_TDM_BUFFER_QUEUE_H +#define DS_TIZEN_BACKEND_TBM_BUFFER_QUEUE_H + +#include +#include + +#include "tdm.h" + +struct ds_tdm_buffer_queue +{ + tbm_surface_queue_h tbm_surface_queue; + struct wl_event_source *acquirable_source; + + struct wl_list buffers; // ds_tdm_queue_buffer.link + + struct { + struct wl_signal acquirable; + } events; + + int acquirable_efd; +}; + +struct ds_tdm_queue_buffer +{ + struct ds_buffer base; + + struct ds_tdm_output *output; + struct ds_tdm_buffer_queue *queue; + tbm_surface_h surface; + + struct wl_list link; + struct wl_listener buffer_release; + + bool acquired; +}; + +struct ds_tdm_buffer_queue *create_buffer_queue(struct ds_tdm_output *output); + +void buffer_queue_destroy(struct ds_tdm_buffer_queue *queue); + +struct ds_tdm_queue_buffer * +buffer_queue_find_buffer(struct ds_tdm_buffer_queue *queue, + struct ds_buffer *ds_buffer); + +#endif -- 2.7.4 From 082ff4eb7b58a49d8270752308f38159ce80f18f Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 17 Mar 2022 16:40:37 +0900 Subject: [PATCH 04/16] Add an example of using ds_tdm_buffer_queue Dependeing on the declaration of USE_TDM_BUFFER_QUEUE macro, tinyds-tdm may be run with ds_tbm_buffer_queue. Change-Id: I1d221d2d5eb94024902eea66d08f5973f1914771 --- src/examples/meson.build | 3 + src/examples/pixman-helper.c | 5 +- src/examples/pixman-helper.h | 3 + src/examples/pixman-tbm-helper.c | 64 +++++++++++ src/examples/pixman-tbm-helper.h | 13 +++ src/examples/tbm-server-helper.c | 24 ++-- src/examples/tbm-server-helper.h | 6 + src/examples/tinyds-tdm-renderer.c | 187 ++++++++++++++++++++++++++++++ src/examples/tinyds-tdm-renderer.h | 48 ++++++++ src/examples/tinyds-tdm.c | 227 +++++++++++++++++++++++++++++-------- 10 files changed, 520 insertions(+), 60 deletions(-) create mode 100644 src/examples/pixman-tbm-helper.c create mode 100644 src/examples/pixman-tbm-helper.h create mode 100644 src/examples/tinyds-tdm-renderer.c create mode 100644 src/examples/tinyds-tdm-renderer.h diff --git a/src/examples/meson.build b/src/examples/meson.build index f95bd50..c60b610 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -35,8 +35,10 @@ if get_option('tizen') tinyds_tdm_files = [ 'tinyds-tdm.c', + 'tinyds-tdm-renderer.c', 'tbm-server-helper.c', 'pixman-helper.c', + 'pixman-tbm-helper.c', ] executable('tinyds-tdm', tinyds_tdm_files, @@ -46,6 +48,7 @@ if get_option('tizen') dependency('libdrm', required: true), dependency('libtbm', required: true), dependency('wayland-tbm-server', required: true), + dependency('threads', required: true), ], install_dir: libds_bindir, install : true diff --git a/src/examples/pixman-helper.c b/src/examples/pixman-helper.c index 5d42ec6..36a22e8 100644 --- a/src/examples/pixman-helper.c +++ b/src/examples/pixman-helper.c @@ -5,8 +5,6 @@ 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, @@ -37,7 +35,6 @@ pixman_image_from_buffer(struct ds_buffer *buffer, return image; } - void pixman_image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b) { @@ -56,7 +53,7 @@ pixman_image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b) pixman_image_unref(color_image); } -static pixman_color_t * +pixman_color_t * color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b) { tmp->alpha = 65535; diff --git a/src/examples/pixman-helper.h b/src/examples/pixman-helper.h index aa039ff..99ceaca 100644 --- a/src/examples/pixman-helper.h +++ b/src/examples/pixman-helper.h @@ -12,4 +12,7 @@ void pixman_image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b); +pixman_color_t * +color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b); + #endif diff --git a/src/examples/pixman-tbm-helper.c b/src/examples/pixman-tbm-helper.c new file mode 100644 index 0000000..710eceb --- /dev/null +++ b/src/examples/pixman-tbm-helper.c @@ -0,0 +1,64 @@ +#include + +#include "pixman-tbm-helper.h" + +static uint32_t convert_tbm_format_to_pixman(uint32_t fmt); +static void destroy_tbm_pixman_image(pixman_image_t *image, void *data); + +pixman_image_t * +pixman_image_from_tbm_surface(tbm_surface_h surface, + enum ds_buffer_data_ptr_access_flag access_flag) +{ + pixman_image_t *image; + tbm_surface_info_s info; + uint32_t format; + int tbm_access_flag = 0; + int width, height; + int ret; + + width = tbm_surface_get_width(surface); + height = tbm_surface_get_height(surface); + + if (access_flag & DS_BUFFER_DATA_PTR_ACCESS_READ) + tbm_access_flag |= TBM_OPTION_READ; + if (access_flag & DS_BUFFER_DATA_PTR_ACCESS_WRITE) + tbm_access_flag |= TBM_OPTION_WRITE; + + ret = tbm_surface_map(surface, tbm_access_flag, &info); + assert(ret == TBM_SURFACE_ERROR_NONE); + + format = convert_tbm_format_to_pixman(info.format); + image = pixman_image_create_bits(format, width, height, + (uint32_t *)info.planes[0].ptr, + info.planes[0].stride); + assert(image); + + tbm_surface_internal_ref(surface); + + pixman_image_set_destroy_function(image, + destroy_tbm_pixman_image, surface); + + return image; +} + +static void +destroy_tbm_pixman_image(pixman_image_t *image, void *data) +{ + tbm_surface_h surface = data; + + tbm_surface_unmap(surface); + tbm_surface_internal_unref(surface); +} + +static uint32_t +convert_tbm_format_to_pixman(uint32_t fmt) +{ + switch (fmt) { + case TBM_FORMAT_XRGB8888: + return PIXMAN_x8r8g8b8; + case TBM_FORMAT_ARGB8888: + return PIXMAN_a8r8g8b8; + default: + assert(0 && "not reached"); + } +} diff --git a/src/examples/pixman-tbm-helper.h b/src/examples/pixman-tbm-helper.h new file mode 100644 index 0000000..bf9bd55 --- /dev/null +++ b/src/examples/pixman-tbm-helper.h @@ -0,0 +1,13 @@ +#ifndef EXAMPLES_PIXMAN_TBM_HELPER_H +#define EXAMPLES_PIXMAN_TBM_HELPER_H + +#include +#include +#include +#include + +pixman_image_t * +pixman_image_from_tbm_surface(tbm_surface_h surface, + enum ds_buffer_data_ptr_access_flag access_flag); + +#endif diff --git a/src/examples/tbm-server-helper.c b/src/examples/tbm-server-helper.c index bd3a34d..320ee4f 100644 --- a/src/examples/tbm-server-helper.c +++ b/src/examples/tbm-server-helper.c @@ -8,6 +8,8 @@ #include static const struct ds_buffer_resource_interface tbm_buffer_resource_iface; +static const struct ds_buffer_interface tbm_client_buffer_iface; + static void tbm_server_handle_display_destroy(struct wl_listener *listener, void *data); static struct tbm_client_buffer * @@ -42,6 +44,19 @@ tbm_server_init_display(struct tbm_server *tbm, struct wl_display *display) return true; } +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; +} + +tbm_surface_h +tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer) +{ + return buffer->surface; +} + static void tbm_server_handle_display_destroy(struct wl_listener *listener, void *data) { @@ -107,15 +122,6 @@ static const struct ds_buffer_resource_interface tbm_buffer_resource_iface = { .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) { diff --git a/src/examples/tbm-server-helper.h b/src/examples/tbm-server-helper.h index a82ad5b..609f370 100644 --- a/src/examples/tbm-server-helper.h +++ b/src/examples/tbm-server-helper.h @@ -32,4 +32,10 @@ bool tbm_server_init_display(struct tbm_server *tbm_server, struct wl_display *display); +struct tbm_client_buffer * +tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer); + +tbm_surface_h +tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer); + #endif diff --git a/src/examples/tinyds-tdm-renderer.c b/src/examples/tinyds-tdm-renderer.c new file mode 100644 index 0000000..0074dc9 --- /dev/null +++ b/src/examples/tinyds-tdm-renderer.c @@ -0,0 +1,187 @@ +#include +#include + +#include + +#include "pixman-helper.h" +#include "pixman-tbm-helper.h" +#include "tinyds-tdm-renderer.h" + +static void renderer_setup_thread(struct tinyds_renderer *renderer); +static void *renderer_thread_func(void *data); +static void texture_destroy(struct tinyds_texture *texture); + +bool +init_renderer(struct tinyds_renderer *renderer) +{ + renderer->damaged = false; + + wl_list_init(&renderer->textures); + + renderer_setup_thread(renderer); + + return true; +} + +void +fini_renderer(struct tinyds_renderer *renderer) +{ + pthread_mutex_lock(&renderer->mutex); + + renderer->destroying = true; + pthread_cond_signal(&renderer->cond); + + pthread_mutex_unlock(&renderer->mutex); + + pthread_join(renderer->worker_thread, NULL); + + pthread_mutex_destroy(&renderer->mutex); + pthread_cond_destroy(&renderer->cond); +} + +void +renderer_set_surface_queue(struct tinyds_renderer *renderer, + void *surface_queue) +{ + pthread_mutex_lock(&renderer->mutex); + + renderer->surface_queue = (tbm_surface_queue_h)surface_queue; + + pthread_mutex_unlock(&renderer->mutex); +} + +void +renderer_set_bg_color(struct tinyds_renderer *renderer, + uint8_t r, uint8_t g, uint8_t b) +{ + pixman_color_t color; + + pthread_mutex_lock(&renderer->mutex); + + color_rgb888(&color, r, g, b); + + renderer->bg_image = pixman_image_create_solid_fill(&color); + assert(renderer->bg_image); + + renderer->damaged = true; + + pthread_mutex_unlock(&renderer->mutex); +} + +void +renderer_add_texture(struct tinyds_renderer *renderer, + tbm_surface_h tbm_surface, int x, int y) +{ + struct tinyds_texture *texture; + + pthread_mutex_lock(&renderer->mutex); + + texture = calloc(1, sizeof *texture); + + texture->x = x; + texture->y = y; + texture->renderer = renderer; + texture->surface = tbm_surface; + texture->image = pixman_image_from_tbm_surface(tbm_surface, + DS_BUFFER_DATA_PTR_ACCESS_READ); + + wl_list_insert(renderer->textures.prev, &texture->link); + + ds_dbg("Add texture(%p)", texture); + + pthread_mutex_unlock(&renderer->mutex); +} + +void +renderer_draw(struct tinyds_renderer *renderer) +{ + pthread_mutex_lock(&renderer->mutex); + + renderer->damaged = true; + pthread_cond_signal(&renderer->cond); + + pthread_mutex_unlock(&renderer->mutex); +} + +static void +renderer_setup_thread(struct tinyds_renderer *renderer) +{ + pthread_mutex_init(&renderer->mutex, NULL); + pthread_cond_init(&renderer->cond, NULL); + pthread_create(&renderer->worker_thread, NULL, + renderer_thread_func, renderer); +} + +static void * +renderer_thread_func(void *data) +{ + struct tinyds_renderer *renderer = data; + struct tinyds_texture *texture, *texture_tmp; + pixman_image_t *dst_image; + tbm_surface_h surface; + tbm_surface_queue_error_e err; + + pthread_mutex_lock(&renderer->mutex); + + while (!renderer->destroying) { + if (!renderer->damaged) + pthread_cond_wait(&renderer->cond, &renderer->mutex); + + if (!renderer->damaged) + continue; + + if (!tbm_surface_queue_can_dequeue(renderer->surface_queue, 0)) + continue; + + ds_dbg(">> BEGIN DRAW"); + + err = tbm_surface_queue_dequeue(renderer->surface_queue, &surface); + assert(err == TBM_SURFACE_QUEUE_ERROR_NONE); + + dst_image = pixman_image_from_tbm_surface(surface, + DS_BUFFER_DATA_PTR_ACCESS_WRITE); + + if (renderer->bg_image) { + pixman_image_composite32(PIXMAN_OP_SRC, + renderer->bg_image, + NULL, + dst_image, + 0, 0, 0, 0, 0, 0, + pixman_image_get_width(dst_image), + pixman_image_get_height(dst_image)); + } + + wl_list_for_each_safe(texture, texture_tmp, &renderer->textures, link) { + ds_dbg("Draw texture(%p)", texture); + pixman_image_composite32(PIXMAN_OP_OVER, + texture->image, + NULL, + dst_image, + 0, 0, 0, 0, + texture->x, texture->y, + pixman_image_get_width(texture->image), + pixman_image_get_height(texture->image)); + texture_destroy(texture); + } + pixman_image_unref(dst_image); + + err = tbm_surface_queue_enqueue(renderer->surface_queue, surface); + assert(err == TBM_SURFACE_QUEUE_ERROR_NONE); + + renderer->damaged = false; + + ds_dbg("<< END DRAW"); + } + + pthread_mutex_unlock(&renderer->mutex); + + return NULL; +} + +static void +texture_destroy(struct tinyds_texture *texture) +{ + pixman_image_unref(texture->image); + wl_list_remove(&texture->link); + free(texture); +} diff --git a/src/examples/tinyds-tdm-renderer.h b/src/examples/tinyds-tdm-renderer.h new file mode 100644 index 0000000..5f3e6fd --- /dev/null +++ b/src/examples/tinyds-tdm-renderer.h @@ -0,0 +1,48 @@ +#ifndef EXAMPLES_TINYDS_TDM_RENDERER_H +#define EXAMPLES_TINYDS_TDM_RENDERER_H + +#include +#include +#include +#include +#include + +struct tinyds_renderer +{ + tbm_surface_queue_h surface_queue; + + struct wl_list textures; + + pthread_t worker_thread; + pthread_mutex_t mutex; + pthread_cond_t cond; + + pixman_image_t *bg_image; + + bool damaged; + bool destroying; +}; + +struct tinyds_texture +{ + struct tinyds_renderer *renderer; + pixman_image_t *image; + tbm_surface_h surface; + + struct wl_list link; + struct wl_listener buffer_destroy; + + int x, y; +}; + +bool init_renderer(struct tinyds_renderer *renderer); +void fini_renderer(struct tinyds_renderer *renderer); +void renderer_set_surface_queue(struct tinyds_renderer *renderer, + void *surface_queue); +void renderer_set_bg_color(struct tinyds_renderer *renderer, + uint8_t r, uint8_t g, uint8_t b); +void renderer_add_texture(struct tinyds_renderer *renderer, + tbm_surface_h tbm_surface, int x, int y); +void renderer_draw(struct tinyds_renderer *renderer); + +#endif diff --git a/src/examples/tinyds-tdm.c b/src/examples/tinyds-tdm.c index 143d53e..6ec1156 100644 --- a/src/examples/tinyds-tdm.c +++ b/src/examples/tinyds-tdm.c @@ -1,6 +1,3 @@ -#include "tbm-server-helper.h" -#include "pixman-helper.h" - #include #include #include @@ -14,12 +11,23 @@ #include #include #include -#include #include #include #include #include +#define USE_TDM_BUFFER_QUEUE + +#ifdef USE_TDM_BUFFER_QUEUE +#include "pixman-tbm-helper.h" +#include "tinyds-tdm-renderer.h" +#else +#include +#endif + +#include "tbm-server-helper.h" +#include "pixman-helper.h" + #define TINYDS_UNUSED __attribute__((unused)) struct tinyds_output @@ -27,7 +35,13 @@ struct tinyds_output struct tinyds_server *server; struct ds_output *ds_output; struct ds_allocator *allocator; +#ifdef USE_TDM_BUFFER_QUEUE + struct tinyds_renderer renderer; + struct ds_tdm_buffer_queue *buffer_queue; + struct wl_listener buffer_queue_acquirable; +#else struct ds_swapchain *swapchain; +#endif struct ds_buffer *front_buffer; struct wl_listener output_destroy; @@ -62,6 +76,7 @@ struct tinyds_view { struct tinyds_server *server; + struct tinyds_texture *texture; struct ds_xdg_surface *xdg_surface; struct wl_listener xdg_surface_map; @@ -82,7 +97,18 @@ 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_with_damage(struct tinyds_server *server); static void draw_output(struct tinyds_output *output); +static void output_swap_buffer(struct tinyds_output *output, + struct ds_buffer *buffer); +static void view_send_frame_done(struct tinyds_view *view); +#ifdef USE_TDM_BUFFER_QUEUE +static void output_buffer_queue_init(struct tinyds_output *output); +static void output_renderer_init(struct tinyds_output *output); +static void output_draw_with_renderer(struct tinyds_output *output); +#else +static void output_swapchain_init(struct tinyds_output *output); +static void output_draw_with_swapchain(struct tinyds_output *output); static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); +#endif int main(void) @@ -150,10 +176,10 @@ view_handle_xdg_surface_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED) { struct tinyds_view *view; + struct tinyds_server *server; view = wl_container_of(listener, view, xdg_surface_destroy); - - draw_server_with_damage(view->server); + server = view->server; wl_list_remove(&view->xdg_surface_destroy.link); wl_list_remove(&view->xdg_surface_map.link); @@ -161,6 +187,8 @@ view_handle_xdg_surface_destroy(struct wl_listener *listener, wl_list_remove(&view->surface_commit.link); wl_list_remove(&view->link); free(view); + + draw_server_with_damage(server); } static void @@ -237,32 +265,25 @@ 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, - mode->width, mode->height, DRM_FORMAT_XRGB8888); - if (!output->swapchain) { - ds_allocator_destroy(output->allocator); - free(output); - return; - } - output->server = server; output->ds_output = ds_output; + output->width = mode->width; + output->height = mode->height; output->drawable = true; output->damaged = true; +#ifdef USE_TDM_BUFFER_QUEUE + output_buffer_queue_init(output); + output_renderer_init(output); +#else + output_swapchain_init(output); +#endif + output->output_destroy.notify = output_handle_destroy; - ds_output_add_destroy_listener(ds_output, - &output->output_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); + ds_output_add_frame_listener(ds_output, &output->output_frame); server->output = output; @@ -318,11 +339,15 @@ output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED) if (output->front_buffer) ds_buffer_unlock(output->front_buffer); +#ifdef USE_TDM_BUFFER_QUEUE + fini_renderer(&output->renderer); +#else if (output->swapchain) ds_swapchain_destroy(output->swapchain); if (output->allocator) ds_allocator_destroy(output->allocator); +#endif wl_display_terminate(output->server->display); @@ -348,15 +373,102 @@ draw_server_with_damage(struct tinyds_server *server) draw_output(server->output); } +#ifdef USE_TDM_BUFFER_QUEUE static void -draw_output(struct tinyds_output *output) +output_handle_buffer_queue_acquirable(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_output *output; + struct ds_buffer *buffer; + + output = wl_container_of(listener, output, buffer_queue_acquirable); + + buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue); + assert(buffer); + + output_swap_buffer(output, buffer); +} + +static void +output_buffer_queue_init(struct tinyds_output *output) +{ + struct ds_tdm_output *tdm_output; + + tdm_output = ds_tdm_output_from_output(output->ds_output); + assert(tdm_output); + + output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output); + assert(output->buffer_queue); + + output->buffer_queue_acquirable.notify = + output_handle_buffer_queue_acquirable; + ds_tdm_buffer_queue_add_acquirable_listener(output->buffer_queue, + &output->buffer_queue_acquirable); +} + +static void +output_renderer_init(struct tinyds_output *output) +{ + init_renderer(&output->renderer); + + renderer_set_surface_queue(&output->renderer, + ds_tdm_buffer_queue_get_native_queue(output->buffer_queue)); + + renderer_set_bg_color(&output->renderer, 80, 80, 80); +} + +static void +output_draw_with_renderer(struct tinyds_output *output) { - struct ds_buffer *output_buffer; - pixman_image_t *output_image; struct tinyds_view *view; - if (!output->drawable || !output->damaged) - return; + ds_dbg(">> BEGIN UPDATE TEXTURES"); + + wl_list_for_each(view, &output->server->views, link) { + struct ds_buffer *ds_buffer; + struct tbm_client_buffer *buffer; + tbm_surface_h surface; + + if (!view->mapped) + continue; + + ds_buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + assert(buffer); + + buffer = tbm_client_buffer_from_buffer(ds_buffer); + assert(buffer); + + surface = tbm_client_buffer_get_tbm_surface(buffer); + + renderer_add_texture(&output->renderer, surface, view->x, view->y); + + view_send_frame_done(view); + } + + ds_dbg("<< END UPDATE TEXTURES"); + + renderer_draw(&output->renderer); + +} +#else +static void +output_swapchain_init(struct tinyds_output *output) +{ + output->allocator = ds_tbm_allocator_create(); + assert(output->allocator); + + output->swapchain = ds_swapchain_create(output->allocator, + mode->width, mode->height, DRM_FORMAT_XRGB8888); + assert(output->swapchain); +} + +static void +output_draw_with_swapchain(struct tinyds_output *output) +{ + struct tinyds_view *view; + struct ds_buffer *output_buffer; + pixman_image_t *output_image; output_buffer = ds_swapchain_acquire(output->swapchain, NULL); if (!output_buffer) @@ -378,24 +490,7 @@ draw_output(struct tinyds_output *output) } 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 -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); + output_swap_buffer(output, output_buffer); } static void @@ -423,6 +518,44 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_image) view_send_frame_done(view); } +#endif + +static void +draw_output(struct tinyds_output *output) +{ + + if (!output->drawable || !output->damaged) + return; + +#ifdef USE_TDM_BUFFER_QUEUE + output_draw_with_renderer(output); +#else + output_draw_with_swapchain(output); +#endif + + output->drawable = false; + output->damaged = false; +} + +static void +output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer) +{ + ds_output_attach_buffer(output->ds_output, buffer); + ds_output_commit(output->ds_output); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + output->front_buffer = buffer; +} + +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 int server_dispatch_stdin(int fd, uint32_t mask, void *data) -- 2.7.4 From 43c51b3bee4ee7bf17cdba0cff235ebb21554234 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 17 Mar 2022 19:52:29 +0900 Subject: [PATCH 05/16] Fix typo on a word of header guard Change-Id: Ie18d91a7868efa6b13175693d4f9a99c2481d09e --- src/libds-tizen/backend/tdm/tdm_buffer_queue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libds-tizen/backend/tdm/tdm_buffer_queue.h b/src/libds-tizen/backend/tdm/tdm_buffer_queue.h index 774b7c3..a983265 100644 --- a/src/libds-tizen/backend/tdm/tdm_buffer_queue.h +++ b/src/libds-tizen/backend/tdm/tdm_buffer_queue.h @@ -1,5 +1,5 @@ #ifndef DS_TIZEN_BACKEND_TDM_BUFFER_QUEUE_H -#define DS_TIZEN_BACKEND_TBM_BUFFER_QUEUE_H +#define DS_TIZEN_BACKEND_TDM_BUFFER_QUEUE_H #include #include -- 2.7.4 From 3009fac9ea49a2ed4b041128a259e6e47a1ca275 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 28 Mar 2022 20:03:20 +0900 Subject: [PATCH 06/16] Add ds_tbm_server ds_tbm_server initializes wayland_tbm to allow wl_client to use tbm_surface as a wl_buffer. Change-Id: Ic3a450b6d450bad94388eeca5e9433b5dc799513 --- include/libds-tizen/tbm_server.h | 24 +++ src/examples/meson.build | 6 +- src/examples/tbm-server-helper.h | 41 ----- src/examples/tinyds-tdm.c | 23 ++- src/libds-tizen/meson.build | 8 +- src/libds-tizen/pixel_format.c | 61 ++++++ src/libds-tizen/pixel_format.h | 10 + .../tbm_server.c} | 204 ++++++++++++--------- src/libds-tizen/tbm_server.h | 34 ++++ 9 files changed, 272 insertions(+), 139 deletions(-) create mode 100644 include/libds-tizen/tbm_server.h delete mode 100644 src/examples/tbm-server-helper.h create mode 100644 src/libds-tizen/pixel_format.c create mode 100644 src/libds-tizen/pixel_format.h rename src/{examples/tbm-server-helper.c => libds-tizen/tbm_server.c} (66%) create mode 100644 src/libds-tizen/tbm_server.h diff --git a/include/libds-tizen/tbm_server.h b/include/libds-tizen/tbm_server.h new file mode 100644 index 0000000..c48977e --- /dev/null +++ b/include/libds-tizen/tbm_server.h @@ -0,0 +1,24 @@ +#ifndef LIBDS_TIZEN_TBM_SERVER_H +#define LIBDS_TIZEN_TBM_SERVER_H + +#include +#include + +struct ds_tbm_server; + +struct ds_tbm_client_buffer; + +struct ds_tbm_server * +ds_tbm_server_create(struct wl_display *display); + +void +ds_tbm_server_add_destroy_listener(struct ds_tbm_server *tbm, + struct wl_listener *listener); + +struct ds_tbm_client_buffer * +ds_tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer); + +tbm_surface_h +ds_tbm_client_buffer_get_tbm_surface(struct ds_tbm_client_buffer *buffer); + +#endif diff --git a/src/examples/meson.build b/src/examples/meson.build index c60b610..ddb0792 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -35,19 +35,15 @@ if get_option('tizen') tinyds_tdm_files = [ 'tinyds-tdm.c', - 'tinyds-tdm-renderer.c', - 'tbm-server-helper.c', 'pixman-helper.c', 'pixman-tbm-helper.c', + 'tinyds-tdm-renderer.c', ] executable('tinyds-tdm', 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), dependency('threads', required: true), ], install_dir: libds_bindir, diff --git a/src/examples/tbm-server-helper.h b/src/examples/tbm-server-helper.h deleted file mode 100644 index 609f370..0000000 --- a/src/examples/tbm-server-helper.h +++ /dev/null @@ -1,41 +0,0 @@ -#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); - -struct tbm_client_buffer * -tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer); - -tbm_surface_h -tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer); - -#endif diff --git a/src/examples/tinyds-tdm.c b/src/examples/tinyds-tdm.c index 6ec1156..c14cb9e 100644 --- a/src/examples/tinyds-tdm.c +++ b/src/examples/tinyds-tdm.c @@ -15,6 +15,7 @@ #include #include #include +#include #define USE_TDM_BUFFER_QUEUE @@ -25,7 +26,6 @@ #include #endif -#include "tbm-server-helper.h" #include "pixman-helper.h" #define TINYDS_UNUSED __attribute__((unused)) @@ -55,7 +55,7 @@ struct tinyds_output struct tinyds_server { - struct tbm_server tbm_server; + struct ds_tbm_server *tbm_server; struct wl_display *display; @@ -127,9 +127,6 @@ main(void) res = init_server(server, display); assert(res); - res = tbm_server_init_display(&server->tbm_server, display); - assert(res); - socket = wl_display_add_socket_auto(display); assert(socket); @@ -314,6 +311,12 @@ init_server(struct tinyds_server *server, struct wl_display *display) return false; } + server->tbm_server = ds_tbm_server_create(display); + if (!server->tbm_server) { + ds_backend_destroy(server->backend); + return false; + } + server->xdg_shell = ds_xdg_shell_create(display); if (!server->xdg_shell) { ds_backend_destroy(server->backend); @@ -426,7 +429,7 @@ output_draw_with_renderer(struct tinyds_output *output) wl_list_for_each(view, &output->server->views, link) { struct ds_buffer *ds_buffer; - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *tbm_buffer; tbm_surface_h surface; if (!view->mapped) @@ -434,12 +437,12 @@ output_draw_with_renderer(struct tinyds_output *output) ds_buffer = ds_surface_get_buffer( ds_xdg_surface_get_surface(view->xdg_surface)); - assert(buffer); + assert(ds_buffer); - buffer = tbm_client_buffer_from_buffer(ds_buffer); - assert(buffer); + tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer); + assert(tbm_buffer); - surface = tbm_client_buffer_get_tbm_surface(buffer); + surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer); renderer_add_texture(&output->renderer, surface, view->x, view->y); diff --git a/src/libds-tizen/meson.build b/src/libds-tizen/meson.build index e9ca734..4f76b68 100644 --- a/src/libds-tizen/meson.build +++ b/src/libds-tizen/meson.build @@ -1,7 +1,13 @@ -libds_tizen_files = [] +libds_tizen_files = [ + 'pixel_format.c', + 'tbm_server.c', +] libds_tizen_deps = [ dep_libds, + dependency('libdrm', required: true), + dependency('libtbm', required: true), + dependency('wayland-tbm-server', required: true), ] subdir('allocator') diff --git a/src/libds-tizen/pixel_format.c b/src/libds-tizen/pixel_format.c new file mode 100644 index 0000000..021652e --- /dev/null +++ b/src/libds-tizen/pixel_format.c @@ -0,0 +1,61 @@ +#include +#include +#include + +#include "libds/log.h" +#include "pixel_format.h" + +#ifdef ARRAY_LENGTH +#undef ARRAY_LENGTH +#endif + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +struct ds_tbm_format +{ + uint32_t drm_format; + uint32_t tbm_format; +}; + +static const struct ds_tbm_format formats[] = +{ + { + .drm_format = DRM_FORMAT_ARGB8888, + .tbm_format = TBM_FORMAT_ARGB8888, + }, + { + .drm_format = DRM_FORMAT_XRGB8888, + .tbm_format = TBM_FORMAT_XRGB8888, + }, + /* TODO more format */ +}; + +uint32_t +convert_drm_format_to_tbm(uint32_t fmt) +{ + size_t i; + + for (i = 0; i < ARRAY_LENGTH(formats); i++) { + if (formats[i].drm_format == fmt) + return formats[i].tbm_format; + } + + ds_err("DRM format 0x%"PRIX32" has no TBM equivalent", fmt); + + return 0; +} + +uint32_t +convert_tbm_format_to_drm(uint32_t fmt) +{ + size_t i; + + for (i = 0; i < ARRAY_LENGTH(formats); i++) { + if (formats[i].tbm_format == fmt) + return formats[i].drm_format; + } + + ds_err("TBM format 0x%"PRIX32" has no DRM equivalent", fmt); + + return 0; +} diff --git a/src/libds-tizen/pixel_format.h b/src/libds-tizen/pixel_format.h new file mode 100644 index 0000000..a63d096 --- /dev/null +++ b/src/libds-tizen/pixel_format.h @@ -0,0 +1,10 @@ +#ifndef DS_TIZEN_PIXEL_FORMAT_H +#define DS_TIZEN_PIXEL_FORMAT_H + +#include + +uint32_t convert_drm_format_to_tbm(uint32_t fmt); + +uint32_t convert_tbm_format_to_drm(uint32_t fmt); + +#endif diff --git a/src/examples/tbm-server-helper.c b/src/libds-tizen/tbm_server.c similarity index 66% rename from src/examples/tbm-server-helper.c rename to src/libds-tizen/tbm_server.c index 320ee4f..ecb46db 100644 --- a/src/examples/tbm-server-helper.c +++ b/src/libds-tizen/tbm_server.c @@ -1,82 +1,111 @@ -#include "tbm-server-helper.h" - #include #include #include -#include + #include -#include + +#include "libds/log.h" +#include "pixel_format.h" +#include "tbm_server.h" static const struct ds_buffer_resource_interface tbm_buffer_resource_iface; static const struct ds_buffer_interface tbm_client_buffer_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) +WL_EXPORT struct ds_tbm_server * +ds_tbm_server_create(struct wl_display *display) { + struct ds_tbm_server *tbm; tbm_bufmgr bufmgr; + tbm = calloc(1, sizeof *tbm); + if (!tbm) + return NULL; + + wl_signal_init(&tbm->events.destroy); + tbm->wl_tbm = wayland_tbm_server_init(display, NULL, -1, 0); if (!tbm->wl_tbm) { - return false; + goto err_wl_tbm; } bufmgr = wayland_tbm_server_get_bufmgr(tbm->wl_tbm); if (!bufmgr) { - wayland_tbm_server_deinit(tbm->wl_tbm); - return false; + goto err_bind; } if (!tbm_bufmgr_bind_native_display(bufmgr, (void *)display)) { - wayland_tbm_server_deinit(tbm->wl_tbm); - return false; + goto err_bind; } - 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; + ds_buffer_register_resource_interface(&tbm_buffer_resource_iface); + + return tbm; + +err_bind: + wayland_tbm_server_deinit(tbm->wl_tbm); +err_wl_tbm: + free(tbm); + + return NULL; } -struct tbm_client_buffer * -tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) +WL_EXPORT void +ds_tbm_server_add_destroy_listener(struct ds_tbm_server *tbm, + struct wl_listener *listener) { - assert(ds_buffer->iface == &tbm_client_buffer_iface); - return (struct tbm_client_buffer *)ds_buffer; + wl_signal_add(&tbm->events.destroy, listener); +} + +WL_EXPORT struct ds_tbm_client_buffer * +ds_tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) +{ + if (ds_buffer->iface != &tbm_client_buffer_iface) + return NULL; + return (struct ds_tbm_client_buffer *)ds_buffer; } -tbm_surface_h -tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer) +WL_EXPORT tbm_surface_h +ds_tbm_client_buffer_get_tbm_surface(struct ds_tbm_client_buffer *buffer) { + if (buffer->base.iface != &tbm_client_buffer_iface) + return NULL; return buffer->surface; } static void tbm_server_handle_display_destroy(struct wl_listener *listener, void *data) { - struct tbm_server *tbm; + struct ds_tbm_server *tbm; tbm = wl_container_of(listener, tbm, display_destroy); + + wl_signal_emit(&tbm->events.destroy, tbm); + wayland_tbm_server_deinit(tbm->wl_tbm); + free(tbm); } -static bool -tbm_buffer_resource_iface_is_instance(struct wl_resource *resource) +static void +tbm_client_buffer_handle_release(struct wl_listener *listener, void *data) { - return !!wayland_tbm_server_get_surface(NULL, resource); + struct ds_tbm_client_buffer *buffer; + + buffer = wl_container_of(listener, buffer, buffer_release); + if (buffer->resource) + wl_buffer_send_release(buffer->resource); } static void tbm_client_buffer_handle_resource_destroy(struct wl_listener *listener, void *data) { - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *buffer; buffer = wl_container_of(listener, buffer, resource_destroy); @@ -88,44 +117,17 @@ tbm_client_buffer_handle_resource_destroy(struct wl_listener *listener, 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) +static struct ds_tbm_client_buffer * +tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer) { - struct tbm_client_buffer *buffer; - - buffer = tbm_client_buffer_get_or_create(resource); - assert(buffer); - - return &buffer->base; + assert(ds_buffer->iface == &tbm_client_buffer_iface); + return (struct ds_tbm_client_buffer *)ds_buffer; } -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 void -tbm_client_buffer_destroy(struct ds_buffer *ds_buffer) +tbm_client_buffer_iface_destroy(struct ds_buffer *ds_buffer) { - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *buffer; buffer = tbm_client_buffer_from_buffer(ds_buffer); @@ -137,11 +139,11 @@ tbm_client_buffer_destroy(struct ds_buffer *ds_buffer) } static bool -tbm_client_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer, +tbm_client_buffer_iface_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; + struct ds_tbm_client_buffer *buffer; tbm_surface_info_s info; tbm_bo_access_option op = TBM_OPTION_NONE; int err; @@ -160,7 +162,7 @@ tbm_client_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer, return false; } - *format = DRM_FORMAT_XRGB8888; // FIXME + *format = convert_tbm_format_to_drm(buffer->format); *stride = info.planes[0].stride; *data = info.planes[0].ptr; @@ -168,9 +170,9 @@ tbm_client_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer, } static void -tbm_client_buffer_end_data_ptr_access(struct ds_buffer *ds_buffer) +tbm_client_buffer_iface_end_ptr_access(struct ds_buffer *ds_buffer) { - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *buffer; buffer = tbm_client_buffer_from_buffer(ds_buffer); @@ -178,36 +180,31 @@ tbm_client_buffer_end_data_ptr_access(struct ds_buffer *ds_buffer) } 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, + .destroy = tbm_client_buffer_iface_destroy, + .begin_data_ptr_access = tbm_client_buffer_iface_begin_data_ptr_access, + .end_data_ptr_access = tbm_client_buffer_iface_end_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 * +static struct ds_tbm_client_buffer * tbm_client_buffer_create(struct wl_resource *resource) { - struct tbm_client_buffer *buffer; + struct ds_tbm_client_buffer *buffer; tbm_surface_h surface; int32_t width, height; surface = wayland_tbm_server_get_surface(NULL, resource); - assert(surface); + if (!surface) { + ds_err("Could not get tbm_surface from wl_resource@%d", + wl_resource_get_id(resource)); + return NULL; + } width = tbm_surface_get_width(surface); height = tbm_surface_get_height(surface); buffer = calloc(1, sizeof *buffer); - assert(buffer); + if (!buffer) + return NULL; ds_buffer_init(&buffer->base, &tbm_client_buffer_iface, width, height); @@ -226,3 +223,46 @@ tbm_client_buffer_create(struct wl_resource *resource) return buffer; } + +static struct ds_tbm_client_buffer * +tbm_client_buffer_get_or_create(struct wl_resource *resource) +{ + struct ds_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 bool +tbm_buffer_resource_iface_is_instance(struct wl_resource *resource) +{ + return !!wayland_tbm_server_get_surface(NULL, resource); +} + +static struct ds_buffer * +tbm_buffer_resource_iface_from_resource(struct wl_resource *resource) +{ + struct ds_tbm_client_buffer *buffer; + + buffer = tbm_client_buffer_get_or_create(resource); + if (!buffer) { + ds_err("Could not get or create ds_tbm_client_buffer"); + return NULL; + } + + 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, +}; diff --git a/src/libds-tizen/tbm_server.h b/src/libds-tizen/tbm_server.h new file mode 100644 index 0000000..be56746 --- /dev/null +++ b/src/libds-tizen/tbm_server.h @@ -0,0 +1,34 @@ +#ifndef DS_TIZEN_TBM_SERVER_H +#define DS_TIZEN_TBM_SERVER_H + +#include +#include +#include +#include "libds/interfaces/buffer.h" + +struct ds_tbm_server +{ + struct wayland_tbm_server *wl_tbm; + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; +}; + +struct ds_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; +}; + +#endif -- 2.7.4 From de85e1d57eb3b1ec7f8ff04a877b335ea99bca54 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 30 Mar 2022 16:44:45 +0900 Subject: [PATCH 07/16] add extern 'C' at tbm_server.h Change-Id: Ida5b0215bcfd753f124c9b3d3102caeb881f5160 --- include/libds-tizen/tbm_server.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/libds-tizen/tbm_server.h b/include/libds-tizen/tbm_server.h index c48977e..f1cc97d 100644 --- a/include/libds-tizen/tbm_server.h +++ b/include/libds-tizen/tbm_server.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct ds_tbm_server; struct ds_tbm_client_buffer; @@ -21,4 +25,8 @@ ds_tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer); tbm_surface_h ds_tbm_client_buffer_get_tbm_surface(struct ds_tbm_client_buffer *buffer); +#ifdef __cplusplus +} +#endif + #endif -- 2.7.4 From 6e6592802e7dbc90538876e5ecb612e6906aafa4 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 30 Mar 2022 19:57:41 +0900 Subject: [PATCH 08/16] add ws_members as reviewers Change-Id: I6e027ad8496c66d91de0edfa5cd9a9c8ed2bb712 --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 2c7fc6d..b37075e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,5 +5,5 @@ # 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 +* @TizenWS/ws_members -- 2.7.4 From d0f5cdc4e96100f43ecfe7e3ae60cb22b2636d23 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EC=9E=84=EC=88=98=EC=B0=AC/Tizen=20Platform=20Lab=28SR=29/?= =?utf8?q?=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 11 Apr 2022 09:27:40 +0900 Subject: [PATCH 09/16] Update CODEOWNERS Change-Id: I1c8886c715c1fbf276cee3f3bf01ac6b3bf86641 --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index b37075e..a215b9e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,5 +5,5 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @TizenWS/ws_members +* @TizenWS/ws_members @sc1-lim @shiin-lee @joonbum-ko @cyeon-lee @doyoun-kang @gl77-lee @duna-oh @jinbong-lee @jk0430-kim @juns-kim @TizenWS/ws_members -- 2.7.4 From 299cfcd39bcc65080646cb8b5a13f19a604fdd41 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EC=9E=84=EC=88=98=EC=B0=AC/Tizen=20Platform=20Lab=28SR=29/?= =?utf8?q?=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 11 Apr 2022 09:27:52 +0900 Subject: [PATCH 10/16] Update CODEOWNERS Change-Id: I6fef91c7a648346b2cdbd3da77f7dfbbb30d3803 --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index a215b9e..d52bfc2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,5 +5,5 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @TizenWS/ws_members @sc1-lim @shiin-lee @joonbum-ko @cyeon-lee @doyoun-kang @gl77-lee @duna-oh @jinbong-lee @jk0430-kim @juns-kim @TizenWS/ws_members +* @sc1-lim @shiin-lee @joonbum-ko @cyeon-lee @doyoun-kang @gl77-lee @duna-oh @jinbong-lee @jk0430-kim @juns-kim @TizenWS/ws_members -- 2.7.4 From 1e0090a999bab75aa5703da58c8cd33206c033d5 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 7 Apr 2022 10:46:48 +0900 Subject: [PATCH 11/16] Add ds_input_device, and ds_pointer. This patch is just the beginning of ds_input_device. Currently, a ds_input_device is created only on the wayland backend, and it only supports a ds_pointer. Other devices like keyboard and touch, and other backends like libinput will be supported in future patches. Change-Id: Ib0714d81b1083e063992848444517759aa7efadd --- include/libds/backend.h | 4 + include/libds/input_device.h | 31 +++ include/libds/interfaces/backend.h | 1 + include/libds/interfaces/input_device.h | 40 ++++ include/libds/interfaces/pointer.h | 30 +++ include/libds/pointer.h | 38 +++ src/examples/meson.build | 9 + src/examples/pointer-test.c | 278 ++++++++++++++++++++++ src/libds/backend.c | 8 + src/libds/backend/wayland/backend.c | 27 ++- src/libds/backend/wayland/backend.h | 61 +++++ src/libds/backend/wayland/meson.build | 1 + src/libds/backend/wayland/output.c | 28 +++ src/libds/backend/wayland/seat.c | 406 ++++++++++++++++++++++++++++++++ src/libds/input_device.c | 69 ++++++ src/libds/meson.build | 2 + src/libds/pointer.c | 55 +++++ 17 files changed, 1083 insertions(+), 5 deletions(-) create mode 100644 include/libds/input_device.h create mode 100644 include/libds/interfaces/input_device.h create mode 100644 include/libds/interfaces/pointer.h create mode 100644 include/libds/pointer.h create mode 100644 src/examples/pointer-test.c create mode 100644 src/libds/backend/wayland/seat.c create mode 100644 src/libds/input_device.c create mode 100644 src/libds/pointer.c diff --git a/include/libds/backend.h b/include/libds/backend.h index 6b587d2..d6a266f 100644 --- a/include/libds/backend.h +++ b/include/libds/backend.h @@ -31,6 +31,10 @@ void ds_backend_add_new_output_listener(struct ds_backend *backend, struct wl_listener *listener); +void +ds_backend_add_new_input_listener(struct ds_backend *backend, + struct wl_listener *listener); + #ifdef __cplusplus } #endif diff --git a/include/libds/input_device.h b/include/libds/input_device.h new file mode 100644 index 0000000..45e125b --- /dev/null +++ b/include/libds/input_device.h @@ -0,0 +1,31 @@ +#ifndef LIBDS_INPUT_DEVICE_H +#define LIBDS_INPUT_DEVICE_H + +struct ds_input_device; + +struct ds_pointer; + +enum ds_button_state +{ + DS_BUTTON_RELEASED, + DS_BUTTON_PRESSED, +}; + +enum ds_input_device_type +{ + DS_INPUT_DEVICE_POINTER, + DS_INPUT_DEVICE_KEYBOARD, + DS_INPUT_DEVICE_TOUCH, +}; + +enum ds_input_device_type +ds_input_device_get_type(struct ds_input_device *dev); + +struct ds_pointer * +ds_input_device_get_pointer(struct ds_input_device *dev); + +void +ds_input_device_add_destroy_listener(struct ds_input_device *dev, + struct wl_listener *listener); + +#endif diff --git a/include/libds/interfaces/backend.h b/include/libds/interfaces/backend.h index e960ac4..bad37a0 100644 --- a/include/libds/interfaces/backend.h +++ b/include/libds/interfaces/backend.h @@ -22,6 +22,7 @@ struct ds_backend { struct wl_signal destroy; struct wl_signal new_output; + struct wl_signal new_input; } events; bool started; diff --git a/include/libds/interfaces/input_device.h b/include/libds/interfaces/input_device.h new file mode 100644 index 0000000..f31594b --- /dev/null +++ b/include/libds/interfaces/input_device.h @@ -0,0 +1,40 @@ +#ifndef LIBDS_INTERFACES_INPUT_DEVICE_H +#define LIBDS_INTERFACES_INPUT_DEVICE_H + +#include +#include +#include + +struct ds_input_device_interface +{ + void (*destroy)(struct ds_input_device *dev); +}; + +struct ds_input_device +{ + const struct ds_input_device_interface *iface; + + char *name; + double width_mm, height_mm; + char *output_name; + + enum ds_input_device_type type; + union { + void *_device; + struct ds_pointer *pointer; + }; + + struct { + struct wl_signal destroy; + } events; + + struct wl_list link; +}; + +void ds_input_device_init(struct ds_input_device *dev, + enum ds_input_device_type type, + const struct ds_input_device_interface *iface, + const char *name, int vendor, int product); +void ds_input_device_destroy(struct ds_input_device *dev); + +#endif diff --git a/include/libds/interfaces/pointer.h b/include/libds/interfaces/pointer.h new file mode 100644 index 0000000..84b0e23 --- /dev/null +++ b/include/libds/interfaces/pointer.h @@ -0,0 +1,30 @@ +#ifndef LIBDS_INTERFACES_POINTER_H +#define LIBDS_INTERFACES_POINTER_H + +#include + +struct ds_pointer; + +struct ds_pointer_interface +{ + void (*destroy)(struct ds_pointer *pointer); +}; + +struct ds_pointer +{ + const struct ds_pointer_interface *iface; + + struct { + struct wl_signal motion; + struct wl_signal motion_absolute; + struct wl_signal button; + struct wl_signal frame; + } events; +}; + +void ds_pointer_init(struct ds_pointer *pointer, + const struct ds_pointer_interface *iface); + +void ds_pointer_destroy(struct ds_pointer *pointer); + +#endif diff --git a/include/libds/pointer.h b/include/libds/pointer.h new file mode 100644 index 0000000..30bfaca --- /dev/null +++ b/include/libds/pointer.h @@ -0,0 +1,38 @@ +#ifndef LIBDS_POINTER_H +#define LIBDS_POINTER_H + +#include +#include +#include + +struct ds_pointer; + +struct ds_event_pointer_motion_absolute +{ + struct ds_input_device *device; + uint32_t time_msec; + // From 0..1 + double x, y; +}; + +struct ds_event_pointer_button +{ + struct ds_input_device *device; + uint32_t time_msec; + uint32_t button; + enum ds_button_state state; +}; + +void ds_pointer_add_motion_listener(struct ds_pointer *pointer, + struct wl_listener *listener); + +void ds_pointer_add_motion_absolute_listener(struct ds_pointer *pointer, + struct wl_listener *listener); + +void ds_pointer_add_button_listener(struct ds_pointer *pointer, + struct wl_listener *listener); + +void ds_pointer_add_frame_listener(struct ds_pointer *pointer, + struct wl_listener *listener); + +#endif diff --git a/src/examples/meson.build b/src/examples/meson.build index ddb0792..f19f139 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -23,6 +23,15 @@ executable('tinyds', install : true ) +executable('pointer-test', + [ + 'pointer-test.c', + 'pixman-helper.c', + ], + dependencies: common_deps, + install_dir: libds_bindir, + install : true) + if get_option('tizen') common_deps += dep_libds_tizen diff --git a/src/examples/pointer-test.c b/src/examples/pointer-test.c new file mode 100644 index 0000000..d669a03 --- /dev/null +++ b/src/examples/pointer-test.c @@ -0,0 +1,278 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pixman-helper.h" + +#define WIDTH 700 +#define HEIGHT 400 + +struct pointer_device { + struct ds_pointer *ds_pointer; + + struct wl_listener destroy; + struct wl_listener motion_absolute; + struct wl_listener button; + struct wl_listener frame; +}; + +struct output +{ + struct server *server; + + struct ds_output *ds_output; + struct ds_allocator *allocator; + struct ds_swapchain *swapchain; + + struct ds_buffer *front_buffer; + + struct wl_listener destroy; +}; + +struct server +{ + struct wl_display *display; + + struct output output; + + struct ds_backend *backend; + + struct wl_listener backend_destroy; + struct wl_listener new_input; +}; + +struct server _server; + +static struct ds_backend *create_backend_auto(struct wl_display *display); +static void handle_backend_destroy(struct wl_listener *listener, void *data); +static void handle_new_input(struct wl_listener *listener, void *data); +static void output_init(struct output *output, struct server *sever); +static void output_draw(struct output *output); + +int +main(void) +{ + struct server *server = &_server; + + ds_log_init(DS_DBG, NULL); + + server->display = wl_display_create(); + assert(server->display); + + server->backend = create_backend_auto(server->display); + assert(server->backend); + + server->backend_destroy.notify = handle_backend_destroy; + ds_backend_add_destroy_listener(server->backend, &server->backend_destroy); + + server->new_input.notify = handle_new_input; + ds_backend_add_new_input_listener(server->backend, &server->new_input); + + output_init(&server->output, server); + + ds_backend_start(server->backend); + + output_draw(&server->output); + + wl_display_run(server->display); + + wl_display_destroy(server->display); + + return 0; +} + +static struct ds_backend * +create_backend_auto(struct wl_display *display) +{ + struct ds_backend *backend = NULL; + char name[512]; + int i; + + for (i = 0; i < 5; i++) { + snprintf(name, sizeof name, "wayland-%d", i); + backend = ds_wl_backend_create(display, name); + if (backend) + break; + } + + return backend; +} + +static void +handle_backend_destroy(struct wl_listener *listener, void *data) +{ + struct server *server; + + server = wl_container_of(listener, server, backend_destroy); + + wl_list_remove(&server->backend_destroy.link); + wl_list_remove(&server->new_input.link); +} + +static char * +device_type_to_string(enum ds_input_device_type type) +{ + switch (type) { + case DS_INPUT_DEVICE_POINTER: + return "pointer"; + break; + case DS_INPUT_DEVICE_KEYBOARD: + return "keyboard"; + break; + case DS_INPUT_DEVICE_TOUCH: + return "touch"; + break; + default: + return "Unknown"; + } +} + +static void +pointer_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct pointer_device *pointer; + + pointer = wl_container_of(listener, pointer, destroy); + + wl_list_remove(&pointer->destroy.link); + wl_list_remove(&pointer->motion_absolute.link); + wl_list_remove(&pointer->button.link); + wl_list_remove(&pointer->frame.link); + + free(pointer); +} + +static void +pointer_handle_motion_absolute(struct wl_listener *listener, void *data) +{ + struct ds_event_pointer_motion_absolute *event = data; + + ds_inf("Pointer device(%p): motion absolute (%f, %f) time(%d ms)", + event->device, event->x, event->y, event->time_msec); +} + +static void +pointer_handle_button(struct wl_listener *listener, void *data) +{ + struct ds_event_pointer_button *event = data; + + ds_inf("Pointer Device(%p): button(%d) state(%d) time(%d ms)", + event->device, event->button, event->state, event->time_msec); +} + +static void +pointer_handle_frame(struct wl_listener *listener, void *data) +{ + ds_inf("Pointer device(%p): frame", data); +} + +static void +add_pointer(struct ds_input_device *dev) +{ + struct pointer_device *pointer; + + pointer = calloc(1, sizeof *pointer); + if (!pointer) + return; + + pointer->ds_pointer = ds_input_device_get_pointer(dev); + + pointer->destroy.notify = pointer_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &pointer->destroy); + + pointer->motion_absolute.notify = pointer_handle_motion_absolute; + ds_pointer_add_motion_absolute_listener(pointer->ds_pointer, + &pointer->motion_absolute); + + pointer->button.notify = pointer_handle_button; + ds_pointer_add_button_listener(pointer->ds_pointer, + &pointer->button); + + pointer->frame.notify = pointer_handle_frame; + ds_pointer_add_frame_listener(pointer->ds_pointer, + &pointer->frame); +} + +static void +handle_new_input(struct wl_listener *listener, void *data) +{ + struct ds_input_device *dev = data; + enum ds_input_device_type type; + + type = ds_input_device_get_type(dev); + + if (type != DS_INPUT_DEVICE_POINTER) + return; + + ds_inf("New pointer device(%p) type(%s)", dev, + device_type_to_string(type)); + + add_pointer(dev); +} + +static void +output_handle_destroy(struct wl_listener *listener, void *data) +{ + struct output *output; + + output = wl_container_of(listener, output, destroy); + + wl_list_remove(&output->destroy.link); + + ds_swapchain_destroy(output->swapchain); + ds_allocator_destroy(output->allocator); +} + +static void +output_init(struct output *output, struct server *server) +{ + output->server = server; + + output->ds_output = ds_wl_backend_create_output(server->backend); + assert(output->ds_output); + + output->destroy.notify = output_handle_destroy; + ds_output_add_destroy_listener(output->ds_output, &output->destroy); + + output->allocator = ds_shm_allocator_create(); + assert(output->allocator); + + output->swapchain = ds_swapchain_create(output->allocator, + WIDTH, HEIGHT, DRM_FORMAT_XRGB8888); + assert(output->swapchain); +} + +static void +output_draw(struct output *output) +{ + struct ds_buffer *buffer; + pixman_image_t *img; + + ds_dbg("Redraw output"); + + buffer = ds_swapchain_acquire(output->swapchain, NULL); + assert(buffer); + + img = pixman_image_from_buffer(buffer, DS_BUFFER_DATA_PTR_ACCESS_WRITE); + assert(img); + + pixman_image_fill_color(img, 80, 80, 80); + + pixman_image_unref(img); + + ds_output_attach_buffer(output->ds_output, buffer); + ds_output_commit(output->ds_output); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + + output->front_buffer = buffer; +} diff --git a/src/libds/backend.c b/src/libds/backend.c index ee2a912..641374a 100644 --- a/src/libds/backend.c +++ b/src/libds/backend.c @@ -41,6 +41,13 @@ ds_backend_add_new_output_listener(struct ds_backend *backend, wl_signal_add(&backend->events.new_output, listener); } +WL_EXPORT void +ds_backend_add_new_input_listener(struct ds_backend *backend, + struct wl_listener *listener) +{ + wl_signal_add(&backend->events.new_input, listener); +} + void ds_backend_init(struct ds_backend *backend, const struct ds_backend_interface *iface) @@ -48,6 +55,7 @@ ds_backend_init(struct ds_backend *backend, backend->iface = iface; wl_signal_init(&backend->events.destroy); wl_signal_init(&backend->events.new_output); + wl_signal_init(&backend->events.new_input); } void diff --git a/src/libds/backend/wayland/backend.c b/src/libds/backend/wayland/backend.c index 778ca1c..d956aa0 100644 --- a/src/libds/backend/wayland/backend.c +++ b/src/libds/backend/wayland/backend.c @@ -14,8 +14,8 @@ static const struct ds_backend_interface wl_backend_interface; static void wl_backend_handle_display_destroy(struct wl_listener *listener, void *data); -static bool wl_backend_server_init(struct ds_wl_backend_server *server, - const char *name); +static bool wl_backend_server_init(struct ds_wl_backend *wl_backend, + struct ds_wl_backend_server *server, const char *name); static void wl_backend_server_finish(struct ds_wl_backend_server *server); static int wl_backend_handle_dispatch_events(int fd, uint32_t mask, void *data); @@ -38,8 +38,9 @@ ds_wl_backend_create(struct wl_display *display, const char *server_name) wl_backend->display = display; wl_list_init(&wl_backend->buffers); wl_list_init(&wl_backend->outputs); + wl_list_init(&wl_backend->seats); - if (!wl_backend_server_init(&wl_backend->server, server_name)) { + if (!wl_backend_server_init(wl_backend, &wl_backend->server, server_name)) { ds_err("Failed to initialize Wayland Server"); goto err_server; } @@ -48,7 +49,7 @@ ds_wl_backend_create(struct wl_display *display, const char *server_name) fd = wl_display_get_fd(wl_backend->server.display); wl_backend->server_event_source = - wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE, + wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE | WL_EVENT_READABLE, wl_backend_handle_dispatch_events, wl_backend); if (!wl_backend->server_event_source) { ds_err("Failed to create event source"); @@ -84,6 +85,7 @@ wl_backend_destroy(struct ds_wl_backend *backend) { struct ds_wl_output *output, *tmp_output; struct ds_wl_buffer *buffer, *tmp_buffer; + struct ds_wl_seat *seat, *tmp_seat; ds_dbg("Destroy wayland backend(%p)", backend); @@ -93,6 +95,9 @@ wl_backend_destroy(struct ds_wl_backend *backend) wl_list_for_each_safe(buffer, tmp_buffer, &backend->buffers, link) destroy_wl_buffer(buffer); + wl_list_for_each_safe(seat, tmp_seat, &backend->seats, link) + destroy_wl_seat(seat); + ds_backend_finish(&backend->base); wl_list_remove(&backend->display_destroy.link); @@ -159,6 +164,7 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *iface, uint32_t version) { struct ds_wl_backend_server *server = data; + struct ds_wl_seat *seat; ds_log(DS_DBG, "Wayland global: %s v%d", iface, version); @@ -176,6 +182,15 @@ registry_handle_global(void *data, struct wl_registry *registry, server->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); wl_shm_add_listener(server->shm, &shm_listener, server); } + else if (strcmp(iface, wl_seat_interface.name) == 0) { + seat = create_wl_seat(server->backend, name, version); + if (!seat) { + ds_err("Could not create ds_wl_seat"); + return; + } + + wl_list_insert(&server->backend->seats, &seat->link); + } } static void @@ -192,8 +207,10 @@ static const struct wl_registry_listener registry_listener = }; static bool -wl_backend_server_init(struct ds_wl_backend_server *server, const char *name) +wl_backend_server_init(struct ds_wl_backend *wl_backend, struct ds_wl_backend_server *server, const char *name) { + server->backend = wl_backend; + server->display = wl_display_connect(name); if (!server->display) { ds_log_errno(DS_ERR, "Could not connect to display: name \"%s\"", name); diff --git a/src/libds/backend/wayland/backend.h b/src/libds/backend/wayland/backend.h index ab37ec0..12e594a 100644 --- a/src/libds/backend/wayland/backend.h +++ b/src/libds/backend/wayland/backend.h @@ -3,9 +3,12 @@ #include "libds/interfaces/backend.h" #include "libds/interfaces/output.h" +#include "libds/interfaces/input_device.h" +#include "libds/interfaces/pointer.h" struct ds_wl_backend_server { + struct ds_wl_backend *backend; struct wl_display *display; struct wl_registry *registry; struct wl_compositor *compositor; @@ -23,6 +26,7 @@ struct ds_wl_backend struct wl_list outputs; // ds_wl_output.link struct wl_list buffers; // ds_wl_buffer.link + struct wl_list seats; // ds_wl_seat.link struct wl_event_source *server_event_source; struct ds_wl_backend_server server; @@ -50,6 +54,53 @@ struct ds_wl_output struct wl_callback *frame_callback; struct wl_list link; + + struct { + struct ds_wl_pointer *pointer; + struct wl_surface *surface; + int32_t hotspot_x, hotspot_y; + uint32_t enter_serial; + } cursor; +}; + +struct ds_wl_seat +{ + struct ds_wl_backend *backend; + struct ds_wl_output *output; + + struct wl_seat *wl_seat; + char *name; + + struct ds_input_device *pointer_dev; + struct ds_input_device *keyboard_dev; + struct ds_input_device *touch_dev; + + struct wl_callback *initial_info_cb; + + struct wl_list link; // ds_wl_backend.seats + + enum wl_seat_capability caps; + + int version; + uint32_t enter_serial; + + bool initialized; +}; + +struct ds_wl_input_device +{ + struct ds_input_device base; + + struct ds_wl_backend *backend; + struct ds_wl_seat *seat; +}; + +struct ds_wl_pointer +{ + struct ds_pointer base; + + struct ds_wl_input_device *input_device; + struct wl_pointer *wl_pointer; }; struct ds_wl_backend * @@ -58,4 +109,14 @@ wl_backend_from_backend(struct ds_backend *backend); void destroy_wl_buffer(struct ds_wl_buffer *buffer); +struct ds_wl_seat *create_wl_seat(struct ds_wl_backend *backend, uint32_t id, + uint32_t available_version); + +void destroy_wl_seat(struct ds_wl_seat *seat); + +void output_enter_pointer(struct ds_wl_output *output, + struct ds_wl_pointer *pointer, uint32_t serial); + +void output_leave_pointer(struct ds_wl_output *output); + #endif diff --git a/src/libds/backend/wayland/meson.build b/src/libds/backend/wayland/meson.build index db68fe9..88574a4 100644 --- a/src/libds/backend/wayland/meson.build +++ b/src/libds/backend/wayland/meson.build @@ -1,6 +1,7 @@ libds_files += files( 'backend.c', 'output.c', + 'seat.c', ) protocols = { diff --git a/src/libds/backend/wayland/output.c b/src/libds/backend/wayland/output.c index 1966a97..36ea5f7 100644 --- a/src/libds/backend/wayland/output.c +++ b/src/libds/backend/wayland/output.c @@ -13,6 +13,8 @@ const struct ds_output_interface wl_output_iface; static const struct xdg_surface_listener wl_output_xdg_surface_listener; static const struct xdg_toplevel_listener wl_output_xdg_toplevel_listener; +static void output_update_cursor(struct ds_wl_output *output); + struct ds_output * ds_wl_backend_create_output(struct ds_backend *ds_backend) { @@ -90,6 +92,32 @@ destroy_wl_buffer(struct ds_wl_buffer *buffer) free(buffer); } +void +output_enter_pointer(struct ds_wl_output *output, + struct ds_wl_pointer *pointer, uint32_t serial) +{ + output->cursor.pointer = pointer; + output->cursor.enter_serial = serial; + + output_update_cursor(output); +} + +void +output_leave_pointer(struct ds_wl_output *output) +{ + output->cursor.pointer = NULL; + output->cursor.enter_serial = 0; +} + +static void output_update_cursor(struct ds_wl_output *output) +{ + struct ds_wl_pointer *pointer = output->cursor.pointer; + + wl_pointer_set_cursor(pointer->wl_pointer, output->cursor.enter_serial, + output->cursor.surface, output->cursor.hotspot_x, + output->cursor.hotspot_y); +} + static struct ds_wl_output * wl_output_from_output(struct ds_output *ds_output) { diff --git a/src/libds/backend/wayland/seat.c b/src/libds/backend/wayland/seat.c new file mode 100644 index 0000000..b799e66 --- /dev/null +++ b/src/libds/backend/wayland/seat.c @@ -0,0 +1,406 @@ +#include +#include +#include +#include +#include + +#include "libds/log.h" +#include "libds/pointer.h" + +#include "backend.h" + +#ifdef MIN +# undef MIN +#endif + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static const struct wl_seat_listener seat_listener; +static const struct wl_callback_listener seat_callback_listener; + +static void seat_update_capabilities(struct ds_wl_seat *seat, + enum wl_seat_capability caps); +static struct ds_input_device * +create_wl_input_device(struct ds_wl_seat *seat, + enum ds_input_device_type type); +static struct ds_pointer *create_wl_pointer(struct ds_wl_seat *seat); + +struct ds_wl_seat * +create_wl_seat(struct ds_wl_backend *backend, uint32_t id, + uint32_t available_version) +{ + struct ds_wl_seat *seat; + + seat = calloc(1, sizeof *seat); + if (!seat) + return NULL; + + seat->backend = backend; + seat->version = MIN(available_version, 5); + seat->wl_seat = wl_registry_bind(backend->server.registry, id, + &wl_seat_interface, seat->version); + + wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); + + seat->initial_info_cb = wl_display_sync(backend->server.display); + wl_callback_add_listener(seat->initial_info_cb, &seat_callback_listener, + seat); + + ds_dbg("wl_backend: Seat(%p) created", seat); + + return seat; +} + +void +destroy_wl_seat(struct ds_wl_seat *seat) +{ + ds_dbg("wl_backend: Seat(%p) destroy", seat); + + if (seat->pointer_dev) + ds_input_device_destroy(seat->pointer_dev); + + if (seat->keyboard_dev) + ds_input_device_destroy(seat->keyboard_dev); + + if (seat->touch_dev) + ds_input_device_destroy(seat->touch_dev); + + if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION) + wl_seat_release(seat->wl_seat); + else + wl_seat_destroy(seat->wl_seat); + + wl_list_remove(&seat->link); + + free(seat->name); + free(seat); +} + +static void +seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + enum wl_seat_capability caps) +{ + struct ds_wl_seat *seat = data; + + if (seat->initialized) + seat_update_capabilities(seat, caps); + else + seat->caps = caps; + + ds_dbg("wl_backend: Seat(%p) capabilities(%d)", seat, caps); +} + +static void +seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) +{ + struct ds_wl_seat *seat = data; + + if (seat->name) + free(seat->name); + + ds_dbg("wl_backend: Seat(%p) name(%s)", seat, name); + + seat->name = strdup(name); +} + +static const struct wl_seat_listener seat_listener = { + .capabilities = seat_handle_capabilities, + .name = seat_handle_name, +}; + +static void +seat_add_callback_handle_done(void *data, struct wl_callback *callback, + uint32_t callback_data) +{ + struct ds_wl_seat *seat = data; + + wl_callback_destroy(seat->initial_info_cb); + seat->initial_info_cb = NULL; + seat->initialized = true; + + seat_update_capabilities(seat, seat->caps); +} + +static const struct wl_callback_listener seat_callback_listener = { + .done = seat_add_callback_handle_done, +}; + +static void +seat_update_capabilities(struct ds_wl_seat *seat, enum wl_seat_capability caps) +{ + if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer_dev == NULL) { + ds_dbg("wl_backend: Seat(%p) offered pointer", seat); + + seat->pointer_dev = create_wl_input_device(seat, + DS_INPUT_DEVICE_POINTER); + seat->pointer_dev->pointer = create_wl_pointer(seat); + + wl_signal_emit(&seat->backend->base.events.new_input, + seat->pointer_dev); + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && + seat->pointer_dev != NULL) { + ds_dbg("wl_backend: Seat(%p) dropped pointer", seat); + ds_input_device_destroy(seat->pointer_dev); + seat->pointer_dev = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard_dev == NULL) { + ds_dbg("wl_backend: Seat(%p) offered keyboard", seat); + + seat->keyboard_dev = create_wl_input_device(seat, + DS_INPUT_DEVICE_KEYBOARD); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && + seat->keyboard_dev != NULL) { + ds_dbg("wl_backend: Seat(%p) dropped keyboard", seat); + ds_input_device_destroy(seat->keyboard_dev); + seat->keyboard_dev = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch_dev == NULL) { + ds_dbg("wl_backend: Seat(%p) offered touch", seat); + seat->touch_dev = create_wl_input_device(seat, + DS_INPUT_DEVICE_TOUCH); + } + else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && + seat->touch_dev != NULL) { + ds_dbg("wl_backend: Seat(%p) dropped touch", seat); + ds_input_device_destroy(seat->touch_dev); + seat->touch_dev = NULL; + } +} + +static const struct ds_input_device_interface input_device_iface; + +static bool +ds_input_device_is_wl(struct ds_input_device *ds_dev) +{ + return ds_dev->iface == &input_device_iface; +} + +static struct ds_wl_input_device * +get_wl_input_device_from_input_device(struct ds_input_device *ds_dev) +{ + assert(ds_input_device_is_wl(ds_dev)); + return (struct ds_wl_input_device *)ds_dev; +} + +static void +input_device_iface_destroy(struct ds_input_device *ds_dev) +{ + struct ds_wl_input_device *dev; + + dev = get_wl_input_device_from_input_device(ds_dev); + + free(dev); +} + +static const struct ds_input_device_interface input_device_iface = +{ + .destroy = input_device_iface_destroy, +}; + +static struct ds_input_device * +create_wl_input_device(struct ds_wl_seat *seat, + enum ds_input_device_type type) +{ + struct ds_wl_input_device *dev; + unsigned int vendor = 0, product = 0; + size_t name_size; + char *name; + + dev = calloc(1, sizeof *dev); + if (!dev) + return NULL; + + dev->backend = seat->backend; + dev->seat = seat; + + name_size = 8 + strlen(seat->name) + 1; + name = alloca(name_size); + (void) snprintf(name, name_size, "wayland-%s", seat->name); + + ds_input_device_init(&dev->base, type, &input_device_iface, name, vendor, + product); + + return &dev->base; +} + +static const struct ds_pointer_interface pointer_iface; + +static struct ds_wl_pointer * +get_wl_pointer_from_pointer(struct ds_pointer *ds_pointer) +{ + assert(ds_pointer->iface == &pointer_iface); + return (struct ds_wl_pointer *)ds_pointer; +} + +static void +pointer_iface_destroy(struct ds_pointer *ds_pointer) +{ + struct ds_wl_pointer *pointer; + + pointer = get_wl_pointer_from_pointer(ds_pointer); + + wl_pointer_release(pointer->wl_pointer); + + free(pointer); +} + +static const struct ds_pointer_interface pointer_iface = { + .destroy = pointer_iface_destroy, +}; + +static void +pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t sx, wl_fixed_t sy) +{ + struct ds_wl_seat *seat = data; + struct ds_wl_pointer *pointer; + + if (!surface) + return; + + ds_dbg("Enter pointer"); + + seat->output = wl_surface_get_user_data(surface); + seat->enter_serial = serial; + + pointer = get_wl_pointer_from_pointer(seat->pointer_dev->pointer); + output_enter_pointer(seat->output, pointer, seat->enter_serial); +} + +static void +pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface) +{ + struct ds_wl_seat *seat = data; + struct ds_wl_output *output; + + if (!seat->output) + return; + + output = wl_surface_get_user_data(surface); + if (seat->output != output) + return; + + ds_dbg("Leave pointer"); + + output_leave_pointer(seat->output); + + seat->output = NULL; + seat->enter_serial = 0; +} + +static void +pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, + uint32_t time, wl_fixed_t sx, wl_fixed_t sy) +{ + struct ds_wl_seat *seat = data; + + if (!seat->output) + return; + + // FIXME take size size of a output into account + struct ds_event_pointer_motion_absolute event = { + .device = seat->pointer_dev, + .time_msec = time, + .x = wl_fixed_to_double(sx) / 700, + .y = wl_fixed_to_double(sy) / 400, + }; + + wl_signal_emit(&seat->pointer_dev->pointer->events.motion_absolute, + &event); +} + +static void +pointer_handle_button(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state) +{ + struct ds_wl_seat *seat = data; + + if (!seat->output) + return; + + struct ds_event_pointer_button event = { + .device = seat->pointer_dev, + .button = button, + .state = state, + .time_msec = time, + }; + + wl_signal_emit(&seat->pointer_dev->pointer->events.button, &event); +} + +static void +pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) +{ + // TODO +} + +static void +pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) +{ + struct ds_wl_seat *seat = data; + + if (!seat->output) + return; + + wl_signal_emit(&seat->pointer_dev->pointer->events.frame, + seat->pointer_dev); +} + +static void +pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer, + uint32_t axis_source) +{ + // TODO +} + +static void +pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis) +{ + // TODO +} + +static void +pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer, + uint32_t axis, int32_t discrete) +{ + // TODO +} + +static const struct wl_pointer_listener wl_pointer_listener = { + .enter = pointer_handle_enter, + .leave = pointer_handle_leave, + .motion = pointer_handle_motion, + .button = pointer_handle_button, + .axis = pointer_handle_axis, + .frame = pointer_handle_frame, + .axis_source = pointer_handle_axis_source, + .axis_stop = pointer_handle_axis_stop, + .axis_discrete = pointer_handle_axis_discrete, +}; + +static struct ds_pointer * +create_wl_pointer(struct ds_wl_seat *seat) +{ + struct ds_wl_pointer *pointer; + + pointer = calloc(1, sizeof *pointer); + if (!pointer) { + ds_err("Could not allocate memory"); + return NULL; + } + + ds_pointer_init(&pointer->base, &pointer_iface); + + pointer->wl_pointer = wl_seat_get_pointer(seat->wl_seat); + wl_pointer_add_listener(pointer->wl_pointer, &wl_pointer_listener, seat); + + return &pointer->base; +} diff --git a/src/libds/input_device.c b/src/libds/input_device.c new file mode 100644 index 0000000..db84100 --- /dev/null +++ b/src/libds/input_device.c @@ -0,0 +1,69 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include + +#include "libds/log.h" +#include "libds/interfaces/input_device.h" +#include "libds/interfaces/pointer.h" + +WL_EXPORT enum ds_input_device_type +ds_input_device_get_type(struct ds_input_device *dev) +{ + return dev->type; +} + +WL_EXPORT struct ds_pointer * +ds_input_device_get_pointer(struct ds_input_device *dev) +{ + if (dev->type != DS_INPUT_DEVICE_POINTER) { + ds_err("Given ds_input_device is not a pointer device"); + return NULL; + } + + return dev->pointer; +} + +WL_EXPORT void +ds_input_device_add_destroy_listener(struct ds_input_device *dev, + struct wl_listener *listener) +{ + wl_signal_add(&dev->events.destroy, listener); +} + +void +ds_input_device_init(struct ds_input_device *dev, + enum ds_input_device_type type, + const struct ds_input_device_interface *iface, + const char *name, int vendor, int product) +{ + dev->type = type; + dev->iface = iface; + dev->name = strdup(name); + + wl_signal_init(&dev->events.destroy); +} + +void +ds_input_device_destroy(struct ds_input_device *dev) +{ + wl_signal_emit(&dev->events.destroy, dev); + + if (dev->_device) { + switch (dev->type) { + case DS_INPUT_DEVICE_POINTER: + ds_pointer_destroy(dev->pointer); + break; + default: + ds_err("Warning: leaking memory %p %p %d", + dev->_device, dev, dev->type); + break; + } + } + + free(dev->name); + if (dev->iface && dev->iface->destroy) + dev->iface->destroy(dev); + else + free(dev); +} diff --git a/src/libds/meson.build b/src/libds/meson.build index 50f7962..a08dfdc 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -18,6 +18,8 @@ libds_files = [ 'xdg_shell/xdg_toplevel.c', 'pixel_format.c', 'backend.c', + 'input_device.c', + 'pointer.c', ] protocols = { diff --git a/src/libds/pointer.c b/src/libds/pointer.c new file mode 100644 index 0000000..5c5cbda --- /dev/null +++ b/src/libds/pointer.c @@ -0,0 +1,55 @@ +#include +#include +#include "libds/interfaces/pointer.h" + +void +ds_pointer_init(struct ds_pointer *pointer, + const struct ds_pointer_interface *iface) +{ + pointer->iface = iface; + + wl_signal_init(&pointer->events.motion); + wl_signal_init(&pointer->events.motion_absolute); + wl_signal_init(&pointer->events.button); + wl_signal_init(&pointer->events.frame); +} + +void +ds_pointer_destroy(struct ds_pointer *pointer) +{ + if (!pointer) + return; + + if (pointer->iface && pointer->iface->destroy) + pointer->iface->destroy(pointer); + else + free(pointer); +} + +WL_EXPORT void +ds_pointer_add_motion_listener(struct ds_pointer *pointer, + struct wl_listener *listener) +{ + wl_signal_add(&pointer->events.motion, listener); +} + +WL_EXPORT void +ds_pointer_add_motion_absolute_listener(struct ds_pointer *pointer, + struct wl_listener *listener) +{ + wl_signal_add(&pointer->events.motion_absolute, listener); +} + +WL_EXPORT void +ds_pointer_add_button_listener(struct ds_pointer *pointer, + struct wl_listener *listener) +{ + wl_signal_add(&pointer->events.button, listener); +} + +WL_EXPORT void +ds_pointer_add_frame_listener(struct ds_pointer *pointer, + struct wl_listener *listener) +{ + wl_signal_add(&pointer->events.frame, listener); +} -- 2.7.4 From 6a33ab528956933deb2c90467e5762b33a7e0ae6 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Fri, 15 Apr 2022 16:11:57 +0900 Subject: [PATCH 12/16] Add missing header for alloca Change-Id: I87ff3dbbfe27a387c835ca2602b011e3dd866733 --- src/libds/backend/wayland/seat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libds/backend/wayland/seat.c b/src/libds/backend/wayland/seat.c index b799e66..c569947 100644 --- a/src/libds/backend/wayland/seat.c +++ b/src/libds/backend/wayland/seat.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "libds/log.h" -- 2.7.4 From cbae7a73a2da444633c693dd64fec6ef81ab0c14 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 10:29:23 +0900 Subject: [PATCH 13/16] Add ds_keyboard A ds_keyboard is for abstracting phisical keyboard device. Change-Id: I382ea96db01679f036283b213c4e540e36687c9d --- include/libds/input_device.h | 5 + include/libds/interfaces/input_device.h | 2 + include/libds/interfaces/keyboard.h | 89 ++++++++++ include/libds/keyboard.h | 45 +++++ packaging/libds.spec | 1 + src/libds/input_device.c | 15 ++ src/libds/keyboard.c | 304 ++++++++++++++++++++++++++++++++ src/libds/meson.build | 5 + src/libds/util.h | 3 + src/libds/util/shm.c | 76 +++++++- 10 files changed, 544 insertions(+), 1 deletion(-) create mode 100644 include/libds/interfaces/keyboard.h create mode 100644 include/libds/keyboard.h create mode 100644 src/libds/keyboard.c diff --git a/include/libds/input_device.h b/include/libds/input_device.h index 45e125b..6143e00 100644 --- a/include/libds/input_device.h +++ b/include/libds/input_device.h @@ -5,6 +5,8 @@ struct ds_input_device; struct ds_pointer; +struct ds_keyboard; + enum ds_button_state { DS_BUTTON_RELEASED, @@ -24,6 +26,9 @@ ds_input_device_get_type(struct ds_input_device *dev); struct ds_pointer * ds_input_device_get_pointer(struct ds_input_device *dev); +struct ds_keyboard * +ds_input_device_get_keyboard(struct ds_input_device *dev); + void ds_input_device_add_destroy_listener(struct ds_input_device *dev, struct wl_listener *listener); diff --git a/include/libds/interfaces/input_device.h b/include/libds/interfaces/input_device.h index f31594b..7828503 100644 --- a/include/libds/interfaces/input_device.h +++ b/include/libds/interfaces/input_device.h @@ -4,6 +4,7 @@ #include #include #include +#include struct ds_input_device_interface { @@ -22,6 +23,7 @@ struct ds_input_device union { void *_device; struct ds_pointer *pointer; + struct ds_keyboard *keyboard; }; struct { diff --git a/include/libds/interfaces/keyboard.h b/include/libds/interfaces/keyboard.h new file mode 100644 index 0000000..f68c9a7 --- /dev/null +++ b/include/libds/interfaces/keyboard.h @@ -0,0 +1,89 @@ +#ifndef LIBDS_INTERFACES_KEYBOARD_H +#define LIBDS_INTERFACES_KEYBOARD_H + +#include +#include + +#include + +#define DS_LED_COUNT 3 + +enum ds_keyboard_led { + DS_LED_NUM_LOCK = 1 << 0, + DS_LED_CAPS_LOCK = 1 << 1, + DS_LED_SCROLL_LOCK = 1 << 2, +}; + +#define DS_MODIFIER_COUNT 8 + +enum ds_keyboard_modifier { + DS_MODIFIER_SHIFT = 1 << 0, + DS_MODIFIER_CAPS = 1 << 1, + DS_MODIFIER_CTRL = 1 << 2, + DS_MODIFIER_ALT = 1 << 3, + DS_MODIFIER_MOD2 = 1 << 4, + DS_MODIFIER_MOD3 = 1 << 5, + DS_MODIFIER_LOGO = 1 << 6, + DS_MODIFIER_MOD5 = 1 << 7, +}; + +#define DS_KEYBOARD_KEYS_CAP 32 + +struct ds_keyboard; + +struct ds_keyboard_interface +{ + void (*destroy)(struct ds_keyboard *keyboard); +}; + +struct ds_keyboard_modifiers +{ + xkb_mod_mask_t depressed; + xkb_mod_mask_t latched; + xkb_mod_mask_t locked; + xkb_mod_mask_t group; +}; + +struct ds_keyboard +{ + const struct ds_keyboard_interface *iface; + + char *keymap_string; + size_t keymap_size; + int keymap_fd; + struct xkb_keymap *keymap; + struct xkb_state *xkb_state; + xkb_led_index_t led_indexes[DS_LED_COUNT]; + xkb_mod_index_t mod_indexes[DS_MODIFIER_COUNT]; + + uint32_t keycodes[DS_KEYBOARD_KEYS_CAP]; + size_t num_keycodes; + struct ds_keyboard_modifiers modifiers; + + struct { + int32_t rate; + int32_t delay; + } repeat_info; + + struct { + struct wl_signal destroy; + struct wl_signal key; + struct wl_signal modifiers; + struct wl_signal keymap; + struct wl_signal repeat_info; + } events; +}; + +void ds_keyboard_init(struct ds_keyboard *keyboard, + const struct ds_keyboard_interface *iface); + +void ds_keyboard_destroy(struct ds_keyboard *keyboard); + +void ds_keyboard_notify_key(struct ds_keyboard *keyboard, + struct ds_event_keyboard_key *event); + +void ds_keyboard_notify_modifiers(struct ds_keyboard *keyboard, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group); + +#endif diff --git a/include/libds/keyboard.h b/include/libds/keyboard.h new file mode 100644 index 0000000..e226cb4 --- /dev/null +++ b/include/libds/keyboard.h @@ -0,0 +1,45 @@ +#ifndef LIBDS_KEYBOARD_H +#define LIBDS_KEYBOARD_H + +#include +#include + +#include +#include + +struct ds_keyboard; + +struct ds_event_keyboard_key +{ + uint32_t time_msec; + uint32_t keycode; + bool update_state; + enum wl_keyboard_key_state state; +}; + +bool ds_keyboard_set_keymap(struct ds_keyboard *keyboard, + struct xkb_keymap *keymap); + +void ds_keyboard_set_repeat_info(struct ds_keyboard *keyboard, + int32_t rate, int32_t delay); + +uint32_t ds_keyboard_get_modifiers(struct ds_keyboard *keyboard); + +struct xkb_state *ds_keyboard_get_xkb_state(struct ds_keyboard *keyboard); + +void ds_keyboard_add_destroy_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +void ds_keyboard_add_key_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +void ds_keyboard_add_modifiers_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +void ds_keyboard_add_keymap_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +void ds_keyboard_add_repeat_info_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener); + +#endif diff --git a/packaging/libds.spec b/packaging/libds.spec index 879a87d..806c75b 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -13,6 +13,7 @@ BuildRequires: pkgconfig(wayland-client) BuildRequires: pkgconfig(wayland-protocols) BuildRequires: pkgconfig(pixman-1) BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(xkbcommon) BuildRequires: pkgconfig(libtdm) BuildRequires: pkgconfig(libtbm) diff --git a/src/libds/input_device.c b/src/libds/input_device.c index db84100..351361f 100644 --- a/src/libds/input_device.c +++ b/src/libds/input_device.c @@ -6,6 +6,7 @@ #include "libds/log.h" #include "libds/interfaces/input_device.h" #include "libds/interfaces/pointer.h" +#include "libds/interfaces/keyboard.h" WL_EXPORT enum ds_input_device_type ds_input_device_get_type(struct ds_input_device *dev) @@ -24,6 +25,17 @@ ds_input_device_get_pointer(struct ds_input_device *dev) return dev->pointer; } +WL_EXPORT struct ds_keyboard * +ds_input_device_get_keyboard(struct ds_input_device *dev) +{ + if (dev->type != DS_INPUT_DEVICE_KEYBOARD) { + ds_err("Given ds_input_device is not a keyboard device"); + return NULL; + } + + return dev->keyboard; +} + WL_EXPORT void ds_input_device_add_destroy_listener(struct ds_input_device *dev, struct wl_listener *listener) @@ -54,6 +66,9 @@ ds_input_device_destroy(struct ds_input_device *dev) case DS_INPUT_DEVICE_POINTER: ds_pointer_destroy(dev->pointer); break; + case DS_INPUT_DEVICE_KEYBOARD: + ds_keyboard_destroy(dev->keyboard); + break; default: ds_err("Warning: leaking memory %p %p %d", dev->_device, dev, dev->type); diff --git a/src/libds/keyboard.c b/src/libds/keyboard.c new file mode 100644 index 0000000..d122e81 --- /dev/null +++ b/src/libds/keyboard.c @@ -0,0 +1,304 @@ +#include +#include +#include +#include + +#include + +#include "libds/log.h" +#include "libds/interfaces/keyboard.h" +#include "util.h" + +static bool keyboard_modifier_update(struct ds_keyboard *keyboard); +static void keyboard_key_update(struct ds_keyboard *keyboard, + struct ds_event_keyboard_key *event); +static void keyboard_led_update(struct ds_keyboard *keyboard); + +WL_EXPORT bool +ds_keyboard_set_keymap(struct ds_keyboard *keyboard, struct xkb_keymap *keymap) +{ + char *tmp_keymap_string; + void *dst; + int rw_fd, ro_fd; + xkb_keycode_t keycode; + const char *led_names[DS_LED_COUNT] = { + XKB_LED_NAME_NUM, + XKB_LED_NAME_CAPS, + XKB_LED_NAME_SCROLL, + }; + const char *mod_names[DS_MODIFIER_COUNT] = { + XKB_MOD_NAME_SHIFT, + XKB_MOD_NAME_CAPS, + XKB_MOD_NAME_CTRL, + XKB_MOD_NAME_ALT, + XKB_MOD_NAME_NUM, + "Mod3", + XKB_MOD_NAME_LOGO, + "Mod5", + }; + + if (keyboard->keymap) + xkb_keymap_unref(keyboard->keymap); + + keyboard->keymap = xkb_keymap_ref(keymap); + + if (keyboard->xkb_state) + xkb_state_unref(keyboard->xkb_state); + + keyboard->xkb_state = xkb_state_new(keyboard->keymap); + if (!keyboard->xkb_state) { + ds_err("Failed to create XKB state"); + goto err_state; + } + + for (size_t i = 0; i < DS_LED_COUNT; i++) { + keyboard->led_indexes[i] = + xkb_map_led_get_index(keyboard->keymap, led_names[i]); + } + + for (size_t i = 0; i < DS_MODIFIER_COUNT; i++) { + keyboard->mod_indexes[i] = + xkb_map_mod_get_index(keyboard->keymap, mod_names[i]); + } + + tmp_keymap_string = xkb_keymap_get_as_string(keyboard->keymap, + XKB_KEYMAP_FORMAT_TEXT_V1); + if (!tmp_keymap_string) { + ds_err("Failed to get string version of keymap"); + goto err_keymap_string; + } + + if (keyboard->keymap_string) + free(keyboard->keymap_string); + keyboard->keymap_string = tmp_keymap_string; + keyboard->keymap_size = strlen(keyboard->keymap_string) + 1; + + if (!allocate_shm_file_pair(keyboard->keymap_size, &rw_fd, &ro_fd)) { + ds_err("Failed to allocate shm_file for keymap"); + goto err_shm_file; + } + + dst = mmap(NULL, keyboard->keymap_size, PROT_READ | PROT_WRITE, + MAP_SHARED, rw_fd, 0); + if (dst == MAP_FAILED) { + ds_log_errno(DS_ERR, "mmap failed"); + goto err_mmap; + } + + memcpy(dst, keyboard->keymap_string, keyboard->keymap_size); + munmap(dst, keyboard->keymap_size); + close(rw_fd); + + if (keyboard->keymap_fd >= 0) + close(keyboard->keymap_fd); + keyboard->keymap_fd = ro_fd; + + for (size_t i = 0; i < keyboard->num_keycodes; i++) { + keycode = keyboard->keycodes[i] + 8; + xkb_state_update_key(keyboard->xkb_state, keycode, XKB_KEY_DOWN); + } + + keyboard_modifier_update(keyboard); + + wl_signal_emit(&keyboard->events.keymap, keyboard); + + return true; + +err_mmap: + close(rw_fd); + close(ro_fd); +err_shm_file: + free(keyboard->keymap_string); + keyboard->keymap_string = NULL; +err_keymap_string: + xkb_state_unref(keyboard->xkb_state); + keyboard->xkb_state = NULL; +err_state: + xkb_keymap_unref(keymap); + keyboard->keymap = NULL; + + return false; +} + +WL_EXPORT void +ds_keyboard_set_repeat_info(struct ds_keyboard *keyboard, + int32_t rate, int32_t delay) +{ + if (keyboard->repeat_info.rate == rate && + keyboard->repeat_info.delay == delay) + return; + keyboard->repeat_info.rate = rate; + keyboard->repeat_info.delay = delay; + + wl_signal_emit(&keyboard->events.repeat_info, keyboard); +} + +WL_EXPORT uint32_t +ds_keyboard_get_modifiers(struct ds_keyboard *keyboard) +{ + xkb_mod_mask_t mask; + uint32_t modifiers = 0; + + mask = keyboard->modifiers.depressed | keyboard->modifiers.latched; + for (size_t i = 0; i < DS_MODIFIER_COUNT; i++) { + if (keyboard->mod_indexes[i] != XKB_MOD_INVALID && + (mask & (1 << keyboard->mod_indexes[i]))) + modifiers |= (1 << i); + } + + return modifiers; +} + +WL_EXPORT struct xkb_state * +ds_keyboard_get_xkb_state(struct ds_keyboard *keyboard) +{ + return keyboard->xkb_state; +} + +WL_EXPORT void +ds_keyboard_notify_key(struct ds_keyboard *keyboard, + struct ds_event_keyboard_key *event) +{ + uint32_t keycode; + enum xkb_key_direction dir; + bool updated; + + keyboard_key_update(keyboard, event); + + wl_signal_emit(&keyboard->events.key, event); + + if (!keyboard->xkb_state) + return; + + if (event->update_state) { + keycode = event->keycode + 8; + dir = (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) ? + XKB_KEY_DOWN : XKB_KEY_UP; + xkb_state_update_key(keyboard->xkb_state, keycode, dir); + } + + updated = keyboard_modifier_update(keyboard); + if (updated) + wl_signal_emit(&keyboard->events.modifiers, keyboard); + + keyboard_led_update(keyboard); +} + +WL_EXPORT void +ds_keyboard_notify_modifiers(struct ds_keyboard *keyboard, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) +{ + bool updated; + + if (!keyboard->xkb_state) + return; + + xkb_state_update_mask(keyboard->xkb_state, mods_depressed, mods_latched, + mods_locked, 0, 0, group); + + updated = keyboard_modifier_update(keyboard); + if (updated) + wl_signal_emit(&keyboard->events.modifiers, keyboard); + + keyboard_led_update(keyboard); +} + +WL_EXPORT void +ds_keyboard_add_destroy_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.destroy, listener); +} + +WL_EXPORT void +ds_keyboard_add_key_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.key, listener); +} + +WL_EXPORT void +ds_keyboard_add_modifiers_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.modifiers, listener); +} + +WL_EXPORT void +ds_keyboard_add_keymap_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.keymap, listener); +} + +WL_EXPORT void +ds_keyboard_add_repeat_info_listener(struct ds_keyboard *keyboard, + struct wl_listener *listener) +{ + wl_signal_add(&keyboard->events.repeat_info, listener); +} + +void +ds_keyboard_init(struct ds_keyboard *keyboard, + const struct ds_keyboard_interface *iface) +{ + keyboard->iface = iface; + keyboard->keymap_fd = -1; + + wl_signal_init(&keyboard->events.destroy); + wl_signal_init(&keyboard->events.key); + wl_signal_init(&keyboard->events.modifiers); + wl_signal_init(&keyboard->events.keymap); + wl_signal_init(&keyboard->events.repeat_info); +} + +void +ds_keyboard_destroy(struct ds_keyboard *keyboard) +{ + if (keyboard->iface && keyboard->iface->destroy) + keyboard->iface->destroy(keyboard); + else + free(keyboard); +} + +static bool +keyboard_modifier_update(struct ds_keyboard *keyboard) +{ + xkb_mod_mask_t depressed, latched, locked, group; + + if (!keyboard->xkb_state) + return false; + + depressed = xkb_state_serialize_mods(keyboard->xkb_state, + XKB_STATE_MODS_DEPRESSED); + latched = xkb_state_serialize_mods(keyboard->xkb_state, + XKB_STATE_MODS_LATCHED); + locked = xkb_state_serialize_mods(keyboard->xkb_state, + XKB_STATE_MODS_LOCKED); + group = xkb_state_serialize_layout(keyboard->xkb_state, + XKB_STATE_LAYOUT_EFFECTIVE); + if (depressed == keyboard->modifiers.depressed && + latched == keyboard->modifiers.latched && + locked == keyboard->modifiers.locked && + group == keyboard->modifiers.group) + return false; + + keyboard->modifiers.depressed = depressed; + keyboard->modifiers.latched = latched; + keyboard->modifiers.locked = locked; + keyboard->modifiers.group = group; + + return true; +} + +static void keyboard_key_update(struct ds_keyboard *keyboard, + struct ds_event_keyboard_key *event) +{ + // TODO +} + +static void keyboard_led_update(struct ds_keyboard *keyboard) +{ + // TODO +} diff --git a/src/libds/meson.build b/src/libds/meson.build index a08dfdc..4d1ae39 100644 --- a/src/libds/meson.build +++ b/src/libds/meson.build @@ -20,6 +20,7 @@ libds_files = [ 'backend.c', 'input_device.c', 'pointer.c', + 'keyboard.c', ] protocols = { @@ -52,12 +53,16 @@ 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) +xkbcommon = dependency('xkbcommon', required: true) +rt = meson.get_compiler('c').find_library('rt') libds_deps = [ math, wayland_server, pixman, libdrm, + xkbcommon, + rt, ] subdir('backend') diff --git a/src/libds/util.h b/src/libds/util.h index 3b7448b..1c9326a 100644 --- a/src/libds/util.h +++ b/src/libds/util.h @@ -10,4 +10,7 @@ timespec_to_msec(const struct timespec *a); int allocate_shm_file(size_t size); +bool +allocate_shm_file_pair(size_t size, int *rw_fd_ptr, int *ro_fd_ptr); + #endif diff --git a/src/libds/util/shm.c b/src/libds/util/shm.c index c8c84e3..4abd229 100644 --- a/src/libds/util/shm.c +++ b/src/libds/util/shm.c @@ -24,13 +24,18 @@ */ #define _POSIX_C_SOURCE 200809L - +#include #include #include #include #include #include +#include #include +#include +#include + +#define RANDNAME_PATTERN "/libds-XXXXXX" int os_fd_set_cloexec(int fd) @@ -172,3 +177,72 @@ allocate_shm_file(off_t size) return fd; } + +static void +randname(char *buf) +{ + struct timespec ts; + long r; + + clock_gettime(CLOCK_REALTIME, &ts); + r = ts.tv_nsec; + for (int i = 0; i < 6; i++) { + buf[i] = 'A' + (r & 15) + (r & 16) * 2; + r >>= 5; + } +} + +static int +excl_shm_open(char *name) +{ + int retries = 100; + int fd; + + do { + randname(name + strlen(RANDNAME_PATTERN) - 6); + + --retries; + + fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) + return fd; + } while (retries > 0 && errno == EEXIST); + + return -1; +} + +bool +allocate_shm_file_pair(size_t size, int *rw_fd_ptr, int *ro_fd_ptr) +{ + char name[] = RANDNAME_PATTERN; + int rw_fd, ro_fd; + int ret; + + rw_fd = excl_shm_open(name); + if (rw_fd < 0) + return false; + + ro_fd = shm_open(name, O_RDONLY, 0); + if (ro_fd < 0) { + shm_unlink(name); + close(rw_fd); + return false; + } + + shm_unlink(name); + + do { + ret = ftruncate(rw_fd, size); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + close(rw_fd); + close(ro_fd); + return false; + } + + *rw_fd_ptr = rw_fd; + *ro_fd_ptr = ro_fd; + + return true; +} -- 2.7.4 From 22c42edd55619b8291c56d2710a57b73a38026f3 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 10:33:19 +0900 Subject: [PATCH 14/16] backend/wayland: Support ds_keyboard Change-Id: I30a6a86e79f34abb22b789dee9ffe50d9d121a88 --- src/libds/backend/wayland/backend.h | 8 ++ src/libds/backend/wayland/seat.c | 196 ++++++++++++++++++++++++++++++++++++ src/libds/util.h | 3 + src/libds/util/time.c | 9 ++ 4 files changed, 216 insertions(+) diff --git a/src/libds/backend/wayland/backend.h b/src/libds/backend/wayland/backend.h index 12e594a..c35f7d1 100644 --- a/src/libds/backend/wayland/backend.h +++ b/src/libds/backend/wayland/backend.h @@ -5,6 +5,7 @@ #include "libds/interfaces/output.h" #include "libds/interfaces/input_device.h" #include "libds/interfaces/pointer.h" +#include "libds/interfaces/keyboard.h" struct ds_wl_backend_server { @@ -103,6 +104,13 @@ struct ds_wl_pointer struct wl_pointer *wl_pointer; }; +struct ds_wl_keyboard +{ + struct ds_keyboard base; + + struct wl_keyboard *wl_keyboard; +}; + struct ds_wl_backend * wl_backend_from_backend(struct ds_backend *backend); diff --git a/src/libds/backend/wayland/seat.c b/src/libds/backend/wayland/seat.c index c569947..966bf77 100644 --- a/src/libds/backend/wayland/seat.c +++ b/src/libds/backend/wayland/seat.c @@ -3,11 +3,14 @@ #include #include #include +#include #include +#include #include "libds/log.h" #include "libds/pointer.h" +#include "util.h" #include "backend.h" #ifdef MIN @@ -25,6 +28,7 @@ static struct ds_input_device * create_wl_input_device(struct ds_wl_seat *seat, enum ds_input_device_type type); static struct ds_pointer *create_wl_pointer(struct ds_wl_seat *seat); +static struct ds_keyboard *create_wl_keyboard(struct ds_wl_seat *seat); struct ds_wl_seat * create_wl_seat(struct ds_wl_backend *backend, uint32_t id, @@ -151,6 +155,10 @@ seat_update_capabilities(struct ds_wl_seat *seat, enum wl_seat_capability caps) seat->keyboard_dev = create_wl_input_device(seat, DS_INPUT_DEVICE_KEYBOARD); + seat->keyboard_dev->keyboard = create_wl_keyboard(seat); + + wl_signal_emit(&seat->backend->base.events.new_input, + seat->keyboard_dev); } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard_dev != NULL) { @@ -405,3 +413,191 @@ create_wl_pointer(struct ds_wl_seat *seat) return &pointer->base; } + +static const struct ds_keyboard_interface keyboard_iface; + +static struct ds_wl_keyboard * +get_wl_keyboard_from_keyboard(struct ds_keyboard *ds_keyboard) +{ + assert(ds_keyboard->iface == &keyboard_iface); + return (struct ds_wl_keyboard *)ds_keyboard; +} + +static void +keyboard_iface_destroy(struct ds_keyboard *ds_keyboard) +{ + struct ds_wl_keyboard *keyboard; + + keyboard = get_wl_keyboard_from_keyboard(ds_keyboard); + + wl_keyboard_release(keyboard->wl_keyboard); + + free(keyboard); +} + +static const struct ds_keyboard_interface keyboard_iface = { + .destroy = keyboard_iface_destroy, +}; + +static void +keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, + uint32_t format, int fd, uint32_t size) +{ + struct ds_wl_seat *seat = data; + struct xkb_context *context; + struct xkb_keymap *keymap; + char *map_str; + + ds_dbg("wl_keyboard: keymap"); + + if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map_str == MAP_FAILED) { + ds_log_errno(DS_ERR, "mmap failed"); + goto end; + } + + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + keymap = xkb_keymap_new_from_string(context, map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, 0); + munmap(map_str, size); + + if (!keymap) { + ds_err("Failed to compile keymap"); + goto end; + } + + ds_keyboard_set_keymap(seat->keyboard_dev->keyboard, keymap); + + xkb_keymap_unref(keymap); + xkb_context_unref(context); + } + + // TODO More case? + +end: + close(fd); +} + +static void +keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface, struct wl_array *keys) +{ + struct ds_wl_seat *seat = data; + uint32_t *keycode_ptr; + uint32_t time; + + ds_dbg("wl_keyboard: enter"); + + time = get_current_time_msec(); + + wl_array_for_each(keycode_ptr, keys) { + struct ds_event_keyboard_key event = { + .keycode = *keycode_ptr, + .state = WL_KEYBOARD_KEY_STATE_PRESSED, + .time_msec = time, + .update_state = false, + }; + + ds_keyboard_notify_key(seat->keyboard_dev->keyboard, &event); + } +} + +static void +keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface) +{ + struct ds_wl_seat *seat = data; + struct ds_keyboard *keyboard = seat->keyboard_dev->keyboard; + uint32_t *pressed; + uint32_t time, keycode; + size_t num_keycodes; + + ds_dbg("wl_keyboard: leave"); + + time = get_current_time_msec(); + + num_keycodes = keyboard->num_keycodes; + pressed = alloca(num_keycodes + 1); + memcpy(pressed, keyboard->keycodes, num_keycodes * sizeof(uint32_t)); + + for (size_t i = 0; i < num_keycodes; i++) { + keycode = pressed[i]; + + struct ds_event_keyboard_key event = { + .keycode = keycode, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + .time_msec = time, + .update_state = false, + }; + + ds_keyboard_notify_key(keyboard, &event); + } +} + +static void +keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + struct ds_wl_seat *seat = data; + + ds_dbg("wl_keyboard: key"); + + struct ds_event_keyboard_key event = { + .keycode = key, + .state = state, + .time_msec = time, + .update_state = false, + }; + + ds_keyboard_notify_key(seat->keyboard_dev->keyboard, &event); +} + +static void +keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial_in, uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ + struct ds_wl_seat *seat = data; + + ds_dbg("wl_keyboard: modifiers"); + + ds_keyboard_notify_modifiers(seat->keyboard_dev->keyboard, + mods_depressed, mods_latched, mods_locked, group); +} + +static void +keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, + int32_t rate, int32_t delay) +{ + ds_dbg("wl_keyboard: repeat_info"); + + // This space is intentionally left blank +} + +static const struct wl_keyboard_listener wl_keyboard_listener = { + .keymap = keyboard_handle_keymap, + .enter = keyboard_handle_enter, + .leave = keyboard_handle_leave, + .key = keyboard_handle_key, + .modifiers = keyboard_handle_modifiers, + .repeat_info = keyboard_handle_repeat_info, +}; + +static struct ds_keyboard * +create_wl_keyboard(struct ds_wl_seat *seat) +{ + struct ds_wl_keyboard *keyboard; + + keyboard = calloc(1, sizeof *keyboard); + if (!keyboard) + return NULL; + + ds_keyboard_init(&keyboard->base, &keyboard_iface); + + keyboard->wl_keyboard = wl_seat_get_keyboard(seat->wl_seat); + wl_keyboard_add_listener(keyboard->wl_keyboard, + &wl_keyboard_listener, seat); + + return &keyboard->base; +} diff --git a/src/libds/util.h b/src/libds/util.h index 1c9326a..4603544 100644 --- a/src/libds/util.h +++ b/src/libds/util.h @@ -7,6 +7,9 @@ int64_t timespec_to_msec(const struct timespec *a); +uint32_t +get_current_time_msec(void); + int allocate_shm_file(size_t size); diff --git a/src/libds/util/time.c b/src/libds/util/time.c index afb0e89..2461cb7 100644 --- a/src/libds/util/time.c +++ b/src/libds/util/time.c @@ -8,3 +8,12 @@ timespec_to_msec(const struct timespec *a) { return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; } + +uint32_t +get_current_time_msec(void) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + return timespec_to_msec(&now); +} -- 2.7.4 From 2026e03cbcc2076dad9418dc91330938e5078931 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 10:35:14 +0900 Subject: [PATCH 15/16] examples: Rename pointer-test to input-device-test This patch also adds code for ds_keyboard in input-device-test. Change-Id: I0e37a9a11beca9c38afc51e6841a08330e4852ab --- .../{pointer-test.c => input-device-test.c} | 105 +++++++++++++++++++-- src/examples/meson.build | 4 +- 2 files changed, 101 insertions(+), 8 deletions(-) rename src/examples/{pointer-test.c => input-device-test.c} (70%) diff --git a/src/examples/pointer-test.c b/src/examples/input-device-test.c similarity index 70% rename from src/examples/pointer-test.c rename to src/examples/input-device-test.c index d669a03..237d0b5 100644 --- a/src/examples/pointer-test.c +++ b/src/examples/input-device-test.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,17 @@ struct pointer_device { struct wl_listener frame; }; +struct server; + +struct keyboard_device { + struct server *server; + struct ds_keyboard *ds_keyboard; + + struct wl_listener destroy; + struct wl_listener modifiers; + struct wl_listener key; +}; + struct output { struct server *server; @@ -202,20 +214,101 @@ add_pointer(struct ds_input_device *dev) } static void +keyboard_handle_device_destroy(struct wl_listener *listener, void *data) +{ + struct keyboard_device *keyboard; + + keyboard = wl_container_of(listener, keyboard, destroy); + + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->modifiers.link); + wl_list_remove(&keyboard->key.link); + + free(keyboard); +} + +static void +keyboard_handle_modifiers(struct wl_listener *listener, void *data) +{ + struct keyboard_device *keyboard; + struct ds_keyboard *ds_keyboard = data; + + keyboard = wl_container_of(listener, keyboard, destroy); + + ds_inf("Keyboard(%p) event modifiers", ds_keyboard); +} + +static void +keyboard_handle_key(struct wl_listener *listener, void *data) +{ + struct ds_event_keyboard_key *event = data; + struct keyboard_device *keyboard; + struct xkb_state *xkb_state; + const xkb_keysym_t *syms; + int nsyms = 0; + + keyboard = wl_container_of(listener, keyboard, key); + + ds_inf("Keyboard(%p) event key: keycode(%d), state(%d), time_msec(%d), " + "update_state(%d)", keyboard->ds_keyboard, + event->keycode, event->state, event->time_msec, + event->update_state); + + xkb_state = ds_keyboard_get_xkb_state(keyboard->ds_keyboard); + if (!xkb_state) + return; + + nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8, &syms); + + for (int i = 0; i < nsyms; i++) { + if (syms[i] == XKB_KEY_Escape) + wl_display_terminate(keyboard->server->display); + } +} + +static void +add_keyboard(struct server *server, struct ds_input_device *dev) +{ + struct keyboard_device *keyboard; + + keyboard = calloc(1, sizeof *keyboard); + if (!keyboard) + return; + + keyboard->server = server; + keyboard->ds_keyboard = ds_input_device_get_keyboard(dev); + + ds_inf("Keyboard(%p) added", keyboard->ds_keyboard); + + keyboard->destroy.notify = keyboard_handle_device_destroy; + ds_input_device_add_destroy_listener(dev, &keyboard->destroy); + + keyboard->modifiers.notify = keyboard_handle_modifiers; + ds_keyboard_add_modifiers_listener(keyboard->ds_keyboard, + &keyboard->modifiers); + + keyboard->key.notify = keyboard_handle_key; + ds_keyboard_add_key_listener(keyboard->ds_keyboard, + &keyboard->key); +} + +static void handle_new_input(struct wl_listener *listener, void *data) { + struct server *server; struct ds_input_device *dev = data; enum ds_input_device_type type; type = ds_input_device_get_type(dev); - if (type != DS_INPUT_DEVICE_POINTER) - return; + ds_inf("New device(%p) type(%s)", dev, device_type_to_string(type)); - ds_inf("New pointer device(%p) type(%s)", dev, - device_type_to_string(type)); - - add_pointer(dev); + if (type == DS_INPUT_DEVICE_POINTER) + add_pointer(dev); + else if (type == DS_INPUT_DEVICE_KEYBOARD) { + server = wl_container_of(listener, server, new_input); + add_keyboard(server, dev); + } } static void diff --git a/src/examples/meson.build b/src/examples/meson.build index f19f139..c568eb6 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -23,9 +23,9 @@ executable('tinyds', install : true ) -executable('pointer-test', +executable('input-device-test', [ - 'pointer-test.c', + 'input-device-test.c', 'pixman-helper.c', ], dependencies: common_deps, -- 2.7.4 From 418c71edde3b957e493912cb04a00729b0e1575e Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 10:37:06 +0900 Subject: [PATCH 16/16] Enable user to get keyboard modifiers input-device-test take modifiers into account when handling key. Change-Id: Iec87c300323d891e18873afcf9b1eabf886ee068 --- include/libds/interfaces/keyboard.h | 13 ------------- include/libds/keyboard.h | 13 +++++++++++++ src/examples/input-device-test.c | 36 ++++++++++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/include/libds/interfaces/keyboard.h b/include/libds/interfaces/keyboard.h index f68c9a7..3602fe5 100644 --- a/include/libds/interfaces/keyboard.h +++ b/include/libds/interfaces/keyboard.h @@ -14,19 +14,6 @@ enum ds_keyboard_led { DS_LED_SCROLL_LOCK = 1 << 2, }; -#define DS_MODIFIER_COUNT 8 - -enum ds_keyboard_modifier { - DS_MODIFIER_SHIFT = 1 << 0, - DS_MODIFIER_CAPS = 1 << 1, - DS_MODIFIER_CTRL = 1 << 2, - DS_MODIFIER_ALT = 1 << 3, - DS_MODIFIER_MOD2 = 1 << 4, - DS_MODIFIER_MOD3 = 1 << 5, - DS_MODIFIER_LOGO = 1 << 6, - DS_MODIFIER_MOD5 = 1 << 7, -}; - #define DS_KEYBOARD_KEYS_CAP 32 struct ds_keyboard; diff --git a/include/libds/keyboard.h b/include/libds/keyboard.h index e226cb4..2a515e3 100644 --- a/include/libds/keyboard.h +++ b/include/libds/keyboard.h @@ -9,6 +9,19 @@ struct ds_keyboard; +#define DS_MODIFIER_COUNT 8 + +enum ds_keyboard_modifier { + DS_MODIFIER_SHIFT = 1 << 0, + DS_MODIFIER_CAPS = 1 << 1, + DS_MODIFIER_CTRL = 1 << 2, + DS_MODIFIER_ALT = 1 << 3, + DS_MODIFIER_MOD2 = 1 << 4, + DS_MODIFIER_MOD3 = 1 << 5, + DS_MODIFIER_LOGO = 1 << 6, + DS_MODIFIER_MOD5 = 1 << 7, +}; + struct ds_event_keyboard_key { uint32_t time_msec; diff --git a/src/examples/input-device-test.c b/src/examples/input-device-test.c index 237d0b5..62fe8b0 100644 --- a/src/examples/input-device-test.c +++ b/src/examples/input-device-test.c @@ -230,12 +230,26 @@ keyboard_handle_device_destroy(struct wl_listener *listener, void *data) static void keyboard_handle_modifiers(struct wl_listener *listener, void *data) { - struct keyboard_device *keyboard; struct ds_keyboard *ds_keyboard = data; - - keyboard = wl_container_of(listener, keyboard, destroy); - - ds_inf("Keyboard(%p) event modifiers", ds_keyboard); + uint32_t modifiers; + + modifiers = ds_keyboard_get_modifiers(ds_keyboard); + if (modifiers & DS_MODIFIER_CTRL) + ds_inf("Keyboard(%p) modifier: Ctrl", ds_keyboard); + if (modifiers & DS_MODIFIER_SHIFT) + ds_inf("Keyboard(%p) modifier: Shift", ds_keyboard); + if (modifiers & DS_MODIFIER_CAPS) + ds_inf("Keyboard(%p) modifier: Caps", ds_keyboard); + if (modifiers & DS_MODIFIER_ALT) + ds_inf("Keyboard(%p) modifier: Alt", ds_keyboard); + if (modifiers & DS_MODIFIER_MOD2) + ds_inf("Keyboard(%p) modifier: Mod2", ds_keyboard); + if (modifiers & DS_MODIFIER_MOD3) + ds_inf("Keyboard(%p) modifier: Mod3", ds_keyboard); + if (modifiers & DS_MODIFIER_LOGO) + ds_inf("Keyboard(%p) modifier: Logo", ds_keyboard); + if (modifiers & DS_MODIFIER_MOD5) + ds_inf("Keyboard(%p) modifier: Mod5", ds_keyboard); } static void @@ -245,6 +259,7 @@ keyboard_handle_key(struct wl_listener *listener, void *data) struct keyboard_device *keyboard; struct xkb_state *xkb_state; const xkb_keysym_t *syms; + uint32_t modifiers; int nsyms = 0; keyboard = wl_container_of(listener, keyboard, key); @@ -260,9 +275,14 @@ keyboard_handle_key(struct wl_listener *listener, void *data) nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8, &syms); - for (int i = 0; i < nsyms; i++) { - if (syms[i] == XKB_KEY_Escape) - wl_display_terminate(keyboard->server->display); + modifiers = ds_keyboard_get_modifiers(keyboard->ds_keyboard); + if ((modifiers & DS_MODIFIER_CTRL) && + (modifiers & DS_MODIFIER_ALT) && + event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + for (int i = 0; i < nsyms; i++) { + if (syms[i] == XKB_KEY_BackSpace) + wl_display_terminate(keyboard->server->display); + } } } -- 2.7.4