From 43aea6774f1822ade82417bc64c9228407842de8 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 18 Mar 2023 19:11:56 +0900 Subject: [PATCH 01/49] move screen backend to backend/screen/ --- zen/meson.build | 2 +- zen/src/backend/{ => screen}/backend.c | 0 zen/src/backend/{ => screen}/backend.h | 0 zen/src/backend/{ => screen}/compositor.c | 2 +- zen/src/backend/{ => screen}/compositor.h | 0 zen/src/backend/{ => screen}/input-device.h | 0 zen/src/backend/{ => screen}/keyboard.c | 0 zen/src/backend/{ => screen}/keyboard.h | 0 zen/src/backend/{ => screen}/layer-surface.c | 0 zen/src/backend/{ => screen}/layer-surface.h | 0 zen/src/backend/{ => screen}/meson.build | 0 zen/src/backend/{ => screen}/output.c | 0 zen/src/backend/{ => screen}/output.h | 0 zen/src/backend/{ => screen}/pointer.c | 0 zen/src/backend/{ => screen}/pointer.h | 0 zen/src/backend/{ => screen}/screen-backend.c | 0 zen/src/backend/{ => screen}/screen-backend.h | 0 zen/src/backend/{ => screen}/surface-snode.c | 0 zen/src/backend/{ => screen}/surface-snode.h | 0 zen/src/backend/{ => screen}/xwayland-surface.c | 0 zen/src/backend/{ => screen}/xwayland-surface.h | 0 21 files changed, 2 insertions(+), 2 deletions(-) rename zen/src/backend/{ => screen}/backend.c (100%) rename zen/src/backend/{ => screen}/backend.h (100%) rename zen/src/backend/{ => screen}/compositor.c (99%) rename zen/src/backend/{ => screen}/compositor.h (100%) rename zen/src/backend/{ => screen}/input-device.h (100%) rename zen/src/backend/{ => screen}/keyboard.c (100%) rename zen/src/backend/{ => screen}/keyboard.h (100%) rename zen/src/backend/{ => screen}/layer-surface.c (100%) rename zen/src/backend/{ => screen}/layer-surface.h (100%) rename zen/src/backend/{ => screen}/meson.build (100%) rename zen/src/backend/{ => screen}/output.c (100%) rename zen/src/backend/{ => screen}/output.h (100%) rename zen/src/backend/{ => screen}/pointer.c (100%) rename zen/src/backend/{ => screen}/pointer.h (100%) rename zen/src/backend/{ => screen}/screen-backend.c (100%) rename zen/src/backend/{ => screen}/screen-backend.h (100%) rename zen/src/backend/{ => screen}/surface-snode.c (100%) rename zen/src/backend/{ => screen}/surface-snode.h (100%) rename zen/src/backend/{ => screen}/xwayland-surface.c (100%) rename zen/src/backend/{ => screen}/xwayland-surface.h (100%) diff --git a/zen/meson.build b/zen/meson.build index 4756bdfa..4b6ebbc1 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -34,7 +34,7 @@ _zen_deps = [ xkbcommon_dep, ] + _zen_pub_deps -subdir('src/backend') +subdir('src/backend/screen') _zen_deps += zen_backend_dep diff --git a/zen/src/backend/backend.c b/zen/src/backend/screen/backend.c similarity index 100% rename from zen/src/backend/backend.c rename to zen/src/backend/screen/backend.c diff --git a/zen/src/backend/backend.h b/zen/src/backend/screen/backend.h similarity index 100% rename from zen/src/backend/backend.h rename to zen/src/backend/screen/backend.h diff --git a/zen/src/backend/compositor.c b/zen/src/backend/screen/compositor.c similarity index 99% rename from zen/src/backend/compositor.c rename to zen/src/backend/screen/compositor.c index aceeb2b2..f4aaf6c0 100644 --- a/zen/src/backend/compositor.c +++ b/zen/src/backend/screen/compositor.c @@ -1,4 +1,4 @@ -#include "backend/compositor.h" +#include "compositor.h" #include diff --git a/zen/src/backend/compositor.h b/zen/src/backend/screen/compositor.h similarity index 100% rename from zen/src/backend/compositor.h rename to zen/src/backend/screen/compositor.h diff --git a/zen/src/backend/input-device.h b/zen/src/backend/screen/input-device.h similarity index 100% rename from zen/src/backend/input-device.h rename to zen/src/backend/screen/input-device.h diff --git a/zen/src/backend/keyboard.c b/zen/src/backend/screen/keyboard.c similarity index 100% rename from zen/src/backend/keyboard.c rename to zen/src/backend/screen/keyboard.c diff --git a/zen/src/backend/keyboard.h b/zen/src/backend/screen/keyboard.h similarity index 100% rename from zen/src/backend/keyboard.h rename to zen/src/backend/screen/keyboard.h diff --git a/zen/src/backend/layer-surface.c b/zen/src/backend/screen/layer-surface.c similarity index 100% rename from zen/src/backend/layer-surface.c rename to zen/src/backend/screen/layer-surface.c diff --git a/zen/src/backend/layer-surface.h b/zen/src/backend/screen/layer-surface.h similarity index 100% rename from zen/src/backend/layer-surface.h rename to zen/src/backend/screen/layer-surface.h diff --git a/zen/src/backend/meson.build b/zen/src/backend/screen/meson.build similarity index 100% rename from zen/src/backend/meson.build rename to zen/src/backend/screen/meson.build diff --git a/zen/src/backend/output.c b/zen/src/backend/screen/output.c similarity index 100% rename from zen/src/backend/output.c rename to zen/src/backend/screen/output.c diff --git a/zen/src/backend/output.h b/zen/src/backend/screen/output.h similarity index 100% rename from zen/src/backend/output.h rename to zen/src/backend/screen/output.h diff --git a/zen/src/backend/pointer.c b/zen/src/backend/screen/pointer.c similarity index 100% rename from zen/src/backend/pointer.c rename to zen/src/backend/screen/pointer.c diff --git a/zen/src/backend/pointer.h b/zen/src/backend/screen/pointer.h similarity index 100% rename from zen/src/backend/pointer.h rename to zen/src/backend/screen/pointer.h diff --git a/zen/src/backend/screen-backend.c b/zen/src/backend/screen/screen-backend.c similarity index 100% rename from zen/src/backend/screen-backend.c rename to zen/src/backend/screen/screen-backend.c diff --git a/zen/src/backend/screen-backend.h b/zen/src/backend/screen/screen-backend.h similarity index 100% rename from zen/src/backend/screen-backend.h rename to zen/src/backend/screen/screen-backend.h diff --git a/zen/src/backend/surface-snode.c b/zen/src/backend/screen/surface-snode.c similarity index 100% rename from zen/src/backend/surface-snode.c rename to zen/src/backend/screen/surface-snode.c diff --git a/zen/src/backend/surface-snode.h b/zen/src/backend/screen/surface-snode.h similarity index 100% rename from zen/src/backend/surface-snode.h rename to zen/src/backend/screen/surface-snode.h diff --git a/zen/src/backend/xwayland-surface.c b/zen/src/backend/screen/xwayland-surface.c similarity index 100% rename from zen/src/backend/xwayland-surface.c rename to zen/src/backend/screen/xwayland-surface.c diff --git a/zen/src/backend/xwayland-surface.h b/zen/src/backend/screen/xwayland-surface.h similarity index 100% rename from zen/src/backend/xwayland-surface.h rename to zen/src/backend/screen/xwayland-surface.h From c90b561d6b9ef63bb84f12a266ec966537aafe5d Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 18 Mar 2023 19:45:58 +0900 Subject: [PATCH 02/49] rename screen backend to layer shell --- zen/src/backend/screen/compositor.c | 6 ++--- .../{screen-backend.c => layer-shell.c} | 26 +++++++++---------- .../{screen-backend.h => layer-shell.h} | 12 ++++----- zen/src/backend/screen/layer-surface.c | 4 +-- zen/src/backend/screen/meson.build | 2 +- zen/src/backend/screen/output.c | 18 ++++++------- zen/src/backend/screen/output.h | 6 ++--- 7 files changed, 37 insertions(+), 37 deletions(-) rename zen/src/backend/screen/{screen-backend.c => layer-shell.c} (91%) rename zen/src/backend/screen/{screen-backend.h => layer-shell.h} (57%) diff --git a/zen/src/backend/screen/compositor.c b/zen/src/backend/screen/compositor.c index f4aaf6c0..8a94db63 100644 --- a/zen/src/backend/screen/compositor.c +++ b/zen/src/backend/screen/compositor.c @@ -2,9 +2,9 @@ #include +#include "layer-shell.h" #include "layer-surface.h" #include "output.h" -#include "screen-backend.h" #include "xwayland-surface.h" #include "zen-common/log.h" #include "zen-common/util.h" @@ -58,8 +58,8 @@ zn_compositor_handle_new_layer_surface( return; } - zn_screen_backend_add_layer_surface( - output->screen_backend, layer_surface, wlr_layer_surface->current.layer); + zn_layer_shell_add_layer_surface( + output->layer_shell, layer_surface, wlr_layer_surface->current.layer); } static void diff --git a/zen/src/backend/screen/screen-backend.c b/zen/src/backend/screen/layer-shell.c similarity index 91% rename from zen/src/backend/screen/screen-backend.c rename to zen/src/backend/screen/layer-shell.c index 631c53aa..402f46e9 100644 --- a/zen/src/backend/screen/screen-backend.c +++ b/zen/src/backend/screen/layer-shell.c @@ -1,4 +1,4 @@ -#include "screen-backend.h" +#include "layer-shell.h" #include @@ -147,7 +147,7 @@ calculate_surface_box( } static void -zn_screen_backend_arrange_layer(struct zn_screen_backend *self, +zn_layer_shell_arrange_layer(struct zn_layer_shell *self, enum zwlr_layer_shell_v1_layer layer, struct wlr_box *usable_area, bool exclusive) { @@ -198,7 +198,7 @@ zn_screen_backend_arrange_layer(struct zn_screen_backend *self, } static void -zn_screen_backend_arrange_layers(struct zn_screen_backend *self) +zn_layer_shell_arrange_layers(struct zn_layer_shell *self) { struct wlr_box usable_area = {0}; wlr_output_effective_resolution( @@ -206,41 +206,41 @@ zn_screen_backend_arrange_layers(struct zn_screen_backend *self) // Arrange exclusive surfaces from top to bottom for (int i = 3; i >= 0; i--) { - zn_screen_backend_arrange_layer(self, i, &usable_area, true); + zn_layer_shell_arrange_layer(self, i, &usable_area, true); } // TODO(@Aki-7): Notify screen the usable area change // Arrange non-exclusive surfaces from top to bottom for (int i = 3; i >= 0; i--) { - zn_screen_backend_arrange_layer(self, i, &usable_area, false); + zn_layer_shell_arrange_layer(self, i, &usable_area, false); } // TODO(@Aki-7): Configure keyboard interactivity } void -zn_screen_backend_add_layer_surface(struct zn_screen_backend *self, +zn_layer_shell_add_layer_surface(struct zn_layer_shell *self, struct zn_layer_surface *layer_surface, enum zwlr_layer_shell_v1_layer layer) { zn_snode_set_position( layer_surface->snode, self->layers[layer], GLM_VEC2_ZERO); - zn_screen_backend_arrange_layers(self); + zn_layer_shell_arrange_layers(self); } struct zn_snode * -zn_screen_backend_get_layer( - struct zn_screen_backend *self, enum zwlr_layer_shell_v1_layer layer) +zn_layer_shell_get_layer( + struct zn_layer_shell *self, enum zwlr_layer_shell_v1_layer layer) { return self->layers[layer]; } -struct zn_screen_backend * -zn_screen_backend_create(struct zn_output *output) +struct zn_layer_shell * +zn_layer_shell_create(struct zn_output *output) { - struct zn_screen_backend *self = zalloc(sizeof *self); + struct zn_layer_shell *self = zalloc(sizeof *self); if (self == NULL) { zn_error("Failed to allocate memory"); goto err; @@ -272,7 +272,7 @@ zn_screen_backend_create(struct zn_output *output) } void -zn_screen_backend_destroy(struct zn_screen_backend *self) +zn_layer_shell_destroy(struct zn_layer_shell *self) { for (int i = 0; i < 4; i++) { zn_snode_destroy(self->layers[i]); diff --git a/zen/src/backend/screen/screen-backend.h b/zen/src/backend/screen/layer-shell.h similarity index 57% rename from zen/src/backend/screen/screen-backend.h rename to zen/src/backend/screen/layer-shell.h index 94245b21..804e829f 100644 --- a/zen/src/backend/screen/screen-backend.h +++ b/zen/src/backend/screen/layer-shell.h @@ -5,7 +5,7 @@ struct zn_snode; struct zn_layer_surface; -struct zn_screen_backend { +struct zn_layer_shell { struct zn_output *output; // @nonnull, @outlive // Every child snode in each layer snode must be that of zn_layer_surface @@ -14,13 +14,13 @@ struct zn_screen_backend { struct zn_snode *layers[4]; // each layer is @nonnull, @owning }; -void zn_screen_backend_add_layer_surface(struct zn_screen_backend *self, +void zn_layer_shell_add_layer_surface(struct zn_layer_shell *self, struct zn_layer_surface *layer_surface, enum zwlr_layer_shell_v1_layer layer); -struct zn_snode *zn_screen_backend_get_layer( - struct zn_screen_backend *self, enum zwlr_layer_shell_v1_layer layer); +struct zn_snode *zn_layer_shell_get_layer( + struct zn_layer_shell *self, enum zwlr_layer_shell_v1_layer layer); -struct zn_screen_backend *zn_screen_backend_create(struct zn_output *output); +struct zn_layer_shell *zn_layer_shell_create(struct zn_output *output); -void zn_screen_backend_destroy(struct zn_screen_backend *self); +void zn_layer_shell_destroy(struct zn_layer_shell *self); diff --git a/zen/src/backend/screen/layer-surface.c b/zen/src/backend/screen/layer-surface.c index 431f3eed..a3c55f20 100644 --- a/zen/src/backend/screen/layer-surface.c +++ b/zen/src/backend/screen/layer-surface.c @@ -3,8 +3,8 @@ #include #include +#include "layer-shell.h" #include "output.h" -#include "screen-backend.h" #include "surface-snode.h" #include "zen-common/log.h" #include "zen-common/util.h" @@ -58,7 +58,7 @@ zn_layer_surface_handle_surface_commit( bool layer_changed = self->layer != self->wlr_layer_surface->current.layer; if (layer_changed) { - zn_screen_backend_add_layer_surface(self->output->screen_backend, self, + zn_layer_shell_add_layer_surface(self->output->layer_shell, self, self->wlr_layer_surface->current.layer); zn_surface_snode_damage_whole(self->surface_snode); } else { diff --git a/zen/src/backend/screen/meson.build b/zen/src/backend/screen/meson.build index c8746b0a..975cd42a 100644 --- a/zen/src/backend/screen/meson.build +++ b/zen/src/backend/screen/meson.build @@ -2,10 +2,10 @@ _zen_backend_srcs = [ 'backend.c', 'compositor.c', 'keyboard.c', + 'layer-shell.c', 'layer-surface.c', 'output.c', 'pointer.c', - 'screen-backend.c', 'surface-snode.c', 'xwayland-surface.c', ] diff --git a/zen/src/backend/screen/output.c b/zen/src/backend/screen/output.c index 88a75ebe..34d12364 100644 --- a/zen/src/backend/screen/output.c +++ b/zen/src/backend/screen/output.c @@ -13,7 +13,7 @@ #include "backend.h" #include "compositor.h" -#include "screen-backend.h" +#include "layer-shell.h" #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" @@ -208,7 +208,7 @@ static struct zn_snode * zn_output_get_layer(void *impl_data, enum zwlr_layer_shell_v1_layer layer) { struct zn_output *self = impl_data; - return zn_screen_backend_get_layer(self->screen_backend, layer); + return zn_layer_shell_get_layer(self->layer_shell, layer); } const struct zn_screen_interface screen_implementation = { @@ -279,16 +279,16 @@ zn_output_create(struct wlr_output *wlr_output) self->wlr_output = wlr_output; wlr_output->data = self; - self->screen_backend = zn_screen_backend_create(self); - if (self->screen_backend == NULL) { - zn_error("Failed to create a zn_screen_backend"); + self->layer_shell = zn_layer_shell_create(self); + if (self->layer_shell == NULL) { + zn_error("Failed to create a zn_layer_shell"); goto err_free; } self->screen = zn_screen_create(self, &screen_implementation); if (self->screen == NULL) { zn_error("Failed to create a zn_screen"); - goto err_screen_backend; + goto err_layer_shell; } self->damage = wlr_output_damage_create(wlr_output); @@ -345,8 +345,8 @@ zn_output_create(struct wlr_output *wlr_output) err_screen: zn_screen_destroy(self->screen); -err_screen_backend: - zn_screen_backend_destroy(self->screen_backend); +err_layer_shell: + zn_layer_shell_destroy(self->layer_shell); err_free: free(self); @@ -372,6 +372,6 @@ zn_output_destroy(struct zn_output *self) */ // wl_list_remove(&self->damage_frame_listener.link); - zn_screen_backend_destroy(self->screen_backend); + zn_layer_shell_destroy(self->layer_shell); free(self); } diff --git a/zen/src/backend/screen/output.h b/zen/src/backend/screen/output.h index 176dcfe6..fe23a3d5 100644 --- a/zen/src/backend/screen/output.h +++ b/zen/src/backend/screen/output.h @@ -5,11 +5,11 @@ #include struct zn_screen; -struct zn_screen_backend; +struct zn_layer_shell; struct zn_output { - struct zn_screen *screen; // @nonnull, @owning - struct zn_screen_backend *screen_backend; // @nonnull, @owning + struct zn_screen *screen; // @nonnull, @owning + struct zn_layer_shell *layer_shell; // @nonnull, @owning struct wlr_output *wlr_output; // @nonnull, @outlive From 2fb034c246efd12adaeb9c1cdbf8ffe972efbc08 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 18 Mar 2023 20:12:17 +0900 Subject: [PATCH 03/49] change directory structure of backend --- zen/meson.build | 2 +- .../{screen/backend.c => default-backend.c} | 10 +++++----- .../{screen/backend.h => default-backend.h} | 0 zen/src/backend/{screen => }/meson.build | 19 ++++++++++--------- zen/src/backend/screen/keyboard.c | 2 +- zen/src/backend/screen/output.c | 2 +- zen/src/backend/screen/pointer.c | 2 +- zen/src/backend/screen/xwayland-surface.c | 2 +- 8 files changed, 20 insertions(+), 19 deletions(-) rename zen/src/backend/{screen/backend.c => default-backend.c} (98%) rename zen/src/backend/{screen/backend.h => default-backend.h} (100%) rename zen/src/backend/{screen => }/meson.build (52%) diff --git a/zen/meson.build b/zen/meson.build index 4b6ebbc1..4756bdfa 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -34,7 +34,7 @@ _zen_deps = [ xkbcommon_dep, ] + _zen_pub_deps -subdir('src/backend/screen') +subdir('src/backend') _zen_deps += zen_backend_dep diff --git a/zen/src/backend/screen/backend.c b/zen/src/backend/default-backend.c similarity index 98% rename from zen/src/backend/screen/backend.c rename to zen/src/backend/default-backend.c index 303a78fb..a6caf3ef 100644 --- a/zen/src/backend/screen/backend.c +++ b/zen/src/backend/default-backend.c @@ -1,4 +1,4 @@ -#include "backend.h" +#include "default-backend.h" #include #include @@ -7,10 +7,10 @@ #include #include -#include "compositor.h" -#include "keyboard.h" -#include "output.h" -#include "pointer.h" +#include "screen/compositor.h" +#include "screen/keyboard.h" +#include "screen/output.h" +#include "screen/pointer.h" #include "seat.h" #include "zen-common/log.h" #include "zen-common/signal.h" diff --git a/zen/src/backend/screen/backend.h b/zen/src/backend/default-backend.h similarity index 100% rename from zen/src/backend/screen/backend.h rename to zen/src/backend/default-backend.h diff --git a/zen/src/backend/screen/meson.build b/zen/src/backend/meson.build similarity index 52% rename from zen/src/backend/screen/meson.build rename to zen/src/backend/meson.build index 975cd42a..96f591c3 100644 --- a/zen/src/backend/screen/meson.build +++ b/zen/src/backend/meson.build @@ -1,13 +1,14 @@ _zen_backend_srcs = [ - 'backend.c', - 'compositor.c', - 'keyboard.c', - 'layer-shell.c', - 'layer-surface.c', - 'output.c', - 'pointer.c', - 'surface-snode.c', - 'xwayland-surface.c', + 'default-backend.c', + + 'screen/compositor.c', + 'screen/keyboard.c', + 'screen/layer-shell.c', + 'screen/layer-surface.c', + 'screen/output.c', + 'screen/pointer.c', + 'screen/surface-snode.c', + 'screen/xwayland-surface.c', ] _zen_backend_lib = static_library( diff --git a/zen/src/backend/screen/keyboard.c b/zen/src/backend/screen/keyboard.c index fafeb026..c80c7fff 100644 --- a/zen/src/backend/screen/keyboard.c +++ b/zen/src/backend/screen/keyboard.c @@ -2,7 +2,7 @@ #include -#include "backend.h" +#include "default-backend.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen/seat.h" diff --git a/zen/src/backend/screen/output.c b/zen/src/backend/screen/output.c index 34d12364..bae0a628 100644 --- a/zen/src/backend/screen/output.c +++ b/zen/src/backend/screen/output.c @@ -11,8 +11,8 @@ #include #include -#include "backend.h" #include "compositor.h" +#include "default-backend.h" #include "layer-shell.h" #include "zen-common/log.h" #include "zen-common/signal.h" diff --git a/zen/src/backend/screen/pointer.c b/zen/src/backend/screen/pointer.c index 59c0fcc2..2d8efa0a 100644 --- a/zen/src/backend/screen/pointer.c +++ b/zen/src/backend/screen/pointer.c @@ -4,8 +4,8 @@ #include #include -#include "backend.h" #include "cursor.h" +#include "default-backend.h" #include "seat.h" #include "zen-common/log.h" #include "zen-common/util.h" diff --git a/zen/src/backend/screen/xwayland-surface.c b/zen/src/backend/screen/xwayland-surface.c index adb1186e..72348812 100644 --- a/zen/src/backend/screen/xwayland-surface.c +++ b/zen/src/backend/screen/xwayland-surface.c @@ -2,7 +2,7 @@ #include -#include "backend.h" +#include "default-backend.h" #include "surface-snode.h" #include "zen-common/log.h" #include "zen-common/util.h" From fec90fa2a9e6c062a5118a41688ab36996bd4b5f Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 22 Mar 2023 16:12:47 +0900 Subject: [PATCH 04/49] Enable to detect HMD --- .clang-tidy | 8 ++ meson.build | 3 + zen-xr/include/zen-xr/system.h | 19 +++ zen-xr/include/zen-xr/xr.h | 27 +++++ zen-xr/meson.build | 31 +++++ zen-xr/pch/pch.h | 7 ++ zen-xr/src/common.h | 9 ++ zen-xr/src/loop.cc | 77 ++++++++++++ zen-xr/src/loop.h | 22 ++++ zen-xr/src/remote-system.cc | 21 ++++ zen-xr/src/remote-system.h | 28 +++++ zen-xr/src/xr.cc | 111 ++++++++++++++++++ zen-xr/src/xr.h | 44 +++++++ zen/include/zen/backend.h | 7 +- zen/include/zen/xr-system.h | 21 ++++ zen/src/backend/default-backend.c | 29 +++++ zen/src/backend/default-backend.h | 4 + zen/src/backend/immersive/common.h | 9 ++ zen/src/backend/immersive/xr-private.h | 34 ++++++ zen/src/backend/immersive/xr-system-private.h | 36 ++++++ zen/src/backend/immersive/xr-system.cc | 23 ++++ zen/src/backend/immersive/xr.cc | 69 +++++++++++ zen/src/backend/immersive/xr.h | 21 ++++ zen/src/backend/meson.build | 7 +- zen/src/backend/pch/pch.h | 9 ++ 25 files changed, 672 insertions(+), 4 deletions(-) create mode 100644 zen-xr/include/zen-xr/system.h create mode 100644 zen-xr/include/zen-xr/xr.h create mode 100644 zen-xr/meson.build create mode 100644 zen-xr/pch/pch.h create mode 100644 zen-xr/src/common.h create mode 100644 zen-xr/src/loop.cc create mode 100644 zen-xr/src/loop.h create mode 100644 zen-xr/src/remote-system.cc create mode 100644 zen-xr/src/remote-system.h create mode 100644 zen-xr/src/xr.cc create mode 100644 zen-xr/src/xr.h create mode 100644 zen/include/zen/xr-system.h create mode 100644 zen/src/backend/immersive/common.h create mode 100644 zen/src/backend/immersive/xr-private.h create mode 100644 zen/src/backend/immersive/xr-system-private.h create mode 100644 zen/src/backend/immersive/xr-system.cc create mode 100644 zen/src/backend/immersive/xr.cc create mode 100644 zen/src/backend/immersive/xr.h create mode 100644 zen/src/backend/pch/pch.h diff --git a/.clang-tidy b/.clang-tidy index 360eab1f..ff07404d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -12,6 +12,8 @@ Checks: " cppcoreguidelines-*, -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-pro-type-vararg, + -cppcoreguidelines-macro-usage, google-*, @@ -19,6 +21,9 @@ Checks: " -misc-no-recursion, modernize-*, + -modernize-use-nodiscard, + -modernize-use-trailing-return-type, + performance-*, portability-*, @@ -28,5 +33,8 @@ Checks: " *-cloexec-*, " +CheckOptions: +- key: 'cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor' + value: 'true' WarningsAsErrors: '*' FormatStyle: file diff --git a/meson.build b/meson.build index ae1df0e6..8ea57092 100644 --- a/meson.build +++ b/meson.build @@ -120,6 +120,7 @@ configure_file( wayland_req = '>= 1.18.0' wayland_protocols_req = '>= 1.24' wlroots_req = ['>= 0.15', '< 0.16'] +zen_remote_server_req = '0.1.1' glew_proj = subproject( @@ -142,6 +143,7 @@ wayland_protocols_dep = dependency('wayland-protocols', version: wayland_protoco wayland_scanner_dep = dependency('wayland-scanner', native: true) wayland_server_dep = dependency('wayland-server', version: wayland_req) xkbcommon_dep = dependency('xkbcommon') +zen_remote_server_dep = dependency('zen-remote-server', version: zen_remote_server_req) subdir('protocol') wlroots_dep = declare_dependency( @@ -161,6 +163,7 @@ if get_option('tests') subdir('test-harness') endif subdir('common') +subdir('zen-xr') subdir('zen-wlr-glew-renderer') subdir('zen') subdir('desktop') diff --git a/zen-xr/include/zen-xr/system.h b/zen-xr/include/zen-xr/system.h new file mode 100644 index 00000000..2798285b --- /dev/null +++ b/zen-xr/include/zen-xr/system.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace zen::xr { + +struct System { + enum Type { + kNone, + kRemote, + }; + + virtual ~System() = default; + + virtual uint64_t handle() = 0; + virtual Type type() = 0; +}; + +} // namespace zen::xr diff --git a/zen-xr/include/zen-xr/xr.h b/zen-xr/include/zen-xr/xr.h new file mode 100644 index 00000000..5bc9d04b --- /dev/null +++ b/zen-xr/include/zen-xr/xr.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include + +namespace zen::xr { + +struct System; + +struct Xr { + virtual ~Xr() = default; +}; + +struct XrDelegate { + virtual ~XrDelegate() = default; + + virtual void NotifySystemAdded(uint64_t handle) = 0; + + virtual void NotifySystemRemoved(std::unique_ptr &system) = 0; +}; + +/// @returns nullptr if failed +/// @param delegate can be NULL +std::unique_ptr CreateXr(wl_display *display, XrDelegate *delegate); + +} // namespace zen::xr diff --git a/zen-xr/meson.build b/zen-xr/meson.build new file mode 100644 index 00000000..65a86479 --- /dev/null +++ b/zen-xr/meson.build @@ -0,0 +1,31 @@ +_zen_xr_srcs = [ + 'src/loop.cc', + 'src/remote-system.cc', + 'src/xr.cc', +] + +_zen_xr_public_deps = [ +] + +_zen_xr_deps = [ + wayland_server_dep, + zen_common_dep, + zen_remote_server_dep, +] + _zen_xr_public_deps + +_zen_xr_inc = include_directories('include') + +_zen_xr_lib = static_library( + 'zen-xr', + _zen_xr_srcs, + install: false, + cpp_args: ['-include', 'pch/pch.h'], + include_directories: _zen_xr_inc, + dependencies: _zen_xr_deps, + cpp_pch: 'pch/pch.h', +) + +zen_xr_dep = declare_dependency( + link_with: _zen_xr_lib, + include_directories: _zen_xr_inc, +) diff --git a/zen-xr/pch/pch.h b/zen-xr/pch/pch.h new file mode 100644 index 00000000..2c9952b9 --- /dev/null +++ b/zen-xr/pch/pch.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +#include +#include diff --git a/zen-xr/src/common.h b/zen-xr/src/common.h new file mode 100644 index 00000000..8e4fc40b --- /dev/null +++ b/zen-xr/src/common.h @@ -0,0 +1,9 @@ +#pragma once + +// NOLINTBEGIN(bugprone-macro-parentheses) +#define DISABLE_MOVE_AND_COPY(Class) \ + Class(const Class &) = delete; \ + Class(Class &&) = delete; \ + Class &operator=(const Class &) = delete; \ + Class &operator=(Class &&) = delete +// NOLINTEND(bugprone-macro-parentheses) diff --git a/zen-xr/src/loop.cc b/zen-xr/src/loop.cc new file mode 100644 index 00000000..155e465d --- /dev/null +++ b/zen-xr/src/loop.cc @@ -0,0 +1,77 @@ +#include "loop.h" + +#include "zen-common/terminate.h" + +namespace zen::xr { + +namespace { + +int +loop_callback(int fd, uint32_t mask, void *data) +{ + auto *source = static_cast(data); + + uint32_t remote_mask = 0; + + if ((mask & WL_EVENT_READABLE) == WL_EVENT_READABLE) { + remote_mask |= zen::remote::FdSource::kReadable; + } + + if ((mask & WL_EVENT_WRITABLE) == WL_EVENT_WRITABLE) { + remote_mask |= zen::remote::FdSource::kWritable; + } + + if ((mask & WL_EVENT_HANGUP) == WL_EVENT_HANGUP) { + remote_mask |= zen::remote::FdSource::kHangup; + } + + if ((mask & WL_EVENT_ERROR) == WL_EVENT_ERROR) { + remote_mask |= zen::remote::FdSource::kError; + } + + source->callback(fd, remote_mask); + + return 1; +} + +} // namespace + +Loop::Loop(wl_event_loop *wl_loop) : wl_loop_(wl_loop) {} + +void +Loop::AddFd(zen::remote::FdSource *source) +{ + using FdSource = zen::remote::FdSource; + + uint32_t mask = 0; + + if ((source->mask & FdSource::kReadable) == FdSource::kReadable) { + mask |= WL_EVENT_READABLE; + } + if ((source->mask & FdSource::kWritable) == FdSource::kWritable) { + mask |= WL_EVENT_WRITABLE; + } + if ((source->mask & FdSource::kHangup) == FdSource::kHangup) { + mask |= WL_EVENT_HANGUP; + } + if ((source->mask & FdSource::kError) == FdSource::kError) { + mask |= WL_EVENT_ERROR; + } + + source->data = + wl_event_loop_add_fd(wl_loop_, source->fd, mask, loop_callback, source); +} + +void +Loop::RemoveFd(zen::remote::FdSource *source) +{ + wl_event_source_remove(static_cast(source->data)); +} + +void +Loop::Terminate() +{ + zn_terminate(EXIT_FAILURE); +} + +} // namespace zen::xr diff --git a/zen-xr/src/loop.h b/zen-xr/src/loop.h new file mode 100644 index 00000000..a16439fa --- /dev/null +++ b/zen-xr/src/loop.h @@ -0,0 +1,22 @@ +#pragma once + +#include "common.h" + +namespace zen::xr { + +class Loop : public zen::remote::ILoop +{ + public: + DISABLE_MOVE_AND_COPY(Loop); + explicit Loop(wl_event_loop *wl_loop); + ~Loop() override = default; + + void AddFd(zen::remote::FdSource *source) override; + void RemoveFd(zen::remote::FdSource *source) override; + void Terminate() override; + + private: + wl_event_loop *wl_loop_; // @nonnull, @outlive +}; + +} // namespace zen::xr diff --git a/zen-xr/src/remote-system.cc b/zen-xr/src/remote-system.cc new file mode 100644 index 00000000..a2707375 --- /dev/null +++ b/zen-xr/src/remote-system.cc @@ -0,0 +1,21 @@ +#include "remote-system.h" + +namespace zen::xr { + +RemoteSystem::RemoteSystem(uint64_t handle, uint64_t peer_id) + : handle_(handle), peer_id_(peer_id) +{} + +uint64_t +RemoteSystem::handle() +{ + return handle_; +} + +System::Type +RemoteSystem::type() +{ + return kRemote; +} + +} // namespace zen::xr diff --git a/zen-xr/src/remote-system.h b/zen-xr/src/remote-system.h new file mode 100644 index 00000000..c3d52326 --- /dev/null +++ b/zen-xr/src/remote-system.h @@ -0,0 +1,28 @@ +#include "xr.h" +#include "zen-xr/system.h" + +namespace zen::xr { + +class RemoteSystem : public System +{ + public: + DISABLE_MOVE_AND_COPY(RemoteSystem); + explicit RemoteSystem(uint64_t handle, uint64_t peer_id); + ~RemoteSystem() override = default; + + uint64_t handle() override; + Type type() override; + [[nodiscard]] inline uint64_t peer_id() const; + + private: + const uint64_t handle_; + const uint64_t peer_id_; +}; + +inline uint64_t +RemoteSystem::peer_id() const +{ + return peer_id_; +} + +} // namespace zen::xr diff --git a/zen-xr/src/xr.cc b/zen-xr/src/xr.cc new file mode 100644 index 00000000..8b927611 --- /dev/null +++ b/zen-xr/src/xr.cc @@ -0,0 +1,111 @@ +#include "xr.h" + +#include "loop.h" +#include "remote-system.h" +#include "zen-common/log.h" + +namespace zen::xr { + +std::unique_ptr +CreateXr(wl_display *display, XrDelegate *delegate) +{ + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + auto *xr = new XrImpl(display, delegate); + + if (!xr->Init()) { + delete xr; // NOLINT(cppcoreguidelines-owning-memory) + return nullptr; + } + + return std::unique_ptr(xr); +} + +XrImpl::XrImpl(wl_display *display, XrDelegate *delegate) + : display_(display), delegate_(delegate) +{} + +XrImpl::~XrImpl() = default; + +bool +XrImpl::Init() +{ + wl_event_loop *wl_loop = wl_display_get_event_loop(display_); + + auto loop = std::make_unique(wl_loop); + + peer_manager_ = zen::remote::server::CreatePeerManager(std::move(loop)); + if (!peer_manager_) { + zn_error("Failed to create a peer manager"); + return false; + } + + peer_manager_->on_peer_discover.Connect( + [this](uint64_t id) { HandleRemotePeerDiscover(id); }); + + peer_manager_->on_peer_lost.Connect( + [this](uint64_t id) { HandleRemotePeerLost(id); }); + + return true; +} + +uint64_t +XrImpl::NextHandle() +{ + return ++next_handle_; +} + +void +XrImpl::RemoveSystemIf(std::function &)> pred) +{ + auto result = + std::remove_if(systems_.begin(), systems_.end(), std::move(pred)); + + std::vector> systems_to_remove( + std::make_move_iterator(result), std::make_move_iterator(systems_.end())); + + systems_.erase(result, systems_.end()); + + if (delegate_ != nullptr) { + for (auto &system : systems_to_remove) { + delegate_->NotifySystemRemoved(system); + } + } +} + +void +XrImpl::HandleRemotePeerDiscover(uint64_t id) +{ + RemoveSystemIf([id](std::unique_ptr &system) { + if (system->type() != System::kRemote) { + return false; + } + + auto *remote_system = dynamic_cast(system.get()); + + return remote_system != nullptr && remote_system->peer_id() == id; + }); + + auto handle = NextHandle(); + auto system = std::unique_ptr(new RemoteSystem(handle, id)); + systems_.emplace_back(std::move(system)); + + if (delegate_ != nullptr) { + delegate_->NotifySystemAdded(handle); + } +} + +void +XrImpl::HandleRemotePeerLost(uint64_t id) +{ + RemoveSystemIf([id](std::unique_ptr &system) { + if (system->type() != System::kRemote) { + return false; + } + + auto *remote_system = dynamic_cast(system.get()); + + return remote_system != nullptr && remote_system->peer_id() == id; + }); +} + +} // namespace zen::xr diff --git a/zen-xr/src/xr.h b/zen-xr/src/xr.h new file mode 100644 index 00000000..385fd3e9 --- /dev/null +++ b/zen-xr/src/xr.h @@ -0,0 +1,44 @@ +#pragma once + +#include "common.h" +#include "zen-xr/xr.h" + +namespace zen::xr { + +struct System; + +class XrImpl : public Xr +{ + public: + DISABLE_MOVE_AND_COPY(XrImpl); + ~XrImpl() override; + + private: + friend std::unique_ptr CreateXr( + wl_display *display, XrDelegate *delegate); + + XrImpl(wl_display *display, XrDelegate *delegate); + + void RemoveSystemIf(std::function &)> pred); + + void HandleRemotePeerDiscover(uint64_t id); + + void HandleRemotePeerLost(uint64_t id); + + bool Init(); + + /// @return value must not be 0 + uint64_t NextHandle(); + + std::vector> systems_; + + std::unique_ptr peer_manager_; // @nonnull + + wl_display *display_; // @nonnull, @outlive + + XrDelegate *delegate_; // @nullable, @outlive if exists + + uint64_t next_handle_ = 0; +}; + +} // namespace zen::xr diff --git a/zen/include/zen/backend.h b/zen/include/zen/backend.h index 8fc6031e..ff02abcf 100644 --- a/zen/include/zen/backend.h +++ b/zen/include/zen/backend.h @@ -23,9 +23,10 @@ struct zn_backend { const struct zn_backend_interface *impl; struct { - struct wl_signal new_screen; // (struct zn_screen *) - struct wl_signal view_mapped; // (struct zn_view *) - struct wl_signal destroy; // (NULL) + struct wl_signal new_screen; // (struct zn_screen *) + struct wl_signal view_mapped; // (struct zn_view *) + struct wl_signal destroy; // (NULL) + struct wl_signal new_xr_system; // (struct zn_xr_system *) } events; }; diff --git a/zen/include/zen/xr-system.h b/zen/include/zen/xr-system.h new file mode 100644 index 00000000..1fffb296 --- /dev/null +++ b/zen/include/zen/xr-system.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_xr_system { + void *impl_data; + + uint64_t handle; + + struct { + struct wl_signal destroy; + } events; +}; + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/backend/default-backend.c b/zen/src/backend/default-backend.c index a6caf3ef..8b8c97e4 100644 --- a/zen/src/backend/default-backend.c +++ b/zen/src/backend/default-backend.c @@ -7,6 +7,7 @@ #include #include +#include "immersive/xr.h" #include "screen/compositor.h" #include "screen/keyboard.h" #include "screen/output.h" @@ -17,6 +18,7 @@ #include "zen-common/util.h" #include "zen/server.h" #include "zen/wlr/render/glew.h" +#include "zen/xr-system.h" static void zn_default_backend_destroy(struct zn_default_backend *self); @@ -130,6 +132,17 @@ zn_default_backend_handle_new_output(struct wl_listener *listener, void *data) wl_signal_emit(&self->base.events.new_screen, output->screen); } +static void +zn_default_backend_handle_new_xr_system( + struct wl_listener *listener, void *data) +{ + struct zn_default_backend *self = + zn_container_of(listener, self, new_xr_system_listener); + struct zn_xr_system *xr_system = data; + + wl_signal_emit(&self->base.events.new_xr_system, xr_system); +} + static struct wlr_texture * zn_default_backend_create_wlr_texture_from_pixels(struct zn_backend *base, uint32_t format, uint32_t stride, uint32_t width, uint32_t height, @@ -186,6 +199,7 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) wl_signal_init(&self->base.events.new_screen); wl_signal_init(&self->base.events.view_mapped); wl_signal_init(&self->base.events.destroy); + wl_signal_init(&self->base.events.new_xr_system); self->base.impl = &implementation; self->display = display; wl_list_init(&self->input_device_list); @@ -226,6 +240,12 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) goto err_wlr_allocator; } + self->xr = zn_xr_create(display); + if (self->xr == NULL) { + zn_error("Failed to create a xr instance"); + goto err_compositor; + } + wlr_xwayland_set_seat(self->compositor->xwayland, zn_seat->wlr_seat); self->new_output_listener.notify = zn_default_backend_handle_new_output; @@ -236,8 +256,14 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) wl_signal_add( &self->wlr_backend->events.new_input, &self->new_input_listener); + self->new_xr_system_listener.notify = zn_default_backend_handle_new_xr_system; + wl_signal_add(&self->xr->events.new_system, &self->new_xr_system_listener); + return &self->base; +err_compositor: + zn_compositor_destroy(self->compositor); + err_wlr_allocator: wlr_allocator_destroy(self->wlr_allocator); @@ -259,8 +285,10 @@ zn_default_backend_destroy(struct zn_default_backend *self) { zn_signal_emit_mutable(&self->base.events.destroy, NULL); + wl_list_remove(&self->new_xr_system_listener.link); wl_list_remove(&self->new_input_listener.link); wl_list_remove(&self->new_output_listener.link); + zn_xr_destroy(self->xr); zn_compositor_destroy(self->compositor); wlr_allocator_destroy(self->wlr_allocator); wlr_renderer_destroy(self->wlr_renderer); @@ -268,6 +296,7 @@ zn_default_backend_destroy(struct zn_default_backend *self) wlr_backend_destroy(self->wlr_backend); } wl_list_remove(&self->input_device_list); + wl_list_remove(&self->base.events.new_xr_system.listener_list); wl_list_remove(&self->base.events.destroy.listener_list); wl_list_remove(&self->base.events.view_mapped.listener_list); wl_list_remove(&self->base.events.new_screen.listener_list); diff --git a/zen/src/backend/default-backend.h b/zen/src/backend/default-backend.h index 8ed0b42c..403f0769 100644 --- a/zen/src/backend/default-backend.h +++ b/zen/src/backend/default-backend.h @@ -4,6 +4,7 @@ struct zn_compositor; struct zn_view; +struct zn_xr; struct zn_default_backend { struct zn_backend base; @@ -18,10 +19,13 @@ struct zn_default_backend { struct zn_compositor *compositor; // @nonnull, @owning + struct zn_xr *xr; // @nonnull, @owing + struct wl_list input_device_list; // zn_input_device_base::link struct wl_listener new_input_listener; struct wl_listener new_output_listener; + struct wl_listener new_xr_system_listener; }; struct zn_default_backend *zn_default_backend_get(struct zn_backend *base); diff --git a/zen/src/backend/immersive/common.h b/zen/src/backend/immersive/common.h new file mode 100644 index 00000000..8e4fc40b --- /dev/null +++ b/zen/src/backend/immersive/common.h @@ -0,0 +1,9 @@ +#pragma once + +// NOLINTBEGIN(bugprone-macro-parentheses) +#define DISABLE_MOVE_AND_COPY(Class) \ + Class(const Class &) = delete; \ + Class(Class &&) = delete; \ + Class &operator=(const Class &) = delete; \ + Class &operator=(Class &&) = delete +// NOLINTEND(bugprone-macro-parentheses) diff --git a/zen/src/backend/immersive/xr-private.h b/zen/src/backend/immersive/xr-private.h new file mode 100644 index 00000000..c18a5c24 --- /dev/null +++ b/zen/src/backend/immersive/xr-private.h @@ -0,0 +1,34 @@ +#pragma once + +#include "common.h" +#include "xr.h" + +namespace zen::xr::proxy { + +class XrSystemProxy; + +class XrProxy : public zen::xr::XrDelegate +{ + public: + DISABLE_MOVE_AND_COPY(XrProxy); + ~XrProxy() override; + + void NotifySystemAdded(uint64_t handle) override; + + void NotifySystemRemoved(std::unique_ptr &system) override; + + private: + friend zn_xr * ::zn_xr_create(struct wl_display *display); + + XrProxy(); + + bool Init(wl_display *display); + + std::unique_ptr xr_; + + zn_xr zn_xr_{}; + + std::vector> systems_; +}; + +} // namespace zen::xr::proxy diff --git a/zen/src/backend/immersive/xr-system-private.h b/zen/src/backend/immersive/xr-system-private.h new file mode 100644 index 00000000..e0a9bf3c --- /dev/null +++ b/zen/src/backend/immersive/xr-system-private.h @@ -0,0 +1,36 @@ +#pragma once + +#include "common.h" +#include "zen/xr-system.h" + +namespace zen::xr::proxy { + +class XrSystemProxy +{ + public: + DISABLE_MOVE_AND_COPY(XrSystemProxy); + explicit XrSystemProxy(uint64_t handle); + ~XrSystemProxy(); + + bool Init(); + + inline uint64_t handle() const; + inline zn_xr_system *zn_xr_system(); + + private: + struct zn_xr_system zn_xr_system_ {}; +}; + +inline uint64_t +XrSystemProxy::handle() const +{ + return zn_xr_system_.handle; +} + +inline zn_xr_system * +XrSystemProxy::zn_xr_system() +{ + return &zn_xr_system_; +} + +} // namespace zen::xr::proxy diff --git a/zen/src/backend/immersive/xr-system.cc b/zen/src/backend/immersive/xr-system.cc new file mode 100644 index 00000000..13939339 --- /dev/null +++ b/zen/src/backend/immersive/xr-system.cc @@ -0,0 +1,23 @@ +#include "xr-system-private.h" + +namespace zen::xr::proxy { + +XrSystemProxy::XrSystemProxy(uint64_t handle) { zn_xr_system_.handle = handle; } + +bool +XrSystemProxy::Init() +{ + zn_xr_system_.impl_data = this; + + wl_signal_init(&zn_xr_system_.events.destroy); + + return true; +} + +XrSystemProxy::~XrSystemProxy() +{ + wl_signal_emit(&zn_xr_system_.events.destroy, nullptr); + wl_list_remove(&zn_xr_system_.events.destroy.listener_list); +} + +} // namespace zen::xr::proxy diff --git a/zen/src/backend/immersive/xr.cc b/zen/src/backend/immersive/xr.cc new file mode 100644 index 00000000..424a6cc1 --- /dev/null +++ b/zen/src/backend/immersive/xr.cc @@ -0,0 +1,69 @@ +#include "xr-private.h" +#include "xr-system-private.h" +#include "zen-common/log.h" + +namespace zen::xr::proxy { + +XrProxy::XrProxy() = default; + +bool +XrProxy::Init(wl_display *display) +{ + zn_xr_.impl_data = this; + wl_signal_init(&zn_xr_.events.new_system); + xr_ = zen::xr::CreateXr(display, this); + return true; +} + +XrProxy::~XrProxy() { wl_list_remove(&zn_xr_.events.new_system.listener_list); } + +void +XrProxy::NotifySystemAdded(uint64_t handle) +{ + auto system = std::make_unique(handle); + if (!system->Init()) { + zn_warn("Failed to init XrSystemProxy"); + return; + } + auto *zn_xr_system = system->zn_xr_system(); + systems_.push_back(std::move(system)); + + wl_signal_emit(&zn_xr_.events.new_system, zn_xr_system); +} + +void +XrProxy::NotifySystemRemoved(std::unique_ptr &system) +{ + auto result = std::remove_if(systems_.begin(), systems_.end(), + [handle = system->handle()]( + std::unique_ptr &system_proxy) { + return system_proxy->handle() == handle; + }); + + systems_.erase(result, systems_.end()); +} + +} // namespace zen::xr::proxy + +zn_xr * +zn_xr_create(struct wl_display *display) +{ + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + auto *proxy = new zen::xr::proxy::XrProxy; + + if (!proxy->Init(display)) { + zn_error("Failed to initialize XrProxy"); + delete proxy; // NOLINT(cppcoreguidelines-owning-memory) + return nullptr; + } + + return &proxy->zn_xr_; +} + +void +zn_xr_destroy(zn_xr *self) +{ + auto *proxy = static_cast(self->impl_data); + + delete proxy; // NOLINT(cppcoreguidelines-owning-memory) +} diff --git a/zen/src/backend/immersive/xr.h b/zen/src/backend/immersive/xr.h new file mode 100644 index 00000000..e1419d13 --- /dev/null +++ b/zen/src/backend/immersive/xr.h @@ -0,0 +1,21 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_xr { + void *impl_data; // used by the impl object + + struct { + struct wl_signal new_system; // (struct zn_xr_system *) + } events; +}; + +struct zn_xr *zn_xr_create(struct wl_display *display); + +void zn_xr_destroy(struct zn_xr *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 96f591c3..bcce219c 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -1,6 +1,9 @@ _zen_backend_srcs = [ 'default-backend.c', + 'immersive/xr.cc', + 'immersive/xr-system.cc', + 'screen/compositor.c', 'screen/keyboard.c', 'screen/layer-shell.c', @@ -15,8 +18,10 @@ _zen_backend_lib = static_library( 'zen-backend', _zen_backend_srcs, install: false, + cpp_args: [ '-include', 'pch/pch.h' ], include_directories: zen_private_inc, - dependencies: _zen_deps, + dependencies: [ _zen_deps, zen_xr_dep ], + cpp_pch: 'pch/pch.h', ) zen_backend_dep = declare_dependency( diff --git a/zen/src/backend/pch/pch.h b/zen/src/backend/pch/pch.h new file mode 100644 index 00000000..7e3adab4 --- /dev/null +++ b/zen/src/backend/pch/pch.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include From 68b737512e06dc5edeff5a098946f3ec08da1f1d Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 1 Apr 2023 20:05:28 +0900 Subject: [PATCH 05/49] refactor immersive backend --- .../include/zen-common/cpp-util.h | 4 + common/include/zen-common/util.h | 16 +-- desktop/include/zen-desktop/shell.h | 1 + desktop/include/zen-desktop/xr-system.h | 18 +++ desktop/meson.build | 4 + desktop/src/shell.c | 17 +++ desktop/src/xr-system.c | 97 +++++++++++++++ meson.build | 3 +- protocol/meson.build | 16 ++- zen-xr/include/zen-xr/system.h | 19 --- zen-xr/include/zen-xr/xr.h | 27 ----- zen-xr/meson.build | 31 ----- zen-xr/src/common.h | 9 -- zen-xr/src/remote-system.cc | 21 ---- zen-xr/src/remote-system.h | 28 ----- zen-xr/src/xr.cc | 111 ------------------ zen-xr/src/xr.h | 44 ------- zen/include/zen/xr-system.h | 4 - zen/src/backend/default-backend.c | 4 +- .../src/backend/immersive/remote}/loop.cc | 4 +- .../src/backend/immersive/remote}/loop.h | 6 +- zen/src/backend/immersive/remote/meson.build | 24 ++++ .../src/backend/immersive/remote}/pch/pch.h | 0 .../immersive/remote/xr-system-manager.cc | 107 +++++++++++++++++ .../immersive/remote/xr-system-manager.h | 41 +++++++ zen/src/backend/immersive/remote/xr-system.cc | 36 ++++++ zen/src/backend/immersive/remote/xr-system.h | 42 +++++++ zen/src/backend/immersive/xr-private.h | 34 ------ zen/src/backend/immersive/xr-system-manager.h | 35 ++++++ zen/src/backend/immersive/xr-system-private.h | 36 ------ zen/src/backend/immersive/xr-system.cc | 23 ---- zen/src/backend/immersive/xr.c | 36 ++++++ zen/src/backend/immersive/xr.cc | 69 ----------- zen/src/backend/immersive/xr.h | 16 +-- zen/src/backend/meson.build | 14 ++- zen/src/backend/pch/pch.h | 9 -- 36 files changed, 496 insertions(+), 510 deletions(-) rename zen/src/backend/immersive/common.h => common/include/zen-common/cpp-util.h (91%) create mode 100644 desktop/include/zen-desktop/xr-system.h create mode 100644 desktop/src/xr-system.c delete mode 100644 zen-xr/include/zen-xr/system.h delete mode 100644 zen-xr/include/zen-xr/xr.h delete mode 100644 zen-xr/meson.build delete mode 100644 zen-xr/src/common.h delete mode 100644 zen-xr/src/remote-system.cc delete mode 100644 zen-xr/src/remote-system.h delete mode 100644 zen-xr/src/xr.cc delete mode 100644 zen-xr/src/xr.h rename {zen-xr/src => zen/src/backend/immersive/remote}/loop.cc (94%) rename {zen-xr/src => zen/src/backend/immersive/remote}/loop.h (74%) create mode 100644 zen/src/backend/immersive/remote/meson.build rename {zen-xr => zen/src/backend/immersive/remote}/pch/pch.h (100%) create mode 100644 zen/src/backend/immersive/remote/xr-system-manager.cc create mode 100644 zen/src/backend/immersive/remote/xr-system-manager.h create mode 100644 zen/src/backend/immersive/remote/xr-system.cc create mode 100644 zen/src/backend/immersive/remote/xr-system.h delete mode 100644 zen/src/backend/immersive/xr-private.h create mode 100644 zen/src/backend/immersive/xr-system-manager.h delete mode 100644 zen/src/backend/immersive/xr-system-private.h delete mode 100644 zen/src/backend/immersive/xr-system.cc create mode 100644 zen/src/backend/immersive/xr.c delete mode 100644 zen/src/backend/immersive/xr.cc delete mode 100644 zen/src/backend/pch/pch.h diff --git a/zen/src/backend/immersive/common.h b/common/include/zen-common/cpp-util.h similarity index 91% rename from zen/src/backend/immersive/common.h rename to common/include/zen-common/cpp-util.h index 8e4fc40b..0022ecb6 100644 --- a/zen/src/backend/immersive/common.h +++ b/common/include/zen-common/cpp-util.h @@ -1,5 +1,7 @@ #pragma once +#ifdef __cplusplus + // NOLINTBEGIN(bugprone-macro-parentheses) #define DISABLE_MOVE_AND_COPY(Class) \ Class(const Class &) = delete; \ @@ -7,3 +9,5 @@ Class &operator=(const Class &) = delete; \ Class &operator=(Class &&) = delete // NOLINTEND(bugprone-macro-parentheses) + +#endif diff --git a/common/include/zen-common/util.h b/common/include/zen-common/util.h index 8fa52bea..b9baab49 100644 --- a/common/include/zen-common/util.h +++ b/common/include/zen-common/util.h @@ -4,7 +4,7 @@ #include #ifdef __cplusplus -extern "C" { +#error "This header is not for C++" #endif /** Visibility attribute */ @@ -41,17 +41,3 @@ zalloc(size_t size) /** Retrieve a pointer to a containing struct */ #define zn_container_of(ptr, sample, member) \ (__typeof__(sample))((char *)(ptr)-offsetof(__typeof__(*(sample)), member)) - -#ifdef __cplusplus - -#define DISABLE_MOVE_AND_COPY(Class) \ - Class(const Class &) = delete; \ - Class(Class &&) = delete; \ - Class &operator=(const Class &) = delete; \ - Class &operator=(Class &&) = delete - -#endif - -#ifdef __cplusplus -} -#endif diff --git a/desktop/include/zen-desktop/shell.h b/desktop/include/zen-desktop/shell.h index 50f45fd9..cfd2fc5b 100644 --- a/desktop/include/zen-desktop/shell.h +++ b/desktop/include/zen-desktop/shell.h @@ -12,6 +12,7 @@ struct zn_desktop_shell { struct zn_theme *theme; // @nonnull, @owning + struct wl_listener new_xr_system_listener; struct wl_listener new_screen_listener; struct wl_listener seat_capabilities_listener; struct wl_listener pointer_motion_listener; diff --git a/desktop/include/zen-desktop/xr-system.h b/desktop/include/zen-desktop/xr-system.h new file mode 100644 index 00000000..01a2e737 --- /dev/null +++ b/desktop/include/zen-desktop/xr-system.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +struct zn_xr_system; +struct zn_desktop_server_xr_system; + +struct zn_desktop_xr_system { + struct zn_xr_system *zn_xr_system; // @nonnull, @outlive + + struct wl_global *global; // @nonnull, @owning + struct wl_list resource_list; // wl_resource::link of zen_xr_system + + struct wl_listener zn_xr_system_destroy_listener; +}; + +struct zn_desktop_xr_system *zn_desktop_xr_system_create( + struct zn_xr_system *zn_xr_system, struct wl_display *display); diff --git a/desktop/meson.build b/desktop/meson.build index 86c5bfdf..0a1de69c 100644 --- a/desktop/meson.build +++ b/desktop/meson.build @@ -20,6 +20,10 @@ _zen_desktop_srcs = [ 'src/ui/decoration/shadow.c', 'src/view.c', + 'src/xr-system.c', + + protocols_code['zen-desktop'], + protocols_server_header['zen-desktop'], ] _zen_desktop_inc = include_directories('include') diff --git a/desktop/src/shell.c b/desktop/src/shell.c index b4b788ae..e0ca9319 100644 --- a/desktop/src/shell.c +++ b/desktop/src/shell.c @@ -10,6 +10,7 @@ #include "zen-desktop/screen.h" #include "zen-desktop/theme.h" #include "zen-desktop/view.h" +#include "zen-desktop/xr-system.h" #include "zen/backend.h" #include "zen/screen.h" #include "zen/seat.h" @@ -20,6 +21,17 @@ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static struct zn_desktop_shell *desktop_shell_singleton = NULL; +static void +zn_desktop_shell_handle_new_xr_system( + struct wl_listener *listener UNUSED, void *data) +{ + struct zn_server *server = zn_server_get_singleton(); + + struct zn_xr_system *zn_xr_system = data; + + zn_desktop_xr_system_create(zn_xr_system, server->display); +} + static void zn_desktop_shell_handle_new_screen(struct wl_listener *listener, void *data) { @@ -174,6 +186,10 @@ zn_desktop_shell_create(void) } self->cursor_grab = &cursor_default_grab->base; + self->new_xr_system_listener.notify = zn_desktop_shell_handle_new_xr_system; + wl_signal_add( + &server->backend->events.new_xr_system, &self->new_xr_system_listener); + self->new_screen_listener.notify = zn_desktop_shell_handle_new_screen; wl_signal_add( &server->backend->events.new_screen, &self->new_screen_listener); @@ -229,6 +245,7 @@ zn_desktop_shell_destroy(struct zn_desktop_shell *self) wl_list_remove(&self->pointer_motion_listener.link); wl_list_remove(&self->seat_capabilities_listener.link); wl_list_remove(&self->new_screen_listener.link); + wl_list_remove(&self->new_xr_system_listener.link); zn_cursor_grab_destroy(self->cursor_grab); zn_screen_layout_destroy(self->screen_layout); zn_theme_destroy(self->theme); diff --git a/desktop/src/xr-system.c b/desktop/src/xr-system.c new file mode 100644 index 00000000..6e5c4c58 --- /dev/null +++ b/desktop/src/xr-system.c @@ -0,0 +1,97 @@ +#include "zen-desktop/xr-system.h" + +#include + +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/xr-system.h" + +static void zn_desktop_xr_system_destroy(struct zn_desktop_xr_system *self); + +static void +zn_desktop_xr_system_handle_destroy(struct wl_resource *resource) +{ + wl_list_remove(wl_resource_get_link(resource)); +} + +static void +zn_desktop_xr_system_protocol_connect( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED) +{} + +static const struct zen_xr_system_interface implementation = { + .connect = zn_desktop_xr_system_protocol_connect, +}; + +static void +zn_desktop_xr_system_bind( + struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + struct zn_desktop_xr_system *self = data; + + struct wl_resource *resource = + wl_resource_create(client, &zen_xr_system_interface, (int)version, id); + if (resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation( + resource, &implementation, self, zn_desktop_xr_system_handle_destroy); + + wl_list_insert(&self->resource_list, wl_resource_get_link(resource)); +} + +static void +zn_desktop_xr_system_handle_xr_system_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_desktop_xr_system *self = + zn_container_of(listener, self, zn_xr_system_destroy_listener); + + zn_desktop_xr_system_destroy(self); +} + +struct zn_desktop_xr_system * +zn_desktop_xr_system_create( + struct zn_xr_system *zn_xr_system, struct wl_display *display) +{ + struct zn_desktop_xr_system *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->zn_xr_system = zn_xr_system; + wl_list_init(&self->resource_list); + + self->global = wl_global_create( + display, &zen_xr_system_interface, 1, self, zn_desktop_xr_system_bind); + if (self->global == NULL) { + zn_error("Failed to create a wl_global"); + goto err_free; + } + + self->zn_xr_system_destroy_listener.notify = + zn_desktop_xr_system_handle_xr_system_destroy; + wl_signal_add( + &zn_xr_system->events.destroy, &self->zn_xr_system_destroy_listener); + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_desktop_xr_system_destroy(struct zn_desktop_xr_system *self) +{ + wl_list_remove(&self->zn_xr_system_destroy_listener.link); + wl_global_destroy(self->global); + wl_list_remove(&self->resource_list); + free(self); +} diff --git a/meson.build b/meson.build index 8ea57092..8effedc9 100644 --- a/meson.build +++ b/meson.build @@ -120,6 +120,7 @@ configure_file( wayland_req = '>= 1.18.0' wayland_protocols_req = '>= 1.24' wlroots_req = ['>= 0.15', '< 0.16'] +zen_protocols_req = '0.1.0' zen_remote_server_req = '0.1.1' @@ -143,6 +144,7 @@ wayland_protocols_dep = dependency('wayland-protocols', version: wayland_protoco wayland_scanner_dep = dependency('wayland-scanner', native: true) wayland_server_dep = dependency('wayland-server', version: wayland_req) xkbcommon_dep = dependency('xkbcommon') +zen_protocols_dep = dependency('zen-protocols', version: zen_protocols_req) zen_remote_server_dep = dependency('zen-remote-server', version: zen_remote_server_req) subdir('protocol') @@ -163,7 +165,6 @@ if get_option('tests') subdir('test-harness') endif subdir('common') -subdir('zen-xr') subdir('zen-wlr-glew-renderer') subdir('zen') subdir('desktop') diff --git a/protocol/meson.build b/protocol/meson.build index f2856347..c919f8b2 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,4 +1,5 @@ wl_protocol_dir = wayland_protocols_dep.get_variable('pkgdatadir') +zen_protocol_dir = zen_protocols_dep.get_variable('pkgdatadir') wayland_scanner = find_program( wayland_scanner_dep.get_variable('wayland_scanner'), @@ -8,11 +9,11 @@ wayland_scanner = find_program( protocols = { 'xdg-shell': wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', + 'zen-desktop': zen_protocol_dir / 'unstable/zen-desktop.xml', + 'wlr-layer-shell-unstable-v1': 'wlr-layer-shell-unstable-v1.xml', } -wlroots_srcs = [] - protocols_code = {} protocols_server_header = {} protocols_client_header = {} @@ -24,8 +25,6 @@ foreach name, path : protocols command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], ) - wlroots_srcs += code - server_header = custom_target( name.underscorify() + '_server_h', input: path, @@ -33,8 +32,6 @@ foreach name, path : protocols command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'], ) - wlroots_srcs += server_header - client_header = custom_target( name.underscorify() + '_client_h', input: path, @@ -47,3 +44,10 @@ foreach name, path : protocols protocols_server_header += { name: server_header } protocols_client_header += { name: client_header } endforeach + +wlroots_srcs = [ + protocols_code['wlr-layer-shell-unstable-v1'], + protocols_code['xdg-shell'], + protocols_server_header['wlr-layer-shell-unstable-v1'], + protocols_server_header['xdg-shell'], +] diff --git a/zen-xr/include/zen-xr/system.h b/zen-xr/include/zen-xr/system.h deleted file mode 100644 index 2798285b..00000000 --- a/zen-xr/include/zen-xr/system.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -namespace zen::xr { - -struct System { - enum Type { - kNone, - kRemote, - }; - - virtual ~System() = default; - - virtual uint64_t handle() = 0; - virtual Type type() = 0; -}; - -} // namespace zen::xr diff --git a/zen-xr/include/zen-xr/xr.h b/zen-xr/include/zen-xr/xr.h deleted file mode 100644 index 5bc9d04b..00000000 --- a/zen-xr/include/zen-xr/xr.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -#include - -namespace zen::xr { - -struct System; - -struct Xr { - virtual ~Xr() = default; -}; - -struct XrDelegate { - virtual ~XrDelegate() = default; - - virtual void NotifySystemAdded(uint64_t handle) = 0; - - virtual void NotifySystemRemoved(std::unique_ptr &system) = 0; -}; - -/// @returns nullptr if failed -/// @param delegate can be NULL -std::unique_ptr CreateXr(wl_display *display, XrDelegate *delegate); - -} // namespace zen::xr diff --git a/zen-xr/meson.build b/zen-xr/meson.build deleted file mode 100644 index 65a86479..00000000 --- a/zen-xr/meson.build +++ /dev/null @@ -1,31 +0,0 @@ -_zen_xr_srcs = [ - 'src/loop.cc', - 'src/remote-system.cc', - 'src/xr.cc', -] - -_zen_xr_public_deps = [ -] - -_zen_xr_deps = [ - wayland_server_dep, - zen_common_dep, - zen_remote_server_dep, -] + _zen_xr_public_deps - -_zen_xr_inc = include_directories('include') - -_zen_xr_lib = static_library( - 'zen-xr', - _zen_xr_srcs, - install: false, - cpp_args: ['-include', 'pch/pch.h'], - include_directories: _zen_xr_inc, - dependencies: _zen_xr_deps, - cpp_pch: 'pch/pch.h', -) - -zen_xr_dep = declare_dependency( - link_with: _zen_xr_lib, - include_directories: _zen_xr_inc, -) diff --git a/zen-xr/src/common.h b/zen-xr/src/common.h deleted file mode 100644 index 8e4fc40b..00000000 --- a/zen-xr/src/common.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -// NOLINTBEGIN(bugprone-macro-parentheses) -#define DISABLE_MOVE_AND_COPY(Class) \ - Class(const Class &) = delete; \ - Class(Class &&) = delete; \ - Class &operator=(const Class &) = delete; \ - Class &operator=(Class &&) = delete -// NOLINTEND(bugprone-macro-parentheses) diff --git a/zen-xr/src/remote-system.cc b/zen-xr/src/remote-system.cc deleted file mode 100644 index a2707375..00000000 --- a/zen-xr/src/remote-system.cc +++ /dev/null @@ -1,21 +0,0 @@ -#include "remote-system.h" - -namespace zen::xr { - -RemoteSystem::RemoteSystem(uint64_t handle, uint64_t peer_id) - : handle_(handle), peer_id_(peer_id) -{} - -uint64_t -RemoteSystem::handle() -{ - return handle_; -} - -System::Type -RemoteSystem::type() -{ - return kRemote; -} - -} // namespace zen::xr diff --git a/zen-xr/src/remote-system.h b/zen-xr/src/remote-system.h deleted file mode 100644 index c3d52326..00000000 --- a/zen-xr/src/remote-system.h +++ /dev/null @@ -1,28 +0,0 @@ -#include "xr.h" -#include "zen-xr/system.h" - -namespace zen::xr { - -class RemoteSystem : public System -{ - public: - DISABLE_MOVE_AND_COPY(RemoteSystem); - explicit RemoteSystem(uint64_t handle, uint64_t peer_id); - ~RemoteSystem() override = default; - - uint64_t handle() override; - Type type() override; - [[nodiscard]] inline uint64_t peer_id() const; - - private: - const uint64_t handle_; - const uint64_t peer_id_; -}; - -inline uint64_t -RemoteSystem::peer_id() const -{ - return peer_id_; -} - -} // namespace zen::xr diff --git a/zen-xr/src/xr.cc b/zen-xr/src/xr.cc deleted file mode 100644 index 8b927611..00000000 --- a/zen-xr/src/xr.cc +++ /dev/null @@ -1,111 +0,0 @@ -#include "xr.h" - -#include "loop.h" -#include "remote-system.h" -#include "zen-common/log.h" - -namespace zen::xr { - -std::unique_ptr -CreateXr(wl_display *display, XrDelegate *delegate) -{ - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - auto *xr = new XrImpl(display, delegate); - - if (!xr->Init()) { - delete xr; // NOLINT(cppcoreguidelines-owning-memory) - return nullptr; - } - - return std::unique_ptr(xr); -} - -XrImpl::XrImpl(wl_display *display, XrDelegate *delegate) - : display_(display), delegate_(delegate) -{} - -XrImpl::~XrImpl() = default; - -bool -XrImpl::Init() -{ - wl_event_loop *wl_loop = wl_display_get_event_loop(display_); - - auto loop = std::make_unique(wl_loop); - - peer_manager_ = zen::remote::server::CreatePeerManager(std::move(loop)); - if (!peer_manager_) { - zn_error("Failed to create a peer manager"); - return false; - } - - peer_manager_->on_peer_discover.Connect( - [this](uint64_t id) { HandleRemotePeerDiscover(id); }); - - peer_manager_->on_peer_lost.Connect( - [this](uint64_t id) { HandleRemotePeerLost(id); }); - - return true; -} - -uint64_t -XrImpl::NextHandle() -{ - return ++next_handle_; -} - -void -XrImpl::RemoveSystemIf(std::function &)> pred) -{ - auto result = - std::remove_if(systems_.begin(), systems_.end(), std::move(pred)); - - std::vector> systems_to_remove( - std::make_move_iterator(result), std::make_move_iterator(systems_.end())); - - systems_.erase(result, systems_.end()); - - if (delegate_ != nullptr) { - for (auto &system : systems_to_remove) { - delegate_->NotifySystemRemoved(system); - } - } -} - -void -XrImpl::HandleRemotePeerDiscover(uint64_t id) -{ - RemoveSystemIf([id](std::unique_ptr &system) { - if (system->type() != System::kRemote) { - return false; - } - - auto *remote_system = dynamic_cast(system.get()); - - return remote_system != nullptr && remote_system->peer_id() == id; - }); - - auto handle = NextHandle(); - auto system = std::unique_ptr(new RemoteSystem(handle, id)); - systems_.emplace_back(std::move(system)); - - if (delegate_ != nullptr) { - delegate_->NotifySystemAdded(handle); - } -} - -void -XrImpl::HandleRemotePeerLost(uint64_t id) -{ - RemoveSystemIf([id](std::unique_ptr &system) { - if (system->type() != System::kRemote) { - return false; - } - - auto *remote_system = dynamic_cast(system.get()); - - return remote_system != nullptr && remote_system->peer_id() == id; - }); -} - -} // namespace zen::xr diff --git a/zen-xr/src/xr.h b/zen-xr/src/xr.h deleted file mode 100644 index 385fd3e9..00000000 --- a/zen-xr/src/xr.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "common.h" -#include "zen-xr/xr.h" - -namespace zen::xr { - -struct System; - -class XrImpl : public Xr -{ - public: - DISABLE_MOVE_AND_COPY(XrImpl); - ~XrImpl() override; - - private: - friend std::unique_ptr CreateXr( - wl_display *display, XrDelegate *delegate); - - XrImpl(wl_display *display, XrDelegate *delegate); - - void RemoveSystemIf(std::function &)> pred); - - void HandleRemotePeerDiscover(uint64_t id); - - void HandleRemotePeerLost(uint64_t id); - - bool Init(); - - /// @return value must not be 0 - uint64_t NextHandle(); - - std::vector> systems_; - - std::unique_ptr peer_manager_; // @nonnull - - wl_display *display_; // @nonnull, @outlive - - XrDelegate *delegate_; // @nullable, @outlive if exists - - uint64_t next_handle_ = 0; -}; - -} // namespace zen::xr diff --git a/zen/include/zen/xr-system.h b/zen/include/zen/xr-system.h index 1fffb296..1545db50 100644 --- a/zen/include/zen/xr-system.h +++ b/zen/include/zen/xr-system.h @@ -7,10 +7,6 @@ extern "C" { #endif struct zn_xr_system { - void *impl_data; - - uint64_t handle; - struct { struct wl_signal destroy; } events; diff --git a/zen/src/backend/default-backend.c b/zen/src/backend/default-backend.c index 8b8c97e4..1191cfef 100644 --- a/zen/src/backend/default-backend.c +++ b/zen/src/backend/default-backend.c @@ -7,6 +7,7 @@ #include #include +#include "immersive/xr-system-manager.h" #include "immersive/xr.h" #include "screen/compositor.h" #include "screen/keyboard.h" @@ -257,7 +258,8 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) &self->wlr_backend->events.new_input, &self->new_input_listener); self->new_xr_system_listener.notify = zn_default_backend_handle_new_xr_system; - wl_signal_add(&self->xr->events.new_system, &self->new_xr_system_listener); + wl_signal_add(&self->xr->xr_system_manager->events.new_system, + &self->new_xr_system_listener); return &self->base; diff --git a/zen-xr/src/loop.cc b/zen/src/backend/immersive/remote/loop.cc similarity index 94% rename from zen-xr/src/loop.cc rename to zen/src/backend/immersive/remote/loop.cc index 155e465d..bc53c588 100644 --- a/zen-xr/src/loop.cc +++ b/zen/src/backend/immersive/remote/loop.cc @@ -2,7 +2,7 @@ #include "zen-common/terminate.h" -namespace zen::xr { +namespace zen::backend::immersive::remote { namespace { @@ -74,4 +74,4 @@ Loop::Terminate() zn_terminate(EXIT_FAILURE); } -} // namespace zen::xr +} // namespace zen::backend::immersive::remote diff --git a/zen-xr/src/loop.h b/zen/src/backend/immersive/remote/loop.h similarity index 74% rename from zen-xr/src/loop.h rename to zen/src/backend/immersive/remote/loop.h index a16439fa..481ba302 100644 --- a/zen-xr/src/loop.h +++ b/zen/src/backend/immersive/remote/loop.h @@ -1,8 +1,8 @@ #pragma once -#include "common.h" +#include "zen-common/cpp-util.h" -namespace zen::xr { +namespace zen::backend::immersive::remote { class Loop : public zen::remote::ILoop { @@ -19,4 +19,4 @@ class Loop : public zen::remote::ILoop wl_event_loop *wl_loop_; // @nonnull, @outlive }; -} // namespace zen::xr +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build new file mode 100644 index 00000000..b15ea819 --- /dev/null +++ b/zen/src/backend/immersive/remote/meson.build @@ -0,0 +1,24 @@ +_zen_remote_immersive_backend_srcs = [ + 'loop.cc', + 'xr-system.cc', + 'xr-system-manager.cc', +] + +_zen_remote_immersive_backend_deps = [ + _zen_deps, + zen_remote_server_dep, +] + +_zen_remote_immersive_backend_lib = static_library( + 'zen-remote-immersive-backend', + _zen_remote_immersive_backend_srcs, + install: false, + cpp_args: [ '-include', 'pch/pch.h' ], + include_directories: zen_private_inc, + dependencies: _zen_remote_immersive_backend_deps, + cpp_pch: 'pch/pch.h', +) + +zen_remote_immersive_backend_dep = declare_dependency( + link_with: _zen_remote_immersive_backend_lib, +) diff --git a/zen-xr/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h similarity index 100% rename from zen-xr/pch/pch.h rename to zen/src/backend/immersive/remote/pch/pch.h diff --git a/zen/src/backend/immersive/remote/xr-system-manager.cc b/zen/src/backend/immersive/remote/xr-system-manager.cc new file mode 100644 index 00000000..8173284b --- /dev/null +++ b/zen/src/backend/immersive/remote/xr-system-manager.cc @@ -0,0 +1,107 @@ +#include "xr-system-manager.h" + +#include "loop.h" +#include "xr-system.h" +#include "zen-common/log.h" + +static void zn_xr_system_manager_destroy_remote( + struct zn_xr_system_manager *c_obj); + +namespace zen::backend::immersive::remote { + +XrSystemManager::XrSystemManager(wl_display *display) : display_(display) {} + +static const struct zn_xr_system_manager_interface implementation = { + XrSystemManager::HandleDestroy, +}; + +bool +XrSystemManager::Init() +{ + auto loop = std::make_unique(wl_display_get_event_loop(display_)); + + peer_manager_ = zen::remote::server::CreatePeerManager(std::move(loop)); + if (!peer_manager_) { + zn_error("Failed to create a peer manager"); + return false; + } + + c_obj_.impl_data = this; + c_obj_.impl = &implementation; + wl_signal_init(&c_obj_.events.new_system); + + peer_manager_->on_peer_discover.Connect( + [this](uint64_t id) { HandleRemotePeerDiscover(id); }); + + peer_manager_->on_peer_lost.Connect( + [this](uint64_t id) { HandleRemotePeerLost(id); }); + + return true; +} + +void +XrSystemManager::HandleDestroy(zn_xr_system_manager *c_obj) +{ + zn_xr_system_manager_destroy_remote(c_obj); +} + +void +XrSystemManager::RemoveXrSystem(uint64_t peer_id) +{ + auto result = std::remove_if(xr_systems_.begin(), xr_systems_.end(), + [peer_id](std::unique_ptr &xr_system) { + return xr_system->peer_id() == peer_id; + }); + + xr_systems_.erase(result, xr_systems_.end()); +} + +void +XrSystemManager::HandleRemotePeerDiscover(uint64_t peer_id) +{ + RemoveXrSystem(peer_id); + + auto xr_system = XrSystem::New(peer_id); + + auto *xr_system_c_obj = xr_system->c_obj(); + + xr_systems_.push_back(std::move(xr_system)); + + wl_signal_emit(&c_obj_.events.new_system, xr_system_c_obj); +} + +void +XrSystemManager::HandleRemotePeerLost(uint64_t peer_id) +{ + RemoveXrSystem(peer_id); +} + +} // namespace zen::backend::immersive::remote + +struct zn_xr_system_manager * +zn_xr_system_manager_create_remote(struct wl_display *display) +{ + using XrSystemManager = zen::backend::immersive::remote::XrSystemManager; + + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + auto *self = new XrSystemManager(display); + + if (!self->Init()) { + zn_error("Failed to initialize remote XrSystemManager"); + delete self; // NOLINT(cppcoreguidelines-owning-memory) + return nullptr; + } + + return &self->c_obj_; +} + +static void +zn_xr_system_manager_destroy_remote(struct zn_xr_system_manager *c_obj) +{ + using XrSystemManager = zen::backend::immersive::remote::XrSystemManager; + + auto *self = static_cast(c_obj->impl_data); + + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + delete self; +} diff --git a/zen/src/backend/immersive/remote/xr-system-manager.h b/zen/src/backend/immersive/remote/xr-system-manager.h new file mode 100644 index 00000000..eef3bfb3 --- /dev/null +++ b/zen/src/backend/immersive/remote/xr-system-manager.h @@ -0,0 +1,41 @@ +#pragma once + +#include "backend/immersive/xr-system-manager.h" +#include "zen-common/cpp-util.h" + +namespace zen::backend::immersive::remote { + +class XrSystem; + +class XrSystemManager +{ + public: + DISABLE_MOVE_AND_COPY(XrSystemManager); + ~XrSystemManager() = default; + + static void HandleDestroy(zn_xr_system_manager *c_obj); + + private: + friend struct zn_xr_system_manager * ::zn_xr_system_manager_create_remote( + struct wl_display *display); + + explicit XrSystemManager(wl_display *display); + + bool Init(); + + void RemoveXrSystem(uint64_t peer_id); + + void HandleRemotePeerDiscover(uint64_t peer_id); + + void HandleRemotePeerLost(uint64_t peer_id); + + zn_xr_system_manager c_obj_{}; + + wl_display *display_; // @nonnull, @outlive + + std::unique_ptr peer_manager_; // @nonnull + + std::vector> xr_systems_; +}; + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-system.cc b/zen/src/backend/immersive/remote/xr-system.cc new file mode 100644 index 00000000..5137d861 --- /dev/null +++ b/zen/src/backend/immersive/remote/xr-system.cc @@ -0,0 +1,36 @@ +#include "xr-system.h" + +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +XrSystem::XrSystem(uint64_t peer_id) : peer_id_(peer_id) {} + +XrSystem::~XrSystem() { wl_signal_emit(&c_obj_.events.destroy, nullptr); } + +std::unique_ptr +XrSystem::New(uint64_t peer_id) +{ + auto self = std::unique_ptr(new XrSystem(peer_id)); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init()) { + zn_error("Failed to initialize remote XrSystem"); + return nullptr; + } + + return self; +} + +bool +XrSystem::Init() +{ + wl_signal_init(&c_obj_.events.destroy); + + return true; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-system.h b/zen/src/backend/immersive/remote/xr-system.h new file mode 100644 index 00000000..6782e20a --- /dev/null +++ b/zen/src/backend/immersive/remote/xr-system.h @@ -0,0 +1,42 @@ +#pragma once + +#include "zen-common/cpp-util.h" +#include "zen/xr-system.h" + +namespace zen::backend::immersive::remote { + +class XrSystem +{ + public: + DISABLE_MOVE_AND_COPY(XrSystem); + ~XrSystem(); + + static std::unique_ptr New(uint64_t peer_id); + + inline uint64_t peer_id() const; + + inline zn_xr_system *c_obj(); + + private: + explicit XrSystem(uint64_t peer_id); + + bool Init(); + + const uint64_t peer_id_; + + zn_xr_system c_obj_{}; +}; + +inline uint64_t +XrSystem::peer_id() const +{ + return peer_id_; +} + +inline zn_xr_system * +XrSystem::c_obj() +{ + return &c_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/xr-private.h b/zen/src/backend/immersive/xr-private.h deleted file mode 100644 index c18a5c24..00000000 --- a/zen/src/backend/immersive/xr-private.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "common.h" -#include "xr.h" - -namespace zen::xr::proxy { - -class XrSystemProxy; - -class XrProxy : public zen::xr::XrDelegate -{ - public: - DISABLE_MOVE_AND_COPY(XrProxy); - ~XrProxy() override; - - void NotifySystemAdded(uint64_t handle) override; - - void NotifySystemRemoved(std::unique_ptr &system) override; - - private: - friend zn_xr * ::zn_xr_create(struct wl_display *display); - - XrProxy(); - - bool Init(wl_display *display); - - std::unique_ptr xr_; - - zn_xr zn_xr_{}; - - std::vector> systems_; -}; - -} // namespace zen::xr::proxy diff --git a/zen/src/backend/immersive/xr-system-manager.h b/zen/src/backend/immersive/xr-system-manager.h new file mode 100644 index 00000000..63d5e8b5 --- /dev/null +++ b/zen/src/backend/immersive/xr-system-manager.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_xr_system_manager; + +struct zn_xr_system_manager_interface { + void (*destroy)(struct zn_xr_system_manager *self); +}; + +struct zn_xr_system_manager { + void *impl_data; // @nullable, @outlive if exists + const struct zn_xr_system_manager_interface *impl; // @nonnull, @outlive + + struct { + struct wl_signal new_system; // (struct zn_xr_system *) + } events; +}; + +struct zn_xr_system_manager *zn_xr_system_manager_create_remote( + struct wl_display *display); + +inline void +zn_xr_system_manager_destroy(struct zn_xr_system_manager *self) +{ + self->impl->destroy(self); +} + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/backend/immersive/xr-system-private.h b/zen/src/backend/immersive/xr-system-private.h deleted file mode 100644 index e0a9bf3c..00000000 --- a/zen/src/backend/immersive/xr-system-private.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "common.h" -#include "zen/xr-system.h" - -namespace zen::xr::proxy { - -class XrSystemProxy -{ - public: - DISABLE_MOVE_AND_COPY(XrSystemProxy); - explicit XrSystemProxy(uint64_t handle); - ~XrSystemProxy(); - - bool Init(); - - inline uint64_t handle() const; - inline zn_xr_system *zn_xr_system(); - - private: - struct zn_xr_system zn_xr_system_ {}; -}; - -inline uint64_t -XrSystemProxy::handle() const -{ - return zn_xr_system_.handle; -} - -inline zn_xr_system * -XrSystemProxy::zn_xr_system() -{ - return &zn_xr_system_; -} - -} // namespace zen::xr::proxy diff --git a/zen/src/backend/immersive/xr-system.cc b/zen/src/backend/immersive/xr-system.cc deleted file mode 100644 index 13939339..00000000 --- a/zen/src/backend/immersive/xr-system.cc +++ /dev/null @@ -1,23 +0,0 @@ -#include "xr-system-private.h" - -namespace zen::xr::proxy { - -XrSystemProxy::XrSystemProxy(uint64_t handle) { zn_xr_system_.handle = handle; } - -bool -XrSystemProxy::Init() -{ - zn_xr_system_.impl_data = this; - - wl_signal_init(&zn_xr_system_.events.destroy); - - return true; -} - -XrSystemProxy::~XrSystemProxy() -{ - wl_signal_emit(&zn_xr_system_.events.destroy, nullptr); - wl_list_remove(&zn_xr_system_.events.destroy.listener_list); -} - -} // namespace zen::xr::proxy diff --git a/zen/src/backend/immersive/xr.c b/zen/src/backend/immersive/xr.c new file mode 100644 index 00000000..92a3e06e --- /dev/null +++ b/zen/src/backend/immersive/xr.c @@ -0,0 +1,36 @@ +#include "xr.h" + +#include "xr-system-manager.h" +#include "zen-common/log.h" +#include "zen-common/util.h" + +struct zn_xr * +zn_xr_create(struct wl_display *display) +{ + struct zn_xr *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->xr_system_manager = zn_xr_system_manager_create_remote(display); + if (self->xr_system_manager == NULL) { + zn_error("Failed to create zn_xr_system_manager"); + goto err_free; + } + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +void +zn_xr_destroy(struct zn_xr *self) +{ + zn_xr_system_manager_destroy(self->xr_system_manager); + free(self); +} diff --git a/zen/src/backend/immersive/xr.cc b/zen/src/backend/immersive/xr.cc deleted file mode 100644 index 424a6cc1..00000000 --- a/zen/src/backend/immersive/xr.cc +++ /dev/null @@ -1,69 +0,0 @@ -#include "xr-private.h" -#include "xr-system-private.h" -#include "zen-common/log.h" - -namespace zen::xr::proxy { - -XrProxy::XrProxy() = default; - -bool -XrProxy::Init(wl_display *display) -{ - zn_xr_.impl_data = this; - wl_signal_init(&zn_xr_.events.new_system); - xr_ = zen::xr::CreateXr(display, this); - return true; -} - -XrProxy::~XrProxy() { wl_list_remove(&zn_xr_.events.new_system.listener_list); } - -void -XrProxy::NotifySystemAdded(uint64_t handle) -{ - auto system = std::make_unique(handle); - if (!system->Init()) { - zn_warn("Failed to init XrSystemProxy"); - return; - } - auto *zn_xr_system = system->zn_xr_system(); - systems_.push_back(std::move(system)); - - wl_signal_emit(&zn_xr_.events.new_system, zn_xr_system); -} - -void -XrProxy::NotifySystemRemoved(std::unique_ptr &system) -{ - auto result = std::remove_if(systems_.begin(), systems_.end(), - [handle = system->handle()]( - std::unique_ptr &system_proxy) { - return system_proxy->handle() == handle; - }); - - systems_.erase(result, systems_.end()); -} - -} // namespace zen::xr::proxy - -zn_xr * -zn_xr_create(struct wl_display *display) -{ - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - auto *proxy = new zen::xr::proxy::XrProxy; - - if (!proxy->Init(display)) { - zn_error("Failed to initialize XrProxy"); - delete proxy; // NOLINT(cppcoreguidelines-owning-memory) - return nullptr; - } - - return &proxy->zn_xr_; -} - -void -zn_xr_destroy(zn_xr *self) -{ - auto *proxy = static_cast(self->impl_data); - - delete proxy; // NOLINT(cppcoreguidelines-owning-memory) -} diff --git a/zen/src/backend/immersive/xr.h b/zen/src/backend/immersive/xr.h index e1419d13..d8b102a8 100644 --- a/zen/src/backend/immersive/xr.h +++ b/zen/src/backend/immersive/xr.h @@ -1,21 +1,13 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif +#include -struct zn_xr { - void *impl_data; // used by the impl object +struct zn_xr_system_manager; - struct { - struct wl_signal new_system; // (struct zn_xr_system *) - } events; +struct zn_xr { + struct zn_xr_system_manager *xr_system_manager; // @nonnull, @owning }; struct zn_xr *zn_xr_create(struct wl_display *display); void zn_xr_destroy(struct zn_xr *self); - -#ifdef __cplusplus -} -#endif diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index bcce219c..1be5625a 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -1,8 +1,9 @@ +subdir('immersive/remote') + _zen_backend_srcs = [ 'default-backend.c', - 'immersive/xr.cc', - 'immersive/xr-system.cc', + 'immersive/xr.c', 'screen/compositor.c', 'screen/keyboard.c', @@ -14,14 +15,17 @@ _zen_backend_srcs = [ 'screen/xwayland-surface.c', ] +_zen_backend_deps = [ + _zen_deps, + zen_remote_immersive_backend_dep, +] + _zen_backend_lib = static_library( 'zen-backend', _zen_backend_srcs, install: false, - cpp_args: [ '-include', 'pch/pch.h' ], include_directories: zen_private_inc, - dependencies: [ _zen_deps, zen_xr_dep ], - cpp_pch: 'pch/pch.h', + dependencies: _zen_backend_deps, ) zen_backend_dep = declare_dependency( diff --git a/zen/src/backend/pch/pch.h b/zen/src/backend/pch/pch.h deleted file mode 100644 index 7e3adab4..00000000 --- a/zen/src/backend/pch/pch.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include From 72be179fef36c0898b6d389bca9f6cefc1b6fa1f Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 2 Apr 2023 18:41:02 +0900 Subject: [PATCH 06/49] Enable to start session --- .github/workflows/test.yaml | 29 ++++++-- desktop/include/zen-desktop/xr-system.h | 1 + desktop/src/xr-system.c | 39 +++++++++- meson.build | 2 +- zen/include/zen/xr-system.h | 23 ++++++ zen/src/backend/immersive/remote/log.h | 46 ++++++++++++ zen/src/backend/immersive/remote/pch/pch.h | 2 + .../immersive/remote/xr-system-manager.cc | 38 +++++++--- .../immersive/remote/xr-system-manager.h | 8 ++- zen/src/backend/immersive/remote/xr-system.cc | 72 ++++++++++++++++++- zen/src/backend/immersive/remote/xr-system.h | 48 +++++++++++-- zen/src/backend/screen/keyboard.c | 12 ++++ 12 files changed, 295 insertions(+), 25 deletions(-) create mode 100644 zen/src/backend/immersive/remote/log.h diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index db9a0ce4..2258f69d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -25,14 +25,22 @@ jobs: steps: - name: Install dependencies run: | - echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" | sudo tee -a /etc/apt/sources.list - echo "deb-src http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" | sudo tee -a /etc/apt/sources.list - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-get update sudo apt-get install \ libwayland-dev libwlroots-dev libpixman-1-dev \ libxkbcommon-dev libglu1-mesa-dev libglew-dev \ - meson libfreetype-dev librsvg2-dev libcglm-dev clang-15 + meson libfreetype-dev librsvg2-dev libcglm-dev + + - name: Install clang15 + if: matrix.clang-version == 15 + run: | + echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" | sudo tee -a /etc/apt/sources.list + echo "deb-src http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" | sudo tee -a /etc/apt/sources.list + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + sudo apt-get update + sudo apt-get install clang-15 clang-format-15 clang-tidy-15 + sudo ln -sf /usr/bin/clang-tidy-15 /usr/bin/clang-tidy + sudo ln -sf /usr/bin/clang-format-15 /usr/bin/clang-format - uses: actions/setup-python@v1 with: @@ -46,12 +54,25 @@ jobs: unzip grpc-dev.zip working-directory: ./grpc-dev + - name: Clone zen-protocols + uses: actions/checkout@v2 + with: + repository: zwin-project/zen-protocols + path: zen-protocols + + - name: Install zen-protocols + working-directory: ./zen-protocols + run: | + meson build + sudo ninja -C build install + - name: Clone zen-remote uses: actions/checkout@v2 with: repository: zwin-project/zen-remote path: zen-remote submodules: recursive + ref: 'v0.2.0' - name: Build zen-remote working-directory: ./zen-remote diff --git a/desktop/include/zen-desktop/xr-system.h b/desktop/include/zen-desktop/xr-system.h index 01a2e737..211f470f 100644 --- a/desktop/include/zen-desktop/xr-system.h +++ b/desktop/include/zen-desktop/xr-system.h @@ -12,6 +12,7 @@ struct zn_desktop_xr_system { struct wl_list resource_list; // wl_resource::link of zen_xr_system struct wl_listener zn_xr_system_destroy_listener; + struct wl_listener session_status_changed_listener; }; struct zn_desktop_xr_system *zn_desktop_xr_system_create( diff --git a/desktop/src/xr-system.c b/desktop/src/xr-system.c index 6e5c4c58..40a9c5ff 100644 --- a/desktop/src/xr-system.c +++ b/desktop/src/xr-system.c @@ -16,8 +16,12 @@ zn_desktop_xr_system_handle_destroy(struct wl_resource *resource) static void zn_desktop_xr_system_protocol_connect( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED) -{} + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + struct zn_desktop_xr_system *self = wl_resource_get_user_data(resource); + + zn_xr_system_connect(self->zn_xr_system); +} static const struct zen_xr_system_interface implementation = { .connect = zn_desktop_xr_system_protocol_connect, @@ -53,6 +57,31 @@ zn_desktop_xr_system_handle_xr_system_destroy( zn_desktop_xr_system_destroy(self); } +static void +zn_desktop_xr_system_handle_session_status_changed( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_desktop_xr_system *self = + zn_container_of(listener, self, session_status_changed_listener); + + struct wl_resource *resource = NULL; + + enum zen_xr_system_status status = ZEN_XR_SYSTEM_STATUS_CONNECTED; + + switch (self->zn_xr_system->status) { + case ZN_XR_SYSTEM_SESSION_STATUS_CONNECTED: + status = ZEN_XR_SYSTEM_STATUS_CONNECTED; + break; + case ZN_XR_SYSTEM_SESSION_STATUS_NOT_CONNECTED: + status = ZEN_XR_SYSTEM_STATUS_UNAVAILABLE; + break; + } + + wl_resource_for_each (resource, &self->resource_list) { + zen_xr_system_send_status(resource, status); + } +} + struct zn_desktop_xr_system * zn_desktop_xr_system_create( struct zn_xr_system *zn_xr_system, struct wl_display *display) @@ -78,6 +107,11 @@ zn_desktop_xr_system_create( wl_signal_add( &zn_xr_system->events.destroy, &self->zn_xr_system_destroy_listener); + self->session_status_changed_listener.notify = + zn_desktop_xr_system_handle_session_status_changed; + wl_signal_add(&zn_xr_system->events.session_status_changed, + &self->session_status_changed_listener); + return self; err_free: @@ -90,6 +124,7 @@ zn_desktop_xr_system_create( static void zn_desktop_xr_system_destroy(struct zn_desktop_xr_system *self) { + wl_list_remove(&self->session_status_changed_listener.link); wl_list_remove(&self->zn_xr_system_destroy_listener.link); wl_global_destroy(self->global); wl_list_remove(&self->resource_list); diff --git a/meson.build b/meson.build index 8effedc9..6f341fba 100644 --- a/meson.build +++ b/meson.build @@ -121,7 +121,7 @@ wayland_req = '>= 1.18.0' wayland_protocols_req = '>= 1.24' wlroots_req = ['>= 0.15', '< 0.16'] zen_protocols_req = '0.1.0' -zen_remote_server_req = '0.1.1' +zen_remote_server_req = '0.2.0' glew_proj = subproject( diff --git a/zen/include/zen/xr-system.h b/zen/include/zen/xr-system.h index 1545db50..a950df0b 100644 --- a/zen/include/zen/xr-system.h +++ b/zen/include/zen/xr-system.h @@ -6,12 +6,35 @@ extern "C" { #endif +struct zn_xr_system; + +struct zn_xr_system_interface { + void (*connect)(struct zn_xr_system *self); +}; + +enum zn_xr_system_session_status { + ZN_XR_SYSTEM_SESSION_STATUS_NOT_CONNECTED, // initial status + ZN_XR_SYSTEM_SESSION_STATUS_CONNECTED, +}; + struct zn_xr_system { + void *impl_data; // @outlive + const struct zn_xr_system_interface *impl; // @nonnull, @outlive + + enum zn_xr_system_session_status status; + struct { + struct wl_signal session_status_changed; // (NULL) struct wl_signal destroy; } events; }; +inline void +zn_xr_system_connect(struct zn_xr_system *self) +{ + self->impl->connect(self); +} + #ifdef __cplusplus } #endif diff --git a/zen/src/backend/immersive/remote/log.h b/zen/src/backend/immersive/remote/log.h new file mode 100644 index 00000000..f38a7f3f --- /dev/null +++ b/zen/src/backend/immersive/remote/log.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +#include + +namespace zen::backend::immersive::remote { + +class LogSink : public zen::remote::ILogSink +{ + void Sink(zen::remote::Severity severity, const char * /*pretty_function*/, + const char *file, int line, const char *format, va_list vp) override + { + zn_log_importance_t importance = ZEN_SILENT; + switch (severity) { + case zen::remote::Severity::DEBUG: + importance = ZEN_DEBUG; + break; + case zen::remote::Severity::INFO: + importance = ZEN_INFO; + break; + case zen::remote::Severity::WARN: + importance = ZEN_WARN; + break; + case zen::remote::Severity::ERROR: + importance = ZEN_ERROR; + break; + case zen::remote::Severity::FATAL: + importance = ZEN_ERROR; + break; + default: + break; + } + + // NOLINTNEXTLINE(cert-err33-c) + std::snprintf( + buffer_.data(), buffer_.size(), "[znr] [%s:%d] %s", file, line, format); + + zn_vlog_(importance, buffer_.data(), vp); + } + + std::array buffer_; +}; + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index 2c9952b9..9ee57188 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include #include diff --git a/zen/src/backend/immersive/remote/xr-system-manager.cc b/zen/src/backend/immersive/remote/xr-system-manager.cc index 8173284b..141e2e8e 100644 --- a/zen/src/backend/immersive/remote/xr-system-manager.cc +++ b/zen/src/backend/immersive/remote/xr-system-manager.cc @@ -1,5 +1,6 @@ #include "xr-system-manager.h" +#include "log.h" #include "loop.h" #include "xr-system.h" #include "zen-common/log.h" @@ -11,13 +12,15 @@ namespace zen::backend::immersive::remote { XrSystemManager::XrSystemManager(wl_display *display) : display_(display) {} -static const struct zn_xr_system_manager_interface implementation = { +const zn_xr_system_manager_interface XrSystemManager::c_implementation_ = { XrSystemManager::HandleDestroy, }; bool XrSystemManager::Init() { + zen::remote::InitializeLogger(std::make_unique()); + auto loop = std::make_unique(wl_display_get_event_loop(display_)); peer_manager_ = zen::remote::server::CreatePeerManager(std::move(loop)); @@ -27,7 +30,7 @@ XrSystemManager::Init() } c_obj_.impl_data = this; - c_obj_.impl = &implementation; + c_obj_.impl = &c_implementation_; wl_signal_init(&c_obj_.events.new_system); peer_manager_->on_peer_discover.Connect( @@ -46,11 +49,11 @@ XrSystemManager::HandleDestroy(zn_xr_system_manager *c_obj) } void -XrSystemManager::RemoveXrSystem(uint64_t peer_id) +XrSystemManager::RemoveDeadXrSystem() { auto result = std::remove_if(xr_systems_.begin(), xr_systems_.end(), - [peer_id](std::unique_ptr &xr_system) { - return xr_system->peer_id() == peer_id; + [](std::unique_ptr &xr_system) { + return !xr_system->is_alive(); }); xr_systems_.erase(result, xr_systems_.end()); @@ -59,9 +62,20 @@ XrSystemManager::RemoveXrSystem(uint64_t peer_id) void XrSystemManager::HandleRemotePeerDiscover(uint64_t peer_id) { - RemoveXrSystem(peer_id); + std::for_each(xr_systems_.begin(), xr_systems_.end(), + [peer_id](std::unique_ptr &xr_system) { + if (xr_system->peer_id() == peer_id) { + xr_system->set_unavailable(); + } + }); + RemoveDeadXrSystem(); + + auto peer = peer_manager_->Get(peer_id); - auto xr_system = XrSystem::New(peer_id); + zn_debug( + "Discover a new remote peer %ld (%s)", peer_id, peer->host().c_str()); + + auto xr_system = XrSystem::New(peer, display_, this); auto *xr_system_c_obj = xr_system->c_obj(); @@ -73,7 +87,15 @@ XrSystemManager::HandleRemotePeerDiscover(uint64_t peer_id) void XrSystemManager::HandleRemotePeerLost(uint64_t peer_id) { - RemoveXrSystem(peer_id); + std::for_each(xr_systems_.begin(), xr_systems_.end(), + [peer_id](std::unique_ptr &xr_system) { + if (xr_system->peer_id() == peer_id) { + xr_system->set_unavailable(); + } + }); + RemoveDeadXrSystem(); + + zn_debug("Lost a remote peer %ld", peer_id); } } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-system-manager.h b/zen/src/backend/immersive/remote/xr-system-manager.h index eef3bfb3..eac54356 100644 --- a/zen/src/backend/immersive/remote/xr-system-manager.h +++ b/zen/src/backend/immersive/remote/xr-system-manager.h @@ -13,7 +13,7 @@ class XrSystemManager DISABLE_MOVE_AND_COPY(XrSystemManager); ~XrSystemManager() = default; - static void HandleDestroy(zn_xr_system_manager *c_obj); + void RemoveDeadXrSystem(); private: friend struct zn_xr_system_manager * ::zn_xr_system_manager_create_remote( @@ -23,12 +23,14 @@ class XrSystemManager bool Init(); - void RemoveXrSystem(uint64_t peer_id); - void HandleRemotePeerDiscover(uint64_t peer_id); void HandleRemotePeerLost(uint64_t peer_id); + static void HandleDestroy(zn_xr_system_manager *c_obj); + + static const zn_xr_system_manager_interface c_implementation_; + zn_xr_system_manager c_obj_{}; wl_display *display_; // @nonnull, @outlive diff --git a/zen/src/backend/immersive/remote/xr-system.cc b/zen/src/backend/immersive/remote/xr-system.cc index 5137d861..ce5a1d03 100644 --- a/zen/src/backend/immersive/remote/xr-system.cc +++ b/zen/src/backend/immersive/remote/xr-system.cc @@ -1,17 +1,26 @@ #include "xr-system.h" +#include "loop.h" +#include "xr-system-manager.h" #include "zen-common/log.h" namespace zen::backend::immersive::remote { -XrSystem::XrSystem(uint64_t peer_id) : peer_id_(peer_id) {} +XrSystem::XrSystem(std::shared_ptr peer, + wl_display *display, XrSystemManager *xr_system_manager) + : peer_(std::move(peer)), + display_(display), + xr_system_manager_(xr_system_manager) +{} XrSystem::~XrSystem() { wl_signal_emit(&c_obj_.events.destroy, nullptr); } std::unique_ptr -XrSystem::New(uint64_t peer_id) +XrSystem::New(std::shared_ptr peer, + wl_display *display, XrSystemManager *xr_system_manager) { - auto self = std::unique_ptr(new XrSystem(peer_id)); + auto self = std::unique_ptr( + new XrSystem(std::move(peer), display, xr_system_manager)); if (!self) { zn_error("Failed to allocate memory"); return nullptr; @@ -28,9 +37,66 @@ XrSystem::New(uint64_t peer_id) bool XrSystem::Init() { + c_obj_.impl_data = this; + c_obj_.impl = &c_implementation_; + c_obj_.status = ZN_XR_SYSTEM_SESSION_STATUS_NOT_CONNECTED; + wl_signal_init(&c_obj_.events.session_status_changed); wl_signal_init(&c_obj_.events.destroy); return true; } +const zn_xr_system_interface XrSystem::c_implementation_ = { + XrSystem::HandleConnect, +}; + +void +XrSystem::HandleConnect(zn_xr_system *c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + self->Connect(); +} + +void +XrSystem::HandleDisconnect() +{ + zn_info("Disconnected from peer %ld", peer_->id()); + + c_obj_.status = ZN_XR_SYSTEM_SESSION_STATUS_NOT_CONNECTED; + + wl_signal_emit(&c_obj_.events.session_status_changed, nullptr); + + xr_system_manager_->RemoveDeadXrSystem(); // Will destroy this XrSystem +} + +void +XrSystem::Connect() +{ + if (session_) { + return; + } + + auto loop = std::make_unique(wl_display_get_event_loop(display_)); + + auto new_session = zen::remote::server::CreateSession(std::move(loop)); + + if (!new_session->Connect(peer_)) { + zn_warn("Failed to start new session"); + return; + } + + zn_info("Connected to peer %ld", peer_->id()); + + set_unavailable(); + + new_session->on_disconnect.Connect([this]() { HandleDisconnect(); }); + + session_ = new_session; + + c_obj_.status = ZN_XR_SYSTEM_SESSION_STATUS_CONNECTED; + + wl_signal_emit(&c_obj_.events.session_status_changed, nullptr); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-system.h b/zen/src/backend/immersive/remote/xr-system.h index 6782e20a..ea3551b4 100644 --- a/zen/src/backend/immersive/remote/xr-system.h +++ b/zen/src/backend/immersive/remote/xr-system.h @@ -5,24 +5,51 @@ namespace zen::backend::immersive::remote { +class XrSystemManager; + class XrSystem { public: DISABLE_MOVE_AND_COPY(XrSystem); ~XrSystem(); - static std::unique_ptr New(uint64_t peer_id); + static std::unique_ptr New( + std::shared_ptr peer, wl_display *display, + XrSystemManager *xr_system_manager); inline uint64_t peer_id() const; inline zn_xr_system *c_obj(); + inline void set_unavailable(); + + inline bool is_alive() const; + private: - explicit XrSystem(uint64_t peer_id); + XrSystem(std::shared_ptr peer, + wl_display *display, XrSystemManager *xr_system_manager); bool Init(); - const uint64_t peer_id_; + void Connect(); + + static void HandleConnect(zn_xr_system *c_obj); + + void HandleDisconnect(); + + static const zn_xr_system_interface c_implementation_; + + std::shared_ptr peer_; // @nonnull + + wl_display *display_; // @nonnull, @outlive + + XrSystemManager *xr_system_manager_; // @nonnull, @outlive + + // Null when status is NOT_CONNECTED. Not null otherwise. + std::shared_ptr session_; + + // True if available to create a new session. + bool is_available_ = true; zn_xr_system c_obj_{}; }; @@ -30,7 +57,7 @@ class XrSystem inline uint64_t XrSystem::peer_id() const { - return peer_id_; + return peer_->id(); } inline zn_xr_system * @@ -39,4 +66,17 @@ XrSystem::c_obj() return &c_obj_; } +inline void +XrSystem::set_unavailable() +{ + is_available_ = false; +} + +inline bool +XrSystem::is_alive() const +{ + return is_available_ || + c_obj_.status == ZN_XR_SYSTEM_SESSION_STATUS_CONNECTED; +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/screen/keyboard.c b/zen/src/backend/screen/keyboard.c index c80c7fff..098b0367 100644 --- a/zen/src/backend/screen/keyboard.c +++ b/zen/src/backend/screen/keyboard.c @@ -1,9 +1,13 @@ #include "keyboard.h" +#include +#include +#include #include #include "default-backend.h" #include "zen-common/log.h" +#include "zen-common/terminate.h" #include "zen-common/util.h" #include "zen/seat.h" #include "zen/server.h" @@ -30,6 +34,14 @@ zn_keyboard_handle_keyboard_key(struct wl_listener *listener, void *user_data) // TODO(@Aki-7): Handle keyboard bindings + // TODO(@Aki-7): For the development convenience, fix this later + if (wlr_keyboard_get_modifiers(self->base.wlr_input_device->keyboard) == + WLR_MODIFIER_ALT && + event->keycode == KEY_Q) { + zn_terminate(EXIT_SUCCESS); + return; + } + wlr_seat_set_keyboard(server->seat->wlr_seat, self->base.wlr_input_device); wlr_seat_keyboard_send_key( server->seat->wlr_seat, event->time_msec, event->keycode, event->state); From 41993686aca9368eebc8c1ba989e6b075bd9019c Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 2 Apr 2023 18:55:21 +0900 Subject: [PATCH 07/49] fix backend mock --- zen/tests/mock/src/backend.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zen/tests/mock/src/backend.c b/zen/tests/mock/src/backend.c index a343b57b..593cdcd1 100644 --- a/zen/tests/mock/src/backend.c +++ b/zen/tests/mock/src/backend.c @@ -54,6 +54,7 @@ zn_mock_backend_create(void) wl_signal_init(&self->base.events.new_screen); wl_signal_init(&self->base.events.view_mapped); wl_signal_init(&self->base.events.destroy); + wl_signal_init(&self->base.events.new_xr_system); return self; } @@ -63,6 +64,7 @@ zn_mock_backend_destroy(struct zn_mock_backend *self) { zn_signal_emit_mutable(&self->base.events.destroy, NULL); + wl_list_remove(&self->base.events.new_xr_system.listener_list); wl_list_remove(&self->base.events.destroy.listener_list); wl_list_remove(&self->base.events.view_mapped.listener_list); wl_list_remove(&self->base.events.new_screen.listener_list); From 0cd855d3df2a10e53e58f214b533815a3fc9c31e Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 2 Apr 2023 20:17:25 +0900 Subject: [PATCH 08/49] create dispatcher --- zen/include/zen/xr-dispatcher.h | 7 ++++ zen/include/zen/xr-system.h | 4 ++ zen/src/backend/immersive/remote/meson.build | 1 + zen/src/backend/immersive/remote/pch/pch.h | 1 + .../backend/immersive/remote/xr-dispatcher.cc | 40 +++++++++++++++++++ .../backend/immersive/remote/xr-dispatcher.h | 35 ++++++++++++++++ zen/src/backend/immersive/remote/xr-system.cc | 15 +++++++ zen/src/backend/immersive/remote/xr-system.h | 4 ++ 8 files changed, 107 insertions(+) create mode 100644 zen/include/zen/xr-dispatcher.h create mode 100644 zen/src/backend/immersive/remote/xr-dispatcher.cc create mode 100644 zen/src/backend/immersive/remote/xr-dispatcher.h diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h new file mode 100644 index 00000000..6881e009 --- /dev/null +++ b/zen/include/zen/xr-dispatcher.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +struct zn_xr_dispatcher { + void *impl_data; +}; diff --git a/zen/include/zen/xr-system.h b/zen/include/zen/xr-system.h index a950df0b..6613292f 100644 --- a/zen/include/zen/xr-system.h +++ b/zen/include/zen/xr-system.h @@ -7,6 +7,7 @@ extern "C" { #endif struct zn_xr_system; +struct zn_xr_dispatcher; struct zn_xr_system_interface { void (*connect)(struct zn_xr_system *self); @@ -23,6 +24,9 @@ struct zn_xr_system { enum zn_xr_system_session_status status; + struct zn_xr_dispatcher *high_priority_dispatcher; // @nonnull, @owning + struct zn_xr_dispatcher *default_dispatcher; // @nonnull, @owning + struct { struct wl_signal session_status_changed; // (NULL) struct wl_signal destroy; diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index b15ea819..2213aa67 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -1,5 +1,6 @@ _zen_remote_immersive_backend_srcs = [ 'loop.cc', + 'xr-dispatcher.cc', 'xr-system.cc', 'xr-system-manager.cc', ] diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index 9ee57188..17478b95 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -2,6 +2,7 @@ #include #include +#include #include #include diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc new file mode 100644 index 00000000..20b102b6 --- /dev/null +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -0,0 +1,40 @@ +#include "xr-dispatcher.h" + +#include + +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +std::unique_ptr +XrDispatcher::New(std::shared_ptr session) +{ + auto self = std::unique_ptr(new XrDispatcher()); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(session))) { + zn_error("Failed to initialize remote XrDispatcher"); + return nullptr; + } + + return self; +} + +bool +XrDispatcher::Init(std::shared_ptr session) +{ + channel_ = zen::remote::server::CreateChannel(session); + if (!channel_) { + zn_error("Failed to create a remote channel"); + return false; + } + + c_obj_.impl_data = this; + + return true; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h new file mode 100644 index 00000000..b6499037 --- /dev/null +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -0,0 +1,35 @@ +#pragma once + +#include "zen-common/cpp-util.h" +#include "zen/xr-dispatcher.h" + +namespace zen::backend::immersive::remote { + +class XrDispatcher +{ + public: + DISABLE_MOVE_AND_COPY(XrDispatcher); + ~XrDispatcher() = default; + + static std::unique_ptr New( + std::shared_ptr session); + + inline zn_xr_dispatcher *c_obj(); + + private: + XrDispatcher() = default; + + bool Init(std::shared_ptr session); + + std::shared_ptr channel_; + + zn_xr_dispatcher c_obj_{}; +}; + +inline zn_xr_dispatcher * +XrDispatcher::c_obj() +{ + return &c_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-system.cc b/zen/src/backend/immersive/remote/xr-system.cc index ce5a1d03..7fd0e439 100644 --- a/zen/src/backend/immersive/remote/xr-system.cc +++ b/zen/src/backend/immersive/remote/xr-system.cc @@ -1,6 +1,7 @@ #include "xr-system.h" #include "loop.h" +#include "xr-dispatcher.h" #include "xr-system-manager.h" #include "zen-common/log.h" @@ -37,9 +38,23 @@ XrSystem::New(std::shared_ptr peer, bool XrSystem::Init() { + high_priority_dispatcher_ = XrDispatcher::New(session_); + if (!high_priority_dispatcher_) { + zn_error("Failed to create a remote XrDispatcher"); + return false; + } + + default_dispatcher_ = XrDispatcher::New(session_); + if (!default_dispatcher_) { + zn_error("Failed to create a remote XrDispatcher"); + return false; + } + c_obj_.impl_data = this; c_obj_.impl = &c_implementation_; c_obj_.status = ZN_XR_SYSTEM_SESSION_STATUS_NOT_CONNECTED; + c_obj_.high_priority_dispatcher = high_priority_dispatcher_->c_obj(); + c_obj_.default_dispatcher = default_dispatcher_->c_obj(); wl_signal_init(&c_obj_.events.session_status_changed); wl_signal_init(&c_obj_.events.destroy); diff --git a/zen/src/backend/immersive/remote/xr-system.h b/zen/src/backend/immersive/remote/xr-system.h index ea3551b4..ae44e945 100644 --- a/zen/src/backend/immersive/remote/xr-system.h +++ b/zen/src/backend/immersive/remote/xr-system.h @@ -6,6 +6,7 @@ namespace zen::backend::immersive::remote { class XrSystemManager; +class XrDispatcher; class XrSystem { @@ -48,6 +49,9 @@ class XrSystem // Null when status is NOT_CONNECTED. Not null otherwise. std::shared_ptr session_; + std::unique_ptr high_priority_dispatcher_; + std::unique_ptr default_dispatcher_; + // True if available to create a new session. bool is_available_ = true; From 1c8d16e433d7020e61c250a9f8d2c21edafa66c6 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 2 Apr 2023 23:14:53 +0900 Subject: [PATCH 09/49] xr compositor --- meson.build | 2 + protocol/meson.build | 3 + zen/include/zen/backend.h | 11 ++ zen/include/zen/xr-system.h | 4 +- zen/src/backend/default-backend.c | 50 +++++++++ zen/src/backend/default-backend.h | 5 + zen/src/backend/immersive/xr-compositor.c | 105 ++++++++++++++++++ zen/src/backend/immersive/xr-compositor.h | 22 ++++ zen/src/backend/immersive/xr-system-manager.h | 4 +- zen/src/backend/meson.build | 4 + zen/tests/mock/src/backend.c | 6 + 11 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 zen/src/backend/immersive/xr-compositor.c create mode 100644 zen/src/backend/immersive/xr-compositor.h diff --git a/meson.build b/meson.build index 6f341fba..0595eef0 100644 --- a/meson.build +++ b/meson.build @@ -122,6 +122,7 @@ wayland_protocols_req = '>= 1.24' wlroots_req = ['>= 0.15', '< 0.16'] zen_protocols_req = '0.1.0' zen_remote_server_req = '0.2.0' +zwin_protocols_req = '0.1.0' glew_proj = subproject( @@ -146,6 +147,7 @@ wayland_server_dep = dependency('wayland-server', version: wayland_req) xkbcommon_dep = dependency('xkbcommon') zen_protocols_dep = dependency('zen-protocols', version: zen_protocols_req) zen_remote_server_dep = dependency('zen-remote-server', version: zen_remote_server_req) +zwin_protocols_dep = dependency('zwin-protocols', version: zwin_protocols_req) subdir('protocol') wlroots_dep = declare_dependency( diff --git a/protocol/meson.build b/protocol/meson.build index c919f8b2..f1841e1b 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,5 +1,6 @@ wl_protocol_dir = wayland_protocols_dep.get_variable('pkgdatadir') zen_protocol_dir = zen_protocols_dep.get_variable('pkgdatadir') +zwin_protocol_dir = zwin_protocols_dep.get_variable('pkgdatadir') wayland_scanner = find_program( wayland_scanner_dep.get_variable('wayland_scanner'), @@ -11,6 +12,8 @@ protocols = { 'zen-desktop': zen_protocol_dir / 'unstable/zen-desktop.xml', + 'zwin': zwin_protocol_dir / 'zwin.xml', + 'wlr-layer-shell-unstable-v1': 'wlr-layer-shell-unstable-v1.xml', } diff --git a/zen/include/zen/backend.h b/zen/include/zen/backend.h index ff02abcf..4d73de30 100644 --- a/zen/include/zen/backend.h +++ b/zen/include/zen/backend.h @@ -5,6 +5,7 @@ #include "zen-common/util.h" struct zn_backend; +struct zn_xr_system; /// Within the lifetime of zn_backend, the start and stop methods can be called /// in this order only once each. @@ -12,6 +13,9 @@ struct zn_backend_interface { struct wlr_texture *(*create_wlr_texture_from_pixels)(struct zn_backend *self, uint32_t format, uint32_t stride, uint32_t width, uint32_t height, const void *data); + /// @param xr_system is nullable + void (*set_xr_system)( + struct zn_backend *self, struct zn_xr_system *xr_system); /// Starts monitoring the connection or disconnection of input/output devices. bool (*start)(struct zn_backend *self); /// Destroy input/output devices @@ -56,3 +60,10 @@ zn_backend_create_wlr_texture_from_pixels(struct zn_backend *self, return self->impl->create_wlr_texture_from_pixels( self, format, stride, width, height, data); } + +UNUSED static inline void +zn_backend_set_xr_system( + struct zn_backend *self, struct zn_xr_system *xr_system) +{ + self->impl->set_xr_system(self, xr_system); +} diff --git a/zen/include/zen/xr-system.h b/zen/include/zen/xr-system.h index 6613292f..a6c5868e 100644 --- a/zen/include/zen/xr-system.h +++ b/zen/include/zen/xr-system.h @@ -2,6 +2,8 @@ #include +#include "zen-common/util.h" + #ifdef __cplusplus extern "C" { #endif @@ -33,7 +35,7 @@ struct zn_xr_system { } events; }; -inline void +UNUSED static inline void zn_xr_system_connect(struct zn_xr_system *self) { self->impl->connect(self); diff --git a/zen/src/backend/default-backend.c b/zen/src/backend/default-backend.c index 1191cfef..a7b94a4c 100644 --- a/zen/src/backend/default-backend.c +++ b/zen/src/backend/default-backend.c @@ -7,6 +7,7 @@ #include #include +#include "immersive/xr-compositor.h" #include "immersive/xr-system-manager.h" #include "immersive/xr.h" #include "screen/compositor.h" @@ -63,6 +64,25 @@ zn_default_backend_notify_view_mapped( wl_signal_emit(&self->base.events.view_mapped, view); } +/// @param xr_system is nullable +static void +zn_default_backend_set_xr_system( + struct zn_default_backend *self, struct zn_xr_system *xr_system) +{ + if (self->xr_compositor) { + wl_list_remove(&self->xr_compositor_destroy_listener.link); + wl_list_init(&self->xr_compositor_destroy_listener.link); + zn_xr_compositor_destroy(self->xr_compositor); + self->xr_compositor = NULL; + } + + if (xr_system) { + self->xr_compositor = zn_xr_compositor_create(self->display, xr_system); + wl_signal_add(&self->xr_compositor->events.destroy, + &self->xr_compositor_destroy_listener); + } +} + static void zn_default_backend_handle_new_input(struct wl_listener *listener, void *data) { @@ -144,6 +164,16 @@ zn_default_backend_handle_new_xr_system( wl_signal_emit(&self->base.events.new_xr_system, xr_system); } +static void +zn_default_backend_handle_xr_compositor_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_default_backend *self = + zn_container_of(listener, self, xr_compositor_destroy_listener); + + zn_default_backend_set_xr_system(self, NULL); +} + static struct wlr_texture * zn_default_backend_create_wlr_texture_from_pixels(struct zn_backend *base, uint32_t format, uint32_t stride, uint32_t width, uint32_t height, @@ -158,6 +188,15 @@ zn_default_backend_create_wlr_texture_from_pixels(struct zn_backend *base, self->wlr_renderer, format, stride, width, height, data); } +static void +zn_default_backend_handle_set_xr_system( + struct zn_backend *base, struct zn_xr_system *xr_system) +{ + struct zn_default_backend *self = zn_container_of(base, self, base); + + zn_default_backend_set_xr_system(self, xr_system); +} + static bool zn_default_backend_start(struct zn_backend *base) { @@ -183,6 +222,7 @@ zn_default_backend_handle_destroy(struct zn_backend *base) static const struct zn_backend_interface implementation = { .create_wlr_texture_from_pixels = zn_default_backend_create_wlr_texture_from_pixels, + .set_xr_system = zn_default_backend_handle_set_xr_system, .start = zn_default_backend_start, .stop = zn_default_backend_stop, .destroy = zn_default_backend_handle_destroy, @@ -203,6 +243,7 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) wl_signal_init(&self->base.events.new_xr_system); self->base.impl = &implementation; self->display = display; + self->xr_compositor = NULL; wl_list_init(&self->input_device_list); self->wlr_backend = wlr_backend_autocreate(display); @@ -261,6 +302,10 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) wl_signal_add(&self->xr->xr_system_manager->events.new_system, &self->new_xr_system_listener); + self->xr_compositor_destroy_listener.notify = + zn_default_backend_handle_xr_compositor_destroy; + wl_list_init(&self->xr_compositor_destroy_listener.link); + return &self->base; err_compositor: @@ -287,6 +332,11 @@ zn_default_backend_destroy(struct zn_default_backend *self) { zn_signal_emit_mutable(&self->base.events.destroy, NULL); + if (self->xr_compositor) { + zn_xr_compositor_destroy(self->xr_compositor); + self->xr_compositor = NULL; + } + wl_list_remove(&self->xr_compositor_destroy_listener.link); wl_list_remove(&self->new_xr_system_listener.link); wl_list_remove(&self->new_input_listener.link); wl_list_remove(&self->new_output_listener.link); diff --git a/zen/src/backend/default-backend.h b/zen/src/backend/default-backend.h index 403f0769..3506e5c7 100644 --- a/zen/src/backend/default-backend.h +++ b/zen/src/backend/default-backend.h @@ -19,6 +19,10 @@ struct zn_default_backend { struct zn_compositor *compositor; // @nonnull, @owning + // Basically owned by zn_default_backend, but can be destroyed when given + // xr_system is destroyed. + struct zn_xr_compositor *xr_compositor; // @nullable + struct zn_xr *xr; // @nonnull, @owing struct wl_list input_device_list; // zn_input_device_base::link @@ -26,6 +30,7 @@ struct zn_default_backend { struct wl_listener new_input_listener; struct wl_listener new_output_listener; struct wl_listener new_xr_system_listener; + struct wl_listener xr_compositor_destroy_listener; }; struct zn_default_backend *zn_default_backend_get(struct zn_backend *base); diff --git a/zen/src/backend/immersive/xr-compositor.c b/zen/src/backend/immersive/xr-compositor.c new file mode 100644 index 00000000..5acc5a44 --- /dev/null +++ b/zen/src/backend/immersive/xr-compositor.c @@ -0,0 +1,105 @@ +#include "xr-compositor.h" + +#include + +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" +#include "zen/xr-system.h" + +static void +zn_xr_compositor_handle_destroy(struct wl_resource *resource) +{ + wl_list_remove(wl_resource_get_link(resource)); +} + +static void +zn_xr_compositor_handle_xr_system_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_xr_compositor *self = + zn_container_of(listener, self, xr_system_destroy_listener); + + zn_xr_compositor_destroy(self); +} + +static void +zn_xr_compositor_protocol_create_virtual_object(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED) +{} + +static void +zn_xr_compositor_protocol_create_region(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED) +{} + +static const struct zwn_compositor_interface implementation = { + .create_virtual_object = zn_xr_compositor_protocol_create_virtual_object, + .create_region = zn_xr_compositor_protocol_create_region, +}; + +static void +zn_xr_compositor_bind( + struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + struct zn_xr_compositor *self = data; + + struct wl_resource *resource = + wl_resource_create(client, &zwn_compositor_interface, (int)version, id); + if (resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation( + resource, &implementation, self, zn_xr_compositor_handle_destroy); + + wl_list_insert(&self->resource_list, wl_resource_get_link(resource)); +} + +struct zn_xr_compositor * +zn_xr_compositor_create( + struct wl_display *display UNUSED, struct zn_xr_system *xr_system) +{ + struct zn_xr_compositor *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->xr_system = xr_system; + wl_signal_init(&self->events.destroy); + wl_list_init(&self->resource_list); + + self->global = wl_global_create( + display, &zwn_compositor_interface, 1, self, zn_xr_compositor_bind); + if (self->global == NULL) { + zn_error("Failed to create zwn_compositor global"); + goto err_free; + } + + self->xr_system_destroy_listener.notify = + zn_xr_compositor_handle_xr_system_destroy; + wl_signal_add(&xr_system->events.destroy, &self->xr_system_destroy_listener); + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +void +zn_xr_compositor_destroy(struct zn_xr_compositor *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_global_destroy(self->global); + wl_list_remove(&self->resource_list); + wl_list_remove(&self->xr_system_destroy_listener.link); + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} diff --git a/zen/src/backend/immersive/xr-compositor.h b/zen/src/backend/immersive/xr-compositor.h new file mode 100644 index 00000000..9ad67b9b --- /dev/null +++ b/zen/src/backend/immersive/xr-compositor.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +struct zn_xr_compositor { + struct zn_xr_system *xr_system; // @nonnull, @outlive + + struct wl_listener xr_system_destroy_listener; + + struct wl_global *global; // @nonnull, @owning + + struct wl_list resource_list; // wl_resource::link of zwn_compositor + + struct { + struct wl_signal destroy; + } events; +}; + +struct zn_xr_compositor *zn_xr_compositor_create( + struct wl_display *display, struct zn_xr_system *xr_system); + +void zn_xr_compositor_destroy(struct zn_xr_compositor *self); diff --git a/zen/src/backend/immersive/xr-system-manager.h b/zen/src/backend/immersive/xr-system-manager.h index 63d5e8b5..600318c4 100644 --- a/zen/src/backend/immersive/xr-system-manager.h +++ b/zen/src/backend/immersive/xr-system-manager.h @@ -2,6 +2,8 @@ #include +#include "zen-common/util.h" + #ifdef __cplusplus extern "C" { #endif @@ -24,7 +26,7 @@ struct zn_xr_system_manager { struct zn_xr_system_manager *zn_xr_system_manager_create_remote( struct wl_display *display); -inline void +UNUSED static inline void zn_xr_system_manager_destroy(struct zn_xr_system_manager *self) { self->impl->destroy(self); diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 1be5625a..027ee0ff 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -4,6 +4,7 @@ _zen_backend_srcs = [ 'default-backend.c', 'immersive/xr.c', + 'immersive/xr-compositor.c', 'screen/compositor.c', 'screen/keyboard.c', @@ -13,6 +14,9 @@ _zen_backend_srcs = [ 'screen/pointer.c', 'screen/surface-snode.c', 'screen/xwayland-surface.c', + + protocols_code['zwin'], + protocols_server_header['zwin'], ] _zen_backend_deps = [ diff --git a/zen/tests/mock/src/backend.c b/zen/tests/mock/src/backend.c index 593cdcd1..b932bac9 100644 --- a/zen/tests/mock/src/backend.c +++ b/zen/tests/mock/src/backend.c @@ -19,6 +19,11 @@ zn_mock_backend_create_wlr_texture_from_pixels(struct zn_backend *base UNUSED, return texture; } +static void +zn_mock_backend_set_xr_system( + struct zn_backend *base UNUSED, struct zn_xr_system *xr_system UNUSED) +{} + static bool zn_mock_backend_start(struct zn_backend *base UNUSED) { @@ -39,6 +44,7 @@ zn_mock_backend_handle_destroy(struct zn_backend *base) static const struct zn_backend_interface implementation = { .create_wlr_texture_from_pixels = zn_mock_backend_create_wlr_texture_from_pixels, + .set_xr_system = zn_mock_backend_set_xr_system, .start = zn_mock_backend_start, .stop = zn_mock_backend_stop, .destroy = zn_mock_backend_handle_destroy, From 0c4a4378302ff45395d305af12c420bae79fa53f Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 8 Apr 2023 18:58:09 +0900 Subject: [PATCH 10/49] virtual object --- common/include/zen-common/log.h | 5 +- common/include/zen-common/util.h | 12 +- desktop/include/zen-desktop/xr-system.h | 5 +- desktop/src/xr-system.c | 43 ++++-- zen/include/zen/backend.h | 8 ++ zen/include/zen/virtual-object.h | 27 ++++ zen/include/zen/xr-dispatcher.h | 37 +++++ zen/include/zen/xr-system.h | 40 +++++- zen/meson.build | 2 + zen/src/backend/default-backend.c | 12 +- .../backend/immersive/client-virtual-object.c | 129 ++++++++++++++++++ .../backend/immersive/client-virtual-object.h | 20 +++ zen/src/backend/immersive/remote/meson.build | 1 + zen/src/backend/immersive/remote/pch/pch.h | 1 + .../immersive/remote/virtual-object.cc | 50 +++++++ .../backend/immersive/remote/virtual-object.h | 35 +++++ .../backend/immersive/remote/xr-dispatcher.cc | 55 +++++++- .../backend/immersive/remote/xr-dispatcher.h | 19 ++- .../immersive/remote/xr-system-manager.cc | 6 +- zen/src/backend/immersive/remote/xr-system.cc | 91 ++++++++---- zen/src/backend/immersive/remote/xr-system.h | 27 ++-- zen/src/backend/immersive/xr-compositor.c | 43 ++++-- zen/src/backend/immersive/xr-compositor.h | 4 +- zen/src/backend/meson.build | 1 + zen/src/virtual-object.c | 32 +++++ zen/src/xr-dispatcher-private.h | 16 +++ zen/src/xr-dispatcher.c | 34 +++++ zen/tests/mock/src/backend.c | 7 + 28 files changed, 675 insertions(+), 87 deletions(-) create mode 100644 zen/include/zen/virtual-object.h create mode 100644 zen/src/backend/immersive/client-virtual-object.c create mode 100644 zen/src/backend/immersive/client-virtual-object.h create mode 100644 zen/src/backend/immersive/remote/virtual-object.cc create mode 100644 zen/src/backend/immersive/remote/virtual-object.h create mode 100644 zen/src/virtual-object.c create mode 100644 zen/src/xr-dispatcher-private.h create mode 100644 zen/src/xr-dispatcher.c diff --git a/common/include/zen-common/log.h b/common/include/zen-common/log.h index e3fb5e07..c41e0060 100644 --- a/common/include/zen-common/log.h +++ b/common/include/zen-common/log.h @@ -59,9 +59,8 @@ bool zn_assert_(bool condition, const char *format, ...) ATTRIB_PRINTF(2, 3); #define zn_abort(fmt, ...) \ zn_abort_("[zen] [%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__) -#define zn_assert(cond, fmt, ...) \ - zn_assert_(cond, "[zen] [%s:%d] %s: " fmt, __FILE__, __LINE__, __func__, \ - ##__VA_ARGS__) +#define zn_assert(cond, fmt, ...) \ + zn_assert_(cond, "[zen] [%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__) #define zn_warn_once(fmt, ...) \ { \ diff --git a/common/include/zen-common/util.h b/common/include/zen-common/util.h index b9baab49..79fc51fd 100644 --- a/common/include/zen-common/util.h +++ b/common/include/zen-common/util.h @@ -1,10 +1,10 @@ #pragma once -#include -#include +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) #ifdef __cplusplus -#error "This header is not for C++" +extern "C" { #endif /** Visibility attribute */ @@ -32,7 +32,7 @@ UNUSED static inline void * zalloc(size_t size) { - return calloc(1, size); + return calloc(1, size); // NOLINT(cppcoreguidelines-*) } #define ZN_MAX(a, b) ((a) > (b) ? (a) : (b)) @@ -41,3 +41,7 @@ zalloc(size_t size) /** Retrieve a pointer to a containing struct */ #define zn_container_of(ptr, sample, member) \ (__typeof__(sample))((char *)(ptr)-offsetof(__typeof__(*(sample)), member)) + +#ifdef __cplusplus +} +#endif diff --git a/desktop/include/zen-desktop/xr-system.h b/desktop/include/zen-desktop/xr-system.h index 211f470f..6078053d 100644 --- a/desktop/include/zen-desktop/xr-system.h +++ b/desktop/include/zen-desktop/xr-system.h @@ -1,6 +1,7 @@ #pragma once #include +#include struct zn_xr_system; struct zn_desktop_server_xr_system; @@ -11,8 +12,10 @@ struct zn_desktop_xr_system { struct wl_global *global; // @nonnull, @owning struct wl_list resource_list; // wl_resource::link of zen_xr_system + enum zen_xr_system_status status; + struct wl_listener zn_xr_system_destroy_listener; - struct wl_listener session_status_changed_listener; + struct wl_listener session_state_changed_listener; }; struct zn_desktop_xr_system *zn_desktop_xr_system_create( diff --git a/desktop/src/xr-system.c b/desktop/src/xr-system.c index 40a9c5ff..c5d70e80 100644 --- a/desktop/src/xr-system.c +++ b/desktop/src/xr-system.c @@ -4,6 +4,8 @@ #include "zen-common/log.h" #include "zen-common/util.h" +#include "zen/backend.h" +#include "zen/server.h" #include "zen/xr-system.h" static void zn_desktop_xr_system_destroy(struct zn_desktop_xr_system *self); @@ -58,27 +60,41 @@ zn_desktop_xr_system_handle_xr_system_destroy( } static void -zn_desktop_xr_system_handle_session_status_changed( +zn_desktop_xr_system_handle_session_state_changed( struct wl_listener *listener, void *data UNUSED) { + struct zn_server *server = zn_server_get_singleton(); + struct zn_desktop_xr_system *self = - zn_container_of(listener, self, session_status_changed_listener); + zn_container_of(listener, self, session_state_changed_listener); struct wl_resource *resource = NULL; - enum zen_xr_system_status status = ZEN_XR_SYSTEM_STATUS_CONNECTED; + enum zen_xr_system_status status = self->status; - switch (self->zn_xr_system->status) { - case ZN_XR_SYSTEM_SESSION_STATUS_CONNECTED: + switch (self->zn_xr_system->state) { + case ZN_XR_SYSTEM_SESSION_STATE_AVAILABLE: + status = ZEN_XR_SYSTEM_STATUS_AVAILABLE; + break; + case ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED: + if (!zn_backend_get_xr_system(server->backend)) { + zn_backend_set_xr_system(server->backend, self->zn_xr_system); + } status = ZEN_XR_SYSTEM_STATUS_CONNECTED; break; - case ZN_XR_SYSTEM_SESSION_STATUS_NOT_CONNECTED: + case ZN_XR_SYSTEM_SESSION_STATE_DEAD: status = ZEN_XR_SYSTEM_STATUS_UNAVAILABLE; break; + case ZN_XR_SYSTEM_SESSION_STATE_VISIBLE: // fallthrough + case ZN_XR_SYSTEM_SESSION_STATE_FOCUS: + return; } - wl_resource_for_each (resource, &self->resource_list) { - zen_xr_system_send_status(resource, status); + if (self->status != status) { + self->status = status; + wl_resource_for_each (resource, &self->resource_list) { + zen_xr_system_send_status(resource, status); + } } } @@ -93,6 +109,7 @@ zn_desktop_xr_system_create( } self->zn_xr_system = zn_xr_system; + self->status = ZEN_XR_SYSTEM_STATUS_AVAILABLE; wl_list_init(&self->resource_list); self->global = wl_global_create( @@ -107,10 +124,10 @@ zn_desktop_xr_system_create( wl_signal_add( &zn_xr_system->events.destroy, &self->zn_xr_system_destroy_listener); - self->session_status_changed_listener.notify = - zn_desktop_xr_system_handle_session_status_changed; - wl_signal_add(&zn_xr_system->events.session_status_changed, - &self->session_status_changed_listener); + self->session_state_changed_listener.notify = + zn_desktop_xr_system_handle_session_state_changed; + wl_signal_add(&zn_xr_system->events.session_state_changed, + &self->session_state_changed_listener); return self; @@ -124,7 +141,7 @@ zn_desktop_xr_system_create( static void zn_desktop_xr_system_destroy(struct zn_desktop_xr_system *self) { - wl_list_remove(&self->session_status_changed_listener.link); + wl_list_remove(&self->session_state_changed_listener.link); wl_list_remove(&self->zn_xr_system_destroy_listener.link); wl_global_destroy(self->global); wl_list_remove(&self->resource_list); diff --git a/zen/include/zen/backend.h b/zen/include/zen/backend.h index 4d73de30..f51ef9b5 100644 --- a/zen/include/zen/backend.h +++ b/zen/include/zen/backend.h @@ -16,6 +16,8 @@ struct zn_backend_interface { /// @param xr_system is nullable void (*set_xr_system)( struct zn_backend *self, struct zn_xr_system *xr_system); + /// @return value can be NULL + struct zn_xr_system *(*get_xr_system)(struct zn_backend *self); /// Starts monitoring the connection or disconnection of input/output devices. bool (*start)(struct zn_backend *self); /// Destroy input/output devices @@ -67,3 +69,9 @@ zn_backend_set_xr_system( { self->impl->set_xr_system(self, xr_system); } + +UNUSED static inline struct zn_xr_system * +zn_backend_get_xr_system(struct zn_backend *self) +{ + return self->impl->get_xr_system(self); +} diff --git a/zen/include/zen/virtual-object.h b/zen/include/zen/virtual-object.h new file mode 100644 index 00000000..7acd63ff --- /dev/null +++ b/zen/include/zen/virtual-object.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "zen-common/util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_virtual_object { + void *impl_data; // @nullable, @outlive if exists + + struct { + struct wl_signal destroy; + } events; +}; + +/// Called by impl object +struct zn_virtual_object *zn_virtual_object_create(void *impl_data); + +/// Can be called by impl object +void zn_virtual_object_destroy(struct zn_virtual_object *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index 6881e009..a9878ccd 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -2,6 +2,43 @@ #include +#include "zen-common/util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_xr_dispatcher; + +struct zn_xr_dispatcher_interface { + struct zn_virtual_object *(*get_new_virtual_object)( + struct zn_xr_dispatcher *self); + void (*destroy_virtual_object)( + struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object); +}; + struct zn_xr_dispatcher { void *impl_data; + const struct zn_xr_dispatcher_interface *impl; + + struct { + struct wl_signal destroy; + } events; }; + +UNUSED static inline struct zn_virtual_object * +zn_xr_dispatcher_get_new_virtual_object(struct zn_xr_dispatcher *self) +{ + return self->impl->get_new_virtual_object(self); +} + +UNUSED static inline void +zn_xr_dispatcher_destroy_virtual_object( + struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object) +{ + self->impl->destroy_virtual_object(self, virtual_object); +} + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/xr-system.h b/zen/include/zen/xr-system.h index a6c5868e..504690d8 100644 --- a/zen/include/zen/xr-system.h +++ b/zen/include/zen/xr-system.h @@ -15,22 +15,39 @@ struct zn_xr_system_interface { void (*connect)(struct zn_xr_system *self); }; -enum zn_xr_system_session_status { - ZN_XR_SYSTEM_SESSION_STATUS_NOT_CONNECTED, // initial status - ZN_XR_SYSTEM_SESSION_STATUS_CONNECTED, +/// +/// create +/// ↓ +/// available --→ dead → destroy +/// ↓↑ ↑ +/// synchronized ---+ +/// ↓↑ +/// visible +/// ↓↑ +/// focus +/// +/// connected = synchronized | visible | focus +/// +enum zn_xr_system_session_state { + ZN_XR_SYSTEM_SESSION_STATE_AVAILABLE, + ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED, + ZN_XR_SYSTEM_SESSION_STATE_VISIBLE, + ZN_XR_SYSTEM_SESSION_STATE_FOCUS, + ZN_XR_SYSTEM_SESSION_STATE_DEAD, }; struct zn_xr_system { void *impl_data; // @outlive const struct zn_xr_system_interface *impl; // @nonnull, @outlive - enum zn_xr_system_session_status status; + enum zn_xr_system_session_state state; - struct zn_xr_dispatcher *high_priority_dispatcher; // @nonnull, @owning - struct zn_xr_dispatcher *default_dispatcher; // @nonnull, @owning + /// These dispatchers are null when connected, not null otherwise. + struct zn_xr_dispatcher *high_priority_dispatcher; // @owning + struct zn_xr_dispatcher *default_dispatcher; // @owning struct { - struct wl_signal session_status_changed; // (NULL) + struct wl_signal session_state_changed; // (NULL) struct wl_signal destroy; } events; }; @@ -41,6 +58,15 @@ zn_xr_system_connect(struct zn_xr_system *self) self->impl->connect(self); } +UNUSED static inline bool +zn_xr_system_is_connected(struct zn_xr_system *self) +{ + uint32_t connected = ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED | + ZN_XR_SYSTEM_SESSION_STATE_VISIBLE | + ZN_XR_SYSTEM_SESSION_STATE_FOCUS; + return (self->state & connected) != 0; +} + #ifdef __cplusplus } #endif diff --git a/zen/meson.build b/zen/meson.build index 4756bdfa..4204fdac 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -6,6 +6,8 @@ _zen_srcs = [ 'src/server.c', 'src/snode.c', 'src/view.c', + 'src/virtual-object.c', + 'src/xr-dispatcher.c', ] zen_inc = include_directories('include') diff --git a/zen/src/backend/default-backend.c b/zen/src/backend/default-backend.c index a7b94a4c..fc4eec8b 100644 --- a/zen/src/backend/default-backend.c +++ b/zen/src/backend/default-backend.c @@ -171,7 +171,9 @@ zn_default_backend_handle_xr_compositor_destroy( struct zn_default_backend *self = zn_container_of(listener, self, xr_compositor_destroy_listener); - zn_default_backend_set_xr_system(self, NULL); + wl_list_remove(&self->xr_compositor_destroy_listener.link); + wl_list_init(&self->xr_compositor_destroy_listener.link); + self->xr_compositor = NULL; } static struct wlr_texture * @@ -197,6 +199,13 @@ zn_default_backend_handle_set_xr_system( zn_default_backend_set_xr_system(self, xr_system); } +static struct zn_xr_system * +zn_default_backend_handle_get_xr_system(struct zn_backend *base) +{ + struct zn_default_backend *self = zn_container_of(base, self, base); + return self->xr_compositor ? self->xr_compositor->xr_system : NULL; +} + static bool zn_default_backend_start(struct zn_backend *base) { @@ -223,6 +232,7 @@ static const struct zn_backend_interface implementation = { .create_wlr_texture_from_pixels = zn_default_backend_create_wlr_texture_from_pixels, .set_xr_system = zn_default_backend_handle_set_xr_system, + .get_xr_system = zn_default_backend_handle_get_xr_system, .start = zn_default_backend_start, .stop = zn_default_backend_stop, .destroy = zn_default_backend_handle_destroy, diff --git a/zen/src/backend/immersive/client-virtual-object.c b/zen/src/backend/immersive/client-virtual-object.c new file mode 100644 index 00000000..984518c1 --- /dev/null +++ b/zen/src/backend/immersive/client-virtual-object.c @@ -0,0 +1,129 @@ +#include "client-virtual-object.h" + +#include + +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/virtual-object.h" +#include "zen/xr-dispatcher.h" + +static void zn_client_virtual_object_destroy( + struct zn_client_virtual_object *self); + +static void +zn_client_virtual_object_handle_destroy(struct wl_resource *resource) +{ + struct zn_client_virtual_object *self = wl_resource_get_user_data(resource); + + zn_client_virtual_object_destroy(self); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_virtual_object_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_virtual_object_protocol_commit( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_virtual_object_protocol_frame(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t callback UNUSED) +{} + +static const struct zwn_virtual_object_interface implementation = { + .destroy = zn_client_virtual_object_protocol_destroy, + .commit = zn_client_virtual_object_protocol_commit, + .frame = zn_client_virtual_object_protocol_frame, +}; + +static void +zn_client_virtual_object_handle_dispatcher_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_virtual_object *self = + zn_container_of(listener, self, dispatcher_destroy_listener); + + zn_client_virtual_object_destroy(self); +} + +static void +zn_client_virtual_object_handle_zn_virtual_object_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_virtual_object *self = + zn_container_of(listener, self, zn_virtual_object_destroy_listener); + + zn_client_virtual_object_destroy(self); +} + +struct zn_client_virtual_object * +zn_client_virtual_object_create( + struct wl_client *client, uint32_t id, struct zn_xr_dispatcher *dispatcher) +{ + struct zn_client_virtual_object *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->dispatcher = dispatcher; + + self->zn_virtual_object = zn_xr_dispatcher_get_new_virtual_object(dispatcher); + if (self->zn_virtual_object == NULL) { + zn_error("Failed to get new zn_virtual_object"); + wl_client_post_no_memory(client); + goto err_free; + } + + self->resource = + wl_resource_create(client, &zwn_virtual_object_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_zn_virtual_object; + } + + wl_resource_set_implementation(self->resource, &implementation, self, + &zn_client_virtual_object_handle_destroy); + + self->zn_virtual_object_destroy_listener.notify = + zn_client_virtual_object_handle_zn_virtual_object_destroy; + wl_signal_add(&self->zn_virtual_object->events.destroy, + &self->zn_virtual_object_destroy_listener); + + self->dispatcher_destroy_listener.notify = + zn_client_virtual_object_handle_dispatcher_destroy; + wl_signal_add( + &self->dispatcher->events.destroy, &self->dispatcher_destroy_listener); + + return self; + +err_zn_virtual_object: + zn_xr_dispatcher_destroy_virtual_object(dispatcher, self->zn_virtual_object); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_client_virtual_object_destroy(struct zn_client_virtual_object *self) +{ + wl_list_remove(&self->zn_virtual_object_destroy_listener.link); + wl_list_remove(&self->dispatcher_destroy_listener.link); + zn_xr_dispatcher_destroy_virtual_object( + self->dispatcher, self->zn_virtual_object); + wl_resource_set_implementation( + self->resource, &zwn_virtual_object_interface, NULL, NULL); + free(self); +} diff --git a/zen/src/backend/immersive/client-virtual-object.h b/zen/src/backend/immersive/client-virtual-object.h new file mode 100644 index 00000000..d1e006a3 --- /dev/null +++ b/zen/src/backend/immersive/client-virtual-object.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +struct zn_virtual_object; +struct zn_xr_dispatcher; + +struct zn_client_virtual_object { + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_xr_dispatcher *dispatcher; // @nonnull, @outlive + + struct zn_virtual_object *zn_virtual_object; // @nonnull, @outlive + + struct wl_listener dispatcher_destroy_listener; + struct wl_listener zn_virtual_object_destroy_listener; +}; + +struct zn_client_virtual_object *zn_client_virtual_object_create( + struct wl_client *client, uint32_t id, struct zn_xr_dispatcher *dispatcher); diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index 2213aa67..5ec707d4 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -1,5 +1,6 @@ _zen_remote_immersive_backend_srcs = [ 'loop.cc', + 'virtual-object.cc', 'xr-dispatcher.cc', 'xr-system.cc', 'xr-system-manager.cc', diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index 17478b95..2f80331b 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff --git a/zen/src/backend/immersive/remote/virtual-object.cc b/zen/src/backend/immersive/remote/virtual-object.cc new file mode 100644 index 00000000..d329cc6e --- /dev/null +++ b/zen/src/backend/immersive/remote/virtual-object.cc @@ -0,0 +1,50 @@ +#include "virtual-object.h" + +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +VirtualObject::~VirtualObject() +{ + if (c_obj_ != nullptr) { + zn_virtual_object_destroy(c_obj_); + } +} + +std::unique_ptr +VirtualObject::New(std::shared_ptr channel) +{ + auto self = std::unique_ptr(new VirtualObject()); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(channel))) { + zn_error("Failed to initialize a remote VirtualObject"); + return nullptr; + } + + return self; +} + +bool +VirtualObject::Init(std::shared_ptr channel) +{ + c_obj_ = zn_virtual_object_create(this); + if (c_obj_ == nullptr) { + zn_error("Failed to create a zn_virtual_object"); + return false; + } + + remote_obj_ = zen::remote::server::CreateVirtualObject(std::move(channel)); + if (!remote_obj_) { + zn_error("Failed to create a remote Virtual Object"); + zn_virtual_object_destroy(c_obj_); + return false; + } + + return true; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/virtual-object.h b/zen/src/backend/immersive/remote/virtual-object.h new file mode 100644 index 00000000..b2d3adba --- /dev/null +++ b/zen/src/backend/immersive/remote/virtual-object.h @@ -0,0 +1,35 @@ +#pragma once + +#include "zen-common/cpp-util.h" +#include "zen/virtual-object.h" + +namespace zen::backend::immersive::remote { + +class VirtualObject +{ + public: + DISABLE_MOVE_AND_COPY(VirtualObject); + ~VirtualObject(); + + static std::unique_ptr New( + std::shared_ptr channel); + + inline zn_virtual_object *c_obj(); + + private: + VirtualObject() = default; + + bool Init(std::shared_ptr channel); + + std::unique_ptr remote_obj_; + + zn_virtual_object *c_obj_ = nullptr; // @nonnull after Init(), @owning +}; + +inline zn_virtual_object * +VirtualObject::c_obj() +{ + return c_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index 20b102b6..dd14f101 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -2,10 +2,23 @@ #include +#include "virtual-object.h" #include "zen-common/log.h" namespace zen::backend::immersive::remote { +const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { + XrDispatcher::HandleGetNewVirtualObject, + XrDispatcher::HandleDestroyVirtualObject, +}; + +XrDispatcher::~XrDispatcher() +{ + if (c_obj_ != nullptr) { + zn_xr_dispatcher_destroy(c_obj_); + } +} + std::unique_ptr XrDispatcher::New(std::shared_ptr session) { @@ -26,15 +39,53 @@ XrDispatcher::New(std::shared_ptr session) bool XrDispatcher::Init(std::shared_ptr session) { + c_obj_ = zn_xr_dispatcher_create(this, &c_implementation_); + if (c_obj_ == nullptr) { + zn_error("Failed to create zn_xr_dispatcher"); + return false; + } + channel_ = zen::remote::server::CreateChannel(session); if (!channel_) { zn_error("Failed to create a remote channel"); + zn_xr_dispatcher_destroy(c_obj_); return false; } - c_obj_.impl_data = this; - return true; } +zn_virtual_object * +XrDispatcher::HandleGetNewVirtualObject(zn_xr_dispatcher *c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto virtual_object = VirtualObject::New(self->channel_); + if (!virtual_object) { + zn_error("Failed to create a remote virtual object"); + return nullptr; + } + + auto *virtual_object_c_obj = virtual_object->c_obj(); + + self->virtual_objects_.push_back(std::move(virtual_object)); + + return virtual_object_c_obj; +} + +void +XrDispatcher::HandleDestroyVirtualObject( + zn_xr_dispatcher *c_obj, zn_virtual_object *virtual_object_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto result = std::remove_if(self->virtual_objects_.begin(), + self->virtual_objects_.end(), + [virtual_object_c_obj](std::unique_ptr &virtual_object) { + return virtual_object->c_obj() == virtual_object_c_obj; + }); + + self->virtual_objects_.erase(result, self->virtual_objects_.end()); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index b6499037..11c35da6 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -1,15 +1,17 @@ #pragma once +#include "xr-dispatcher-private.h" #include "zen-common/cpp-util.h" -#include "zen/xr-dispatcher.h" namespace zen::backend::immersive::remote { +class VirtualObject; + class XrDispatcher { public: DISABLE_MOVE_AND_COPY(XrDispatcher); - ~XrDispatcher() = default; + ~XrDispatcher(); static std::unique_ptr New( std::shared_ptr session); @@ -21,15 +23,24 @@ class XrDispatcher bool Init(std::shared_ptr session); + static zn_virtual_object *HandleGetNewVirtualObject(zn_xr_dispatcher *c_obj); + + static void HandleDestroyVirtualObject( + zn_xr_dispatcher *c_obj, zn_virtual_object *virtual_object_c_obj); + std::shared_ptr channel_; - zn_xr_dispatcher c_obj_{}; + std::vector> virtual_objects_; + + static const zn_xr_dispatcher_interface c_implementation_; + + zn_xr_dispatcher *c_obj_ = nullptr; // @nonnull after Init(), @owning }; inline zn_xr_dispatcher * XrDispatcher::c_obj() { - return &c_obj_; + return c_obj_; } } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-system-manager.cc b/zen/src/backend/immersive/remote/xr-system-manager.cc index 141e2e8e..f04de3a2 100644 --- a/zen/src/backend/immersive/remote/xr-system-manager.cc +++ b/zen/src/backend/immersive/remote/xr-system-manager.cc @@ -65,7 +65,7 @@ XrSystemManager::HandleRemotePeerDiscover(uint64_t peer_id) std::for_each(xr_systems_.begin(), xr_systems_.end(), [peer_id](std::unique_ptr &xr_system) { if (xr_system->peer_id() == peer_id) { - xr_system->set_unavailable(); + xr_system->Kill(); } }); RemoveDeadXrSystem(); @@ -89,8 +89,8 @@ XrSystemManager::HandleRemotePeerLost(uint64_t peer_id) { std::for_each(xr_systems_.begin(), xr_systems_.end(), [peer_id](std::unique_ptr &xr_system) { - if (xr_system->peer_id() == peer_id) { - xr_system->set_unavailable(); + if (xr_system->peer_id() == peer_id && !xr_system->is_connected()) { + xr_system->Kill(); } }); RemoveDeadXrSystem(); diff --git a/zen/src/backend/immersive/remote/xr-system.cc b/zen/src/backend/immersive/remote/xr-system.cc index 7fd0e439..398336b0 100644 --- a/zen/src/backend/immersive/remote/xr-system.cc +++ b/zen/src/backend/immersive/remote/xr-system.cc @@ -1,9 +1,11 @@ #include "xr-system.h" #include "loop.h" +#include "virtual-object.h" #include "xr-dispatcher.h" #include "xr-system-manager.h" #include "zen-common/log.h" +#include "zen-common/signal.h" namespace zen::backend::immersive::remote { @@ -14,7 +16,10 @@ XrSystem::XrSystem(std::shared_ptr peer, xr_system_manager_(xr_system_manager) {} -XrSystem::~XrSystem() { wl_signal_emit(&c_obj_.events.destroy, nullptr); } +XrSystem::~XrSystem() +{ + zn_signal_emit_mutable(&c_obj_.events.destroy, nullptr); +} std::unique_ptr XrSystem::New(std::shared_ptr peer, @@ -38,24 +43,10 @@ XrSystem::New(std::shared_ptr peer, bool XrSystem::Init() { - high_priority_dispatcher_ = XrDispatcher::New(session_); - if (!high_priority_dispatcher_) { - zn_error("Failed to create a remote XrDispatcher"); - return false; - } - - default_dispatcher_ = XrDispatcher::New(session_); - if (!default_dispatcher_) { - zn_error("Failed to create a remote XrDispatcher"); - return false; - } - c_obj_.impl_data = this; c_obj_.impl = &c_implementation_; - c_obj_.status = ZN_XR_SYSTEM_SESSION_STATUS_NOT_CONNECTED; - c_obj_.high_priority_dispatcher = high_priority_dispatcher_->c_obj(); - c_obj_.default_dispatcher = default_dispatcher_->c_obj(); - wl_signal_init(&c_obj_.events.session_status_changed); + c_obj_.state = ZN_XR_SYSTEM_SESSION_STATE_AVAILABLE; + wl_signal_init(&c_obj_.events.session_state_changed); wl_signal_init(&c_obj_.events.destroy); return true; @@ -78,17 +69,49 @@ XrSystem::HandleDisconnect() { zn_info("Disconnected from peer %ld", peer_->id()); - c_obj_.status = ZN_XR_SYSTEM_SESSION_STATUS_NOT_CONNECTED; - - wl_signal_emit(&c_obj_.events.session_status_changed, nullptr); + Kill(); xr_system_manager_->RemoveDeadXrSystem(); // Will destroy this XrSystem } +void +XrSystem::Kill() +{ + if (c_obj_.state == ZN_XR_SYSTEM_SESSION_STATE_AVAILABLE) { + c_obj_.state = ZN_XR_SYSTEM_SESSION_STATE_DEAD; + zn_signal_emit_mutable(&c_obj_.events.session_state_changed, nullptr); + return; + } + + if (c_obj_.state == ZN_XR_SYSTEM_SESSION_STATE_FOCUS) { + c_obj_.state = ZN_XR_SYSTEM_SESSION_STATE_VISIBLE; + zn_signal_emit_mutable(&c_obj_.events.session_state_changed, nullptr); + } + + if (c_obj_.state == ZN_XR_SYSTEM_SESSION_STATE_VISIBLE) { + c_obj_.state = ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED; + zn_signal_emit_mutable(&c_obj_.events.session_state_changed, nullptr); + } + + if (c_obj_.state == ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED) { + c_obj_.state = ZN_XR_SYSTEM_SESSION_STATE_DEAD; + + session_.reset(); + high_priority_dispatcher_.reset(); + default_dispatcher_.reset(); + c_obj_.high_priority_dispatcher = nullptr; + c_obj_.default_dispatcher = nullptr; + + zn_signal_emit_mutable(&c_obj_.events.session_state_changed, nullptr); + } +} + void XrSystem::Connect() { - if (session_) { + if (c_obj_.state != ZN_XR_SYSTEM_SESSION_STATE_AVAILABLE) { + zn_warn("Tried to Connect to %s but the current state(%d) is invalid.", + peer_->host().c_str(), c_obj_.state); return; } @@ -101,17 +124,35 @@ XrSystem::Connect() return; } - zn_info("Connected to peer %ld", peer_->id()); + auto high_priority_dispatcher = XrDispatcher::New(new_session); + if (!high_priority_dispatcher) { + zn_error("Failed to create a remote XrDispatcher"); + } - set_unavailable(); + auto default_dispatcher = XrDispatcher::New(new_session); + if (!default_dispatcher) { + zn_error("Failed to create a remote XrDispatcher"); + } + + zn_info("Connected to peer %ld", peer_->id()); new_session->on_disconnect.Connect([this]() { HandleDisconnect(); }); session_ = new_session; - c_obj_.status = ZN_XR_SYSTEM_SESSION_STATUS_CONNECTED; + c_obj_.state = ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED; + high_priority_dispatcher_ = std::move(high_priority_dispatcher); + default_dispatcher_ = std::move(default_dispatcher); + c_obj_.high_priority_dispatcher = high_priority_dispatcher_->c_obj(); + c_obj_.default_dispatcher = default_dispatcher_->c_obj(); + + zn_signal_emit_mutable(&c_obj_.events.session_state_changed, nullptr); + + c_obj_.state = ZN_XR_SYSTEM_SESSION_STATE_VISIBLE; + zn_signal_emit_mutable(&c_obj_.events.session_state_changed, nullptr); - wl_signal_emit(&c_obj_.events.session_status_changed, nullptr); + c_obj_.state = ZN_XR_SYSTEM_SESSION_STATE_FOCUS; + zn_signal_emit_mutable(&c_obj_.events.session_state_changed, nullptr); } } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-system.h b/zen/src/backend/immersive/remote/xr-system.h index ae44e945..9a4c7d20 100644 --- a/zen/src/backend/immersive/remote/xr-system.h +++ b/zen/src/backend/immersive/remote/xr-system.h @@ -18,14 +18,16 @@ class XrSystem std::shared_ptr peer, wl_display *display, XrSystemManager *xr_system_manager); + void Kill(); + inline uint64_t peer_id() const; inline zn_xr_system *c_obj(); - inline void set_unavailable(); - inline bool is_alive() const; + inline bool is_connected() const; + private: XrSystem(std::shared_ptr peer, wl_display *display, XrSystemManager *xr_system_manager); @@ -46,15 +48,11 @@ class XrSystem XrSystemManager *xr_system_manager_; // @nonnull, @outlive - // Null when status is NOT_CONNECTED. Not null otherwise. + // These objects are null when state is AVAILABLE or DEAD, not null otherwise. std::shared_ptr session_; - std::unique_ptr high_priority_dispatcher_; std::unique_ptr default_dispatcher_; - // True if available to create a new session. - bool is_available_ = true; - zn_xr_system c_obj_{}; }; @@ -70,17 +68,20 @@ XrSystem::c_obj() return &c_obj_; } -inline void -XrSystem::set_unavailable() +inline bool +XrSystem::is_alive() const { - is_available_ = false; + return c_obj_.state != ZN_XR_SYSTEM_SESSION_STATE_DEAD; } inline bool -XrSystem::is_alive() const +XrSystem::is_connected() const { - return is_available_ || - c_obj_.status == ZN_XR_SYSTEM_SESSION_STATUS_CONNECTED; + uint32_t connected = ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED | + ZN_XR_SYSTEM_SESSION_STATE_VISIBLE | + ZN_XR_SYSTEM_SESSION_STATE_FOCUS; + + return (c_obj_.state & connected) != 0; } } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/xr-compositor.c b/zen/src/backend/immersive/xr-compositor.c index 5acc5a44..49f0cd08 100644 --- a/zen/src/backend/immersive/xr-compositor.c +++ b/zen/src/backend/immersive/xr-compositor.c @@ -2,6 +2,7 @@ #include +#include "client-virtual-object.h" #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" @@ -14,19 +15,35 @@ zn_xr_compositor_handle_destroy(struct wl_resource *resource) } static void -zn_xr_compositor_handle_xr_system_destroy( +zn_xr_compositor_handle_xr_system_session_state_changed( struct wl_listener *listener, void *data UNUSED) { struct zn_xr_compositor *self = - zn_container_of(listener, self, xr_system_destroy_listener); + zn_container_of(listener, self, xr_system_session_state_changed_listener); - zn_xr_compositor_destroy(self); + if (!zn_xr_system_is_connected(self->xr_system)) { + zn_xr_compositor_destroy(self); + } } static void -zn_xr_compositor_protocol_create_virtual_object(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, uint32_t id UNUSED) -{} +zn_xr_compositor_protocol_create_virtual_object( + struct wl_client *client, struct wl_resource *resource, uint32_t id) +{ + struct zn_xr_compositor *self = wl_resource_get_user_data(resource); + + if (!zn_assert(self->xr_system->default_dispatcher != NULL, + "xr system must be connected")) { + return; + } + + struct zn_client_virtual_object *virtual_object = + zn_client_virtual_object_create( + client, id, self->xr_system->default_dispatcher); + if (virtual_object == NULL) { + zn_error("Failed to create zn_client_virtual_object"); + } +} static void zn_xr_compositor_protocol_create_region(struct wl_client *client UNUSED, @@ -62,6 +79,11 @@ struct zn_xr_compositor * zn_xr_compositor_create( struct wl_display *display UNUSED, struct zn_xr_system *xr_system) { + if (!zn_assert(zn_xr_system_is_connected(xr_system), + "xr_system must be connected")) { + goto err; + } + struct zn_xr_compositor *self = zalloc(sizeof *self); if (self == NULL) { zn_error("Failed to allocate memory"); @@ -79,9 +101,10 @@ zn_xr_compositor_create( goto err_free; } - self->xr_system_destroy_listener.notify = - zn_xr_compositor_handle_xr_system_destroy; - wl_signal_add(&xr_system->events.destroy, &self->xr_system_destroy_listener); + self->xr_system_session_state_changed_listener.notify = + zn_xr_compositor_handle_xr_system_session_state_changed; + wl_signal_add(&xr_system->events.session_state_changed, + &self->xr_system_session_state_changed_listener); return self; @@ -99,7 +122,7 @@ zn_xr_compositor_destroy(struct zn_xr_compositor *self) wl_global_destroy(self->global); wl_list_remove(&self->resource_list); - wl_list_remove(&self->xr_system_destroy_listener.link); + wl_list_remove(&self->xr_system_session_state_changed_listener.link); wl_list_remove(&self->events.destroy.listener_list); free(self); } diff --git a/zen/src/backend/immersive/xr-compositor.h b/zen/src/backend/immersive/xr-compositor.h index 9ad67b9b..06dce597 100644 --- a/zen/src/backend/immersive/xr-compositor.h +++ b/zen/src/backend/immersive/xr-compositor.h @@ -3,9 +3,10 @@ #include struct zn_xr_compositor { + // must be connected state struct zn_xr_system *xr_system; // @nonnull, @outlive - struct wl_listener xr_system_destroy_listener; + struct wl_listener xr_system_session_state_changed_listener; struct wl_global *global; // @nonnull, @owning @@ -16,6 +17,7 @@ struct zn_xr_compositor { } events; }; +/// @param xr_system must be in connected state struct zn_xr_compositor *zn_xr_compositor_create( struct wl_display *display, struct zn_xr_system *xr_system); diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 027ee0ff..7cbd46a1 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -3,6 +3,7 @@ subdir('immersive/remote') _zen_backend_srcs = [ 'default-backend.c', + 'immersive/client-virtual-object.c', 'immersive/xr.c', 'immersive/xr-compositor.c', diff --git a/zen/src/virtual-object.c b/zen/src/virtual-object.c new file mode 100644 index 00000000..40f7d73f --- /dev/null +++ b/zen/src/virtual-object.c @@ -0,0 +1,32 @@ +#include "zen/virtual-object.h" + +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_virtual_object * +zn_virtual_object_create(void *impl_data) +{ + struct zn_virtual_object *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_virtual_object_destroy(struct zn_virtual_object *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} diff --git a/zen/src/xr-dispatcher-private.h b/zen/src/xr-dispatcher-private.h new file mode 100644 index 00000000..796654ce --- /dev/null +++ b/zen/src/xr-dispatcher-private.h @@ -0,0 +1,16 @@ +#pragma once + +#include "zen/xr-dispatcher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_xr_dispatcher *zn_xr_dispatcher_create( + void *impl_data, const struct zn_xr_dispatcher_interface *implementation); + +void zn_xr_dispatcher_destroy(struct zn_xr_dispatcher *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/xr-dispatcher.c b/zen/src/xr-dispatcher.c new file mode 100644 index 00000000..99862f7e --- /dev/null +++ b/zen/src/xr-dispatcher.c @@ -0,0 +1,34 @@ +#include "xr-dispatcher-private.h" +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_xr_dispatcher * +zn_xr_dispatcher_create( + void *impl_data, const struct zn_xr_dispatcher_interface *implementation) +{ + struct zn_xr_dispatcher *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + self->impl = implementation; + + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_xr_dispatcher_destroy(struct zn_xr_dispatcher *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} diff --git a/zen/tests/mock/src/backend.c b/zen/tests/mock/src/backend.c index b932bac9..504f1170 100644 --- a/zen/tests/mock/src/backend.c +++ b/zen/tests/mock/src/backend.c @@ -24,6 +24,12 @@ zn_mock_backend_set_xr_system( struct zn_backend *base UNUSED, struct zn_xr_system *xr_system UNUSED) {} +static struct zn_xr_system * +zn_mock_backend_get_xr_system(struct zn_backend *base UNUSED) +{ + return NULL; +} + static bool zn_mock_backend_start(struct zn_backend *base UNUSED) { @@ -45,6 +51,7 @@ static const struct zn_backend_interface implementation = { .create_wlr_texture_from_pixels = zn_mock_backend_create_wlr_texture_from_pixels, .set_xr_system = zn_mock_backend_set_xr_system, + .get_xr_system = zn_mock_backend_get_xr_system, .start = zn_mock_backend_start, .stop = zn_mock_backend_stop, .destroy = zn_mock_backend_handle_destroy, From 2ef3347778d262f0bccf757b98a0635db1180dff Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Thu, 13 Apr 2023 22:47:00 +0900 Subject: [PATCH 11/49] zwn_gl global object --- .clang-tidy | 1 + LICENSE | 2 +- protocol/meson.build | 1 + zen/src/backend/immersive/xr-gl.c | 73 +++++++++++++++++++++++++++++++ zen/src/backend/immersive/xr-gl.h | 11 +++++ zen/src/backend/immersive/xr.c | 11 +++++ zen/src/backend/immersive/xr.h | 3 ++ zen/src/backend/meson.build | 3 ++ 8 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 zen/src/backend/immersive/xr-gl.c create mode 100644 zen/src/backend/immersive/xr-gl.h diff --git a/.clang-tidy b/.clang-tidy index ff07404d..eba4f37e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -12,6 +12,7 @@ Checks: " cppcoreguidelines-*, -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-type-vararg, -cppcoreguidelines-macro-usage, diff --git a/LICENSE b/LICENSE index 308dad92..2ce7cd3b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Akihiro Kiuchi & Taishi Eguchi +Copyright (c) 2023 Zwin Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/protocol/meson.build b/protocol/meson.build index f1841e1b..4ae929eb 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -13,6 +13,7 @@ protocols = { 'zen-desktop': zen_protocol_dir / 'unstable/zen-desktop.xml', 'zwin': zwin_protocol_dir / 'zwin.xml', + 'zwin-gl': zwin_protocol_dir / 'zwin-gl.xml', 'wlr-layer-shell-unstable-v1': 'wlr-layer-shell-unstable-v1.xml', } diff --git a/zen/src/backend/immersive/xr-gl.c b/zen/src/backend/immersive/xr-gl.c new file mode 100644 index 00000000..257b0ebf --- /dev/null +++ b/zen/src/backend/immersive/xr-gl.c @@ -0,0 +1,73 @@ +#include "xr-gl.h" + +#include + +#include "zen-common/log.h" +#include "zen-common/util.h" + +static void +zn_xr_gl_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +zn_xr_gl_protocol_create_gl_context(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED, + struct wl_resource *zwn_compositor UNUSED) +{} + +static const struct zwn_gl_interface implementation = { + .destroy = zn_xr_gl_protocol_destroy, + .create_gl_context = zn_xr_gl_protocol_create_gl_context, +}; + +static void +zn_xr_gl_bind( + struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + struct zn_xr_gl *self = data; + + struct wl_resource *resource = + wl_resource_create(client, &zwn_gl_interface, (int)version, id); + if (resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &implementation, self, NULL); +} + +struct zn_xr_gl * +zn_xr_gl_create(struct wl_display *display) +{ + struct zn_xr_gl *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->global = + wl_global_create(display, &zwn_gl_interface, 1, self, zn_xr_gl_bind); + if (self->global == NULL) { + zn_error("Failed to create zwn_gl global"); + goto err_free; + } + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +void +zn_xr_gl_destroy(struct zn_xr_gl *self) +{ + wl_global_destroy(self->global); + free(self); +} diff --git a/zen/src/backend/immersive/xr-gl.h b/zen/src/backend/immersive/xr-gl.h new file mode 100644 index 00000000..584ea5aa --- /dev/null +++ b/zen/src/backend/immersive/xr-gl.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct zn_xr_gl { + struct wl_global *global; +}; + +struct zn_xr_gl *zn_xr_gl_create(struct wl_display *display); + +void zn_xr_gl_destroy(struct zn_xr_gl *self); diff --git a/zen/src/backend/immersive/xr.c b/zen/src/backend/immersive/xr.c index 92a3e06e..c82f6dcd 100644 --- a/zen/src/backend/immersive/xr.c +++ b/zen/src/backend/immersive/xr.c @@ -1,5 +1,6 @@ #include "xr.h" +#include "xr-gl.h" #include "xr-system-manager.h" #include "zen-common/log.h" #include "zen-common/util.h" @@ -19,8 +20,17 @@ zn_xr_create(struct wl_display *display) goto err_free; } + self->xr_gl = zn_xr_gl_create(display); + if (self->xr_gl == NULL) { + zn_error("Failed to create zn_xr_gl"); + goto err_free_system_manager; + } + return self; +err_free_system_manager: + zn_xr_system_manager_destroy(self->xr_system_manager); + err_free: free(self); @@ -31,6 +41,7 @@ zn_xr_create(struct wl_display *display) void zn_xr_destroy(struct zn_xr *self) { + zn_xr_gl_destroy(self->xr_gl); zn_xr_system_manager_destroy(self->xr_system_manager); free(self); } diff --git a/zen/src/backend/immersive/xr.h b/zen/src/backend/immersive/xr.h index d8b102a8..8066a7d6 100644 --- a/zen/src/backend/immersive/xr.h +++ b/zen/src/backend/immersive/xr.h @@ -3,9 +3,12 @@ #include struct zn_xr_system_manager; +struct zn_xr_gl; struct zn_xr { struct zn_xr_system_manager *xr_system_manager; // @nonnull, @owning + + struct zn_xr_gl *xr_gl; // @nonnull, @owning }; struct zn_xr *zn_xr_create(struct wl_display *display); diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 7cbd46a1..c48f0f7e 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -6,6 +6,7 @@ _zen_backend_srcs = [ 'immersive/client-virtual-object.c', 'immersive/xr.c', 'immersive/xr-compositor.c', + 'immersive/xr-gl.c', 'screen/compositor.c', 'screen/keyboard.c', @@ -18,6 +19,8 @@ _zen_backend_srcs = [ protocols_code['zwin'], protocols_server_header['zwin'], + protocols_code['zwin-gl'], + protocols_server_header['zwin-gl'], ] _zen_backend_deps = [ From 0cc73a7526c4fba0fd7ab3ec379ba74fb09dc6d6 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Thu, 13 Apr 2023 23:39:32 +0900 Subject: [PATCH 12/49] add zn_client_gl_context --- zen/src/backend/immersive/client-gl-context.c | 147 ++++++++++++++++++ zen/src/backend/immersive/client-gl-context.h | 19 +++ zen/src/backend/immersive/xr-gl.c | 14 +- zen/src/backend/immersive/xr-gl.h | 2 +- zen/src/backend/meson.build | 1 + 5 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 zen/src/backend/immersive/client-gl-context.c create mode 100644 zen/src/backend/immersive/client-gl-context.h diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c new file mode 100644 index 00000000..94156018 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-context.c @@ -0,0 +1,147 @@ +#include "client-gl-context.h" + +#include +#include + +#include "xr-compositor.h" +#include "zen-common/log.h" +#include "zen-common/util.h" + +static void +zn_client_gl_context_handle_destroy(struct wl_resource *resource) +{ + struct zn_client_gl_context *self = wl_resource_get_user_data(resource); + + zn_client_gl_context_destroy(self); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_context_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_context_protocol_create_rendering_unit( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + uint32_t id UNUSED, struct wl_resource *virtual_object UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_context_protocol_create_gl_buffer(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_context_protocol_create_gl_shader(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED, + struct wl_resource *buffer UNUSED, uint32_t type UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_context_protocol_create_gl_program(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_context_protocol_create_gl_texture(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_context_protocol_create_gl_sampler(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_context_protocol_create_gl_vertex_array( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + uint32_t id UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_context_protocol_create_gl_base_technique( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + uint32_t id UNUSED, struct wl_resource *unit UNUSED) +{} + +static const struct zwn_gl_context_interface implementation = { + .destroy = zn_client_gl_context_protocol_destroy, + .create_rendering_unit = + zn_client_gl_context_protocol_create_rendering_unit, + .create_gl_buffer = zn_client_gl_context_protocol_create_gl_buffer, + .create_gl_shader = zn_client_gl_context_protocol_create_gl_shader, + .create_gl_program = zn_client_gl_context_protocol_create_gl_program, + .create_gl_texture = zn_client_gl_context_protocol_create_gl_texture, + .create_gl_sampler = zn_client_gl_context_protocol_create_gl_sampler, + .create_gl_vertex_array = + zn_client_gl_context_protocol_create_gl_vertex_array, + .create_gl_base_technique = + zn_client_gl_context_protocol_create_gl_base_technique, +}; + +static void +zn_client_gl_context_handle_xr_compositor_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_context *self = + zn_container_of(listener, self, xr_compositor_destroy_listener); + + zn_client_gl_context_destroy(self); +} + +struct zn_client_gl_context * +zn_client_gl_context_create(struct wl_client *client, uint32_t id, + struct zn_xr_compositor *xr_compositor) +{ + struct zn_client_gl_context *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->xr_compositor = xr_compositor; + + self->resource = wl_resource_create(client, &zwn_gl_context_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_free; + } + + wl_resource_set_implementation(self->resource, &implementation, self, + zn_client_gl_context_handle_destroy); + + self->xr_compositor_destroy_listener.notify = + zn_client_gl_context_handle_xr_compositor_destroy; + wl_signal_add(&self->xr_compositor->events.destroy, + &self->xr_compositor_destroy_listener); + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +void +zn_client_gl_context_destroy(struct zn_client_gl_context *self) +{ + zwn_gl_context_send_destroyed(self->resource); + + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); + wl_list_remove(&self->xr_compositor_destroy_listener.link); + free(self); +} diff --git a/zen/src/backend/immersive/client-gl-context.h b/zen/src/backend/immersive/client-gl-context.h new file mode 100644 index 00000000..92bed0c7 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-context.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +struct zn_xr_compositor; + +struct zn_client_gl_context { + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_xr_compositor *xr_compositor; // @nonnull, @outlive + + struct wl_listener xr_compositor_destroy_listener; +}; + +struct zn_client_gl_context *zn_client_gl_context_create( + struct wl_client *client, uint32_t id, + struct zn_xr_compositor *xr_compositor); + +void zn_client_gl_context_destroy(struct zn_client_gl_context *self); diff --git a/zen/src/backend/immersive/xr-gl.c b/zen/src/backend/immersive/xr-gl.c index 257b0ebf..e5688f28 100644 --- a/zen/src/backend/immersive/xr-gl.c +++ b/zen/src/backend/immersive/xr-gl.c @@ -2,6 +2,7 @@ #include +#include "client-gl-context.h" #include "zen-common/log.h" #include "zen-common/util.h" @@ -13,10 +14,15 @@ zn_xr_gl_protocol_destroy( } static void -zn_xr_gl_protocol_create_gl_context(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, uint32_t id UNUSED, - struct wl_resource *zwn_compositor UNUSED) -{} +zn_xr_gl_protocol_create_gl_context(struct wl_client *client, + struct wl_resource *resource UNUSED, uint32_t id, + struct wl_resource *zwn_compositor) +{ + struct zn_xr_compositor *xr_compositor = + wl_resource_get_user_data(zwn_compositor); + + zn_client_gl_context_create(client, id, xr_compositor); +} static const struct zwn_gl_interface implementation = { .destroy = zn_xr_gl_protocol_destroy, diff --git a/zen/src/backend/immersive/xr-gl.h b/zen/src/backend/immersive/xr-gl.h index 584ea5aa..11bfe977 100644 --- a/zen/src/backend/immersive/xr-gl.h +++ b/zen/src/backend/immersive/xr-gl.h @@ -3,7 +3,7 @@ #include struct zn_xr_gl { - struct wl_global *global; + struct wl_global *global; // @nonnull, @owning }; struct zn_xr_gl *zn_xr_gl_create(struct wl_display *display); diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index c48f0f7e..1cdef133 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -3,6 +3,7 @@ subdir('immersive/remote') _zen_backend_srcs = [ 'default-backend.c', + 'immersive/client-gl-context.c', 'immersive/client-virtual-object.c', 'immersive/xr.c', 'immersive/xr-compositor.c', From ecb9747e668dac3c7cde8acb29f8a580b140742e Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 15 Apr 2023 15:29:40 +0900 Subject: [PATCH 13/49] add gl_rendering_unit --- zen/include/zen/gl-rendering-unit.h | 19 +++ zen/include/zen/virtual-object.h | 6 - zen/include/zen/xr-dispatcher.h | 21 ++++ zen/meson.build | 1 + zen/src/backend/immersive/client-gl-context.c | 18 ++- .../immersive/client-gl-rendering-unit.c | 117 ++++++++++++++++++ .../immersive/client-gl-rendering-unit.h | 21 ++++ .../backend/immersive/client-virtual-object.c | 8 +- .../backend/immersive/client-virtual-object.h | 4 + .../immersive/remote/gl-rendering-unit.cc | 55 ++++++++ .../immersive/remote/gl-rendering-unit.h | 39 ++++++ zen/src/backend/immersive/remote/meson.build | 1 + zen/src/backend/immersive/remote/pch/pch.h | 1 + .../immersive/remote/virtual-object.cc | 1 + .../backend/immersive/remote/virtual-object.h | 9 +- .../backend/immersive/remote/xr-dispatcher.cc | 44 +++++++ .../backend/immersive/remote/xr-dispatcher.h | 9 ++ zen/src/backend/meson.build | 1 + zen/src/gl-rendering-unit-private.h | 17 +++ zen/src/gl-rendering-unit.c | 32 +++++ zen/src/virtual-object-private.h | 16 +++ 21 files changed, 425 insertions(+), 15 deletions(-) create mode 100644 zen/include/zen/gl-rendering-unit.h create mode 100644 zen/src/backend/immersive/client-gl-rendering-unit.c create mode 100644 zen/src/backend/immersive/client-gl-rendering-unit.h create mode 100644 zen/src/backend/immersive/remote/gl-rendering-unit.cc create mode 100644 zen/src/backend/immersive/remote/gl-rendering-unit.h create mode 100644 zen/src/gl-rendering-unit-private.h create mode 100644 zen/src/gl-rendering-unit.c create mode 100644 zen/src/virtual-object-private.h diff --git a/zen/include/zen/gl-rendering-unit.h b/zen/include/zen/gl-rendering-unit.h new file mode 100644 index 00000000..a2d5a8f5 --- /dev/null +++ b/zen/include/zen/gl-rendering-unit.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_gl_rendering_unit { + void *impl_data; + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/virtual-object.h b/zen/include/zen/virtual-object.h index 7acd63ff..98e7e53a 100644 --- a/zen/include/zen/virtual-object.h +++ b/zen/include/zen/virtual-object.h @@ -16,12 +16,6 @@ struct zn_virtual_object { } events; }; -/// Called by impl object -struct zn_virtual_object *zn_virtual_object_create(void *impl_data); - -/// Can be called by impl object -void zn_virtual_object_destroy(struct zn_virtual_object *self); - #ifdef __cplusplus } #endif diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index a9878ccd..d0d34465 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -8,6 +8,8 @@ extern "C" { #endif +struct zn_gl_rendering_unit; +struct zn_virtual_object; struct zn_xr_dispatcher; struct zn_xr_dispatcher_interface { @@ -15,6 +17,11 @@ struct zn_xr_dispatcher_interface { struct zn_xr_dispatcher *self); void (*destroy_virtual_object)( struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object); + + struct zn_gl_rendering_unit *(*get_new_gl_rendering_unit)( + struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object); + void (*destroy_gl_rendering_unit)(struct zn_xr_dispatcher *self, + struct zn_gl_rendering_unit *gl_rendering_unit); }; struct zn_xr_dispatcher { @@ -39,6 +46,20 @@ zn_xr_dispatcher_destroy_virtual_object( self->impl->destroy_virtual_object(self, virtual_object); } +UNUSED static inline struct zn_gl_rendering_unit * +zn_xr_dispatcher_get_new_gl_rendering_unit( + struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object) +{ + return self->impl->get_new_gl_rendering_unit(self, virtual_object); +} + +UNUSED static inline void +zn_xr_dispatcher_destroy_gl_rendering_unit(struct zn_xr_dispatcher *self, + struct zn_gl_rendering_unit *gl_rendering_unit) +{ + self->impl->destroy_gl_rendering_unit(self, gl_rendering_unit); +} + #ifdef __cplusplus } #endif diff --git a/zen/meson.build b/zen/meson.build index 4204fdac..6ce00034 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -1,6 +1,7 @@ _zen_srcs = [ 'src/config.c', 'src/cursor.c', + 'src/gl-rendering-unit.c', 'src/screen.c', 'src/seat.c', 'src/server.c', diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c index 94156018..a1e1a832 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/client-gl-context.c @@ -3,6 +3,7 @@ #include #include +#include "client-gl-rendering-unit.h" #include "xr-compositor.h" #include "zen-common/log.h" #include "zen-common/util.h" @@ -25,10 +26,15 @@ zn_client_gl_context_protocol_destroy( /// @param resource can be inert (resource->user_data == NULL) static void -zn_client_gl_context_protocol_create_rendering_unit( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, - uint32_t id UNUSED, struct wl_resource *virtual_object UNUSED) -{} +zn_client_gl_context_protocol_create_gl_rendering_unit(struct wl_client *client, + struct wl_resource *resource UNUSED, uint32_t id, + struct wl_resource *virtual_object_resource) +{ + struct zn_client_virtual_object *client_virtual_object = + wl_resource_get_user_data(virtual_object_resource); + + zn_client_gl_rendering_unit_create(client, id, client_virtual_object); +} /// @param resource can be inert (resource->user_data == NULL) static void @@ -77,8 +83,8 @@ zn_client_gl_context_protocol_create_gl_base_technique( static const struct zwn_gl_context_interface implementation = { .destroy = zn_client_gl_context_protocol_destroy, - .create_rendering_unit = - zn_client_gl_context_protocol_create_rendering_unit, + .create_gl_rendering_unit = + zn_client_gl_context_protocol_create_gl_rendering_unit, .create_gl_buffer = zn_client_gl_context_protocol_create_gl_buffer, .create_gl_shader = zn_client_gl_context_protocol_create_gl_shader, .create_gl_program = zn_client_gl_context_protocol_create_gl_program, diff --git a/zen/src/backend/immersive/client-gl-rendering-unit.c b/zen/src/backend/immersive/client-gl-rendering-unit.c new file mode 100644 index 00000000..e6fc40fa --- /dev/null +++ b/zen/src/backend/immersive/client-gl-rendering-unit.c @@ -0,0 +1,117 @@ +#include "client-gl-rendering-unit.h" + +#include + +#include "client-virtual-object.h" +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/gl-rendering-unit.h" +#include "zen/xr-dispatcher.h" + +static void zn_client_gl_rendering_unit_destroy( + struct zn_client_gl_rendering_unit *self); + +static void +zn_client_gl_rendering_unit_handle_destroy(struct wl_resource *resource) +{ + struct zn_client_gl_rendering_unit *self = + wl_resource_get_user_data(resource); + + zn_client_gl_rendering_unit_destroy(self); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_rendering_unit_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct zwn_gl_rendering_unit_interface implementation = { + .destroy = zn_client_gl_rendering_unit_protocol_destroy, +}; + +static void +zn_client_gl_rendering_unit_handle_virtual_object_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_rendering_unit *self = + zn_container_of(listener, self, virtual_object_destroy_listener); + + zn_client_gl_rendering_unit_destroy(self); +} + +static void +zn_client_gl_rendering_unit_handle_zn_gl_rendering_unit_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_rendering_unit *self = + zn_container_of(listener, self, zn_gl_rendering_unit_destroy_listener); + + zn_client_gl_rendering_unit_destroy(self); +} + +struct zn_client_gl_rendering_unit * +zn_client_gl_rendering_unit_create(struct wl_client *client, uint32_t id, + struct zn_client_virtual_object *virtual_object) +{ + struct zn_client_gl_rendering_unit *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->virtual_object = virtual_object; + + self->zn_gl_rendering_unit = zn_xr_dispatcher_get_new_gl_rendering_unit( + virtual_object->dispatcher, virtual_object->zn_virtual_object); + if (self->zn_gl_rendering_unit == NULL) { + zn_error("Failed to get new zn_gl_rendering_unit"); + goto err_free; + } + + self->resource = + wl_resource_create(client, &zwn_gl_rendering_unit_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_gl_rendering_unit; + } + + wl_resource_set_implementation(self->resource, &implementation, self, + zn_client_gl_rendering_unit_handle_destroy); + + self->virtual_object_destroy_listener.notify = + zn_client_gl_rendering_unit_handle_virtual_object_destroy; + wl_signal_add( + &virtual_object->events.destroy, &self->virtual_object_destroy_listener); + + self->zn_gl_rendering_unit_destroy_listener.notify = + zn_client_gl_rendering_unit_handle_zn_gl_rendering_unit_destroy; + wl_signal_add(&self->zn_gl_rendering_unit->events.destroy, + &self->zn_gl_rendering_unit_destroy_listener); + + return self; + +err_gl_rendering_unit: + zn_xr_dispatcher_destroy_gl_rendering_unit( + virtual_object->dispatcher, self->zn_gl_rendering_unit); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_client_gl_rendering_unit_destroy(struct zn_client_gl_rendering_unit *self) +{ + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); + wl_list_remove(&self->virtual_object_destroy_listener.link); + wl_list_remove(&self->zn_gl_rendering_unit_destroy_listener.link); + zn_xr_dispatcher_destroy_gl_rendering_unit( + self->virtual_object->dispatcher, self->zn_gl_rendering_unit); + free(self); +} diff --git a/zen/src/backend/immersive/client-gl-rendering-unit.h b/zen/src/backend/immersive/client-gl-rendering-unit.h new file mode 100644 index 00000000..21fbf70d --- /dev/null +++ b/zen/src/backend/immersive/client-gl-rendering-unit.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +struct zn_client_virtual_object; +struct zn_gl_rendering_unit; + +struct zn_client_gl_rendering_unit { + struct zn_client_virtual_object *virtual_object; // @nonnull, @outlive + + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_gl_rendering_unit *zn_gl_rendering_unit; // @nonnull, @outlive + + struct wl_listener virtual_object_destroy_listener; + struct wl_listener zn_gl_rendering_unit_destroy_listener; +}; + +struct zn_client_gl_rendering_unit *zn_client_gl_rendering_unit_create( + struct wl_client *client, uint32_t id, + struct zn_client_virtual_object *virtual_object); diff --git a/zen/src/backend/immersive/client-virtual-object.c b/zen/src/backend/immersive/client-virtual-object.c index 984518c1..bfb4377f 100644 --- a/zen/src/backend/immersive/client-virtual-object.c +++ b/zen/src/backend/immersive/client-virtual-object.c @@ -3,6 +3,7 @@ #include #include "zen-common/log.h" +#include "zen-common/signal.h" #include "zen-common/util.h" #include "zen/virtual-object.h" #include "zen/xr-dispatcher.h" @@ -75,6 +76,7 @@ zn_client_virtual_object_create( } self->dispatcher = dispatcher; + wl_signal_init(&self->events.destroy); self->zn_virtual_object = zn_xr_dispatcher_get_new_virtual_object(dispatcher); if (self->zn_virtual_object == NULL) { @@ -119,11 +121,13 @@ zn_client_virtual_object_create( static void zn_client_virtual_object_destroy(struct zn_client_virtual_object *self) { + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); wl_list_remove(&self->zn_virtual_object_destroy_listener.link); wl_list_remove(&self->dispatcher_destroy_listener.link); zn_xr_dispatcher_destroy_virtual_object( self->dispatcher, self->zn_virtual_object); - wl_resource_set_implementation( - self->resource, &zwn_virtual_object_interface, NULL, NULL); + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); free(self); } diff --git a/zen/src/backend/immersive/client-virtual-object.h b/zen/src/backend/immersive/client-virtual-object.h index d1e006a3..75c9b2e2 100644 --- a/zen/src/backend/immersive/client-virtual-object.h +++ b/zen/src/backend/immersive/client-virtual-object.h @@ -14,6 +14,10 @@ struct zn_client_virtual_object { struct wl_listener dispatcher_destroy_listener; struct wl_listener zn_virtual_object_destroy_listener; + + struct { + struct wl_signal destroy; // (NULL) + } events; }; struct zn_client_virtual_object *zn_client_virtual_object_create( diff --git a/zen/src/backend/immersive/remote/gl-rendering-unit.cc b/zen/src/backend/immersive/remote/gl-rendering-unit.cc new file mode 100644 index 00000000..08eee156 --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-rendering-unit.cc @@ -0,0 +1,55 @@ +#include "gl-rendering-unit.h" + +#include "virtual-object.h" +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +GlRenderingUnit::~GlRenderingUnit() +{ + if (c_obj_ != nullptr) { + zn_gl_rendering_unit_destroy(c_obj_); + } +} + +std::unique_ptr +GlRenderingUnit::New(std::shared_ptr channel, + std::unique_ptr &virtual_object) +{ + auto self = std::unique_ptr(new GlRenderingUnit()); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(channel), virtual_object)) { + zn_error("Failed to initialize a remote GlRenderingUnit"); + return nullptr; + } + + return self; +} + +bool +GlRenderingUnit::Init(std::shared_ptr channel, + std::unique_ptr &virtual_object) +{ + c_obj_ = zn_gl_rendering_unit_create(this); + if (c_obj_ == nullptr) { + zn_error("Failed to create a zn_gl_rendering_unit"); + return false; + } + + remote_obj_ = zen::remote::server::CreateRenderingUnit( + std::move(channel), virtual_object->remote_obj()->id()); + if (!remote_obj_) { + zn_error("Failed to create a remote RenderingUnit"); + zn_gl_rendering_unit_destroy(c_obj_); + c_obj_ = nullptr; + return false; + } + + return true; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-rendering-unit.h b/zen/src/backend/immersive/remote/gl-rendering-unit.h new file mode 100644 index 00000000..4ef7118c --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-rendering-unit.h @@ -0,0 +1,39 @@ +#pragma once + +#include "gl-rendering-unit-private.h" +#include "zen-common/cpp-util.h" + +namespace zen::backend::immersive::remote { + +class VirtualObject; + +class GlRenderingUnit +{ + public: + DISABLE_MOVE_AND_COPY(GlRenderingUnit); + ~GlRenderingUnit(); + + static std::unique_ptr New( + std::shared_ptr channel, + std::unique_ptr &virtual_object); + + inline zn_gl_rendering_unit *c_obj(); + + private: + GlRenderingUnit() = default; + + bool Init(std::shared_ptr channel, + std::unique_ptr &virtual_object); + + std::unique_ptr remote_obj_; + + zn_gl_rendering_unit *c_obj_ = nullptr; // @nonnull after Init(), @owning +}; + +inline zn_gl_rendering_unit * +GlRenderingUnit::c_obj() +{ + return c_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index 5ec707d4..9143e89e 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -1,4 +1,5 @@ _zen_remote_immersive_backend_srcs = [ + 'gl-rendering-unit.cc', 'loop.cc', 'virtual-object.cc', 'xr-dispatcher.cc', diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index 2f80331b..5a510a41 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/zen/src/backend/immersive/remote/virtual-object.cc b/zen/src/backend/immersive/remote/virtual-object.cc index d329cc6e..9468d659 100644 --- a/zen/src/backend/immersive/remote/virtual-object.cc +++ b/zen/src/backend/immersive/remote/virtual-object.cc @@ -41,6 +41,7 @@ VirtualObject::Init(std::shared_ptr channel) if (!remote_obj_) { zn_error("Failed to create a remote Virtual Object"); zn_virtual_object_destroy(c_obj_); + c_obj_ = nullptr; return false; } diff --git a/zen/src/backend/immersive/remote/virtual-object.h b/zen/src/backend/immersive/remote/virtual-object.h index b2d3adba..cd108741 100644 --- a/zen/src/backend/immersive/remote/virtual-object.h +++ b/zen/src/backend/immersive/remote/virtual-object.h @@ -1,7 +1,7 @@ #pragma once +#include "virtual-object-private.h" #include "zen-common/cpp-util.h" -#include "zen/virtual-object.h" namespace zen::backend::immersive::remote { @@ -14,6 +14,7 @@ class VirtualObject static std::unique_ptr New( std::shared_ptr channel); + inline std::unique_ptr &remote_obj(); inline zn_virtual_object *c_obj(); private: @@ -32,4 +33,10 @@ VirtualObject::c_obj() return c_obj_; } +inline std::unique_ptr & +VirtualObject::remote_obj() +{ + return remote_obj_; +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index dd14f101..9b8d2bed 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -2,6 +2,7 @@ #include +#include "gl-rendering-unit.h" #include "virtual-object.h" #include "zen-common/log.h" @@ -10,6 +11,8 @@ namespace zen::backend::immersive::remote { const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { XrDispatcher::HandleGetNewVirtualObject, XrDispatcher::HandleDestroyVirtualObject, + XrDispatcher::HandleGetNewGlRenderingUnit, + XrDispatcher::HandleDestroyGlRenderingUnit, }; XrDispatcher::~XrDispatcher() @@ -49,6 +52,7 @@ XrDispatcher::Init(std::shared_ptr session) if (!channel_) { zn_error("Failed to create a remote channel"); zn_xr_dispatcher_destroy(c_obj_); + c_obj_ = nullptr; return false; } @@ -88,4 +92,44 @@ XrDispatcher::HandleDestroyVirtualObject( self->virtual_objects_.erase(result, self->virtual_objects_.end()); } +zn_gl_rendering_unit * +XrDispatcher::HandleGetNewGlRenderingUnit( + zn_xr_dispatcher *c_obj, zn_virtual_object *virtual_object_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + for (auto &virtual_object : self->virtual_objects_) { + if (virtual_object->c_obj() != virtual_object_c_obj) { + continue; + } + + auto gl_rendering_unit = + GlRenderingUnit::New(self->channel_, virtual_object); + + auto *gl_rendering_unit_c_obj = gl_rendering_unit->c_obj(); + + self->gl_rendering_units_.push_back(std::move(gl_rendering_unit)); + + return gl_rendering_unit_c_obj; + } + + return nullptr; +} + +void +XrDispatcher::HandleDestroyGlRenderingUnit( + zn_xr_dispatcher *c_obj, zn_gl_rendering_unit *gl_rendering_unit_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto result = std::remove_if(self->gl_rendering_units_.begin(), + self->gl_rendering_units_.end(), + [gl_rendering_unit_c_obj]( + std::unique_ptr &gl_rendering_unit) { + return gl_rendering_unit->c_obj() == gl_rendering_unit_c_obj; + }); + + self->gl_rendering_units_.erase(result, self->gl_rendering_units_.end()); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index 11c35da6..1a6d80bd 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -6,6 +6,7 @@ namespace zen::backend::immersive::remote { class VirtualObject; +class GlRenderingUnit; class XrDispatcher { @@ -28,10 +29,18 @@ class XrDispatcher static void HandleDestroyVirtualObject( zn_xr_dispatcher *c_obj, zn_virtual_object *virtual_object_c_obj); + static zn_gl_rendering_unit *HandleGetNewGlRenderingUnit( + zn_xr_dispatcher *c_obj, zn_virtual_object *virtual_object_c_obj); + + static void HandleDestroyGlRenderingUnit( + zn_xr_dispatcher *c_obj, zn_gl_rendering_unit *gl_rendering_unit_c_obj); + std::shared_ptr channel_; std::vector> virtual_objects_; + std::vector> gl_rendering_units_; + static const zn_xr_dispatcher_interface c_implementation_; zn_xr_dispatcher *c_obj_ = nullptr; // @nonnull after Init(), @owning diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 1cdef133..c109cc89 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -4,6 +4,7 @@ _zen_backend_srcs = [ 'default-backend.c', 'immersive/client-gl-context.c', + 'immersive/client-gl-rendering-unit.c', 'immersive/client-virtual-object.c', 'immersive/xr.c', 'immersive/xr-compositor.c', diff --git a/zen/src/gl-rendering-unit-private.h b/zen/src/gl-rendering-unit-private.h new file mode 100644 index 00000000..7647bf03 --- /dev/null +++ b/zen/src/gl-rendering-unit-private.h @@ -0,0 +1,17 @@ +#pragma once + +#include "zen/gl-rendering-unit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Called by impl object +struct zn_gl_rendering_unit *zn_gl_rendering_unit_create(void *impl_data); + +/// Called by impl object +void zn_gl_rendering_unit_destroy(struct zn_gl_rendering_unit *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/gl-rendering-unit.c b/zen/src/gl-rendering-unit.c new file mode 100644 index 00000000..d1a292f5 --- /dev/null +++ b/zen/src/gl-rendering-unit.c @@ -0,0 +1,32 @@ +#include "gl-rendering-unit-private.h" +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_gl_rendering_unit * +zn_gl_rendering_unit_create(void *impl_data) +{ + struct zn_gl_rendering_unit *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_gl_rendering_unit_destroy(struct zn_gl_rendering_unit *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + + free(self); +} diff --git a/zen/src/virtual-object-private.h b/zen/src/virtual-object-private.h new file mode 100644 index 00000000..a62bbdea --- /dev/null +++ b/zen/src/virtual-object-private.h @@ -0,0 +1,16 @@ +#include "zen/virtual-object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Called by impl object +struct zn_virtual_object *zn_virtual_object_create(void *impl_data); + +/// Called by impl object +void zn_virtual_object_destroy(struct zn_virtual_object *self); + +#ifdef __cplusplus +} +#endif + From 7cb5b36877b0bccec136334d852d669b87ccbf1e Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 15 Apr 2023 20:20:09 +0900 Subject: [PATCH 14/49] add gl_buffer --- common/include/zen-common/wl-array.h | 15 + common/meson.build | 1 + common/src/wl-array.c | 15 + zen/include/zen/backend.h | 1 + zen/include/zen/gl-buffer.h | 19 + zen/include/zen/xr-dispatcher.h | 18 + zen/include/zen/xr-system.h | 2 +- zen/meson.build | 1 + zen/src/backend/default-backend.c | 3 + zen/src/backend/immersive/client-gl-buffer.c | 119 ++++ zen/src/backend/immersive/client-gl-buffer.h | 16 + zen/src/backend/immersive/client-gl-context.c | 9 +- zen/src/backend/immersive/remote/gl-buffer.cc | 51 ++ zen/src/backend/immersive/remote/gl-buffer.h | 35 + zen/src/backend/immersive/remote/meson.build | 1 + zen/src/backend/immersive/remote/pch/pch.h | 1 + .../backend/immersive/remote/xr-dispatcher.cc | 36 ++ .../backend/immersive/remote/xr-dispatcher.h | 8 + zen/src/backend/immersive/shm.c | 609 ++++++++++++++++++ zen/src/backend/immersive/shm.h | 27 + zen/src/backend/meson.build | 2 + zen/src/gl-buffer-private.h | 17 + zen/src/gl-buffer.c | 31 + 23 files changed, 1033 insertions(+), 4 deletions(-) create mode 100644 common/include/zen-common/wl-array.h create mode 100644 common/src/wl-array.c create mode 100644 zen/include/zen/gl-buffer.h create mode 100644 zen/src/backend/immersive/client-gl-buffer.c create mode 100644 zen/src/backend/immersive/client-gl-buffer.h create mode 100644 zen/src/backend/immersive/remote/gl-buffer.cc create mode 100644 zen/src/backend/immersive/remote/gl-buffer.h create mode 100644 zen/src/backend/immersive/shm.c create mode 100644 zen/src/backend/immersive/shm.h create mode 100644 zen/src/gl-buffer-private.h create mode 100644 zen/src/gl-buffer.c diff --git a/common/include/zen-common/wl-array.h b/common/include/zen-common/wl-array.h new file mode 100644 index 00000000..481c639b --- /dev/null +++ b/common/include/zen-common/wl-array.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// @return true if successful, false otherwise +bool zn_wl_array_to_int64_t(struct wl_array *array, int64_t *value); + +#ifdef __cplusplus +} +#endif diff --git a/common/meson.build b/common/meson.build index 6cdd2058..1e59ce94 100644 --- a/common/meson.build +++ b/common/meson.build @@ -3,6 +3,7 @@ _zen_common_srcs = [ 'src/log.c', 'src/signal.c', 'src/terminate.c', + 'src/wl-array.c', 'src/wlr/box.c', ] diff --git a/common/src/wl-array.c b/common/src/wl-array.c new file mode 100644 index 00000000..f7340058 --- /dev/null +++ b/common/src/wl-array.c @@ -0,0 +1,15 @@ +#include "zen-common/wl-array.h" + +#include + +bool +zn_wl_array_to_int64_t(struct wl_array *array, int64_t *value) +{ + if (array->size != sizeof(*value)) { + return false; + } + + memcpy(value, array->data, array->size); + + return true; +} diff --git a/zen/include/zen/backend.h b/zen/include/zen/backend.h index f51ef9b5..44f9de28 100644 --- a/zen/include/zen/backend.h +++ b/zen/include/zen/backend.h @@ -70,6 +70,7 @@ zn_backend_set_xr_system( self->impl->set_xr_system(self, xr_system); } +/// @return value can be NULL UNUSED static inline struct zn_xr_system * zn_backend_get_xr_system(struct zn_backend *self) { diff --git a/zen/include/zen/gl-buffer.h b/zen/include/zen/gl-buffer.h new file mode 100644 index 00000000..03cb52ca --- /dev/null +++ b/zen/include/zen/gl-buffer.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_gl_buffer { + void *impl_data; + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index d0d34465..49773065 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -8,6 +8,7 @@ extern "C" { #endif +struct zn_gl_buffer; struct zn_gl_rendering_unit; struct zn_virtual_object; struct zn_xr_dispatcher; @@ -22,6 +23,10 @@ struct zn_xr_dispatcher_interface { struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object); void (*destroy_gl_rendering_unit)(struct zn_xr_dispatcher *self, struct zn_gl_rendering_unit *gl_rendering_unit); + + struct zn_gl_buffer *(*get_new_gl_buffer)(struct zn_xr_dispatcher *self); + void (*destroy_gl_buffer)( + struct zn_xr_dispatcher *self, struct zn_gl_buffer *gl_buffer); }; struct zn_xr_dispatcher { @@ -60,6 +65,19 @@ zn_xr_dispatcher_destroy_gl_rendering_unit(struct zn_xr_dispatcher *self, self->impl->destroy_gl_rendering_unit(self, gl_rendering_unit); } +UNUSED static inline struct zn_gl_buffer * +zn_xr_dispatcher_get_new_gl_buffer(struct zn_xr_dispatcher *self) +{ + return self->impl->get_new_gl_buffer(self); +} + +UNUSED static inline void +zn_xr_dispatcher_destroy_gl_buffer( + struct zn_xr_dispatcher *self, struct zn_gl_buffer *gl_buffer) +{ + self->impl->destroy_gl_buffer(self, gl_buffer); +} + #ifdef __cplusplus } #endif diff --git a/zen/include/zen/xr-system.h b/zen/include/zen/xr-system.h index 504690d8..4bf63429 100644 --- a/zen/include/zen/xr-system.h +++ b/zen/include/zen/xr-system.h @@ -42,7 +42,7 @@ struct zn_xr_system { enum zn_xr_system_session_state state; - /// These dispatchers are null when connected, not null otherwise. + /// These dispatchers are not null when connected, null otherwise. struct zn_xr_dispatcher *high_priority_dispatcher; // @owning struct zn_xr_dispatcher *default_dispatcher; // @owning diff --git a/zen/meson.build b/zen/meson.build index 6ce00034..e0a1d0ba 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -1,6 +1,7 @@ _zen_srcs = [ 'src/config.c', 'src/cursor.c', + 'src/gl-buffer.c', 'src/gl-rendering-unit.c', 'src/screen.c', 'src/seat.c', diff --git a/zen/src/backend/default-backend.c b/zen/src/backend/default-backend.c index fc4eec8b..cc7c8fcf 100644 --- a/zen/src/backend/default-backend.c +++ b/zen/src/backend/default-backend.c @@ -7,6 +7,7 @@ #include #include +#include "immersive/shm.h" #include "immersive/xr-compositor.h" #include "immersive/xr-system-manager.h" #include "immersive/xr.h" @@ -298,6 +299,8 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) goto err_compositor; } + zn_shm_init(display); + wlr_xwayland_set_seat(self->compositor->xwayland, zn_seat->wlr_seat); self->new_output_listener.notify = zn_default_backend_handle_new_output; diff --git a/zen/src/backend/immersive/client-gl-buffer.c b/zen/src/backend/immersive/client-gl-buffer.c new file mode 100644 index 00000000..a80671eb --- /dev/null +++ b/zen/src/backend/immersive/client-gl-buffer.c @@ -0,0 +1,119 @@ +#include "client-gl-buffer.h" + +#include + +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/backend.h" +#include "zen/gl-buffer.h" +#include "zen/server.h" +#include "zen/xr-dispatcher.h" +#include "zen/xr-system.h" + +static void zn_client_gl_buffer_destroy(struct zn_client_gl_buffer *self); + +static void +zn_client_gl_buffer_handle_destroy(struct wl_resource *resource) +{ + struct zn_client_gl_buffer *self = wl_resource_get_user_data(resource); + + zn_client_gl_buffer_destroy(self); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_buffer_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_buffer_protocol_data(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t target UNUSED, + struct wl_resource *data UNUSED, uint32_t usage UNUSED) +{} + +static const struct zwn_gl_buffer_interface implementation = { + .destroy = zn_client_gl_buffer_protocol_destroy, + .data = zn_client_gl_buffer_protocol_data, +}; + +static void +zn_client_gl_buffer_handle_zn_gl_buffer_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_buffer *self = + zn_container_of(listener, self, zn_gl_buffer_destroy_listener); + + zn_client_gl_buffer_destroy(self); +} + +struct zn_client_gl_buffer * +zn_client_gl_buffer_create(struct wl_client *client, uint32_t id) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + if (xr_system == NULL || !zn_xr_system_is_connected(xr_system)) { + zn_error("Failed to get xr_system"); + goto err; + } + + struct zn_client_gl_buffer *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->zn_gl_buffer = + zn_xr_dispatcher_get_new_gl_buffer(xr_system->default_dispatcher); + if (self->zn_gl_buffer == NULL) { + zn_error("Failed to get new zn_gl_buffer"); + goto err_free; + } + + self->resource = wl_resource_create(client, &zwn_gl_buffer_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + goto err_gl_buffer; + } + + wl_resource_set_implementation(self->resource, &implementation, self, + zn_client_gl_buffer_handle_destroy); + + self->zn_gl_buffer_destroy_listener.notify = + zn_client_gl_buffer_handle_zn_gl_buffer_destroy; + wl_signal_add(&self->zn_gl_buffer->events.destroy, + &self->zn_gl_buffer_destroy_listener); + + return self; + +err_gl_buffer: + zn_xr_dispatcher_destroy_gl_buffer( + xr_system->default_dispatcher, self->zn_gl_buffer); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_client_gl_buffer_destroy(struct zn_client_gl_buffer *self) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); + wl_list_remove(&self->zn_gl_buffer_destroy_listener.link); + + if (xr_system != NULL && zn_xr_system_is_connected(xr_system)) { + zn_xr_dispatcher_destroy_gl_buffer( + xr_system->default_dispatcher, self->zn_gl_buffer); + } + + free(self); +} diff --git a/zen/src/backend/immersive/client-gl-buffer.h b/zen/src/backend/immersive/client-gl-buffer.h new file mode 100644 index 00000000..987ad813 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-buffer.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +struct zn_gl_buffer; + +struct zn_client_gl_buffer { + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_gl_buffer *zn_gl_buffer; // @nonnull, @outlive + + struct wl_listener zn_gl_buffer_destroy_listener; +}; + +struct zn_client_gl_buffer *zn_client_gl_buffer_create( + struct wl_client *client, uint32_t id); diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c index a1e1a832..034bb651 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/client-gl-context.c @@ -3,6 +3,7 @@ #include #include +#include "client-gl-buffer.h" #include "client-gl-rendering-unit.h" #include "xr-compositor.h" #include "zen-common/log.h" @@ -38,9 +39,11 @@ zn_client_gl_context_protocol_create_gl_rendering_unit(struct wl_client *client, /// @param resource can be inert (resource->user_data == NULL) static void -zn_client_gl_context_protocol_create_gl_buffer(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, uint32_t id UNUSED) -{} +zn_client_gl_context_protocol_create_gl_buffer( + struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) +{ + zn_client_gl_buffer_create(client, id); +} /// @param resource can be inert (resource->user_data == NULL) static void diff --git a/zen/src/backend/immersive/remote/gl-buffer.cc b/zen/src/backend/immersive/remote/gl-buffer.cc new file mode 100644 index 00000000..c2b44f4e --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-buffer.cc @@ -0,0 +1,51 @@ +#include "gl-buffer.h" + +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +GlBuffer::~GlBuffer() +{ + if (c_obj_ != nullptr) { + zn_gl_buffer_destroy(c_obj_); + } +} + +std::unique_ptr +GlBuffer::New(std::shared_ptr channel) +{ + auto self = std::unique_ptr(new GlBuffer()); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(channel))) { + zn_error("Failed to initialize a remote GlBuffer"); + return nullptr; + } + + return self; +} + +bool +GlBuffer::Init(std::shared_ptr channel) +{ + c_obj_ = zn_gl_buffer_create(this); + if (c_obj_ == nullptr) { + zn_error("Failed to create a zn_gl_buffer"); + return false; + } + + remote_obj_ = zen::remote::server::CreateGlBuffer(std::move(channel)); + if (!remote_obj_) { + zn_error("Failed to create a remote GlBuffer"); + zn_gl_buffer_destroy(c_obj_); + c_obj_ = nullptr; + return false; + } + + return true; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-buffer.h b/zen/src/backend/immersive/remote/gl-buffer.h new file mode 100644 index 00000000..dc76061f --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-buffer.h @@ -0,0 +1,35 @@ +#pragma once + +#include "gl-buffer-private.h" +#include "zen-common/cpp-util.h" + +namespace zen::backend::immersive::remote { + +class GlBuffer +{ + public: + DISABLE_MOVE_AND_COPY(GlBuffer); + ~GlBuffer(); + + static std::unique_ptr New( + std::shared_ptr channel); + + inline zn_gl_buffer *c_obj() const; + + private: + GlBuffer() = default; + + bool Init(std::shared_ptr channel); + + std::unique_ptr remote_obj_; + + zn_gl_buffer *c_obj_ = nullptr; // @nonnull after Init(), @owning +}; + +inline zn_gl_buffer * +GlBuffer::c_obj() const +{ + return c_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index 9143e89e..8b274645 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -1,4 +1,5 @@ _zen_remote_immersive_backend_srcs = [ + 'gl-buffer.cc', 'gl-rendering-unit.cc', 'loop.cc', 'virtual-object.cc', diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index 5a510a41..e8f8426a 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index 9b8d2bed..91f0baab 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -2,6 +2,7 @@ #include +#include "gl-buffer.h" #include "gl-rendering-unit.h" #include "virtual-object.h" #include "zen-common/log.h" @@ -13,6 +14,8 @@ const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { XrDispatcher::HandleDestroyVirtualObject, XrDispatcher::HandleGetNewGlRenderingUnit, XrDispatcher::HandleDestroyGlRenderingUnit, + XrDispatcher::HandleGetNewGlBuffer, + XrDispatcher::HandleDestroyGlBuffer, }; XrDispatcher::~XrDispatcher() @@ -132,4 +135,37 @@ XrDispatcher::HandleDestroyGlRenderingUnit( self->gl_rendering_units_.erase(result, self->gl_rendering_units_.end()); } +zn_gl_buffer * +XrDispatcher::HandleGetNewGlBuffer(zn_xr_dispatcher *c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto gl_buffer = GlBuffer::New(self->channel_); + if (!gl_buffer) { + zn_error("Failed to create a remote gl_buffer"); + return nullptr; + } + + auto *gl_buffer_c_obj = gl_buffer->c_obj(); + + self->gl_buffers_.push_back((std::move(gl_buffer))); + + return gl_buffer_c_obj; +} + +void +XrDispatcher::HandleDestroyGlBuffer( + zn_xr_dispatcher *c_obj, struct zn_gl_buffer *gl_buffer_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto result = + std::remove_if(self->gl_buffers_.begin(), self->gl_buffers_.end(), + [gl_buffer_c_obj](std::unique_ptr &gl_buffer) { + return gl_buffer->c_obj() == gl_buffer_c_obj; + }); + + self->gl_buffers_.erase(result, self->gl_buffers_.end()); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index 1a6d80bd..7cfdce58 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -6,6 +6,7 @@ namespace zen::backend::immersive::remote { class VirtualObject; +class GlBuffer; class GlRenderingUnit; class XrDispatcher @@ -35,12 +36,19 @@ class XrDispatcher static void HandleDestroyGlRenderingUnit( zn_xr_dispatcher *c_obj, zn_gl_rendering_unit *gl_rendering_unit_c_obj); + static zn_gl_buffer *HandleGetNewGlBuffer(zn_xr_dispatcher *c_obj); + + static void HandleDestroyGlBuffer( + zn_xr_dispatcher *c_obj, struct zn_gl_buffer *gl_buffer_c_obj); + std::shared_ptr channel_; std::vector> virtual_objects_; std::vector> gl_rendering_units_; + std::vector> gl_buffers_; + static const zn_xr_dispatcher_interface c_implementation_; zn_xr_dispatcher *c_obj_ = nullptr; // @nonnull after Init(), @owning diff --git a/zen/src/backend/immersive/shm.c b/zen/src/backend/immersive/shm.c new file mode 100644 index 00000000..f386e817 --- /dev/null +++ b/zen/src/backend/immersive/shm.c @@ -0,0 +1,609 @@ +/** + * Copyright © 2008-2012 Kristian Høgsberg + * Copyright © 2010-2012 Intel Corporation + * Copyright © 2011 Benjamin Franzke + * Copyright © 2012 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Note: + * This file was copied from wayland project on November 5, 2022 and + * modified for this project. + */ + +#include "shm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen-common/wl-array.h" + +/* This once_t is used to synchronize installing the SIGBUS handler + * and creating the TLS key. This will be done in the first call + * zn_shm_buffer_begin_access which can happen from any thread */ +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static pthread_once_t zn_shm_sigbus_once = PTHREAD_ONCE_INIT; +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static pthread_key_t zn_shm_sigbus_data_key; +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static struct sigaction zn_shm_old_sigbus_action; + +struct zn_shm_pool { + struct wl_resource *resource; + int internal_refcount; + int external_refcount; + char *data; + ssize_t size; + ssize_t new_size; + bool sigbuf_is_impossible; +}; + +/** + * @brief A SHM buffer + * + * zn_shm_buffer provides a helper for accessing the contents of a zwn_buffer + * resource created via the zn_shm interface. + * + * A zn_shm_buffer becomes invalid as soon as its wl_resource is destroyed. + */ +struct zn_shm_buffer { + struct wl_resource *resource; + ssize_t size; + ssize_t offset; + struct zn_shm_pool *pool; +}; + +struct zn_shm_sigbus_data { + struct zn_shm_pool *current_pool; + int access_count; + int fallback_mapping_used; +}; + +static void * +shm_pool_grow_mapping(struct zn_shm_pool *pool) +{ + void *data = NULL; + +#ifdef MREMAP_MAYMOVE + data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE); +#else +#error Operating system must implement mremap(MREMAP_MAYMOVE) + // TODO: fallback +#endif + return data; +} + +static void +shm_pool_finish_resize(struct zn_shm_pool *pool) +{ + void *data = NULL; + + if (pool->size == pool->new_size) { + return; + } + + data = shm_pool_grow_mapping(pool); + if (data == MAP_FAILED) { // NOLINT(performance-no-int-to-ptr) + wl_resource_post_error( + pool->resource, ZWN_SHM_ERROR_INVALID_FD, "failed mremap"); + return; + } + + pool->data = data; + pool->size = pool->new_size; +} + +static void +shm_pool_unref(struct zn_shm_pool *pool, bool external) +{ + if (external) { + pool->external_refcount--; + assert(pool->external_refcount >= 0); + if (pool->external_refcount == 0) { + shm_pool_finish_resize(pool); + } + } else { + pool->internal_refcount--; + assert(pool->internal_refcount >= 0); + } + + if (pool->internal_refcount + pool->external_refcount > 0) { + return; + } + + munmap(pool->data, pool->size); + free(pool); +} + +static void +destroy_buffer(struct wl_resource *resource) +{ + struct zn_shm_buffer *buffer = wl_resource_get_user_data(resource); + + shm_pool_unref(buffer->pool, false); + free(buffer); +} + +static void +shm_buffer_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct zwn_buffer_interface shm_buffer_interface = { + shm_buffer_destroy, +}; + +static void +shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource, + uint32_t id, struct wl_array *offset_array, struct wl_array *size_array) +{ + struct zn_shm_pool *pool = wl_resource_get_user_data(resource); + struct zn_shm_buffer *buffer = NULL; + int64_t offset = 0; + int64_t size = 0; + + if (zn_wl_array_to_int64_t(offset_array, &offset) != 0 || + zn_wl_array_to_int64_t(size_array, &size) != 0) { + wl_resource_post_error( + resource, ZWN_COMPOSITOR_ERROR_INVALID_WL_ARRAY_SIZE, "invalid size"); + } + + if (offset < 0 || size <= 0 || offset > pool->size - size) { + wl_resource_post_error( + resource, ZWN_SHM_ERROR_INVALID_SIZE, "invalid size (%ld)", size); + return; + } + + buffer = zalloc(sizeof *buffer); + if (buffer == NULL) { + wl_client_post_no_memory(client); + return; + } + + buffer->size = size; + buffer->offset = offset; + buffer->pool = pool; + pool->internal_refcount++; + + buffer->resource = wl_resource_create(client, &zwn_buffer_interface, 1, id); + if (buffer->resource == NULL) { + wl_client_post_no_memory(client); + shm_pool_unref(pool, false); + free(buffer); + return; + } + + wl_resource_set_implementation( + buffer->resource, &shm_buffer_interface, buffer, destroy_buffer); +} + +static void +destroy_pool(struct wl_resource *resource) +{ + struct zn_shm_pool *pool = wl_resource_get_user_data(resource); + + shm_pool_unref(pool, false); +} + +static void +shm_pool_destroy(struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +shm_pool_resize( + struct wl_client *client UNUSED, struct wl_resource *resource, int32_t size) +{ + struct zn_shm_pool *pool = wl_resource_get_user_data(resource); + + if (size < pool->size) { + wl_resource_post_error( + resource, ZWN_SHM_ERROR_INVALID_FD, "shrinking pool invalid"); + return; + } + + pool->new_size = size; + + /* If the compositor has taken references on this pool it + * may be caching pointers into it. In that case we + * defer the resize (which may move the entire mapping) + * until the compositor finishes dereferencing the pool. + */ + if (pool->external_refcount == 0) { + shm_pool_finish_resize(pool); + } +} + +static const struct zwn_shm_pool_interface shm_pool_interface = { + shm_pool_destroy, + shm_pool_create_buffer, + shm_pool_resize, +}; + +static void +shm_create_pool(struct wl_client *client, struct wl_resource *resource, + uint32_t id, int fd, struct wl_array *size_array) +{ + struct zn_shm_pool *pool = NULL; + struct stat statbuf; + int seals = 0; + int64_t size = 0; + + if (zn_wl_array_to_int64_t(size_array, &size) != 0) { + wl_resource_post_error( + resource, ZWN_SHM_ERROR_INVALID_SIZE, "invalid size"); + goto err_close; + } + + if (size <= 0) { + wl_resource_post_error( + resource, ZWN_SHM_ERROR_INVALID_SIZE, "invalid size (%ld)", size); + goto err_close; + } + + pool = zalloc(sizeof *pool); + if (pool == NULL) { + wl_client_post_no_memory(client); + goto err_close; + } + + seals = fcntl(fd, F_GET_SEALS); + if (seals == -1) { + seals = 0; + } + + if ((seals & F_SEAL_SHRINK) && fstat(fd, &statbuf) >= 0) { + pool->sigbuf_is_impossible = statbuf.st_size >= size; + } else { + pool->sigbuf_is_impossible = false; + } + + pool->internal_refcount = 1; + pool->external_refcount = 0; + pool->size = size; + pool->new_size = size; + pool->data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (pool->data == MAP_FAILED) { // NOLINT(performance-no-int-to-ptr) + wl_resource_post_error(resource, ZWN_SHM_ERROR_INVALID_FD, + "failed mmap fd %d: %s", fd, strerror(errno)); + goto err_free; + } + + close(fd); + + pool->resource = wl_resource_create(client, &zwn_shm_pool_interface, 1, id); + if (!pool->resource) { + wl_client_post_no_memory(client); + munmap(pool->data, pool->size); + free(pool); + return; + } + + wl_resource_set_implementation( + pool->resource, &shm_pool_interface, pool, destroy_pool); + + return; + +err_free: + free(pool); + +err_close: + close(fd); +} + +static const struct zwn_shm_interface shm_interface = { + shm_create_pool, +}; + +static void +bind_shm( + struct wl_client *client, void *data, uint32_t version UNUSED, uint32_t id) +{ + struct wl_resource *resource = + wl_resource_create(client, &zwn_shm_interface, 1, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &shm_interface, data, NULL); +} + +int +zn_shm_init(struct wl_display *display) +{ + if (!wl_global_create(display, &zwn_shm_interface, 1, NULL, bind_shm)) { + return -1; + } + + return 0; +} + +struct zn_shm_buffer * +zn_shm_buffer_get(struct wl_resource *resource) +{ + if (resource == NULL) { + return NULL; + } + + if (wl_resource_instance_of( + resource, &zwn_buffer_interface, &shm_buffer_interface)) { + return wl_resource_get_user_data(resource); + } + + return NULL; +} + +ssize_t +zn_shm_buffer_get_size(struct zn_shm_buffer *buffer) +{ + return buffer->size; +} + +/** + * Get a pointer to the memory for the SHM buffer + * + * \param buffer The buffer object + * + * Returns a pointer which can be used to read the data contained in + * the given SHM buffer. + * + * As this buffer is memory-mapped, reading from it may generate + * SIGBUS signals. This can happen if the client claims that the + * buffer is larger than it is or if something truncates the + * underlying file. To prevent this signal from causing the compositor + * to crash you should call zn_shm_buffer_begin_access and + * zn_shm_buffer_end_access around code that reads from the memory. + * + * \memberof zn_shm_buffer + */ +void * +zn_shm_buffer_get_data(struct zn_shm_buffer *buffer) +{ + if (buffer->pool->external_refcount && + (buffer->pool->size != buffer->pool->new_size)) { + zn_warn( + "Buffer address requested when its parent pool has an external " + "reference and a deferred resize pending."); + } + + return buffer->pool->data + buffer->offset; +} + +/** + * Get a reference to a shm_buffer's shm_pool + * + * \param buffer The buffer object + * + * Returns a pointer to a buffer's zwn_pool and increases the + * shm_pool refcount. + * + * The compositor must remember to call zn_shm_pool_unref when + * it no longer needs the reference to ensure proper destruction + * of the pool. + * + * \memberof zn_shm_buffer + * \sa zn_shm_pool_unref + */ +struct zn_shm_pool * +zn_shm_buffer_ref_pool(struct zn_shm_buffer *buffer) +{ + assert(buffer->pool->internal_refcount + buffer->pool->external_refcount); + + buffer->pool->external_refcount++; + return buffer->pool; +} + +/** + * Unreference a shm_pool + * + * \param pool The pool object + * + * Drops a reference to a zn_shm_pool object. + * + * This is only necessary if the compositor has explicitly + * taken a reference with zn_shm_buffer_ref_pool(), otherwise + * the pool will be automatically destroyed when appropriate. + * + * \memberof zn_shm_pool + * \sa zn_shm_buffer_ref_pool + */ +void +zn_shm_pool_unref(struct zn_shm_pool *pool) +{ + shm_pool_unref(pool, true); +} + +static void +reraise_sigbus(void) +{ + /* If SIGBUS is raised for some other reason than accessing + * the pool then we'll uninstall the signal handler so we can + * reraise it. This would presumably kill the process */ + sigaction(SIGBUS, &zn_shm_old_sigbus_action, NULL); + raise(SIGBUS); // NOLINT(cert-err33-c) +} + +static void +sigbus_handler(int signum UNUSED, siginfo_t *info, void *context UNUSED) +{ + struct zn_shm_sigbus_data *sigbus_data = + pthread_getspecific(zn_shm_sigbus_data_key); + struct zn_shm_pool *pool = NULL; + + if (sigbus_data == NULL) { + reraise_sigbus(); + return; + } + + pool = sigbus_data->current_pool; + + if (pool == NULL || (char *)info->si_addr < pool->data || + (char *)info->si_addr >= pool->data + pool->size) { + reraise_sigbus(); + return; + } + + sigbus_data->fallback_mapping_used = 1; + + if (mmap(pool->data, pool->size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, + 0) == MAP_FAILED) { // NOLINT(performance-no-int-to-ptr) + reraise_sigbus(); + return; + } +} + +static void +destroy_sigbus_data(void *data) +{ + struct zn_shm_sigbus_data *sigbus_data = data; + + free(sigbus_data); +} + +static void +init_sigbus_data_key(void) +{ + struct sigaction new_action = { + .sa_sigaction = sigbus_handler, + .sa_flags = SA_SIGINFO | SA_NODEFER, + }; + + sigemptyset(&new_action.sa_mask); + + sigaction(SIGBUS, &new_action, &zn_shm_old_sigbus_action); + + pthread_key_create(&zn_shm_sigbus_data_key, destroy_sigbus_data); +} + +/** + * Mark that the given SHM buffer is about to be accessed + * + * \param buffer The SHM buffer + * + * An SHM buffer is a memory-mapped file given by the client. + * According to POSIX, reading from a memory-mapped region that + * extends off the end of the file will cause a SIGBUS signal to be + * generated. Normally this would cause the compositor to terminate. + * In order to make the compositor robust against clients that change + * the size of the underlying file or lie about its size, you should + * protect access to the buffer by calling this function before + * reading from the memory and call zn_shm_buffer_end_access + * afterwards. This will install a signal handler for SIGBUS which + * will prevent the compositor from crashing. + * + * After calling this function the signal handler will remain + * installed for the lifetime of the compositor process. Note that + * this function will not work properly if the compositor is also + * installing its own handler for SIGBUS. + * + * If a SIGBUS signal is received for an address within the range of + * the SHM pool of the given buffer then the client will be sent an + * error event when zn_shm_buffer_end_access is called. If the signal + * is for an address outside that range then the signal handler will + * reraise the signal which would will likely cause the compositor to + * terminate. + * + * It is safe to nest calls to these functions as long as the nested + * calls are all accessing the same buffer. The number of calls to + * zn_shm_buffer_end_access must match the number of calls to + * zn_shm_buffer_begin_access. These functions are thread-safe and it + * is allowed to simultaneously access different buffers or the same + * buffer from multiple threads. + * + * \memberof zn_shm_buffer + */ +void +zn_shm_buffer_begin_access(struct zn_shm_buffer *buffer) +{ + struct zn_shm_pool *pool = buffer->pool; + struct zn_shm_sigbus_data *sigbus_data = NULL; + + if (pool->sigbuf_is_impossible) { + return; + } + + pthread_once(&zn_shm_sigbus_once, init_sigbus_data_key); + + sigbus_data = pthread_getspecific(zn_shm_sigbus_data_key); + if (sigbus_data == NULL) { + sigbus_data = zalloc(sizeof *sigbus_data); + if (sigbus_data == NULL) { + return; + } + + pthread_setspecific(zn_shm_sigbus_data_key, sigbus_data); + } + + assert( + sigbus_data->current_pool == NULL || sigbus_data->current_pool == pool); + + sigbus_data->current_pool = pool; + sigbus_data->access_count++; +} + +/** + * Ends the access to a buffer started by zn_shm_buffer_begin_access + * + * \param buffer The SHM buffer + * + * This should be called after zn_shm_buffer_begin_access once the + * buffer is no longer being accessed. If a SIGBUS signal was + * generated in-between these two calls then the resource for the + * given buffer will be sent an error. + * + * \memberof zn_shm_buffer + */ +void +zn_shm_buffer_end_access(struct zn_shm_buffer *buffer) +{ + struct zn_shm_pool *pool = buffer->pool; + struct zn_shm_sigbus_data *sigbus_data = NULL; + + if (pool->sigbuf_is_impossible) { + return; + } + + sigbus_data = pthread_getspecific(zn_shm_sigbus_data_key); + assert(sigbus_data && sigbus_data->access_count >= 1); + + if (--sigbus_data->access_count == 0) { + if (sigbus_data->fallback_mapping_used) { + wl_resource_post_error(buffer->resource, ZWN_SHM_ERROR_INVALID_FD, + "error accessing SHM buffer"); + sigbus_data->fallback_mapping_used = 0; + } + + sigbus_data->current_pool = NULL; + } +} diff --git a/zen/src/backend/immersive/shm.h b/zen/src/backend/immersive/shm.h new file mode 100644 index 00000000..c2fb1978 --- /dev/null +++ b/zen/src/backend/immersive/shm.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_shm_buffer *zn_shm_buffer_get(struct wl_resource *resource); + +void zn_shm_buffer_begin_access(struct zn_shm_buffer *buffer); + +void zn_shm_buffer_end_access(struct zn_shm_buffer *buffer); + +void *zn_shm_buffer_get_data(struct zn_shm_buffer *buffer); + +ssize_t zn_shm_buffer_get_size(struct zn_shm_buffer *buffer); + +struct zn_shm_pool *zn_shm_buffer_ref_pool(struct zn_shm_buffer *buffer); + +void zn_shm_pool_unref(struct zn_shm_pool *pool); + +int zn_shm_init(struct wl_display *display); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index c109cc89..1f9178f2 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -3,9 +3,11 @@ subdir('immersive/remote') _zen_backend_srcs = [ 'default-backend.c', + 'immersive/client-gl-buffer.c', 'immersive/client-gl-context.c', 'immersive/client-gl-rendering-unit.c', 'immersive/client-virtual-object.c', + 'immersive/shm.c', 'immersive/xr.c', 'immersive/xr-compositor.c', 'immersive/xr-gl.c', diff --git a/zen/src/gl-buffer-private.h b/zen/src/gl-buffer-private.h new file mode 100644 index 00000000..7c803f05 --- /dev/null +++ b/zen/src/gl-buffer-private.h @@ -0,0 +1,17 @@ +#pragma once + +#include "zen/gl-buffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Called by impl object +struct zn_gl_buffer *zn_gl_buffer_create(void *impl_data); + +/// Called by impl object +void zn_gl_buffer_destroy(struct zn_gl_buffer *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/gl-buffer.c b/zen/src/gl-buffer.c new file mode 100644 index 00000000..d1235e23 --- /dev/null +++ b/zen/src/gl-buffer.c @@ -0,0 +1,31 @@ +#include "gl-buffer-private.h" +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_gl_buffer * +zn_gl_buffer_create(void *impl_data) +{ + struct zn_gl_buffer *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_gl_buffer_destroy(struct zn_gl_buffer *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} From a064d57e772781810d4e8e485eab6ebc73cbef00 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 16 Apr 2023 23:09:54 +0900 Subject: [PATCH 15/49] gl_buffer::data --- desktop/src/xr-system.c | 1 + zen/include/zen/buffer.h | 51 ++ zen/include/zen/gl-buffer.h | 22 +- zen/include/zen/lease-buffer.h | 28 + zen/meson.build | 2 + zen/src/backend/immersive/client-gl-buffer.c | 39 +- zen/src/backend/immersive/remote/gl-buffer.cc | 40 +- zen/src/backend/immersive/remote/gl-buffer.h | 12 +- .../backend/immersive/remote/xr-dispatcher.cc | 9 +- .../backend/immersive/remote/xr-dispatcher.h | 7 +- zen/src/backend/immersive/remote/xr-system.cc | 4 +- zen/src/backend/immersive/shm-buffer.c | 296 +++++++++ zen/src/backend/immersive/shm-buffer.h | 23 + zen/src/backend/immersive/shm-pool.c | 206 ++++++ zen/src/backend/immersive/shm-pool.h | 22 + zen/src/backend/immersive/shm.c | 593 +----------------- zen/src/backend/immersive/shm.h | 25 +- zen/src/backend/meson.build | 2 + zen/src/buffer.c | 29 + zen/src/gl-buffer-private.h | 3 +- zen/src/gl-buffer.c | 4 +- zen/src/lease-buffer.c | 32 + zen/src/virtual-object-private.h | 1 - 23 files changed, 836 insertions(+), 615 deletions(-) create mode 100644 zen/include/zen/buffer.h create mode 100644 zen/include/zen/lease-buffer.h create mode 100644 zen/src/backend/immersive/shm-buffer.c create mode 100644 zen/src/backend/immersive/shm-buffer.h create mode 100644 zen/src/backend/immersive/shm-pool.c create mode 100644 zen/src/backend/immersive/shm-pool.h create mode 100644 zen/src/buffer.c create mode 100644 zen/src/lease-buffer.c diff --git a/desktop/src/xr-system.c b/desktop/src/xr-system.c index c5d70e80..09833364 100644 --- a/desktop/src/xr-system.c +++ b/desktop/src/xr-system.c @@ -70,6 +70,7 @@ zn_desktop_xr_system_handle_session_state_changed( struct wl_resource *resource = NULL; + // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores) enum zen_xr_system_status status = self->status; switch (self->zn_xr_system->state) { diff --git a/zen/include/zen/buffer.h b/zen/include/zen/buffer.h new file mode 100644 index 00000000..d2f06316 --- /dev/null +++ b/zen/include/zen/buffer.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include "zen-common/util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_buffer; + +struct zn_buffer_interface { + void *(*begin_access)(struct zn_buffer *self); + /// @return false if errors occur during the access + bool (*end_access)(struct zn_buffer *self); + + ssize_t (*get_size)(struct zn_buffer *self); +}; + +struct zn_buffer { + void *impl_data; // @nullable, @outlive + const struct zn_buffer_interface *impl; // @nonnull, @outlive +}; + +struct zn_buffer *zn_buffer_create( + void *impl_data, const struct zn_buffer_interface *implementation); + +void zn_buffer_destroy(struct zn_buffer *self); + +UNUSED static inline void * +zn_buffer_begin_access(struct zn_buffer *self) +{ + return self->impl->begin_access(self); +} + +UNUSED static inline bool +zn_buffer_end_access(struct zn_buffer *self) +{ + return self->impl->end_access(self); +} + +UNUSED static inline ssize_t +zn_buffer_get_size(struct zn_buffer *self) +{ + return self->impl->get_size(self); +} + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/gl-buffer.h b/zen/include/zen/gl-buffer.h index 03cb52ca..cd2d1ae3 100644 --- a/zen/include/zen/gl-buffer.h +++ b/zen/include/zen/gl-buffer.h @@ -2,18 +2,38 @@ #include +#include "zen-common/util.h" + #ifdef __cplusplus extern "C" { #endif +struct zn_lease_buffer; +struct zn_gl_buffer; + +struct zn_gl_buffer_interface { + /// @param lease_buffer will be released by the callee + void (*data)(struct zn_gl_buffer *self, uint32_t target, + struct zn_lease_buffer *lease_buffer, uint32_t usage); +}; + struct zn_gl_buffer { - void *impl_data; + void *impl_data; // @nullable, @outlive + const struct zn_gl_buffer_interface *impl; // @nonnull, @outlive struct { struct wl_signal destroy; // (NULL) } events; }; +/// @param lease_buffer will be released by the callee +UNUSED static inline void +zn_gl_buffer_data(struct zn_gl_buffer *self, uint32_t target, + struct zn_lease_buffer *lease_buffer, uint32_t usage) +{ + self->impl->data(self, target, lease_buffer, usage); +} + #ifdef __cplusplus } #endif diff --git a/zen/include/zen/lease-buffer.h b/zen/include/zen/lease-buffer.h new file mode 100644 index 00000000..48fd00b9 --- /dev/null +++ b/zen/include/zen/lease-buffer.h @@ -0,0 +1,28 @@ +#pragma once + +struct zn_buffer; + +#ifdef __cplusplus +extern "C" { +#endif + +// NOLINTNEXTLINE(modernize-use-using) +typedef void (*zn_lease_buffer_release_callback)( + struct zn_buffer *buffer, void *user_data); + +struct zn_lease_buffer { + void *user_data; // @nullable, @outlive + struct zn_buffer *buffer; // @nonnull, @outlive + zn_lease_buffer_release_callback callback; +}; + +/// @param zn_buffer must outlive this +struct zn_lease_buffer *zn_lease_buffer_create(struct zn_buffer *buffer, + zn_lease_buffer_release_callback callback, void *user_data); + +/// This also destroy itself +void zn_lease_buffer_release(struct zn_lease_buffer *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/meson.build b/zen/meson.build index e0a1d0ba..a65ba328 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -1,8 +1,10 @@ _zen_srcs = [ + 'src/buffer.c', 'src/config.c', 'src/cursor.c', 'src/gl-buffer.c', 'src/gl-rendering-unit.c', + 'src/lease-buffer.c', 'src/screen.c', 'src/seat.c', 'src/server.c', diff --git a/zen/src/backend/immersive/client-gl-buffer.c b/zen/src/backend/immersive/client-gl-buffer.c index a80671eb..c7634a89 100644 --- a/zen/src/backend/immersive/client-gl-buffer.c +++ b/zen/src/backend/immersive/client-gl-buffer.c @@ -2,10 +2,12 @@ #include +#include "shm-buffer.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen/backend.h" #include "zen/gl-buffer.h" +#include "zen/lease-buffer.h" #include "zen/server.h" #include "zen/xr-dispatcher.h" #include "zen/xr-system.h" @@ -28,12 +30,43 @@ zn_client_gl_buffer_protocol_destroy( wl_resource_destroy(resource); } +static void +zn_client_gl_buffer_data_release_callback( + struct zn_buffer *buffer UNUSED, void *user_data) +{ + struct zn_shm_buffer *shm_buffer = user_data; + + zn_shm_buffer_unref(shm_buffer); +} + /// @param resource can be inert (resource->user_data == NULL) static void zn_client_gl_buffer_protocol_data(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, uint32_t target UNUSED, - struct wl_resource *data UNUSED, uint32_t usage UNUSED) -{} + struct wl_resource *resource, uint32_t target, + struct wl_resource *data_resource, uint32_t usage) +{ + struct zn_client_gl_buffer *self = wl_resource_get_user_data(resource); + + struct zn_shm_buffer *shm_buffer = zn_shm_buffer_get(data_resource); + if (!zn_assert(shm_buffer != NULL, "zn_shm_buffer not found")) { + return; + } + + // NOLINTNEXTLINE(clang-analyzer-core.NullDereference) + struct zn_buffer *zn_buffer = shm_buffer->zn_buffer; + + struct zn_lease_buffer *lease_buffer = zn_lease_buffer_create( + zn_buffer, zn_client_gl_buffer_data_release_callback, shm_buffer); + if (lease_buffer == NULL) { + zn_error("Failed to create lease buffer"); + wl_client_post_no_memory(client); + return; + } + + zn_shm_buffer_ref(shm_buffer); + + zn_gl_buffer_data(self->zn_gl_buffer, target, lease_buffer, usage); +} static const struct zwn_gl_buffer_interface implementation = { .destroy = zn_client_gl_buffer_protocol_destroy, diff --git a/zen/src/backend/immersive/remote/gl-buffer.cc b/zen/src/backend/immersive/remote/gl-buffer.cc index c2b44f4e..ca64585f 100644 --- a/zen/src/backend/immersive/remote/gl-buffer.cc +++ b/zen/src/backend/immersive/remote/gl-buffer.cc @@ -1,9 +1,16 @@ #include "gl-buffer.h" +#include "loop.h" #include "zen-common/log.h" +#include "zen/buffer.h" +#include "zen/lease-buffer.h" namespace zen::backend::immersive::remote { +const zn_gl_buffer_interface GlBuffer::c_implementation_ = { + GlBuffer::HandleData, +}; + GlBuffer::~GlBuffer() { if (c_obj_ != nullptr) { @@ -11,10 +18,13 @@ GlBuffer::~GlBuffer() } } +GlBuffer::GlBuffer(wl_display *display) : display_(display) {} + std::unique_ptr -GlBuffer::New(std::shared_ptr channel) +GlBuffer::New( + std::shared_ptr channel, wl_display *display) { - auto self = std::unique_ptr(new GlBuffer()); + auto self = std::unique_ptr(new GlBuffer(display)); if (!self) { zn_error("Failed to allocate memory"); return nullptr; @@ -31,7 +41,7 @@ GlBuffer::New(std::shared_ptr channel) bool GlBuffer::Init(std::shared_ptr channel) { - c_obj_ = zn_gl_buffer_create(this); + c_obj_ = zn_gl_buffer_create(this, &c_implementation_); if (c_obj_ == nullptr) { zn_error("Failed to create a zn_gl_buffer"); return false; @@ -48,4 +58,28 @@ GlBuffer::Init(std::shared_ptr channel) return true; } +void +GlBuffer::HandleData(struct zn_gl_buffer *c_obj, uint32_t target, + struct zn_lease_buffer *lease_buffer, uint32_t usage) +{ + auto *self = static_cast(c_obj->impl_data); + + ssize_t size = zn_buffer_get_size(lease_buffer->buffer); + + auto loop = std::make_unique(wl_display_get_event_loop(self->display_)); + + auto buffer = zen::remote::server::CreateBuffer( + [lease_buffer]() { return zn_buffer_begin_access(lease_buffer->buffer); }, + [lease_buffer]() { return zn_buffer_end_access(lease_buffer->buffer); }, + [lease_buffer]() { zn_lease_buffer_release(lease_buffer); }, + std::move(loop)); + + if (!buffer) { + zn_abort("Failed to create remote buffer"); + return; + } + + self->remote_obj_->GlBufferData(std::move(buffer), target, size, usage); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-buffer.h b/zen/src/backend/immersive/remote/gl-buffer.h index dc76061f..6fb4ec1a 100644 --- a/zen/src/backend/immersive/remote/gl-buffer.h +++ b/zen/src/backend/immersive/remote/gl-buffer.h @@ -12,17 +12,25 @@ class GlBuffer ~GlBuffer(); static std::unique_ptr New( - std::shared_ptr channel); + std::shared_ptr channel, + wl_display *display); inline zn_gl_buffer *c_obj() const; private: - GlBuffer() = default; + explicit GlBuffer(wl_display *display); bool Init(std::shared_ptr channel); + static void HandleData(struct zn_gl_buffer *c_obj, uint32_t target, + struct zn_lease_buffer *lease_buffer, uint32_t usage); + + wl_display *display_; // @nonnull, @outlive + std::unique_ptr remote_obj_; + static const zn_gl_buffer_interface c_implementation_; + zn_gl_buffer *c_obj_ = nullptr; // @nonnull after Init(), @owning }; diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index 91f0baab..83897831 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -18,6 +18,8 @@ const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { XrDispatcher::HandleDestroyGlBuffer, }; +XrDispatcher::XrDispatcher(wl_display *display) : display_(display) {} + XrDispatcher::~XrDispatcher() { if (c_obj_ != nullptr) { @@ -26,9 +28,10 @@ XrDispatcher::~XrDispatcher() } std::unique_ptr -XrDispatcher::New(std::shared_ptr session) +XrDispatcher::New( + std::shared_ptr session, wl_display *display) { - auto self = std::unique_ptr(new XrDispatcher()); + auto self = std::unique_ptr(new XrDispatcher(display)); if (!self) { zn_error("Failed to allocate memory"); return nullptr; @@ -140,7 +143,7 @@ XrDispatcher::HandleGetNewGlBuffer(zn_xr_dispatcher *c_obj) { auto *self = static_cast(c_obj->impl_data); - auto gl_buffer = GlBuffer::New(self->channel_); + auto gl_buffer = GlBuffer::New(self->channel_, self->display_); if (!gl_buffer) { zn_error("Failed to create a remote gl_buffer"); return nullptr; diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index 7cfdce58..fdcb407c 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -16,12 +16,13 @@ class XrDispatcher ~XrDispatcher(); static std::unique_ptr New( - std::shared_ptr session); + std::shared_ptr session, + wl_display *display); inline zn_xr_dispatcher *c_obj(); private: - XrDispatcher() = default; + explicit XrDispatcher(wl_display *display); bool Init(std::shared_ptr session); @@ -41,6 +42,8 @@ class XrDispatcher static void HandleDestroyGlBuffer( zn_xr_dispatcher *c_obj, struct zn_gl_buffer *gl_buffer_c_obj); + wl_display *display_; // @nonnull, @outlive + std::shared_ptr channel_; std::vector> virtual_objects_; diff --git a/zen/src/backend/immersive/remote/xr-system.cc b/zen/src/backend/immersive/remote/xr-system.cc index 398336b0..5e5a1bd2 100644 --- a/zen/src/backend/immersive/remote/xr-system.cc +++ b/zen/src/backend/immersive/remote/xr-system.cc @@ -124,12 +124,12 @@ XrSystem::Connect() return; } - auto high_priority_dispatcher = XrDispatcher::New(new_session); + auto high_priority_dispatcher = XrDispatcher::New(new_session, display_); if (!high_priority_dispatcher) { zn_error("Failed to create a remote XrDispatcher"); } - auto default_dispatcher = XrDispatcher::New(new_session); + auto default_dispatcher = XrDispatcher::New(new_session, display_); if (!default_dispatcher) { zn_error("Failed to create a remote XrDispatcher"); } diff --git a/zen/src/backend/immersive/shm-buffer.c b/zen/src/backend/immersive/shm-buffer.c new file mode 100644 index 00000000..abaf367e --- /dev/null +++ b/zen/src/backend/immersive/shm-buffer.c @@ -0,0 +1,296 @@ +#include "shm-buffer.h" + +#include +#include +#include +#include + +#include "shm-pool.h" +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/buffer.h" + +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static pthread_once_t zn_shm_sigbus_once = PTHREAD_ONCE_INIT; +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static pthread_key_t zn_shm_sigbus_data_key; +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static struct sigaction zn_shm_old_sigbus_action; + +struct zn_shm_sigbus_data { + struct zn_shm_pool *current_pool; + int access_count; + int fallback_mapping_used; +}; + +static void zn_shm_buffer_destroy(struct zn_shm_buffer *self); + +static void +reraise_sigbus(void) +{ + sigaction(SIGBUS, &zn_shm_old_sigbus_action, NULL); + raise(SIGBUS); // NOLINT(cert-err33-c) +} + +static void +sigbus_handler(int signum UNUSED, siginfo_t *info, void *context UNUSED) +{ + struct zn_shm_sigbus_data *sigbus_data = + pthread_getspecific(zn_shm_sigbus_data_key); + struct zn_shm_pool *pool = NULL; + + if (sigbus_data == NULL) { + reraise_sigbus(); + return; + } + + pool = sigbus_data->current_pool; + + if (pool == NULL || (char *)info->si_addr < pool->data || + (char *)info->si_addr >= pool->data + pool->size) { + reraise_sigbus(); + return; + } + + sigbus_data->fallback_mapping_used = 1; + + if (mmap(pool->data, pool->size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, + 0) == MAP_FAILED) { // NOLINT(performance-no-int-to-ptr) + reraise_sigbus(); + return; + } +} + +static void +destroy_sigbus_data(void *data) +{ + struct zn_shm_sigbus_data *sigbus_data = data; + + free(sigbus_data); +} + +static void +init_sigbus_data_key(void) +{ + struct sigaction new_action = { + .sa_sigaction = sigbus_handler, + .sa_flags = SA_SIGINFO | SA_NODEFER, + }; + + sigemptyset(&new_action.sa_mask); + + sigaction(SIGBUS, &new_action, &zn_shm_old_sigbus_action); + + pthread_key_create(&zn_shm_sigbus_data_key, destroy_sigbus_data); +} + +static void * +zn_shm_buffer_begin_access(struct zn_buffer *zn_buffer) +{ + struct zn_shm_buffer *self = (struct zn_shm_buffer *)(zn_buffer->impl_data); + struct zn_shm_pool *pool = self->pool; + + if (self->pool->external_refcount && + self->pool->size != self->pool->new_size) { + zn_warn( + "Buffer address requested when its parent pool has an external " + "reference and a deferred resize pending."); + } + + void *data = self->pool->data + self->offset; + + if (pool->sigbuf_is_impossible) { + return data; + } + + pthread_once(&zn_shm_sigbus_once, init_sigbus_data_key); + + struct zn_shm_sigbus_data *sigbus_data = + pthread_getspecific(zn_shm_sigbus_data_key); + if (sigbus_data == NULL) { + sigbus_data = zalloc(sizeof *sigbus_data); + if (sigbus_data == NULL) { + return NULL; + } + + pthread_setspecific(zn_shm_sigbus_data_key, sigbus_data); + } + + zn_assert( + sigbus_data->current_pool == NULL || sigbus_data->current_pool == pool, + "Accessing a pool data while accessing another pool data is prohibited"); + + sigbus_data->current_pool = pool; + sigbus_data->access_count++; + + return data; +} + +static bool +zn_shm_buffer_end_access(struct zn_buffer *zn_buffer) +{ + struct zn_shm_buffer *self = (struct zn_shm_buffer *)(zn_buffer->impl_data); + struct zn_shm_pool *pool = self->pool; + + if (pool->sigbuf_is_impossible) { + return true; + } + + struct zn_shm_sigbus_data *sigbus_data = + pthread_getspecific(zn_shm_sigbus_data_key); + if (!zn_assert(sigbus_data && sigbus_data->access_count >= 1, + "More zn_shm_buffer_end_access was called than the previously called " + "zn_shm_buffer_begin_access.")) { + return false; + } + + bool status = true; + + if (--sigbus_data->access_count == 0) { + if (sigbus_data->fallback_mapping_used) { + status = false; + if (self->resource != NULL) { + wl_resource_post_error(self->resource, ZWN_SHM_ERROR_INVALID_FD, + "error accessing SHM buffer"); + } + sigbus_data->fallback_mapping_used = 0; + } + + sigbus_data->current_pool = NULL; + } + + return status; +} + +static ssize_t +zn_shm_buffer_get_size(struct zn_buffer *zn_buffer) +{ + struct zn_shm_buffer *self = (struct zn_shm_buffer *)(zn_buffer->impl_data); + + return self->size; +} + +static const struct zn_buffer_interface buffer_implementation = { + .begin_access = zn_shm_buffer_begin_access, + .end_access = zn_shm_buffer_end_access, + .get_size = zn_shm_buffer_get_size, +}; + +static void +zn_shm_buffer_handle_destroy(struct wl_resource *resource) +{ + struct zn_shm_buffer *self = wl_resource_get_user_data(resource); + + self->resource = NULL; + + zn_shm_buffer_unref(self); +} + +static void +zn_shm_buffer_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct zwn_buffer_interface implementation = { + .destroy = zn_shm_buffer_protocol_destroy, +}; + +void +zn_shm_buffer_ref(struct zn_shm_buffer *self) +{ + zn_assert(self->refcount > 0, "invalid refcount status"); + + self->refcount++; +} + +void +zn_shm_buffer_unref(struct zn_shm_buffer *self) +{ + self->refcount--; + zn_assert(self->refcount >= 0, "invalid refcount status"); + + if (self->refcount == 0) { + zn_shm_buffer_destroy(self); + } +} + +struct zn_shm_buffer * +zn_shm_buffer_get(struct wl_resource *resource) +{ + if (resource == NULL) { + return NULL; + } + + if (!zn_assert(wl_resource_instance_of( + resource, &zwn_buffer_interface, &implementation), + "resource is not zn_shm_buffer")) { + return NULL; + } + + return wl_resource_get_user_data(resource); +} + +struct zn_shm_buffer * +zn_shm_buffer_create(struct wl_client *client, uint32_t id, int64_t offset, + int64_t size, struct wl_resource *pool_resource) +{ + struct zn_shm_pool *pool = wl_resource_get_user_data(pool_resource); + + if (offset < 0 || size <= 0 || offset > pool->size - size) { + wl_resource_post_error( + pool_resource, ZWN_SHM_ERROR_INVALID_SIZE, "invalid size (%ld)", size); + goto err; + } + + struct zn_shm_buffer *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + wl_client_post_no_memory(client); + goto err; + } + + self->refcount = 1; + self->size = size; + self->offset = offset; + self->pool = pool; + + self->zn_buffer = zn_buffer_create(self, &buffer_implementation); + if (self->zn_buffer == NULL) { + zn_error("Failed to create zn_buffer"); + goto err_free; + } + + pool->internal_refcount++; + + self->resource = wl_resource_create(client, &zwn_buffer_interface, 1, id); + if (self->resource == NULL) { + wl_client_post_no_memory(client); + goto err_ref; + } + + wl_resource_set_implementation( + self->resource, &implementation, self, zn_shm_buffer_handle_destroy); + + return self; + +err_ref: + zn_shm_pool_unref(pool, false); + zn_buffer_destroy(self->zn_buffer); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_shm_buffer_destroy(struct zn_shm_buffer *self) +{ + zn_shm_pool_unref(self->pool, false); + zn_buffer_destroy(self->zn_buffer); + free(self); +} diff --git a/zen/src/backend/immersive/shm-buffer.h b/zen/src/backend/immersive/shm-buffer.h new file mode 100644 index 00000000..105feeda --- /dev/null +++ b/zen/src/backend/immersive/shm-buffer.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +struct zn_shm_buffer { + struct wl_resource *resource; // @nullable, @ref + int refcount; + ssize_t size; + ssize_t offset; + struct zn_shm_pool *pool; // @nonnull, @owning(shared) + struct zn_buffer *zn_buffer; // @nonnull, @owning +}; + +void zn_shm_buffer_ref(struct zn_shm_buffer *self); + +void zn_shm_buffer_unref(struct zn_shm_buffer *self); + +struct zn_shm_buffer *zn_shm_buffer_get(struct wl_resource *resource); + +struct zn_shm_buffer *zn_shm_buffer_create(struct wl_client *client, + uint32_t id, int64_t offset, int64_t size, + struct wl_resource *pool_resource); diff --git a/zen/src/backend/immersive/shm-pool.c b/zen/src/backend/immersive/shm-pool.c new file mode 100644 index 00000000..a90fa7ff --- /dev/null +++ b/zen/src/backend/immersive/shm-pool.c @@ -0,0 +1,206 @@ +#include "shm-pool.h" + +#include +#include +#include +#include + +#include "shm-buffer.h" +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen-common/wl-array.h" + +static void zn_shm_pool_destroy(struct zn_shm_pool *self); + +static void * +zn_shm_pool_grow_mapping(struct zn_shm_pool *self) +{ + void *data = NULL; + +#ifdef MREMAP_MAYMOVE + data = mremap(self->data, self->size, self->new_size, MREMAP_MAYMOVE); +#else +#error Operating system must implement mremap(MREMAP_MAYMOVE) +// TODO: fallback +#endif + + return data; +} + +static void +zn_shm_pool_finish_resize(struct zn_shm_pool *self) +{ + if (self->size == self->new_size) { + return; + } + + void *data = zn_shm_pool_grow_mapping(self); + if (data == MAP_FAILED) { // NOLINT(performance-no-int-to-ptr) + if (self->resource) { + wl_resource_post_error( + self->resource, ZWN_SHM_ERROR_INVALID_FD, "failed mremap"); + } + return; + } + + self->data = data; + self->size = self->new_size; +} + +static void +zn_shm_pool_handle_destroy(struct wl_resource *resource) +{ + struct zn_shm_pool *self = wl_resource_get_user_data(resource); + + self->resource = NULL; + + zn_shm_pool_unref(self, false); +} + +static void +zn_shm_pool_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +zn_shm_pool_protocol_create_buffer(struct wl_client *client, + struct wl_resource *resource, uint32_t id, struct wl_array *offset_array, + struct wl_array *size_array) +{ + int64_t offset = 0; + int64_t size = 0; + + if (!zn_wl_array_to_int64_t(offset_array, &offset) || + !zn_wl_array_to_int64_t(size_array, &size)) { + wl_resource_post_error(resource, ZWN_COMPOSITOR_ERROR_INVALID_WL_ARRAY_SIZE, + "invalid wl_array size"); + return; + } + + zn_shm_buffer_create(client, id, offset, size, resource); +} + +static void +zn_shm_pool_protocol_resize( + struct wl_client *client UNUSED, struct wl_resource *resource, int32_t size) +{ + struct zn_shm_pool *self = wl_resource_get_user_data(resource); + + if (size < self->size) { + wl_resource_post_error( + resource, ZWN_SHM_ERROR_INVALID_SIZE, "shrinking pool invalid"); + return; + } + + self->new_size = size; + + if (self->external_refcount == 0) { + zn_shm_pool_finish_resize(self); + } +} + +static const struct zwn_shm_pool_interface implementation = { + .destroy = zn_shm_pool_protocol_destroy, + .create_buffer = zn_shm_pool_protocol_create_buffer, + .resize = zn_shm_pool_protocol_resize, +}; + +void +zn_shm_pool_ref(struct zn_shm_pool *self) +{ + zn_assert(self->internal_refcount + self->external_refcount > 0, + "invalid refcount status"); + + self->external_refcount++; +} + +void +zn_shm_pool_unref(struct zn_shm_pool *self, bool external) +{ + if (external) { + self->external_refcount--; + zn_assert(self->external_refcount >= 0, "invalid external refcount status"); + if (self->external_refcount == 0) { + zn_shm_pool_finish_resize(self); + } + } else { + self->internal_refcount--; + zn_assert(self->external_refcount >= 0, "invalid internal refcount status"); + } + + if (self->internal_refcount + self->external_refcount > 0) { + return; + } + + zn_shm_pool_destroy(self); +} + +struct zn_shm_pool * +zn_shm_pool_create(struct wl_client *client, uint32_t id, int fd, int64_t size, + struct wl_resource *error_resource) +{ + if (size <= 0) { + wl_resource_post_error( + error_resource, ZWN_SHM_ERROR_INVALID_SIZE, "invalid size"); + } + + struct zn_shm_pool *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + int seals = fcntl(fd, F_GET_SEALS); + if (seals == -1) { + seals = 0; + } + + struct stat stat_buf; + if ((seals & F_SEAL_SHRINK) && fstat(fd, &stat_buf) >= 0) { + self->sigbuf_is_impossible = stat_buf.st_size >= size; + } else { + self->sigbuf_is_impossible = false; + } + + self->internal_refcount = 1; + self->external_refcount = 0; + self->size = size; + self->new_size = size; + + self->data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (self->data == MAP_FAILED) { // NOLINT(performance-no-int-to-ptr) + wl_resource_post_error(error_resource, ZWN_SHM_ERROR_INVALID_FD, + "failed mmap fd %d: %s", fd, strerror(errno)); + goto err_free; + } + + self->resource = wl_resource_create(client, &zwn_shm_pool_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_mmap; + } + + wl_resource_set_implementation( + self->resource, &implementation, self, zn_shm_pool_handle_destroy); + + return self; + +err_mmap: + munmap(self->data, self->size); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_shm_pool_destroy(struct zn_shm_pool *self) +{ + munmap(self->data, self->size); + free(self); +} diff --git a/zen/src/backend/immersive/shm-pool.h b/zen/src/backend/immersive/shm-pool.h new file mode 100644 index 00000000..51754a8d --- /dev/null +++ b/zen/src/backend/immersive/shm-pool.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +struct zn_shm_pool { + struct wl_resource *resource; // @nullable, @ref + int internal_refcount; + int external_refcount; + char *data; // @nonnull, mapped + ssize_t size; + ssize_t new_size; + bool sigbuf_is_impossible; +}; + +void zn_shm_pool_ref(struct zn_shm_pool *self); + +void zn_shm_pool_unref(struct zn_shm_pool *self, bool external); + +struct zn_shm_pool *zn_shm_pool_create(struct wl_client *client, uint32_t id, + int fd, int64_t size, struct wl_resource *error_resource); diff --git a/zen/src/backend/immersive/shm.c b/zen/src/backend/immersive/shm.c index f386e817..09b2631f 100644 --- a/zen/src/backend/immersive/shm.c +++ b/zen/src/backend/immersive/shm.c @@ -1,609 +1,56 @@ -/** - * Copyright © 2008-2012 Kristian Høgsberg - * Copyright © 2010-2012 Intel Corporation - * Copyright © 2011 Benjamin Franzke - * Copyright © 2012 Collabora, Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Note: - * This file was copied from wayland project on November 5, 2022 and - * modified for this project. - */ - #include "shm.h" -#include -#include -#include -#include -#include -#include -#include #include #include +#include "shm-pool.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen-common/wl-array.h" -/* This once_t is used to synchronize installing the SIGBUS handler - * and creating the TLS key. This will be done in the first call - * zn_shm_buffer_begin_access which can happen from any thread */ -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -static pthread_once_t zn_shm_sigbus_once = PTHREAD_ONCE_INIT; -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -static pthread_key_t zn_shm_sigbus_data_key; -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -static struct sigaction zn_shm_old_sigbus_action; - -struct zn_shm_pool { - struct wl_resource *resource; - int internal_refcount; - int external_refcount; - char *data; - ssize_t size; - ssize_t new_size; - bool sigbuf_is_impossible; -}; - -/** - * @brief A SHM buffer - * - * zn_shm_buffer provides a helper for accessing the contents of a zwn_buffer - * resource created via the zn_shm interface. - * - * A zn_shm_buffer becomes invalid as soon as its wl_resource is destroyed. - */ -struct zn_shm_buffer { - struct wl_resource *resource; - ssize_t size; - ssize_t offset; - struct zn_shm_pool *pool; -}; - -struct zn_shm_sigbus_data { - struct zn_shm_pool *current_pool; - int access_count; - int fallback_mapping_used; -}; - -static void * -shm_pool_grow_mapping(struct zn_shm_pool *pool) -{ - void *data = NULL; - -#ifdef MREMAP_MAYMOVE - data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE); -#else -#error Operating system must implement mremap(MREMAP_MAYMOVE) - // TODO: fallback -#endif - return data; -} - -static void -shm_pool_finish_resize(struct zn_shm_pool *pool) -{ - void *data = NULL; - - if (pool->size == pool->new_size) { - return; - } - - data = shm_pool_grow_mapping(pool); - if (data == MAP_FAILED) { // NOLINT(performance-no-int-to-ptr) - wl_resource_post_error( - pool->resource, ZWN_SHM_ERROR_INVALID_FD, "failed mremap"); - return; - } - - pool->data = data; - pool->size = pool->new_size; -} - static void -shm_pool_unref(struct zn_shm_pool *pool, bool external) +zn_shm_protocol_create_pool(struct wl_client *client, + struct wl_resource *resource, uint32_t id, int fd, + struct wl_array *size_array) { - if (external) { - pool->external_refcount--; - assert(pool->external_refcount >= 0); - if (pool->external_refcount == 0) { - shm_pool_finish_resize(pool); - } - } else { - pool->internal_refcount--; - assert(pool->internal_refcount >= 0); - } - - if (pool->internal_refcount + pool->external_refcount > 0) { - return; - } - - munmap(pool->data, pool->size); - free(pool); -} - -static void -destroy_buffer(struct wl_resource *resource) -{ - struct zn_shm_buffer *buffer = wl_resource_get_user_data(resource); - - shm_pool_unref(buffer->pool, false); - free(buffer); -} - -static void -shm_buffer_destroy( - struct wl_client *client UNUSED, struct wl_resource *resource) -{ - wl_resource_destroy(resource); -} - -static const struct zwn_buffer_interface shm_buffer_interface = { - shm_buffer_destroy, -}; - -static void -shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource, - uint32_t id, struct wl_array *offset_array, struct wl_array *size_array) -{ - struct zn_shm_pool *pool = wl_resource_get_user_data(resource); - struct zn_shm_buffer *buffer = NULL; - int64_t offset = 0; int64_t size = 0; - if (zn_wl_array_to_int64_t(offset_array, &offset) != 0 || - zn_wl_array_to_int64_t(size_array, &size) != 0) { - wl_resource_post_error( - resource, ZWN_COMPOSITOR_ERROR_INVALID_WL_ARRAY_SIZE, "invalid size"); - } - - if (offset < 0 || size <= 0 || offset > pool->size - size) { - wl_resource_post_error( - resource, ZWN_SHM_ERROR_INVALID_SIZE, "invalid size (%ld)", size); + if (!zn_wl_array_to_int64_t(size_array, &size)) { + wl_resource_post_error(resource, ZWN_COMPOSITOR_ERROR_INVALID_WL_ARRAY_SIZE, + "invalid wl_array size"); return; } - buffer = zalloc(sizeof *buffer); - if (buffer == NULL) { - wl_client_post_no_memory(client); - return; - } - - buffer->size = size; - buffer->offset = offset; - buffer->pool = pool; - pool->internal_refcount++; - - buffer->resource = wl_resource_create(client, &zwn_buffer_interface, 1, id); - if (buffer->resource == NULL) { - wl_client_post_no_memory(client); - shm_pool_unref(pool, false); - free(buffer); - return; - } - - wl_resource_set_implementation( - buffer->resource, &shm_buffer_interface, buffer, destroy_buffer); -} + zn_shm_pool_create(client, id, fd, size, resource); -static void -destroy_pool(struct wl_resource *resource) -{ - struct zn_shm_pool *pool = wl_resource_get_user_data(resource); - - shm_pool_unref(pool, false); -} - -static void -shm_pool_destroy(struct wl_client *client UNUSED, struct wl_resource *resource) -{ - wl_resource_destroy(resource); -} - -static void -shm_pool_resize( - struct wl_client *client UNUSED, struct wl_resource *resource, int32_t size) -{ - struct zn_shm_pool *pool = wl_resource_get_user_data(resource); - - if (size < pool->size) { - wl_resource_post_error( - resource, ZWN_SHM_ERROR_INVALID_FD, "shrinking pool invalid"); - return; - } - - pool->new_size = size; - - /* If the compositor has taken references on this pool it - * may be caching pointers into it. In that case we - * defer the resize (which may move the entire mapping) - * until the compositor finishes dereferencing the pool. - */ - if (pool->external_refcount == 0) { - shm_pool_finish_resize(pool); - } -} - -static const struct zwn_shm_pool_interface shm_pool_interface = { - shm_pool_destroy, - shm_pool_create_buffer, - shm_pool_resize, -}; - -static void -shm_create_pool(struct wl_client *client, struct wl_resource *resource, - uint32_t id, int fd, struct wl_array *size_array) -{ - struct zn_shm_pool *pool = NULL; - struct stat statbuf; - int seals = 0; - int64_t size = 0; - - if (zn_wl_array_to_int64_t(size_array, &size) != 0) { - wl_resource_post_error( - resource, ZWN_SHM_ERROR_INVALID_SIZE, "invalid size"); - goto err_close; - } - - if (size <= 0) { - wl_resource_post_error( - resource, ZWN_SHM_ERROR_INVALID_SIZE, "invalid size (%ld)", size); - goto err_close; - } - - pool = zalloc(sizeof *pool); - if (pool == NULL) { - wl_client_post_no_memory(client); - goto err_close; - } - - seals = fcntl(fd, F_GET_SEALS); - if (seals == -1) { - seals = 0; - } - - if ((seals & F_SEAL_SHRINK) && fstat(fd, &statbuf) >= 0) { - pool->sigbuf_is_impossible = statbuf.st_size >= size; - } else { - pool->sigbuf_is_impossible = false; - } - - pool->internal_refcount = 1; - pool->external_refcount = 0; - pool->size = size; - pool->new_size = size; - pool->data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (pool->data == MAP_FAILED) { // NOLINT(performance-no-int-to-ptr) - wl_resource_post_error(resource, ZWN_SHM_ERROR_INVALID_FD, - "failed mmap fd %d: %s", fd, strerror(errno)); - goto err_free; - } - - close(fd); - - pool->resource = wl_resource_create(client, &zwn_shm_pool_interface, 1, id); - if (!pool->resource) { - wl_client_post_no_memory(client); - munmap(pool->data, pool->size); - free(pool); - return; - } - - wl_resource_set_implementation( - pool->resource, &shm_pool_interface, pool, destroy_pool); - - return; - -err_free: - free(pool); - -err_close: close(fd); } -static const struct zwn_shm_interface shm_interface = { - shm_create_pool, +static const struct zwn_shm_interface implementation = { + .create_pool = zn_shm_protocol_create_pool, }; static void -bind_shm( - struct wl_client *client, void *data, uint32_t version UNUSED, uint32_t id) +zn_shm_bind( + struct wl_client *client, void *data UNUSED, uint32_t version, uint32_t id) { struct wl_resource *resource = - wl_resource_create(client, &zwn_shm_interface, 1, id); - if (!resource) { + wl_resource_create(client, &zwn_shm_interface, (int)version, id); + if (resource == NULL) { wl_client_post_no_memory(client); + zn_error("Failed to create a wl_resource"); return; } - wl_resource_set_implementation(resource, &shm_interface, data, NULL); + wl_resource_set_implementation(resource, &implementation, NULL, NULL); } -int +bool zn_shm_init(struct wl_display *display) { - if (!wl_global_create(display, &zwn_shm_interface, 1, NULL, bind_shm)) { - return -1; + if (!wl_global_create(display, &zwn_shm_interface, 1, NULL, zn_shm_bind)) { + return false; } - return 0; -} - -struct zn_shm_buffer * -zn_shm_buffer_get(struct wl_resource *resource) -{ - if (resource == NULL) { - return NULL; - } - - if (wl_resource_instance_of( - resource, &zwn_buffer_interface, &shm_buffer_interface)) { - return wl_resource_get_user_data(resource); - } - - return NULL; -} - -ssize_t -zn_shm_buffer_get_size(struct zn_shm_buffer *buffer) -{ - return buffer->size; -} - -/** - * Get a pointer to the memory for the SHM buffer - * - * \param buffer The buffer object - * - * Returns a pointer which can be used to read the data contained in - * the given SHM buffer. - * - * As this buffer is memory-mapped, reading from it may generate - * SIGBUS signals. This can happen if the client claims that the - * buffer is larger than it is or if something truncates the - * underlying file. To prevent this signal from causing the compositor - * to crash you should call zn_shm_buffer_begin_access and - * zn_shm_buffer_end_access around code that reads from the memory. - * - * \memberof zn_shm_buffer - */ -void * -zn_shm_buffer_get_data(struct zn_shm_buffer *buffer) -{ - if (buffer->pool->external_refcount && - (buffer->pool->size != buffer->pool->new_size)) { - zn_warn( - "Buffer address requested when its parent pool has an external " - "reference and a deferred resize pending."); - } - - return buffer->pool->data + buffer->offset; -} - -/** - * Get a reference to a shm_buffer's shm_pool - * - * \param buffer The buffer object - * - * Returns a pointer to a buffer's zwn_pool and increases the - * shm_pool refcount. - * - * The compositor must remember to call zn_shm_pool_unref when - * it no longer needs the reference to ensure proper destruction - * of the pool. - * - * \memberof zn_shm_buffer - * \sa zn_shm_pool_unref - */ -struct zn_shm_pool * -zn_shm_buffer_ref_pool(struct zn_shm_buffer *buffer) -{ - assert(buffer->pool->internal_refcount + buffer->pool->external_refcount); - - buffer->pool->external_refcount++; - return buffer->pool; -} - -/** - * Unreference a shm_pool - * - * \param pool The pool object - * - * Drops a reference to a zn_shm_pool object. - * - * This is only necessary if the compositor has explicitly - * taken a reference with zn_shm_buffer_ref_pool(), otherwise - * the pool will be automatically destroyed when appropriate. - * - * \memberof zn_shm_pool - * \sa zn_shm_buffer_ref_pool - */ -void -zn_shm_pool_unref(struct zn_shm_pool *pool) -{ - shm_pool_unref(pool, true); -} - -static void -reraise_sigbus(void) -{ - /* If SIGBUS is raised for some other reason than accessing - * the pool then we'll uninstall the signal handler so we can - * reraise it. This would presumably kill the process */ - sigaction(SIGBUS, &zn_shm_old_sigbus_action, NULL); - raise(SIGBUS); // NOLINT(cert-err33-c) -} - -static void -sigbus_handler(int signum UNUSED, siginfo_t *info, void *context UNUSED) -{ - struct zn_shm_sigbus_data *sigbus_data = - pthread_getspecific(zn_shm_sigbus_data_key); - struct zn_shm_pool *pool = NULL; - - if (sigbus_data == NULL) { - reraise_sigbus(); - return; - } - - pool = sigbus_data->current_pool; - - if (pool == NULL || (char *)info->si_addr < pool->data || - (char *)info->si_addr >= pool->data + pool->size) { - reraise_sigbus(); - return; - } - - sigbus_data->fallback_mapping_used = 1; - - if (mmap(pool->data, pool->size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, - 0) == MAP_FAILED) { // NOLINT(performance-no-int-to-ptr) - reraise_sigbus(); - return; - } -} - -static void -destroy_sigbus_data(void *data) -{ - struct zn_shm_sigbus_data *sigbus_data = data; - - free(sigbus_data); -} - -static void -init_sigbus_data_key(void) -{ - struct sigaction new_action = { - .sa_sigaction = sigbus_handler, - .sa_flags = SA_SIGINFO | SA_NODEFER, - }; - - sigemptyset(&new_action.sa_mask); - - sigaction(SIGBUS, &new_action, &zn_shm_old_sigbus_action); - - pthread_key_create(&zn_shm_sigbus_data_key, destroy_sigbus_data); -} - -/** - * Mark that the given SHM buffer is about to be accessed - * - * \param buffer The SHM buffer - * - * An SHM buffer is a memory-mapped file given by the client. - * According to POSIX, reading from a memory-mapped region that - * extends off the end of the file will cause a SIGBUS signal to be - * generated. Normally this would cause the compositor to terminate. - * In order to make the compositor robust against clients that change - * the size of the underlying file or lie about its size, you should - * protect access to the buffer by calling this function before - * reading from the memory and call zn_shm_buffer_end_access - * afterwards. This will install a signal handler for SIGBUS which - * will prevent the compositor from crashing. - * - * After calling this function the signal handler will remain - * installed for the lifetime of the compositor process. Note that - * this function will not work properly if the compositor is also - * installing its own handler for SIGBUS. - * - * If a SIGBUS signal is received for an address within the range of - * the SHM pool of the given buffer then the client will be sent an - * error event when zn_shm_buffer_end_access is called. If the signal - * is for an address outside that range then the signal handler will - * reraise the signal which would will likely cause the compositor to - * terminate. - * - * It is safe to nest calls to these functions as long as the nested - * calls are all accessing the same buffer. The number of calls to - * zn_shm_buffer_end_access must match the number of calls to - * zn_shm_buffer_begin_access. These functions are thread-safe and it - * is allowed to simultaneously access different buffers or the same - * buffer from multiple threads. - * - * \memberof zn_shm_buffer - */ -void -zn_shm_buffer_begin_access(struct zn_shm_buffer *buffer) -{ - struct zn_shm_pool *pool = buffer->pool; - struct zn_shm_sigbus_data *sigbus_data = NULL; - - if (pool->sigbuf_is_impossible) { - return; - } - - pthread_once(&zn_shm_sigbus_once, init_sigbus_data_key); - - sigbus_data = pthread_getspecific(zn_shm_sigbus_data_key); - if (sigbus_data == NULL) { - sigbus_data = zalloc(sizeof *sigbus_data); - if (sigbus_data == NULL) { - return; - } - - pthread_setspecific(zn_shm_sigbus_data_key, sigbus_data); - } - - assert( - sigbus_data->current_pool == NULL || sigbus_data->current_pool == pool); - - sigbus_data->current_pool = pool; - sigbus_data->access_count++; -} - -/** - * Ends the access to a buffer started by zn_shm_buffer_begin_access - * - * \param buffer The SHM buffer - * - * This should be called after zn_shm_buffer_begin_access once the - * buffer is no longer being accessed. If a SIGBUS signal was - * generated in-between these two calls then the resource for the - * given buffer will be sent an error. - * - * \memberof zn_shm_buffer - */ -void -zn_shm_buffer_end_access(struct zn_shm_buffer *buffer) -{ - struct zn_shm_pool *pool = buffer->pool; - struct zn_shm_sigbus_data *sigbus_data = NULL; - - if (pool->sigbuf_is_impossible) { - return; - } - - sigbus_data = pthread_getspecific(zn_shm_sigbus_data_key); - assert(sigbus_data && sigbus_data->access_count >= 1); - - if (--sigbus_data->access_count == 0) { - if (sigbus_data->fallback_mapping_used) { - wl_resource_post_error(buffer->resource, ZWN_SHM_ERROR_INVALID_FD, - "error accessing SHM buffer"); - sigbus_data->fallback_mapping_used = 0; - } - - sigbus_data->current_pool = NULL; - } + return true; } diff --git a/zen/src/backend/immersive/shm.h b/zen/src/backend/immersive/shm.h index c2fb1978..635b9690 100644 --- a/zen/src/backend/immersive/shm.h +++ b/zen/src/backend/immersive/shm.h @@ -2,26 +2,5 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - -struct zn_shm_buffer *zn_shm_buffer_get(struct wl_resource *resource); - -void zn_shm_buffer_begin_access(struct zn_shm_buffer *buffer); - -void zn_shm_buffer_end_access(struct zn_shm_buffer *buffer); - -void *zn_shm_buffer_get_data(struct zn_shm_buffer *buffer); - -ssize_t zn_shm_buffer_get_size(struct zn_shm_buffer *buffer); - -struct zn_shm_pool *zn_shm_buffer_ref_pool(struct zn_shm_buffer *buffer); - -void zn_shm_pool_unref(struct zn_shm_pool *pool); - -int zn_shm_init(struct wl_display *display); - -#ifdef __cplusplus -} -#endif +/// @return true if successful, false otherwise +bool zn_shm_init(struct wl_display *display); diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 1f9178f2..64087502 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -8,6 +8,8 @@ _zen_backend_srcs = [ 'immersive/client-gl-rendering-unit.c', 'immersive/client-virtual-object.c', 'immersive/shm.c', + 'immersive/shm-buffer.c', + 'immersive/shm-pool.c', 'immersive/xr.c', 'immersive/xr-compositor.c', 'immersive/xr-gl.c', diff --git a/zen/src/buffer.c b/zen/src/buffer.c new file mode 100644 index 00000000..d56c2488 --- /dev/null +++ b/zen/src/buffer.c @@ -0,0 +1,29 @@ +#include "zen/buffer.h" + +#include "zen-common/log.h" +#include "zen-common/util.h" + +struct zn_buffer * +zn_buffer_create( + void *impl_data, const struct zn_buffer_interface *implementation) +{ + struct zn_buffer *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + self->impl = implementation; + + return self; + +err: + return NULL; +} + +void +zn_buffer_destroy(struct zn_buffer *self) +{ + free(self); +} diff --git a/zen/src/gl-buffer-private.h b/zen/src/gl-buffer-private.h index 7c803f05..4b70d3f7 100644 --- a/zen/src/gl-buffer-private.h +++ b/zen/src/gl-buffer-private.h @@ -7,7 +7,8 @@ extern "C" { #endif /// Called by impl object -struct zn_gl_buffer *zn_gl_buffer_create(void *impl_data); +struct zn_gl_buffer *zn_gl_buffer_create( + void *impl_data, const struct zn_gl_buffer_interface *implementation); /// Called by impl object void zn_gl_buffer_destroy(struct zn_gl_buffer *self); diff --git a/zen/src/gl-buffer.c b/zen/src/gl-buffer.c index d1235e23..7fa8411a 100644 --- a/zen/src/gl-buffer.c +++ b/zen/src/gl-buffer.c @@ -4,7 +4,8 @@ #include "zen-common/util.h" struct zn_gl_buffer * -zn_gl_buffer_create(void *impl_data) +zn_gl_buffer_create( + void *impl_data, const struct zn_gl_buffer_interface *implementation) { struct zn_gl_buffer *self = zalloc(sizeof *self); if (self == NULL) { @@ -13,6 +14,7 @@ zn_gl_buffer_create(void *impl_data) } self->impl_data = impl_data; + self->impl = implementation; wl_signal_init(&self->events.destroy); return self; diff --git a/zen/src/lease-buffer.c b/zen/src/lease-buffer.c new file mode 100644 index 00000000..3c273da0 --- /dev/null +++ b/zen/src/lease-buffer.c @@ -0,0 +1,32 @@ +#include "zen/lease-buffer.h" + +#include "zen-common/log.h" +#include "zen-common/util.h" + +struct zn_lease_buffer * +zn_lease_buffer_create(struct zn_buffer *buffer, + zn_lease_buffer_release_callback callback, void *user_data) +{ + struct zn_lease_buffer *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->user_data = user_data; + self->buffer = buffer; + self->callback = callback; + + return self; + +err: + return NULL; +} + +void +zn_lease_buffer_release(struct zn_lease_buffer *self) +{ + self->callback(self->buffer, self->user_data); + + free(self); +} diff --git a/zen/src/virtual-object-private.h b/zen/src/virtual-object-private.h index a62bbdea..00c88ff3 100644 --- a/zen/src/virtual-object-private.h +++ b/zen/src/virtual-object-private.h @@ -13,4 +13,3 @@ void zn_virtual_object_destroy(struct zn_virtual_object *self); #ifdef __cplusplus } #endif - From 1cad059c3de345eb91efd75064d57fb6a95ee7a5 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Fri, 21 Apr 2023 21:33:30 +0900 Subject: [PATCH 16/49] add gl-base-technique --- zen/include/zen/gl-base-technique.h | 19 ++ zen/include/zen/gl-rendering-unit.h | 2 +- zen/include/zen/xr-dispatcher.h | 21 ++ zen/meson.build | 1 + .../immersive/client-gl-base-technique.c | 184 ++++++++++++++++++ .../immersive/client-gl-base-technique.h | 21 ++ zen/src/backend/immersive/client-gl-context.c | 24 ++- .../immersive/client-gl-rendering-unit.c | 7 + .../immersive/client-gl-rendering-unit.h | 4 + .../immersive/remote/gl-base-technique.cc | 55 ++++++ .../immersive/remote/gl-base-technique.h | 46 +++++ .../immersive/remote/gl-rendering-unit.h | 7 + zen/src/backend/immersive/remote/meson.build | 1 + zen/src/backend/immersive/remote/pch/pch.h | 1 + .../backend/immersive/remote/xr-dispatcher.cc | 43 ++++ .../backend/immersive/remote/xr-dispatcher.h | 9 + zen/src/backend/meson.build | 1 + zen/src/gl-base-technique-private.h | 17 ++ zen/src/gl-base-technique.c | 32 +++ 19 files changed, 489 insertions(+), 6 deletions(-) create mode 100644 zen/include/zen/gl-base-technique.h create mode 100644 zen/src/backend/immersive/client-gl-base-technique.c create mode 100644 zen/src/backend/immersive/client-gl-base-technique.h create mode 100644 zen/src/backend/immersive/remote/gl-base-technique.cc create mode 100644 zen/src/backend/immersive/remote/gl-base-technique.h create mode 100644 zen/src/gl-base-technique-private.h create mode 100644 zen/src/gl-base-technique.c diff --git a/zen/include/zen/gl-base-technique.h b/zen/include/zen/gl-base-technique.h new file mode 100644 index 00000000..ed96519c --- /dev/null +++ b/zen/include/zen/gl-base-technique.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_gl_base_technique { + void *impl_data; // @nullable, @outlive + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/gl-rendering-unit.h b/zen/include/zen/gl-rendering-unit.h index a2d5a8f5..b754e62e 100644 --- a/zen/include/zen/gl-rendering-unit.h +++ b/zen/include/zen/gl-rendering-unit.h @@ -7,7 +7,7 @@ extern "C" { #endif struct zn_gl_rendering_unit { - void *impl_data; + void *impl_data; // @nullable, @outlive struct { struct wl_signal destroy; // (NULL) diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index 49773065..0e068a65 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -8,6 +8,7 @@ extern "C" { #endif +struct zn_gl_base_technique; struct zn_gl_buffer; struct zn_gl_rendering_unit; struct zn_virtual_object; @@ -24,6 +25,12 @@ struct zn_xr_dispatcher_interface { void (*destroy_gl_rendering_unit)(struct zn_xr_dispatcher *self, struct zn_gl_rendering_unit *gl_rendering_unit); + struct zn_gl_base_technique *(*get_new_gl_base_technique)( + struct zn_xr_dispatcher *self, + struct zn_gl_rendering_unit *gl_rendering_unit); + void (*destroy_gl_base_technique)(struct zn_xr_dispatcher *self, + struct zn_gl_base_technique *gl_base_technique); + struct zn_gl_buffer *(*get_new_gl_buffer)(struct zn_xr_dispatcher *self); void (*destroy_gl_buffer)( struct zn_xr_dispatcher *self, struct zn_gl_buffer *gl_buffer); @@ -65,6 +72,20 @@ zn_xr_dispatcher_destroy_gl_rendering_unit(struct zn_xr_dispatcher *self, self->impl->destroy_gl_rendering_unit(self, gl_rendering_unit); } +UNUSED static inline struct zn_gl_base_technique * +zn_xr_dispatcher_get_new_gl_base_technique( + struct zn_xr_dispatcher *self, struct zn_gl_rendering_unit *gl_rendering_unit) +{ + return self->impl->get_new_gl_base_technique(self, gl_rendering_unit); +} + +UNUSED static inline void +zn_xr_dispatcher_destroy_gl_base_technique( + struct zn_xr_dispatcher *self, struct zn_gl_base_technique *gl_base_technique) +{ + self->impl->destroy_gl_base_technique(self, gl_base_technique); +} + UNUSED static inline struct zn_gl_buffer * zn_xr_dispatcher_get_new_gl_buffer(struct zn_xr_dispatcher *self) { diff --git a/zen/meson.build b/zen/meson.build index a65ba328..37c5cb79 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -2,6 +2,7 @@ _zen_srcs = [ 'src/buffer.c', 'src/config.c', 'src/cursor.c', + 'src/gl-base-technique.c', 'src/gl-buffer.c', 'src/gl-rendering-unit.c', 'src/lease-buffer.c', diff --git a/zen/src/backend/immersive/client-gl-base-technique.c b/zen/src/backend/immersive/client-gl-base-technique.c new file mode 100644 index 00000000..676ab947 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-base-technique.c @@ -0,0 +1,184 @@ +#include "client-gl-base-technique.h" + +#include + +#include "client-gl-rendering-unit.h" +#include "client-virtual-object.h" +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/gl-base-technique.h" +#include "zen/xr-dispatcher.h" + +static void zn_client_gl_base_technique_destroy( + struct zn_client_gl_base_technique *self); + +static void +zn_client_gl_base_technique_handle_destroy(struct wl_resource *resource) +{ + struct zn_client_gl_base_technique *self = + wl_resource_get_user_data(resource); + + zn_client_gl_base_technique_destroy(self); +} + +static void +zn_client_gl_base_technique_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_base_technique_protocol_bind_program( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + struct wl_resource *program UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_base_technique_protocol_bind_vertex_array( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + struct wl_resource *vertex_array UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_base_technique_protocol_bind_texture( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + uint32_t binding UNUSED, const char *name UNUSED, + struct wl_resource *texture UNUSED, uint32_t target UNUSED, + struct wl_resource *sampler UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_base_technique_protocol_uniform_vector( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + uint32_t location UNUSED, const char *name UNUSED, uint32_t type UNUSED, + uint32_t size UNUSED, uint32_t count UNUSED, struct wl_array *value UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_base_technique_protocol_uniform_matrix( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + uint32_t location UNUSED, const char *name UNUSED, uint32_t col UNUSED, + uint32_t row UNUSED, uint32_t count UNUSED, uint32_t transpose UNUSED, + struct wl_array *value UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_base_technique_protocol_draw_arrays( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + uint32_t mode UNUSED, int32_t first UNUSED, uint32_t count UNUSED) +{} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_base_technique_protocol_draw_elements( + struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, + uint32_t mode UNUSED, uint32_t count UNUSED, uint32_t type UNUSED, + struct wl_array *offset UNUSED, + struct wl_resource *element_array_buffer UNUSED) +{} + +static const struct zwn_gl_base_technique_interface implementation = { + .destroy = zn_client_gl_base_technique_protocol_destroy, + .bind_program = zn_client_gl_base_technique_protocol_bind_program, + .bind_vertex_array = zn_client_gl_base_technique_protocol_bind_vertex_array, + .bind_texture = zn_client_gl_base_technique_protocol_bind_texture, + .uniform_vector = zn_client_gl_base_technique_protocol_uniform_vector, + .uniform_matrix = zn_client_gl_base_technique_protocol_uniform_matrix, + .draw_arrays = zn_client_gl_base_technique_protocol_draw_arrays, + .draw_elements = zn_client_gl_base_technique_protocol_draw_elements, +}; + +static void +zn_client_gl_base_technique_handle_rendering_unit_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_base_technique *self = + zn_container_of(listener, self, rendering_unit_destroy_listener); + + zn_client_gl_base_technique_destroy(self); +} + +static void +zn_client_gl_base_technique_handle_zn_gl_base_technique_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_base_technique *self = + zn_container_of(listener, self, zn_gl_base_technique_destroy_listener); + + zn_client_gl_base_technique_destroy(self); +} + +struct zn_client_gl_base_technique * +zn_client_gl_base_technique_create(struct wl_client *client, uint32_t id, + struct zn_client_gl_rendering_unit *rendering_unit) +{ + struct zn_client_gl_base_technique *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + wl_client_post_no_memory(client); + goto err; + } + + self->rendering_unit = rendering_unit; + + self->zn_gl_base_technique = zn_xr_dispatcher_get_new_gl_base_technique( + rendering_unit->virtual_object->dispatcher, + rendering_unit->zn_gl_rendering_unit); + if (self->zn_gl_base_technique == NULL) { + zn_error("Failed to get new zn_gl_base_technique"); + wl_client_post_no_memory(client); + goto err_free; + } + + self->resource = + wl_resource_create(client, &zwn_gl_base_technique_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_gl_base_technique; + } + + wl_resource_set_implementation(self->resource, &implementation, self, + zn_client_gl_base_technique_handle_destroy); + + self->rendering_unit_destroy_listener.notify = + zn_client_gl_base_technique_handle_rendering_unit_destroy; + wl_signal_add( + &rendering_unit->events.destroy, &self->rendering_unit_destroy_listener); + + self->zn_gl_base_technique_destroy_listener.notify = + zn_client_gl_base_technique_handle_zn_gl_base_technique_destroy; + wl_signal_add(&self->zn_gl_base_technique->events.destroy, + &self->zn_gl_base_technique_destroy_listener); + + return self; + +err_gl_base_technique: + zn_xr_dispatcher_destroy_gl_base_technique( + rendering_unit->virtual_object->dispatcher, self->zn_gl_base_technique); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_client_gl_base_technique_destroy(struct zn_client_gl_base_technique *self) +{ + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); + wl_list_remove(&self->rendering_unit_destroy_listener.link); + wl_list_remove(&self->zn_gl_base_technique_destroy_listener.link); + zn_xr_dispatcher_destroy_gl_base_technique( + self->rendering_unit->virtual_object->dispatcher, + self->zn_gl_base_technique); + free(self); +} diff --git a/zen/src/backend/immersive/client-gl-base-technique.h b/zen/src/backend/immersive/client-gl-base-technique.h new file mode 100644 index 00000000..b701ae3e --- /dev/null +++ b/zen/src/backend/immersive/client-gl-base-technique.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +struct zn_client_gl_rendering_unit; +struct zn_gl_base_technique; + +struct zn_client_gl_base_technique { + struct zn_client_gl_rendering_unit *rendering_unit; // @nonnull @outlive + + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_gl_base_technique *zn_gl_base_technique; // @nonnull, @outlive + + struct wl_listener rendering_unit_destroy_listener; + struct wl_listener zn_gl_base_technique_destroy_listener; +}; + +struct zn_client_gl_base_technique *zn_client_gl_base_technique_create( + struct wl_client *client, uint32_t id, + struct zn_client_gl_rendering_unit *rendering_unit); diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c index 034bb651..8bba50d0 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/client-gl-context.c @@ -3,6 +3,7 @@ #include #include +#include "client-gl-base-technique.h" #include "client-gl-buffer.h" #include "client-gl-rendering-unit.h" #include "xr-compositor.h" @@ -28,9 +29,13 @@ zn_client_gl_context_protocol_destroy( /// @param resource can be inert (resource->user_data == NULL) static void zn_client_gl_context_protocol_create_gl_rendering_unit(struct wl_client *client, - struct wl_resource *resource UNUSED, uint32_t id, + struct wl_resource *resource, uint32_t id, struct wl_resource *virtual_object_resource) { + if (wl_resource_get_user_data(resource) == NULL) { + return; + } + struct zn_client_virtual_object *client_virtual_object = wl_resource_get_user_data(virtual_object_resource); @@ -79,10 +84,19 @@ zn_client_gl_context_protocol_create_gl_vertex_array( /// @param resource can be inert (resource->user_data == NULL) static void -zn_client_gl_context_protocol_create_gl_base_technique( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, - uint32_t id UNUSED, struct wl_resource *unit UNUSED) -{} +zn_client_gl_context_protocol_create_gl_base_technique(struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *rendering_unit_resource) +{ + if (wl_resource_get_user_data(resource) == NULL) { + return; + } + + struct zn_client_gl_rendering_unit *rendering_unit = + wl_resource_get_user_data(rendering_unit_resource); + + zn_client_gl_base_technique_create(client, id, rendering_unit); +} static const struct zwn_gl_context_interface implementation = { .destroy = zn_client_gl_context_protocol_destroy, diff --git a/zen/src/backend/immersive/client-gl-rendering-unit.c b/zen/src/backend/immersive/client-gl-rendering-unit.c index e6fc40fa..68827524 100644 --- a/zen/src/backend/immersive/client-gl-rendering-unit.c +++ b/zen/src/backend/immersive/client-gl-rendering-unit.c @@ -4,6 +4,7 @@ #include "client-virtual-object.h" #include "zen-common/log.h" +#include "zen-common/signal.h" #include "zen-common/util.h" #include "zen/gl-rendering-unit.h" #include "zen/xr-dispatcher.h" @@ -59,15 +60,18 @@ zn_client_gl_rendering_unit_create(struct wl_client *client, uint32_t id, struct zn_client_gl_rendering_unit *self = zalloc(sizeof *self); if (self == NULL) { zn_error("Failed to allocate memory"); + wl_client_post_no_memory(client); goto err; } self->virtual_object = virtual_object; + wl_signal_init(&self->events.destroy); self->zn_gl_rendering_unit = zn_xr_dispatcher_get_new_gl_rendering_unit( virtual_object->dispatcher, virtual_object->zn_virtual_object); if (self->zn_gl_rendering_unit == NULL) { zn_error("Failed to get new zn_gl_rendering_unit"); + wl_client_post_no_memory(client); goto err_free; } @@ -108,9 +112,12 @@ zn_client_gl_rendering_unit_create(struct wl_client *client, uint32_t id, static void zn_client_gl_rendering_unit_destroy(struct zn_client_gl_rendering_unit *self) { + zn_signal_emit_mutable(&self->events.destroy, NULL); + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); wl_list_remove(&self->virtual_object_destroy_listener.link); wl_list_remove(&self->zn_gl_rendering_unit_destroy_listener.link); + wl_list_remove(&self->events.destroy.listener_list); zn_xr_dispatcher_destroy_gl_rendering_unit( self->virtual_object->dispatcher, self->zn_gl_rendering_unit); free(self); diff --git a/zen/src/backend/immersive/client-gl-rendering-unit.h b/zen/src/backend/immersive/client-gl-rendering-unit.h index 21fbf70d..cd9129aa 100644 --- a/zen/src/backend/immersive/client-gl-rendering-unit.h +++ b/zen/src/backend/immersive/client-gl-rendering-unit.h @@ -14,6 +14,10 @@ struct zn_client_gl_rendering_unit { struct wl_listener virtual_object_destroy_listener; struct wl_listener zn_gl_rendering_unit_destroy_listener; + + struct { + struct wl_signal destroy; // (NULL) + } events; }; struct zn_client_gl_rendering_unit *zn_client_gl_rendering_unit_create( diff --git a/zen/src/backend/immersive/remote/gl-base-technique.cc b/zen/src/backend/immersive/remote/gl-base-technique.cc new file mode 100644 index 00000000..bb136264 --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-base-technique.cc @@ -0,0 +1,55 @@ +#include "gl-base-technique.h" + +#include "gl-rendering-unit.h" +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +GlBaseTechnique::~GlBaseTechnique() +{ + if (c_obj_ != nullptr) { + zn_gl_base_technique_destroy(c_obj_); + } +} + +std::unique_ptr +GlBaseTechnique::New(std::shared_ptr channel, + std::unique_ptr &rendering_unit) +{ + auto self = std::unique_ptr(new GlBaseTechnique()); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(channel), rendering_unit)) { + zn_error("Failed to initialize a remote GlBaseTechnique"); + return nullptr; + } + + return self; +} + +bool +GlBaseTechnique::Init(std::shared_ptr channel, + std::unique_ptr &rendering_unit) +{ + c_obj_ = zn_gl_base_technique_create(this); + if (c_obj_ == nullptr) { + zn_error("Failed to create a zn_gl_base_technique"); + return false; + } + + remote_obj_ = zen::remote::server::CreateGlBaseTechnique( + std::move(channel), rendering_unit->remote_obj()->id()); + if (!remote_obj_) { + zn_error("Failed to create a remote GlBaseTechnique"); + zn_gl_base_technique_destroy(c_obj_); + c_obj_ = nullptr; + return false; + } + + return true; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-base-technique.h b/zen/src/backend/immersive/remote/gl-base-technique.h new file mode 100644 index 00000000..902d4bed --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-base-technique.h @@ -0,0 +1,46 @@ +#pragma once + +#include "gl-base-technique-private.h" +#include "zen-common/cpp-util.h" + +namespace zen::backend::immersive::remote { + +class GlRenderingUnit; + +class GlBaseTechnique +{ + public: + DISABLE_MOVE_AND_COPY(GlBaseTechnique); + ~GlBaseTechnique(); + + static std::unique_ptr New( + std::shared_ptr channel, + std::unique_ptr &rendering_unit); + + inline std::unique_ptr &remote_obj(); + inline zn_gl_base_technique *c_obj(); + + private: + GlBaseTechnique() = default; + + bool Init(std::shared_ptr channel, + std::unique_ptr &rendering_unit); + + std::unique_ptr remote_obj_; + + zn_gl_base_technique *c_obj_ = nullptr; // @nonnull after Init(), @owning +}; + +inline zn_gl_base_technique * +GlBaseTechnique::c_obj() +{ + return c_obj_; +} + +inline std::unique_ptr & +GlBaseTechnique::remote_obj() +{ + return remote_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-rendering-unit.h b/zen/src/backend/immersive/remote/gl-rendering-unit.h index 4ef7118c..1b8d41cf 100644 --- a/zen/src/backend/immersive/remote/gl-rendering-unit.h +++ b/zen/src/backend/immersive/remote/gl-rendering-unit.h @@ -17,6 +17,7 @@ class GlRenderingUnit std::shared_ptr channel, std::unique_ptr &virtual_object); + inline std::unique_ptr &remote_obj(); inline zn_gl_rendering_unit *c_obj(); private: @@ -36,4 +37,10 @@ GlRenderingUnit::c_obj() return c_obj_; } +inline std::unique_ptr & +GlRenderingUnit::remote_obj() +{ + return remote_obj_; +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index 8b274645..fc0e3921 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -1,4 +1,5 @@ _zen_remote_immersive_backend_srcs = [ + 'gl-base-technique.cc', 'gl-buffer.cc', 'gl-rendering-unit.cc', 'loop.cc', diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index e8f8426a..94862b9b 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index 83897831..c138511f 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -2,6 +2,7 @@ #include +#include "gl-base-technique.h" #include "gl-buffer.h" #include "gl-rendering-unit.h" #include "virtual-object.h" @@ -14,6 +15,8 @@ const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { XrDispatcher::HandleDestroyVirtualObject, XrDispatcher::HandleGetNewGlRenderingUnit, XrDispatcher::HandleDestroyGlRenderingUnit, + XrDispatcher::HandleGetNewGlBaseTechnique, + XrDispatcher::HandleDestroyGlBaseTechnique, XrDispatcher::HandleGetNewGlBuffer, XrDispatcher::HandleDestroyGlBuffer, }; @@ -138,6 +141,46 @@ XrDispatcher::HandleDestroyGlRenderingUnit( self->gl_rendering_units_.erase(result, self->gl_rendering_units_.end()); } +zn_gl_base_technique * +XrDispatcher::HandleGetNewGlBaseTechnique( + zn_xr_dispatcher *c_obj, zn_gl_rendering_unit *gl_rendering_unit_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + for (auto &rendering_unit : self->gl_rendering_units_) { + if (rendering_unit->c_obj() != gl_rendering_unit_c_obj) { + continue; + } + + auto gl_base_technique = + GlBaseTechnique::New(self->channel_, rendering_unit); + + auto *gl_base_technique_c_obj = gl_base_technique->c_obj(); + + self->gl_base_techniques_.push_back(std::move(gl_base_technique)); + + return gl_base_technique_c_obj; + } + + return nullptr; +} + +void +XrDispatcher::HandleDestroyGlBaseTechnique( + zn_xr_dispatcher *c_obj, zn_gl_base_technique *gl_base_technique_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto result = std::remove_if(self->gl_base_techniques_.begin(), + self->gl_base_techniques_.end(), + [gl_base_technique_c_obj]( + std::unique_ptr &gl_base_technique) { + return gl_base_technique->c_obj() == gl_base_technique_c_obj; + }); + + self->gl_base_techniques_.erase(result, self->gl_base_techniques_.end()); +} + zn_gl_buffer * XrDispatcher::HandleGetNewGlBuffer(zn_xr_dispatcher *c_obj) { diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index fdcb407c..4f6952d5 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -8,6 +8,7 @@ namespace zen::backend::immersive::remote { class VirtualObject; class GlBuffer; class GlRenderingUnit; +class GlBaseTechnique; class XrDispatcher { @@ -37,6 +38,12 @@ class XrDispatcher static void HandleDestroyGlRenderingUnit( zn_xr_dispatcher *c_obj, zn_gl_rendering_unit *gl_rendering_unit_c_obj); + static zn_gl_base_technique *HandleGetNewGlBaseTechnique( + zn_xr_dispatcher *c_obj, zn_gl_rendering_unit *gl_rendering_unit_c_obj); + + static void HandleDestroyGlBaseTechnique( + zn_xr_dispatcher *c_obj, zn_gl_base_technique *gl_base_technique_c_obj); + static zn_gl_buffer *HandleGetNewGlBuffer(zn_xr_dispatcher *c_obj); static void HandleDestroyGlBuffer( @@ -50,6 +57,8 @@ class XrDispatcher std::vector> gl_rendering_units_; + std::vector> gl_base_techniques_; + std::vector> gl_buffers_; static const zn_xr_dispatcher_interface c_implementation_; diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 64087502..fdd915fa 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -3,6 +3,7 @@ subdir('immersive/remote') _zen_backend_srcs = [ 'default-backend.c', + 'immersive/client-gl-base-technique.c', 'immersive/client-gl-buffer.c', 'immersive/client-gl-context.c', 'immersive/client-gl-rendering-unit.c', diff --git a/zen/src/gl-base-technique-private.h b/zen/src/gl-base-technique-private.h new file mode 100644 index 00000000..d02fa8aa --- /dev/null +++ b/zen/src/gl-base-technique-private.h @@ -0,0 +1,17 @@ +#pragma once + +#include "zen/gl-base-technique.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Called by impl object +struct zn_gl_base_technique *zn_gl_base_technique_create(void *impl_data); + +/// Called by impl object +void zn_gl_base_technique_destroy(struct zn_gl_base_technique *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/gl-base-technique.c b/zen/src/gl-base-technique.c new file mode 100644 index 00000000..2ae17b4d --- /dev/null +++ b/zen/src/gl-base-technique.c @@ -0,0 +1,32 @@ +#include "gl-base-technique-private.h" +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_gl_base_technique * +zn_gl_base_technique_create(void *impl_data) +{ + struct zn_gl_base_technique *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_gl_base_technique_destroy(struct zn_gl_base_technique *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + + free(self); +} From e18f76afbb4177120bbdd991027d87932af21d40 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 26 Apr 2023 17:04:47 +0900 Subject: [PATCH 17/49] add gl-shader --- zen/include/zen/gl-shader.h | 21 +++ zen/include/zen/lease-buffer.h | 7 +- zen/include/zen/xr-dispatcher.h | 29 +++- zen/meson.build | 1 + zen/src/backend/immersive/client-gl-context.c | 14 +- .../immersive/client-gl-rendering-unit.h | 2 +- zen/src/backend/immersive/client-gl-shader.c | 138 ++++++++++++++++++ zen/src/backend/immersive/client-gl-shader.h | 17 +++ zen/src/backend/immersive/remote/gl-shader.cc | 57 ++++++++ zen/src/backend/immersive/remote/gl-shader.h | 39 +++++ zen/src/backend/immersive/remote/meson.build | 1 + zen/src/backend/immersive/remote/pch/pch.h | 1 + .../backend/immersive/remote/xr-dispatcher.cc | 51 ++++++- .../backend/immersive/remote/xr-dispatcher.h | 13 +- zen/src/backend/meson.build | 1 + zen/src/gl-shader-private.h | 17 +++ zen/src/gl-shader.c | 31 ++++ zen/src/lease-buffer.c | 4 +- 18 files changed, 428 insertions(+), 16 deletions(-) create mode 100644 zen/include/zen/gl-shader.h create mode 100644 zen/src/backend/immersive/client-gl-shader.c create mode 100644 zen/src/backend/immersive/client-gl-shader.h create mode 100644 zen/src/backend/immersive/remote/gl-shader.cc create mode 100644 zen/src/backend/immersive/remote/gl-shader.h create mode 100644 zen/src/gl-shader-private.h create mode 100644 zen/src/gl-shader.c diff --git a/zen/include/zen/gl-shader.h b/zen/include/zen/gl-shader.h new file mode 100644 index 00000000..bafe5802 --- /dev/null +++ b/zen/include/zen/gl-shader.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "zen-common/util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_gl_shader { + void *impl_data; // @nullable, @outlive + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/lease-buffer.h b/zen/include/zen/lease-buffer.h index 48fd00b9..9524b703 100644 --- a/zen/include/zen/lease-buffer.h +++ b/zen/include/zen/lease-buffer.h @@ -11,12 +11,13 @@ typedef void (*zn_lease_buffer_release_callback)( struct zn_buffer *buffer, void *user_data); struct zn_lease_buffer { - void *user_data; // @nullable, @outlive - struct zn_buffer *buffer; // @nonnull, @outlive - zn_lease_buffer_release_callback callback; + void *user_data; // @nullable, @outlive + struct zn_buffer *buffer; // @nonnull, @outlive + zn_lease_buffer_release_callback callback; // @nullable, @outlive }; /// @param zn_buffer must outlive this +/// @param callback is nullable struct zn_lease_buffer *zn_lease_buffer_create(struct zn_buffer *buffer, zn_lease_buffer_release_callback callback, void *user_data); diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index 0e068a65..e78a2459 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -11,6 +11,8 @@ extern "C" { struct zn_gl_base_technique; struct zn_gl_buffer; struct zn_gl_rendering_unit; +struct zn_gl_shader; +struct zn_lease_buffer; struct zn_virtual_object; struct zn_xr_dispatcher; @@ -34,6 +36,11 @@ struct zn_xr_dispatcher_interface { struct zn_gl_buffer *(*get_new_gl_buffer)(struct zn_xr_dispatcher *self); void (*destroy_gl_buffer)( struct zn_xr_dispatcher *self, struct zn_gl_buffer *gl_buffer); + + struct zn_gl_shader *(*get_new_gl_shader)(struct zn_xr_dispatcher *self, + struct zn_lease_buffer *buffer, uint32_t type); + void (*destroy_gl_shader)( + struct zn_xr_dispatcher *self, struct zn_gl_shader *gl_shader); }; struct zn_xr_dispatcher { @@ -73,15 +80,15 @@ zn_xr_dispatcher_destroy_gl_rendering_unit(struct zn_xr_dispatcher *self, } UNUSED static inline struct zn_gl_base_technique * -zn_xr_dispatcher_get_new_gl_base_technique( - struct zn_xr_dispatcher *self, struct zn_gl_rendering_unit *gl_rendering_unit) +zn_xr_dispatcher_get_new_gl_base_technique(struct zn_xr_dispatcher *self, + struct zn_gl_rendering_unit *gl_rendering_unit) { return self->impl->get_new_gl_base_technique(self, gl_rendering_unit); } UNUSED static inline void -zn_xr_dispatcher_destroy_gl_base_technique( - struct zn_xr_dispatcher *self, struct zn_gl_base_technique *gl_base_technique) +zn_xr_dispatcher_destroy_gl_base_technique(struct zn_xr_dispatcher *self, + struct zn_gl_base_technique *gl_base_technique) { self->impl->destroy_gl_base_technique(self, gl_base_technique); } @@ -99,6 +106,20 @@ zn_xr_dispatcher_destroy_gl_buffer( self->impl->destroy_gl_buffer(self, gl_buffer); } +UNUSED static inline struct zn_gl_shader * +zn_xr_dispatcher_get_new_gl_shader(struct zn_xr_dispatcher *self, + struct zn_lease_buffer *buffer, uint32_t type) +{ + return self->impl->get_new_gl_shader(self, buffer, type); +} + +UNUSED static void +zn_xr_dispatcher_destroy_gl_shader( + struct zn_xr_dispatcher *self, struct zn_gl_shader *gl_shader) +{ + self->impl->destroy_gl_shader(self, gl_shader); +} + #ifdef __cplusplus } #endif diff --git a/zen/meson.build b/zen/meson.build index 37c5cb79..5504c714 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -5,6 +5,7 @@ _zen_srcs = [ 'src/gl-base-technique.c', 'src/gl-buffer.c', 'src/gl-rendering-unit.c', + 'src/gl-shader.c', 'src/lease-buffer.c', 'src/screen.c', 'src/seat.c', diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c index 8bba50d0..3d11eeaf 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/client-gl-context.c @@ -6,6 +6,8 @@ #include "client-gl-base-technique.h" #include "client-gl-buffer.h" #include "client-gl-rendering-unit.h" +#include "client-gl-shader.h" +#include "shm-buffer.h" #include "xr-compositor.h" #include "zen-common/log.h" #include "zen-common/util.h" @@ -52,10 +54,14 @@ zn_client_gl_context_protocol_create_gl_buffer( /// @param resource can be inert (resource->user_data == NULL) static void -zn_client_gl_context_protocol_create_gl_shader(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, uint32_t id UNUSED, - struct wl_resource *buffer UNUSED, uint32_t type UNUSED) -{} +zn_client_gl_context_protocol_create_gl_shader(struct wl_client *client, + struct wl_resource *resource UNUSED, uint32_t id, + struct wl_resource *buffer_resource, uint32_t type) +{ + struct zn_shm_buffer *buffer = zn_shm_buffer_get(buffer_resource); + + zn_client_gl_shader_create(client, id, buffer, type); +} /// @param resource can be inert (resource->user_data == NULL) static void diff --git a/zen/src/backend/immersive/client-gl-rendering-unit.h b/zen/src/backend/immersive/client-gl-rendering-unit.h index cd9129aa..fbc2d9f9 100644 --- a/zen/src/backend/immersive/client-gl-rendering-unit.h +++ b/zen/src/backend/immersive/client-gl-rendering-unit.h @@ -16,7 +16,7 @@ struct zn_client_gl_rendering_unit { struct wl_listener zn_gl_rendering_unit_destroy_listener; struct { - struct wl_signal destroy; // (NULL) + struct wl_signal destroy; // (NULL) } events; }; diff --git a/zen/src/backend/immersive/client-gl-shader.c b/zen/src/backend/immersive/client-gl-shader.c new file mode 100644 index 00000000..0a03e4b4 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-shader.c @@ -0,0 +1,138 @@ +#include "client-gl-shader.h" + +#include + +#include "shm-buffer.h" +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/backend.h" +#include "zen/buffer.h" +#include "zen/gl-shader.h" +#include "zen/lease-buffer.h" +#include "zen/server.h" +#include "zen/xr-dispatcher.h" +#include "zen/xr-system.h" + +static void zn_client_gl_shader_destroy(struct zn_client_gl_shader *self); + +static void +zn_client_gl_shader_handle_destroy(struct wl_resource *resource) +{ + struct zn_client_gl_shader *self = wl_resource_get_user_data(resource); + + zn_client_gl_shader_destroy(self); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_shader_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct zwn_gl_shader_interface implementation = { + .destroy = zn_client_gl_shader_protocol_destroy, +}; + +static void +zn_client_gl_shader_handle_zn_gl_shader_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_shader *self = + zn_container_of(listener, self, zn_gl_shader_destroy_listener); + + zn_client_gl_shader_destroy(self); +} + +static void +zn_client_gl_shader_buffer_release_callback( + struct zn_buffer *buffer UNUSED, void *user_data) +{ + struct zn_shm_buffer *shm_buffer = user_data; + + zn_shm_buffer_unref(shm_buffer); +} + +struct zn_client_gl_shader * +zn_client_gl_shader_create(struct wl_client *client, uint32_t id, + struct zn_shm_buffer *buffer, uint32_t type) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + if (xr_system == NULL || !zn_xr_system_is_connected(xr_system)) { + zn_error("Failed to get xr_system"); + goto err; + } + + struct zn_client_gl_shader *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + wl_client_post_no_memory(client); + goto err; + } + + struct zn_lease_buffer *lease_buffer = zn_lease_buffer_create( + buffer->zn_buffer, zn_client_gl_shader_buffer_release_callback, buffer); + if (lease_buffer == NULL) { + zn_error("Failed to create lease buffer"); + wl_client_post_no_memory(client); + goto err_free; + } + + zn_shm_buffer_ref(buffer); + + self->zn_gl_shader = zn_xr_dispatcher_get_new_gl_shader( + xr_system->default_dispatcher, lease_buffer, type); + if (self->zn_gl_shader == NULL) { + zn_error("Failed to get new gl_shader"); + zn_lease_buffer_release(lease_buffer); + wl_client_post_no_memory(client); + goto err_free; + } + + self->resource = wl_resource_create(client, &zwn_gl_shader_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_gl_shader; + } + + wl_resource_set_implementation(self->resource, &implementation, self, + zn_client_gl_shader_handle_destroy); + + self->zn_gl_shader_destroy_listener.notify = + zn_client_gl_shader_handle_zn_gl_shader_destroy; + wl_signal_add(&self->zn_gl_shader->events.destroy, + &self->zn_gl_shader_destroy_listener); + + return self; + +err_gl_shader: + zn_xr_dispatcher_destroy_gl_shader( + xr_system->default_dispatcher, self->zn_gl_shader); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_client_gl_shader_destroy(struct zn_client_gl_shader *self) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); + wl_list_remove(&self->zn_gl_shader_destroy_listener.link); + + if (xr_system != NULL && zn_xr_system_is_connected(xr_system)) { + zn_xr_dispatcher_destroy_gl_shader( + xr_system->default_dispatcher, self->zn_gl_shader); + } + + free(self); +} diff --git a/zen/src/backend/immersive/client-gl-shader.h b/zen/src/backend/immersive/client-gl-shader.h new file mode 100644 index 00000000..3f0b1743 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-shader.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +struct zn_shm_buffer; +struct zn_gl_shader; + +struct zn_client_gl_shader { + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_gl_shader *zn_gl_shader; // @nonnull, @outlive + + struct wl_listener zn_gl_shader_destroy_listener; +}; + +struct zn_client_gl_shader *zn_client_gl_shader_create(struct wl_client *client, + uint32_t id, struct zn_shm_buffer *buffer, uint32_t type); diff --git a/zen/src/backend/immersive/remote/gl-shader.cc b/zen/src/backend/immersive/remote/gl-shader.cc new file mode 100644 index 00000000..467254c1 --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-shader.cc @@ -0,0 +1,57 @@ +#include "gl-shader.h" + +#include + +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +GlShader::~GlShader() +{ + if (c_obj_ != nullptr) { + zn_gl_shader_destroy(c_obj_); + } +} + +std::unique_ptr +GlShader::New(std::shared_ptr channel, + std::string source, uint32_t type) + +{ + auto self = std::unique_ptr(new GlShader()); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(channel), std::move(source), type)) { + zn_error("Failed to initialize a remote GlShader"); + return nullptr; + } + + return self; +} + +bool +GlShader::Init(std::shared_ptr channel, + std::string source, uint32_t type) +{ + c_obj_ = zn_gl_shader_create(this); + if (c_obj_ == nullptr) { + zn_error("Failed to create a zn_gl_shader"); + return false; + } + + remote_obj_ = zen::remote::server::CreateGlShader( + std::move(channel), std::move(source), type); + if (!remote_obj_) { + zn_error("Failed to create a remote GlShader"); + zn_gl_shader_destroy(c_obj_); + c_obj_ = nullptr; + return false; + } + + return true; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-shader.h b/zen/src/backend/immersive/remote/gl-shader.h new file mode 100644 index 00000000..b5f6ace0 --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-shader.h @@ -0,0 +1,39 @@ +#pragma once + +#include "gl-shader-private.h" +#include "zen-common/cpp-util.h" + +struct zn_lease_buffer; + +namespace zen::backend::immersive::remote { + +class GlShader +{ + public: + DISABLE_MOVE_AND_COPY(GlShader); + ~GlShader(); + + static std::unique_ptr New( + std::shared_ptr channel, + std::string source, uint32_t type); + + inline zn_gl_shader *c_obj() const; + + private: + GlShader() = default; + + bool Init(std::shared_ptr channel, + std::string source, uint32_t type); + + std::unique_ptr remote_obj_; + + zn_gl_shader *c_obj_ = nullptr; // @nonnull after Init(), @owning +}; + +inline zn_gl_shader * +GlShader::c_obj() const +{ + return c_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index fc0e3921..d37bb45d 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -2,6 +2,7 @@ _zen_remote_immersive_backend_srcs = [ 'gl-base-technique.cc', 'gl-buffer.cc', 'gl-rendering-unit.cc', + 'gl-shader.cc', 'loop.cc', 'virtual-object.cc', 'xr-dispatcher.cc', diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index 94862b9b..5942e35f 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index c138511f..3e4dd9a2 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -5,8 +5,11 @@ #include "gl-base-technique.h" #include "gl-buffer.h" #include "gl-rendering-unit.h" +#include "gl-shader.h" #include "virtual-object.h" #include "zen-common/log.h" +#include "zen/buffer.h" +#include "zen/lease-buffer.h" namespace zen::backend::immersive::remote { @@ -19,6 +22,8 @@ const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { XrDispatcher::HandleDestroyGlBaseTechnique, XrDispatcher::HandleGetNewGlBuffer, XrDispatcher::HandleDestroyGlBuffer, + XrDispatcher::HandleGetNewGlShader, + XrDispatcher::HandleDestroyGlShader, }; XrDispatcher::XrDispatcher(wl_display *display) : display_(display) {} @@ -194,7 +199,7 @@ XrDispatcher::HandleGetNewGlBuffer(zn_xr_dispatcher *c_obj) auto *gl_buffer_c_obj = gl_buffer->c_obj(); - self->gl_buffers_.push_back((std::move(gl_buffer))); + self->gl_buffers_.push_back(std::move(gl_buffer)); return gl_buffer_c_obj; } @@ -214,4 +219,48 @@ XrDispatcher::HandleDestroyGlBuffer( self->gl_buffers_.erase(result, self->gl_buffers_.end()); } +zn_gl_shader * +XrDispatcher::HandleGetNewGlShader(struct zn_xr_dispatcher *c_obj, + struct zn_lease_buffer *lease_buffer, uint32_t type) +{ + auto *self = static_cast(c_obj->impl_data); + + std::string source; + + { + ssize_t length = zn_buffer_get_size(lease_buffer->buffer); + auto *data = zn_buffer_begin_access(lease_buffer->buffer); + source = std::string(static_cast(data), length); + zn_buffer_end_access(lease_buffer->buffer); + zn_lease_buffer_release(lease_buffer); + } + + auto gl_shader = GlShader::New(self->channel_, std::move(source), type); + if (!gl_shader) { + zn_error("Failed to create a remote gl_shader"); + return nullptr; + } + + auto *gl_shader_c_obj = gl_shader->c_obj(); + + self->gl_shaders_.push_back(std::move(gl_shader)); + + return gl_shader_c_obj; +} + +void +XrDispatcher::HandleDestroyGlShader( + struct zn_xr_dispatcher *c_obj, struct zn_gl_shader *gl_shader_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto result = + std::remove_if(self->gl_shaders_.begin(), self->gl_shaders_.end(), + [gl_shader_c_obj](std::unique_ptr &gl_shader) { + return gl_shader->c_obj() == gl_shader_c_obj; + }); + + self->gl_shaders_.erase(result, self->gl_shaders_.end()); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index 4f6952d5..fb2a8bfa 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -5,10 +5,11 @@ namespace zen::backend::immersive::remote { -class VirtualObject; +class GlBaseTechnique; class GlBuffer; class GlRenderingUnit; -class GlBaseTechnique; +class GlShader; +class VirtualObject; class XrDispatcher { @@ -49,6 +50,12 @@ class XrDispatcher static void HandleDestroyGlBuffer( zn_xr_dispatcher *c_obj, struct zn_gl_buffer *gl_buffer_c_obj); + static zn_gl_shader *HandleGetNewGlShader(struct zn_xr_dispatcher *c_obj, + struct zn_lease_buffer *buffer, uint32_t type); + + static void HandleDestroyGlShader( + struct zn_xr_dispatcher *c_obj, struct zn_gl_shader *gl_shader_c_obj); + wl_display *display_; // @nonnull, @outlive std::shared_ptr channel_; @@ -61,6 +68,8 @@ class XrDispatcher std::vector> gl_buffers_; + std::vector> gl_shaders_; + static const zn_xr_dispatcher_interface c_implementation_; zn_xr_dispatcher *c_obj_ = nullptr; // @nonnull after Init(), @owning diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index fdd915fa..864f8f11 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -7,6 +7,7 @@ _zen_backend_srcs = [ 'immersive/client-gl-buffer.c', 'immersive/client-gl-context.c', 'immersive/client-gl-rendering-unit.c', + 'immersive/client-gl-shader.c', 'immersive/client-virtual-object.c', 'immersive/shm.c', 'immersive/shm-buffer.c', diff --git a/zen/src/gl-shader-private.h b/zen/src/gl-shader-private.h new file mode 100644 index 00000000..f9b4ae3d --- /dev/null +++ b/zen/src/gl-shader-private.h @@ -0,0 +1,17 @@ +#pragma once + +#include "zen/gl-shader.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Called by impl object +struct zn_gl_shader *zn_gl_shader_create(void *impl_data); + +/// Called by impl object +void zn_gl_shader_destroy(struct zn_gl_shader *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/gl-shader.c b/zen/src/gl-shader.c new file mode 100644 index 00000000..851d0c40 --- /dev/null +++ b/zen/src/gl-shader.c @@ -0,0 +1,31 @@ +#include "gl-shader-private.h" +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_gl_shader * +zn_gl_shader_create(void *impl_data) +{ + struct zn_gl_shader *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_gl_shader_destroy(struct zn_gl_shader *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} diff --git a/zen/src/lease-buffer.c b/zen/src/lease-buffer.c index 3c273da0..260a3fc4 100644 --- a/zen/src/lease-buffer.c +++ b/zen/src/lease-buffer.c @@ -26,7 +26,9 @@ zn_lease_buffer_create(struct zn_buffer *buffer, void zn_lease_buffer_release(struct zn_lease_buffer *self) { - self->callback(self->buffer, self->user_data); + if (self->callback) { + self->callback(self->buffer, self->user_data); + } free(self); } From 175409b64718e2f6597cc2818a88e3ebe4e6dfec Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 26 Apr 2023 17:49:12 +0900 Subject: [PATCH 18/49] remove lease buffer --- zen/include/zen/buffer.h | 18 ++++++++ zen/include/zen/gl-buffer.h | 10 ++-- zen/include/zen/lease-buffer.h | 29 ------------ zen/include/zen/xr-dispatcher.h | 10 ++-- zen/meson.build | 1 - zen/src/backend/immersive/client-gl-buffer.c | 27 +---------- zen/src/backend/immersive/client-gl-context.c | 4 +- zen/src/backend/immersive/client-gl-shader.c | 25 +--------- zen/src/backend/immersive/client-gl-shader.h | 4 +- zen/src/backend/immersive/remote/gl-buffer.cc | 21 +++++---- zen/src/backend/immersive/remote/gl-buffer.h | 2 +- zen/src/backend/immersive/remote/gl-shader.h | 2 - .../backend/immersive/remote/xr-dispatcher.cc | 12 ++--- .../backend/immersive/remote/xr-dispatcher.h | 4 +- zen/src/backend/immersive/shm-buffer.c | 46 +++++++++++-------- zen/src/backend/immersive/shm-buffer.h | 6 +-- zen/src/lease-buffer.c | 34 -------------- 17 files changed, 82 insertions(+), 173 deletions(-) delete mode 100644 zen/include/zen/lease-buffer.h delete mode 100644 zen/src/lease-buffer.c diff --git a/zen/include/zen/buffer.h b/zen/include/zen/buffer.h index d2f06316..7d5faa51 100644 --- a/zen/include/zen/buffer.h +++ b/zen/include/zen/buffer.h @@ -10,7 +10,12 @@ extern "C" { struct zn_buffer; +/// The initial refcount must be 1 struct zn_buffer_interface { + void (*ref)(struct zn_buffer *self); + + void (*unref)(struct zn_buffer *self); + void *(*begin_access)(struct zn_buffer *self); /// @return false if errors occur during the access bool (*end_access)(struct zn_buffer *self); @@ -18,6 +23,7 @@ struct zn_buffer_interface { ssize_t (*get_size)(struct zn_buffer *self); }; +/// The initial refcount is 1 struct zn_buffer { void *impl_data; // @nullable, @outlive const struct zn_buffer_interface *impl; // @nonnull, @outlive @@ -28,6 +34,18 @@ struct zn_buffer *zn_buffer_create( void zn_buffer_destroy(struct zn_buffer *self); +UNUSED static inline void +zn_buffer_ref(struct zn_buffer *self) +{ + self->impl->ref(self); +} + +UNUSED static inline void +zn_buffer_unref(struct zn_buffer *self) +{ + self->impl->unref(self); +} + UNUSED static inline void * zn_buffer_begin_access(struct zn_buffer *self) { diff --git a/zen/include/zen/gl-buffer.h b/zen/include/zen/gl-buffer.h index cd2d1ae3..057a1138 100644 --- a/zen/include/zen/gl-buffer.h +++ b/zen/include/zen/gl-buffer.h @@ -8,13 +8,12 @@ extern "C" { #endif -struct zn_lease_buffer; +struct zn_buffer; struct zn_gl_buffer; struct zn_gl_buffer_interface { - /// @param lease_buffer will be released by the callee void (*data)(struct zn_gl_buffer *self, uint32_t target, - struct zn_lease_buffer *lease_buffer, uint32_t usage); + struct zn_buffer *buffer, uint32_t usage); }; struct zn_gl_buffer { @@ -26,12 +25,11 @@ struct zn_gl_buffer { } events; }; -/// @param lease_buffer will be released by the callee UNUSED static inline void zn_gl_buffer_data(struct zn_gl_buffer *self, uint32_t target, - struct zn_lease_buffer *lease_buffer, uint32_t usage) + struct zn_buffer *buffer, uint32_t usage) { - self->impl->data(self, target, lease_buffer, usage); + self->impl->data(self, target, buffer, usage); } #ifdef __cplusplus diff --git a/zen/include/zen/lease-buffer.h b/zen/include/zen/lease-buffer.h deleted file mode 100644 index 9524b703..00000000 --- a/zen/include/zen/lease-buffer.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -struct zn_buffer; - -#ifdef __cplusplus -extern "C" { -#endif - -// NOLINTNEXTLINE(modernize-use-using) -typedef void (*zn_lease_buffer_release_callback)( - struct zn_buffer *buffer, void *user_data); - -struct zn_lease_buffer { - void *user_data; // @nullable, @outlive - struct zn_buffer *buffer; // @nonnull, @outlive - zn_lease_buffer_release_callback callback; // @nullable, @outlive -}; - -/// @param zn_buffer must outlive this -/// @param callback is nullable -struct zn_lease_buffer *zn_lease_buffer_create(struct zn_buffer *buffer, - zn_lease_buffer_release_callback callback, void *user_data); - -/// This also destroy itself -void zn_lease_buffer_release(struct zn_lease_buffer *self); - -#ifdef __cplusplus -} -#endif diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index e78a2459..ec1e8216 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -8,11 +8,11 @@ extern "C" { #endif +struct zn_buffer; struct zn_gl_base_technique; struct zn_gl_buffer; struct zn_gl_rendering_unit; struct zn_gl_shader; -struct zn_lease_buffer; struct zn_virtual_object; struct zn_xr_dispatcher; @@ -37,8 +37,8 @@ struct zn_xr_dispatcher_interface { void (*destroy_gl_buffer)( struct zn_xr_dispatcher *self, struct zn_gl_buffer *gl_buffer); - struct zn_gl_shader *(*get_new_gl_shader)(struct zn_xr_dispatcher *self, - struct zn_lease_buffer *buffer, uint32_t type); + struct zn_gl_shader *(*get_new_gl_shader)( + struct zn_xr_dispatcher *self, struct zn_buffer *buffer, uint32_t type); void (*destroy_gl_shader)( struct zn_xr_dispatcher *self, struct zn_gl_shader *gl_shader); }; @@ -107,8 +107,8 @@ zn_xr_dispatcher_destroy_gl_buffer( } UNUSED static inline struct zn_gl_shader * -zn_xr_dispatcher_get_new_gl_shader(struct zn_xr_dispatcher *self, - struct zn_lease_buffer *buffer, uint32_t type) +zn_xr_dispatcher_get_new_gl_shader( + struct zn_xr_dispatcher *self, struct zn_buffer *buffer, uint32_t type) { return self->impl->get_new_gl_shader(self, buffer, type); } diff --git a/zen/meson.build b/zen/meson.build index 5504c714..34086e7c 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -6,7 +6,6 @@ _zen_srcs = [ 'src/gl-buffer.c', 'src/gl-rendering-unit.c', 'src/gl-shader.c', - 'src/lease-buffer.c', 'src/screen.c', 'src/seat.c', 'src/server.c', diff --git a/zen/src/backend/immersive/client-gl-buffer.c b/zen/src/backend/immersive/client-gl-buffer.c index c7634a89..93f8274f 100644 --- a/zen/src/backend/immersive/client-gl-buffer.c +++ b/zen/src/backend/immersive/client-gl-buffer.c @@ -7,7 +7,6 @@ #include "zen-common/util.h" #include "zen/backend.h" #include "zen/gl-buffer.h" -#include "zen/lease-buffer.h" #include "zen/server.h" #include "zen/xr-dispatcher.h" #include "zen/xr-system.h" @@ -30,15 +29,6 @@ zn_client_gl_buffer_protocol_destroy( wl_resource_destroy(resource); } -static void -zn_client_gl_buffer_data_release_callback( - struct zn_buffer *buffer UNUSED, void *user_data) -{ - struct zn_shm_buffer *shm_buffer = user_data; - - zn_shm_buffer_unref(shm_buffer); -} - /// @param resource can be inert (resource->user_data == NULL) static void zn_client_gl_buffer_protocol_data(struct wl_client *client UNUSED, @@ -48,24 +38,11 @@ zn_client_gl_buffer_protocol_data(struct wl_client *client UNUSED, struct zn_client_gl_buffer *self = wl_resource_get_user_data(resource); struct zn_shm_buffer *shm_buffer = zn_shm_buffer_get(data_resource); - if (!zn_assert(shm_buffer != NULL, "zn_shm_buffer not found")) { + if (!zn_assert(shm_buffer, "zn_shm_buffer not found")) { return; } - // NOLINTNEXTLINE(clang-analyzer-core.NullDereference) - struct zn_buffer *zn_buffer = shm_buffer->zn_buffer; - - struct zn_lease_buffer *lease_buffer = zn_lease_buffer_create( - zn_buffer, zn_client_gl_buffer_data_release_callback, shm_buffer); - if (lease_buffer == NULL) { - zn_error("Failed to create lease buffer"); - wl_client_post_no_memory(client); - return; - } - - zn_shm_buffer_ref(shm_buffer); - - zn_gl_buffer_data(self->zn_gl_buffer, target, lease_buffer, usage); + zn_gl_buffer_data(self->zn_gl_buffer, target, shm_buffer->zn_buffer, usage); } static const struct zwn_gl_buffer_interface implementation = { diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c index 3d11eeaf..2e66ff21 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/client-gl-context.c @@ -58,9 +58,9 @@ zn_client_gl_context_protocol_create_gl_shader(struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id, struct wl_resource *buffer_resource, uint32_t type) { - struct zn_shm_buffer *buffer = zn_shm_buffer_get(buffer_resource); + struct zn_shm_buffer *shm_buffer = zn_shm_buffer_get(buffer_resource); - zn_client_gl_shader_create(client, id, buffer, type); + zn_client_gl_shader_create(client, id, shm_buffer->zn_buffer, type); } /// @param resource can be inert (resource->user_data == NULL) diff --git a/zen/src/backend/immersive/client-gl-shader.c b/zen/src/backend/immersive/client-gl-shader.c index 0a03e4b4..c698990a 100644 --- a/zen/src/backend/immersive/client-gl-shader.c +++ b/zen/src/backend/immersive/client-gl-shader.c @@ -8,7 +8,6 @@ #include "zen/backend.h" #include "zen/buffer.h" #include "zen/gl-shader.h" -#include "zen/lease-buffer.h" #include "zen/server.h" #include "zen/xr-dispatcher.h" #include "zen/xr-system.h" @@ -45,18 +44,9 @@ zn_client_gl_shader_handle_zn_gl_shader_destroy( zn_client_gl_shader_destroy(self); } -static void -zn_client_gl_shader_buffer_release_callback( - struct zn_buffer *buffer UNUSED, void *user_data) -{ - struct zn_shm_buffer *shm_buffer = user_data; - - zn_shm_buffer_unref(shm_buffer); -} - struct zn_client_gl_shader * zn_client_gl_shader_create(struct wl_client *client, uint32_t id, - struct zn_shm_buffer *buffer, uint32_t type) + struct zn_buffer *buffer, uint32_t type) { struct zn_server *server = zn_server_get_singleton(); struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); @@ -73,21 +63,10 @@ zn_client_gl_shader_create(struct wl_client *client, uint32_t id, goto err; } - struct zn_lease_buffer *lease_buffer = zn_lease_buffer_create( - buffer->zn_buffer, zn_client_gl_shader_buffer_release_callback, buffer); - if (lease_buffer == NULL) { - zn_error("Failed to create lease buffer"); - wl_client_post_no_memory(client); - goto err_free; - } - - zn_shm_buffer_ref(buffer); - self->zn_gl_shader = zn_xr_dispatcher_get_new_gl_shader( - xr_system->default_dispatcher, lease_buffer, type); + xr_system->default_dispatcher, buffer, type); if (self->zn_gl_shader == NULL) { zn_error("Failed to get new gl_shader"); - zn_lease_buffer_release(lease_buffer); wl_client_post_no_memory(client); goto err_free; } diff --git a/zen/src/backend/immersive/client-gl-shader.h b/zen/src/backend/immersive/client-gl-shader.h index 3f0b1743..af048d50 100644 --- a/zen/src/backend/immersive/client-gl-shader.h +++ b/zen/src/backend/immersive/client-gl-shader.h @@ -2,7 +2,7 @@ #include -struct zn_shm_buffer; +struct zn_buffer; struct zn_gl_shader; struct zn_client_gl_shader { @@ -14,4 +14,4 @@ struct zn_client_gl_shader { }; struct zn_client_gl_shader *zn_client_gl_shader_create(struct wl_client *client, - uint32_t id, struct zn_shm_buffer *buffer, uint32_t type); + uint32_t id, struct zn_buffer *buffer, uint32_t type); diff --git a/zen/src/backend/immersive/remote/gl-buffer.cc b/zen/src/backend/immersive/remote/gl-buffer.cc index ca64585f..a696bba7 100644 --- a/zen/src/backend/immersive/remote/gl-buffer.cc +++ b/zen/src/backend/immersive/remote/gl-buffer.cc @@ -3,7 +3,6 @@ #include "loop.h" #include "zen-common/log.h" #include "zen/buffer.h" -#include "zen/lease-buffer.h" namespace zen::backend::immersive::remote { @@ -60,26 +59,28 @@ GlBuffer::Init(std::shared_ptr channel) void GlBuffer::HandleData(struct zn_gl_buffer *c_obj, uint32_t target, - struct zn_lease_buffer *lease_buffer, uint32_t usage) + struct zn_buffer *buffer, uint32_t usage) { auto *self = static_cast(c_obj->impl_data); - ssize_t size = zn_buffer_get_size(lease_buffer->buffer); + ssize_t size = zn_buffer_get_size(buffer); auto loop = std::make_unique(wl_display_get_event_loop(self->display_)); - auto buffer = zen::remote::server::CreateBuffer( - [lease_buffer]() { return zn_buffer_begin_access(lease_buffer->buffer); }, - [lease_buffer]() { return zn_buffer_end_access(lease_buffer->buffer); }, - [lease_buffer]() { zn_lease_buffer_release(lease_buffer); }, - std::move(loop)); + auto remote_buffer = zen::remote::server::CreateBuffer( + [buffer]() { return zn_buffer_begin_access(buffer); }, + [buffer]() { return zn_buffer_end_access(buffer); }, + [buffer]() { zn_buffer_unref(buffer); }, std::move(loop)); - if (!buffer) { + if (!remote_buffer) { zn_abort("Failed to create remote buffer"); return; } - self->remote_obj_->GlBufferData(std::move(buffer), target, size, usage); + zn_buffer_ref(buffer); + + self->remote_obj_->GlBufferData( + std::move(remote_buffer), target, size, usage); } } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-buffer.h b/zen/src/backend/immersive/remote/gl-buffer.h index 6fb4ec1a..63163a3c 100644 --- a/zen/src/backend/immersive/remote/gl-buffer.h +++ b/zen/src/backend/immersive/remote/gl-buffer.h @@ -23,7 +23,7 @@ class GlBuffer bool Init(std::shared_ptr channel); static void HandleData(struct zn_gl_buffer *c_obj, uint32_t target, - struct zn_lease_buffer *lease_buffer, uint32_t usage); + struct zn_buffer *buffer, uint32_t usage); wl_display *display_; // @nonnull, @outlive diff --git a/zen/src/backend/immersive/remote/gl-shader.h b/zen/src/backend/immersive/remote/gl-shader.h index b5f6ace0..03ae4590 100644 --- a/zen/src/backend/immersive/remote/gl-shader.h +++ b/zen/src/backend/immersive/remote/gl-shader.h @@ -3,8 +3,6 @@ #include "gl-shader-private.h" #include "zen-common/cpp-util.h" -struct zn_lease_buffer; - namespace zen::backend::immersive::remote { class GlShader diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index 3e4dd9a2..ed38d4a6 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -9,7 +9,6 @@ #include "virtual-object.h" #include "zen-common/log.h" #include "zen/buffer.h" -#include "zen/lease-buffer.h" namespace zen::backend::immersive::remote { @@ -220,19 +219,18 @@ XrDispatcher::HandleDestroyGlBuffer( } zn_gl_shader * -XrDispatcher::HandleGetNewGlShader(struct zn_xr_dispatcher *c_obj, - struct zn_lease_buffer *lease_buffer, uint32_t type) +XrDispatcher::HandleGetNewGlShader( + struct zn_xr_dispatcher *c_obj, struct zn_buffer *buffer, uint32_t type) { auto *self = static_cast(c_obj->impl_data); std::string source; { - ssize_t length = zn_buffer_get_size(lease_buffer->buffer); - auto *data = zn_buffer_begin_access(lease_buffer->buffer); + ssize_t length = zn_buffer_get_size(buffer); + auto *data = zn_buffer_begin_access(buffer); source = std::string(static_cast(data), length); - zn_buffer_end_access(lease_buffer->buffer); - zn_lease_buffer_release(lease_buffer); + zn_buffer_end_access(buffer); } auto gl_shader = GlShader::New(self->channel_, std::move(source), type); diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index fb2a8bfa..95ca977b 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -50,8 +50,8 @@ class XrDispatcher static void HandleDestroyGlBuffer( zn_xr_dispatcher *c_obj, struct zn_gl_buffer *gl_buffer_c_obj); - static zn_gl_shader *HandleGetNewGlShader(struct zn_xr_dispatcher *c_obj, - struct zn_lease_buffer *buffer, uint32_t type); + static zn_gl_shader *HandleGetNewGlShader( + struct zn_xr_dispatcher *c_obj, struct zn_buffer *buffer, uint32_t type); static void HandleDestroyGlShader( struct zn_xr_dispatcher *c_obj, struct zn_gl_shader *gl_shader_c_obj); diff --git a/zen/src/backend/immersive/shm-buffer.c b/zen/src/backend/immersive/shm-buffer.c index abaf367e..26ddc18c 100644 --- a/zen/src/backend/immersive/shm-buffer.c +++ b/zen/src/backend/immersive/shm-buffer.c @@ -85,6 +85,29 @@ init_sigbus_data_key(void) pthread_key_create(&zn_shm_sigbus_data_key, destroy_sigbus_data); } +static void +zn_shm_buffer_ref(struct zn_buffer *zn_buffer) +{ + struct zn_shm_buffer *self = (struct zn_shm_buffer *)(zn_buffer->impl_data); + + zn_assert(self->refcount > 0, "invalid refcount status"); + + self->refcount++; +} + +static void +zn_shm_buffer_unref(struct zn_buffer *zn_buffer) +{ + struct zn_shm_buffer *self = (struct zn_shm_buffer *)(zn_buffer->impl_data); + + self->refcount--; + zn_assert(self->refcount >= 0, "invalid refcount status"); + + if (self->refcount == 0) { + zn_shm_buffer_destroy(self); + } +} + static void * zn_shm_buffer_begin_access(struct zn_buffer *zn_buffer) { @@ -172,6 +195,8 @@ zn_shm_buffer_get_size(struct zn_buffer *zn_buffer) } static const struct zn_buffer_interface buffer_implementation = { + .ref = zn_shm_buffer_ref, + .unref = zn_shm_buffer_unref, .begin_access = zn_shm_buffer_begin_access, .end_access = zn_shm_buffer_end_access, .get_size = zn_shm_buffer_get_size, @@ -184,7 +209,7 @@ zn_shm_buffer_handle_destroy(struct wl_resource *resource) self->resource = NULL; - zn_shm_buffer_unref(self); + zn_shm_buffer_unref(self->zn_buffer); } static void @@ -198,25 +223,6 @@ static const struct zwn_buffer_interface implementation = { .destroy = zn_shm_buffer_protocol_destroy, }; -void -zn_shm_buffer_ref(struct zn_shm_buffer *self) -{ - zn_assert(self->refcount > 0, "invalid refcount status"); - - self->refcount++; -} - -void -zn_shm_buffer_unref(struct zn_shm_buffer *self) -{ - self->refcount--; - zn_assert(self->refcount >= 0, "invalid refcount status"); - - if (self->refcount == 0) { - zn_shm_buffer_destroy(self); - } -} - struct zn_shm_buffer * zn_shm_buffer_get(struct wl_resource *resource) { diff --git a/zen/src/backend/immersive/shm-buffer.h b/zen/src/backend/immersive/shm-buffer.h index 105feeda..7917b781 100644 --- a/zen/src/backend/immersive/shm-buffer.h +++ b/zen/src/backend/immersive/shm-buffer.h @@ -3,6 +3,8 @@ #include #include +struct zn_buffer; + struct zn_shm_buffer { struct wl_resource *resource; // @nullable, @ref int refcount; @@ -12,10 +14,6 @@ struct zn_shm_buffer { struct zn_buffer *zn_buffer; // @nonnull, @owning }; -void zn_shm_buffer_ref(struct zn_shm_buffer *self); - -void zn_shm_buffer_unref(struct zn_shm_buffer *self); - struct zn_shm_buffer *zn_shm_buffer_get(struct wl_resource *resource); struct zn_shm_buffer *zn_shm_buffer_create(struct wl_client *client, diff --git a/zen/src/lease-buffer.c b/zen/src/lease-buffer.c deleted file mode 100644 index 260a3fc4..00000000 --- a/zen/src/lease-buffer.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "zen/lease-buffer.h" - -#include "zen-common/log.h" -#include "zen-common/util.h" - -struct zn_lease_buffer * -zn_lease_buffer_create(struct zn_buffer *buffer, - zn_lease_buffer_release_callback callback, void *user_data) -{ - struct zn_lease_buffer *self = zalloc(sizeof *self); - if (self == NULL) { - zn_error("Failed to allocate memory"); - goto err; - } - - self->user_data = user_data; - self->buffer = buffer; - self->callback = callback; - - return self; - -err: - return NULL; -} - -void -zn_lease_buffer_release(struct zn_lease_buffer *self) -{ - if (self->callback) { - self->callback(self->buffer, self->user_data); - } - - free(self); -} From 6330d326ec362d76502c21d0527d2d33c5b5efba Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 26 Apr 2023 21:06:16 +0900 Subject: [PATCH 19/49] add gl-program --- zen/include/zen/gl-program.h | 44 ++++++ zen/include/zen/xr-dispatcher.h | 18 +++ zen/meson.build | 1 + zen/src/backend/immersive/client-gl-context.c | 9 +- zen/src/backend/immersive/client-gl-program.c | 147 ++++++++++++++++++ zen/src/backend/immersive/client-gl-program.h | 16 ++ .../backend/immersive/remote/gl-program.cc | 76 +++++++++ zen/src/backend/immersive/remote/gl-program.h | 42 +++++ zen/src/backend/immersive/remote/gl-shader.cc | 2 - zen/src/backend/immersive/remote/gl-shader.h | 7 + zen/src/backend/immersive/remote/meson.build | 1 + zen/src/backend/immersive/remote/pch/pch.h | 1 + .../backend/immersive/remote/xr-dispatcher.cc | 36 +++++ .../backend/immersive/remote/xr-dispatcher.h | 8 + zen/src/backend/meson.build | 1 + zen/src/gl-program-private.h | 18 +++ zen/src/gl-program.c | 33 ++++ 17 files changed, 455 insertions(+), 5 deletions(-) create mode 100644 zen/include/zen/gl-program.h create mode 100644 zen/src/backend/immersive/client-gl-program.c create mode 100644 zen/src/backend/immersive/client-gl-program.h create mode 100644 zen/src/backend/immersive/remote/gl-program.cc create mode 100644 zen/src/backend/immersive/remote/gl-program.h create mode 100644 zen/src/gl-program-private.h create mode 100644 zen/src/gl-program.c diff --git a/zen/include/zen/gl-program.h b/zen/include/zen/gl-program.h new file mode 100644 index 00000000..5123613d --- /dev/null +++ b/zen/include/zen/gl-program.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include "zen-common/util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_gl_program; +struct zn_gl_shader; + +struct zn_gl_program_interface { + void (*attach_shader)( + struct zn_gl_program *self, struct zn_gl_shader *gl_shader); + void (*link)(struct zn_gl_program *self); +}; + +struct zn_gl_program { + void *impl_data; // @nullable, @outlive + const struct zn_gl_program_interface *impl; // @nonnull, @outlive + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +UNUSED static inline void +zn_gl_program_attach_shader( + struct zn_gl_program *self, struct zn_gl_shader *gl_shader) +{ + self->impl->attach_shader(self, gl_shader); +} + +UNUSED static inline void +zn_gl_program_link(struct zn_gl_program *self) +{ + self->impl->link(self); +} + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index ec1e8216..ba74b0b6 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -11,6 +11,7 @@ extern "C" { struct zn_buffer; struct zn_gl_base_technique; struct zn_gl_buffer; +struct zn_gl_program; struct zn_gl_rendering_unit; struct zn_gl_shader; struct zn_virtual_object; @@ -41,6 +42,10 @@ struct zn_xr_dispatcher_interface { struct zn_xr_dispatcher *self, struct zn_buffer *buffer, uint32_t type); void (*destroy_gl_shader)( struct zn_xr_dispatcher *self, struct zn_gl_shader *gl_shader); + + struct zn_gl_program *(*get_new_gl_program)(struct zn_xr_dispatcher *self); + void (*destroy_gl_program)( + struct zn_xr_dispatcher *self, struct zn_gl_program *gl_program); }; struct zn_xr_dispatcher { @@ -120,6 +125,19 @@ zn_xr_dispatcher_destroy_gl_shader( self->impl->destroy_gl_shader(self, gl_shader); } +UNUSED static struct zn_gl_program * +zn_xr_dispatcher_get_new_gl_program(struct zn_xr_dispatcher *self) +{ + return self->impl->get_new_gl_program(self); +} + +UNUSED static void +zn_xr_dispatcher_destroy_gl_program( + struct zn_xr_dispatcher *self, struct zn_gl_program *gl_program) +{ + self->impl->destroy_gl_program(self, gl_program); +} + #ifdef __cplusplus } #endif diff --git a/zen/meson.build b/zen/meson.build index 34086e7c..536ea1d2 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -4,6 +4,7 @@ _zen_srcs = [ 'src/cursor.c', 'src/gl-base-technique.c', 'src/gl-buffer.c', + 'src/gl-program.c', 'src/gl-rendering-unit.c', 'src/gl-shader.c', 'src/screen.c', diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c index 2e66ff21..eed54242 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/client-gl-context.c @@ -5,6 +5,7 @@ #include "client-gl-base-technique.h" #include "client-gl-buffer.h" +#include "client-gl-program.h" #include "client-gl-rendering-unit.h" #include "client-gl-shader.h" #include "shm-buffer.h" @@ -65,9 +66,11 @@ zn_client_gl_context_protocol_create_gl_shader(struct wl_client *client, /// @param resource can be inert (resource->user_data == NULL) static void -zn_client_gl_context_protocol_create_gl_program(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, uint32_t id UNUSED) -{} +zn_client_gl_context_protocol_create_gl_program( + struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) +{ + zn_client_gl_program_create(client, id); +} /// @param resource can be inert (resource->user_data == NULL) static void diff --git a/zen/src/backend/immersive/client-gl-program.c b/zen/src/backend/immersive/client-gl-program.c new file mode 100644 index 00000000..387bb0f5 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-program.c @@ -0,0 +1,147 @@ +#include "client-gl-program.h" + +#include + +#include "client-gl-shader.h" +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/backend.h" +#include "zen/gl-program.h" +#include "zen/server.h" +#include "zen/xr-dispatcher.h" +#include "zen/xr-system.h" + +static void zn_client_gl_program_destroy(struct zn_client_gl_program *self); + +static void +zn_client_gl_program_handle_destroy(struct wl_resource *resource) +{ + struct zn_client_gl_program *self = wl_resource_get_user_data(resource); + + zn_client_gl_program_destroy(self); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_program_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_program_protocol_attach_shader(struct wl_client *client UNUSED, + struct wl_resource *resource, struct wl_resource *shader_resource) +{ + struct zn_client_gl_program *self = wl_resource_get_user_data(resource); + struct zn_client_gl_shader *shader = + wl_resource_get_user_data(shader_resource); + + if (self == NULL || shader == NULL) { + return; + } + + zn_gl_program_attach_shader(self->zn_gl_program, shader->zn_gl_shader); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_program_protocol_link( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + struct zn_client_gl_program *self = wl_resource_get_user_data(resource); + + if (self == NULL) { + return; + } + + zn_gl_program_link(self->zn_gl_program); +} + +static const struct zwn_gl_program_interface implementation = { + .destroy = zn_client_gl_program_protocol_destroy, + .attach_shader = zn_client_gl_program_protocol_attach_shader, + .link = zn_client_gl_program_protocol_link, +}; + +static void +zn_client_gl_program_handle_zn_gl_program_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_program *self = + zn_container_of(listener, self, zn_gl_program_destroy_listener); + + zn_client_gl_program_destroy(self); +} + +struct zn_client_gl_program * +zn_client_gl_program_create(struct wl_client *client, uint32_t id) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + if (xr_system == NULL || !zn_xr_system_is_connected(xr_system)) { + zn_error("Failed to get xr_system"); + goto err; + } + + struct zn_client_gl_program *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + wl_client_post_no_memory(client); + goto err; + } + + self->zn_gl_program = + zn_xr_dispatcher_get_new_gl_program(xr_system->default_dispatcher); + if (self->zn_gl_program == NULL) { + zn_error("Failed to get new gl_program"); + wl_client_post_no_memory(client); + goto err_free; + } + + self->resource = wl_resource_create(client, &zwn_gl_program_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_gl_program; + } + + wl_resource_set_implementation(self->resource, &implementation, self, + zn_client_gl_program_handle_destroy); + + self->zn_gl_program_destroy_listener.notify = + zn_client_gl_program_handle_zn_gl_program_destroy; + wl_signal_add(&self->zn_gl_program->events.destroy, + &self->zn_gl_program_destroy_listener); + + return self; + +err_gl_program: + zn_xr_dispatcher_destroy_gl_program( + xr_system->default_dispatcher, self->zn_gl_program); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_client_gl_program_destroy(struct zn_client_gl_program *self) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); + wl_list_remove(&self->zn_gl_program_destroy_listener.link); + + if (xr_system != NULL && zn_xr_system_is_connected(xr_system)) { + zn_xr_dispatcher_destroy_gl_program( + xr_system->default_dispatcher, self->zn_gl_program); + } + + free(self); +} diff --git a/zen/src/backend/immersive/client-gl-program.h b/zen/src/backend/immersive/client-gl-program.h new file mode 100644 index 00000000..851d341b --- /dev/null +++ b/zen/src/backend/immersive/client-gl-program.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +struct zn_gl_program; + +struct zn_client_gl_program { + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_gl_program *zn_gl_program; // @nonnull, @outlive + + struct wl_listener zn_gl_program_destroy_listener; +}; + +struct zn_client_gl_program *zn_client_gl_program_create( + struct wl_client *client, uint32_t id); diff --git a/zen/src/backend/immersive/remote/gl-program.cc b/zen/src/backend/immersive/remote/gl-program.cc new file mode 100644 index 00000000..b6275022 --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-program.cc @@ -0,0 +1,76 @@ +#include "gl-program.h" + +#include "gl-shader.h" +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +const zn_gl_program_interface GlProgram::c_implementation_ = { + GlProgram::HandleAttachShader, + GlProgram::HandleLink, +}; + +GlProgram::~GlProgram() +{ + if (c_obj_ != nullptr) { + zn_gl_program_destroy(c_obj_); + } +} + +std::unique_ptr +GlProgram::New(std::shared_ptr channel) +{ + auto self = std::unique_ptr(new GlProgram()); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(channel))) { + zn_error("Failed to initialize a remote GlProgram"); + return nullptr; + } + + return self; +} + +bool +GlProgram::Init(std::shared_ptr channel) +{ + c_obj_ = zn_gl_program_create(this, &c_implementation_); + if (c_obj_ == nullptr) { + zn_error("Failed to create a zn_gl_program"); + return false; + } + + remote_obj_ = zen::remote::server::CreateGlProgram(std::move(channel)); + if (!remote_obj_) { + zn_error("Failed to create a remote GlProgram"); + zn_gl_program_destroy(c_obj_); + c_obj_ = nullptr; + return false; + } + + return true; +} + +void +GlProgram::HandleAttachShader( + struct zn_gl_program *c_obj, struct zn_gl_shader *gl_shader_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto *gl_shader = static_cast(gl_shader_c_obj->impl_data); + + self->remote_obj_->GlAttachShader(gl_shader->remote_obj()->id()); +} + +void +GlProgram::HandleLink(struct zn_gl_program *c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->GlLinkProgram(); +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-program.h b/zen/src/backend/immersive/remote/gl-program.h new file mode 100644 index 00000000..52b6e7c4 --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-program.h @@ -0,0 +1,42 @@ +#pragma once + +#include "gl-program-private.h" +#include "zen-common/cpp-util.h" + +namespace zen::backend::immersive::remote { + +class GlProgram +{ + public: + DISABLE_MOVE_AND_COPY(GlProgram); + ~GlProgram(); + + static std::unique_ptr New( + std::shared_ptr channel); + + inline zn_gl_program *c_obj() const; + + private: + GlProgram() = default; + + bool Init(std::shared_ptr channel); + + static void HandleAttachShader( + struct zn_gl_program *c_obj, struct zn_gl_shader *gl_shader_c_obj); + + static void HandleLink(struct zn_gl_program *c_obj); + + std::unique_ptr remote_obj_; + + static const zn_gl_program_interface c_implementation_; + + zn_gl_program *c_obj_ = nullptr; // @nonnull after Init(), @owning +}; + +inline zn_gl_program * +GlProgram::c_obj() const +{ + return c_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-shader.cc b/zen/src/backend/immersive/remote/gl-shader.cc index 467254c1..be065d3f 100644 --- a/zen/src/backend/immersive/remote/gl-shader.cc +++ b/zen/src/backend/immersive/remote/gl-shader.cc @@ -1,7 +1,5 @@ #include "gl-shader.h" -#include - #include "zen-common/log.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-shader.h b/zen/src/backend/immersive/remote/gl-shader.h index 03ae4590..f121ed5c 100644 --- a/zen/src/backend/immersive/remote/gl-shader.h +++ b/zen/src/backend/immersive/remote/gl-shader.h @@ -15,6 +15,7 @@ class GlShader std::shared_ptr channel, std::string source, uint32_t type); + inline std::unique_ptr &remote_obj(); inline zn_gl_shader *c_obj() const; private: @@ -28,6 +29,12 @@ class GlShader zn_gl_shader *c_obj_ = nullptr; // @nonnull after Init(), @owning }; +inline std::unique_ptr & +GlShader::remote_obj() +{ + return remote_obj_; +} + inline zn_gl_shader * GlShader::c_obj() const { diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index d37bb45d..c5af5c93 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -1,6 +1,7 @@ _zen_remote_immersive_backend_srcs = [ 'gl-base-technique.cc', 'gl-buffer.cc', + 'gl-program.cc', 'gl-rendering-unit.cc', 'gl-shader.cc', 'loop.cc', diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index 5942e35f..dd60427f 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index ed38d4a6..3fc6007f 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -4,6 +4,7 @@ #include "gl-base-technique.h" #include "gl-buffer.h" +#include "gl-program.h" #include "gl-rendering-unit.h" #include "gl-shader.h" #include "virtual-object.h" @@ -23,6 +24,8 @@ const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { XrDispatcher::HandleDestroyGlBuffer, XrDispatcher::HandleGetNewGlShader, XrDispatcher::HandleDestroyGlShader, + XrDispatcher::HandleGetNewGlProgram, + XrDispatcher::HandleDestroyGlProgram, }; XrDispatcher::XrDispatcher(wl_display *display) : display_(display) {} @@ -261,4 +264,37 @@ XrDispatcher::HandleDestroyGlShader( self->gl_shaders_.erase(result, self->gl_shaders_.end()); } +zn_gl_program * +XrDispatcher::HandleGetNewGlProgram(struct zn_xr_dispatcher *c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto gl_program = GlProgram::New(self->channel_); + if (!gl_program) { + zn_error("Failed to create a remote gl_program"); + return nullptr; + } + + auto *gl_program_c_obj = gl_program->c_obj(); + + self->gl_programs_.push_back(std::move(gl_program)); + + return gl_program_c_obj; +} + +void +XrDispatcher::HandleDestroyGlProgram( + struct zn_xr_dispatcher *c_obj, struct zn_gl_program *gl_program_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto result = + std::remove_if(self->gl_programs_.begin(), self->gl_programs_.end(), + [gl_program_c_obj](std::unique_ptr &gl_program) { + return gl_program->c_obj() == gl_program_c_obj; + }); + + self->gl_programs_.erase(result, self->gl_programs_.end()); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index 95ca977b..b8aa822d 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -9,6 +9,7 @@ class GlBaseTechnique; class GlBuffer; class GlRenderingUnit; class GlShader; +class GlProgram; class VirtualObject; class XrDispatcher @@ -56,6 +57,11 @@ class XrDispatcher static void HandleDestroyGlShader( struct zn_xr_dispatcher *c_obj, struct zn_gl_shader *gl_shader_c_obj); + static zn_gl_program *HandleGetNewGlProgram(struct zn_xr_dispatcher *c_obj); + + static void HandleDestroyGlProgram( + struct zn_xr_dispatcher *c_obj, struct zn_gl_program *gl_program_c_obj); + wl_display *display_; // @nonnull, @outlive std::shared_ptr channel_; @@ -70,6 +76,8 @@ class XrDispatcher std::vector> gl_shaders_; + std::vector> gl_programs_; + static const zn_xr_dispatcher_interface c_implementation_; zn_xr_dispatcher *c_obj_ = nullptr; // @nonnull after Init(), @owning diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 864f8f11..f9c01f07 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -6,6 +6,7 @@ _zen_backend_srcs = [ 'immersive/client-gl-base-technique.c', 'immersive/client-gl-buffer.c', 'immersive/client-gl-context.c', + 'immersive/client-gl-program.c', 'immersive/client-gl-rendering-unit.c', 'immersive/client-gl-shader.c', 'immersive/client-virtual-object.c', diff --git a/zen/src/gl-program-private.h b/zen/src/gl-program-private.h new file mode 100644 index 00000000..a39b8973 --- /dev/null +++ b/zen/src/gl-program-private.h @@ -0,0 +1,18 @@ +#pragma once + +#include "zen/gl-program.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Called by impl object +struct zn_gl_program *zn_gl_program_create( + void *impl_data, const struct zn_gl_program_interface *implementation); + +/// Called by impl object +void zn_gl_program_destroy(struct zn_gl_program *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/gl-program.c b/zen/src/gl-program.c new file mode 100644 index 00000000..be1e310a --- /dev/null +++ b/zen/src/gl-program.c @@ -0,0 +1,33 @@ +#include "gl-program-private.h" +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_gl_program * +zn_gl_program_create( + void *impl_data, const struct zn_gl_program_interface *implementation) +{ + struct zn_gl_program *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + self->impl = implementation; + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_gl_program_destroy(struct zn_gl_program *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} From f4ade2ed35865ce14a7b00bec1646bbc23ecaa16 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 26 Apr 2023 21:21:46 +0900 Subject: [PATCH 20/49] VirtualObject::Commit --- zen/include/zen/virtual-object.h | 15 ++++++++++++++- zen/src/backend/immersive/client-virtual-object.c | 12 ++++++++++-- .../backend/immersive/remote/virtual-object.cc | 14 +++++++++++++- zen/src/backend/immersive/remote/virtual-object.h | 4 ++++ zen/src/virtual-object-private.h | 3 ++- zen/src/virtual-object.c | 4 +++- 6 files changed, 46 insertions(+), 6 deletions(-) diff --git a/zen/include/zen/virtual-object.h b/zen/include/zen/virtual-object.h index 98e7e53a..28d381d4 100644 --- a/zen/include/zen/virtual-object.h +++ b/zen/include/zen/virtual-object.h @@ -8,14 +8,27 @@ extern "C" { #endif +struct zn_virtual_object; + +struct zn_virtual_object_interface { + void (*commit)(struct zn_virtual_object *self); +}; + struct zn_virtual_object { - void *impl_data; // @nullable, @outlive if exists + void *impl_data; // @nullable, @outlive + const struct zn_virtual_object_interface *impl; // @nonnull, @outlive struct { struct wl_signal destroy; } events; }; +UNUSED static inline void +zn_virtual_object_commit(struct zn_virtual_object *self) +{ + self->impl->commit(self); +} + #ifdef __cplusplus } #endif diff --git a/zen/src/backend/immersive/client-virtual-object.c b/zen/src/backend/immersive/client-virtual-object.c index bfb4377f..52ef5c56 100644 --- a/zen/src/backend/immersive/client-virtual-object.c +++ b/zen/src/backend/immersive/client-virtual-object.c @@ -30,8 +30,16 @@ zn_client_virtual_object_protocol_destroy( /// @param resource can be inert (resource->user_data == NULL) static void zn_client_virtual_object_protocol_commit( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED) -{} + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + struct zn_client_virtual_object *self = wl_resource_get_user_data(resource); + + if (self == NULL) { + return; + } + + zn_virtual_object_commit(self->zn_virtual_object); +} /// @param resource can be inert (resource->user_data == NULL) static void diff --git a/zen/src/backend/immersive/remote/virtual-object.cc b/zen/src/backend/immersive/remote/virtual-object.cc index 9468d659..e9506349 100644 --- a/zen/src/backend/immersive/remote/virtual-object.cc +++ b/zen/src/backend/immersive/remote/virtual-object.cc @@ -4,6 +4,10 @@ namespace zen::backend::immersive::remote { +const zn_virtual_object_interface VirtualObject::c_implementation_ = { + VirtualObject::HandleCommit, +}; + VirtualObject::~VirtualObject() { if (c_obj_ != nullptr) { @@ -31,7 +35,7 @@ VirtualObject::New(std::shared_ptr channel) bool VirtualObject::Init(std::shared_ptr channel) { - c_obj_ = zn_virtual_object_create(this); + c_obj_ = zn_virtual_object_create(this, &c_implementation_); if (c_obj_ == nullptr) { zn_error("Failed to create a zn_virtual_object"); return false; @@ -48,4 +52,12 @@ VirtualObject::Init(std::shared_ptr channel) return true; } +void +VirtualObject::HandleCommit(zn_virtual_object *c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->Commit(); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/virtual-object.h b/zen/src/backend/immersive/remote/virtual-object.h index cd108741..4501e36a 100644 --- a/zen/src/backend/immersive/remote/virtual-object.h +++ b/zen/src/backend/immersive/remote/virtual-object.h @@ -22,8 +22,12 @@ class VirtualObject bool Init(std::shared_ptr channel); + static void HandleCommit(zn_virtual_object *c_obj); + std::unique_ptr remote_obj_; + static const zn_virtual_object_interface c_implementation_; + zn_virtual_object *c_obj_ = nullptr; // @nonnull after Init(), @owning }; diff --git a/zen/src/virtual-object-private.h b/zen/src/virtual-object-private.h index 00c88ff3..a240cb32 100644 --- a/zen/src/virtual-object-private.h +++ b/zen/src/virtual-object-private.h @@ -5,7 +5,8 @@ extern "C" { #endif /// Called by impl object -struct zn_virtual_object *zn_virtual_object_create(void *impl_data); +struct zn_virtual_object *zn_virtual_object_create( + void *impl_data, const struct zn_virtual_object_interface *implementation); /// Called by impl object void zn_virtual_object_destroy(struct zn_virtual_object *self); diff --git a/zen/src/virtual-object.c b/zen/src/virtual-object.c index 40f7d73f..93f0a1fb 100644 --- a/zen/src/virtual-object.c +++ b/zen/src/virtual-object.c @@ -5,7 +5,8 @@ #include "zen-common/util.h" struct zn_virtual_object * -zn_virtual_object_create(void *impl_data) +zn_virtual_object_create( + void *impl_data, const struct zn_virtual_object_interface *implementation) { struct zn_virtual_object *self = zalloc(sizeof *self); if (self == NULL) { @@ -14,6 +15,7 @@ zn_virtual_object_create(void *impl_data) } self->impl_data = impl_data; + self->impl = implementation; wl_signal_init(&self->events.destroy); return self; From da7ca0531f3a43f3734ac1dcbc14bfc9b9006a96 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 26 Apr 2023 22:04:05 +0900 Subject: [PATCH 21/49] GlBaseTechnique::BindProgram --- zen/include/zen/gl-base-technique.h | 20 ++++++++++++++++++- .../immersive/client-gl-base-technique.c | 20 ++++++++++++++++--- .../immersive/remote/gl-base-technique.cc | 18 ++++++++++++++++- .../immersive/remote/gl-base-technique.h | 5 +++++ zen/src/backend/immersive/remote/gl-program.h | 7 +++++++ zen/src/gl-base-technique-private.h | 3 ++- zen/src/gl-base-technique.c | 4 +++- 7 files changed, 70 insertions(+), 7 deletions(-) diff --git a/zen/include/zen/gl-base-technique.h b/zen/include/zen/gl-base-technique.h index ed96519c..ac990cc0 100644 --- a/zen/include/zen/gl-base-technique.h +++ b/zen/include/zen/gl-base-technique.h @@ -2,18 +2,36 @@ #include +#include "zen-common/util.h" + #ifdef __cplusplus extern "C" { #endif +struct zn_gl_base_technique; +struct zn_gl_program; + +struct zn_gl_base_technique_interface { + void (*bind_program)( + struct zn_gl_base_technique *self, struct zn_gl_program *gl_program); +}; + struct zn_gl_base_technique { - void *impl_data; // @nullable, @outlive + void *impl_data; // @nullable, @outlive + const struct zn_gl_base_technique_interface *impl; // @nonnull, @outlive struct { struct wl_signal destroy; // (NULL) } events; }; +UNUSED static inline void +zn_gl_base_technique_bind_program( + struct zn_gl_base_technique *self, struct zn_gl_program *gl_program) +{ + self->impl->bind_program(self, gl_program); +} + #ifdef __cplusplus } #endif diff --git a/zen/src/backend/immersive/client-gl-base-technique.c b/zen/src/backend/immersive/client-gl-base-technique.c index 676ab947..cd8e53cb 100644 --- a/zen/src/backend/immersive/client-gl-base-technique.c +++ b/zen/src/backend/immersive/client-gl-base-technique.c @@ -2,6 +2,7 @@ #include +#include "client-gl-program.h" #include "client-gl-rendering-unit.h" #include "client-virtual-object.h" #include "zen-common/log.h" @@ -31,9 +32,22 @@ zn_client_gl_base_technique_protocol_destroy( /// @param resource can be inert (resource->user_data == NULL) static void zn_client_gl_base_technique_protocol_bind_program( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, - struct wl_resource *program UNUSED) -{} + struct wl_client *client UNUSED, struct wl_resource *resource, + struct wl_resource *program_resource) +{ + struct zn_client_gl_base_technique *self = + wl_resource_get_user_data(resource); + + struct zn_client_gl_program *program = + wl_resource_get_user_data(program_resource); + + if (self == NULL || program == NULL) { + return; + } + + zn_gl_base_technique_bind_program( + self->zn_gl_base_technique, program->zn_gl_program); +} /// @param resource can be inert (resource->user_data == NULL) static void diff --git a/zen/src/backend/immersive/remote/gl-base-technique.cc b/zen/src/backend/immersive/remote/gl-base-technique.cc index bb136264..90a593de 100644 --- a/zen/src/backend/immersive/remote/gl-base-technique.cc +++ b/zen/src/backend/immersive/remote/gl-base-technique.cc @@ -1,10 +1,15 @@ #include "gl-base-technique.h" +#include "gl-program.h" #include "gl-rendering-unit.h" #include "zen-common/log.h" namespace zen::backend::immersive::remote { +const zn_gl_base_technique_interface GlBaseTechnique::c_implementation_ = { + GlBaseTechnique::HandleBindProgram, +}; + GlBaseTechnique::~GlBaseTechnique() { if (c_obj_ != nullptr) { @@ -34,7 +39,7 @@ bool GlBaseTechnique::Init(std::shared_ptr channel, std::unique_ptr &rendering_unit) { - c_obj_ = zn_gl_base_technique_create(this); + c_obj_ = zn_gl_base_technique_create(this, &c_implementation_); if (c_obj_ == nullptr) { zn_error("Failed to create a zn_gl_base_technique"); return false; @@ -52,4 +57,15 @@ GlBaseTechnique::Init(std::shared_ptr channel, return true; } +void +GlBaseTechnique::HandleBindProgram( + struct zn_gl_base_technique *c_obj, struct zn_gl_program *gl_program_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto *gl_program = static_cast(gl_program_c_obj->impl_data); + + self->remote_obj_->BindProgram(gl_program->remote_obj()->id()); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-base-technique.h b/zen/src/backend/immersive/remote/gl-base-technique.h index 902d4bed..091c0ba9 100644 --- a/zen/src/backend/immersive/remote/gl-base-technique.h +++ b/zen/src/backend/immersive/remote/gl-base-technique.h @@ -26,8 +26,13 @@ class GlBaseTechnique bool Init(std::shared_ptr channel, std::unique_ptr &rendering_unit); + static void HandleBindProgram(struct zn_gl_base_technique *c_obj, + struct zn_gl_program *gl_program_c_obj); + std::unique_ptr remote_obj_; + static const zn_gl_base_technique_interface c_implementation_; + zn_gl_base_technique *c_obj_ = nullptr; // @nonnull after Init(), @owning }; diff --git a/zen/src/backend/immersive/remote/gl-program.h b/zen/src/backend/immersive/remote/gl-program.h index 52b6e7c4..e2a5390f 100644 --- a/zen/src/backend/immersive/remote/gl-program.h +++ b/zen/src/backend/immersive/remote/gl-program.h @@ -14,6 +14,7 @@ class GlProgram static std::unique_ptr New( std::shared_ptr channel); + inline std::unique_ptr &remote_obj(); inline zn_gl_program *c_obj() const; private: @@ -33,6 +34,12 @@ class GlProgram zn_gl_program *c_obj_ = nullptr; // @nonnull after Init(), @owning }; +inline std::unique_ptr & +GlProgram::remote_obj() +{ + return remote_obj_; +} + inline zn_gl_program * GlProgram::c_obj() const { diff --git a/zen/src/gl-base-technique-private.h b/zen/src/gl-base-technique-private.h index d02fa8aa..9ba47153 100644 --- a/zen/src/gl-base-technique-private.h +++ b/zen/src/gl-base-technique-private.h @@ -7,7 +7,8 @@ extern "C" { #endif /// Called by impl object -struct zn_gl_base_technique *zn_gl_base_technique_create(void *impl_data); +struct zn_gl_base_technique *zn_gl_base_technique_create(void *impl_data, + const struct zn_gl_base_technique_interface *implementation); /// Called by impl object void zn_gl_base_technique_destroy(struct zn_gl_base_technique *self); diff --git a/zen/src/gl-base-technique.c b/zen/src/gl-base-technique.c index 2ae17b4d..80835cbe 100644 --- a/zen/src/gl-base-technique.c +++ b/zen/src/gl-base-technique.c @@ -4,7 +4,8 @@ #include "zen-common/util.h" struct zn_gl_base_technique * -zn_gl_base_technique_create(void *impl_data) +zn_gl_base_technique_create(void *impl_data, + const struct zn_gl_base_technique_interface *implementation) { struct zn_gl_base_technique *self = zalloc(sizeof *self); if (self == NULL) { @@ -13,6 +14,7 @@ zn_gl_base_technique_create(void *impl_data) } self->impl_data = impl_data; + self->impl = implementation; wl_signal_init(&self->events.destroy); return self; From 54e9eac09d3d1dec4e2c7405afb92d91f352d3a4 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 26 Apr 2023 22:05:11 +0900 Subject: [PATCH 22/49] Refactor getting user_data from wl_resource --- .../immersive/client-gl-base-technique.c | 12 +++++++++--- .../immersive/client-gl-base-technique.h | 4 ++++ zen/src/backend/immersive/client-gl-buffer.c | 10 ++++++++-- zen/src/backend/immersive/client-gl-buffer.h | 4 ++++ zen/src/backend/immersive/client-gl-context.c | 17 ++++++++++++----- zen/src/backend/immersive/client-gl-context.h | 4 ++++ zen/src/backend/immersive/client-gl-program.c | 15 ++++++++++----- zen/src/backend/immersive/client-gl-program.h | 4 ++++ .../immersive/client-gl-rendering-unit.c | 8 +++++++- .../immersive/client-gl-rendering-unit.h | 3 +++ zen/src/backend/immersive/client-gl-shader.c | 8 +++++++- zen/src/backend/immersive/client-gl-shader.h | 4 ++++ .../backend/immersive/client-virtual-object.c | 12 ++++++++++-- .../backend/immersive/client-virtual-object.h | 3 +++ 14 files changed, 89 insertions(+), 19 deletions(-) diff --git a/zen/src/backend/immersive/client-gl-base-technique.c b/zen/src/backend/immersive/client-gl-base-technique.c index cd8e53cb..148e197e 100644 --- a/zen/src/backend/immersive/client-gl-base-technique.c +++ b/zen/src/backend/immersive/client-gl-base-technique.c @@ -17,7 +17,7 @@ static void zn_client_gl_base_technique_handle_destroy(struct wl_resource *resource) { struct zn_client_gl_base_technique *self = - wl_resource_get_user_data(resource); + zn_client_gl_base_technique_get(resource); zn_client_gl_base_technique_destroy(self); } @@ -36,10 +36,10 @@ zn_client_gl_base_technique_protocol_bind_program( struct wl_resource *program_resource) { struct zn_client_gl_base_technique *self = - wl_resource_get_user_data(resource); + zn_client_gl_base_technique_get(resource); struct zn_client_gl_program *program = - wl_resource_get_user_data(program_resource); + zn_client_gl_program_get(program_resource); if (self == NULL || program == NULL) { return; @@ -109,6 +109,12 @@ static const struct zwn_gl_base_technique_interface implementation = { .draw_elements = zn_client_gl_base_technique_protocol_draw_elements, }; +struct zn_client_gl_base_technique * +zn_client_gl_base_technique_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + static void zn_client_gl_base_technique_handle_rendering_unit_destroy( struct wl_listener *listener, void *data UNUSED) diff --git a/zen/src/backend/immersive/client-gl-base-technique.h b/zen/src/backend/immersive/client-gl-base-technique.h index b701ae3e..980e7c62 100644 --- a/zen/src/backend/immersive/client-gl-base-technique.h +++ b/zen/src/backend/immersive/client-gl-base-technique.h @@ -19,3 +19,7 @@ struct zn_client_gl_base_technique { struct zn_client_gl_base_technique *zn_client_gl_base_technique_create( struct wl_client *client, uint32_t id, struct zn_client_gl_rendering_unit *rendering_unit); + +/// @return value is nullable +struct zn_client_gl_base_technique *zn_client_gl_base_technique_get( + struct wl_resource *resource); diff --git a/zen/src/backend/immersive/client-gl-buffer.c b/zen/src/backend/immersive/client-gl-buffer.c index 93f8274f..39796a14 100644 --- a/zen/src/backend/immersive/client-gl-buffer.c +++ b/zen/src/backend/immersive/client-gl-buffer.c @@ -16,7 +16,7 @@ static void zn_client_gl_buffer_destroy(struct zn_client_gl_buffer *self); static void zn_client_gl_buffer_handle_destroy(struct wl_resource *resource) { - struct zn_client_gl_buffer *self = wl_resource_get_user_data(resource); + struct zn_client_gl_buffer *self = zn_client_gl_buffer_get(resource); zn_client_gl_buffer_destroy(self); } @@ -35,7 +35,7 @@ zn_client_gl_buffer_protocol_data(struct wl_client *client UNUSED, struct wl_resource *resource, uint32_t target, struct wl_resource *data_resource, uint32_t usage) { - struct zn_client_gl_buffer *self = wl_resource_get_user_data(resource); + struct zn_client_gl_buffer *self = zn_client_gl_buffer_get(resource); struct zn_shm_buffer *shm_buffer = zn_shm_buffer_get(data_resource); if (!zn_assert(shm_buffer, "zn_shm_buffer not found")) { @@ -50,6 +50,12 @@ static const struct zwn_gl_buffer_interface implementation = { .data = zn_client_gl_buffer_protocol_data, }; +struct zn_client_gl_buffer * +zn_client_gl_buffer_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + static void zn_client_gl_buffer_handle_zn_gl_buffer_destroy( struct wl_listener *listener, void *data UNUSED) diff --git a/zen/src/backend/immersive/client-gl-buffer.h b/zen/src/backend/immersive/client-gl-buffer.h index 987ad813..a9dd7e4e 100644 --- a/zen/src/backend/immersive/client-gl-buffer.h +++ b/zen/src/backend/immersive/client-gl-buffer.h @@ -14,3 +14,7 @@ struct zn_client_gl_buffer { struct zn_client_gl_buffer *zn_client_gl_buffer_create( struct wl_client *client, uint32_t id); + +/// @return value is nullable +struct zn_client_gl_buffer *zn_client_gl_buffer_get( + struct wl_resource *resource); diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c index eed54242..e027d95c 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/client-gl-context.c @@ -8,6 +8,7 @@ #include "client-gl-program.h" #include "client-gl-rendering-unit.h" #include "client-gl-shader.h" +#include "client-virtual-object.h" #include "shm-buffer.h" #include "xr-compositor.h" #include "zen-common/log.h" @@ -16,7 +17,7 @@ static void zn_client_gl_context_handle_destroy(struct wl_resource *resource) { - struct zn_client_gl_context *self = wl_resource_get_user_data(resource); + struct zn_client_gl_context *self = zn_client_gl_context_get(resource); zn_client_gl_context_destroy(self); } @@ -35,12 +36,12 @@ zn_client_gl_context_protocol_create_gl_rendering_unit(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *virtual_object_resource) { - if (wl_resource_get_user_data(resource) == NULL) { + if (zn_client_gl_context_get(resource) == NULL) { return; } struct zn_client_virtual_object *client_virtual_object = - wl_resource_get_user_data(virtual_object_resource); + zn_client_virtual_object_get(virtual_object_resource); zn_client_gl_rendering_unit_create(client, id, client_virtual_object); } @@ -97,12 +98,12 @@ zn_client_gl_context_protocol_create_gl_base_technique(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *rendering_unit_resource) { - if (wl_resource_get_user_data(resource) == NULL) { + if (zn_client_gl_context_get(resource) == NULL) { return; } struct zn_client_gl_rendering_unit *rendering_unit = - wl_resource_get_user_data(rendering_unit_resource); + zn_client_gl_rendering_unit_get(rendering_unit_resource); zn_client_gl_base_technique_create(client, id, rendering_unit); } @@ -122,6 +123,12 @@ static const struct zwn_gl_context_interface implementation = { zn_client_gl_context_protocol_create_gl_base_technique, }; +struct zn_client_gl_context * +zn_client_gl_context_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + static void zn_client_gl_context_handle_xr_compositor_destroy( struct wl_listener *listener, void *data UNUSED) diff --git a/zen/src/backend/immersive/client-gl-context.h b/zen/src/backend/immersive/client-gl-context.h index 92bed0c7..03d0c62c 100644 --- a/zen/src/backend/immersive/client-gl-context.h +++ b/zen/src/backend/immersive/client-gl-context.h @@ -16,4 +16,8 @@ struct zn_client_gl_context *zn_client_gl_context_create( struct wl_client *client, uint32_t id, struct zn_xr_compositor *xr_compositor); +/// @return value is nullable +struct zn_client_gl_context *zn_client_gl_context_get( + struct wl_resource *resource); + void zn_client_gl_context_destroy(struct zn_client_gl_context *self); diff --git a/zen/src/backend/immersive/client-gl-program.c b/zen/src/backend/immersive/client-gl-program.c index 387bb0f5..7c86cb12 100644 --- a/zen/src/backend/immersive/client-gl-program.c +++ b/zen/src/backend/immersive/client-gl-program.c @@ -16,7 +16,7 @@ static void zn_client_gl_program_destroy(struct zn_client_gl_program *self); static void zn_client_gl_program_handle_destroy(struct wl_resource *resource) { - struct zn_client_gl_program *self = wl_resource_get_user_data(resource); + struct zn_client_gl_program *self = zn_client_gl_program_get(resource); zn_client_gl_program_destroy(self); } @@ -34,9 +34,8 @@ static void zn_client_gl_program_protocol_attach_shader(struct wl_client *client UNUSED, struct wl_resource *resource, struct wl_resource *shader_resource) { - struct zn_client_gl_program *self = wl_resource_get_user_data(resource); - struct zn_client_gl_shader *shader = - wl_resource_get_user_data(shader_resource); + struct zn_client_gl_program *self = zn_client_gl_program_get(resource); + struct zn_client_gl_shader *shader = zn_client_gl_shader_get(shader_resource); if (self == NULL || shader == NULL) { return; @@ -50,7 +49,7 @@ static void zn_client_gl_program_protocol_link( struct wl_client *client UNUSED, struct wl_resource *resource) { - struct zn_client_gl_program *self = wl_resource_get_user_data(resource); + struct zn_client_gl_program *self = zn_client_gl_program_get(resource); if (self == NULL) { return; @@ -65,6 +64,12 @@ static const struct zwn_gl_program_interface implementation = { .link = zn_client_gl_program_protocol_link, }; +struct zn_client_gl_program * +zn_client_gl_program_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + static void zn_client_gl_program_handle_zn_gl_program_destroy( struct wl_listener *listener, void *data UNUSED) diff --git a/zen/src/backend/immersive/client-gl-program.h b/zen/src/backend/immersive/client-gl-program.h index 851d341b..97e62499 100644 --- a/zen/src/backend/immersive/client-gl-program.h +++ b/zen/src/backend/immersive/client-gl-program.h @@ -14,3 +14,7 @@ struct zn_client_gl_program { struct zn_client_gl_program *zn_client_gl_program_create( struct wl_client *client, uint32_t id); + +/// @return value is nullable +struct zn_client_gl_program *zn_client_gl_program_get( + struct wl_resource *resource); diff --git a/zen/src/backend/immersive/client-gl-rendering-unit.c b/zen/src/backend/immersive/client-gl-rendering-unit.c index 68827524..31f57282 100644 --- a/zen/src/backend/immersive/client-gl-rendering-unit.c +++ b/zen/src/backend/immersive/client-gl-rendering-unit.c @@ -16,7 +16,7 @@ static void zn_client_gl_rendering_unit_handle_destroy(struct wl_resource *resource) { struct zn_client_gl_rendering_unit *self = - wl_resource_get_user_data(resource); + zn_client_gl_rendering_unit_get(resource); zn_client_gl_rendering_unit_destroy(self); } @@ -33,6 +33,12 @@ static const struct zwn_gl_rendering_unit_interface implementation = { .destroy = zn_client_gl_rendering_unit_protocol_destroy, }; +struct zn_client_gl_rendering_unit * +zn_client_gl_rendering_unit_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + static void zn_client_gl_rendering_unit_handle_virtual_object_destroy( struct wl_listener *listener, void *data UNUSED) diff --git a/zen/src/backend/immersive/client-gl-rendering-unit.h b/zen/src/backend/immersive/client-gl-rendering-unit.h index fbc2d9f9..8744e829 100644 --- a/zen/src/backend/immersive/client-gl-rendering-unit.h +++ b/zen/src/backend/immersive/client-gl-rendering-unit.h @@ -23,3 +23,6 @@ struct zn_client_gl_rendering_unit { struct zn_client_gl_rendering_unit *zn_client_gl_rendering_unit_create( struct wl_client *client, uint32_t id, struct zn_client_virtual_object *virtual_object); + +struct zn_client_gl_rendering_unit *zn_client_gl_rendering_unit_get( + struct wl_resource *resource); diff --git a/zen/src/backend/immersive/client-gl-shader.c b/zen/src/backend/immersive/client-gl-shader.c index c698990a..aaaefae6 100644 --- a/zen/src/backend/immersive/client-gl-shader.c +++ b/zen/src/backend/immersive/client-gl-shader.c @@ -17,7 +17,7 @@ static void zn_client_gl_shader_destroy(struct zn_client_gl_shader *self); static void zn_client_gl_shader_handle_destroy(struct wl_resource *resource) { - struct zn_client_gl_shader *self = wl_resource_get_user_data(resource); + struct zn_client_gl_shader *self = zn_client_gl_shader_get(resource); zn_client_gl_shader_destroy(self); } @@ -34,6 +34,12 @@ static const struct zwn_gl_shader_interface implementation = { .destroy = zn_client_gl_shader_protocol_destroy, }; +struct zn_client_gl_shader * +zn_client_gl_shader_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + static void zn_client_gl_shader_handle_zn_gl_shader_destroy( struct wl_listener *listener, void *data UNUSED) diff --git a/zen/src/backend/immersive/client-gl-shader.h b/zen/src/backend/immersive/client-gl-shader.h index af048d50..880edbc9 100644 --- a/zen/src/backend/immersive/client-gl-shader.h +++ b/zen/src/backend/immersive/client-gl-shader.h @@ -15,3 +15,7 @@ struct zn_client_gl_shader { struct zn_client_gl_shader *zn_client_gl_shader_create(struct wl_client *client, uint32_t id, struct zn_buffer *buffer, uint32_t type); + +/// @return value is nullable +struct zn_client_gl_shader *zn_client_gl_shader_get( + struct wl_resource *resource); diff --git a/zen/src/backend/immersive/client-virtual-object.c b/zen/src/backend/immersive/client-virtual-object.c index 52ef5c56..0e0249be 100644 --- a/zen/src/backend/immersive/client-virtual-object.c +++ b/zen/src/backend/immersive/client-virtual-object.c @@ -14,7 +14,8 @@ static void zn_client_virtual_object_destroy( static void zn_client_virtual_object_handle_destroy(struct wl_resource *resource) { - struct zn_client_virtual_object *self = wl_resource_get_user_data(resource); + struct zn_client_virtual_object *self = + zn_client_virtual_object_get(resource); zn_client_virtual_object_destroy(self); } @@ -32,7 +33,8 @@ static void zn_client_virtual_object_protocol_commit( struct wl_client *client UNUSED, struct wl_resource *resource) { - struct zn_client_virtual_object *self = wl_resource_get_user_data(resource); + struct zn_client_virtual_object *self = + zn_client_virtual_object_get(resource); if (self == NULL) { return; @@ -53,6 +55,12 @@ static const struct zwn_virtual_object_interface implementation = { .frame = zn_client_virtual_object_protocol_frame, }; +struct zn_client_virtual_object * +zn_client_virtual_object_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + static void zn_client_virtual_object_handle_dispatcher_destroy( struct wl_listener *listener, void *data UNUSED) diff --git a/zen/src/backend/immersive/client-virtual-object.h b/zen/src/backend/immersive/client-virtual-object.h index 75c9b2e2..bab8e5e9 100644 --- a/zen/src/backend/immersive/client-virtual-object.h +++ b/zen/src/backend/immersive/client-virtual-object.h @@ -22,3 +22,6 @@ struct zn_client_virtual_object { struct zn_client_virtual_object *zn_client_virtual_object_create( struct wl_client *client, uint32_t id, struct zn_xr_dispatcher *dispatcher); + +struct zn_client_virtual_object *zn_client_virtual_object_get( + struct wl_resource *resource); From 7a37790021e38b3cad12bb94414898e6e0c80a4a Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 26 Apr 2023 23:37:35 +0900 Subject: [PATCH 23/49] add GlTexture --- zen/include/zen/gl-texture.h | 47 ++++++ zen/include/zen/xr-dispatcher.h | 18 ++ zen/meson.build | 1 + zen/src/backend/immersive/client-gl-buffer.c | 7 +- zen/src/backend/immersive/client-gl-context.c | 9 +- zen/src/backend/immersive/client-gl-texture.c | 154 ++++++++++++++++++ zen/src/backend/immersive/client-gl-texture.h | 20 +++ .../backend/immersive/remote/gl-texture.cc | 94 +++++++++++ zen/src/backend/immersive/remote/gl-texture.h | 54 ++++++ zen/src/backend/immersive/remote/meson.build | 1 + zen/src/backend/immersive/remote/pch/pch.h | 1 + .../backend/immersive/remote/xr-dispatcher.cc | 36 ++++ .../backend/immersive/remote/xr-dispatcher.h | 10 +- zen/src/backend/meson.build | 1 + zen/src/gl-texture-private.h | 18 ++ zen/src/gl-texture.c | 33 ++++ 16 files changed, 498 insertions(+), 6 deletions(-) create mode 100644 zen/include/zen/gl-texture.h create mode 100644 zen/src/backend/immersive/client-gl-texture.c create mode 100644 zen/src/backend/immersive/client-gl-texture.h create mode 100644 zen/src/backend/immersive/remote/gl-texture.cc create mode 100644 zen/src/backend/immersive/remote/gl-texture.h create mode 100644 zen/src/gl-texture-private.h create mode 100644 zen/src/gl-texture.c diff --git a/zen/include/zen/gl-texture.h b/zen/include/zen/gl-texture.h new file mode 100644 index 00000000..32c4c47e --- /dev/null +++ b/zen/include/zen/gl-texture.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include "zen-common/util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_gl_texture; +struct zn_buffer; + +struct zn_gl_texture_interface { + void (*image_2d)(struct zn_gl_texture *self, uint32_t target, int32_t level, + int32_t internal_format, uint32_t width, uint32_t height, int32_t border, + uint32_t format, uint32_t type, struct zn_buffer *data); + void (*generate_mipmap)(struct zn_gl_texture *self, uint32_t target); +}; + +struct zn_gl_texture { + void *impl_data; // @nullable, @outlive + const struct zn_gl_texture_interface *impl; // @nonnull, @outlive + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +UNUSED static inline void +zn_gl_texture_image_2d(struct zn_gl_texture *self, uint32_t target, + int32_t level, int32_t internal_format, uint32_t width, uint32_t height, + int32_t border, uint32_t format, uint32_t type, struct zn_buffer *data) +{ + self->impl->image_2d(self, target, level, internal_format, width, height, + border, format, type, data); +} + +UNUSED static inline void +zn_gl_texture_generate_mipmap(struct zn_gl_texture *self, uint32_t target) +{ + self->impl->generate_mipmap(self, target); +} + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index ba74b0b6..5d1325f1 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -14,6 +14,7 @@ struct zn_gl_buffer; struct zn_gl_program; struct zn_gl_rendering_unit; struct zn_gl_shader; +struct zn_gl_texture; struct zn_virtual_object; struct zn_xr_dispatcher; @@ -46,6 +47,10 @@ struct zn_xr_dispatcher_interface { struct zn_gl_program *(*get_new_gl_program)(struct zn_xr_dispatcher *self); void (*destroy_gl_program)( struct zn_xr_dispatcher *self, struct zn_gl_program *gl_program); + + struct zn_gl_texture *(*get_new_gl_texture)(struct zn_xr_dispatcher *self); + void (*destroy_gl_texture)( + struct zn_xr_dispatcher *self, struct zn_gl_texture *gl_texture); }; struct zn_xr_dispatcher { @@ -138,6 +143,19 @@ zn_xr_dispatcher_destroy_gl_program( self->impl->destroy_gl_program(self, gl_program); } +UNUSED static struct zn_gl_texture * +zn_xr_dispatcher_get_new_gl_texture(struct zn_xr_dispatcher *self) +{ + return self->impl->get_new_gl_texture(self); +} + +UNUSED static void +zn_xr_dispatcher_destroy_gl_texture( + struct zn_xr_dispatcher *self, struct zn_gl_texture *gl_texture) +{ + self->impl->destroy_gl_texture(self, gl_texture); +} + #ifdef __cplusplus } #endif diff --git a/zen/meson.build b/zen/meson.build index 536ea1d2..3fc0b26d 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -7,6 +7,7 @@ _zen_srcs = [ 'src/gl-program.c', 'src/gl-rendering-unit.c', 'src/gl-shader.c', + 'src/gl-texture.c', 'src/screen.c', 'src/seat.c', 'src/server.c', diff --git a/zen/src/backend/immersive/client-gl-buffer.c b/zen/src/backend/immersive/client-gl-buffer.c index 39796a14..c1e1860f 100644 --- a/zen/src/backend/immersive/client-gl-buffer.c +++ b/zen/src/backend/immersive/client-gl-buffer.c @@ -36,9 +36,9 @@ zn_client_gl_buffer_protocol_data(struct wl_client *client UNUSED, struct wl_resource *data_resource, uint32_t usage) { struct zn_client_gl_buffer *self = zn_client_gl_buffer_get(resource); - struct zn_shm_buffer *shm_buffer = zn_shm_buffer_get(data_resource); - if (!zn_assert(shm_buffer, "zn_shm_buffer not found")) { + + if (self == NULL || shm_buffer == NULL) { return; } @@ -80,6 +80,7 @@ zn_client_gl_buffer_create(struct wl_client *client, uint32_t id) struct zn_client_gl_buffer *self = zalloc(sizeof *self); if (self == NULL) { zn_error("Failed to allocate memory"); + wl_client_post_no_memory(client); goto err; } @@ -87,12 +88,14 @@ zn_client_gl_buffer_create(struct wl_client *client, uint32_t id) zn_xr_dispatcher_get_new_gl_buffer(xr_system->default_dispatcher); if (self->zn_gl_buffer == NULL) { zn_error("Failed to get new zn_gl_buffer"); + wl_client_post_no_memory(client); goto err_free; } self->resource = wl_resource_create(client, &zwn_gl_buffer_interface, 1, id); if (self->resource == NULL) { zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); goto err_gl_buffer; } diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c index e027d95c..2dc2c878 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/client-gl-context.c @@ -8,6 +8,7 @@ #include "client-gl-program.h" #include "client-gl-rendering-unit.h" #include "client-gl-shader.h" +#include "client-gl-texture.h" #include "client-virtual-object.h" #include "shm-buffer.h" #include "xr-compositor.h" @@ -75,9 +76,11 @@ zn_client_gl_context_protocol_create_gl_program( /// @param resource can be inert (resource->user_data == NULL) static void -zn_client_gl_context_protocol_create_gl_texture(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, uint32_t id UNUSED) -{} +zn_client_gl_context_protocol_create_gl_texture( + struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) +{ + zn_client_gl_texture_create(client, id); +} /// @param resource can be inert (resource->user_data == NULL) static void diff --git a/zen/src/backend/immersive/client-gl-texture.c b/zen/src/backend/immersive/client-gl-texture.c new file mode 100644 index 00000000..a27a4142 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-texture.c @@ -0,0 +1,154 @@ +#include "client-gl-texture.h" + +#include + +#include "shm-buffer.h" +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/backend.h" +#include "zen/gl-texture.h" +#include "zen/server.h" +#include "zen/xr-dispatcher.h" +#include "zen/xr-system.h" + +static void zn_client_gl_texture_destroy(struct zn_client_gl_texture *self); + +static void +zn_client_gl_texture_handle_destroy(struct wl_resource *resource) +{ + struct zn_client_gl_texture *self = zn_client_gl_texture_get(resource); + + zn_client_gl_texture_destroy(self); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_texture_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_texture_protocol_image_2d(struct wl_client *client UNUSED, + struct wl_resource *resource, uint32_t target, int32_t level, + int32_t internal_format, uint32_t width, uint32_t height, int32_t border, + uint32_t format, uint32_t type, struct wl_resource *data) +{ + struct zn_client_gl_texture *self = zn_client_gl_texture_get(resource); + struct zn_shm_buffer *shm_buffer = zn_shm_buffer_get(data); + + if (self == NULL || shm_buffer == NULL) { + return; + } + + zn_gl_texture_image_2d(self->zn_gl_texture, target, level, internal_format, + width, height, border, format, type, shm_buffer->zn_buffer); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_texture_protocol_generate_mipmap(struct wl_client *client UNUSED, + struct wl_resource *resource, uint32_t target) +{ + struct zn_client_gl_texture *self = zn_client_gl_texture_get(resource); + + if (self == NULL) { + return; + } + + zn_gl_texture_generate_mipmap(self->zn_gl_texture, target); +} + +static const struct zwn_gl_texture_interface implementation = { + .destroy = zn_client_gl_texture_protocol_destroy, + .image_2d = zn_client_gl_texture_protocol_image_2d, + .generate_mipmap = zn_client_gl_texture_protocol_generate_mipmap, +}; + +struct zn_client_gl_texture * +zn_client_gl_texture_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + +static void +zn_client_gl_texture_handle_zn_gl_texture_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_texture *self = + zn_container_of(listener, self, zn_gl_texture_destroy_listener); + + zn_client_gl_texture_destroy(self); +} + +struct zn_client_gl_texture * +zn_client_gl_texture_create(struct wl_client *client, uint32_t id) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + if (xr_system == NULL || !zn_xr_system_is_connected(xr_system)) { + zn_error("Failed to get xr_system"); + goto err; + } + + struct zn_client_gl_texture *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + wl_client_post_no_memory(client); + goto err; + } + + self->zn_gl_texture = + zn_xr_dispatcher_get_new_gl_texture(xr_system->default_dispatcher); + if (self->zn_gl_texture == NULL) { + zn_error("Failed to get new zn_gl_texture"); + goto err_free; + } + + self->resource = wl_resource_create(client, &zwn_gl_texture_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_gl_texture; + } + + wl_resource_set_implementation(self->resource, &implementation, self, + zn_client_gl_texture_handle_destroy); + + self->zn_gl_texture_destroy_listener.notify = + zn_client_gl_texture_handle_zn_gl_texture_destroy; + wl_signal_add(&self->zn_gl_texture->events.destroy, + &self->zn_gl_texture_destroy_listener); + + return self; + +err_gl_texture: + zn_xr_dispatcher_destroy_gl_texture( + xr_system->default_dispatcher, self->zn_gl_texture); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_client_gl_texture_destroy(struct zn_client_gl_texture *self) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); + wl_list_remove(&self->zn_gl_texture_destroy_listener.link); + + if (xr_system != NULL && zn_xr_system_is_connected(xr_system)) { + zn_xr_dispatcher_destroy_gl_texture( + xr_system->default_dispatcher, self->zn_gl_texture); + } + + free(self); +} diff --git a/zen/src/backend/immersive/client-gl-texture.h b/zen/src/backend/immersive/client-gl-texture.h new file mode 100644 index 00000000..e6ef9c5b --- /dev/null +++ b/zen/src/backend/immersive/client-gl-texture.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +struct zn_gl_texture; + +struct zn_client_gl_texture { + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_gl_texture *zn_gl_texture; // @nonnull, @outlive + + struct wl_listener zn_gl_texture_destroy_listener; +}; + +struct zn_client_gl_texture *zn_client_gl_texture_create( + struct wl_client *client, uint32_t id); + +/// @return value is nullable +struct zn_client_gl_texture *zn_client_gl_texture_get( + struct wl_resource *resource); diff --git a/zen/src/backend/immersive/remote/gl-texture.cc b/zen/src/backend/immersive/remote/gl-texture.cc new file mode 100644 index 00000000..2ae7cdef --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-texture.cc @@ -0,0 +1,94 @@ +#include "gl-texture.h" + +#include "loop.h" +#include "zen-common/log.h" +#include "zen/buffer.h" + +namespace zen::backend::immersive::remote { + +const zn_gl_texture_interface GlTexture::c_implementation_ = { + GlTexture::HandleImage2D, + GlTexture::HandleGenerateMipmap, +}; + +GlTexture::~GlTexture() +{ + if (c_obj_ != nullptr) { + zn_gl_texture_destroy(c_obj_); + } +} + +GlTexture::GlTexture(wl_display *display) : display_(display) {} + +std::unique_ptr +GlTexture::New( + std::shared_ptr channel, wl_display *display) +{ + auto self = std::unique_ptr(new GlTexture(display)); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(channel))) { + zn_error("Failed to initialize a remote GlTexture"); + return nullptr; + } + + return self; +} + +bool +GlTexture::Init(std::shared_ptr channel) +{ + c_obj_ = zn_gl_texture_create(this, &c_implementation_); + if (c_obj_ == nullptr) { + zn_error("Failed to create a zn_gl_texture"); + return false; + } + + remote_obj_ = zen::remote::server::CreateGlTexture(std::move(channel)); + if (!remote_obj_) { + zn_error("Failed to create a remote GlTexture"); + zn_gl_texture_destroy(c_obj_); + c_obj_ = nullptr; + return false; + } + + return true; +} + +void +GlTexture::HandleImage2D(struct zn_gl_texture *c_obj, uint32_t target, + int32_t level, int32_t internal_format, uint32_t width, uint32_t height, + int32_t border, uint32_t format, uint32_t type, struct zn_buffer *data) +{ + auto *self = static_cast(c_obj->impl_data); + + auto loop = std::make_unique(wl_display_get_event_loop(self->display_)); + + auto remote_buffer = zen::remote::server::CreateBuffer( + [data]() { return zn_buffer_begin_access(data); }, + [data]() { return zn_buffer_end_access(data); }, + [data]() { zn_buffer_unref(data); }, std::move(loop)); + + if (!remote_buffer) { + zn_abort("Failed to create remote buffer"); + return; + } + + zn_buffer_ref(data); + + self->remote_obj_->GlTexImage2D(target, level, internal_format, width, height, + border, format, type, std::move(remote_buffer)); +} + +void +GlTexture::HandleGenerateMipmap(struct zn_gl_texture *c_obj, uint32_t target) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->GlGenerateMipmap(target); +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-texture.h b/zen/src/backend/immersive/remote/gl-texture.h new file mode 100644 index 00000000..6ea00e15 --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-texture.h @@ -0,0 +1,54 @@ +#pragma once + +#include "gl-texture-private.h" +#include "zen-common/cpp-util.h" + +namespace zen::backend::immersive::remote { + +class GlTexture +{ + public: + DISABLE_MOVE_AND_COPY(GlTexture); + ~GlTexture(); + + static std::unique_ptr New( + std::shared_ptr channel, + wl_display *display); + + inline std::unique_ptr &remote_obj(); + inline zn_gl_texture *c_obj() const; + + private: + explicit GlTexture(wl_display *display); + + bool Init(std::shared_ptr channel); + + static void HandleImage2D(struct zn_gl_texture *c_obj, uint32_t target, + int32_t level, int32_t internal_format, uint32_t width, uint32_t height, + int32_t border, uint32_t format, uint32_t type, struct zn_buffer *data); + + static void HandleGenerateMipmap( + struct zn_gl_texture *c_obj, uint32_t target); + + wl_display *display_; // @nonnull, @outlive + + std::unique_ptr remote_obj_; + + static const zn_gl_texture_interface c_implementation_; + + zn_gl_texture *c_obj_ = nullptr; // @nonnull after Init(), @owning +}; + +inline std::unique_ptr & +GlTexture::remote_obj() +{ + return remote_obj_; +} + +inline zn_gl_texture * +GlTexture::c_obj() const +{ + return c_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index c5af5c93..eee3e54b 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -4,6 +4,7 @@ _zen_remote_immersive_backend_srcs = [ 'gl-program.cc', 'gl-rendering-unit.cc', 'gl-shader.cc', + 'gl-texture.cc', 'loop.cc', 'virtual-object.cc', 'xr-dispatcher.cc', diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index dd60427f..a86f3b94 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index 3fc6007f..fe2082e9 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -7,6 +7,7 @@ #include "gl-program.h" #include "gl-rendering-unit.h" #include "gl-shader.h" +#include "gl-texture.h" #include "virtual-object.h" #include "zen-common/log.h" #include "zen/buffer.h" @@ -26,6 +27,8 @@ const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { XrDispatcher::HandleDestroyGlShader, XrDispatcher::HandleGetNewGlProgram, XrDispatcher::HandleDestroyGlProgram, + XrDispatcher::HandleGetNewGlTexture, + XrDispatcher::HandleDestroyGlTexture, }; XrDispatcher::XrDispatcher(wl_display *display) : display_(display) {} @@ -297,4 +300,37 @@ XrDispatcher::HandleDestroyGlProgram( self->gl_programs_.erase(result, self->gl_programs_.end()); } +zn_gl_texture * +XrDispatcher::HandleGetNewGlTexture(struct zn_xr_dispatcher *c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto gl_texture = GlTexture::New(self->channel_, self->display_); + if (!gl_texture) { + zn_error("Failed to create a remote gl_texture"); + return nullptr; + } + + auto *gl_texture_c_obj = gl_texture->c_obj(); + + self->gl_textures_.push_back(std::move(gl_texture)); + + return gl_texture_c_obj; +} + +void +XrDispatcher::HandleDestroyGlTexture( + struct zn_xr_dispatcher *c_obj, struct zn_gl_texture *gl_texture_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto result = + std::remove_if(self->gl_textures_.begin(), self->gl_textures_.end(), + [gl_texture_c_obj](std::unique_ptr &gl_texture) { + return gl_texture->c_obj() == gl_texture_c_obj; + }); + + self->gl_textures_.erase(result, self->gl_textures_.end()); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index b8aa822d..c73ab003 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -7,9 +7,10 @@ namespace zen::backend::immersive::remote { class GlBaseTechnique; class GlBuffer; +class GlProgram; class GlRenderingUnit; class GlShader; -class GlProgram; +class GlTexture; class VirtualObject; class XrDispatcher @@ -62,6 +63,11 @@ class XrDispatcher static void HandleDestroyGlProgram( struct zn_xr_dispatcher *c_obj, struct zn_gl_program *gl_program_c_obj); + static zn_gl_texture *HandleGetNewGlTexture(struct zn_xr_dispatcher *c_obj); + + static void HandleDestroyGlTexture( + struct zn_xr_dispatcher *c_obj, struct zn_gl_texture *gl_texture_c_obj); + wl_display *display_; // @nonnull, @outlive std::shared_ptr channel_; @@ -78,6 +84,8 @@ class XrDispatcher std::vector> gl_programs_; + std::vector> gl_textures_; + static const zn_xr_dispatcher_interface c_implementation_; zn_xr_dispatcher *c_obj_ = nullptr; // @nonnull after Init(), @owning diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index f9c01f07..77e71dfb 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -9,6 +9,7 @@ _zen_backend_srcs = [ 'immersive/client-gl-program.c', 'immersive/client-gl-rendering-unit.c', 'immersive/client-gl-shader.c', + 'immersive/client-gl-texture.c', 'immersive/client-virtual-object.c', 'immersive/shm.c', 'immersive/shm-buffer.c', diff --git a/zen/src/gl-texture-private.h b/zen/src/gl-texture-private.h new file mode 100644 index 00000000..4290c8f6 --- /dev/null +++ b/zen/src/gl-texture-private.h @@ -0,0 +1,18 @@ +#pragma once + +#include "zen/gl-texture.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Called by impl object +struct zn_gl_texture *zn_gl_texture_create( + void *impl_data, const struct zn_gl_texture_interface *implementation); + +/// Called by impl object +void zn_gl_texture_destroy(struct zn_gl_texture *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/gl-texture.c b/zen/src/gl-texture.c new file mode 100644 index 00000000..caa18a02 --- /dev/null +++ b/zen/src/gl-texture.c @@ -0,0 +1,33 @@ +#include "gl-texture-private.h" +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_gl_texture * +zn_gl_texture_create( + void *impl_data, const struct zn_gl_texture_interface *implementation) +{ + struct zn_gl_texture *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + self->impl = implementation; + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_gl_texture_destroy(struct zn_gl_texture *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} From 26ef997d494720e32d117fc4c1ea194b641fd760 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Fri, 28 Apr 2023 22:36:29 +0900 Subject: [PATCH 24/49] add GlVertexArray --- common/include/zen-common/wl-array.h | 3 + common/src/wl-array.c | 12 ++ zen/include/zen/gl-vertex-array.h | 58 ++++++ zen/include/zen/xr-dispatcher.h | 19 ++ zen/meson.build | 1 + zen/src/backend/immersive/client-gl-context.c | 8 +- .../immersive/client-gl-vertex-array.c | 195 ++++++++++++++++++ .../immersive/client-gl-vertex-array.h | 20 ++ zen/src/backend/immersive/remote/gl-buffer.h | 7 + .../immersive/remote/gl-vertex-array.cc | 89 ++++++++ .../immersive/remote/gl-vertex-array.h | 54 +++++ zen/src/backend/immersive/remote/meson.build | 1 + zen/src/backend/immersive/remote/pch/pch.h | 1 + .../backend/immersive/remote/xr-dispatcher.cc | 36 ++++ .../backend/immersive/remote/xr-dispatcher.h | 9 + zen/src/backend/meson.build | 1 + zen/src/gl-vertex-array-private.h | 18 ++ zen/src/gl-vertex-array.c | 33 +++ 18 files changed, 562 insertions(+), 3 deletions(-) create mode 100644 zen/include/zen/gl-vertex-array.h create mode 100644 zen/src/backend/immersive/client-gl-vertex-array.c create mode 100644 zen/src/backend/immersive/client-gl-vertex-array.h create mode 100644 zen/src/backend/immersive/remote/gl-vertex-array.cc create mode 100644 zen/src/backend/immersive/remote/gl-vertex-array.h create mode 100644 zen/src/gl-vertex-array-private.h create mode 100644 zen/src/gl-vertex-array.c diff --git a/common/include/zen-common/wl-array.h b/common/include/zen-common/wl-array.h index 481c639b..c679f8e6 100644 --- a/common/include/zen-common/wl-array.h +++ b/common/include/zen-common/wl-array.h @@ -10,6 +10,9 @@ extern "C" { /// @return true if successful, false otherwise bool zn_wl_array_to_int64_t(struct wl_array *array, int64_t *value); +/// @return true if successful, false otherwise +bool zn_wl_array_to_uint64_t(struct wl_array *array, uint64_t *value); + #ifdef __cplusplus } #endif diff --git a/common/src/wl-array.c b/common/src/wl-array.c index f7340058..0c0531f9 100644 --- a/common/src/wl-array.c +++ b/common/src/wl-array.c @@ -13,3 +13,15 @@ zn_wl_array_to_int64_t(struct wl_array *array, int64_t *value) return true; } + +bool +zn_wl_array_to_uint64_t(struct wl_array *array, uint64_t *value) +{ + if (array->size != sizeof(*value)) { + return false; + } + + memcpy(value, array->data, array->size); + + return true; +} diff --git a/zen/include/zen/gl-vertex-array.h b/zen/include/zen/gl-vertex-array.h new file mode 100644 index 00000000..a60ced8b --- /dev/null +++ b/zen/include/zen/gl-vertex-array.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include "zen-common/util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_gl_buffer; +struct zn_gl_vertex_array; + +struct zn_gl_vertex_array_interface { + void (*enable_vertex_attrib_array)( + struct zn_gl_vertex_array *self, uint32_t index); + void (*disable_vertex_attrib_array)( + struct zn_gl_vertex_array *self, uint32_t index); + void (*vertex_attrib_pointer)(struct zn_gl_vertex_array *self, uint32_t index, + int32_t size, uint32_t type, bool normalized, int32_t stride, + uint64_t offset, struct zn_gl_buffer *gl_buffer); +}; + +struct zn_gl_vertex_array { + void *impl_data; // @nullable, @outlive + const struct zn_gl_vertex_array_interface *impl; // @nonnull, @outlive + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +UNUSED static inline void +zn_gl_vertex_array_enable_vertex_attrib_array( + struct zn_gl_vertex_array *self, uint32_t index) +{ + self->impl->enable_vertex_attrib_array(self, index); +} + +UNUSED static inline void +zn_gl_vertex_array_disable_vertex_attrib_array( + struct zn_gl_vertex_array *self, uint32_t index) +{ + self->impl->disable_vertex_attrib_array(self, index); +} + +UNUSED static inline void +zn_gl_vertex_array_vertex_attrib_pointer(struct zn_gl_vertex_array *self, + uint32_t index, int32_t size, uint32_t type, bool normalized, + int32_t stride, uint64_t offset, struct zn_gl_buffer *gl_buffer) +{ + self->impl->vertex_attrib_pointer( + self, index, size, type, normalized, stride, offset, gl_buffer); +} + +#ifdef __cplusplus +} +#endif diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index 5d1325f1..0765c0af 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -15,6 +15,7 @@ struct zn_gl_program; struct zn_gl_rendering_unit; struct zn_gl_shader; struct zn_gl_texture; +struct zn_gl_vertex_array; struct zn_virtual_object; struct zn_xr_dispatcher; @@ -51,6 +52,11 @@ struct zn_xr_dispatcher_interface { struct zn_gl_texture *(*get_new_gl_texture)(struct zn_xr_dispatcher *self); void (*destroy_gl_texture)( struct zn_xr_dispatcher *self, struct zn_gl_texture *gl_texture); + + struct zn_gl_vertex_array *(*get_new_gl_vertex_array)( + struct zn_xr_dispatcher *self); + void (*destroy_gl_vertex_array)(struct zn_xr_dispatcher *self, + struct zn_gl_vertex_array *gl_vertex_array); }; struct zn_xr_dispatcher { @@ -156,6 +162,19 @@ zn_xr_dispatcher_destroy_gl_texture( self->impl->destroy_gl_texture(self, gl_texture); } +UNUSED static struct zn_gl_vertex_array * +zn_xr_dispatcher_get_new_gl_vertex_array(struct zn_xr_dispatcher *self) +{ + return self->impl->get_new_gl_vertex_array(self); +} + +UNUSED static void +zn_xr_dispatcher_destroy_gl_vertex_array( + struct zn_xr_dispatcher *self, struct zn_gl_vertex_array *gl_vertex_array) +{ + self->impl->destroy_gl_vertex_array(self, gl_vertex_array); +} + #ifdef __cplusplus } #endif diff --git a/zen/meson.build b/zen/meson.build index 3fc0b26d..97a3a8ae 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -8,6 +8,7 @@ _zen_srcs = [ 'src/gl-rendering-unit.c', 'src/gl-shader.c', 'src/gl-texture.c', + 'src/gl-vertex-array.c', 'src/screen.c', 'src/seat.c', 'src/server.c', diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/client-gl-context.c index 2dc2c878..914f8f65 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/client-gl-context.c @@ -9,6 +9,7 @@ #include "client-gl-rendering-unit.h" #include "client-gl-shader.h" #include "client-gl-texture.h" +#include "client-gl-vertex-array.h" #include "client-virtual-object.h" #include "shm-buffer.h" #include "xr-compositor.h" @@ -91,9 +92,10 @@ zn_client_gl_context_protocol_create_gl_sampler(struct wl_client *client UNUSED, /// @param resource can be inert (resource->user_data == NULL) static void zn_client_gl_context_protocol_create_gl_vertex_array( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, - uint32_t id UNUSED) -{} + struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) +{ + zn_client_gl_vertex_array_create(client, id); +} /// @param resource can be inert (resource->user_data == NULL) static void diff --git a/zen/src/backend/immersive/client-gl-vertex-array.c b/zen/src/backend/immersive/client-gl-vertex-array.c new file mode 100644 index 00000000..9651f939 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-vertex-array.c @@ -0,0 +1,195 @@ +#include "client-gl-vertex-array.h" + +#include +#include + +#include "client-gl-buffer.h" +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen-common/wl-array.h" +#include "zen/backend.h" +#include "zen/gl-vertex-array.h" +#include "zen/server.h" +#include "zen/xr-dispatcher.h" +#include "zen/xr-system.h" + +static void zn_client_gl_vertex_array_destroy( + struct zn_client_gl_vertex_array *self); + +static void +zn_client_gl_vertex_array_handle_destroy(struct wl_resource *resource) +{ + struct zn_client_gl_vertex_array *self = + zn_client_gl_vertex_array_get(resource); + + zn_client_gl_vertex_array_destroy(self); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_vertex_array_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_vertex_array_protocol_enable_vertex_attrib_array( + struct wl_client *client UNUSED, struct wl_resource *resource, + uint32_t index) +{ + struct zn_client_gl_vertex_array *self = + zn_client_gl_vertex_array_get(resource); + + if (self == NULL) { + return; + } + + zn_gl_vertex_array_enable_vertex_attrib_array( + self->zn_gl_vertex_array, index); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_vertex_array_protocol_disable_vertex_attrib_array( + struct wl_client *client UNUSED, struct wl_resource *resource, + uint32_t index) +{ + struct zn_client_gl_vertex_array *self = + zn_client_gl_vertex_array_get(resource); + + if (self == NULL) { + return; + } + + zn_gl_vertex_array_disable_vertex_attrib_array( + self->zn_gl_vertex_array, index); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_vertex_array_protocol_vertex_attrib_pointer( + struct wl_client *client UNUSED, struct wl_resource *resource, + uint32_t index, int32_t size, uint32_t type, uint32_t normalized, + int32_t stride, struct wl_array *offset_array, + struct wl_resource *gl_buffer_resource) +{ + struct zn_client_gl_vertex_array *self = + zn_client_gl_vertex_array_get(resource); + struct zn_client_gl_buffer *gl_buffer = + zn_client_gl_buffer_get(gl_buffer_resource); + + if (self == NULL || gl_buffer == NULL) { + return; + } + + uint64_t offset = 0; + + if (!zn_wl_array_to_uint64_t(offset_array, &offset)) { + wl_resource_post_error(resource, ZWN_COMPOSITOR_ERROR_INVALID_WL_ARRAY_SIZE, + "invalid wl_array size"); + return; + } + + zn_gl_vertex_array_vertex_attrib_pointer(self->zn_gl_vertex_array, index, + size, type, normalized, stride, offset, gl_buffer->zn_gl_buffer); +} + +static const struct zwn_gl_vertex_array_interface implementation = { + .destroy = zn_client_gl_vertex_array_protocol_destroy, + .enable_vertex_attrib_array = + zn_client_gl_vertex_array_protocol_enable_vertex_attrib_array, + .disable_vertex_attrib_array = + zn_client_gl_vertex_array_protocol_disable_vertex_attrib_array, + .vertex_attrib_pointer = + zn_client_gl_vertex_array_protocol_vertex_attrib_pointer, +}; + +struct zn_client_gl_vertex_array * +zn_client_gl_vertex_array_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + +static void +zn_client_gl_vertex_array_handle_zn_gl_vertex_array_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_client_gl_vertex_array *self = + zn_container_of(listener, self, zn_gl_vertex_array_destroy_listener); + + zn_client_gl_vertex_array_destroy(self); +} + +struct zn_client_gl_vertex_array * +zn_client_gl_vertex_array_create(struct wl_client *client, uint32_t id) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + if (xr_system == NULL || !zn_xr_system_is_connected(xr_system)) { + zn_error("Failed to get xr_system"); + goto err; + } + + struct zn_client_gl_vertex_array *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + wl_client_post_no_memory(client); + goto err; + } + + self->zn_gl_vertex_array = + zn_xr_dispatcher_get_new_gl_vertex_array(xr_system->default_dispatcher); + if (self->zn_gl_vertex_array == NULL) { + zn_error("Failed to get new gl_vertex_array"); + wl_client_post_no_memory(client); + goto err_free; + } + + self->resource = + wl_resource_create(client, &zwn_gl_vertex_array_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_gl_vertex_array; + } + + wl_resource_set_implementation(self->resource, &implementation, self, + zn_client_gl_vertex_array_handle_destroy); + + self->zn_gl_vertex_array_destroy_listener.notify = + zn_client_gl_vertex_array_handle_zn_gl_vertex_array_destroy; + wl_signal_add(&self->zn_gl_vertex_array->events.destroy, + &self->zn_gl_vertex_array_destroy_listener); + + return self; + +err_gl_vertex_array: + zn_xr_dispatcher_destroy_gl_vertex_array( + xr_system->default_dispatcher, self->zn_gl_vertex_array); + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_client_gl_vertex_array_destroy(struct zn_client_gl_vertex_array *self) +{ + struct zn_server *server = zn_server_get_singleton(); + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); + wl_list_remove(&self->zn_gl_vertex_array_destroy_listener.link); + + if (xr_system != NULL && zn_xr_system_is_connected(xr_system)) { + zn_xr_dispatcher_destroy_gl_vertex_array( + xr_system->default_dispatcher, self->zn_gl_vertex_array); + } + + free(self); +} diff --git a/zen/src/backend/immersive/client-gl-vertex-array.h b/zen/src/backend/immersive/client-gl-vertex-array.h new file mode 100644 index 00000000..e039b9a4 --- /dev/null +++ b/zen/src/backend/immersive/client-gl-vertex-array.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +struct zn_gl_vertex_array; + +struct zn_client_gl_vertex_array { + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_gl_vertex_array *zn_gl_vertex_array; // @nonnull, @outlive + + struct wl_listener zn_gl_vertex_array_destroy_listener; +}; + +struct zn_client_gl_vertex_array *zn_client_gl_vertex_array_create( + struct wl_client *client, uint32_t id); + +/// @return value is nullable +struct zn_client_gl_vertex_array *zn_client_gl_vertex_array_get( + struct wl_resource *resource); diff --git a/zen/src/backend/immersive/remote/gl-buffer.h b/zen/src/backend/immersive/remote/gl-buffer.h index 63163a3c..7bdc8753 100644 --- a/zen/src/backend/immersive/remote/gl-buffer.h +++ b/zen/src/backend/immersive/remote/gl-buffer.h @@ -15,6 +15,7 @@ class GlBuffer std::shared_ptr channel, wl_display *display); + inline std::unique_ptr &remote_obj(); inline zn_gl_buffer *c_obj() const; private: @@ -34,6 +35,12 @@ class GlBuffer zn_gl_buffer *c_obj_ = nullptr; // @nonnull after Init(), @owning }; +inline std::unique_ptr & +GlBuffer::remote_obj() +{ + return remote_obj_; +} + inline zn_gl_buffer * GlBuffer::c_obj() const { diff --git a/zen/src/backend/immersive/remote/gl-vertex-array.cc b/zen/src/backend/immersive/remote/gl-vertex-array.cc new file mode 100644 index 00000000..33aada0e --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-vertex-array.cc @@ -0,0 +1,89 @@ +#include "gl-vertex-array.h" + +#include "gl-buffer.h" +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +const zn_gl_vertex_array_interface GlVertexArray::c_implementation_ = { + GlVertexArray::HandleEnableVertexAttribArray, + GlVertexArray::HandleDisableVertexAttribArray, + GlVertexArray::HandleVertexAttribPointer, +}; + +GlVertexArray::~GlVertexArray() +{ + if (c_obj_ != nullptr) { + zn_gl_vertex_array_destroy(c_obj_); + } +} + +std::unique_ptr +GlVertexArray::New(std::shared_ptr channel) +{ + auto self = std::unique_ptr(new GlVertexArray()); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(channel))) { + zn_error("Failed to initialize a remote GlVertexArray"); + return nullptr; + } + + return self; +} + +bool +GlVertexArray::Init(std::shared_ptr channel) +{ + c_obj_ = zn_gl_vertex_array_create(this, &c_implementation_); + if (c_obj_ == nullptr) { + zn_error("Failed to create a zn_gl_vertex_array"); + return false; + } + + remote_obj_ = zen::remote::server::CreateGlVertexArray(std::move(channel)); + if (!remote_obj_) { + zn_error("Failed to create a remote GlVertexArray"); + zn_gl_vertex_array_destroy(c_obj_); + c_obj_ = nullptr; + return false; + } + + return true; +} + +void +GlVertexArray::HandleEnableVertexAttribArray( + struct zn_gl_vertex_array *c_obj, uint32_t index) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->GlEnableVertexAttribArray(index); +} + +void +GlVertexArray::HandleDisableVertexAttribArray( + struct zn_gl_vertex_array *c_obj, uint32_t index) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->GlDisableVertexAttribArray(index); +} + +void +GlVertexArray::HandleVertexAttribPointer(struct zn_gl_vertex_array *c_obj, + uint32_t index, int32_t size, uint32_t type, bool normalized, + int32_t stride, uint64_t offset, zn_gl_buffer *gl_buffer_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto *gl_buffer = static_cast(gl_buffer_c_obj->impl_data); + + self->remote_obj_->GlVertexAttribPointer(index, size, type, normalized, + stride, offset, gl_buffer->remote_obj()->id()); +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-vertex-array.h b/zen/src/backend/immersive/remote/gl-vertex-array.h new file mode 100644 index 00000000..63e82dce --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-vertex-array.h @@ -0,0 +1,54 @@ +#pragma once + +#include "gl-vertex-array-private.h" +#include "zen-common/cpp-util.h" + +namespace zen::backend::immersive::remote { + +class GlVertexArray +{ + public: + DISABLE_MOVE_AND_COPY(GlVertexArray); + ~GlVertexArray(); + + static std::unique_ptr New( + std::shared_ptr channel); + + inline std::unique_ptr &remote_obj(); + inline zn_gl_vertex_array *c_obj() const; + + private: + GlVertexArray() = default; + + bool Init(std::shared_ptr channel); + + static void HandleEnableVertexAttribArray( + struct zn_gl_vertex_array *c_obj, uint32_t index); + + static void HandleDisableVertexAttribArray( + struct zn_gl_vertex_array *c_obj, uint32_t index); + + static void HandleVertexAttribPointer(struct zn_gl_vertex_array *c_obj, + uint32_t index, int32_t size, uint32_t type, bool normalized, + int32_t stride, uint64_t offset, zn_gl_buffer *gl_buffer_c_obj); + + std::unique_ptr remote_obj_; + + static const zn_gl_vertex_array_interface c_implementation_; + + zn_gl_vertex_array *c_obj_ = nullptr; // @nonnull after Init(), @owning +}; + +inline std::unique_ptr & +GlVertexArray::remote_obj() +{ + return remote_obj_; +} + +inline zn_gl_vertex_array * +GlVertexArray::c_obj() const +{ + return c_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index eee3e54b..e640ef7c 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -5,6 +5,7 @@ _zen_remote_immersive_backend_srcs = [ 'gl-rendering-unit.cc', 'gl-shader.cc', 'gl-texture.cc', + 'gl-vertex-array.cc', 'loop.cc', 'virtual-object.cc', 'xr-dispatcher.cc', diff --git a/zen/src/backend/immersive/remote/pch/pch.h b/zen/src/backend/immersive/remote/pch/pch.h index a86f3b94..097f018e 100644 --- a/zen/src/backend/immersive/remote/pch/pch.h +++ b/zen/src/backend/immersive/remote/pch/pch.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index fe2082e9..4b4e63ea 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -8,6 +8,7 @@ #include "gl-rendering-unit.h" #include "gl-shader.h" #include "gl-texture.h" +#include "gl-vertex-array.h" #include "virtual-object.h" #include "zen-common/log.h" #include "zen/buffer.h" @@ -29,6 +30,8 @@ const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { XrDispatcher::HandleDestroyGlProgram, XrDispatcher::HandleGetNewGlTexture, XrDispatcher::HandleDestroyGlTexture, + XrDispatcher::HandleGetNewGlVertexArray, + XrDispatcher::HandleDestroyGlVertexArray, }; XrDispatcher::XrDispatcher(wl_display *display) : display_(display) {} @@ -333,4 +336,37 @@ XrDispatcher::HandleDestroyGlTexture( self->gl_textures_.erase(result, self->gl_textures_.end()); } +zn_gl_vertex_array * +XrDispatcher::HandleGetNewGlVertexArray(struct zn_xr_dispatcher *c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto gl_vertex_array = GlVertexArray::New(self->channel_); + if (!gl_vertex_array) { + zn_error("Failed to create a remote gl_vertex_array"); + return nullptr; + } + + auto *gl_vertex_array_c_obj = gl_vertex_array->c_obj(); + + self->gl_vertex_arrays_.push_back(std::move(gl_vertex_array)); + + return gl_vertex_array_c_obj; +} + +void +XrDispatcher::HandleDestroyGlVertexArray(struct zn_xr_dispatcher *c_obj, + struct zn_gl_vertex_array *gl_vertex_array_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto result = std::remove_if(self->gl_vertex_arrays_.begin(), + self->gl_vertex_arrays_.end(), + [gl_vertex_array_c_obj](std::unique_ptr &gl_vertex_array) { + return gl_vertex_array->c_obj() == gl_vertex_array_c_obj; + }); + + self->gl_vertex_arrays_.erase(result, self->gl_vertex_arrays_.end()); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.h index c73ab003..3d211b57 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.h @@ -11,6 +11,7 @@ class GlProgram; class GlRenderingUnit; class GlShader; class GlTexture; +class GlVertexArray; class VirtualObject; class XrDispatcher @@ -68,6 +69,12 @@ class XrDispatcher static void HandleDestroyGlTexture( struct zn_xr_dispatcher *c_obj, struct zn_gl_texture *gl_texture_c_obj); + static zn_gl_vertex_array *HandleGetNewGlVertexArray( + struct zn_xr_dispatcher *c_obj); + + static void HandleDestroyGlVertexArray(struct zn_xr_dispatcher *c_obj, + struct zn_gl_vertex_array *gl_vertex_array_c_obj); + wl_display *display_; // @nonnull, @outlive std::shared_ptr channel_; @@ -86,6 +93,8 @@ class XrDispatcher std::vector> gl_textures_; + std::vector> gl_vertex_arrays_; + static const zn_xr_dispatcher_interface c_implementation_; zn_xr_dispatcher *c_obj_ = nullptr; // @nonnull after Init(), @owning diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 77e71dfb..067a5b25 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -10,6 +10,7 @@ _zen_backend_srcs = [ 'immersive/client-gl-rendering-unit.c', 'immersive/client-gl-shader.c', 'immersive/client-gl-texture.c', + 'immersive/client-gl-vertex-array.c', 'immersive/client-virtual-object.c', 'immersive/shm.c', 'immersive/shm-buffer.c', diff --git a/zen/src/gl-vertex-array-private.h b/zen/src/gl-vertex-array-private.h new file mode 100644 index 00000000..dcf06389 --- /dev/null +++ b/zen/src/gl-vertex-array-private.h @@ -0,0 +1,18 @@ +#pragma once + +#include "zen/gl-vertex-array.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Called by impl object +struct zn_gl_vertex_array *zn_gl_vertex_array_create( + void *impl_data, const struct zn_gl_vertex_array_interface *implementation); + +/// Called by impl object +void zn_gl_vertex_array_destroy(struct zn_gl_vertex_array *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/gl-vertex-array.c b/zen/src/gl-vertex-array.c new file mode 100644 index 00000000..277e1547 --- /dev/null +++ b/zen/src/gl-vertex-array.c @@ -0,0 +1,33 @@ +#include "gl-vertex-array-private.h" +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_gl_vertex_array * +zn_gl_vertex_array_create( + void *impl_data, const struct zn_gl_vertex_array_interface *implementation) +{ + struct zn_gl_vertex_array *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + self->impl = implementation; + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_gl_vertex_array_destroy(struct zn_gl_vertex_array *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} From 1b1c453f1ace4a116f149cdd1efeffe373d4ede9 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Fri, 28 Apr 2023 23:21:38 +0900 Subject: [PATCH 25/49] implement some methods of GlBaseTechnique --- zen/include/zen/gl-base-technique.h | 54 ++++++++ .../immersive/client-gl-base-technique.c | 127 +++++++++++++++--- .../immersive/remote/gl-base-technique.cc | 77 +++++++++++ .../immersive/remote/gl-base-technique.h | 18 +++ 4 files changed, 260 insertions(+), 16 deletions(-) diff --git a/zen/include/zen/gl-base-technique.h b/zen/include/zen/gl-base-technique.h index ac990cc0..d1d08e70 100644 --- a/zen/include/zen/gl-base-technique.h +++ b/zen/include/zen/gl-base-technique.h @@ -9,11 +9,26 @@ extern "C" { #endif struct zn_gl_base_technique; +struct zn_gl_buffer; struct zn_gl_program; +struct zn_gl_vertex_array; struct zn_gl_base_technique_interface { void (*bind_program)( struct zn_gl_base_technique *self, struct zn_gl_program *gl_program); + void (*bind_vertex_array)(struct zn_gl_base_technique *self, + struct zn_gl_vertex_array *gl_vertex_array); + void (*uniform_vector)(struct zn_gl_base_technique *self, uint32_t location, + const char *name, uint32_t type, uint32_t size, uint32_t count, + void *value); + void (*uniform_matrix)(struct zn_gl_base_technique *self, uint32_t location, + const char *name, uint32_t col, uint32_t row, uint32_t count, + bool transpose, void *value); + void (*draw_arrays)(struct zn_gl_base_technique *self, uint32_t mode, + int32_t first, uint32_t count); + void (*draw_elements)(struct zn_gl_base_technique *self, uint32_t mode, + uint32_t count, uint32_t type, uint64_t offset, + struct zn_gl_buffer *gl_buffer); }; struct zn_gl_base_technique { @@ -32,6 +47,45 @@ zn_gl_base_technique_bind_program( self->impl->bind_program(self, gl_program); } +UNUSED static inline void +zn_gl_base_technique_bind_vertex_array(struct zn_gl_base_technique *self, + struct zn_gl_vertex_array *gl_vertex_array) +{ + self->impl->bind_vertex_array(self, gl_vertex_array); +} + +UNUSED static inline void +zn_gl_base_technique_uniform_vector(struct zn_gl_base_technique *self, + uint32_t location, const char *name, uint32_t type, uint32_t size, + uint32_t count, void *value) +{ + self->impl->uniform_vector(self, location, name, type, size, count, value); +} + +UNUSED static inline void +zn_gl_base_technique_uniform_matrix(struct zn_gl_base_technique *self, + uint32_t location, const char *name, uint32_t col, uint32_t row, + uint32_t count, bool transpose, void *value) +{ + self->impl->uniform_matrix( + self, location, name, col, row, count, transpose, value); +} + +UNUSED static inline void +zn_gl_base_technique_draw_arrays(struct zn_gl_base_technique *self, + uint32_t mode, int32_t first, uint32_t count) +{ + self->impl->draw_arrays(self, mode, first, count); +} + +UNUSED static inline void +zn_gl_base_technique_draw_elements(struct zn_gl_base_technique *self, + uint32_t mode, uint32_t count, uint32_t type, uint64_t offset, + struct zn_gl_buffer *gl_buffer) +{ + self->impl->draw_elements(self, mode, count, type, offset, gl_buffer); +} + #ifdef __cplusplus } #endif diff --git a/zen/src/backend/immersive/client-gl-base-technique.c b/zen/src/backend/immersive/client-gl-base-technique.c index 148e197e..c236118b 100644 --- a/zen/src/backend/immersive/client-gl-base-technique.c +++ b/zen/src/backend/immersive/client-gl-base-technique.c @@ -1,12 +1,16 @@ #include "client-gl-base-technique.h" #include +#include +#include "client-gl-buffer.h" #include "client-gl-program.h" #include "client-gl-rendering-unit.h" +#include "client-gl-vertex-array.h" #include "client-virtual-object.h" #include "zen-common/log.h" #include "zen-common/util.h" +#include "zen-common/wl-array.h" #include "zen/gl-base-technique.h" #include "zen/xr-dispatcher.h" @@ -52,9 +56,22 @@ zn_client_gl_base_technique_protocol_bind_program( /// @param resource can be inert (resource->user_data == NULL) static void zn_client_gl_base_technique_protocol_bind_vertex_array( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, - struct wl_resource *vertex_array UNUSED) -{} + struct wl_client *client UNUSED, struct wl_resource *resource, + struct wl_resource *vertex_array_resource) +{ + struct zn_client_gl_base_technique *self = + zn_client_gl_base_technique_get(resource); + + struct zn_client_gl_vertex_array *gl_vertex_array = + zn_client_gl_vertex_array_get(vertex_array_resource); + + if (self == NULL || gl_vertex_array == NULL) { + return; + } + + zn_gl_base_technique_bind_vertex_array( + self->zn_gl_base_technique, gl_vertex_array->zn_gl_vertex_array); +} /// @param resource can be inert (resource->user_data == NULL) static void @@ -68,10 +85,40 @@ zn_client_gl_base_technique_protocol_bind_texture( /// @param resource can be inert (resource->user_data == NULL) static void zn_client_gl_base_technique_protocol_uniform_vector( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, - uint32_t location UNUSED, const char *name UNUSED, uint32_t type UNUSED, - uint32_t size UNUSED, uint32_t count UNUSED, struct wl_array *value UNUSED) -{} + struct wl_client *client UNUSED, struct wl_resource *resource, + uint32_t location, const char *name, uint32_t type, uint32_t size, + uint32_t count, struct wl_array *value) +{ + struct zn_client_gl_base_technique *self = + zn_client_gl_base_technique_get(resource); + + if (self == NULL) { + return; + } + + size_t expected_size = 0; + + switch ((enum zwn_gl_base_technique_uniform_variable_type)type) { + case ZWN_GL_BASE_TECHNIQUE_UNIFORM_VARIABLE_TYPE_INT: + expected_size = sizeof(int32_t) * size * count; + break; + case ZWN_GL_BASE_TECHNIQUE_UNIFORM_VARIABLE_TYPE_UINT: + expected_size = sizeof(uint32_t) * size * count; + break; + case ZWN_GL_BASE_TECHNIQUE_UNIFORM_VARIABLE_TYPE_FLOAT: + expected_size = sizeof(float) * size * count; + break; + } + + if (expected_size != value->size) { + wl_resource_post_error(resource, ZWN_COMPOSITOR_ERROR_INVALID_WL_ARRAY_SIZE, + "invalid wl_array size"); + return; + } + + zn_gl_base_technique_uniform_vector(self->zn_gl_base_technique, location, + name, type, size, count, value->data); +} /// @param resource can be inert (resource->user_data == NULL) static void @@ -80,23 +127,71 @@ zn_client_gl_base_technique_protocol_uniform_matrix( uint32_t location UNUSED, const char *name UNUSED, uint32_t col UNUSED, uint32_t row UNUSED, uint32_t count UNUSED, uint32_t transpose UNUSED, struct wl_array *value UNUSED) -{} +{ + struct zn_client_gl_base_technique *self = + zn_client_gl_base_technique_get(resource); + + if (self == NULL) { + return; + } + + size_t expected_size = sizeof(float) * col * row * count; + + if (expected_size != value->size) { + wl_resource_post_error(resource, ZWN_COMPOSITOR_ERROR_INVALID_WL_ARRAY_SIZE, + "invalid wl_array size"); + return; + } + + zn_gl_base_technique_uniform_matrix(self->zn_gl_base_technique, location, + name, col, row, count, transpose, value->data); +} /// @param resource can be inert (resource->user_data == NULL) static void zn_client_gl_base_technique_protocol_draw_arrays( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, - uint32_t mode UNUSED, int32_t first UNUSED, uint32_t count UNUSED) -{} + struct wl_client *client UNUSED, struct wl_resource *resource, + uint32_t mode, int32_t first, uint32_t count) +{ + struct zn_client_gl_base_technique *self = + zn_client_gl_base_technique_get(resource); + + if (self == NULL) { + return; + } + + zn_gl_base_technique_draw_arrays( + self->zn_gl_base_technique, mode, first, count); +} /// @param resource can be inert (resource->user_data == NULL) static void zn_client_gl_base_technique_protocol_draw_elements( - struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, - uint32_t mode UNUSED, uint32_t count UNUSED, uint32_t type UNUSED, - struct wl_array *offset UNUSED, - struct wl_resource *element_array_buffer UNUSED) -{} + struct wl_client *client UNUSED, struct wl_resource *resource, + uint32_t mode, uint32_t count, uint32_t type, struct wl_array *offset_array, + struct wl_resource *element_array_buffer_resource) +{ + struct zn_client_gl_base_technique *self = + zn_client_gl_base_technique_get(resource); + + struct zn_client_gl_buffer *element_array_buffer = + zn_client_gl_buffer_get(element_array_buffer_resource); + + if (self == NULL || element_array_buffer_resource == NULL) { + return; + } + + uint64_t offset = 0; + + if (!zn_wl_array_to_uint64_t(offset_array, &offset)) { + wl_resource_post_error(resource, ZWN_COMPOSITOR_ERROR_INVALID_WL_ARRAY_SIZE, + "invalid wl_array size"); + return; + } + + zn_gl_base_technique_draw_elements(self->zn_gl_base_technique, mode, count, + type, offset, element_array_buffer->zn_gl_buffer); +} static const struct zwn_gl_base_technique_interface implementation = { .destroy = zn_client_gl_base_technique_protocol_destroy, diff --git a/zen/src/backend/immersive/remote/gl-base-technique.cc b/zen/src/backend/immersive/remote/gl-base-technique.cc index 90a593de..024f96bf 100644 --- a/zen/src/backend/immersive/remote/gl-base-technique.cc +++ b/zen/src/backend/immersive/remote/gl-base-technique.cc @@ -1,13 +1,22 @@ #include "gl-base-technique.h" +#include + +#include "gl-buffer.h" #include "gl-program.h" #include "gl-rendering-unit.h" +#include "gl-vertex-array.h" #include "zen-common/log.h" namespace zen::backend::immersive::remote { const zn_gl_base_technique_interface GlBaseTechnique::c_implementation_ = { GlBaseTechnique::HandleBindProgram, + GlBaseTechnique::HandleBindVertexArray, + GlBaseTechnique::HandleUniformVector, + GlBaseTechnique::HandleUniformMatrix, + GlBaseTechnique::HandleDrawArrays, + GlBaseTechnique::HandleDrawElements, }; GlBaseTechnique::~GlBaseTechnique() @@ -68,4 +77,72 @@ GlBaseTechnique::HandleBindProgram( self->remote_obj_->BindProgram(gl_program->remote_obj()->id()); } +void +GlBaseTechnique::HandleBindVertexArray(struct zn_gl_base_technique *c_obj, + struct zn_gl_vertex_array *gl_vertex_array_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto *gl_vertex_array = + static_cast(gl_vertex_array_c_obj->impl_data); + + self->remote_obj_->BindVertexArray(gl_vertex_array->remote_obj()->id()); +} + +void +GlBaseTechnique::HandleUniformVector(struct zn_gl_base_technique *c_obj, + uint32_t location, const char *name, uint32_t type, uint32_t size, + uint32_t count, void *value) +{ + auto *self = static_cast(c_obj->impl_data); + + switch (static_cast(type)) { + case ZWN_GL_BASE_TECHNIQUE_UNIFORM_VARIABLE_TYPE_FLOAT: + self->remote_obj_->GlUniformVector( + location, name, size, count, static_cast(value)); + break; + case ZWN_GL_BASE_TECHNIQUE_UNIFORM_VARIABLE_TYPE_UINT: + self->remote_obj_->GlUniformVector( + location, name, size, count, static_cast(value)); + break; + case ZWN_GL_BASE_TECHNIQUE_UNIFORM_VARIABLE_TYPE_INT: + self->remote_obj_->GlUniformVector( + location, name, size, count, static_cast(value)); + break; + } +} + +void +GlBaseTechnique::HandleUniformMatrix(struct zn_gl_base_technique *c_obj, + uint32_t location, const char *name, uint32_t col, uint32_t row, + uint32_t count, bool transpose, void *value) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->GlUniformMatrix( + location, name, col, row, count, transpose, static_cast(value)); +} + +void +GlBaseTechnique::HandleDrawArrays(struct zn_gl_base_technique *c_obj, + uint32_t mode, int32_t first, uint32_t count) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->GlDrawArrays(mode, first, count); +} + +void +GlBaseTechnique::HandleDrawElements(struct zn_gl_base_technique *c_obj, + uint32_t mode, uint32_t count, uint32_t type, uint64_t offset, + struct zn_gl_buffer *gl_buffer_c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + auto *gl_buffer = static_cast(gl_buffer_c_obj->impl_data); + + self->remote_obj_->GlDrawElements( + mode, count, type, offset, gl_buffer->remote_obj()->id()); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-base-technique.h b/zen/src/backend/immersive/remote/gl-base-technique.h index 091c0ba9..f057e1ac 100644 --- a/zen/src/backend/immersive/remote/gl-base-technique.h +++ b/zen/src/backend/immersive/remote/gl-base-technique.h @@ -29,6 +29,24 @@ class GlBaseTechnique static void HandleBindProgram(struct zn_gl_base_technique *c_obj, struct zn_gl_program *gl_program_c_obj); + static void HandleBindVertexArray(struct zn_gl_base_technique *c_obj, + struct zn_gl_vertex_array *gl_vertex_array_c_obj); + + static void HandleUniformVector(struct zn_gl_base_technique *c_obj, + uint32_t location, const char *name, uint32_t type, uint32_t size, + uint32_t count, void *value); + + static void HandleUniformMatrix(struct zn_gl_base_technique *c_obj, + uint32_t location, const char *name, uint32_t col, uint32_t row, + uint32_t count, bool transpose, void *value); + + static void HandleDrawArrays(struct zn_gl_base_technique *c_obj, + uint32_t mode, int32_t first, uint32_t count); + + static void HandleDrawElements(struct zn_gl_base_technique *c_obj, + uint32_t mode, uint32_t count, uint32_t type, uint64_t offset, + struct zn_gl_buffer *gl_buffer_c_obj); + std::unique_ptr remote_obj_; static const zn_gl_base_technique_interface c_implementation_; From a3e94f0856d537c5f52a637f0f00d0f9f12811d2 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 29 Apr 2023 15:14:37 +0900 Subject: [PATCH 26/49] fix protocol --- zen/src/backend/immersive/client-gl-base-technique.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zen/src/backend/immersive/client-gl-base-technique.c b/zen/src/backend/immersive/client-gl-base-technique.c index c236118b..54a72085 100644 --- a/zen/src/backend/immersive/client-gl-base-technique.c +++ b/zen/src/backend/immersive/client-gl-base-technique.c @@ -86,7 +86,7 @@ zn_client_gl_base_technique_protocol_bind_texture( static void zn_client_gl_base_technique_protocol_uniform_vector( struct wl_client *client UNUSED, struct wl_resource *resource, - uint32_t location, const char *name, uint32_t type, uint32_t size, + int32_t location, const char *name, uint32_t type, uint32_t size, uint32_t count, struct wl_array *value) { struct zn_client_gl_base_technique *self = @@ -124,7 +124,7 @@ zn_client_gl_base_technique_protocol_uniform_vector( static void zn_client_gl_base_technique_protocol_uniform_matrix( struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, - uint32_t location UNUSED, const char *name UNUSED, uint32_t col UNUSED, + int32_t location UNUSED, const char *name UNUSED, uint32_t col UNUSED, uint32_t row UNUSED, uint32_t count UNUSED, uint32_t transpose UNUSED, struct wl_array *value UNUSED) { From 20e254938f24007d88d01ffbb2733b6273a61a16 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 29 Apr 2023 18:43:02 +0900 Subject: [PATCH 27/49] separate zwn-gl protocols implementations to a static library --- .../{ => gl}/client-gl-base-technique.c | 2 +- .../{ => gl}/client-gl-base-technique.h | 0 .../immersive/{ => gl}/client-gl-buffer.c | 2 +- .../immersive/{ => gl}/client-gl-buffer.h | 0 .../immersive/{ => gl}/client-gl-context.c | 6 ++-- .../immersive/{ => gl}/client-gl-context.h | 0 .../immersive/{ => gl}/client-gl-program.c | 0 .../immersive/{ => gl}/client-gl-program.h | 0 .../{ => gl}/client-gl-rendering-unit.c | 2 +- .../{ => gl}/client-gl-rendering-unit.h | 0 .../immersive/{ => gl}/client-gl-shader.c | 2 +- .../immersive/{ => gl}/client-gl-shader.h | 0 .../immersive/{ => gl}/client-gl-texture.c | 2 +- .../immersive/{ => gl}/client-gl-texture.h | 0 .../{ => gl}/client-gl-vertex-array.c | 0 .../{ => gl}/client-gl-vertex-array.h | 0 zen/src/backend/immersive/gl/meson.build | 30 +++++++++++++++++++ zen/src/backend/immersive/{ => gl}/xr-gl.c | 2 +- zen/src/backend/meson.build | 13 ++------ 19 files changed, 41 insertions(+), 20 deletions(-) rename zen/src/backend/immersive/{ => gl}/client-gl-base-technique.c (99%) rename zen/src/backend/immersive/{ => gl}/client-gl-base-technique.h (100%) rename zen/src/backend/immersive/{ => gl}/client-gl-buffer.c (98%) rename zen/src/backend/immersive/{ => gl}/client-gl-buffer.h (100%) rename zen/src/backend/immersive/{ => gl}/client-gl-context.c (97%) rename zen/src/backend/immersive/{ => gl}/client-gl-context.h (100%) rename zen/src/backend/immersive/{ => gl}/client-gl-program.c (100%) rename zen/src/backend/immersive/{ => gl}/client-gl-program.h (100%) rename zen/src/backend/immersive/{ => gl}/client-gl-rendering-unit.c (98%) rename zen/src/backend/immersive/{ => gl}/client-gl-rendering-unit.h (100%) rename zen/src/backend/immersive/{ => gl}/client-gl-shader.c (98%) rename zen/src/backend/immersive/{ => gl}/client-gl-shader.h (100%) rename zen/src/backend/immersive/{ => gl}/client-gl-texture.c (99%) rename zen/src/backend/immersive/{ => gl}/client-gl-texture.h (100%) rename zen/src/backend/immersive/{ => gl}/client-gl-vertex-array.c (100%) rename zen/src/backend/immersive/{ => gl}/client-gl-vertex-array.h (100%) create mode 100644 zen/src/backend/immersive/gl/meson.build rename zen/src/backend/immersive/{ => gl}/xr-gl.c (97%) diff --git a/zen/src/backend/immersive/client-gl-base-technique.c b/zen/src/backend/immersive/gl/client-gl-base-technique.c similarity index 99% rename from zen/src/backend/immersive/client-gl-base-technique.c rename to zen/src/backend/immersive/gl/client-gl-base-technique.c index 54a72085..3fb4861d 100644 --- a/zen/src/backend/immersive/client-gl-base-technique.c +++ b/zen/src/backend/immersive/gl/client-gl-base-technique.c @@ -3,11 +3,11 @@ #include #include +#include "backend/immersive/client-virtual-object.h" #include "client-gl-buffer.h" #include "client-gl-program.h" #include "client-gl-rendering-unit.h" #include "client-gl-vertex-array.h" -#include "client-virtual-object.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen-common/wl-array.h" diff --git a/zen/src/backend/immersive/client-gl-base-technique.h b/zen/src/backend/immersive/gl/client-gl-base-technique.h similarity index 100% rename from zen/src/backend/immersive/client-gl-base-technique.h rename to zen/src/backend/immersive/gl/client-gl-base-technique.h diff --git a/zen/src/backend/immersive/client-gl-buffer.c b/zen/src/backend/immersive/gl/client-gl-buffer.c similarity index 98% rename from zen/src/backend/immersive/client-gl-buffer.c rename to zen/src/backend/immersive/gl/client-gl-buffer.c index c1e1860f..610735c0 100644 --- a/zen/src/backend/immersive/client-gl-buffer.c +++ b/zen/src/backend/immersive/gl/client-gl-buffer.c @@ -2,7 +2,7 @@ #include -#include "shm-buffer.h" +#include "backend/immersive/shm-buffer.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen/backend.h" diff --git a/zen/src/backend/immersive/client-gl-buffer.h b/zen/src/backend/immersive/gl/client-gl-buffer.h similarity index 100% rename from zen/src/backend/immersive/client-gl-buffer.h rename to zen/src/backend/immersive/gl/client-gl-buffer.h diff --git a/zen/src/backend/immersive/client-gl-context.c b/zen/src/backend/immersive/gl/client-gl-context.c similarity index 97% rename from zen/src/backend/immersive/client-gl-context.c rename to zen/src/backend/immersive/gl/client-gl-context.c index 914f8f65..4223fa53 100644 --- a/zen/src/backend/immersive/client-gl-context.c +++ b/zen/src/backend/immersive/gl/client-gl-context.c @@ -3,6 +3,9 @@ #include #include +#include "backend/immersive/client-virtual-object.h" +#include "backend/immersive/shm-buffer.h" +#include "backend/immersive/xr-compositor.h" #include "client-gl-base-technique.h" #include "client-gl-buffer.h" #include "client-gl-program.h" @@ -10,9 +13,6 @@ #include "client-gl-shader.h" #include "client-gl-texture.h" #include "client-gl-vertex-array.h" -#include "client-virtual-object.h" -#include "shm-buffer.h" -#include "xr-compositor.h" #include "zen-common/log.h" #include "zen-common/util.h" diff --git a/zen/src/backend/immersive/client-gl-context.h b/zen/src/backend/immersive/gl/client-gl-context.h similarity index 100% rename from zen/src/backend/immersive/client-gl-context.h rename to zen/src/backend/immersive/gl/client-gl-context.h diff --git a/zen/src/backend/immersive/client-gl-program.c b/zen/src/backend/immersive/gl/client-gl-program.c similarity index 100% rename from zen/src/backend/immersive/client-gl-program.c rename to zen/src/backend/immersive/gl/client-gl-program.c diff --git a/zen/src/backend/immersive/client-gl-program.h b/zen/src/backend/immersive/gl/client-gl-program.h similarity index 100% rename from zen/src/backend/immersive/client-gl-program.h rename to zen/src/backend/immersive/gl/client-gl-program.h diff --git a/zen/src/backend/immersive/client-gl-rendering-unit.c b/zen/src/backend/immersive/gl/client-gl-rendering-unit.c similarity index 98% rename from zen/src/backend/immersive/client-gl-rendering-unit.c rename to zen/src/backend/immersive/gl/client-gl-rendering-unit.c index 31f57282..55bd2277 100644 --- a/zen/src/backend/immersive/client-gl-rendering-unit.c +++ b/zen/src/backend/immersive/gl/client-gl-rendering-unit.c @@ -2,7 +2,7 @@ #include -#include "client-virtual-object.h" +#include "backend/immersive/client-virtual-object.h" #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" diff --git a/zen/src/backend/immersive/client-gl-rendering-unit.h b/zen/src/backend/immersive/gl/client-gl-rendering-unit.h similarity index 100% rename from zen/src/backend/immersive/client-gl-rendering-unit.h rename to zen/src/backend/immersive/gl/client-gl-rendering-unit.h diff --git a/zen/src/backend/immersive/client-gl-shader.c b/zen/src/backend/immersive/gl/client-gl-shader.c similarity index 98% rename from zen/src/backend/immersive/client-gl-shader.c rename to zen/src/backend/immersive/gl/client-gl-shader.c index aaaefae6..1edc3594 100644 --- a/zen/src/backend/immersive/client-gl-shader.c +++ b/zen/src/backend/immersive/gl/client-gl-shader.c @@ -2,7 +2,7 @@ #include -#include "shm-buffer.h" +#include "backend/immersive/shm-buffer.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen/backend.h" diff --git a/zen/src/backend/immersive/client-gl-shader.h b/zen/src/backend/immersive/gl/client-gl-shader.h similarity index 100% rename from zen/src/backend/immersive/client-gl-shader.h rename to zen/src/backend/immersive/gl/client-gl-shader.h diff --git a/zen/src/backend/immersive/client-gl-texture.c b/zen/src/backend/immersive/gl/client-gl-texture.c similarity index 99% rename from zen/src/backend/immersive/client-gl-texture.c rename to zen/src/backend/immersive/gl/client-gl-texture.c index a27a4142..e292a9f9 100644 --- a/zen/src/backend/immersive/client-gl-texture.c +++ b/zen/src/backend/immersive/gl/client-gl-texture.c @@ -2,7 +2,7 @@ #include -#include "shm-buffer.h" +#include "backend/immersive/shm-buffer.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen/backend.h" diff --git a/zen/src/backend/immersive/client-gl-texture.h b/zen/src/backend/immersive/gl/client-gl-texture.h similarity index 100% rename from zen/src/backend/immersive/client-gl-texture.h rename to zen/src/backend/immersive/gl/client-gl-texture.h diff --git a/zen/src/backend/immersive/client-gl-vertex-array.c b/zen/src/backend/immersive/gl/client-gl-vertex-array.c similarity index 100% rename from zen/src/backend/immersive/client-gl-vertex-array.c rename to zen/src/backend/immersive/gl/client-gl-vertex-array.c diff --git a/zen/src/backend/immersive/client-gl-vertex-array.h b/zen/src/backend/immersive/gl/client-gl-vertex-array.h similarity index 100% rename from zen/src/backend/immersive/client-gl-vertex-array.h rename to zen/src/backend/immersive/gl/client-gl-vertex-array.h diff --git a/zen/src/backend/immersive/gl/meson.build b/zen/src/backend/immersive/gl/meson.build new file mode 100644 index 00000000..165cd525 --- /dev/null +++ b/zen/src/backend/immersive/gl/meson.build @@ -0,0 +1,30 @@ +_zen_gl_immersive_backend_srcs = [ + 'client-gl-base-technique.c', + 'client-gl-buffer.c', + 'client-gl-context.c', + 'client-gl-program.c', + 'client-gl-rendering-unit.c', + 'client-gl-shader.c', + 'client-gl-texture.c', + 'client-gl-vertex-array.c', + 'xr-gl.c', + + protocols_code['zwin-gl'], + protocols_server_header['zwin-gl'], +] + +_zen_gl_immersive_backend_deps = [ + _zen_deps, +] + +_zen_gl_immersive_backend_lib = static_library( + 'zen-gl-immersive-backend', + _zen_gl_immersive_backend_srcs, + install: false, + include_directories: zen_private_inc, + dependencies: _zen_gl_immersive_backend_deps, +) + +zen_gl_immersive_backend_dep = declare_dependency( + link_with: _zen_gl_immersive_backend_lib, +) diff --git a/zen/src/backend/immersive/xr-gl.c b/zen/src/backend/immersive/gl/xr-gl.c similarity index 97% rename from zen/src/backend/immersive/xr-gl.c rename to zen/src/backend/immersive/gl/xr-gl.c index e5688f28..37d382e3 100644 --- a/zen/src/backend/immersive/xr-gl.c +++ b/zen/src/backend/immersive/gl/xr-gl.c @@ -1,4 +1,4 @@ -#include "xr-gl.h" +#include "backend/immersive/xr-gl.h" #include diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 067a5b25..d083dd8f 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -1,23 +1,15 @@ +subdir('immersive/gl') subdir('immersive/remote') _zen_backend_srcs = [ 'default-backend.c', - 'immersive/client-gl-base-technique.c', - 'immersive/client-gl-buffer.c', - 'immersive/client-gl-context.c', - 'immersive/client-gl-program.c', - 'immersive/client-gl-rendering-unit.c', - 'immersive/client-gl-shader.c', - 'immersive/client-gl-texture.c', - 'immersive/client-gl-vertex-array.c', 'immersive/client-virtual-object.c', 'immersive/shm.c', 'immersive/shm-buffer.c', 'immersive/shm-pool.c', 'immersive/xr.c', 'immersive/xr-compositor.c', - 'immersive/xr-gl.c', 'screen/compositor.c', 'screen/keyboard.c', @@ -30,12 +22,11 @@ _zen_backend_srcs = [ protocols_code['zwin'], protocols_server_header['zwin'], - protocols_code['zwin-gl'], - protocols_server_header['zwin-gl'], ] _zen_backend_deps = [ _zen_deps, + zen_gl_immersive_backend_dep, zen_remote_immersive_backend_dep, ] From 080641e554dc5cdf4e43ac5cdc3dfd9d139d4908 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 29 Apr 2023 20:06:26 +0900 Subject: [PATCH 28/49] add zn_xr_shell --- protocol/meson.build | 1 + zen/src/backend/immersive/shell/meson.build | 22 ++++++ zen/src/backend/immersive/shell/xr-shell.c | 81 +++++++++++++++++++++ zen/src/backend/immersive/xr-shell.h | 11 +++ zen/src/backend/immersive/xr.c | 11 +++ zen/src/backend/immersive/xr.h | 4 +- zen/src/backend/meson.build | 2 + 7 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 zen/src/backend/immersive/shell/meson.build create mode 100644 zen/src/backend/immersive/shell/xr-shell.c create mode 100644 zen/src/backend/immersive/xr-shell.h diff --git a/protocol/meson.build b/protocol/meson.build index 4ae929eb..c1718219 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -14,6 +14,7 @@ protocols = { 'zwin': zwin_protocol_dir / 'zwin.xml', 'zwin-gl': zwin_protocol_dir / 'zwin-gl.xml', + 'zwin-shell': zwin_protocol_dir / 'zwin-shell.xml', 'wlr-layer-shell-unstable-v1': 'wlr-layer-shell-unstable-v1.xml', } diff --git a/zen/src/backend/immersive/shell/meson.build b/zen/src/backend/immersive/shell/meson.build new file mode 100644 index 00000000..fd7c0b71 --- /dev/null +++ b/zen/src/backend/immersive/shell/meson.build @@ -0,0 +1,22 @@ +_zen_shell_immersive_backend_srcs = [ + 'xr-shell.c', + + protocols_code['zwin-shell'], + protocols_server_header['zwin-shell'], +] + +_zen_shell_immersive_backend_deps = [ + _zen_deps, +] + +_zen_shell_immersive_backend_lib = static_library( + 'zen-shell-immersive-backend', + _zen_shell_immersive_backend_srcs, + install: false, + include_directories: zen_private_inc, + dependencies: _zen_shell_immersive_backend_deps, +) + +zen_shell_immersive_backend_dep = declare_dependency( + link_with: _zen_shell_immersive_backend_lib, +) diff --git a/zen/src/backend/immersive/shell/xr-shell.c b/zen/src/backend/immersive/shell/xr-shell.c new file mode 100644 index 00000000..34dc4673 --- /dev/null +++ b/zen/src/backend/immersive/shell/xr-shell.c @@ -0,0 +1,81 @@ +#include "backend/immersive/xr-shell.h" + +#include + +#include "zen-common/log.h" +#include "zen-common/util.h" + +static void +zn_xr_shell_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +zn_xr_shell_protocol_get_bounded(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED, + struct wl_resource *virtual_object UNUSED, + struct wl_array *half_size UNUSED) +{} + +static void +zn_xr_shell_protocol_get_expansive(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED, + struct wl_resource *virtual_object UNUSED) +{} + +static const struct zwn_shell_interface implementation = { + .destroy = zn_xr_shell_protocol_destroy, + .get_bounded = zn_xr_shell_protocol_get_bounded, + .get_expansive = zn_xr_shell_protocol_get_expansive, +}; + +static void +zn_xr_shell_bind( + struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + struct zn_xr_shell *self = data; + + struct wl_resource *resource = + wl_resource_create(client, &zwn_shell_interface, (int)version, id); + if (resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &implementation, self, NULL); +} + +struct zn_xr_shell * +zn_xr_shell_create(struct wl_display *display) +{ + struct zn_xr_shell *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->global = wl_global_create( + display, &zwn_shell_interface, 1, self, zn_xr_shell_bind); + if (self->global == NULL) { + zn_error("Failed to create zwn_shell global"); + goto err_free; + } + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +void +zn_xr_shell_destroy(struct zn_xr_shell *self) +{ + wl_global_destroy(self->global); + free(self); +} diff --git a/zen/src/backend/immersive/xr-shell.h b/zen/src/backend/immersive/xr-shell.h new file mode 100644 index 00000000..5f4679c4 --- /dev/null +++ b/zen/src/backend/immersive/xr-shell.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct zn_xr_shell { + struct wl_global *global; // @nonnull, @outlive +}; + +struct zn_xr_shell *zn_xr_shell_create(struct wl_display *display); + +void zn_xr_shell_destroy(struct zn_xr_shell *self); diff --git a/zen/src/backend/immersive/xr.c b/zen/src/backend/immersive/xr.c index c82f6dcd..b2d645ad 100644 --- a/zen/src/backend/immersive/xr.c +++ b/zen/src/backend/immersive/xr.c @@ -1,6 +1,7 @@ #include "xr.h" #include "xr-gl.h" +#include "xr-shell.h" #include "xr-system-manager.h" #include "zen-common/log.h" #include "zen-common/util.h" @@ -26,8 +27,17 @@ zn_xr_create(struct wl_display *display) goto err_free_system_manager; } + self->xr_shell = zn_xr_shell_create(display); + if (self->xr_shell == NULL) { + zn_error("Failed to create zn_xr_shell"); + goto err_xr_gl; + } + return self; +err_xr_gl: + zn_xr_gl_destroy(self->xr_gl); + err_free_system_manager: zn_xr_system_manager_destroy(self->xr_system_manager); @@ -41,6 +51,7 @@ zn_xr_create(struct wl_display *display) void zn_xr_destroy(struct zn_xr *self) { + zn_xr_shell_destroy(self->xr_shell); zn_xr_gl_destroy(self->xr_gl); zn_xr_system_manager_destroy(self->xr_system_manager); free(self); diff --git a/zen/src/backend/immersive/xr.h b/zen/src/backend/immersive/xr.h index 8066a7d6..71ce8262 100644 --- a/zen/src/backend/immersive/xr.h +++ b/zen/src/backend/immersive/xr.h @@ -4,11 +4,13 @@ struct zn_xr_system_manager; struct zn_xr_gl; +struct zn_xr_shell; struct zn_xr { struct zn_xr_system_manager *xr_system_manager; // @nonnull, @owning - struct zn_xr_gl *xr_gl; // @nonnull, @owning + struct zn_xr_gl *xr_gl; // @nonnull, @owning + struct zn_xr_shell *xr_shell; // @nonnull, @owning }; struct zn_xr *zn_xr_create(struct wl_display *display); diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index d083dd8f..6ce824df 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -1,5 +1,6 @@ subdir('immersive/gl') subdir('immersive/remote') +subdir('immersive/shell') _zen_backend_srcs = [ 'default-backend.c', @@ -28,6 +29,7 @@ _zen_backend_deps = [ _zen_deps, zen_gl_immersive_backend_dep, zen_remote_immersive_backend_dep, + zen_shell_immersive_backend_dep, ] _zen_backend_lib = static_library( From 274efcc44186e3fe2663ea72e990bd9e1bd24903 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 3 May 2023 18:25:06 +0900 Subject: [PATCH 29/49] add zn_bounded --- common/include/zen-common/wl-array.h | 5 + common/src/wl-array.c | 13 ++ zen/include/zen/bounded.h | 27 +++ zen/include/zen/virtual-object.h | 29 ++- .../immersive/remote/virtual-object.cc | 4 +- .../backend/immersive/remote/virtual-object.h | 2 +- zen/src/backend/immersive/shell/bounded.c | 187 ++++++++++++++++++ zen/src/backend/immersive/shell/bounded.h | 8 + zen/src/backend/immersive/shell/meson.build | 1 + zen/src/backend/immersive/shell/xr-shell.c | 38 +++- zen/src/backend/immersive/xr.h | 2 +- zen/src/virtual-object.c | 61 ++++++ 12 files changed, 360 insertions(+), 17 deletions(-) create mode 100644 zen/include/zen/bounded.h create mode 100644 zen/src/backend/immersive/shell/bounded.c create mode 100644 zen/src/backend/immersive/shell/bounded.h diff --git a/common/include/zen-common/wl-array.h b/common/include/zen-common/wl-array.h index c679f8e6..d1d77262 100644 --- a/common/include/zen-common/wl-array.h +++ b/common/include/zen-common/wl-array.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -13,6 +14,10 @@ bool zn_wl_array_to_int64_t(struct wl_array *array, int64_t *value); /// @return true if successful, false otherwise bool zn_wl_array_to_uint64_t(struct wl_array *array, uint64_t *value); +/// @return true if successful, false otherwise +/// @param array must be initialized +bool zn_wl_array_from_vec3(struct wl_array *array, vec3 v); + #ifdef __cplusplus } #endif diff --git a/common/src/wl-array.c b/common/src/wl-array.c index 0c0531f9..cec3bf3f 100644 --- a/common/src/wl-array.c +++ b/common/src/wl-array.c @@ -25,3 +25,16 @@ zn_wl_array_to_uint64_t(struct wl_array *array, uint64_t *value) return true; } + +bool +zn_wl_array_from_vec3(struct wl_array *array, vec3 v) +{ + void *data = wl_array_add(array, sizeof(vec3)); + if (data == NULL) { + return false; + } + + memcpy(data, v, sizeof(vec3)); + + return true; +} diff --git a/zen/include/zen/bounded.h b/zen/include/zen/bounded.h new file mode 100644 index 00000000..f6550fb9 --- /dev/null +++ b/zen/include/zen/bounded.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +struct zn_virtual_object; + +struct zn_bounded { + struct wl_resource *resource; // @nonnull, @outlive + + struct zn_virtual_object *virtual_object; // @nonnull, @outlive + + struct wl_listener virtual_object_destroy_listener; + struct wl_listener commit_listener; + + struct { + uint32_t serial; + vec3 half_size; + struct wl_event_source *idle; // @nullable, @owning + } scheduled_config; + + bool added; + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; diff --git a/zen/include/zen/virtual-object.h b/zen/include/zen/virtual-object.h index 28d381d4..1c27a727 100644 --- a/zen/include/zen/virtual-object.h +++ b/zen/include/zen/virtual-object.h @@ -9,25 +9,40 @@ extern "C" { #endif struct zn_virtual_object; +struct zn_bounded; + +enum zn_virtual_object_role { + ZN_VIRTUAL_OBJECT_ROLE_NONE = 0, + ZN_VIRTUAL_OBJECT_ROLE_BOUNDED, +}; struct zn_virtual_object_interface { - void (*commit)(struct zn_virtual_object *self); + void (*committed)(struct zn_virtual_object *self); }; struct zn_virtual_object { void *impl_data; // @nullable, @outlive const struct zn_virtual_object_interface *impl; // @nonnull, @outlive + union { + void *role_object; // @nullable, @ref + struct zn_bounded *bounded; // when role == BOUNDED + }; + enum zn_virtual_object_role role; + + struct wl_listener role_object_destroy_listener; + struct { - struct wl_signal destroy; + struct wl_signal destroy; // (NULL) + struct wl_signal commit; // (NULL) } events; }; -UNUSED static inline void -zn_virtual_object_commit(struct zn_virtual_object *self) -{ - self->impl->commit(self); -} +void zn_virtual_object_commit(struct zn_virtual_object *self); + +/// @return true if successful, false otherwise +bool zn_virtual_object_set_role(struct zn_virtual_object *self, + enum zn_virtual_object_role role, void *role_object); #ifdef __cplusplus } diff --git a/zen/src/backend/immersive/remote/virtual-object.cc b/zen/src/backend/immersive/remote/virtual-object.cc index e9506349..7b853fdc 100644 --- a/zen/src/backend/immersive/remote/virtual-object.cc +++ b/zen/src/backend/immersive/remote/virtual-object.cc @@ -5,7 +5,7 @@ namespace zen::backend::immersive::remote { const zn_virtual_object_interface VirtualObject::c_implementation_ = { - VirtualObject::HandleCommit, + VirtualObject::HandleCommitted, }; VirtualObject::~VirtualObject() @@ -53,7 +53,7 @@ VirtualObject::Init(std::shared_ptr channel) } void -VirtualObject::HandleCommit(zn_virtual_object *c_obj) +VirtualObject::HandleCommitted(zn_virtual_object *c_obj) { auto *self = static_cast(c_obj->impl_data); diff --git a/zen/src/backend/immersive/remote/virtual-object.h b/zen/src/backend/immersive/remote/virtual-object.h index 4501e36a..1b71ec78 100644 --- a/zen/src/backend/immersive/remote/virtual-object.h +++ b/zen/src/backend/immersive/remote/virtual-object.h @@ -22,7 +22,7 @@ class VirtualObject bool Init(std::shared_ptr channel); - static void HandleCommit(zn_virtual_object *c_obj); + static void HandleCommitted(zn_virtual_object *c_obj); std::unique_ptr remote_obj_; diff --git a/zen/src/backend/immersive/shell/bounded.c b/zen/src/backend/immersive/shell/bounded.c new file mode 100644 index 00000000..6aa749da --- /dev/null +++ b/zen/src/backend/immersive/shell/bounded.c @@ -0,0 +1,187 @@ +#include "bounded.h" + +#include +#include +#include + +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" +#include "zen-common/wl-array.h" +#include "zen/virtual-object.h" + +static void zn_bounded_destroy(struct zn_bounded *self); + +static void +zn_bounded_send_configure(void *user_data) +{ + struct zn_bounded *self = user_data; + + self->scheduled_config.idle = NULL; + + struct wl_array half_size_array; + wl_array_init(&half_size_array); + + if (!zn_wl_array_from_vec3( + &half_size_array, self->scheduled_config.half_size)) { + zn_error("Failed to convert from vec3 to wl_array"); + wl_array_release(&half_size_array); + return; + } + + zwn_bounded_send_configure( + self->resource, &half_size_array, self->scheduled_config.serial); + + wl_array_release(&half_size_array); +} + +uint32_t +zn_bounded_schedule_configure(struct zn_bounded *self) +{ + struct wl_client *client = wl_resource_get_client(self->resource); + struct wl_display *display = wl_client_get_display(client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + + if (self->scheduled_config.idle == NULL) { + self->scheduled_config.serial = wl_display_get_serial(display); + self->scheduled_config.idle = + wl_event_loop_add_idle(loop, zn_bounded_send_configure, self); + if (self->scheduled_config.idle == NULL) { + wl_client_post_no_memory(client); + } + } + + return self->scheduled_config.serial; +} + +static void +zn_bounded_handle_destroy(struct wl_resource *resource) +{ + struct zn_bounded *self = wl_resource_get_user_data(resource); + + zn_bounded_destroy(self); +} + +static void +zn_bounded_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +zn_bounded_protocol_ack_configure(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, struct wl_array *half_size UNUSED, + uint32_t serial UNUSED) +{} + +static void +zn_bounded_protocol_set_title(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, const char *title UNUSED) +{} + +static void +zn_bounded_protocol_set_input_region(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, struct wl_resource *region UNUSED) +{} + +static void +zn_bounded_protocol_move(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, struct wl_resource *seat UNUSED, + uint32_t serial UNUSED) +{} + +static const struct zwn_bounded_interface implementation = { + .destroy = zn_bounded_protocol_destroy, + .ack_configure = zn_bounded_protocol_ack_configure, + .set_title = zn_bounded_protocol_set_title, + .set_input_region = zn_bounded_protocol_set_input_region, + .move = zn_bounded_protocol_move, +}; + +static void +zn_bounded_handle_virtual_object_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_bounded *self = + zn_container_of(listener, self, virtual_object_destroy_listener); + + wl_resource_post_error(self->resource, + ZWN_VIRTUAL_OBJECT_ERROR_DEFUNCT_ROLE_OBJECT, + "Virtual object is destroyed before its role object (zwn_bounded)"); + + wl_resource_destroy(self->resource); +} + +static void +zn_bounded_handle_commit(struct wl_listener *listener, void *data UNUSED) +{ + struct zn_bounded *self = zn_container_of(listener, self, commit_listener); + + if (!self->added) { + // on the initial commit + + self->added = true; + glm_vec3_zero(self->scheduled_config.half_size); + zn_bounded_schedule_configure(self); + } +} + +struct zn_bounded * +zn_bounded_create(struct wl_client *client, uint32_t id, + struct zn_virtual_object *virtual_object) +{ + struct zn_bounded *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + wl_client_post_no_memory(client); + goto err; + } + + self->virtual_object = virtual_object; + wl_signal_init(&self->events.destroy); + glm_vec3_zero(self->scheduled_config.half_size); + self->scheduled_config.idle = NULL; + self->added = false; + + self->resource = wl_resource_create(client, &zwn_bounded_interface, 1, id); + if (self->resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + goto err_free; + } + + wl_resource_set_implementation( + self->resource, &implementation, self, zn_bounded_handle_destroy); + + self->virtual_object_destroy_listener.notify = + zn_bounded_handle_virtual_object_destroy; + wl_signal_add(&self->virtual_object->events.destroy, + &self->virtual_object_destroy_listener); + + self->commit_listener.notify = zn_bounded_handle_commit; + wl_signal_add(&self->virtual_object->events.commit, &self->commit_listener); + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_bounded_destroy(struct zn_bounded *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + if (self->scheduled_config.idle != NULL) { + wl_event_source_remove(self->scheduled_config.idle); + } + + wl_list_remove(&self->events.destroy.listener_list); + wl_list_remove(&self->virtual_object_destroy_listener.link); + wl_list_remove(&self->commit_listener.link); + free(self); +} diff --git a/zen/src/backend/immersive/shell/bounded.h b/zen/src/backend/immersive/shell/bounded.h new file mode 100644 index 00000000..14c5a660 --- /dev/null +++ b/zen/src/backend/immersive/shell/bounded.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +#include "zen/bounded.h" + +struct zn_bounded *zn_bounded_create(struct wl_client *client, uint32_t id, + struct zn_virtual_object *virtual_object); diff --git a/zen/src/backend/immersive/shell/meson.build b/zen/src/backend/immersive/shell/meson.build index fd7c0b71..2756870d 100644 --- a/zen/src/backend/immersive/shell/meson.build +++ b/zen/src/backend/immersive/shell/meson.build @@ -1,5 +1,6 @@ _zen_shell_immersive_backend_srcs = [ 'xr-shell.c', + 'bounded.c', protocols_code['zwin-shell'], protocols_server_header['zwin-shell'], diff --git a/zen/src/backend/immersive/shell/xr-shell.c b/zen/src/backend/immersive/shell/xr-shell.c index 34dc4673..af00ba1c 100644 --- a/zen/src/backend/immersive/shell/xr-shell.c +++ b/zen/src/backend/immersive/shell/xr-shell.c @@ -1,9 +1,13 @@ #include "backend/immersive/xr-shell.h" +#include #include +#include "backend/immersive/client-virtual-object.h" +#include "bounded.h" #include "zen-common/log.h" #include "zen-common/util.h" +#include "zen/virtual-object.h" static void zn_xr_shell_protocol_destroy( @@ -13,16 +17,38 @@ zn_xr_shell_protocol_destroy( } static void -zn_xr_shell_protocol_get_bounded(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, uint32_t id UNUSED, - struct wl_resource *virtual_object UNUSED, - struct wl_array *half_size UNUSED) -{} +zn_xr_shell_protocol_get_bounded(struct wl_client *client, + struct wl_resource *resource UNUSED, uint32_t id, + struct wl_resource *virtual_object_resource) +{ + struct zn_client_virtual_object *client_virtual_object = + zn_client_virtual_object_get(virtual_object_resource); + + if (client_virtual_object == NULL) { + return; + } + + struct zn_bounded *bounded = + zn_bounded_create(client, id, client_virtual_object->zn_virtual_object); + if (bounded == NULL) { + zn_error("Failed to create a zn_bounded"); + return; + } + + if (!zn_virtual_object_set_role(client_virtual_object->zn_virtual_object, + ZN_VIRTUAL_OBJECT_ROLE_BOUNDED, bounded)) { + wl_resource_post_error(client_virtual_object->resource, + ZWN_VIRTUAL_OBJECT_ERROR_ROLE, + "Failed assign bounded role to the virtual object (%d)", + wl_resource_get_id(client_virtual_object->resource)); + wl_resource_destroy(bounded->resource); + } +} static void zn_xr_shell_protocol_get_expansive(struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, uint32_t id UNUSED, - struct wl_resource *virtual_object UNUSED) + struct wl_resource *virtual_object_resource UNUSED) {} static const struct zwn_shell_interface implementation = { diff --git a/zen/src/backend/immersive/xr.h b/zen/src/backend/immersive/xr.h index 71ce8262..6b6df91f 100644 --- a/zen/src/backend/immersive/xr.h +++ b/zen/src/backend/immersive/xr.h @@ -9,7 +9,7 @@ struct zn_xr_shell; struct zn_xr { struct zn_xr_system_manager *xr_system_manager; // @nonnull, @owning - struct zn_xr_gl *xr_gl; // @nonnull, @owning + struct zn_xr_gl *xr_gl; // @nonnull, @owning struct zn_xr_shell *xr_shell; // @nonnull, @owning }; diff --git a/zen/src/virtual-object.c b/zen/src/virtual-object.c index 93f0a1fb..d7ec1ea2 100644 --- a/zen/src/virtual-object.c +++ b/zen/src/virtual-object.c @@ -3,6 +3,60 @@ #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" +#include "zen/bounded.h" + +bool +zn_virtual_object_set_role(struct zn_virtual_object *self, + enum zn_virtual_object_role role, void *role_object) +{ + zn_assert(role != ZN_VIRTUAL_OBJECT_ROLE_NONE, + "Do not pass NONE role to zn_virtual_object_set_role"); + + bool valid = self->role == ZN_VIRTUAL_OBJECT_ROLE_NONE || + (self->role == role && self->role_object == NULL); + + if (!valid) { + return false; + } + + zn_assert(self->role_object == NULL, "Invalid role_object state"); + + self->role = role; + self->role_object = role_object; + + if (self->role_object) { + switch (self->role) { + case ZN_VIRTUAL_OBJECT_ROLE_NONE: + zn_assert(false, "unreachable"); + break; + case ZN_VIRTUAL_OBJECT_ROLE_BOUNDED: + wl_signal_add(&self->bounded->events.destroy, + &self->role_object_destroy_listener); + break; + } + } + + return true; +} + +static void +zn_virtual_object_handle_role_object_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_virtual_object *self = + zn_container_of(listener, self, role_object_destroy_listener); + + self->role_object = NULL; + wl_list_remove(&self->role_object_destroy_listener.link); + wl_list_init(&self->role_object_destroy_listener.link); +} + +void +zn_virtual_object_commit(struct zn_virtual_object *self) +{ + zn_signal_emit_mutable(&self->events.commit, NULL); + self->impl->committed(self); +} struct zn_virtual_object * zn_virtual_object_create( @@ -17,6 +71,11 @@ zn_virtual_object_create( self->impl_data = impl_data; self->impl = implementation; wl_signal_init(&self->events.destroy); + wl_signal_init(&self->events.commit); + + self->role_object_destroy_listener.notify = + zn_virtual_object_handle_role_object_destroy; + wl_list_init(&self->role_object_destroy_listener.link); return self; @@ -29,6 +88,8 @@ zn_virtual_object_destroy(struct zn_virtual_object *self) { zn_signal_emit_mutable(&self->events.destroy, NULL); + wl_list_remove(&self->role_object_destroy_listener.link); wl_list_remove(&self->events.destroy.listener_list); + wl_list_remove(&self->events.commit.listener_list); free(self); } From b8725f7e00be61162eb5d8202de0612ff3d8f565 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 7 May 2023 16:08:59 +0900 Subject: [PATCH 30/49] zn_bounded configure --- common/include/zen-common/wl-array.h | 5 +- common/src/wl-array.c | 16 +++- zen/include/zen/backend.h | 9 +- zen/include/zen/bounded-configure.h | 10 ++ zen/include/zen/bounded.h | 13 +++ zen/src/backend/default-backend.c | 9 ++ zen/src/backend/default-backend.h | 4 + .../immersive/shell/bounded-configure.c | 32 +++++++ .../immersive/shell/bounded-configure.h | 6 ++ zen/src/backend/immersive/shell/bounded.c | 91 +++++++++++++++++-- zen/src/backend/immersive/shell/meson.build | 1 + 11 files changed, 182 insertions(+), 14 deletions(-) create mode 100644 zen/include/zen/bounded-configure.h create mode 100644 zen/src/backend/immersive/shell/bounded-configure.c create mode 100644 zen/src/backend/immersive/shell/bounded-configure.h diff --git a/common/include/zen-common/wl-array.h b/common/include/zen-common/wl-array.h index d1d77262..a2f7e17c 100644 --- a/common/include/zen-common/wl-array.h +++ b/common/include/zen-common/wl-array.h @@ -16,7 +16,10 @@ bool zn_wl_array_to_uint64_t(struct wl_array *array, uint64_t *value); /// @return true if successful, false otherwise /// @param array must be initialized -bool zn_wl_array_from_vec3(struct wl_array *array, vec3 v); +bool zn_wl_array_from_vec3(struct wl_array *array, vec3 value); + +/// @return true if successful, false otherwise +bool zn_wl_array_to_vec3(struct wl_array *array, vec3 value); #ifdef __cplusplus } diff --git a/common/src/wl-array.c b/common/src/wl-array.c index cec3bf3f..564d113b 100644 --- a/common/src/wl-array.c +++ b/common/src/wl-array.c @@ -27,14 +27,26 @@ zn_wl_array_to_uint64_t(struct wl_array *array, uint64_t *value) } bool -zn_wl_array_from_vec3(struct wl_array *array, vec3 v) +zn_wl_array_from_vec3(struct wl_array *array, vec3 value) { void *data = wl_array_add(array, sizeof(vec3)); if (data == NULL) { return false; } - memcpy(data, v, sizeof(vec3)); + memcpy(data, value, sizeof(vec3)); + + return true; +} + +bool +zn_wl_array_to_vec3(struct wl_array *array, vec3 value) +{ + if (array->size != sizeof(vec3)) { + return false; + } + + memcpy(value, array->data, array->size); return true; } diff --git a/zen/include/zen/backend.h b/zen/include/zen/backend.h index 44f9de28..f6686be8 100644 --- a/zen/include/zen/backend.h +++ b/zen/include/zen/backend.h @@ -29,10 +29,11 @@ struct zn_backend { const struct zn_backend_interface *impl; struct { - struct wl_signal new_screen; // (struct zn_screen *) - struct wl_signal view_mapped; // (struct zn_view *) - struct wl_signal destroy; // (NULL) - struct wl_signal new_xr_system; // (struct zn_xr_system *) + struct wl_signal new_screen; // (struct zn_screen *) + struct wl_signal view_mapped; // (struct zn_view *) + struct wl_signal bounded_mapped; // (struct zn_bounded *) + struct wl_signal destroy; // (NULL) + struct wl_signal new_xr_system; // (struct zn_xr_system *) } events; }; diff --git a/zen/include/zen/bounded-configure.h b/zen/include/zen/bounded-configure.h new file mode 100644 index 00000000..2b8a907c --- /dev/null +++ b/zen/include/zen/bounded-configure.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +struct zn_bounded_configure { + uint32_t serial; + vec3 half_size; + struct wl_list link; // zn_bounded::configure_list +}; diff --git a/zen/include/zen/bounded.h b/zen/include/zen/bounded.h index f6550fb9..17a03ae9 100644 --- a/zen/include/zen/bounded.h +++ b/zen/include/zen/bounded.h @@ -10,6 +10,9 @@ struct zn_bounded { struct zn_virtual_object *virtual_object; // @nonnull, @outlive + /// configure_list.prev is the latest + struct wl_list configure_list; // zn_bounded_configure::link, @owning items + struct wl_listener virtual_object_destroy_listener; struct wl_listener commit_listener; @@ -20,6 +23,16 @@ struct zn_bounded { } scheduled_config; bool added; + bool configured; + bool mapped; + + struct { + vec3 half_size; + } pending; + + struct { + vec3 half_size; + } current; struct { struct wl_signal destroy; // (NULL) diff --git a/zen/src/backend/default-backend.c b/zen/src/backend/default-backend.c index cc7c8fcf..355e8a75 100644 --- a/zen/src/backend/default-backend.c +++ b/zen/src/backend/default-backend.c @@ -65,6 +65,13 @@ zn_default_backend_notify_view_mapped( wl_signal_emit(&self->base.events.view_mapped, view); } +void +zn_default_backend_notify_bounded_mapped( + struct zn_default_backend *self, struct zn_bounded *bounded) +{ + wl_signal_emit(&self->base.events.bounded_mapped, bounded); +} + /// @param xr_system is nullable static void zn_default_backend_set_xr_system( @@ -250,6 +257,7 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) wl_signal_init(&self->base.events.new_screen); wl_signal_init(&self->base.events.view_mapped); + wl_signal_init(&self->base.events.bounded_mapped); wl_signal_init(&self->base.events.destroy); wl_signal_init(&self->base.events.new_xr_system); self->base.impl = &implementation; @@ -363,6 +371,7 @@ zn_default_backend_destroy(struct zn_default_backend *self) wl_list_remove(&self->input_device_list); wl_list_remove(&self->base.events.new_xr_system.listener_list); wl_list_remove(&self->base.events.destroy.listener_list); + wl_list_remove(&self->base.events.bounded_mapped.listener_list); wl_list_remove(&self->base.events.view_mapped.listener_list); wl_list_remove(&self->base.events.new_screen.listener_list); free(self); diff --git a/zen/src/backend/default-backend.h b/zen/src/backend/default-backend.h index 3506e5c7..0c7b7eb3 100644 --- a/zen/src/backend/default-backend.h +++ b/zen/src/backend/default-backend.h @@ -2,6 +2,7 @@ #include "zen/backend.h" +struct zn_bounded; struct zn_compositor; struct zn_view; struct zn_xr; @@ -39,3 +40,6 @@ void zn_default_backend_update_capabilities(struct zn_default_backend *self); void zn_default_backend_notify_view_mapped( struct zn_default_backend *self, struct zn_view *view); + +void zn_default_backend_notify_bounded_mapped( + struct zn_default_backend *self, struct zn_bounded *bounded); diff --git a/zen/src/backend/immersive/shell/bounded-configure.c b/zen/src/backend/immersive/shell/bounded-configure.c new file mode 100644 index 00000000..e7d5a038 --- /dev/null +++ b/zen/src/backend/immersive/shell/bounded-configure.c @@ -0,0 +1,32 @@ +#include "bounded-configure.h" + +#include + +#include "zen-common/log.h" +#include "zen-common/util.h" + +struct zn_bounded_configure * +zn_bounded_configure_create(uint32_t serial, vec3 half_size) +{ + struct zn_bounded_configure *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->serial = serial; + glm_vec3_copy(half_size, self->half_size); + wl_list_init(&self->link); + + return self; + +err: + return NULL; +} + +void +zn_bounded_configure_destroy(struct zn_bounded_configure *self) +{ + wl_list_remove(&self->link); + free(self); +} diff --git a/zen/src/backend/immersive/shell/bounded-configure.h b/zen/src/backend/immersive/shell/bounded-configure.h new file mode 100644 index 00000000..19346047 --- /dev/null +++ b/zen/src/backend/immersive/shell/bounded-configure.h @@ -0,0 +1,6 @@ +#include "zen/bounded-configure.h" + +struct zn_bounded_configure *zn_bounded_configure_create( + uint32_t serial, vec3 half_size); + +void zn_bounded_configure_destroy(struct zn_bounded_configure *self); diff --git a/zen/src/backend/immersive/shell/bounded.c b/zen/src/backend/immersive/shell/bounded.c index 6aa749da..de3e342b 100644 --- a/zen/src/backend/immersive/shell/bounded.c +++ b/zen/src/backend/immersive/shell/bounded.c @@ -4,10 +4,13 @@ #include #include +#include "backend/default-backend.h" +#include "bounded-configure.h" #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" #include "zen-common/wl-array.h" +#include "zen/server.h" #include "zen/virtual-object.h" static void zn_bounded_destroy(struct zn_bounded *self); @@ -25,13 +28,23 @@ zn_bounded_send_configure(void *user_data) if (!zn_wl_array_from_vec3( &half_size_array, self->scheduled_config.half_size)) { zn_error("Failed to convert from vec3 to wl_array"); - wl_array_release(&half_size_array); - return; + goto out; + } + + struct zn_bounded_configure *configure = zn_bounded_configure_create( + self->scheduled_config.serial, self->scheduled_config.half_size); + if (configure == NULL) { + wl_client_post_no_memory(wl_resource_get_client(self->resource)); + zn_error("Failed to create a zn_bounded_configure"); + goto out; } zwn_bounded_send_configure( self->resource, &half_size_array, self->scheduled_config.serial); + wl_list_insert(self->configure_list.prev, &configure->link); + +out: wl_array_release(&half_size_array); } @@ -71,9 +84,51 @@ zn_bounded_protocol_destroy( static void zn_bounded_protocol_ack_configure(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, struct wl_array *half_size UNUSED, - uint32_t serial UNUSED) -{} + struct wl_resource *resource, struct wl_array *half_size_array, + uint32_t serial) +{ + struct zn_bounded *self = wl_resource_get_user_data(resource); + vec3 half_size; + + if (!zn_wl_array_to_vec3(half_size_array, half_size)) { + wl_resource_post_error(resource, ZWN_COMPOSITOR_ERROR_INVALID_WL_ARRAY_SIZE, + "invalid wl_array size"); + return; + } + + bool found = false; + struct zn_bounded_configure *configure = NULL; + + wl_list_for_each (configure, &self->configure_list, link) { + if (configure->serial == serial) { + found = true; + break; + } + } + + if (!found) { + wl_resource_post_error(resource, ZWN_BOUNDED_ERROR_INVALID_SERIAL, + "wrong configure serial: %u", serial); + return; + } + + struct zn_bounded_configure *configure_tmp = NULL; + + wl_list_for_each_safe ( + configure, configure_tmp, &self->configure_list, link) { + if (configure->serial == serial) { + break; + } + + zn_bounded_configure_destroy(configure); + } + + self->configured = true; + + glm_vec3_copy(half_size, self->pending.half_size); + + zn_bounded_configure_destroy(configure); +} static void zn_bounded_protocol_set_title(struct wl_client *client UNUSED, @@ -117,14 +172,22 @@ static void zn_bounded_handle_commit(struct wl_listener *listener, void *data UNUSED) { struct zn_bounded *self = zn_container_of(listener, self, commit_listener); + struct zn_server *server = zn_server_get_singleton(); + struct zn_default_backend *backend = zn_default_backend_get(server->backend); + + glm_vec3_copy(self->pending.half_size, self->current.half_size); if (!self->added) { // on the initial commit - self->added = true; glm_vec3_zero(self->scheduled_config.half_size); zn_bounded_schedule_configure(self); } + + if (self->configured && !self->mapped) { + self->mapped = true; + zn_default_backend_notify_bounded_mapped(backend, self); + } } struct zn_bounded * @@ -139,10 +202,15 @@ zn_bounded_create(struct wl_client *client, uint32_t id, } self->virtual_object = virtual_object; - wl_signal_init(&self->events.destroy); + wl_list_init(&self->configure_list); glm_vec3_zero(self->scheduled_config.half_size); self->scheduled_config.idle = NULL; self->added = false; + self->configured = false; + self->mapped = false; + glm_vec3_zero(self->pending.half_size); + glm_vec3_zero(self->current.half_size); + wl_signal_init(&self->events.destroy); self->resource = wl_resource_create(client, &zwn_bounded_interface, 1, id); if (self->resource == NULL) { @@ -174,12 +242,21 @@ zn_bounded_create(struct wl_client *client, uint32_t id, static void zn_bounded_destroy(struct zn_bounded *self) { + struct zn_bounded_configure *configure = NULL; + struct zn_bounded_configure *configure_tmp = NULL; + zn_signal_emit_mutable(&self->events.destroy, NULL); if (self->scheduled_config.idle != NULL) { wl_event_source_remove(self->scheduled_config.idle); } + wl_list_for_each_safe ( + configure, configure_tmp, &self->configure_list, link) { + zn_bounded_configure_destroy(configure); + } + + wl_list_remove(&self->configure_list); wl_list_remove(&self->events.destroy.listener_list); wl_list_remove(&self->virtual_object_destroy_listener.link); wl_list_remove(&self->commit_listener.link); diff --git a/zen/src/backend/immersive/shell/meson.build b/zen/src/backend/immersive/shell/meson.build index 2756870d..1d1c6cd7 100644 --- a/zen/src/backend/immersive/shell/meson.build +++ b/zen/src/backend/immersive/shell/meson.build @@ -1,6 +1,7 @@ _zen_shell_immersive_backend_srcs = [ 'xr-shell.c', 'bounded.c', + 'bounded-configure.c', protocols_code['zwin-shell'], protocols_server_header['zwin-shell'], From 8123e7ae026fb041daaedf8309c072b5e7868d69 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 10 May 2023 22:09:49 +0900 Subject: [PATCH 31/49] inode --- test-harness/include/test-harness.h | 8 ++ zen/include/zen/inode.h | 46 +++++++++ zen/meson.build | 1 + zen/src/inode.c | 134 ++++++++++++++++++++++++++ zen/tests/inode/inode-map.c | 142 ++++++++++++++++++++++++++++ zen/tests/meson.build | 1 + 6 files changed, 332 insertions(+) create mode 100644 zen/include/zen/inode.h create mode 100644 zen/src/inode.c create mode 100644 zen/tests/inode/inode-map.c diff --git a/test-harness/include/test-harness.h b/test-harness/include/test-harness.h index d65f7b91..8477f2d2 100644 --- a/test-harness/include/test-harness.h +++ b/test-harness/include/test-harness.h @@ -26,6 +26,14 @@ struct test { \ static void name##_test(void) +#define FAIL_TEST(name) \ + static void name##_test(void); \ + \ + const struct test test##name __attribute__(( \ + used, section("test_section"))) = {#name, name##_test, 1}; \ + \ + static void name##_test(void) + // Assertions void assert_equal_string_( diff --git a/zen/include/zen/inode.h b/zen/include/zen/inode.h new file mode 100644 index 00000000..716bb9d2 --- /dev/null +++ b/zen/include/zen/inode.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +struct zn_inode_interface { + void (*mapped)(void *impl_data); + void (*unmapped)(void *impl_data); +}; + +extern const struct zn_inode_interface zn_inode_noop_implementation; + +/// inode is a root node when self->parent == NULL +struct zn_inode { + void *impl_data; // @nullable, @outlive + const struct zn_inode_interface *impl; // @nonnull, @outlive + + vec3 position; + versor quaternion; + + struct zn_inode *parent; // @nullable, @ref + struct wl_list link; // zn_inode::child_list + struct wl_list child_list; // zn_inode::link + + bool mapped; + + struct wl_listener parent_destroy_listener; + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +/// @param self must be root +void zn_inode_map(struct zn_inode *self); + +/// @param self must be root +void zn_inode_unmap(struct zn_inode *self); + +void zn_inode_move(struct zn_inode *self, struct zn_inode *parent, + vec3 position, versor quaternion); + +struct zn_inode *zn_inode_create( + void *impl_data, const struct zn_inode_interface *implementation); + +void zn_inode_destroy(struct zn_inode *self); diff --git a/zen/meson.build b/zen/meson.build index 97a3a8ae..c7cf0d34 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -9,6 +9,7 @@ _zen_srcs = [ 'src/gl-shader.c', 'src/gl-texture.c', 'src/gl-vertex-array.c', + 'src/inode.c', 'src/screen.c', 'src/seat.c', 'src/server.c', diff --git a/zen/src/inode.c b/zen/src/inode.c new file mode 100644 index 00000000..8e53fc9a --- /dev/null +++ b/zen/src/inode.c @@ -0,0 +1,134 @@ +#include "zen/inode.h" + +#include +#include + +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +static void +zn_inode_noop_mapped(void *impl_data UNUSED) +{} + +static void +zn_inode_noop_unmapped(void *impl_data UNUSED) +{} + +const struct zn_inode_interface zn_inode_noop_implementation = { + .mapped = zn_inode_noop_mapped, + .unmapped = zn_inode_noop_unmapped, +}; + +static void +zn_inode_map_internal(struct zn_inode *self, bool mapped) +{ + if (self->mapped == mapped) { + return; + } + + struct zn_inode *child = NULL; + + wl_list_for_each (child, &self->child_list, link) { + zn_inode_map_internal(child, mapped); + } + + self->mapped = mapped; + + if (self->mapped) { + self->impl->mapped(self); + } else { + self->impl->unmapped(self); + } +} + +void +zn_inode_map(struct zn_inode *self) +{ + zn_assert(self->parent == NULL, "self must be root"); + + zn_inode_map_internal(self, true); +} + +void +zn_inode_unmap(struct zn_inode *self) +{ + zn_assert(self->parent == NULL, "self must be root"); + + zn_inode_map_internal(self, false); +} + +void +zn_inode_move(struct zn_inode *self, struct zn_inode *parent, vec3 position, + versor quaternion) +{ + glm_vec3_copy(position, self->position); + glm_quat_copy(quaternion, self->quaternion); + + if (self->parent) { + wl_list_remove(&self->parent_destroy_listener.link); + wl_list_init(&self->parent_destroy_listener.link); + wl_list_remove(&self->link); + wl_list_init(&self->link); + } + + self->parent = parent; + + if (self->parent) { + wl_signal_add( + &self->parent->events.destroy, &self->parent_destroy_listener); + wl_list_insert(&self->parent->child_list, &self->link); + } + + zn_inode_map_internal(self, parent && parent->mapped); +} + +static void +zn_inode_handle_parent_destroy(struct wl_listener *listener, void *data UNUSED) +{ + struct zn_inode *self = + zn_container_of(listener, self, parent_destroy_listener); + + zn_inode_move(self, NULL, self->position, self->quaternion); +} + +struct zn_inode * +zn_inode_create( + void *impl_data, const struct zn_inode_interface *implementation) +{ + struct zn_inode *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + self->impl = implementation; + glm_vec3_zero(self->position); + glm_quat_identity(self->quaternion); + self->parent = NULL; + wl_list_init(&self->link); + wl_list_init(&self->child_list); + self->mapped = false; + wl_signal_init(&self->events.destroy); + + self->parent_destroy_listener.notify = zn_inode_handle_parent_destroy; + wl_list_init(&self->parent_destroy_listener.link); + + return self; + +err: + return NULL; +} + +void +zn_inode_destroy(struct zn_inode *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + wl_list_remove(&self->parent_destroy_listener.link); + wl_list_remove(&self->child_list); + wl_list_remove(&self->link); + free(self); +} diff --git a/zen/tests/inode/inode-map.c b/zen/tests/inode/inode-map.c new file mode 100644 index 00000000..a7365ff4 --- /dev/null +++ b/zen/tests/inode/inode-map.c @@ -0,0 +1,142 @@ +#include +#include + +#include "test-harness.h" +#include "zen/inode.h" + +TEST(map) +{ + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + + struct zn_inode *n1 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n2 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n3 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n11 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n12 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n21 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n211 = zn_inode_create(NULL, &zn_inode_noop_implementation); + + zn_inode_move(n1, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n2, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n3, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n11, n1, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n12, n1, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n21, n2, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n211, n21, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + zn_inode_map(root); + + ASSERT_EQUAL_BOOL(true, root->mapped); + ASSERT_EQUAL_BOOL(true, n1->mapped); + ASSERT_EQUAL_BOOL(true, n2->mapped); + ASSERT_EQUAL_BOOL(true, n3->mapped); + ASSERT_EQUAL_BOOL(true, n11->mapped); + ASSERT_EQUAL_BOOL(true, n12->mapped); + ASSERT_EQUAL_BOOL(true, n21->mapped); + ASSERT_EQUAL_BOOL(true, n211->mapped); + + zn_inode_unmap(root); + + ASSERT_EQUAL_BOOL(false, root->mapped); + ASSERT_EQUAL_BOOL(false, n1->mapped); + ASSERT_EQUAL_BOOL(false, n2->mapped); + ASSERT_EQUAL_BOOL(false, n3->mapped); + ASSERT_EQUAL_BOOL(false, n11->mapped); + ASSERT_EQUAL_BOOL(false, n12->mapped); + ASSERT_EQUAL_BOOL(false, n21->mapped); + ASSERT_EQUAL_BOOL(false, n211->mapped); + + zn_inode_map(root); + + ASSERT_EQUAL_BOOL(true, root->mapped); + ASSERT_EQUAL_BOOL(true, n1->mapped); + ASSERT_EQUAL_BOOL(true, n2->mapped); + ASSERT_EQUAL_BOOL(true, n3->mapped); + ASSERT_EQUAL_BOOL(true, n11->mapped); + ASSERT_EQUAL_BOOL(true, n12->mapped); + ASSERT_EQUAL_BOOL(true, n21->mapped); + ASSERT_EQUAL_BOOL(true, n211->mapped); + + zn_inode_move(n1, NULL, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n2, NULL, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(true, root->mapped); + ASSERT_EQUAL_BOOL(false, n1->mapped); + ASSERT_EQUAL_BOOL(false, n2->mapped); + ASSERT_EQUAL_BOOL(true, n3->mapped); + ASSERT_EQUAL_BOOL(false, n11->mapped); + ASSERT_EQUAL_BOOL(false, n12->mapped); + ASSERT_EQUAL_BOOL(false, n21->mapped); + ASSERT_EQUAL_BOOL(false, n211->mapped); + + zn_inode_unmap(root); + zn_inode_move(n1, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(false, root->mapped); + ASSERT_EQUAL_BOOL(false, n1->mapped); + ASSERT_EQUAL_BOOL(false, n2->mapped); + ASSERT_EQUAL_BOOL(false, n3->mapped); + ASSERT_EQUAL_BOOL(false, n11->mapped); + ASSERT_EQUAL_BOOL(false, n12->mapped); + ASSERT_EQUAL_BOOL(false, n21->mapped); + ASSERT_EQUAL_BOOL(false, n211->mapped); + + zn_inode_map(root); + + ASSERT_EQUAL_BOOL(true, root->mapped); + ASSERT_EQUAL_BOOL(true, n1->mapped); + ASSERT_EQUAL_BOOL(false, n2->mapped); + ASSERT_EQUAL_BOOL(true, n3->mapped); + ASSERT_EQUAL_BOOL(true, n11->mapped); + ASSERT_EQUAL_BOOL(true, n12->mapped); + ASSERT_EQUAL_BOOL(false, n21->mapped); + ASSERT_EQUAL_BOOL(false, n211->mapped); + + zn_inode_move(n2, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(true, root->mapped); + ASSERT_EQUAL_BOOL(true, n1->mapped); + ASSERT_EQUAL_BOOL(true, n2->mapped); + ASSERT_EQUAL_BOOL(true, n3->mapped); + ASSERT_EQUAL_BOOL(true, n11->mapped); + ASSERT_EQUAL_BOOL(true, n12->mapped); + ASSERT_EQUAL_BOOL(true, n21->mapped); + ASSERT_EQUAL_BOOL(true, n211->mapped); +} + +FAIL_TEST(non_root_map) +{ + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(NULL, &zn_inode_noop_implementation); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + zn_inode_map(node); +} + +FAIL_TEST(non_root_unmap) +{ + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(NULL, &zn_inode_noop_implementation); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + zn_inode_unmap(node); +} + +TEST(destroy) +{ + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(NULL, &zn_inode_noop_implementation); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + zn_inode_map(root); + + ASSERT_EQUAL_BOOL(true, node->mapped); + + zn_inode_destroy(root); + + ASSERT_EQUAL_BOOL(false, node->mapped); + ASSERT_EQUAL_POINTER(NULL, node->parent); +} diff --git a/zen/tests/meson.build b/zen/tests/meson.build index e23a6bdb..69213f72 100644 --- a/zen/tests/meson.build +++ b/zen/tests/meson.build @@ -14,6 +14,7 @@ _zen_unit_tests = { }, }, 'config/config-path.c': {}, + 'inode/inode-map.c': {}, 'server/construct-destroy.c': {}, 'snode/snode-damage.c': {}, 'snode/snode-focus.c': {}, From d5471d7a40c0f4e65b7976a48a2aae1d86eae3dd Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 10 May 2023 23:50:35 +0900 Subject: [PATCH 32/49] inode move --- test-harness/include/test-harness.h | 3 ++ zen/include/zen/inode.h | 5 +++ zen/src/inode.c | 55 ++++++++++++++++++++++------- zen/tests/inode/inode-move.c | 42 ++++++++++++++++++++++ zen/tests/meson.build | 1 + 5 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 zen/tests/inode/inode-move.c diff --git a/test-harness/include/test-harness.h b/test-harness/include/test-harness.h index 8477f2d2..018659ac 100644 --- a/test-harness/include/test-harness.h +++ b/test-harness/include/test-harness.h @@ -80,3 +80,6 @@ void assert_equal_vec_(const char *actual_expression, const float *expected, #define ASSERT_EQUAL_VEC2(expected, actual) \ assert_equal_vec_(#actual, expected, actual, 2) + +#define ASSERT_EQUAL_VEC3(expected, actual) \ + assert_equal_vec_(#actual, expected, actual, 3) diff --git a/zen/include/zen/inode.h b/zen/include/zen/inode.h index 716bb9d2..4e8a33ff 100644 --- a/zen/include/zen/inode.h +++ b/zen/include/zen/inode.h @@ -6,6 +6,7 @@ struct zn_inode_interface { void (*mapped)(void *impl_data); void (*unmapped)(void *impl_data); + void (*moved)(void *impl_data); }; extern const struct zn_inode_interface zn_inode_noop_implementation; @@ -15,9 +16,13 @@ struct zn_inode { void *impl_data; // @nullable, @outlive const struct zn_inode_interface *impl; // @nonnull, @outlive + // local coords vec3 position; versor quaternion; + // root node local coords, affine matrix + mat4 transform_abs; + struct zn_inode *parent; // @nullable, @ref struct wl_list link; // zn_inode::child_list struct wl_list child_list; // zn_inode::link diff --git a/zen/src/inode.c b/zen/src/inode.c index 8e53fc9a..3026b2aa 100644 --- a/zen/src/inode.c +++ b/zen/src/inode.c @@ -15,9 +15,14 @@ static void zn_inode_noop_unmapped(void *impl_data UNUSED) {} +static void +zn_inode_noop_moved(void *impl_data UNUSED) +{} + const struct zn_inode_interface zn_inode_noop_implementation = { .mapped = zn_inode_noop_mapped, .unmapped = zn_inode_noop_unmapped, + .moved = zn_inode_noop_moved, }; static void @@ -58,6 +63,26 @@ zn_inode_unmap(struct zn_inode *self) zn_inode_map_internal(self, false); } +static void +zn_inode_update_position_recursive(struct zn_inode *self, mat4 parent_transform) +{ + mat4 transform; + glm_quat_mat4(self->quaternion, transform); + transform[3][0] = self->position[0]; + transform[3][1] = self->position[1]; + transform[3][2] = self->position[2]; + + glm_mul(parent_transform, transform, self->transform_abs); + + struct zn_inode *child = NULL; + + wl_list_for_each (child, &self->child_list, link) { + zn_inode_update_position_recursive(child, self->transform_abs); + } + + self->impl->moved(self); +} + void zn_inode_move(struct zn_inode *self, struct zn_inode *parent, vec3 position, versor quaternion) @@ -65,22 +90,27 @@ zn_inode_move(struct zn_inode *self, struct zn_inode *parent, vec3 position, glm_vec3_copy(position, self->position); glm_quat_copy(quaternion, self->quaternion); - if (self->parent) { - wl_list_remove(&self->parent_destroy_listener.link); - wl_list_init(&self->parent_destroy_listener.link); - wl_list_remove(&self->link); - wl_list_init(&self->link); - } + if (self->parent != parent) { + if (self->parent) { + wl_list_remove(&self->parent_destroy_listener.link); + wl_list_init(&self->parent_destroy_listener.link); + wl_list_remove(&self->link); + wl_list_init(&self->link); + } + + self->parent = parent; - self->parent = parent; + if (self->parent) { + wl_signal_add( + &self->parent->events.destroy, &self->parent_destroy_listener); + wl_list_insert(&self->parent->child_list, &self->link); + } - if (self->parent) { - wl_signal_add( - &self->parent->events.destroy, &self->parent_destroy_listener); - wl_list_insert(&self->parent->child_list, &self->link); + zn_inode_map_internal(self, parent && parent->mapped); } - zn_inode_map_internal(self, parent && parent->mapped); + zn_inode_update_position_recursive( + self, self->parent ? self->parent->transform_abs : GLM_MAT4_IDENTITY); } static void @@ -106,6 +136,7 @@ zn_inode_create( self->impl = implementation; glm_vec3_zero(self->position); glm_quat_identity(self->quaternion); + glm_mat4_identity(self->transform_abs); self->parent = NULL; wl_list_init(&self->link); wl_list_init(&self->child_list); diff --git a/zen/tests/inode/inode-move.c b/zen/tests/inode/inode-move.c new file mode 100644 index 00000000..e564aea1 --- /dev/null +++ b/zen/tests/inode/inode-move.c @@ -0,0 +1,42 @@ +#include +#include + +#include "test-harness.h" +#include "zen/inode.h" + +TEST(general) +{ + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + + struct zn_inode *n1 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n2 = zn_inode_create(NULL, &zn_inode_noop_implementation); + + versor x90; + versor y90; + versor z90; + + glm_quat(x90, GLM_PI_2f, 1, 0, 0); + glm_quat(y90, GLM_PI_2f, 0, 1, 0); + glm_quat(z90, GLM_PI_2f, 0, 0, 1); + + zn_inode_move(root, NULL, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n1, root, (vec3){20, 30, 40}, y90); + zn_inode_move(n2, n1, (vec3){30, 40, 50}, z90); + + vec3 local = {1, 0, 0}; + vec3 global; + + glm_mat4_mulv3(n1->transform_abs, local, 1, global); + + ASSERT_EQUAL_VEC3(((vec3){20, 30, 39}), global); + + zn_inode_move(root, NULL, (vec3){10, 20, 30}, x90); + + glm_mat4_mulv3(n1->transform_abs, local, 1, global); + + ASSERT_EQUAL_VEC3(((vec3){30, -19, 60}), global); + + glm_mat4_mulv3(n2->transform_abs, local, 1, global); + + ASSERT_EQUAL_VEC3(((vec3){80, 10, 101}), global); +} diff --git a/zen/tests/meson.build b/zen/tests/meson.build index 69213f72..a407f5e9 100644 --- a/zen/tests/meson.build +++ b/zen/tests/meson.build @@ -15,6 +15,7 @@ _zen_unit_tests = { }, 'config/config-path.c': {}, 'inode/inode-map.c': {}, + 'inode/inode-move.c': {}, 'server/construct-destroy.c': {}, 'snode/snode-damage.c': {}, 'snode/snode-focus.c': {}, From dc29a74bec51fe99d369fc2192d7893bcdc9a4d5 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Thu, 11 May 2023 23:48:15 +0900 Subject: [PATCH 33/49] gl_rendering_unit.change_visibility --- zen/include/zen/gl-rendering-unit.h | 18 +++++++++++++++++- zen/include/zen/inode.h | 6 ++++++ .../immersive/gl/client-gl-rendering-unit.c | 16 ++++++++++++++++ .../immersive/remote/gl-rendering-unit.cc | 15 ++++++++++++++- .../immersive/remote/gl-rendering-unit.h | 4 ++++ zen/src/gl-rendering-unit-private.h | 3 ++- zen/src/gl-rendering-unit.c | 4 +++- zen/src/inode.c | 6 +++--- 8 files changed, 65 insertions(+), 7 deletions(-) diff --git a/zen/include/zen/gl-rendering-unit.h b/zen/include/zen/gl-rendering-unit.h index b754e62e..d3a583f9 100644 --- a/zen/include/zen/gl-rendering-unit.h +++ b/zen/include/zen/gl-rendering-unit.h @@ -2,18 +2,34 @@ #include +#include "zen-common/util.h" + #ifdef __cplusplus extern "C" { #endif +struct zn_gl_rendering_unit; + +struct zn_gl_rendering_unit_interface { + void (*change_visibility)(struct zn_gl_rendering_unit *self, bool visible); +}; + struct zn_gl_rendering_unit { - void *impl_data; // @nullable, @outlive + void *impl_data; // @nullable, @outlive + const struct zn_gl_rendering_unit_interface *impl; // @nonnull, @outlive struct { struct wl_signal destroy; // (NULL) } events; }; +UNUSED static inline void +zn_gl_rendering_unit_change_visibility( + struct zn_gl_rendering_unit *self, bool visible) +{ + self->impl->change_visibility(self, visible); +} + #ifdef __cplusplus } #endif diff --git a/zen/include/zen/inode.h b/zen/include/zen/inode.h index 4e8a33ff..6db39dc2 100644 --- a/zen/include/zen/inode.h +++ b/zen/include/zen/inode.h @@ -9,6 +9,12 @@ struct zn_inode_interface { void (*moved)(void *impl_data); }; +void zn_inode_noop_mapped(void *impl_data); + +void zn_inode_noop_unmapped(void *impl_data); + +void zn_inode_noop_moved(void *impl_data); + extern const struct zn_inode_interface zn_inode_noop_implementation; /// inode is a root node when self->parent == NULL diff --git a/zen/src/backend/immersive/gl/client-gl-rendering-unit.c b/zen/src/backend/immersive/gl/client-gl-rendering-unit.c index 55bd2277..4a2e5ba8 100644 --- a/zen/src/backend/immersive/gl/client-gl-rendering-unit.c +++ b/zen/src/backend/immersive/gl/client-gl-rendering-unit.c @@ -29,8 +29,24 @@ zn_client_gl_rendering_unit_protocol_destroy( wl_resource_destroy(resource); } +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_client_gl_rendering_unit_protocol_change_visibility( + struct wl_client *client UNUSED, struct wl_resource *resource, + uint32_t visible) +{ + struct zn_client_gl_rendering_unit *self = + wl_resource_get_user_data(resource); + if (self == NULL) { + return; + } + + zn_gl_rendering_unit_change_visibility(self->zn_gl_rendering_unit, visible); +} + static const struct zwn_gl_rendering_unit_interface implementation = { .destroy = zn_client_gl_rendering_unit_protocol_destroy, + .change_visibility = zn_client_gl_rendering_unit_protocol_change_visibility, }; struct zn_client_gl_rendering_unit * diff --git a/zen/src/backend/immersive/remote/gl-rendering-unit.cc b/zen/src/backend/immersive/remote/gl-rendering-unit.cc index 08eee156..415b3c8b 100644 --- a/zen/src/backend/immersive/remote/gl-rendering-unit.cc +++ b/zen/src/backend/immersive/remote/gl-rendering-unit.cc @@ -5,6 +5,10 @@ namespace zen::backend::immersive::remote { +const zn_gl_rendering_unit_interface GlRenderingUnit::c_implementation_ = { + GlRenderingUnit::HandleChangeVisibility, +}; + GlRenderingUnit::~GlRenderingUnit() { if (c_obj_ != nullptr) { @@ -34,7 +38,7 @@ bool GlRenderingUnit::Init(std::shared_ptr channel, std::unique_ptr &virtual_object) { - c_obj_ = zn_gl_rendering_unit_create(this); + c_obj_ = zn_gl_rendering_unit_create(this, &c_implementation_); if (c_obj_ == nullptr) { zn_error("Failed to create a zn_gl_rendering_unit"); return false; @@ -52,4 +56,13 @@ GlRenderingUnit::Init(std::shared_ptr channel, return true; } +void +GlRenderingUnit::HandleChangeVisibility( + zn_gl_rendering_unit *c_obj, bool visible) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->ChangeVisibility(visible); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-rendering-unit.h b/zen/src/backend/immersive/remote/gl-rendering-unit.h index 1b8d41cf..7af90c48 100644 --- a/zen/src/backend/immersive/remote/gl-rendering-unit.h +++ b/zen/src/backend/immersive/remote/gl-rendering-unit.h @@ -26,8 +26,12 @@ class GlRenderingUnit bool Init(std::shared_ptr channel, std::unique_ptr &virtual_object); + static void HandleChangeVisibility(zn_gl_rendering_unit *c_obj, bool visible); + std::unique_ptr remote_obj_; + static const zn_gl_rendering_unit_interface c_implementation_; + zn_gl_rendering_unit *c_obj_ = nullptr; // @nonnull after Init(), @owning }; diff --git a/zen/src/gl-rendering-unit-private.h b/zen/src/gl-rendering-unit-private.h index 7647bf03..298f53a8 100644 --- a/zen/src/gl-rendering-unit-private.h +++ b/zen/src/gl-rendering-unit-private.h @@ -7,7 +7,8 @@ extern "C" { #endif /// Called by impl object -struct zn_gl_rendering_unit *zn_gl_rendering_unit_create(void *impl_data); +struct zn_gl_rendering_unit *zn_gl_rendering_unit_create(void *impl_data, + const struct zn_gl_rendering_unit_interface *implementation); /// Called by impl object void zn_gl_rendering_unit_destroy(struct zn_gl_rendering_unit *self); diff --git a/zen/src/gl-rendering-unit.c b/zen/src/gl-rendering-unit.c index d1a292f5..ed4f957c 100644 --- a/zen/src/gl-rendering-unit.c +++ b/zen/src/gl-rendering-unit.c @@ -4,7 +4,8 @@ #include "zen-common/util.h" struct zn_gl_rendering_unit * -zn_gl_rendering_unit_create(void *impl_data) +zn_gl_rendering_unit_create(void *impl_data, + const struct zn_gl_rendering_unit_interface *implementation) { struct zn_gl_rendering_unit *self = zalloc(sizeof *self); if (self == NULL) { @@ -13,6 +14,7 @@ zn_gl_rendering_unit_create(void *impl_data) } self->impl_data = impl_data; + self->impl = implementation; wl_signal_init(&self->events.destroy); return self; diff --git a/zen/src/inode.c b/zen/src/inode.c index 3026b2aa..d4813536 100644 --- a/zen/src/inode.c +++ b/zen/src/inode.c @@ -7,15 +7,15 @@ #include "zen-common/signal.h" #include "zen-common/util.h" -static void +void zn_inode_noop_mapped(void *impl_data UNUSED) {} -static void +void zn_inode_noop_unmapped(void *impl_data UNUSED) {} -static void +void zn_inode_noop_moved(void *impl_data UNUSED) {} From bec1f7ff152c339e0487ccb8315fd702bc68fd17 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 14 May 2023 20:10:10 +0900 Subject: [PATCH 34/49] virtual_object.change_visibility --- desktop/include/zen-desktop/shell.h | 1 + desktop/src/shell.c | 16 ++++++++++++++++ zen/include/zen/virtual-object.h | 8 ++++++++ .../backend/immersive/client-virtual-object.c | 6 ++++++ .../backend/immersive/remote/virtual-object.cc | 9 +++++++++ .../backend/immersive/remote/virtual-object.h | 2 ++ zen/src/backend/immersive/shell/bounded.c | 16 +++++++++++----- 7 files changed, 53 insertions(+), 5 deletions(-) diff --git a/desktop/include/zen-desktop/shell.h b/desktop/include/zen-desktop/shell.h index cfd2fc5b..8934eaff 100644 --- a/desktop/include/zen-desktop/shell.h +++ b/desktop/include/zen-desktop/shell.h @@ -20,6 +20,7 @@ struct zn_desktop_shell { struct wl_listener pointer_axis_listener; struct wl_listener pointer_frame_listener; struct wl_listener view_mapped_listener; + struct wl_listener bounded_mapped_listener; }; /// Ownership of `grab` moves to `self` diff --git a/desktop/src/shell.c b/desktop/src/shell.c index e0ca9319..61515b10 100644 --- a/desktop/src/shell.c +++ b/desktop/src/shell.c @@ -12,11 +12,13 @@ #include "zen-desktop/view.h" #include "zen-desktop/xr-system.h" #include "zen/backend.h" +#include "zen/bounded.h" #include "zen/screen.h" #include "zen/seat.h" #include "zen/server.h" #include "zen/snode.h" #include "zen/view.h" +#include "zen/virtual-object.h" // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static struct zn_desktop_shell *desktop_shell_singleton = NULL; @@ -61,6 +63,15 @@ zn_desktop_shell_handle_view_mapped(struct wl_listener *listener, void *data) } } +static void +zn_desktop_shell_handle_bounded_mapped( + struct wl_listener *listener UNUSED, void *data) +{ + struct zn_bounded *bounded = data; + + zn_virtual_object_change_visibility(bounded->virtual_object, true); +} + static void zn_desktop_shell_handle_seat_capabilities( struct wl_listener *listener UNUSED, void *data) @@ -219,6 +230,10 @@ zn_desktop_shell_create(void) wl_signal_add( &server->backend->events.view_mapped, &self->view_mapped_listener); + self->bounded_mapped_listener.notify = zn_desktop_shell_handle_bounded_mapped; + wl_signal_add( + &server->backend->events.bounded_mapped, &self->bounded_mapped_listener); + return self; err_screen_layout: @@ -238,6 +253,7 @@ zn_desktop_shell_create(void) void zn_desktop_shell_destroy(struct zn_desktop_shell *self) { + wl_list_remove(&self->bounded_mapped_listener.link); wl_list_remove(&self->view_mapped_listener.link); wl_list_remove(&self->pointer_frame_listener.link); wl_list_remove(&self->pointer_axis_listener.link); diff --git a/zen/include/zen/virtual-object.h b/zen/include/zen/virtual-object.h index 1c27a727..4ddec4ca 100644 --- a/zen/include/zen/virtual-object.h +++ b/zen/include/zen/virtual-object.h @@ -18,6 +18,7 @@ enum zn_virtual_object_role { struct zn_virtual_object_interface { void (*committed)(struct zn_virtual_object *self); + void (*change_visibility)(struct zn_virtual_object *self, bool visible); }; struct zn_virtual_object { @@ -40,6 +41,13 @@ struct zn_virtual_object { void zn_virtual_object_commit(struct zn_virtual_object *self); +UNUSED static inline void +zn_virtual_object_change_visibility( + struct zn_virtual_object *self, bool visible) +{ + self->impl->change_visibility(self, visible); +} + /// @return true if successful, false otherwise bool zn_virtual_object_set_role(struct zn_virtual_object *self, enum zn_virtual_object_role role, void *role_object); diff --git a/zen/src/backend/immersive/client-virtual-object.c b/zen/src/backend/immersive/client-virtual-object.c index 0e0249be..ec3a6af0 100644 --- a/zen/src/backend/immersive/client-virtual-object.c +++ b/zen/src/backend/immersive/client-virtual-object.c @@ -17,6 +17,12 @@ zn_client_virtual_object_handle_destroy(struct wl_resource *resource) struct zn_client_virtual_object *self = zn_client_virtual_object_get(resource); + if (self->zn_virtual_object->role_object != NULL) { + wl_resource_post_error(self->resource, + ZWN_VIRTUAL_OBJECT_ERROR_DEFUNCT_ROLE_OBJECT, + "Virtual object is destroyed before its role object"); + } + zn_client_virtual_object_destroy(self); } diff --git a/zen/src/backend/immersive/remote/virtual-object.cc b/zen/src/backend/immersive/remote/virtual-object.cc index 7b853fdc..2d0927e5 100644 --- a/zen/src/backend/immersive/remote/virtual-object.cc +++ b/zen/src/backend/immersive/remote/virtual-object.cc @@ -6,6 +6,7 @@ namespace zen::backend::immersive::remote { const zn_virtual_object_interface VirtualObject::c_implementation_ = { VirtualObject::HandleCommitted, + VirtualObject::HandleChangeVisibility, }; VirtualObject::~VirtualObject() @@ -60,4 +61,12 @@ VirtualObject::HandleCommitted(zn_virtual_object *c_obj) self->remote_obj_->Commit(); } +void +VirtualObject::HandleChangeVisibility(zn_virtual_object *c_obj, bool visible) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->ChangeVisibility(visible); +} + } // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/virtual-object.h b/zen/src/backend/immersive/remote/virtual-object.h index 1b71ec78..2577f8d9 100644 --- a/zen/src/backend/immersive/remote/virtual-object.h +++ b/zen/src/backend/immersive/remote/virtual-object.h @@ -24,6 +24,8 @@ class VirtualObject static void HandleCommitted(zn_virtual_object *c_obj); + static void HandleChangeVisibility(zn_virtual_object *c_obj, bool visible); + std::unique_ptr remote_obj_; static const zn_virtual_object_interface c_implementation_; diff --git a/zen/src/backend/immersive/shell/bounded.c b/zen/src/backend/immersive/shell/bounded.c index de3e342b..85c979d8 100644 --- a/zen/src/backend/immersive/shell/bounded.c +++ b/zen/src/backend/immersive/shell/bounded.c @@ -75,6 +75,7 @@ zn_bounded_handle_destroy(struct wl_resource *resource) zn_bounded_destroy(self); } +/// @param resource can be inert (resource->user_data == NULL) static void zn_bounded_protocol_destroy( struct wl_client *client UNUSED, struct wl_resource *resource) @@ -82,12 +83,17 @@ zn_bounded_protocol_destroy( wl_resource_destroy(resource); } +/// @param resource can be inert (resource->user_data == NULL) static void zn_bounded_protocol_ack_configure(struct wl_client *client UNUSED, struct wl_resource *resource, struct wl_array *half_size_array, uint32_t serial) { struct zn_bounded *self = wl_resource_get_user_data(resource); + if (self == NULL) { + return; + } + vec3 half_size; if (!zn_wl_array_to_vec3(half_size_array, half_size)) { @@ -130,16 +136,19 @@ zn_bounded_protocol_ack_configure(struct wl_client *client UNUSED, zn_bounded_configure_destroy(configure); } +/// @param resource can be inert (resource->user_data == NULL) static void zn_bounded_protocol_set_title(struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, const char *title UNUSED) {} +/// @param resource can be inert (resource->user_data == NULL) static void zn_bounded_protocol_set_input_region(struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, struct wl_resource *region UNUSED) {} +/// @param resource can be inert (resource->user_data == NULL) static void zn_bounded_protocol_move(struct wl_client *client UNUSED, struct wl_resource *resource UNUSED, struct wl_resource *seat UNUSED, @@ -161,11 +170,7 @@ zn_bounded_handle_virtual_object_destroy( struct zn_bounded *self = zn_container_of(listener, self, virtual_object_destroy_listener); - wl_resource_post_error(self->resource, - ZWN_VIRTUAL_OBJECT_ERROR_DEFUNCT_ROLE_OBJECT, - "Virtual object is destroyed before its role object (zwn_bounded)"); - - wl_resource_destroy(self->resource); + zn_bounded_destroy(self); } static void @@ -260,5 +265,6 @@ zn_bounded_destroy(struct zn_bounded *self) wl_list_remove(&self->events.destroy.listener_list); wl_list_remove(&self->virtual_object_destroy_listener.link); wl_list_remove(&self->commit_listener.link); + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); free(self); } From 8ba72f0a190abb63e0bf8c446265f14d3612f6de Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 8 Jul 2023 19:48:03 +0900 Subject: [PATCH 35/49] fix test --- zen/tests/mock/src/backend.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zen/tests/mock/src/backend.c b/zen/tests/mock/src/backend.c index 504f1170..dbd0147d 100644 --- a/zen/tests/mock/src/backend.c +++ b/zen/tests/mock/src/backend.c @@ -68,6 +68,7 @@ zn_mock_backend_create(void) wl_signal_init(&self->base.events.view_mapped); wl_signal_init(&self->base.events.destroy); wl_signal_init(&self->base.events.new_xr_system); + wl_signal_init(&self->base.events.bounded_mapped); return self; } From bfab3ddc0195feb86c6f816d27215645a7580743 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 8 Jul 2023 20:17:09 +0900 Subject: [PATCH 36/49] binding --- desktop/main.c | 14 +- desktop/tests/screen-layout/setup.h | 6 +- zen/include/zen/binding.h | 36 ++++ zen/include/zen/config.h | 32 +--- zen/include/zen/server.h | 8 +- zen/meson.build | 1 + zen/src/backend/screen/keyboard.c | 15 +- zen/src/binding.c | 209 +++++++++++++++++++++ zen/src/config.c | 64 ++----- zen/src/server.c | 20 +- zen/tests/binding.c | 89 +++++++++ zen/tests/config/config-section.c | 137 ++------------ zen/tests/meson.build | 5 + zen/tests/server/construct-destroy.c | 5 +- zen/tests/testdata/zen-desktop/config.toml | 4 + 15 files changed, 429 insertions(+), 216 deletions(-) create mode 100644 zen/include/zen/binding.h create mode 100644 zen/src/binding.c create mode 100644 zen/tests/binding.c diff --git a/desktop/main.c b/desktop/main.c index c549359a..00dc79f8 100644 --- a/desktop/main.c +++ b/desktop/main.c @@ -9,6 +9,7 @@ #include "zen-common/terminate.h" #include "zen-common/util.h" #include "zen-desktop/shell.h" +#include "zen/config.h" #include "zen/include/zen/server.h" static void @@ -76,10 +77,16 @@ main(int argc UNUSED, const char *argv[] UNUSED) goto err_signal; } - struct zn_server *server = zn_server_create(display, NULL); + struct zn_config *config = zn_config_create(); + if (config == NULL) { + zn_error("Failed to create a zn_config"); + goto err_signal; + } + + struct zn_server *server = zn_server_create(display, NULL, config); if (server == NULL) { zn_error("Failed to create a zn_server"); - goto err_signal; + goto err_config; } struct zn_desktop_shell *shell = zn_desktop_shell_create(); @@ -95,6 +102,9 @@ main(int argc UNUSED, const char *argv[] UNUSED) err_server: zn_server_destroy(server); +err_config: + zn_config_destroy(config); + err_signal: for (int i = ARRAY_LENGTH(signal_sources) - 1; i >= 0; i--) { if (signal_sources[i]) { diff --git a/desktop/tests/screen-layout/setup.h b/desktop/tests/screen-layout/setup.h index 460d294b..8cf2fc4e 100644 --- a/desktop/tests/screen-layout/setup.h +++ b/desktop/tests/screen-layout/setup.h @@ -4,13 +4,15 @@ #include "mock/output.h" #include "zen-common/util.h" #include "zen-desktop/shell.h" +#include "zen/config.h" #include "zen/server.h" UNUSED static void setup(struct wl_display *display) { struct zn_mock_backend *backend = zn_mock_backend_create(); - zn_server_create(display, &backend->base); + struct zn_config *config = zn_config_create(); + zn_server_create(display, &backend->base, config); zn_desktop_shell_create(); } @@ -19,6 +21,8 @@ teardown(void) { struct zn_server *server = zn_server_get_singleton(); struct zn_desktop_shell *shell = zn_desktop_shell_get_singleton(); + struct zn_config *config = server->config; zn_desktop_shell_destroy(shell); zn_server_destroy(server); + zn_config_destroy(config); } diff --git a/zen/include/zen/binding.h b/zen/include/zen/binding.h new file mode 100644 index 00000000..cee9eb9a --- /dev/null +++ b/zen/include/zen/binding.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "zen/config.h" + +/// @return true if the key is used and should not be used any more +typedef bool (*zn_binding_handler_t)( + const char *name, uint32_t key, uint32_t modifiers, void *user_data); + +struct zn_binding_item { + const char *name; // @nonnull, @outlive + uint32_t key; + uint32_t modifiers; + zn_binding_handler_t handler; // nonnull + void *user_data; +}; + +struct zn_binding { + struct wl_array items; // [zn_binding_item] +}; + +/// @param name must be a string literal +void zn_binding_add(struct zn_binding *self, const char *name, + zn_binding_handler_t handler, void *user_data); + +/// @return true if the key is used and should not be used any more +/// @param modifiers is a bitfield of enum wlr_keyboard_modifier +bool zn_binding_handle_key( + struct zn_binding *self, uint32_t key, uint32_t modifiers); + +void zn_binding_remap(struct zn_binding *self); + +struct zn_binding *zn_binding_create(void); + +void zn_binding_destroy(struct zn_binding *self); diff --git a/zen/include/zen/config.h b/zen/include/zen/config.h index 5edd58fe..6664f504 100644 --- a/zen/include/zen/config.h +++ b/zen/include/zen/config.h @@ -4,34 +4,16 @@ #include #include -struct zn_config_section { - /// This must be called once in zn_config_add_section - /// @param table is nullable - /// @return true if successful, false otherwise - bool (*load)(struct zn_config_section *self, toml_table_t *table); - - /// This must be called once when zn_config_destroy - void (*destroy)(struct zn_config_section *self); -}; - -struct zn_config_section_info { - char *name; // @nonnull, @owning - struct zn_config_section *section; // @nonnull, @owning -}; - struct zn_config { - toml_table_t *root_table; // @nullable, @owning - struct wl_array sections; // [struct zn_config_section_info] + toml_table_t *root_table; // @nullable, @owning + struct wl_array reserved_sections; // [const char *] }; -/// @returns true if successful, false otherwise -/// @param section's ownership will be moved to the zn_config -bool zn_config_add_section(struct zn_config *self, const char *name, - struct zn_config_section *section); - -/// @return value is nullable -struct zn_config_section *zn_config_get_section( - struct zn_config *self, const char *name); +/// @returns true if no other component has been reserved the section yet. +/// +/// This doesn't check if the section exist or not +bool zn_config_reserve_section( + struct zn_config *self, const char *section_name); struct zn_config *zn_config_create(void); diff --git a/zen/include/zen/server.h b/zen/include/zen/server.h index 58ae2825..981f629e 100644 --- a/zen/include/zen/server.h +++ b/zen/include/zen/server.h @@ -5,12 +5,15 @@ struct zn_backend; struct zn_seat; +struct zn_binding; struct zn_server { struct wl_display *display; // @nonnull, @outlive struct zn_backend *backend; // @nonnull, @owning struct zn_seat *seat; // @nonnull, @owning + struct zn_binding *binding; // @nonnull, @owning + struct zn_config *config; // @nonnull, @outlive bool running; int exit_status; @@ -29,7 +32,8 @@ int zn_server_run(struct zn_server *self); void zn_server_terminate(struct zn_server *self, int exit_status); /// @param backend is nullable, ownership will be moved -struct zn_server *zn_server_create( - struct wl_display *display, struct zn_backend *backend); +/// @param config must not be null +struct zn_server *zn_server_create(struct wl_display *display, + struct zn_backend *backend, struct zn_config *config); void zn_server_destroy(struct zn_server *self); diff --git a/zen/meson.build b/zen/meson.build index c7cf0d34..3042030f 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -1,4 +1,5 @@ _zen_srcs = [ + 'src/binding.c', 'src/buffer.c', 'src/config.c', 'src/cursor.c', diff --git a/zen/src/backend/screen/keyboard.c b/zen/src/backend/screen/keyboard.c index 098b0367..c9881ea5 100644 --- a/zen/src/backend/screen/keyboard.c +++ b/zen/src/backend/screen/keyboard.c @@ -9,6 +9,7 @@ #include "zen-common/log.h" #include "zen-common/terminate.h" #include "zen-common/util.h" +#include "zen/binding.h" #include "zen/seat.h" #include "zen/server.h" @@ -32,8 +33,6 @@ zn_keyboard_handle_keyboard_key(struct wl_listener *listener, void *user_data) struct wlr_event_keyboard_key *event = user_data; struct zn_server *server = zn_server_get_singleton(); - // TODO(@Aki-7): Handle keyboard bindings - // TODO(@Aki-7): For the development convenience, fix this later if (wlr_keyboard_get_modifiers(self->base.wlr_input_device->keyboard) == WLR_MODIFIER_ALT && @@ -43,8 +42,16 @@ zn_keyboard_handle_keyboard_key(struct wl_listener *listener, void *user_data) } wlr_seat_set_keyboard(server->seat->wlr_seat, self->base.wlr_input_device); - wlr_seat_keyboard_send_key( - server->seat->wlr_seat, event->time_msec, event->keycode, event->state); + + uint32_t modifiers = wlr_keyboard_get_modifiers( + server->seat->wlr_seat->keyboard_state.keyboard); + bool handled = + zn_binding_handle_key(server->binding, event->keycode, modifiers); + + if (!handled) { + wlr_seat_keyboard_send_key( + server->seat->wlr_seat, event->time_msec, event->keycode, event->state); + } } static void diff --git a/zen/src/binding.c b/zen/src/binding.c new file mode 100644 index 00000000..0e5418d5 --- /dev/null +++ b/zen/src/binding.c @@ -0,0 +1,209 @@ +#include "zen/binding.h" + +#include +#include + +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/server.h" + +#define CONFIG_SECTION_KEY "binding" + +#define TOKEN_SHIFT "shift" +#define TOKEN_CTRL "ctrl" +#define TOKEN_ALT "alt" +#define TOKEN_LOGO "logo" +#define TOKEN_RIGHT "right" +#define TOKEN_LEFT "left" +#define TOKEN_UP "up" +#define TOKEN_DOWN "down" +#define TOKEN_SEPARATOR '+' + +static const uint32_t ascii_to_keycode[] = { + ['a'] = KEY_A, + ['b'] = KEY_B, + ['c'] = KEY_C, + ['d'] = KEY_D, + ['e'] = KEY_E, + ['f'] = KEY_F, + ['g'] = KEY_G, + ['h'] = KEY_H, + ['i'] = KEY_I, + ['j'] = KEY_J, + ['k'] = KEY_K, + ['l'] = KEY_L, + ['m'] = KEY_M, + ['n'] = KEY_N, + ['o'] = KEY_O, + ['p'] = KEY_P, + ['q'] = KEY_Q, + ['r'] = KEY_R, + ['s'] = KEY_S, + ['t'] = KEY_T, + ['u'] = KEY_U, + ['v'] = KEY_V, + ['w'] = KEY_W, + ['x'] = KEY_X, + ['y'] = KEY_Y, + ['z'] = KEY_Z, + ['0'] = KEY_0, + ['1'] = KEY_1, + ['2'] = KEY_2, + ['3'] = KEY_3, + ['4'] = KEY_4, + ['5'] = KEY_5, + ['6'] = KEY_6, + ['7'] = KEY_7, + ['8'] = KEY_8, + ['9'] = KEY_9, +}; + +void +zn_binding_add(struct zn_binding *self, const char *name, + zn_binding_handler_t handler, void *user_data) +{ + struct zn_binding_item *item = NULL; + + wl_array_for_each (item, &self->items) { + if (strcmp(name, item->name) == 0) { + zn_warn("Binding name is duplicated (%s). Skipping.", name); + return; + } + } + + item = wl_array_add(&self->items, sizeof *item); + item->name = name; + item->handler = handler; + item->key = 0; + item->modifiers = 0; + item->user_data = user_data; +} + +bool +zn_binding_handle_key(struct zn_binding *self, uint32_t key, uint32_t modifiers) +{ + struct zn_binding_item *item = NULL; + + wl_array_for_each (item, &self->items) { + bool matches = item->key == key && item->modifiers == modifiers; + + if (!matches) { + continue; + } + + if (item->handler(item->name, key, modifiers, item->user_data)) { + return true; + } + } + + return false; +} + +static int +find_next_separator(const char *string, char separator) +{ + for (int i = 0;; i++) { + if (string[i] == separator || string[i] == '\0') { + return i; + } + } + + assert(false && "Unreachable"); +} + +static void +zn_binding_item_reconfigure(struct zn_binding_item *item, char *description) +{ + char *current = description; + while (true) { + int length = find_next_separator(current, TOKEN_SEPARATOR); + if (length <= 0) { + break; + } + + if (strncmp(current, TOKEN_SHIFT, length) == 0) { + item->modifiers |= WLR_MODIFIER_SHIFT; + } else if (strncmp(current, TOKEN_CTRL, length) == 0) { + item->modifiers |= WLR_MODIFIER_CTRL; + } else if (strncmp(current, TOKEN_ALT, length) == 0) { + item->modifiers |= WLR_MODIFIER_ALT; + } else if (strncmp(current, TOKEN_LOGO, length) == 0) { + item->modifiers |= WLR_MODIFIER_LOGO; + } else if (strncmp(current, TOKEN_RIGHT, length) == 0) { + item->key = KEY_RIGHT; + } else if (strncmp(current, TOKEN_LEFT, length) == 0) { + item->key = KEY_LEFT; + } else if (strncmp(current, TOKEN_UP, length) == 0) { + item->key = KEY_UP; + } else if (strncmp(current, TOKEN_DOWN, length) == 0) { + item->key = KEY_DOWN; + } else if (length == 1) { + char key = current[0]; + if (('0' <= key && key <= '9') || ('a' <= key && key <= 'z')) { + item->key = ascii_to_keycode[(int)key]; + } + } + + if (current[length] == '\0') { + break; + } + + current += length + 1; + } +} + +void +zn_binding_remap(struct zn_binding *self) +{ + struct zn_server *server = zn_server_get_singleton(); + + toml_table_t *table = NULL; + if (server->config->root_table) { + table = toml_table_in(server->config->root_table, CONFIG_SECTION_KEY); + } + + if (table == NULL) { + return; + } + + struct zn_binding_item *item = NULL; + + // TODO(@Aki-7): Refactor implementing lexer for more flexibility + // TODO(@Aki-7): Enable to add multiple key bindings to one command + wl_array_for_each (item, &self->items) { + toml_datum_t data = toml_string_in(table, item->name); + if (!data.ok) { + continue; + } + + zn_binding_item_reconfigure(item, data.u.s); + } +} + +struct zn_binding * +zn_binding_create(void) +{ + struct zn_server *server = zn_server_get_singleton(); + + struct zn_binding *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + wl_array_init(&self->items); + + zn_config_reserve_section(server->config, CONFIG_SECTION_KEY); + + return self; + +err: + return NULL; +} + +void +zn_binding_destroy(struct zn_binding *self) +{ + wl_array_release(&self->items); + free(self); +} diff --git a/zen/src/config.c b/zen/src/config.c index 9fc223c7..00d7a4bc 100644 --- a/zen/src/config.c +++ b/zen/src/config.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -87,59 +86,24 @@ get_config_toml_table(void) } bool -zn_config_add_section( - struct zn_config *self, const char *name, struct zn_config_section *section) +zn_config_reserve_section(struct zn_config *self, const char *section_name) { - struct zn_config_section_info *info = NULL; - wl_array_for_each (info, &self->sections) { - if (strcmp(info->name, name) == 0) { - zn_error("Config section %s is used by two or more modules", name); + const char **name = NULL; + + wl_array_for_each (name, &self->reserved_sections) { + if (strcmp(*name, section_name) == 0) { + zn_warn( + "Section name '%s' has been reserved by another component", *name); return false; } } - toml_table_t *table = NULL; - if (self->root_table) { - table = toml_table_in(self->root_table, name); - } - - if (!section->load(section, table)) { - zn_error("Failed to load '%s' config section", name); - return false; - } - - char *name_copy = strdup(name); - if (name_copy == NULL) { - zn_error("Failed to strdup"); - return false; - } - - info = wl_array_add(&self->sections, sizeof(*info)); - if (info == NULL) { - zn_error("Failed to allocate memory"); - free(name_copy); - return false; - } - - info->name = name_copy; - info->section = section; + name = wl_array_add(&self->reserved_sections, sizeof *name); + *name = section_name; return true; } -struct zn_config_section * -zn_config_get_section(struct zn_config *self, const char *name) -{ - struct zn_config_section_info *info = NULL; - wl_array_for_each (info, &self->sections) { - if (strcmp(info->name, name) == 0) { - return info->section; - } - } - - return NULL; -} - struct zn_config * zn_config_create(void) { @@ -150,7 +114,7 @@ zn_config_create(void) } self->root_table = get_config_toml_table(); - wl_array_init(&self->sections); + wl_array_init(&self->reserved_sections); return self; @@ -165,12 +129,6 @@ zn_config_destroy(struct zn_config *self) toml_free(self->root_table); } - struct zn_config_section_info *info = NULL; - wl_array_for_each (info, &self->sections) { - free(info->name); - info->section->destroy(info->section); - } - - wl_array_release(&self->sections); + wl_array_release(&self->reserved_sections); free(self); } diff --git a/zen/src/server.c b/zen/src/server.c index 0a40835d..a5ebaf68 100644 --- a/zen/src/server.c +++ b/zen/src/server.c @@ -10,6 +10,8 @@ #include "zen-common/log.h" #include "zen-common/util.h" #include "zen/backend.h" +#include "zen/binding.h" +#include "zen/config.h" // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static struct zn_server *server_singleton = NULL; @@ -37,6 +39,8 @@ zn_server_run(struct zn_server *self) return self->exit_status; } + zn_binding_remap(self->binding); + wl_display_run(self->display); if (!zn_assert(!self->running, "Not terminated with zn_server_terminate")) { @@ -91,7 +95,8 @@ handle_wlr_log( } struct zn_server * -zn_server_create(struct wl_display *display, struct zn_backend *backend) +zn_server_create(struct wl_display *display, struct zn_backend *backend, + struct zn_config *config) { wlr_log_init(WLR_DEBUG, handle_wlr_log); @@ -111,11 +116,18 @@ zn_server_create(struct wl_display *display, struct zn_backend *backend) self->display = display; self->running = false; self->exit_status = EXIT_FAILURE; + self->config = config; + + self->binding = zn_binding_create(); + if (self->binding == NULL) { + zn_error("Failed to create a zn_binding"); + goto err_free; + } self->seat = zn_seat_create(display); if (self->seat == NULL) { zn_error("Failed to create a zn_seat"); - goto err_free; + goto err_binding; } if (backend) { @@ -133,6 +145,9 @@ zn_server_create(struct wl_display *display, struct zn_backend *backend) err_seat: zn_seat_destroy(self->seat); +err_binding: + zn_binding_destroy(self->binding); + err_free: free(self); @@ -145,6 +160,7 @@ zn_server_destroy(struct zn_server *self) { zn_backend_destroy(self->backend); zn_seat_destroy(self->seat); + zn_binding_destroy(self->binding); server_singleton = NULL; wl_list_remove(&self->events.start.listener_list); wl_list_remove(&self->events.end.listener_list); diff --git a/zen/tests/binding.c b/zen/tests/binding.c new file mode 100644 index 00000000..832bf39e --- /dev/null +++ b/zen/tests/binding.c @@ -0,0 +1,89 @@ +#include "zen/binding.h" + +#include + +#include "mock/backend.h" +#include "test-harness.h" +#include "zen/config.h" +#include "zen/server.h" + +static struct zn_server * +setup(void) +{ + struct zn_mock_backend *backend = zn_mock_backend_create(); + struct wl_display *display = wl_display_create(); + struct zn_config *config = zn_config_create(); + struct zn_server *server = zn_server_create(display, &backend->base, config); + return server; +} + +static void +teardown(struct zn_server *server) +{ + struct zn_config *config = server->config; + zn_server_destroy(server); + zn_config_destroy(config); +} + +static bool +handle_test1(const char *name UNUSED, uint32_t key UNUSED, + uint32_t modifiers UNUSED, void *user_data) +{ + bool *test1 = (bool *)user_data; + *test1 = true; + + return true; +} + +static bool +handle_test2(const char *name UNUSED, uint32_t key UNUSED, + uint32_t modifiers UNUSED, void *user_data) +{ + bool *test2 = (bool *)user_data; + *test2 = true; + + return true; +} + +TEST(binding) +{ + struct zn_server *server = setup(); + + bool test1 = false; + bool test2 = false; + + zn_binding_add(server->binding, "test1", handle_test1, &test1); + zn_binding_add(server->binding, "test2", handle_test2, &test2); + + zn_binding_remap(server->binding); + + zn_binding_handle_key(server->binding, KEY_4, WLR_MODIFIER_ALT); + ASSERT_EQUAL_BOOL(true, test1); + ASSERT_EQUAL_BOOL(false, test2); + + zn_binding_handle_key( + server->binding, KEY_4, WLR_MODIFIER_ALT | WLR_MODIFIER_LOGO); + ASSERT_EQUAL_BOOL(true, test1); + ASSERT_EQUAL_BOOL(true, test2); + + teardown(server); +} + +TEST(duplicated) +{ + struct zn_server *server = setup(); + + bool test1 = false; + bool test2 = false; + + zn_binding_add(server->binding, "test1", handle_test1, &test1); + zn_binding_add(server->binding, "test1", handle_test1, &test1); + zn_binding_add(server->binding, "test2", handle_test2, &test2); + + ulong item_count = + server->binding->items.size / sizeof(struct zn_binding_item); + + ASSERT_EQUAL_INT(2, item_count); + + teardown(server); +} diff --git a/zen/tests/config/config-section.c b/zen/tests/config/config-section.c index df79156a..6359958d 100644 --- a/zen/tests/config/config-section.c +++ b/zen/tests/config/config-section.c @@ -1,148 +1,33 @@ -#include #include -#include "config.c" // NOLINT(bugprone-suspicious-include) #include "test-harness.h" -#include "zen-common/util.h" #include "zen/config.h" -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -static bool test_config_section_destroyed = false; - -static void test_config_section_destroy(struct zn_config_section *base); - -struct test_config_section { - struct zn_config_section base; - bool loaded; - int64_t number; -}; - -static bool -test_config_section_load(struct zn_config_section *base, toml_table_t *table) -{ - struct test_config_section *self = zn_container_of(base, self, base); - - self->loaded = true; - if (table) { - toml_datum_t result = toml_int_in(table, "number"); - if (result.ok) { - self->number = result.u.i; - } - } - - return self->number >= 0; -} - -static struct test_config_section * -test_config_section_create(void) -{ - struct test_config_section *section = zalloc(sizeof *section); - - section->base.load = test_config_section_load; - section->base.destroy = test_config_section_destroy; - section->loaded = false; - section->number = 0; - - return section; -} - -static void -test_config_section_destroy(struct zn_config_section *base) +TEST(reserve) { - struct test_config_section *self = zn_container_of(base, self, base); - free(self); - - test_config_section_destroyed = true; -} - -/// valid section -TEST(config_section_valid) -{ - struct test_config_section *section = test_config_section_create(); - struct zn_config *config = zn_config_create(); - zn_config_add_section(config, "test", §ion->base); - - ASSERT_EQUAL_POINTER(section, zn_config_get_section(config, "test")); + ASSERT_EQUAL_BOOL(true, zn_config_reserve_section(config, "section1")); - ASSERT_EQUAL_BOOL(true, section->loaded); - - ASSERT_EQUAL_INT(4, section->number); + ASSERT_EQUAL_BOOL(false, zn_config_reserve_section(config, "section1")); zn_config_destroy(config); - - ASSERT_EQUAL_BOOL(true, test_config_section_destroyed); } -/// missing section -TEST(config_section_invalid) +TEST(get_section) { - struct test_config_section *section = test_config_section_create(); - struct zn_config *config = zn_config_create(); - zn_config_add_section(config, "missing_section", §ion->base); + toml_table_t *table = toml_table_in(config->root_table, "test"); + toml_datum_t result = toml_int_in(table, "number"); - ASSERT_EQUAL_POINTER( - section, zn_config_get_section(config, "missing_section")); + ASSERT_NOT_EQUAL_POINTER(NULL, table); + ASSERT_EQUAL_INT(1, result.ok); + ASSERT_EQUAL_INT(4, result.u.i); - ASSERT_EQUAL_BOOL(true, section->loaded); + table = toml_table_in(config->root_table, "test2"); - ASSERT_EQUAL_INT(0, section->number); + ASSERT_EQUAL_POINTER(NULL, table); zn_config_destroy(config); - - ASSERT_EQUAL_BOOL(true, test_config_section_destroyed); -} - -/// duplicated section -TEST(config_section_duplicate) -{ - struct test_config_section *section1 = test_config_section_create(); - struct test_config_section *section2 = test_config_section_create(); - - struct zn_config *config = zn_config_create(); - - ASSERT_EQUAL_BOOL( - true, zn_config_add_section(config, "test", §ion1->base)); - ASSERT_EQUAL_BOOL( - false, zn_config_add_section(config, "test", §ion2->base)); -} - -/// load error -TEST(config_section_error) -{ - struct test_config_section *section = test_config_section_create(); - - struct zn_config *config = zn_config_create(); - - ASSERT_EQUAL_BOOL( - false, zn_config_add_section(config, "error", §ion->base)); -} - -/// missing config file -TEST(config_section_no_file) -{ - setenv("XDG_CONFIG_HOME", "/tmp/path", 1); - - struct test_config_section *section = test_config_section_create(); - - struct zn_config *config = zn_config_create(); - - zn_config_add_section(config, "test", §ion->base); - - ASSERT_EQUAL_POINTER(section, zn_config_get_section(config, "test")); - - ASSERT_EQUAL_BOOL(true, section->loaded); - - ASSERT_EQUAL_INT(0, section->number); -} - -/// unknown section -TEST(config_section_unknown) -{ - struct zn_config *config = zn_config_create(); - - ASSERT_EQUAL_POINTER(NULL, zn_config_get_section(config, "unkown")); } diff --git a/zen/tests/meson.build b/zen/tests/meson.build index a407f5e9..aad0b117 100644 --- a/zen/tests/meson.build +++ b/zen/tests/meson.build @@ -8,6 +8,11 @@ _zen_unit_tests_deps = [ ] _zen_unit_tests = { + 'binding.c': { + 'env': { + 'XDG_CONFIG_HOME': '@0@/testdata'.format(meson.current_source_dir()), + }, + }, 'config/config-section.c': { 'env': { 'XDG_CONFIG_HOME': '@0@/testdata'.format(meson.current_source_dir()), diff --git a/zen/tests/server/construct-destroy.c b/zen/tests/server/construct-destroy.c index 5466dd3d..f1ccb0c9 100644 --- a/zen/tests/server/construct-destroy.c +++ b/zen/tests/server/construct-destroy.c @@ -2,6 +2,7 @@ #include "mock/backend.h" #include "test-harness.h" +#include "zen/config.h" #include "zen/cursor.h" #include "zen/seat.h" #include "zen/server.h" @@ -10,9 +11,11 @@ TEST(construct_destroy) { struct zn_mock_backend *backend = zn_mock_backend_create(); struct wl_display *display = wl_display_create(); - struct zn_server *server = zn_server_create(display, &backend->base); + struct zn_config *config = zn_config_create(); + struct zn_server *server = zn_server_create(display, &backend->base, config); ASSERT_NOT_EQUAL_POINTER(NULL, server); zn_server_destroy(server); + zn_config_destroy(config); } diff --git a/zen/tests/testdata/zen-desktop/config.toml b/zen/tests/testdata/zen-desktop/config.toml index 3a506e7c..ad23e78e 100644 --- a/zen/tests/testdata/zen-desktop/config.toml +++ b/zen/tests/testdata/zen-desktop/config.toml @@ -5,3 +5,7 @@ number = 4 [error] number = -1 + +[binding] +test1 = "alt+4" +test2 = "logo+alt+4" From 3433d70ef07286ddfaf55ac6b4c3ec797f793d3c Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Wed, 12 Jul 2023 22:49:43 +0900 Subject: [PATCH 37/49] send xr_system status on bind --- desktop/src/xr-system.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/desktop/src/xr-system.c b/desktop/src/xr-system.c index 09833364..1da1905c 100644 --- a/desktop/src/xr-system.c +++ b/desktop/src/xr-system.c @@ -47,6 +47,8 @@ zn_desktop_xr_system_bind( resource, &implementation, self, zn_desktop_xr_system_handle_destroy); wl_list_insert(&self->resource_list, wl_resource_get_link(resource)); + + zen_xr_system_send_status(resource, self->status); } static void From 3ac192d8ca0005fca3a28e8024ea328799411f79 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Fri, 14 Jul 2023 23:15:15 +0900 Subject: [PATCH 38/49] xdg toplevel --- desktop/src/shell.c | 4 + zen/src/backend/meson.build | 2 + zen/src/backend/screen/compositor.c | 50 ++++ zen/src/backend/screen/compositor.h | 5 + zen/src/backend/screen/xdg-decoration.c | 82 ++++++ zen/src/backend/screen/xdg-decoration.h | 17 ++ zen/src/backend/screen/xdg-toplevel.c | 337 ++++++++++++++++++++++ zen/src/backend/screen/xdg-toplevel.h | 40 +++ zen/src/backend/screen/xwayland-surface.c | 1 + zen/src/backend/screen/xwayland-surface.h | 2 +- 10 files changed, 539 insertions(+), 1 deletion(-) create mode 100644 zen/src/backend/screen/xdg-decoration.c create mode 100644 zen/src/backend/screen/xdg-decoration.h create mode 100644 zen/src/backend/screen/xdg-toplevel.c create mode 100644 zen/src/backend/screen/xdg-toplevel.h diff --git a/desktop/src/shell.c b/desktop/src/shell.c index 61515b10..a5d725e6 100644 --- a/desktop/src/shell.c +++ b/desktop/src/shell.c @@ -61,6 +61,10 @@ zn_desktop_shell_handle_view_mapped(struct wl_listener *listener, void *data) zn_snode_set_position( view->snode, desktop_screen->view_layer, (vec2){0, 0}); } + + struct zn_server *server = zn_server_get_singleton(); + + zn_seat_set_focus(server->seat, view->snode); } static void diff --git a/zen/src/backend/meson.build b/zen/src/backend/meson.build index 6ce824df..517903f4 100644 --- a/zen/src/backend/meson.build +++ b/zen/src/backend/meson.build @@ -19,6 +19,8 @@ _zen_backend_srcs = [ 'screen/output.c', 'screen/pointer.c', 'screen/surface-snode.c', + 'screen/xdg-decoration.c', + 'screen/xdg-toplevel.c', 'screen/xwayland-surface.c', protocols_code['zwin'], diff --git a/zen/src/backend/screen/compositor.c b/zen/src/backend/screen/compositor.c index 8a94db63..a14739b9 100644 --- a/zen/src/backend/screen/compositor.c +++ b/zen/src/backend/screen/compositor.c @@ -5,6 +5,8 @@ #include "layer-shell.h" #include "layer-surface.h" #include "output.h" +#include "xdg-decoration.h" +#include "xdg-toplevel.h" #include "xwayland-surface.h" #include "zen-common/log.h" #include "zen-common/util.h" @@ -26,6 +28,17 @@ zn_compositor_handle_new_xwayland_surface( zn_xwayland_surface_create(wlr_xsurface); } +static void +zn_compositor_handle_new_xdg_surface( + struct wl_listener *listener UNUSED, void *data) +{ + struct wlr_xdg_surface *xdg_surface = data; + + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + zn_xdg_toplevel_create(xdg_surface->toplevel); + } +} + static void zn_compositor_handle_new_layer_surface( struct wl_listener *listener UNUSED, void *data) @@ -62,6 +75,26 @@ zn_compositor_handle_new_layer_surface( output->layer_shell, layer_surface, wlr_layer_surface->current.layer); } +static void +zn_compositor_handle_new_xdg_decoration( + struct wl_listener *listener UNUSED, void *data) +{ + struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration = data; + + struct zn_xdg_decoration *decoration = + zn_xdg_decoration_create(wlr_decoration); + if (decoration == NULL) { + zn_error("Failed to create zn_xdg_decoration"); + return; + } + + struct zn_xdg_toplevel *toplevel = + zn_xdg_toplevel_from_wlr_xdg_surface(wlr_decoration->surface); + if (toplevel) { + zn_xdg_toplevel_set_decoration(toplevel, decoration); + } +} + static void zn_compositor_handle_server_end(struct wl_listener *listener, void *data UNUSED) { @@ -125,6 +158,12 @@ zn_compositor_create(struct wl_display *display, struct wlr_renderer *renderer) goto err_output_layout; } + self->xdg_decoration_manager = wlr_xdg_decoration_manager_v1_create(display); + if (self->xdg_decoration_manager == NULL) { + zn_error("Failed to create a wlr_xdg_decoration_manager_v1"); + goto err_output_layout; + } + for (int i = 0; i <= 32; i++) { sprintf(socket_name_candidate, "wayland-%d", i); // NOLINT(cert-err33-c) if (wl_display_add_socket(display, socket_name_candidate) >= 0) { @@ -157,11 +196,20 @@ zn_compositor_create(struct wl_display *display, struct wlr_renderer *renderer) wl_signal_add(&self->xwayland->events.new_surface, &self->new_xwayland_surface_listener); + self->new_xdg_surface_listener.notify = zn_compositor_handle_new_xdg_surface; + wl_signal_add( + &self->xdg_shell->events.new_surface, &self->new_xdg_surface_listener); + self->new_layer_surface_listener.notify = zn_compositor_handle_new_layer_surface; wl_signal_add(&self->wlr_layer_shell->events.new_surface, &self->new_layer_surface_listener); + self->new_xdg_decoration_listener.notify = + zn_compositor_handle_new_xdg_decoration; + wl_signal_add(&self->xdg_decoration_manager->events.new_toplevel_decoration, + &self->new_xdg_decoration_listener); + self->server_end_listener.notify = zn_compositor_handle_server_end; wl_signal_add(&server->events.end, &self->server_end_listener); @@ -181,7 +229,9 @@ void zn_compositor_destroy(struct zn_compositor *self) { wl_list_remove(&self->server_end_listener.link); + wl_list_remove(&self->new_xdg_decoration_listener.link); wl_list_remove(&self->new_layer_surface_listener.link); + wl_list_remove(&self->new_xdg_surface_listener.link); wl_list_remove(&self->new_xwayland_surface_listener.link); if (self->xwayland) { wlr_xwayland_destroy(self->xwayland); diff --git a/zen/src/backend/screen/compositor.h b/zen/src/backend/screen/compositor.h index 4f65a24a..615c768c 100644 --- a/zen/src/backend/screen/compositor.h +++ b/zen/src/backend/screen/compositor.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,8 @@ struct zn_compositor { struct wlr_layer_shell_v1 *wlr_layer_shell; // @nonnull, @outlive struct wlr_data_device_manager *data_device_manager; // @nonnull, @outlive struct wlr_xdg_output_manager_v1 *xdg_output_manager; // @nonnull, @outlive + struct wlr_xdg_decoration_manager_v1 + *xdg_decoration_manager; // @nonnull, @outlive // TODO(@Aki-7): Use this appropriately #388 struct wlr_output_layout *output_layout; // @nonnull, @owning @@ -22,7 +25,9 @@ struct zn_compositor { struct wlr_xwayland *xwayland; // @nullable, @owning struct wl_listener new_xwayland_surface_listener; + struct wl_listener new_xdg_surface_listener; struct wl_listener new_layer_surface_listener; + struct wl_listener new_xdg_decoration_listener; struct wl_listener server_end_listener; }; diff --git a/zen/src/backend/screen/xdg-decoration.c b/zen/src/backend/screen/xdg-decoration.c new file mode 100644 index 00000000..248ad2ff --- /dev/null +++ b/zen/src/backend/screen/xdg-decoration.c @@ -0,0 +1,82 @@ +#include "xdg-decoration.h" + +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +static void zn_xdg_decoration_destroy(struct zn_xdg_decoration *self); + +static void +zn_xdg_decoration_handle_wlr_decoration_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_xdg_decoration *self = + zn_container_of(listener, self, wlr_decoration_destroy_listener); + + zn_xdg_decoration_destroy(self); +} + +static void +zn_xdg_decoration_handle_request_mode( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_xdg_decoration *self = + zn_container_of(listener, self, wlr_decoration_request_mode_listener); + + // TODO(@Aki-7): make this configurable from the desktop component + enum wlr_xdg_toplevel_decoration_v1_mode mode = + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + + enum wlr_xdg_toplevel_decoration_v1_mode client_mode = + self->wlr_decoration->requested_mode; + + if (client_mode) { + mode = client_mode; + } + + wlr_xdg_toplevel_decoration_v1_set_mode(self->wlr_decoration, mode); +} + +struct zn_xdg_decoration * +zn_xdg_decoration_create(struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration) +{ + struct zn_xdg_decoration *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->wlr_decoration = wlr_decoration; + wl_signal_init(&self->events.destroy); + + self->wlr_decoration_destroy_listener.notify = + zn_xdg_decoration_handle_wlr_decoration_destroy; + wl_signal_add(&self->wlr_decoration->events.destroy, + &self->wlr_decoration_destroy_listener); + + self->wlr_decoration_request_mode_listener.notify = + zn_xdg_decoration_handle_request_mode; + wl_signal_add(&self->wlr_decoration->events.request_mode, + &self->wlr_decoration_request_mode_listener); + + /// For some clients, the set_mode request has already been processed at this + /// point. + zn_xdg_decoration_handle_request_mode( + &self->wlr_decoration_request_mode_listener, wlr_decoration); + + return self; + +err: + return NULL; +} + +static void +zn_xdg_decoration_destroy(struct zn_xdg_decoration *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + wl_list_remove(&self->wlr_decoration_request_mode_listener.link); + wl_list_remove(&self->wlr_decoration_destroy_listener.link); + free(self); +} diff --git a/zen/src/backend/screen/xdg-decoration.h b/zen/src/backend/screen/xdg-decoration.h new file mode 100644 index 00000000..967c71a9 --- /dev/null +++ b/zen/src/backend/screen/xdg-decoration.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +struct zn_xdg_decoration { + struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration; // @nonnull, @outlive + + struct wl_listener wlr_decoration_destroy_listener; + struct wl_listener wlr_decoration_request_mode_listener; + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +struct zn_xdg_decoration *zn_xdg_decoration_create( + struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration); diff --git a/zen/src/backend/screen/xdg-toplevel.c b/zen/src/backend/screen/xdg-toplevel.c new file mode 100644 index 00000000..3d0d9981 --- /dev/null +++ b/zen/src/backend/screen/xdg-toplevel.c @@ -0,0 +1,337 @@ +#include "xdg-toplevel.h" + +#include + +#include "default-backend.h" +#include "surface-snode.h" +#include "xdg-decoration.h" +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/seat.h" +#include "zen/server.h" +#include "zen/snode.h" +#include "zen/view.h" + +static void zn_xdg_toplevel_destroy(struct zn_xdg_toplevel *self); + +static void +zn_xdg_toplevel_set_focus(void *impl_data, bool focused) +{ + struct zn_xdg_toplevel *self = impl_data; + struct zn_server *server = zn_server_get_singleton(); + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(server->seat->wlr_seat); + + if (keyboard) { + wlr_seat_keyboard_enter(server->seat->wlr_seat, + self->wlr_xdg_toplevel->base->surface, keyboard->keycodes, + keyboard->num_keycodes, &keyboard->modifiers); + } else { + wlr_seat_keyboard_enter(server->seat->wlr_seat, + self->wlr_xdg_toplevel->base->surface, NULL, 0, NULL); + } + + wlr_xdg_toplevel_set_activated(self->wlr_xdg_toplevel->base, focused); +} + +static void +zn_xdg_toplevel_configure_size(void *impl_data, vec2 size) +{ + struct zn_xdg_toplevel *self = impl_data; + + wlr_xdg_toplevel_set_size( + self->wlr_xdg_toplevel->base, (uint32_t)size[0], (uint32_t)size[1]); +} + +static void +zn_xdg_toplevel_close(void *impl_data) +{ + struct zn_xdg_toplevel *self = impl_data; + + wlr_xdg_toplevel_send_close(self->wlr_xdg_toplevel->base); +} + +static const struct zn_view_interface view_implementation = { + .set_focus = zn_xdg_toplevel_set_focus, + .configure_size = zn_xdg_toplevel_configure_size, + .close = zn_xdg_toplevel_close, +}; + +static void +zn_xdg_toplevel_update_view_size(struct zn_xdg_toplevel *self) +{ + struct wlr_box geometry; + wlr_xdg_surface_get_geometry(self->wlr_xdg_toplevel->base, &geometry); + vec2 new_size = {(float)geometry.width, (float)geometry.height}; + + if (!glm_vec2_eqv(self->view->size, new_size)) { + zn_view_notify_resized(self->view, new_size); + } +} + +static void +zn_xdg_toplevel_update_surface_position(struct zn_xdg_toplevel *self) +{ + struct wlr_box geometry; + wlr_xdg_surface_get_geometry(self->wlr_xdg_toplevel->base, &geometry); + + if (self->surface_snode == NULL) { + return; + } + + struct zn_snode *snode = self->surface_snode->snode; + vec2 position = {(float)-geometry.x, (float)-geometry.y}; + + if (!glm_vec2_eqv(snode->position, position)) { + zn_snode_set_position(snode, snode->parent, position); + } +} + +static void +zn_xdg_toplevel_update_view_decoration( + struct zn_xdg_toplevel *self, bool use_pending_state) +{ + enum wlr_xdg_toplevel_decoration_v1_mode wlr_mode = + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE; + + if (self->decoration) { + wlr_mode = use_pending_state + ? self->decoration->wlr_decoration->pending.mode + : self->decoration->wlr_decoration->current.mode; + } + + enum zn_view_decoration_mode mode = ZN_VIEW_DECORATION_MODE_CLIENT_SIDE; + + switch (wlr_mode) { + case WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: + mode = ZN_VIEW_DECORATION_MODE_CLIENT_SIDE; + break; + case WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: + mode = ZN_VIEW_DECORATION_MODE_SERVER_SIDE; + break; + case WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE: + mode = ZN_VIEW_DECORATION_MODE_SERVER_SIDE; + break; + } + + if (self->view->decoration_mode != mode) { + zn_view_notify_decoration(self->view, mode); + } +} + +static void +zn_xdg_toplevel_handle_surface_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_xdg_toplevel *self = + zn_container_of(listener, self, surface_destroy_listener); + + zn_xdg_toplevel_destroy(self); +} + +static void +zn_xdg_toplevel_handle_surface_map( + struct wl_listener *listener UNUSED, void *data UNUSED) +{ + struct zn_xdg_toplevel *self = + zn_container_of(listener, self, surface_map_listener); + struct zn_server *server = zn_server_get_singleton(); + struct zn_default_backend *backend = zn_default_backend_get(server->backend); + + wl_signal_add(&self->wlr_xdg_toplevel->base->surface->events.commit, + &self->surface_commit_listener); + + self->surface_snode = + zn_surface_snode_create(self->wlr_xdg_toplevel->base->surface); + if (self->surface_snode == NULL) { + zn_error("Failed to create a surface snode"); + wlr_xdg_toplevel_send_close(self->wlr_xdg_toplevel->base); + return; + } + + // TODO(@Aki-7): Respect window geometry + zn_snode_set_position( + self->surface_snode->snode, self->view->snode, GLM_VEC2_ZERO); + + zn_xdg_toplevel_update_surface_position(self); + + zn_xdg_toplevel_update_view_size(self); + + zn_xdg_toplevel_update_view_decoration(self, false); + + zn_default_backend_notify_view_mapped(backend, self->view); +} + +static void +zn_xdg_toplevel_handle_surface_unmap( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_xdg_toplevel *self = + zn_container_of(listener, self, surface_unmap_listener); + + wl_list_remove(&self->surface_commit_listener.link); + wl_list_init(&self->surface_commit_listener.link); + + zn_snode_set_position(self->surface_snode->snode, NULL, GLM_VEC2_ZERO); + self->surface_snode = NULL; + + zn_view_notify_unmap(self->view); +} + +static void +zn_xdg_toplevel_handle_surface_commit( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_xdg_toplevel *self = + zn_container_of(listener, self, surface_commit_listener); + + if (!zn_assert_(self->surface_snode, + "Commit signal must be handled only when the view is mapped")) { + return; + } + + zn_surface_snode_commit_damage(self->surface_snode); + + zn_xdg_toplevel_update_surface_position(self); + + zn_xdg_toplevel_update_view_size(self); + + // Use the pending state because the commit signal handler of the decoration + // object can be called after this commit signal handler. + zn_xdg_toplevel_update_view_decoration(self, true); +} + +static void +zn_xdg_toplevel_handle_surface_move_request( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_xdg_toplevel *self = + zn_container_of(listener, self, surface_move_request_listener); + + zn_view_notify_move_request(self->view); +} + +static void +zn_xdg_toplevel_handle_surface_resize_request( + struct wl_listener *listener, void *data) +{ + struct zn_xdg_toplevel *self = + zn_container_of(listener, self, surface_resize_request_listener); + + struct wlr_xdg_toplevel_resize_event *wlr_event = data; + struct zn_view_resize_event event; + + event.edges = wlr_event->edges; + + zn_view_notify_resize_request(self->view, &event); +} + +static void +zn_xdg_toplevel_handle_decoration_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_xdg_toplevel *self = + zn_container_of(listener, self, decoration_destroy_listener); + + zn_xdg_toplevel_set_decoration(self, NULL); +} + +void +zn_xdg_toplevel_set_decoration( + struct zn_xdg_toplevel *self, struct zn_xdg_decoration *decoration) +{ + if (self->decoration) { + wl_list_remove(&self->decoration_destroy_listener.link); + wl_list_init(&self->decoration_destroy_listener.link); + } + + self->decoration = decoration; + + if (decoration) { + wl_signal_add( + &decoration->events.destroy, &self->decoration_destroy_listener); + } +} + +struct zn_xdg_toplevel * +zn_xdg_toplevel_from_wlr_xdg_surface(struct wlr_xdg_surface *surface) +{ + if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return surface->data; + } + + return NULL; +} + +struct zn_xdg_toplevel * +zn_xdg_toplevel_create(struct wlr_xdg_toplevel *wlr_xdg_toplevel) +{ + struct zn_xdg_toplevel *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->wlr_xdg_toplevel = wlr_xdg_toplevel; + wlr_xdg_toplevel->base->data = self; + + self->view = zn_view_create(self, &view_implementation); + if (self->view == NULL) { + zn_error("Failed to create a zn_view"); + goto err_free; + } + + self->decoration = NULL; + self->surface_snode = NULL; + + self->surface_destroy_listener.notify = + zn_xdg_toplevel_handle_surface_destroy; + wl_signal_add(&self->wlr_xdg_toplevel->base->events.destroy, + &self->surface_destroy_listener); + + self->surface_map_listener.notify = zn_xdg_toplevel_handle_surface_map; + wl_signal_add( + &self->wlr_xdg_toplevel->base->events.map, &self->surface_map_listener); + + self->surface_unmap_listener.notify = zn_xdg_toplevel_handle_surface_unmap; + wl_signal_add(&self->wlr_xdg_toplevel->base->events.unmap, + &self->surface_unmap_listener); + + self->surface_commit_listener.notify = zn_xdg_toplevel_handle_surface_commit; + wl_list_init(&self->surface_commit_listener.link); + + self->surface_move_request_listener.notify = + zn_xdg_toplevel_handle_surface_move_request; + wl_signal_add(&self->wlr_xdg_toplevel->events.request_move, + &self->surface_move_request_listener); + + self->surface_resize_request_listener.notify = + zn_xdg_toplevel_handle_surface_resize_request; + wl_signal_add(&self->wlr_xdg_toplevel->events.request_resize, + &self->surface_resize_request_listener); + + self->decoration_destroy_listener.notify = + zn_xdg_toplevel_handle_decoration_destroy; + wl_list_init(&self->decoration_destroy_listener.link); + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +static void +zn_xdg_toplevel_destroy(struct zn_xdg_toplevel *self) +{ + wl_list_remove(&self->decoration_destroy_listener.link); + wl_list_remove(&self->surface_resize_request_listener.link); + wl_list_remove(&self->surface_move_request_listener.link); + wl_list_remove(&self->surface_commit_listener.link); + wl_list_remove(&self->surface_unmap_listener.link); + wl_list_remove(&self->surface_map_listener.link); + wl_list_remove(&self->surface_destroy_listener.link); + zn_view_destroy(self->view); + free(self); +} diff --git a/zen/src/backend/screen/xdg-toplevel.h b/zen/src/backend/screen/xdg-toplevel.h new file mode 100644 index 00000000..c362513d --- /dev/null +++ b/zen/src/backend/screen/xdg-toplevel.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +struct zn_view; +struct zn_surface_snode; +struct zn_xdg_decoration; + +struct zn_xdg_toplevel { + struct wlr_xdg_toplevel *wlr_xdg_toplevel; // @nonnull, @outlive + + struct zn_view *view; // @nonnull, @owning + + struct zn_xdg_decoration *decoration; // @nullable, @ref + + // @nonnull while mapped + // Automatically destroyed when given wlr_surface is destroyed; + struct zn_surface_snode *surface_snode; + + // Developer note: Reading through the wlroots source, the unmap signal is + // always emitted before the destroy signal + struct wl_listener surface_destroy_listener; + struct wl_listener surface_map_listener; + struct wl_listener surface_unmap_listener; + struct wl_listener surface_commit_listener; // listen only when mapped + struct wl_listener surface_move_request_listener; + struct wl_listener surface_resize_request_listener; + struct wl_listener decoration_destroy_listener; +}; + +/// @param decoration may NULL +void zn_xdg_toplevel_set_decoration( + struct zn_xdg_toplevel *self, struct zn_xdg_decoration *decoration); + +/// @return value may NULL +struct zn_xdg_toplevel *zn_xdg_toplevel_from_wlr_xdg_surface( + struct wlr_xdg_surface *surface); + +struct zn_xdg_toplevel *zn_xdg_toplevel_create( + struct wlr_xdg_toplevel *wlr_xdg_toplevel); diff --git a/zen/src/backend/screen/xwayland-surface.c b/zen/src/backend/screen/xwayland-surface.c index 72348812..9f06a13e 100644 --- a/zen/src/backend/screen/xwayland-surface.c +++ b/zen/src/backend/screen/xwayland-surface.c @@ -230,6 +230,7 @@ zn_xwayland_surface_handle_surface_unmap( wl_list_remove(&self->surface_commit_listener.link); wl_list_init(&self->surface_commit_listener.link); + zn_snode_set_position(self->surface_snode->snode, NULL, GLM_VEC2_ZERO); self->surface_snode = NULL; zn_view_notify_unmap(self->view); diff --git a/zen/src/backend/screen/xwayland-surface.h b/zen/src/backend/screen/xwayland-surface.h index 72f4f2ac..4d083807 100644 --- a/zen/src/backend/screen/xwayland-surface.h +++ b/zen/src/backend/screen/xwayland-surface.h @@ -11,7 +11,7 @@ struct zn_xwayland_surface { struct zn_view *view; // @nonnull, @owning // @nonnull while mapped - // Automatically destroyed when give wlr_surface is destroyed. + // Automatically destroyed when given wlr_surface is destroyed. struct zn_surface_snode *surface_snode; // Developer note: Reading through the wlroots source, the unmap signal is From 1091611592fc6e5438e31933ecda6b8b1e3b48f0 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Fri, 14 Jul 2023 23:23:19 +0900 Subject: [PATCH 39/49] use zwin v0.2.0 branch --- .github/workflows/test.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2258f69d..f53e4e58 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -86,6 +86,7 @@ jobs: with: repository: zwin-project/zwin path: zwin + ref: 'v0.2.0' - name: Build zwin working-directory: ./zwin From 7d7a34ef329fc99d870e92fc658f4872f2cc0973 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 15 Jul 2023 16:19:29 +0900 Subject: [PATCH 40/49] fix clang-tidy error --- zen/include/zen/xr-system.h | 6 +++--- zen/src/backend/immersive/remote/gl-buffer.cc | 2 +- .../backend/immersive/remote/xr-dispatcher.cc | 2 +- zen/src/backend/immersive/remote/xr-system.h | 6 +++--- zen/src/binding.c | 18 +++++++++--------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/zen/include/zen/xr-system.h b/zen/include/zen/xr-system.h index 4bf63429..3d4a284a 100644 --- a/zen/include/zen/xr-system.h +++ b/zen/include/zen/xr-system.h @@ -61,9 +61,9 @@ zn_xr_system_connect(struct zn_xr_system *self) UNUSED static inline bool zn_xr_system_is_connected(struct zn_xr_system *self) { - uint32_t connected = ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED | - ZN_XR_SYSTEM_SESSION_STATE_VISIBLE | - ZN_XR_SYSTEM_SESSION_STATE_FOCUS; + const uint32_t connected = ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED | + ZN_XR_SYSTEM_SESSION_STATE_VISIBLE | + ZN_XR_SYSTEM_SESSION_STATE_FOCUS; return (self->state & connected) != 0; } diff --git a/zen/src/backend/immersive/remote/gl-buffer.cc b/zen/src/backend/immersive/remote/gl-buffer.cc index a696bba7..1525a6ec 100644 --- a/zen/src/backend/immersive/remote/gl-buffer.cc +++ b/zen/src/backend/immersive/remote/gl-buffer.cc @@ -63,7 +63,7 @@ GlBuffer::HandleData(struct zn_gl_buffer *c_obj, uint32_t target, { auto *self = static_cast(c_obj->impl_data); - ssize_t size = zn_buffer_get_size(buffer); + const ssize_t size = zn_buffer_get_size(buffer); auto loop = std::make_unique(wl_display_get_event_loop(self->display_)); diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index 4b4e63ea..565aa483 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -236,7 +236,7 @@ XrDispatcher::HandleGetNewGlShader( std::string source; { - ssize_t length = zn_buffer_get_size(buffer); + const ssize_t length = zn_buffer_get_size(buffer); auto *data = zn_buffer_begin_access(buffer); source = std::string(static_cast(data), length); zn_buffer_end_access(buffer); diff --git a/zen/src/backend/immersive/remote/xr-system.h b/zen/src/backend/immersive/remote/xr-system.h index 9a4c7d20..bf548179 100644 --- a/zen/src/backend/immersive/remote/xr-system.h +++ b/zen/src/backend/immersive/remote/xr-system.h @@ -77,9 +77,9 @@ XrSystem::is_alive() const inline bool XrSystem::is_connected() const { - uint32_t connected = ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED | - ZN_XR_SYSTEM_SESSION_STATE_VISIBLE | - ZN_XR_SYSTEM_SESSION_STATE_FOCUS; + const uint32_t connected = ZN_XR_SYSTEM_SESSION_STATE_SYNCHRONIZED | + ZN_XR_SYSTEM_SESSION_STATE_VISIBLE | + ZN_XR_SYSTEM_SESSION_STATE_FOCUS; return (c_obj_.state & connected) != 0; } diff --git a/zen/src/binding.c b/zen/src/binding.c index 0e5418d5..a619b1c5 100644 --- a/zen/src/binding.c +++ b/zen/src/binding.c @@ -9,15 +9,15 @@ #define CONFIG_SECTION_KEY "binding" -#define TOKEN_SHIFT "shift" -#define TOKEN_CTRL "ctrl" -#define TOKEN_ALT "alt" -#define TOKEN_LOGO "logo" -#define TOKEN_RIGHT "right" -#define TOKEN_LEFT "left" -#define TOKEN_UP "up" -#define TOKEN_DOWN "down" -#define TOKEN_SEPARATOR '+' +const char *const TOKEN_SHIFT = "shift"; +const char *const TOKEN_CTRL = "ctrl"; +const char *const TOKEN_ALT = "alt"; +const char *const TOKEN_LOGO = "logo"; +const char *const TOKEN_RIGHT = "right"; +const char *const TOKEN_LEFT = "left"; +const char *const TOKEN_UP = "up"; +const char *const TOKEN_DOWN = "down"; +const char TOKEN_SEPARATOR = '+'; static const uint32_t ascii_to_keycode[] = { ['a'] = KEY_A, From 0ec0cbbe65788a1a42b62508c655e19250b5bb34 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 22 Jul 2023 19:01:34 +0900 Subject: [PATCH 41/49] subsurface --- desktop/src/shell.c | 11 +- desktop/src/ui/decoration/header-bar.c | 7 +- desktop/src/view.c | 2 +- zen/include/zen/snode.h | 17 +++ zen/src/backend/screen/surface-snode.c | 164 ++++++++++++++++++++++-- zen/src/backend/screen/surface-snode.h | 7 +- zen/src/backend/screen/xdg-decoration.c | 2 +- zen/src/backend/screen/xdg-toplevel.c | 6 +- zen/src/snode.c | 74 ++++++++++- zen/src/view.c | 2 +- zen/tests/snode/snode-damage.c | 108 ++++++++++++++++ zen/tests/snode/snode-position.c | 83 ++++++++++++ 12 files changed, 458 insertions(+), 25 deletions(-) diff --git a/desktop/src/shell.c b/desktop/src/shell.c index a5d725e6..8014cdc7 100644 --- a/desktop/src/shell.c +++ b/desktop/src/shell.c @@ -1,5 +1,6 @@ #include "zen-desktop/shell.h" +#include #include #include @@ -57,9 +58,17 @@ zn_desktop_shell_handle_view_mapped(struct wl_listener *listener, void *data) struct zn_desktop_screen *desktop_screen = zn_screen_layout_get_main_screen(self->screen_layout); + vec2 initial_position; + glm_vec2_sub( + desktop_screen->screen->size, view->zn_view->size, initial_position); + glm_vec2_scale(initial_position, 0.5F, initial_position); + if (initial_position[1] < 40) { + initial_position[1] = 40; + } + if (desktop_screen) { zn_snode_set_position( - view->snode, desktop_screen->view_layer, (vec2){0, 0}); + view->snode, desktop_screen->view_layer, initial_position); } struct zn_server *server = zn_server_get_singleton(); diff --git a/desktop/src/ui/decoration/header-bar.c b/desktop/src/ui/decoration/header-bar.c index 8e7a5bd1..6dcc2998 100644 --- a/desktop/src/ui/decoration/header-bar.c +++ b/desktop/src/ui/decoration/header-bar.c @@ -118,14 +118,17 @@ zn_ui_header_bar_update_texture(struct zn_ui_header_bar *self) if (self->texture) { zn_snode_damage_whole(self->snode); wlr_texture_destroy(self->texture); + self->texture = NULL; } unsigned char *data = cairo_image_surface_get_data(surface); int stride = cairo_image_surface_get_stride(surface); int width = cairo_image_surface_get_width(surface); int height = cairo_image_surface_get_height(surface); - self->texture = zn_backend_create_wlr_texture_from_pixels( - server->backend, DRM_FORMAT_ARGB8888, stride, width, height, data); + if (width > 0 && height > 0) { + self->texture = zn_backend_create_wlr_texture_from_pixels( + server->backend, DRM_FORMAT_ARGB8888, stride, width, height, data); + } zn_snode_damage_whole(self->snode); diff --git a/desktop/src/view.c b/desktop/src/view.c index fa36df76..c651fd48 100644 --- a/desktop/src/view.c +++ b/desktop/src/view.c @@ -133,7 +133,7 @@ zn_desktop_view_handle_zn_view_resized(struct wl_listener *listener, void *data) if (position_changed) { vec2 new_position; glm_vec2_add(self->snode->position, position_diff, new_position); - zn_snode_set_position(self->snode, self->snode->parent, new_position); + zn_snode_change_position(self->snode, new_position); } zn_desktop_view_update_decoration(self); diff --git a/zen/include/zen/snode.h b/zen/include/zen/snode.h index 9ec13036..947cbf69 100644 --- a/zen/include/zen/snode.h +++ b/zen/include/zen/snode.h @@ -169,9 +169,26 @@ void zn_snode_notify_frame(struct zn_snode *self, const struct timespec *when); /// @param parent is nullable /// @param position is in the parent local coords +/// The node is placed on top. void zn_snode_set_position( struct zn_snode *self, struct zn_snode *parent, vec2 position); +/// @param position is in the parent local coords +/// Only the position changes, the order of the siblings remains the same. +void zn_snode_change_position(struct zn_snode *self, vec2 position); + +/// @param sibling must not be NULL +/// self and sibling must have the same direct nonnull parent. +/// self is placed directly above the sibling. +/// Position doesn't change +void zn_snode_place_above(struct zn_snode *self, struct zn_snode *sibling); + +/// @param sibling must not be NULL +/// self and sibling must have the same direct nonnull parent. +/// self is placed directly below the sibling. +/// Position doesn't change +void zn_snode_place_below(struct zn_snode *self, struct zn_snode *sibling); + /// @return value is nullable struct wlr_texture *zn_snode_get_texture(struct zn_snode *self); diff --git a/zen/src/backend/screen/surface-snode.c b/zen/src/backend/screen/surface-snode.c index 192b8097..8ffbe983 100644 --- a/zen/src/backend/screen/surface-snode.c +++ b/zen/src/backend/screen/surface-snode.c @@ -1,5 +1,8 @@ #include "surface-snode.h" +#include +#include + #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" @@ -94,6 +97,84 @@ static const struct zn_snode_interface implementation = { .on_focus = zn_snode_noop_on_focus, }; +typedef void (*zn_surface_snode_iter_children_func_t)( + struct zn_surface_snode *self, struct zn_surface_snode *child, void *data); + +static void +zn_surface_snode_iter_children(struct zn_surface_snode *self, + zn_surface_snode_iter_children_func_t func, void *data) +{ + struct zn_snode *snode = NULL; + + wl_list_for_each ( + snode, &self->subsurfaces_below_node->child_node_list, link) { + struct zn_surface_snode *surface_snode = snode->user_data; + func(self, surface_snode, data); + } + + wl_list_for_each ( + snode, &self->subsurfaces_above_node->child_node_list, link) { + struct zn_surface_snode *surface_snode = snode->user_data; + func(self, surface_snode, data); + } +} + +static void +zn_surface_snode_update_child_subsurface_position( + struct zn_surface_snode *self UNUSED, struct zn_surface_snode *child, + void *data UNUSED) +{ + if (!wlr_surface_is_subsurface(child->surface)) { + return; + } + + struct wlr_subsurface *subsurface = + wlr_subsurface_from_wlr_surface(child->surface); + + vec2 position = {(float)subsurface->current.x, (float)subsurface->current.y}; + + zn_snode_change_position(child->surface_node, position); +} + +static void +zn_surface_snode_update_child_subsurfaces_position( + struct zn_surface_snode *self) +{ + zn_surface_snode_iter_children( + self, zn_surface_snode_update_child_subsurface_position, NULL); +} + +static void +zn_surface_snode_handle_new_subsurface( + struct wl_listener *listener UNUSED, void *user_data) +{ + struct wlr_subsurface *subsurface = user_data; + + zn_surface_snode_create(subsurface->surface); +} + +static void +zn_surface_snode_handle_commit( + struct wl_listener *listener, void *user_data UNUSED) +{ + struct zn_surface_snode *self = + zn_container_of(listener, self, surface_commit_listener); + + zn_surface_snode_commit_damage(self); + + zn_surface_snode_update_child_subsurfaces_position(self); +} + +static void +zn_surface_snode_handle_surface_destroy( + struct wl_listener *listener, void *user_data UNUSED) +{ + struct zn_surface_snode *self = + zn_container_of(listener, self, surface_destroy_listener); + + zn_surface_snode_destroy(self); +} + void zn_surface_snode_commit_damage(struct zn_surface_snode *self) { @@ -116,7 +197,7 @@ zn_surface_snode_commit_damage(struct zn_surface_snode *self) .height = rects[i].y2 - rects[i].y1, }; - zn_snode_damage(self->snode, &damage_fbox); + zn_snode_damage(self->surface_node, &damage_fbox); } pixman_region32_fini(&damage); @@ -125,17 +206,7 @@ zn_surface_snode_commit_damage(struct zn_surface_snode *self) void zn_surface_snode_damage_whole(struct zn_surface_snode *self) { - zn_snode_damage_whole(self->snode); -} - -static void -zn_surface_snode_handle_surface_destroy( - struct wl_listener *listener, void *user_data UNUSED) -{ - struct zn_surface_snode *self = - zn_container_of(listener, self, surface_destroy_listener); - - zn_surface_snode_destroy(self); + zn_snode_damage_whole(self->surface_node); } struct zn_surface_snode * @@ -149,19 +220,81 @@ zn_surface_snode_create(struct wlr_surface *surface) self->surface = surface; wl_signal_init(&self->events.destroy); + surface->data = self; - self->snode = zn_snode_create(self, &implementation); + self->snode = zn_snode_create(self, &zn_snode_noop_implementation); if (self->snode == NULL) { zn_error("Failed to create a snode"); goto err_free; } + self->surface_node = zn_snode_create(self, &implementation); + if (self->surface_node == NULL) { + zn_error("Failed to create a surface snode"); + goto err_snode; + } + + self->subsurfaces_above_node = + zn_snode_create(self, &zn_snode_noop_implementation); + if (self->subsurfaces_above_node == NULL) { + zn_error("Failed to create an above subsurfaces node"); + goto err_surface_node; + } + + self->subsurfaces_below_node = + zn_snode_create(self, &zn_snode_noop_implementation); + if (self->subsurfaces_below_node == NULL) { + zn_error("Failed to create an below subsurface node"); + goto err_subsurface_above_node; + } + self->surface_destroy_listener.notify = zn_surface_snode_handle_surface_destroy; wl_signal_add(&surface->events.destroy, &self->surface_destroy_listener); + self->new_subsurface_listener.notify = zn_surface_snode_handle_new_subsurface; + wl_signal_add( + &surface->events.new_subsurface, &self->new_subsurface_listener); + + self->surface_commit_listener.notify = zn_surface_snode_handle_commit; + wl_signal_add(&self->surface->events.commit, &self->surface_commit_listener); + + zn_snode_set_position( + self->subsurfaces_below_node, self->snode, GLM_VEC2_ZERO); + zn_snode_set_position(self->surface_node, self->snode, GLM_VEC2_ZERO); + zn_snode_set_position( + self->subsurfaces_above_node, self->snode, GLM_VEC2_ZERO); + + struct wlr_subsurface *subsurface = NULL; + wl_list_for_each ( + subsurface, &self->surface->current.subsurfaces_below, current.link) { + struct zn_surface_snode *surface_snode = + zn_surface_snode_create(subsurface->surface); + zn_snode_set_position( + surface_snode->snode, self->subsurfaces_below_node, GLM_VEC2_ZERO); + } + + wl_list_for_each ( + subsurface, &self->surface->current.subsurfaces_above, current.link) { + struct zn_surface_snode *surface_snode = + zn_surface_snode_create(subsurface->surface); + zn_snode_set_position( + surface_snode->snode, self->subsurfaces_above_node, GLM_VEC2_ZERO); + } + + zn_surface_snode_update_child_subsurfaces_position(self); + return self; +err_subsurface_above_node: + zn_snode_destroy(self->subsurfaces_above_node); + +err_surface_node: + zn_snode_destroy(self->surface_node); + +err_snode: + zn_snode_destroy(self->snode); + err_free: free(self); @@ -174,7 +307,12 @@ zn_surface_snode_destroy(struct zn_surface_snode *self) { zn_signal_emit_mutable(&self->events.destroy, NULL); + zn_snode_destroy(self->subsurfaces_below_node); + zn_snode_destroy(self->subsurfaces_above_node); + zn_snode_destroy(self->surface_node); zn_snode_destroy(self->snode); + wl_list_remove(&self->new_subsurface_listener.link); + wl_list_remove(&self->surface_commit_listener.link); wl_list_remove(&self->surface_destroy_listener.link); wl_list_remove(&self->events.destroy.listener_list); diff --git a/zen/src/backend/screen/surface-snode.h b/zen/src/backend/screen/surface-snode.h index 5bf1c378..62feb120 100644 --- a/zen/src/backend/screen/surface-snode.h +++ b/zen/src/backend/screen/surface-snode.h @@ -6,10 +6,15 @@ struct zn_snode; // Lifetime is identical with given wlr_surface struct zn_surface_snode { - struct zn_snode *snode; // @nonnull, @owning + struct zn_snode *snode; // @nonnull, @owning + struct zn_snode *surface_node; // @nonnull, @owning + struct zn_snode *subsurfaces_below_node; // @nonnull, @owning + struct zn_snode *subsurfaces_above_node; // @nonnull, @owning struct wlr_surface *surface; // @nonnull, @outlive + struct wl_listener new_subsurface_listener; + struct wl_listener surface_commit_listener; struct wl_listener surface_destroy_listener; struct { diff --git a/zen/src/backend/screen/xdg-decoration.c b/zen/src/backend/screen/xdg-decoration.c index 248ad2ff..4e9503af 100644 --- a/zen/src/backend/screen/xdg-decoration.c +++ b/zen/src/backend/screen/xdg-decoration.c @@ -25,7 +25,7 @@ zn_xdg_decoration_handle_request_mode( // TODO(@Aki-7): make this configurable from the desktop component enum wlr_xdg_toplevel_decoration_v1_mode mode = - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; enum wlr_xdg_toplevel_decoration_v1_mode client_mode = self->wlr_decoration->requested_mode; diff --git a/zen/src/backend/screen/xdg-toplevel.c b/zen/src/backend/screen/xdg-toplevel.c index 3d0d9981..54767f8e 100644 --- a/zen/src/backend/screen/xdg-toplevel.c +++ b/zen/src/backend/screen/xdg-toplevel.c @@ -81,9 +81,7 @@ zn_xdg_toplevel_update_surface_position(struct zn_xdg_toplevel *self) struct zn_snode *snode = self->surface_snode->snode; vec2 position = {(float)-geometry.x, (float)-geometry.y}; - if (!glm_vec2_eqv(snode->position, position)) { - zn_snode_set_position(snode, snode->parent, position); - } + zn_snode_change_position(snode, position); } static void @@ -109,7 +107,7 @@ zn_xdg_toplevel_update_view_decoration( mode = ZN_VIEW_DECORATION_MODE_SERVER_SIDE; break; case WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE: - mode = ZN_VIEW_DECORATION_MODE_SERVER_SIDE; + mode = ZN_VIEW_DECORATION_MODE_CLIENT_SIDE; break; } diff --git a/zen/src/snode.c b/zen/src/snode.c index 72e580a4..4f229a84 100644 --- a/zen/src/snode.c +++ b/zen/src/snode.c @@ -179,7 +179,10 @@ zn_snode_move_front(struct zn_snode *self) return; } - zn_snode_set_position(self, self->parent, self->position); + struct zn_snode *front = + zn_container_of(self->parent->child_node_list.prev, front, link); + + zn_snode_place_above(self, front); } void @@ -196,6 +199,10 @@ void zn_snode_set_position( struct zn_snode *self, struct zn_snode *parent, vec2 position) { + if (self->parent == parent && glm_vec2_eqv(self->position, position)) { + return; + } + zn_snode_damage_whole(self); if (self->parent) { @@ -225,6 +232,71 @@ zn_snode_set_position( wl_signal_emit(&self->events.position_changed, NULL); } +void +zn_snode_change_position(struct zn_snode *self, vec2 position) +{ + if (self->parent == NULL) { + return; + } + + if (glm_vec2_eqv(self->position, position)) { + return; + } + + zn_snode_damage_whole(self); + + glm_vec2_copy(position, self->position); + + zn_snode_update_absolute_position(self); + + zn_snode_damage_whole(self); + + wl_signal_emit(&self->events.position_changed, NULL); +} + +static void +zn_snode_place_next_to( + struct zn_snode *self, struct zn_snode *sibling, bool above) +{ + if (!zn_assert(self->parent, "snode should have a parent")) { + return; + } + + if (!zn_assert(self->parent == sibling->parent, + "self and sibling should have the same parent")) { + return; + } + + if (self == sibling) { + return; + } + + struct wl_list *link = above ? &sibling->link : sibling->link.prev; + + if (&self->link == link->next) { + return; + } + + wl_list_remove(&self->link); + wl_list_insert(link, &self->link); + + zn_snode_damage_whole(self); + + wl_signal_emit(&self->events.position_changed, NULL); +} + +void +zn_snode_place_above(struct zn_snode *self, struct zn_snode *sibling) +{ + zn_snode_place_next_to(self, sibling, true); +} + +void +zn_snode_place_below(struct zn_snode *self, struct zn_snode *sibling) +{ + zn_snode_place_next_to(self, sibling, false); +} + struct wlr_texture * zn_snode_get_texture(struct zn_snode *self) { diff --git a/zen/src/view.c b/zen/src/view.c index 22c7db16..a25d0e42 100644 --- a/zen/src/view.c +++ b/zen/src/view.c @@ -86,7 +86,7 @@ zn_view_create(void *impl_data, const struct zn_view_interface *implementation) self->impl_data = impl_data; self->impl = implementation; - self->decoration_mode = ZN_VIEW_DECORATION_MODE_SERVER_SIDE; + self->decoration_mode = ZN_VIEW_DECORATION_MODE_CLIENT_SIDE; wl_signal_init(&self->events.resized); wl_signal_init(&self->events.unmap); diff --git a/zen/tests/snode/snode-damage.c b/zen/tests/snode/snode-damage.c index 86ea1607..1ca9bd9b 100644 --- a/zen/tests/snode/snode-damage.c +++ b/zen/tests/snode/snode-damage.c @@ -171,3 +171,111 @@ TEST(damage) zn_snode_damage(node4, &(struct wlr_fbox){10, 30, 10, 10}); ASSERT_EQUAL_BOOL(false, pixman_region32_not_empty(&output->damage)); } + +TEST(change_position) +{ + struct zn_mock_output *output = zn_mock_output_create(0, 0); + + struct wlr_texture texture; + texture.width = 50; + texture.height = 50; + + struct zn_snode *root = zn_snode_create_root(output->screen); + + struct zn_snode *node1 = zn_snode_create(&texture, &test_impl); + struct zn_snode *node2 = zn_snode_create(&texture, &test_impl); + struct zn_snode *node3 = zn_snode_create(&texture, &test_impl); + + zn_snode_set_position(node3, node2, (vec2){200, 100}); + zn_snode_set_position(node2, node1, (vec2){100, 200}); + zn_snode_set_position(node1, root, (vec2){100, 100}); + + zn_mock_output_damage_clear(output); + + zn_snode_change_position(node1, (vec2){-100, -100}); + + ASSERT_EQUAL_BOOL(true, zn_mock_output_damage_contains(output, + 100 + 100 + 200 + 25, 100 + 200 + 100 + 25)); + ASSERT_EQUAL_BOOL(true, + zn_mock_output_damage_contains(output, 100 + 100 + 25, 100 + 200 + 25)); + ASSERT_EQUAL_BOOL( + true, zn_mock_output_damage_contains(output, 100 + 25, 100 + 25)); + ASSERT_EQUAL_BOOL( + false, zn_mock_output_damage_contains(output, 100 - 25, 100 - 25)); + + ASSERT_EQUAL_BOOL(true, zn_mock_output_damage_contains(output, + -100 + 100 + 200 + 25, -100 + 200 + 100 + 25)); + ASSERT_EQUAL_BOOL(true, + zn_mock_output_damage_contains(output, -100 + 100 + 25, -100 + 200 + 25)); + ASSERT_EQUAL_BOOL( + true, zn_mock_output_damage_contains(output, -100 + 25, -100 + 25)); + ASSERT_EQUAL_BOOL( + false, zn_mock_output_damage_contains(output, -100 - 25, -100 - 25)); +} + +TEST(set_next_to) +{ + struct zn_mock_output *output = zn_mock_output_create(0, 0); + + struct wlr_texture texture; + texture.width = 50; + texture.height = 50; + + struct zn_snode *root = zn_snode_create_root(output->screen); + + struct zn_snode *node1 = zn_snode_create(&texture, &test_impl); + struct zn_snode *node11 = zn_snode_create(&texture, &test_impl); + struct zn_snode *node12 = zn_snode_create(&texture, &test_impl); + + zn_snode_set_position(node1, root, (vec2){100, 100}); + zn_snode_set_position(node12, node1, (vec2){100, 200}); + zn_snode_set_position(node11, node1, (vec2){200, 100}); + + zn_mock_output_damage_clear(output); + + zn_snode_place_below(node11, node12); + + ASSERT_EQUAL_BOOL(true, + zn_mock_output_damage_contains(output, 100 + 200 + 25, 100 + 100 + 25)); + ASSERT_EQUAL_BOOL(false, + zn_mock_output_damage_contains(output, 100 + 100 + 25, 100 + 200 + 25)); +} + +TEST(no_damage) +{ + struct zn_mock_output *output = zn_mock_output_create(0, 0); + + struct wlr_texture texture; + texture.width = 50; + texture.height = 50; + + struct zn_snode *root = zn_snode_create_root(output->screen); + + struct zn_snode *node1 = zn_snode_create(&texture, &test_impl); + struct zn_snode *node11 = zn_snode_create(&texture, &test_impl); + struct zn_snode *node12 = zn_snode_create(&texture, &test_impl); + + zn_snode_set_position(node1, root, (vec2){100, 100}); + zn_snode_set_position(node12, node1, (vec2){100, 200}); + zn_snode_set_position(node11, node1, (vec2){200, 100}); + + zn_mock_output_damage_clear(output); + + ASSERT_EQUAL_BOOL(false, pixman_region32_not_empty(&output->damage)); + + zn_snode_set_position(node1, root, (vec2){100, 100}); + + ASSERT_EQUAL_BOOL(false, pixman_region32_not_empty(&output->damage)); + + zn_snode_change_position(node11, (vec2){200, 100}); + + ASSERT_EQUAL_BOOL(false, pixman_region32_not_empty(&output->damage)); + + zn_snode_place_above(node11, node12); + + ASSERT_EQUAL_BOOL(false, pixman_region32_not_empty(&output->damage)); + + zn_snode_place_above(node12, node11); + + ASSERT_EQUAL_BOOL(true, pixman_region32_not_empty(&output->damage)); +} diff --git a/zen/tests/snode/snode-position.c b/zen/tests/snode/snode-position.c index 086ccedf..1e1e87e9 100644 --- a/zen/tests/snode/snode-position.c +++ b/zen/tests/snode/snode-position.c @@ -78,3 +78,86 @@ TEST(parent_change) ASSERT_EQUAL_DOUBLE(3 + 4, box4.x); ASSERT_EQUAL_DOUBLE(0.3F + 0.4F, box4.y); } + +TEST(change_position) +{ + struct zn_snode *root = zn_snode_create(NULL, &zn_snode_noop_implementation); + + struct zn_snode *node1 = zn_snode_create(NULL, &zn_snode_noop_implementation); + struct zn_snode *node2 = zn_snode_create(NULL, &zn_snode_noop_implementation); + struct zn_snode *node3 = zn_snode_create(NULL, &zn_snode_noop_implementation); + struct zn_snode *node4 = zn_snode_create(NULL, &zn_snode_noop_implementation); + + zn_snode_set_position(node4, node3, (vec2){4, 0.4F}); + zn_snode_set_position(node3, node2, (vec2){3, 0.3F}); + zn_snode_set_position(node2, node1, (vec2){2, 0.2F}); + zn_snode_set_position(node1, root, (vec2){1, 0.1F}); + + struct wlr_fbox box4; + zn_snode_get_fbox(node4, &box4); + + ASSERT_EQUAL_DOUBLE(1 + 2 + 3 + 4, box4.x); + ASSERT_EQUAL_DOUBLE(0.1F + 0.2F + 0.3F + 0.4F, box4.y); + + zn_snode_change_position(node2, (vec2){12, 1.2F}); + zn_snode_get_fbox(node4, &box4); + + ASSERT_EQUAL_DOUBLE(1 + 12 + 3 + 4, box4.x); + ASSERT_EQUAL_DOUBLE(0.1F + 1.2F + 0.3F + 0.4F, box4.y); +} + +TEST(set_next_to) +{ + struct zn_snode *root = zn_snode_create(NULL, &zn_snode_noop_implementation); + + struct zn_snode *node1 = zn_snode_create(NULL, &zn_snode_noop_implementation); + struct zn_snode *node11 = + zn_snode_create(NULL, &zn_snode_noop_implementation); + struct zn_snode *node12 = + zn_snode_create(NULL, &zn_snode_noop_implementation); + struct zn_snode *node13 = + zn_snode_create(NULL, &zn_snode_noop_implementation); + + zn_snode_set_position(node1, root, (vec2){1, 0.1F}); + zn_snode_set_position(node13, node1, (vec2){4, 0.4F}); + zn_snode_set_position(node12, node1, (vec2){3, 0.3F}); + zn_snode_set_position(node11, node1, (vec2){2, 0.2F}); + + struct wlr_fbox box11; + zn_snode_get_fbox(node11, &box11); + + ASSERT_EQUAL_DOUBLE(1 + 2, box11.x); + ASSERT_EQUAL_DOUBLE(0.1F + 0.2F, box11.y); + ASSERT_EQUAL_POINTER(&node11->link, node12->link.next); + + zn_snode_place_above(node11, node13); + zn_snode_get_fbox(node11, &box11); + + ASSERT_EQUAL_DOUBLE(1 + 2, box11.x); + ASSERT_EQUAL_DOUBLE(0.1F + 0.2F, box11.y); + ASSERT_EQUAL_POINTER(&node11->link, node13->link.next); + + zn_snode_place_below(node11, node13); + zn_snode_get_fbox(node11, &box11); + + ASSERT_EQUAL_DOUBLE(1 + 2, box11.x); + ASSERT_EQUAL_DOUBLE(0.1F + 0.2F, box11.y); + ASSERT_EQUAL_POINTER(&node11->link, node13->link.prev); +} + +FAIL_TEST(set_next_to_not_sibling) +{ + struct zn_snode *root = zn_snode_create(NULL, &zn_snode_noop_implementation); + + struct zn_snode *node1 = zn_snode_create(NULL, &zn_snode_noop_implementation); + struct zn_snode *node2 = zn_snode_create(NULL, &zn_snode_noop_implementation); + struct zn_snode *node3 = zn_snode_create(NULL, &zn_snode_noop_implementation); + struct zn_snode *node4 = zn_snode_create(NULL, &zn_snode_noop_implementation); + + zn_snode_set_position(node4, node3, (vec2){4, 0.4F}); + zn_snode_set_position(node3, node2, (vec2){3, 0.3F}); + zn_snode_set_position(node2, node1, (vec2){2, 0.2F}); + zn_snode_set_position(node1, root, (vec2){1, 0.1F}); + + zn_snode_place_above(node1, node3); +} From 042097b957223ddf79f87535821ee8c4ff6b2017 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sat, 22 Jul 2023 20:10:15 +0900 Subject: [PATCH 42/49] organize zen apis --- zen/include/zen/binding.h | 25 ++------------------- zen/include/zen/screen.h | 14 ------------ zen/include/zen/view.h | 24 -------------------- zen/src/backend/screen/keyboard.c | 2 +- zen/src/backend/screen/output.c | 2 +- zen/src/backend/screen/xdg-toplevel.c | 2 +- zen/src/backend/screen/xwayland-surface.c | 2 +- zen/src/binding.c | 2 +- zen/src/binding.h | 26 ++++++++++++++++++++++ zen/src/screen.c | 2 +- zen/src/screen.h | 17 ++++++++++++++ zen/src/server.c | 2 +- zen/src/view.h | 27 +++++++++++++++++++++++ zen/tests/binding.c | 2 +- zen/tests/mock/src/output.c | 2 +- zen/tests/snode/snode-frame.c | 1 + 16 files changed, 82 insertions(+), 70 deletions(-) create mode 100644 zen/src/binding.h create mode 100644 zen/src/screen.h create mode 100644 zen/src/view.h diff --git a/zen/include/zen/binding.h b/zen/include/zen/binding.h index cee9eb9a..4d2f43bd 100644 --- a/zen/include/zen/binding.h +++ b/zen/include/zen/binding.h @@ -4,33 +4,12 @@ #include "zen/config.h" +struct zn_binding; + /// @return true if the key is used and should not be used any more typedef bool (*zn_binding_handler_t)( const char *name, uint32_t key, uint32_t modifiers, void *user_data); -struct zn_binding_item { - const char *name; // @nonnull, @outlive - uint32_t key; - uint32_t modifiers; - zn_binding_handler_t handler; // nonnull - void *user_data; -}; - -struct zn_binding { - struct wl_array items; // [zn_binding_item] -}; - /// @param name must be a string literal void zn_binding_add(struct zn_binding *self, const char *name, zn_binding_handler_t handler, void *user_data); - -/// @return true if the key is used and should not be used any more -/// @param modifiers is a bitfield of enum wlr_keyboard_modifier -bool zn_binding_handle_key( - struct zn_binding *self, uint32_t key, uint32_t modifiers); - -void zn_binding_remap(struct zn_binding *self); - -struct zn_binding *zn_binding_create(void); - -void zn_binding_destroy(struct zn_binding *self); diff --git a/zen/include/zen/screen.h b/zen/include/zen/screen.h index d3b7089e..863a2aeb 100644 --- a/zen/include/zen/screen.h +++ b/zen/include/zen/screen.h @@ -46,17 +46,3 @@ void zn_screen_set_layout_position( /// @param fbox : Effective coordinate system void zn_screen_damage(struct zn_screen *self, struct wlr_fbox *fbox); - -/// Called by the impl object -/// @param size : effective coords -void zn_screen_notify_resize(struct zn_screen *self, vec2 size); - -/// Called by the impl object -void zn_screen_notify_frame(struct zn_screen *self, struct timespec *when); - -/// Called by the impl object -struct zn_screen *zn_screen_create( - void *impl_data, const struct zn_screen_interface *implementation); - -/// Called by the impl object -void zn_screen_destroy(struct zn_screen *self); diff --git a/zen/include/zen/view.h b/zen/include/zen/view.h index 9b05c4f7..d35e4d7f 100644 --- a/zen/include/zen/view.h +++ b/zen/include/zen/view.h @@ -54,27 +54,3 @@ void zn_view_set_focus(struct zn_view *self, bool focused); void zn_view_configure_size(struct zn_view *self, vec2 size); void zn_view_close(struct zn_view *self); - -/// Called by the impl object -void zn_view_notify_resized(struct zn_view *self, vec2 size); - -/// Called by the impl object -void zn_view_notify_decoration( - struct zn_view *self, enum zn_view_decoration_mode mode); - -/// Called by the impl object -void zn_view_notify_move_request(struct zn_view *self); - -/// Called by the impl object -void zn_view_notify_resize_request( - struct zn_view *self, struct zn_view_resize_event *event); - -/// Called by the impl object -void zn_view_notify_unmap(struct zn_view *self); - -/// Called by the impl object -struct zn_view *zn_view_create( - void *impl_data, const struct zn_view_interface *implementation); - -/// Called by the impl object -void zn_view_destroy(struct zn_view *self); diff --git a/zen/src/backend/screen/keyboard.c b/zen/src/backend/screen/keyboard.c index c9881ea5..bce4f9fd 100644 --- a/zen/src/backend/screen/keyboard.c +++ b/zen/src/backend/screen/keyboard.c @@ -5,11 +5,11 @@ #include #include +#include "binding.h" #include "default-backend.h" #include "zen-common/log.h" #include "zen-common/terminate.h" #include "zen-common/util.h" -#include "zen/binding.h" #include "zen/seat.h" #include "zen/server.h" diff --git a/zen/src/backend/screen/output.c b/zen/src/backend/screen/output.c index bae0a628..7783b40d 100644 --- a/zen/src/backend/screen/output.c +++ b/zen/src/backend/screen/output.c @@ -14,10 +14,10 @@ #include "compositor.h" #include "default-backend.h" #include "layer-shell.h" +#include "screen.h" #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" -#include "zen/screen.h" #include "zen/server.h" #include "zen/snode.h" diff --git a/zen/src/backend/screen/xdg-toplevel.c b/zen/src/backend/screen/xdg-toplevel.c index 54767f8e..c5e362af 100644 --- a/zen/src/backend/screen/xdg-toplevel.c +++ b/zen/src/backend/screen/xdg-toplevel.c @@ -4,13 +4,13 @@ #include "default-backend.h" #include "surface-snode.h" +#include "view.h" #include "xdg-decoration.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen/seat.h" #include "zen/server.h" #include "zen/snode.h" -#include "zen/view.h" static void zn_xdg_toplevel_destroy(struct zn_xdg_toplevel *self); diff --git a/zen/src/backend/screen/xwayland-surface.c b/zen/src/backend/screen/xwayland-surface.c index 9f06a13e..cd31d4c6 100644 --- a/zen/src/backend/screen/xwayland-surface.c +++ b/zen/src/backend/screen/xwayland-surface.c @@ -4,12 +4,12 @@ #include "default-backend.h" #include "surface-snode.h" +#include "view.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen/seat.h" #include "zen/server.h" #include "zen/snode.h" -#include "zen/view.h" static void zn_xwayland_surface_destroy(struct zn_xwayland_surface *self); diff --git a/zen/src/binding.c b/zen/src/binding.c index a619b1c5..c6d103db 100644 --- a/zen/src/binding.c +++ b/zen/src/binding.c @@ -1,4 +1,4 @@ -#include "zen/binding.h" +#include "binding.h" #include #include diff --git a/zen/src/binding.h b/zen/src/binding.h new file mode 100644 index 00000000..de2d21e2 --- /dev/null +++ b/zen/src/binding.h @@ -0,0 +1,26 @@ +#pragma once + +#include "zen/binding.h" + +struct zn_binding_item { + const char *name; // @nonnull, @outlive + uint32_t key; + uint32_t modifiers; + zn_binding_handler_t handler; // nonnull + void *user_data; +}; + +struct zn_binding { + struct wl_array items; // [zn_binding_item] +}; + +/// @return true if the key is used and should not be used any more +/// @param modifiers is a bitfield of enum wlr_keyboard_modifier +bool zn_binding_handle_key( + struct zn_binding *self, uint32_t key, uint32_t modifiers); + +void zn_binding_remap(struct zn_binding *self); + +struct zn_binding *zn_binding_create(void); + +void zn_binding_destroy(struct zn_binding *self); diff --git a/zen/src/screen.c b/zen/src/screen.c index e811ca55..03362aba 100644 --- a/zen/src/screen.c +++ b/zen/src/screen.c @@ -1,4 +1,4 @@ -#include "zen/screen.h" +#include "screen.h" #include #include diff --git a/zen/src/screen.h b/zen/src/screen.h new file mode 100644 index 00000000..3e770ba6 --- /dev/null +++ b/zen/src/screen.h @@ -0,0 +1,17 @@ +#pragma once + +#include "zen/screen.h" + +/// Called by the impl object +/// @param size : effective coords +void zn_screen_notify_resize(struct zn_screen *self, vec2 size); + +/// Called by the impl object +void zn_screen_notify_frame(struct zn_screen *self, struct timespec *when); + +/// Called by the impl object +struct zn_screen *zn_screen_create( + void *impl_data, const struct zn_screen_interface *implementation); + +/// Called by the impl object +void zn_screen_destroy(struct zn_screen *self); diff --git a/zen/src/server.c b/zen/src/server.c index a5ebaf68..b4e99888 100644 --- a/zen/src/server.c +++ b/zen/src/server.c @@ -6,11 +6,11 @@ #include #include "backend.h" +#include "binding.h" #include "seat.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen/backend.h" -#include "zen/binding.h" #include "zen/config.h" // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) diff --git a/zen/src/view.h b/zen/src/view.h new file mode 100644 index 00000000..78f7e0aa --- /dev/null +++ b/zen/src/view.h @@ -0,0 +1,27 @@ +#pragma once + +#include "zen/view.h" + +/// Called by the impl object +void zn_view_notify_resized(struct zn_view *self, vec2 size); + +/// Called by the impl object +void zn_view_notify_decoration( + struct zn_view *self, enum zn_view_decoration_mode mode); + +/// Called by the impl object +void zn_view_notify_move_request(struct zn_view *self); + +/// Called by the impl object +void zn_view_notify_resize_request( + struct zn_view *self, struct zn_view_resize_event *event); + +/// Called by the impl object +void zn_view_notify_unmap(struct zn_view *self); + +/// Called by the impl object +struct zn_view *zn_view_create( + void *impl_data, const struct zn_view_interface *implementation); + +/// Called by the impl object +void zn_view_destroy(struct zn_view *self); diff --git a/zen/tests/binding.c b/zen/tests/binding.c index 832bf39e..438ff3c8 100644 --- a/zen/tests/binding.c +++ b/zen/tests/binding.c @@ -1,4 +1,4 @@ -#include "zen/binding.h" +#include "binding.h" #include diff --git a/zen/tests/mock/src/output.c b/zen/tests/mock/src/output.c index a4978478..652f20e2 100644 --- a/zen/tests/mock/src/output.c +++ b/zen/tests/mock/src/output.c @@ -3,8 +3,8 @@ #include #include +#include "screen.h" #include "zen-common/util.h" -#include "zen/screen.h" #include "zen/snode.h" static void diff --git a/zen/tests/snode/snode-frame.c b/zen/tests/snode/snode-frame.c index 5ffc11e0..9710b3d0 100644 --- a/zen/tests/snode/snode-frame.c +++ b/zen/tests/snode/snode-frame.c @@ -2,6 +2,7 @@ #include #include "mock/output.h" +#include "screen.h" #include "test-harness.h" #include "zen-common/util.h" #include "zen/snode.h" From 56f77cba8256d980690543483c1573cab7bcb917 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 23 Jul 2023 14:39:07 +0900 Subject: [PATCH 43/49] snode root --- desktop/src/cursor-grab.c | 22 +++++------- desktop/src/cursor-grab/default.c | 10 +++--- desktop/src/cursor-grab/down.c | 3 +- desktop/src/cursor-grab/move.c | 11 +++--- desktop/src/screen.c | 15 ++++---- desktop/src/shell.c | 15 ++++++++ zen/include/zen/screen.h | 5 ++- zen/include/zen/snode-root.h | 35 +++++++++++++++++++ zen/include/zen/snode.h | 11 +++--- zen/meson.build | 1 + zen/src/backend/screen/output.c | 3 +- zen/src/backend/screen/xwayland-surface.c | 6 ++-- zen/src/screen.c | 41 +++++++++++++++++++--- zen/src/seat.c | 11 +++--- zen/src/snode-root.c | 42 +++++++++++++++++++++++ zen/src/snode.c | 32 ++++++++--------- zen/tests/snode/snode-damage.c | 15 ++++---- zen/tests/snode/snode-frame.c | 3 +- zen/tests/snode/snode-get-at.c | 3 +- 19 files changed, 209 insertions(+), 75 deletions(-) create mode 100644 zen/include/zen/snode-root.h create mode 100644 zen/src/snode-root.c diff --git a/desktop/src/cursor-grab.c b/desktop/src/cursor-grab.c index 525b4477..a43b7312 100644 --- a/desktop/src/cursor-grab.c +++ b/desktop/src/cursor-grab.c @@ -17,24 +17,20 @@ zn_cursor_grab_move_relative(vec2 delta) struct zn_server *server = zn_server_get_singleton(); struct zn_desktop_shell *shell = zn_desktop_shell_get_singleton(); struct zn_cursor *cursor = server->seat->cursor; + struct zn_screen *screen = zn_screen_from_snode_root(cursor->snode->root); + struct zn_desktop_screen *desktop_screen = - cursor->snode->screen ? zn_desktop_screen_get(cursor->snode->screen) - : NULL; - vec2 position; + screen ? zn_desktop_screen_get(screen) : NULL; if (desktop_screen == NULL) { - desktop_screen = zn_screen_layout_get_main_screen(shell->screen_layout); + return; + } - if (!desktop_screen) { - return; - } + vec2 position; - glm_vec2_divs(desktop_screen->screen->size, 2, position); - } else { - glm_vec2_add(cursor->snode->position, delta, position); - zn_screen_layout_get_closest_position(shell->screen_layout, desktop_screen, - position, &desktop_screen, position); - } + glm_vec2_add(cursor->snode->position, delta, position); + zn_screen_layout_get_closest_position(shell->screen_layout, desktop_screen, + position, &desktop_screen, position); zn_snode_set_position(cursor->snode, desktop_screen->cursor_layer, position); } diff --git a/desktop/src/cursor-grab/default.c b/desktop/src/cursor-grab/default.c index 4956d75d..577d6133 100644 --- a/desktop/src/cursor-grab/default.c +++ b/desktop/src/cursor-grab/default.c @@ -9,6 +9,7 @@ #include "zen/screen.h" #include "zen/seat.h" #include "zen/server.h" +#include "zen/snode-root.h" #include "zen/snode.h" static void zn_cursor_default_grab_destroy(struct zn_cursor_default_grab *self); @@ -26,16 +27,17 @@ zn_cursor_default_grab_handle_motion_relative( { struct zn_server *server = zn_server_get_singleton(); struct zn_cursor *cursor = server->seat->cursor; + struct zn_screen *screen = zn_screen_from_snode_root(cursor->snode->root); zn_cursor_grab_move_relative(delta); - if (cursor->snode->screen == NULL) { + if (screen == NULL) { return; } vec2 point = GLM_VEC2_ZERO_INIT; struct zn_snode *snode = zn_snode_get_snode_at( - cursor->snode->screen->snode_root, cursor->snode->position, point); + screen->snode_root->node, cursor->snode->position, point); zn_seat_pointer_enter(server->seat, snode, point); @@ -48,13 +50,13 @@ zn_cursor_default_grab_handle_rebase(struct zn_cursor_grab *grab UNUSED) struct zn_server *server = zn_server_get_singleton(); struct zn_cursor *cursor = server->seat->cursor; - if (cursor->snode->screen == NULL) { + if (cursor->snode->root == NULL) { return; } vec2 point = GLM_VEC2_ZERO_INIT; struct zn_snode *snode = zn_snode_get_snode_at( - cursor->snode->screen->snode_root, cursor->snode->position, point); + cursor->snode->root->node, cursor->snode->position, point); zn_seat_pointer_enter(server->seat, snode, point); } diff --git a/desktop/src/cursor-grab/down.c b/desktop/src/cursor-grab/down.c index 707173ff..9eb70d9f 100644 --- a/desktop/src/cursor-grab/down.c +++ b/desktop/src/cursor-grab/down.c @@ -30,7 +30,8 @@ zn_cursor_down_grab_handle_motion_relative( zn_cursor_grab_move_relative(delta); - if (focus == NULL || focus->screen == NULL || cursor->snode->screen == NULL) { + if (focus == NULL || zn_screen_from_snode_root(focus->root) == NULL || + zn_screen_from_snode_root(cursor->snode->root) == NULL) { return; } diff --git a/desktop/src/cursor-grab/move.c b/desktop/src/cursor-grab/move.c index e97c5ea7..cb701f9c 100644 --- a/desktop/src/cursor-grab/move.c +++ b/desktop/src/cursor-grab/move.c @@ -8,8 +8,10 @@ #include "zen-desktop/shell.h" #include "zen-desktop/view.h" #include "zen/cursor.h" +#include "zen/screen.h" #include "zen/seat.h" #include "zen/server.h" +#include "zen/snode-root.h" #include "zen/snode.h" static void zn_cursor_move_grab_destroy(struct zn_cursor_move_grab *self); @@ -27,23 +29,24 @@ zn_cursor_move_grab_handle_motion_relative( { struct zn_server *server = zn_server_get_singleton(); struct zn_cursor *cursor = server->seat->cursor; + struct zn_screen *screen = zn_screen_from_snode_root(cursor->snode->root); struct zn_cursor_move_grab *self = zn_cursor_move_grab_get(grab); vec2 new_position; zn_cursor_grab_move_relative(delta); - if (cursor->snode->screen == NULL) { + if (screen == NULL) { return; } - struct zn_desktop_screen *screen = - zn_desktop_screen_get(cursor->snode->screen); + struct zn_desktop_screen *desktop_screen = zn_desktop_screen_get(screen); glm_vec2_add(cursor->snode->position, self->initial_view_cursor_position, new_position); - zn_snode_set_position(self->view->snode, screen->view_layer, new_position); + zn_snode_set_position( + self->view->snode, desktop_screen->view_layer, new_position); } static void diff --git a/desktop/src/screen.c b/desktop/src/screen.c index 1a686615..c32ca64b 100644 --- a/desktop/src/screen.c +++ b/desktop/src/screen.c @@ -7,6 +7,7 @@ #include "zen-desktop/screen-layout.h" #include "zen-desktop/shell.h" #include "zen/screen.h" +#include "zen/snode-root.h" #include "zen/snode.h" static void zn_desktop_screen_destroy(struct zn_desktop_screen *self); @@ -77,15 +78,17 @@ zn_desktop_screen_create(struct zn_screen *screen) } zn_snode_set_position(screen->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - screen->snode_root, GLM_VEC2_ZERO); + screen->snode_root->node, GLM_VEC2_ZERO); zn_snode_set_position(screen->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - screen->snode_root, GLM_VEC2_ZERO); - zn_snode_set_position(self->view_layer, screen->snode_root, GLM_VEC2_ZERO); + screen->snode_root->node, GLM_VEC2_ZERO); + zn_snode_set_position( + self->view_layer, screen->snode_root->node, GLM_VEC2_ZERO); zn_snode_set_position(screen->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - screen->snode_root, GLM_VEC2_ZERO); + screen->snode_root->node, GLM_VEC2_ZERO); zn_snode_set_position(screen->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - screen->snode_root, GLM_VEC2_ZERO); - zn_snode_set_position(self->cursor_layer, screen->snode_root, GLM_VEC2_ZERO); + screen->snode_root->node, GLM_VEC2_ZERO); + zn_snode_set_position( + self->cursor_layer, screen->snode_root->node, GLM_VEC2_ZERO); self->screen_destroy_listener.notify = zn_desktop_screen_handle_screen_destroy; diff --git a/desktop/src/shell.c b/desktop/src/shell.c index 8014cdc7..ffa98328 100644 --- a/desktop/src/shell.c +++ b/desktop/src/shell.c @@ -14,6 +14,7 @@ #include "zen-desktop/xr-system.h" #include "zen/backend.h" #include "zen/bounded.h" +#include "zen/cursor.h" #include "zen/screen.h" #include "zen/seat.h" #include "zen/server.h" @@ -44,6 +45,20 @@ zn_desktop_shell_handle_new_screen(struct wl_listener *listener, void *data) struct zn_desktop_screen *desktop_screen = zn_desktop_screen_create(screen); zn_screen_layout_add(self->screen_layout, desktop_screen); + + struct zn_server *server = zn_server_get_singleton(); + struct zn_cursor *cursor = server->seat->cursor; + + // FIXME(@Aki-7): when it's immersive display system, the cursor should not + // appear on the screen + if (cursor->snode->root == NULL) { + vec2 position; + + glm_vec2_divs(desktop_screen->screen->size, 2.0F, position); + + zn_snode_set_position( + cursor->snode, desktop_screen->cursor_layer, position); + } } static void diff --git a/zen/include/zen/screen.h b/zen/include/zen/screen.h index 863a2aeb..f0a78c1f 100644 --- a/zen/include/zen/screen.h +++ b/zen/include/zen/screen.h @@ -22,7 +22,7 @@ struct zn_screen { void *user_data; // @nonnull, @outlive if exists - struct zn_snode *snode_root; // @nonnull, @owning + struct zn_snode_root *snode_root; // @nonnull, @owning // These layers do not have a parent at first, user must set a parent to show // them. User must not add children to these layers. @@ -41,6 +41,9 @@ struct zn_screen { } events; }; +/// @return value can be NULL +struct zn_screen *zn_screen_from_snode_root(struct zn_snode_root *snode_root); + void zn_screen_set_layout_position( struct zn_screen *self, vec2 layout_position); diff --git a/zen/include/zen/snode-root.h b/zen/include/zen/snode-root.h new file mode 100644 index 00000000..44312ad0 --- /dev/null +++ b/zen/include/zen/snode-root.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include "zen-common/util.h" + +struct zn_snode_root_interface { + void (*damage)(void *user_data, struct wlr_fbox *fbox); + void (*layout_position)(void *user_data, vec2 position); +}; + +struct zn_snode_root { + void *user_data; // @nullable, @outlive if exists + const struct zn_snode_root_interface *impl; // @nonnull, @outlive + + struct zn_snode *node; // @nonnull, @owning +}; + +UNUSED static void +zn_snode_root_damage(struct zn_snode_root *self, struct wlr_fbox *fbox) +{ + self->impl->damage(self->user_data, fbox); +} + +UNUSED static void +zn_snode_root_layout_position(struct zn_snode_root *self, vec2 position) +{ + self->impl->layout_position(self->user_data, position); +} + +struct zn_snode_root *zn_snode_root_create( + void *user_data, const struct zn_snode_root_interface *implementation); + +void zn_snode_root_destroy(struct zn_snode_root *self); diff --git a/zen/include/zen/snode.h b/zen/include/zen/snode.h index 947cbf69..60447820 100644 --- a/zen/include/zen/snode.h +++ b/zen/include/zen/snode.h @@ -8,6 +8,8 @@ #include "zen-common/util.h" +struct zn_snode_root; + enum zn_snode_flag { ZN_SNODE_FLAG_FOCUSABLE = 1 << 0, }; @@ -80,10 +82,9 @@ struct zn_snode { uint32_t flags; // a bitfield of enum zn_snode_flag - // When the screen is destroyed, the root snode is destroyed and - // `position_changed` signal handler will set this NULL. - // For root snode, this is @outlive - struct zn_screen *screen; // @nullable, @ref + // When the root is destroyed, `position_changed` signal handler will set this + // NULL. + struct zn_snode_root *root; // @nullable, @ref struct wl_list child_node_list; // zn_snode::link, sorted from back to front struct wl_list link; // zn_snode::child_node_list @@ -205,6 +206,4 @@ struct zn_snode *zn_snode_create( struct zn_snode *zn_snode_create_focusable( void *user_data, const struct zn_snode_interface *implementation); -struct zn_snode *zn_snode_create_root(struct zn_screen *screen); - void zn_snode_destroy(struct zn_snode *self); diff --git a/zen/meson.build b/zen/meson.build index 3042030f..8781684a 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -15,6 +15,7 @@ _zen_srcs = [ 'src/seat.c', 'src/server.c', 'src/snode.c', + 'src/snode-root.c', 'src/view.c', 'src/virtual-object.c', 'src/xr-dispatcher.c', diff --git a/zen/src/backend/screen/output.c b/zen/src/backend/screen/output.c index 7783b40d..39dd19f5 100644 --- a/zen/src/backend/screen/output.c +++ b/zen/src/backend/screen/output.c @@ -19,6 +19,7 @@ #include "zen-common/signal.h" #include "zen-common/util.h" #include "zen/server.h" +#include "zen/snode-root.h" #include "zen/snode.h" static void zn_output_destroy(struct zn_output *self); @@ -145,7 +146,7 @@ zn_output_render(struct zn_output *self, pixman_region32_t *damage) wlr_renderer_clear(self->wlr_output->renderer, screen_background_color); } - zn_output_render_snode(self, self->screen->snode_root, &screen_damage); + zn_output_render_snode(self, self->screen->snode_root->node, &screen_damage); screen_damage_finish: pixman_region32_fini(&screen_damage); diff --git a/zen/src/backend/screen/xwayland-surface.c b/zen/src/backend/screen/xwayland-surface.c index cd31d4c6..53689b93 100644 --- a/zen/src/backend/screen/xwayland-surface.c +++ b/zen/src/backend/screen/xwayland-surface.c @@ -38,8 +38,7 @@ zn_xwayland_surface_configure_size(void *impl_data, vec2 size) { struct zn_xwayland_surface *self = impl_data; - if (self->surface_snode == NULL || - self->surface_snode->snode->screen == NULL) { + if (self->surface_snode == NULL || self->surface_snode->snode->root == NULL) { return; } @@ -96,8 +95,7 @@ zn_xwayland_surface_handle_snode_position_changed( struct zn_xwayland_surface *self = zn_container_of(listener, self, snode_position_changed_listener); - if (self->surface_snode == NULL || - self->surface_snode->snode->screen == NULL) { + if (self->surface_snode == NULL || self->surface_snode->snode->root == NULL) { return; } diff --git a/zen/src/screen.c b/zen/src/screen.c index 03362aba..837515e5 100644 --- a/zen/src/screen.c +++ b/zen/src/screen.c @@ -6,8 +6,29 @@ #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" +#include "zen/snode-root.h" #include "zen/snode.h" +static void +zn_screen_snode_root_damage(void *user_data, struct wlr_fbox *fbox) +{ + struct zn_screen *self = user_data; + zn_screen_damage(self, fbox); +} + +static void +zn_screen_snode_root_layout_position(void *user_data, vec2 position) +{ + struct zn_screen *self = user_data; + glm_vec2_copy(self->layout_position, position); +} + +static const struct zn_snode_root_interface + zn_screen_snode_root_implementation = { + .damage = zn_screen_snode_root_damage, + .layout_position = zn_screen_snode_root_layout_position, +}; + void zn_screen_set_layout_position(struct zn_screen *self, vec2 layout_position) { @@ -32,7 +53,18 @@ zn_screen_notify_resize(struct zn_screen *self, vec2 size) void zn_screen_notify_frame(struct zn_screen *self, struct timespec *when) { - zn_snode_notify_frame(self->snode_root, when); + zn_snode_notify_frame(self->snode_root->node, when); +} + +struct zn_screen * +zn_screen_from_snode_root(struct zn_snode_root *snode_root) +{ + if (snode_root == NULL || + snode_root->impl != &zn_screen_snode_root_implementation) { + return NULL; + } + + return snode_root->user_data; } struct zn_screen * @@ -53,7 +85,8 @@ zn_screen_create( wl_signal_init(&self->events.destroy); wl_signal_init(&self->events.layout_position_changed); - self->snode_root = zn_snode_create_root(self); + self->snode_root = + zn_snode_root_create(self, &zn_screen_snode_root_implementation); if (self->snode_root == NULL) { zn_error("Failed to create a zn_snode"); goto err_free; @@ -70,7 +103,7 @@ zn_screen_create( return self; err_snode_root: - zn_snode_destroy(self->snode_root); + zn_snode_root_destroy(self->snode_root); err_free: free(self); @@ -84,7 +117,7 @@ zn_screen_destroy(struct zn_screen *self) { zn_signal_emit_mutable(&self->events.destroy, NULL); - zn_snode_destroy(self->snode_root); + zn_snode_root_destroy(self->snode_root); wl_list_remove(&self->events.layout_position_changed.listener_list); wl_list_remove(&self->events.destroy.listener_list); wl_list_remove(&self->events.resized.listener_list); diff --git a/zen/src/seat.c b/zen/src/seat.c index 35250b9c..e276bab2 100644 --- a/zen/src/seat.c +++ b/zen/src/seat.c @@ -5,6 +5,7 @@ #include "cursor.h" #include "zen-common/log.h" #include "zen-common/util.h" +#include "zen/screen.h" #include "zen/snode.h" #define DEFAULT_SEAT "seat0" @@ -54,14 +55,16 @@ zn_seat_get_focused_screen(struct zn_seat *self) { struct zn_screen *focus_screen = NULL; - // TODO(@Aki-7): Respect keyboard focus + if (self->focus) { + focus_screen = zn_screen_from_snode_root(self->focus->root); + } - if (self->pointer_state.focus) { - focus_screen = self->pointer_state.focus->screen; + if (!focus_screen && self->pointer_state.focus) { + focus_screen = zn_screen_from_snode_root(self->pointer_state.focus->root); } if (!focus_screen) { - focus_screen = self->cursor->snode->screen; + focus_screen = zn_screen_from_snode_root(self->cursor->snode->root); } return focus_screen; diff --git a/zen/src/snode-root.c b/zen/src/snode-root.c new file mode 100644 index 00000000..9ef2e4e8 --- /dev/null +++ b/zen/src/snode-root.c @@ -0,0 +1,42 @@ +#include "zen/snode-root.h" + +#include "zen-common/log.h" +#include "zen-common/util.h" +#include "zen/snode.h" + +struct zn_snode_root * +zn_snode_root_create( + void *user_data, const struct zn_snode_root_interface *implementation) +{ + struct zn_snode_root *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl = implementation; + self->user_data = user_data; + + self->node = zn_snode_create(self, &zn_snode_noop_implementation); + if (self->node == NULL) { + zn_error("Failed to create root snode"); + goto err_free; + } + + self->node->root = self; + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +void +zn_snode_root_destroy(struct zn_snode_root *self) +{ + zn_snode_destroy(self->node); + free(self); +} diff --git a/zen/src/snode.c b/zen/src/snode.c index 4f229a84..557ba019 100644 --- a/zen/src/snode.c +++ b/zen/src/snode.c @@ -6,6 +6,7 @@ #include "zen-common/signal.h" #include "zen-common/util.h" #include "zen/screen.h" +#include "zen/snode-root.h" bool zn_snode_is_focusable(struct zn_snode *self) @@ -113,12 +114,12 @@ void zn_snode_damage_whole(struct zn_snode *self) { struct wlr_fbox box; - if (!self->screen) { + if (!self->root) { return; } zn_snode_get_fbox(self, &box); - zn_screen_damage(self->screen, &box); + zn_snode_root_damage(self->root, &box); } static void @@ -158,7 +159,7 @@ zn_snode_get_snode_at(struct zn_snode *self, vec2 point, vec2 local_point) void zn_snode_damage(struct zn_snode *self, struct wlr_fbox *damage) { - if (!self->screen) { + if (!self->root) { return; } @@ -169,7 +170,7 @@ zn_snode_damage(struct zn_snode *self, struct wlr_fbox *damage) .height = damage->height, }; - zn_screen_damage(self->screen, &fbox); + zn_snode_root_damage(self->root, &fbox); } void @@ -222,7 +223,7 @@ zn_snode_set_position( } self->parent = parent; - self->screen = parent ? parent->screen : NULL; + self->root = parent ? parent->root : NULL; glm_vec2_copy(position, self->position); zn_snode_update_absolute_position(self); @@ -323,9 +324,12 @@ zn_snode_get_layout_fbox(struct zn_snode *self, struct wlr_fbox *fbox) { zn_snode_get_fbox(self, fbox); - if (self->screen) { - fbox->x += self->screen->layout_position[0]; - fbox->y += self->screen->layout_position[1]; + if (self->root) { + vec2 root_layout_position; + zn_snode_root_layout_position(self->root, root_layout_position); + + fbox->x += root_layout_position[0]; + fbox->y += root_layout_position[1]; } } @@ -339,7 +343,7 @@ zn_snode_handle_parent_position_changed( zn_snode_damage_whole(self); zn_snode_update_absolute_position(self); - self->screen = self->parent->screen; + self->root = self->parent->root; zn_snode_damage_whole(self); @@ -373,7 +377,7 @@ zn_snode_create( glm_vec2_zero(self->position); glm_vec2_zero(self->absolute_position); - self->screen = NULL; + self->root = NULL; wl_list_init(&self->child_node_list); wl_list_init(&self->link); @@ -407,14 +411,6 @@ zn_snode_create_focusable( return self; } -struct zn_snode * -zn_snode_create_root(struct zn_screen *screen) -{ - struct zn_snode *self = zn_snode_create(NULL, &zn_snode_noop_implementation); - self->screen = screen; - return self; -} - void zn_snode_destroy(struct zn_snode *self) { diff --git a/zen/tests/snode/snode-damage.c b/zen/tests/snode/snode-damage.c index 1ca9bd9b..dd11ecfe 100644 --- a/zen/tests/snode/snode-damage.c +++ b/zen/tests/snode/snode-damage.c @@ -3,6 +3,7 @@ #include "mock/output.h" #include "test-harness.h" #include "zen-common/util.h" +#include "zen/snode-root.h" #include "zen/snode.h" static struct wlr_texture * @@ -36,7 +37,7 @@ TEST(set_position) texture2.width = 20; texture2.height = 20; - struct zn_snode *root = zn_snode_create_root(output->screen); + struct zn_snode *root = output->screen->snode_root->node; struct zn_snode *node1 = zn_snode_create(&texture1, &test_impl); struct zn_snode *node2 = zn_snode_create(&texture2, &test_impl); @@ -77,8 +78,8 @@ TEST(set_position_rebase_parent) texture.width = 10; texture.height = 10; - struct zn_snode *root = zn_snode_create_root(output->screen); - struct zn_snode *root2 = zn_snode_create_root(output2->screen); + struct zn_snode *root = output->screen->snode_root->node; + struct zn_snode *root2 = output2->screen->snode_root->node; struct zn_snode *node1 = zn_snode_create(&texture, &test_impl); struct zn_snode *node2 = zn_snode_create(&texture, &test_impl); @@ -145,7 +146,7 @@ TEST(damage) texture.width = 50; texture.height = 50; - struct zn_snode *root = zn_snode_create_root(output->screen); + struct zn_snode *root = output->screen->snode_root->node; struct zn_snode *node1 = zn_snode_create(&texture, &test_impl); struct zn_snode *node2 = zn_snode_create(&texture, &test_impl); @@ -180,7 +181,7 @@ TEST(change_position) texture.width = 50; texture.height = 50; - struct zn_snode *root = zn_snode_create_root(output->screen); + struct zn_snode *root = output->screen->snode_root->node; struct zn_snode *node1 = zn_snode_create(&texture, &test_impl); struct zn_snode *node2 = zn_snode_create(&texture, &test_impl); @@ -221,7 +222,7 @@ TEST(set_next_to) texture.width = 50; texture.height = 50; - struct zn_snode *root = zn_snode_create_root(output->screen); + struct zn_snode *root = output->screen->snode_root->node; struct zn_snode *node1 = zn_snode_create(&texture, &test_impl); struct zn_snode *node11 = zn_snode_create(&texture, &test_impl); @@ -249,7 +250,7 @@ TEST(no_damage) texture.width = 50; texture.height = 50; - struct zn_snode *root = zn_snode_create_root(output->screen); + struct zn_snode *root = output->screen->snode_root->node; struct zn_snode *node1 = zn_snode_create(&texture, &test_impl); struct zn_snode *node11 = zn_snode_create(&texture, &test_impl); diff --git a/zen/tests/snode/snode-frame.c b/zen/tests/snode/snode-frame.c index 9710b3d0..8ed24d01 100644 --- a/zen/tests/snode/snode-frame.c +++ b/zen/tests/snode/snode-frame.c @@ -5,6 +5,7 @@ #include "screen.h" #include "test-harness.h" #include "zen-common/util.h" +#include "zen/snode-root.h" #include "zen/snode.h" static void @@ -39,7 +40,7 @@ TEST(frame) struct zn_snode *node3 = zn_snode_create(&counter, &test_impl); struct zn_snode *node4 = zn_snode_create(&counter, &test_impl); - zn_snode_set_position(node1, output->screen->snode_root, (vec2){0, 0}); + zn_snode_set_position(node1, output->screen->snode_root->node, (vec2){0, 0}); zn_snode_set_position(node2, node1, (vec2){0, 0}); zn_snode_set_position(node3, node1, (vec2){0, 0}); zn_snode_set_position(node4, node2, (vec2){0, 0}); diff --git a/zen/tests/snode/snode-get-at.c b/zen/tests/snode/snode-get-at.c index 0e678ff7..7ac04380 100644 --- a/zen/tests/snode/snode-get-at.c +++ b/zen/tests/snode/snode-get-at.c @@ -5,6 +5,7 @@ #include "mock/output.h" #include "test-harness.h" #include "zen-common/wlr/box.h" +#include "zen/snode-root.h" #include "zen/snode.h" bool @@ -53,7 +54,7 @@ TEST(normal) { struct zn_mock_output *output = zn_mock_output_create(0, 0); - struct zn_snode *root = zn_snode_create_root(output->screen); + struct zn_snode *root = output->screen->snode_root->node; struct zn_snode *node1 = create_snode_with_input_region(0, 0, 900, 800); struct zn_snode *node2 = create_snode_with_input_region(0, 0, 300, 300); struct zn_snode *node3 = create_snode_with_input_region(400, -100, 200, 300); From 76c7191952af094d5f5b20cc8e35acff1b724039 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 23 Jul 2023 20:04:41 +0900 Subject: [PATCH 44/49] change display mode --- common/include/zen-common/delay-signal.h | 22 +++++++++++ common/meson.build | 1 + common/src/delay-signal.c | 49 ++++++++++++++++++++++++ desktop/include/zen-desktop/shell.h | 8 ++++ desktop/src/shell.c | 34 ++++++++++++++++ zen/include/zen/backend.h | 20 +++++++--- zen/src/backend/default-backend.c | 6 +++ 7 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 common/include/zen-common/delay-signal.h create mode 100644 common/src/delay-signal.c diff --git a/common/include/zen-common/delay-signal.h b/common/include/zen-common/delay-signal.h new file mode 100644 index 00000000..e7c47305 --- /dev/null +++ b/common/include/zen-common/delay-signal.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +struct zn_delay_signal { + struct wl_signal signal; + struct wl_event_source *idle; // @nonnull, @ref +}; + +/// The signal handlers will be called at the next idle time. +/// No user data is allowed as it's hard to manage the ownership of the data. +/// In there is already a scheduled signal, this signal scheduling will be +/// ignored. +void zn_delay_signal_schedule( + struct zn_delay_signal *self, struct wl_display *display); + +void zn_delay_signal_add( + struct zn_delay_signal *self, struct wl_listener *listener); + +void zn_delay_signal_init(struct zn_delay_signal *self); + +void zn_delay_signal_release(struct zn_delay_signal *self); diff --git a/common/meson.build b/common/meson.build index 1e59ce94..64f84872 100644 --- a/common/meson.build +++ b/common/meson.build @@ -1,5 +1,6 @@ _zen_common_srcs = [ 'src/cairo/rounded.c', + 'src/delay-signal.c', 'src/log.c', 'src/signal.c', 'src/terminate.c', diff --git a/common/src/delay-signal.c b/common/src/delay-signal.c new file mode 100644 index 00000000..0b24103a --- /dev/null +++ b/common/src/delay-signal.c @@ -0,0 +1,49 @@ +#include "zen-common/delay-signal.h" + +#include "zen-common/signal.h" +#include "zen-common/util.h" + +static void +zn_delay_signal_idle_timer(void *data) +{ + struct zn_delay_signal *self = data; + + self->idle = NULL; + + zn_signal_emit_mutable(&self->signal, NULL); +} + +void +zn_delay_signal_schedule( + struct zn_delay_signal *self, struct wl_display *display) +{ + if (self->idle) { + return; + } + + struct wl_event_loop *loop = wl_display_get_event_loop(display); + + self->idle = wl_event_loop_add_idle(loop, zn_delay_signal_idle_timer, self); +} + +void +zn_delay_signal_add(struct zn_delay_signal *self, struct wl_listener *listener) +{ + wl_signal_add(&self->signal, listener); +} + +void +zn_delay_signal_init(struct zn_delay_signal *self) +{ + wl_signal_init(&self->signal); + self->idle = NULL; +} + +void +zn_delay_signal_release(struct zn_delay_signal *self) +{ + wl_list_remove(&self->signal.listener_list); + if (self->idle) { + wl_event_source_remove(self->idle); + } +} diff --git a/desktop/include/zen-desktop/shell.h b/desktop/include/zen-desktop/shell.h index 8934eaff..ca7df436 100644 --- a/desktop/include/zen-desktop/shell.h +++ b/desktop/include/zen-desktop/shell.h @@ -5,6 +5,11 @@ struct zn_cursor_grab; struct zn_theme; +enum zn_desktop_shell_display_mode { + ZN_DESKTOP_SHELL_DISPLAY_MODE_SCREEN, + ZN_DESKTOP_SHELL_DISPLAY_MODE_IMMERSIVE, +}; + struct zn_desktop_shell { struct zn_screen_layout *screen_layout; // @nonnull, @owning @@ -12,6 +17,9 @@ struct zn_desktop_shell { struct zn_theme *theme; // @nonnull, @owning + enum zn_desktop_shell_display_mode mode; + + struct wl_listener xr_system_changed_listener; struct wl_listener new_xr_system_listener; struct wl_listener new_screen_listener; struct wl_listener seat_capabilities_listener; diff --git a/desktop/src/shell.c b/desktop/src/shell.c index ffa98328..b891bc48 100644 --- a/desktop/src/shell.c +++ b/desktop/src/shell.c @@ -25,6 +25,32 @@ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static struct zn_desktop_shell *desktop_shell_singleton = NULL; +static void +zn_desktop_shell_handle_xr_system_changed( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_desktop_shell *self = + zn_container_of(listener, self, xr_system_changed_listener); + struct zn_server *server = zn_server_get_singleton(); + + struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); + enum zn_desktop_shell_display_mode mode = + xr_system ? ZN_DESKTOP_SHELL_DISPLAY_MODE_IMMERSIVE + : ZN_DESKTOP_SHELL_DISPLAY_MODE_SCREEN; + + if (self->mode == mode) { + return; + } + + self->mode = mode; + + if (self->mode == ZN_DESKTOP_SHELL_DISPLAY_MODE_SCREEN) { + zn_info("Switch to screen display mode"); + } else { + zn_info("Switch to immersive display mode"); + } +} + static void zn_desktop_shell_handle_new_xr_system( struct wl_listener *listener UNUSED, void *data) @@ -205,6 +231,8 @@ zn_desktop_shell_create(void) desktop_shell_singleton = self; + self->mode = ZN_DESKTOP_SHELL_DISPLAY_MODE_SCREEN; + self->theme = zn_theme_create(); if (self->theme == NULL) { zn_error("Failed to create theme"); @@ -225,6 +253,11 @@ zn_desktop_shell_create(void) } self->cursor_grab = &cursor_default_grab->base; + self->xr_system_changed_listener.notify = + zn_desktop_shell_handle_xr_system_changed; + zn_delay_signal_add(&server->backend->events.xr_system_changed, + &self->xr_system_changed_listener); + self->new_xr_system_listener.notify = zn_desktop_shell_handle_new_xr_system; wl_signal_add( &server->backend->events.new_xr_system, &self->new_xr_system_listener); @@ -290,6 +323,7 @@ zn_desktop_shell_destroy(struct zn_desktop_shell *self) wl_list_remove(&self->seat_capabilities_listener.link); wl_list_remove(&self->new_screen_listener.link); wl_list_remove(&self->new_xr_system_listener.link); + wl_list_remove(&self->xr_system_changed_listener.link); zn_cursor_grab_destroy(self->cursor_grab); zn_screen_layout_destroy(self->screen_layout); zn_theme_destroy(self->theme); diff --git a/zen/include/zen/backend.h b/zen/include/zen/backend.h index f6686be8..3b35f7f3 100644 --- a/zen/include/zen/backend.h +++ b/zen/include/zen/backend.h @@ -2,6 +2,7 @@ #include +#include "zen-common/delay-signal.h" #include "zen-common/util.h" struct zn_backend; @@ -13,15 +14,21 @@ struct zn_backend_interface { struct wlr_texture *(*create_wlr_texture_from_pixels)(struct zn_backend *self, uint32_t format, uint32_t stride, uint32_t width, uint32_t height, const void *data); - /// @param xr_system is nullable + + /// @param xr_system is nullable. + /// If not null, xr_system must be connected state void (*set_xr_system)( struct zn_backend *self, struct zn_xr_system *xr_system); + /// @return value can be NULL struct zn_xr_system *(*get_xr_system)(struct zn_backend *self); + /// Starts monitoring the connection or disconnection of input/output devices. bool (*start)(struct zn_backend *self); + /// Destroy input/output devices void (*stop)(struct zn_backend *self); + void (*destroy)(struct zn_backend *self); }; @@ -29,11 +36,12 @@ struct zn_backend { const struct zn_backend_interface *impl; struct { - struct wl_signal new_screen; // (struct zn_screen *) - struct wl_signal view_mapped; // (struct zn_view *) - struct wl_signal bounded_mapped; // (struct zn_bounded *) - struct wl_signal destroy; // (NULL) - struct wl_signal new_xr_system; // (struct zn_xr_system *) + struct wl_signal new_screen; // (struct zn_screen *) + struct wl_signal view_mapped; // (struct zn_view *) + struct wl_signal bounded_mapped; // (struct zn_bounded *) + struct wl_signal destroy; // (NULL) + struct wl_signal new_xr_system; // (struct zn_xr_system *) + struct zn_delay_signal xr_system_changed; // (NULL) } events; }; diff --git a/zen/src/backend/default-backend.c b/zen/src/backend/default-backend.c index 355e8a75..154c4f1e 100644 --- a/zen/src/backend/default-backend.c +++ b/zen/src/backend/default-backend.c @@ -89,6 +89,8 @@ zn_default_backend_set_xr_system( wl_signal_add(&self->xr_compositor->events.destroy, &self->xr_compositor_destroy_listener); } + + zn_delay_signal_schedule(&self->base.events.xr_system_changed, self->display); } static void @@ -182,6 +184,8 @@ zn_default_backend_handle_xr_compositor_destroy( wl_list_remove(&self->xr_compositor_destroy_listener.link); wl_list_init(&self->xr_compositor_destroy_listener.link); self->xr_compositor = NULL; + + zn_delay_signal_schedule(&self->base.events.xr_system_changed, self->display); } static struct wlr_texture * @@ -260,6 +264,7 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) wl_signal_init(&self->base.events.bounded_mapped); wl_signal_init(&self->base.events.destroy); wl_signal_init(&self->base.events.new_xr_system); + zn_delay_signal_init(&self->base.events.xr_system_changed); self->base.impl = &implementation; self->display = display; self->xr_compositor = NULL; @@ -369,6 +374,7 @@ zn_default_backend_destroy(struct zn_default_backend *self) wlr_backend_destroy(self->wlr_backend); } wl_list_remove(&self->input_device_list); + zn_delay_signal_release(&self->base.events.xr_system_changed); wl_list_remove(&self->base.events.new_xr_system.listener_list); wl_list_remove(&self->base.events.destroy.listener_list); wl_list_remove(&self->base.events.bounded_mapped.listener_list); From a0462b7b742f82a9f6ef1743d06cc263d16d8eed Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 23 Jul 2023 23:06:55 +0900 Subject: [PATCH 45/49] fix test --- zen/tests/mock/src/backend.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zen/tests/mock/src/backend.c b/zen/tests/mock/src/backend.c index dbd0147d..5b0b85fe 100644 --- a/zen/tests/mock/src/backend.c +++ b/zen/tests/mock/src/backend.c @@ -69,6 +69,7 @@ zn_mock_backend_create(void) wl_signal_init(&self->base.events.destroy); wl_signal_init(&self->base.events.new_xr_system); wl_signal_init(&self->base.events.bounded_mapped); + zn_delay_signal_init(&self->base.events.xr_system_changed); return self; } @@ -78,6 +79,7 @@ zn_mock_backend_destroy(struct zn_mock_backend *self) { zn_signal_emit_mutable(&self->base.events.destroy, NULL); + zn_delay_signal_release(&self->base.events.xr_system_changed); wl_list_remove(&self->base.events.new_xr_system.listener_list); wl_list_remove(&self->base.events.destroy.listener_list); wl_list_remove(&self->base.events.view_mapped.listener_list); From 02929bd90cce01f70d71e3c438c6ff4327ee1423 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Tue, 25 Jul 2023 22:27:43 +0900 Subject: [PATCH 46/49] inode mapping --- desktop/src/shell.c | 9 +- zen/include/zen/backend.h | 13 ++- zen/include/zen/inode.h | 36 +++++-- zen/include/zen/server.h | 5 + zen/src/backend/default-backend.c | 48 +++++---- zen/src/inode.c | 66 ++++++++++-- zen/src/inode.h | 10 ++ zen/src/server.c | 13 ++- zen/tests/inode/inode-map.c | 129 +++++++++++++----------- zen/tests/inode/inode-set-xr-system.c | 140 ++++++++++++++++++++++++++ zen/tests/meson.build | 1 + zen/tests/mock/src/backend.c | 4 +- 12 files changed, 371 insertions(+), 103 deletions(-) create mode 100644 zen/src/inode.h create mode 100644 zen/tests/inode/inode-set-xr-system.c diff --git a/desktop/src/shell.c b/desktop/src/shell.c index b891bc48..62a61c8a 100644 --- a/desktop/src/shell.c +++ b/desktop/src/shell.c @@ -15,6 +15,7 @@ #include "zen/backend.h" #include "zen/bounded.h" #include "zen/cursor.h" +#include "zen/inode.h" #include "zen/screen.h" #include "zen/seat.h" #include "zen/server.h" @@ -27,13 +28,13 @@ static struct zn_desktop_shell *desktop_shell_singleton = NULL; static void zn_desktop_shell_handle_xr_system_changed( - struct wl_listener *listener, void *data UNUSED) + struct wl_listener *listener, void *data) { struct zn_desktop_shell *self = zn_container_of(listener, self, xr_system_changed_listener); + struct zn_xr_system *xr_system = data; struct zn_server *server = zn_server_get_singleton(); - struct zn_xr_system *xr_system = zn_backend_get_xr_system(server->backend); enum zn_desktop_shell_display_mode mode = xr_system ? ZN_DESKTOP_SHELL_DISPLAY_MODE_IMMERSIVE : ZN_DESKTOP_SHELL_DISPLAY_MODE_SCREEN; @@ -45,8 +46,10 @@ zn_desktop_shell_handle_xr_system_changed( self->mode = mode; if (self->mode == ZN_DESKTOP_SHELL_DISPLAY_MODE_SCREEN) { + zn_inode_unmap(server->inode_root); zn_info("Switch to screen display mode"); } else { + zn_inode_map(server->inode_root); zn_info("Switch to immersive display mode"); } } @@ -255,7 +258,7 @@ zn_desktop_shell_create(void) self->xr_system_changed_listener.notify = zn_desktop_shell_handle_xr_system_changed; - zn_delay_signal_add(&server->backend->events.xr_system_changed, + wl_signal_add(&server->backend->events.xr_system_changed, &self->xr_system_changed_listener); self->new_xr_system_listener.notify = zn_desktop_shell_handle_new_xr_system; diff --git a/zen/include/zen/backend.h b/zen/include/zen/backend.h index 3b35f7f3..43252cd3 100644 --- a/zen/include/zen/backend.h +++ b/zen/include/zen/backend.h @@ -2,7 +2,6 @@ #include -#include "zen-common/delay-signal.h" #include "zen-common/util.h" struct zn_backend; @@ -36,12 +35,12 @@ struct zn_backend { const struct zn_backend_interface *impl; struct { - struct wl_signal new_screen; // (struct zn_screen *) - struct wl_signal view_mapped; // (struct zn_view *) - struct wl_signal bounded_mapped; // (struct zn_bounded *) - struct wl_signal destroy; // (NULL) - struct wl_signal new_xr_system; // (struct zn_xr_system *) - struct zn_delay_signal xr_system_changed; // (NULL) + struct wl_signal new_screen; // (struct zn_screen *) + struct wl_signal view_mapped; // (struct zn_view *) + struct wl_signal bounded_mapped; // (struct zn_bounded *) + struct wl_signal destroy; // (NULL) + struct wl_signal new_xr_system; // (struct zn_xr_system *) + struct wl_signal xr_system_changed; // (struct zn_xr_system *) } events; }; diff --git a/zen/include/zen/inode.h b/zen/include/zen/inode.h index 6db39dc2..5d7f162a 100644 --- a/zen/include/zen/inode.h +++ b/zen/include/zen/inode.h @@ -3,9 +3,15 @@ #include #include +#include "zen-common/util.h" + +struct zn_xr_system; + struct zn_inode_interface { void (*mapped)(void *impl_data); void (*unmapped)(void *impl_data); + void (*activated)(void *impl_data); + void (*deactivated)(void *impl_data); void (*moved)(void *impl_data); }; @@ -13,6 +19,10 @@ void zn_inode_noop_mapped(void *impl_data); void zn_inode_noop_unmapped(void *impl_data); +void zn_inode_noop_activated(void *impl_data); + +void zn_inode_noop_deactivated(void *impl_data); + void zn_inode_noop_moved(void *impl_data); extern const struct zn_inode_interface zn_inode_noop_implementation; @@ -22,6 +32,10 @@ struct zn_inode { void *impl_data; // @nullable, @outlive const struct zn_inode_interface *impl; // @nonnull, @outlive + struct zn_xr_system *xr_system; // @nullable, @ref + + bool mapped; + // local coords vec3 position; versor quaternion; @@ -33,8 +47,6 @@ struct zn_inode { struct wl_list link; // zn_inode::child_list struct wl_list child_list; // zn_inode::link - bool mapped; - struct wl_listener parent_destroy_listener; struct { @@ -42,15 +54,27 @@ struct zn_inode { } events; }; -/// @param self must be root -void zn_inode_map(struct zn_inode *self); +UNUSED static inline bool +zn_inode_is_mapped(struct zn_inode *self) +{ + return self->mapped; +} -/// @param self must be root -void zn_inode_unmap(struct zn_inode *self); +UNUSED static inline bool +zn_inode_is_active(struct zn_inode *self) +{ + return self->mapped && self->xr_system != NULL; +} void zn_inode_move(struct zn_inode *self, struct zn_inode *parent, vec3 position, versor quaternion); +/// @param self must be root +void zn_inode_unmap(struct zn_inode *self); + +/// @param self must be root +void zn_inode_map(struct zn_inode *self); + struct zn_inode *zn_inode_create( void *impl_data, const struct zn_inode_interface *implementation); diff --git a/zen/include/zen/server.h b/zen/include/zen/server.h index 981f629e..fceca3ab 100644 --- a/zen/include/zen/server.h +++ b/zen/include/zen/server.h @@ -6,6 +6,7 @@ struct zn_backend; struct zn_seat; struct zn_binding; +struct zn_inode; struct zn_server { struct wl_display *display; // @nonnull, @outlive @@ -15,6 +16,10 @@ struct zn_server { struct zn_binding *binding; // @nonnull, @owning struct zn_config *config; // @nonnull, @outlive + // zn_inode_set_xr_system for this root inode is called in the backend + // implementation + struct zn_inode *inode_root; // @nonnull, @owning + bool running; int exit_status; diff --git a/zen/src/backend/default-backend.c b/zen/src/backend/default-backend.c index 154c4f1e..cc97819d 100644 --- a/zen/src/backend/default-backend.c +++ b/zen/src/backend/default-backend.c @@ -11,6 +11,7 @@ #include "immersive/xr-compositor.h" #include "immersive/xr-system-manager.h" #include "immersive/xr.h" +#include "inode.h" #include "screen/compositor.h" #include "screen/keyboard.h" #include "screen/output.h" @@ -77,6 +78,14 @@ static void zn_default_backend_set_xr_system( struct zn_default_backend *self, struct zn_xr_system *xr_system) { + struct zn_xr_system *current_xr_system = + zn_backend_get_xr_system(&self->base); + if (current_xr_system == xr_system) { + return; + } + + struct zn_server *server = zn_server_get_singleton(); + if (self->xr_compositor) { wl_list_remove(&self->xr_compositor_destroy_listener.link); wl_list_init(&self->xr_compositor_destroy_listener.link); @@ -90,7 +99,26 @@ zn_default_backend_set_xr_system( &self->xr_compositor_destroy_listener); } - zn_delay_signal_schedule(&self->base.events.xr_system_changed, self->display); + zn_inode_set_xr_system(server->inode_root, xr_system); + + zn_signal_emit_mutable(&self->base.events.xr_system_changed, xr_system); +} + +static void +zn_default_backend_handle_xr_compositor_destroy( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_default_backend *self = + zn_container_of(listener, self, xr_compositor_destroy_listener); + struct zn_server *server = zn_server_get_singleton(); + + wl_list_remove(&self->xr_compositor_destroy_listener.link); + wl_list_init(&self->xr_compositor_destroy_listener.link); + self->xr_compositor = NULL; + + zn_inode_set_xr_system(server->inode_root, NULL); + + zn_signal_emit_mutable(&self->base.events.xr_system_changed, NULL); } static void @@ -174,20 +202,6 @@ zn_default_backend_handle_new_xr_system( wl_signal_emit(&self->base.events.new_xr_system, xr_system); } -static void -zn_default_backend_handle_xr_compositor_destroy( - struct wl_listener *listener, void *data UNUSED) -{ - struct zn_default_backend *self = - zn_container_of(listener, self, xr_compositor_destroy_listener); - - wl_list_remove(&self->xr_compositor_destroy_listener.link); - wl_list_init(&self->xr_compositor_destroy_listener.link); - self->xr_compositor = NULL; - - zn_delay_signal_schedule(&self->base.events.xr_system_changed, self->display); -} - static struct wlr_texture * zn_default_backend_create_wlr_texture_from_pixels(struct zn_backend *base, uint32_t format, uint32_t stride, uint32_t width, uint32_t height, @@ -264,7 +278,7 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) wl_signal_init(&self->base.events.bounded_mapped); wl_signal_init(&self->base.events.destroy); wl_signal_init(&self->base.events.new_xr_system); - zn_delay_signal_init(&self->base.events.xr_system_changed); + wl_signal_init(&self->base.events.xr_system_changed); self->base.impl = &implementation; self->display = display; self->xr_compositor = NULL; @@ -374,7 +388,7 @@ zn_default_backend_destroy(struct zn_default_backend *self) wlr_backend_destroy(self->wlr_backend); } wl_list_remove(&self->input_device_list); - zn_delay_signal_release(&self->base.events.xr_system_changed); + wl_list_remove(&self->base.events.xr_system_changed.listener_list); wl_list_remove(&self->base.events.new_xr_system.listener_list); wl_list_remove(&self->base.events.destroy.listener_list); wl_list_remove(&self->base.events.bounded_mapped.listener_list); diff --git a/zen/src/inode.c b/zen/src/inode.c index d4813536..da59995d 100644 --- a/zen/src/inode.c +++ b/zen/src/inode.c @@ -1,4 +1,4 @@ -#include "zen/inode.h" +#include "inode.h" #include #include @@ -15,6 +15,14 @@ void zn_inode_noop_unmapped(void *impl_data UNUSED) {} +void +zn_inode_noop_activated(void *impl_data UNUSED) +{} + +void +zn_inode_noop_deactivated(void *impl_data UNUSED) +{} + void zn_inode_noop_moved(void *impl_data UNUSED) {} @@ -22,6 +30,8 @@ zn_inode_noop_moved(void *impl_data UNUSED) const struct zn_inode_interface zn_inode_noop_implementation = { .mapped = zn_inode_noop_mapped, .unmapped = zn_inode_noop_unmapped, + .activated = zn_inode_noop_activated, + .deactivated = zn_inode_noop_deactivated, .moved = zn_inode_noop_moved, }; @@ -34,16 +44,16 @@ zn_inode_map_internal(struct zn_inode *self, bool mapped) struct zn_inode *child = NULL; + self->mapped = mapped; + wl_list_for_each (child, &self->child_list, link) { zn_inode_map_internal(child, mapped); } - self->mapped = mapped; - if (self->mapped) { - self->impl->mapped(self); + self->impl->mapped(self->impl_data); } else { - self->impl->unmapped(self); + self->impl->unmapped(self->impl_data); } } @@ -63,6 +73,43 @@ zn_inode_unmap(struct zn_inode *self) zn_inode_map_internal(self, false); } +static void +zn_inode_set_xr_system_internal( + struct zn_inode *self, struct zn_xr_system *xr_system) +{ + if (self->xr_system == xr_system) { + return; + } + + bool was_active = zn_inode_is_active(self); + + self->xr_system = xr_system; + + struct zn_inode *child = NULL; + + wl_list_for_each (child, &self->child_list, link) { + zn_inode_set_xr_system_internal(child, xr_system); + } + + bool is_active = zn_inode_is_active(self); + + if (was_active != is_active) { + if (is_active) { + self->impl->activated(self->impl_data); + } else { + self->impl->deactivated(self->impl_data); + } + } +} + +void +zn_inode_set_xr_system(struct zn_inode *self, struct zn_xr_system *xr_system) +{ + zn_assert(self->parent == NULL, "self must be root"); + + zn_inode_set_xr_system_internal(self, xr_system); +} + static void zn_inode_update_position_recursive(struct zn_inode *self, mat4 parent_transform) { @@ -80,7 +127,7 @@ zn_inode_update_position_recursive(struct zn_inode *self, mat4 parent_transform) zn_inode_update_position_recursive(child, self->transform_abs); } - self->impl->moved(self); + self->impl->moved(self->impl_data); } void @@ -106,7 +153,9 @@ zn_inode_move(struct zn_inode *self, struct zn_inode *parent, vec3 position, wl_list_insert(&self->parent->child_list, &self->link); } - zn_inode_map_internal(self, parent && parent->mapped); + zn_inode_set_xr_system_internal(self, parent ? parent->xr_system : NULL); + + zn_inode_map_internal(self, parent ? parent->mapped : false); } zn_inode_update_position_recursive( @@ -134,13 +183,14 @@ zn_inode_create( self->impl_data = impl_data; self->impl = implementation; + self->xr_system = NULL; + self->mapped = false; glm_vec3_zero(self->position); glm_quat_identity(self->quaternion); glm_mat4_identity(self->transform_abs); self->parent = NULL; wl_list_init(&self->link); wl_list_init(&self->child_list); - self->mapped = false; wl_signal_init(&self->events.destroy); self->parent_destroy_listener.notify = zn_inode_handle_parent_destroy; diff --git a/zen/src/inode.h b/zen/src/inode.h new file mode 100644 index 00000000..1679d24b --- /dev/null +++ b/zen/src/inode.h @@ -0,0 +1,10 @@ +#pragma once + +#include "zen/inode.h" + +/// @param self must be root +/// @param xr_system is nullable +/// If this is called with nonnull xr_system, the caller must call this with +/// NULL when the xr_system is disconnected or destroyed +void zn_inode_set_xr_system( + struct zn_inode *self, struct zn_xr_system *xr_system); diff --git a/zen/src/server.c b/zen/src/server.c index b4e99888..a0ae4e40 100644 --- a/zen/src/server.c +++ b/zen/src/server.c @@ -12,6 +12,7 @@ #include "zen-common/util.h" #include "zen/backend.h" #include "zen/config.h" +#include "zen/inode.h" // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static struct zn_server *server_singleton = NULL; @@ -130,6 +131,12 @@ zn_server_create(struct wl_display *display, struct zn_backend *backend, goto err_binding; } + self->inode_root = zn_inode_create(self, &zn_inode_noop_implementation); + if (self->inode_root == NULL) { + zn_error("Failed to create a root inode"); + goto err_seat; + } + if (backend) { self->backend = backend; } else { @@ -137,7 +144,7 @@ zn_server_create(struct wl_display *display, struct zn_backend *backend, } if (self->backend == NULL) { zn_error("Failed to create a zn_backend"); - goto err_seat; + goto err_inode_root; } return self; @@ -145,6 +152,9 @@ zn_server_create(struct wl_display *display, struct zn_backend *backend, err_seat: zn_seat_destroy(self->seat); +err_inode_root: + zn_inode_destroy(self->inode_root); + err_binding: zn_binding_destroy(self->binding); @@ -160,6 +170,7 @@ zn_server_destroy(struct zn_server *self) { zn_backend_destroy(self->backend); zn_seat_destroy(self->seat); + zn_inode_destroy(self->inode_root); zn_binding_destroy(self->binding); server_singleton = NULL; wl_list_remove(&self->events.start.listener_list); diff --git a/zen/tests/inode/inode-map.c b/zen/tests/inode/inode-map.c index a7365ff4..03a392c5 100644 --- a/zen/tests/inode/inode-map.c +++ b/zen/tests/inode/inode-map.c @@ -1,8 +1,8 @@ #include #include +#include "inode.h" #include "test-harness.h" -#include "zen/inode.h" TEST(map) { @@ -26,82 +26,82 @@ TEST(map) zn_inode_map(root); - ASSERT_EQUAL_BOOL(true, root->mapped); - ASSERT_EQUAL_BOOL(true, n1->mapped); - ASSERT_EQUAL_BOOL(true, n2->mapped); - ASSERT_EQUAL_BOOL(true, n3->mapped); - ASSERT_EQUAL_BOOL(true, n11->mapped); - ASSERT_EQUAL_BOOL(true, n12->mapped); - ASSERT_EQUAL_BOOL(true, n21->mapped); - ASSERT_EQUAL_BOOL(true, n211->mapped); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(root)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n1)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n2)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n3)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n11)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n12)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n21)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n211)); zn_inode_unmap(root); - ASSERT_EQUAL_BOOL(false, root->mapped); - ASSERT_EQUAL_BOOL(false, n1->mapped); - ASSERT_EQUAL_BOOL(false, n2->mapped); - ASSERT_EQUAL_BOOL(false, n3->mapped); - ASSERT_EQUAL_BOOL(false, n11->mapped); - ASSERT_EQUAL_BOOL(false, n12->mapped); - ASSERT_EQUAL_BOOL(false, n21->mapped); - ASSERT_EQUAL_BOOL(false, n211->mapped); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(root)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n1)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n2)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n3)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n11)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n12)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n21)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n211)); zn_inode_map(root); - ASSERT_EQUAL_BOOL(true, root->mapped); - ASSERT_EQUAL_BOOL(true, n1->mapped); - ASSERT_EQUAL_BOOL(true, n2->mapped); - ASSERT_EQUAL_BOOL(true, n3->mapped); - ASSERT_EQUAL_BOOL(true, n11->mapped); - ASSERT_EQUAL_BOOL(true, n12->mapped); - ASSERT_EQUAL_BOOL(true, n21->mapped); - ASSERT_EQUAL_BOOL(true, n211->mapped); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(root)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n1)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n2)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n3)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n11)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n12)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n21)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n211)); zn_inode_move(n1, NULL, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); zn_inode_move(n2, NULL, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); - ASSERT_EQUAL_BOOL(true, root->mapped); - ASSERT_EQUAL_BOOL(false, n1->mapped); - ASSERT_EQUAL_BOOL(false, n2->mapped); - ASSERT_EQUAL_BOOL(true, n3->mapped); - ASSERT_EQUAL_BOOL(false, n11->mapped); - ASSERT_EQUAL_BOOL(false, n12->mapped); - ASSERT_EQUAL_BOOL(false, n21->mapped); - ASSERT_EQUAL_BOOL(false, n211->mapped); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(root)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n1)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n2)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n3)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n11)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n12)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n21)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n211)); zn_inode_unmap(root); zn_inode_move(n1, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); - ASSERT_EQUAL_BOOL(false, root->mapped); - ASSERT_EQUAL_BOOL(false, n1->mapped); - ASSERT_EQUAL_BOOL(false, n2->mapped); - ASSERT_EQUAL_BOOL(false, n3->mapped); - ASSERT_EQUAL_BOOL(false, n11->mapped); - ASSERT_EQUAL_BOOL(false, n12->mapped); - ASSERT_EQUAL_BOOL(false, n21->mapped); - ASSERT_EQUAL_BOOL(false, n211->mapped); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(root)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n1)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n2)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n3)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n11)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n12)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n21)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n211)); zn_inode_map(root); - ASSERT_EQUAL_BOOL(true, root->mapped); - ASSERT_EQUAL_BOOL(true, n1->mapped); - ASSERT_EQUAL_BOOL(false, n2->mapped); - ASSERT_EQUAL_BOOL(true, n3->mapped); - ASSERT_EQUAL_BOOL(true, n11->mapped); - ASSERT_EQUAL_BOOL(true, n12->mapped); - ASSERT_EQUAL_BOOL(false, n21->mapped); - ASSERT_EQUAL_BOOL(false, n211->mapped); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(root)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n1)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n2)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n3)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n11)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n12)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n21)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(n211)); zn_inode_move(n2, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); - ASSERT_EQUAL_BOOL(true, root->mapped); - ASSERT_EQUAL_BOOL(true, n1->mapped); - ASSERT_EQUAL_BOOL(true, n2->mapped); - ASSERT_EQUAL_BOOL(true, n3->mapped); - ASSERT_EQUAL_BOOL(true, n11->mapped); - ASSERT_EQUAL_BOOL(true, n12->mapped); - ASSERT_EQUAL_BOOL(true, n21->mapped); - ASSERT_EQUAL_BOOL(true, n211->mapped); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(root)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n1)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n2)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n3)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n11)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n12)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n21)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(n211)); } FAIL_TEST(non_root_map) @@ -124,6 +124,17 @@ FAIL_TEST(non_root_unmap) zn_inode_unmap(node); } +TEST(already_mapped) +{ + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(NULL, &zn_inode_noop_implementation); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + zn_inode_map(root); + zn_inode_map(root); // no error +} + TEST(destroy) { struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); @@ -133,10 +144,10 @@ TEST(destroy) zn_inode_map(root); - ASSERT_EQUAL_BOOL(true, node->mapped); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(node)); zn_inode_destroy(root); - ASSERT_EQUAL_BOOL(false, node->mapped); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(node)); ASSERT_EQUAL_POINTER(NULL, node->parent); } diff --git a/zen/tests/inode/inode-set-xr-system.c b/zen/tests/inode/inode-set-xr-system.c new file mode 100644 index 00000000..0664bf6f --- /dev/null +++ b/zen/tests/inode/inode-set-xr-system.c @@ -0,0 +1,140 @@ +#include +#include + +#include "inode.h" +#include "test-harness.h" + +TEST(map) +{ + struct zn_xr_system *xr_system = (void *)1; + + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + + struct zn_inode *n1 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n2 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n3 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n11 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n12 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n21 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *n211 = zn_inode_create(NULL, &zn_inode_noop_implementation); + + zn_inode_move(n1, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n2, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n3, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n11, n1, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n12, n1, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n21, n2, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n211, n21, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + zn_inode_map(root); + zn_inode_set_xr_system(root, xr_system); + + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(root)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n1)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n2)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n3)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n11)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n12)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n21)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n211)); + + zn_inode_set_xr_system(root, NULL); + + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(root)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n1)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n2)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n3)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n11)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n12)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n21)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n211)); + + zn_inode_set_xr_system(root, xr_system); + + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(root)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n1)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n2)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n3)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n11)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n12)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n21)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n211)); + + zn_inode_move(n1, NULL, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(n2, NULL, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(root)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n1)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n2)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n3)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n11)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n12)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n21)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n211)); + + zn_inode_set_xr_system(root, NULL); + zn_inode_move(n1, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(root)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n1)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n2)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n3)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n11)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n12)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n21)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n211)); + + zn_inode_set_xr_system(root, xr_system); + + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(root)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n1)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n2)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n3)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n11)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n12)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n21)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n211)); + + zn_inode_unmap(root); + + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(root)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n1)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n2)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n3)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n11)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n12)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n21)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n211)); +} + +FAIL_TEST(non_root_map) +{ + struct zn_xr_system *xr_system = (void *)1; + + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(NULL, &zn_inode_noop_implementation); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + zn_inode_set_xr_system(node, xr_system); +} + +TEST(destroy) +{ + struct zn_xr_system *xr_system = (void *)1; + + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(NULL, &zn_inode_noop_implementation); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + zn_inode_map(root); + zn_inode_set_xr_system(root, xr_system); + + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(node)); + + zn_inode_destroy(root); + + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(node)); + ASSERT_EQUAL_POINTER(NULL, node->parent); +} diff --git a/zen/tests/meson.build b/zen/tests/meson.build index aad0b117..359a0bd5 100644 --- a/zen/tests/meson.build +++ b/zen/tests/meson.build @@ -21,6 +21,7 @@ _zen_unit_tests = { 'config/config-path.c': {}, 'inode/inode-map.c': {}, 'inode/inode-move.c': {}, + 'inode/inode-set-xr-system.c': {}, 'server/construct-destroy.c': {}, 'snode/snode-damage.c': {}, 'snode/snode-focus.c': {}, diff --git a/zen/tests/mock/src/backend.c b/zen/tests/mock/src/backend.c index 5b0b85fe..d0dff0ef 100644 --- a/zen/tests/mock/src/backend.c +++ b/zen/tests/mock/src/backend.c @@ -69,7 +69,7 @@ zn_mock_backend_create(void) wl_signal_init(&self->base.events.destroy); wl_signal_init(&self->base.events.new_xr_system); wl_signal_init(&self->base.events.bounded_mapped); - zn_delay_signal_init(&self->base.events.xr_system_changed); + wl_signal_init(&self->base.events.xr_system_changed); return self; } @@ -79,7 +79,7 @@ zn_mock_backend_destroy(struct zn_mock_backend *self) { zn_signal_emit_mutable(&self->base.events.destroy, NULL); - zn_delay_signal_release(&self->base.events.xr_system_changed); + wl_list_remove(&self->base.events.xr_system_changed.listener_list); wl_list_remove(&self->base.events.new_xr_system.listener_list); wl_list_remove(&self->base.events.destroy.listener_list); wl_list_remove(&self->base.events.view_mapped.listener_list); From 337ba041b39e70ad61f60cd5eaef4f6a428c21d8 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Tue, 25 Jul 2023 22:52:48 +0900 Subject: [PATCH 47/49] add inline --- zen/include/zen/snode-root.h | 4 ++-- zen/include/zen/xr-dispatcher.h | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/zen/include/zen/snode-root.h b/zen/include/zen/snode-root.h index 44312ad0..6f67a82a 100644 --- a/zen/include/zen/snode-root.h +++ b/zen/include/zen/snode-root.h @@ -17,13 +17,13 @@ struct zn_snode_root { struct zn_snode *node; // @nonnull, @owning }; -UNUSED static void +UNUSED static inline void zn_snode_root_damage(struct zn_snode_root *self, struct wlr_fbox *fbox) { self->impl->damage(self->user_data, fbox); } -UNUSED static void +UNUSED static inline void zn_snode_root_layout_position(struct zn_snode_root *self, vec2 position) { self->impl->layout_position(self->user_data, position); diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index 0765c0af..1e833145 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -129,46 +129,46 @@ zn_xr_dispatcher_get_new_gl_shader( return self->impl->get_new_gl_shader(self, buffer, type); } -UNUSED static void +UNUSED static inline void zn_xr_dispatcher_destroy_gl_shader( struct zn_xr_dispatcher *self, struct zn_gl_shader *gl_shader) { self->impl->destroy_gl_shader(self, gl_shader); } -UNUSED static struct zn_gl_program * +UNUSED static inline struct zn_gl_program * zn_xr_dispatcher_get_new_gl_program(struct zn_xr_dispatcher *self) { return self->impl->get_new_gl_program(self); } -UNUSED static void +UNUSED static inline void zn_xr_dispatcher_destroy_gl_program( struct zn_xr_dispatcher *self, struct zn_gl_program *gl_program) { self->impl->destroy_gl_program(self, gl_program); } -UNUSED static struct zn_gl_texture * +UNUSED static inline struct zn_gl_texture * zn_xr_dispatcher_get_new_gl_texture(struct zn_xr_dispatcher *self) { return self->impl->get_new_gl_texture(self); } -UNUSED static void +UNUSED static inline void zn_xr_dispatcher_destroy_gl_texture( struct zn_xr_dispatcher *self, struct zn_gl_texture *gl_texture) { self->impl->destroy_gl_texture(self, gl_texture); } -UNUSED static struct zn_gl_vertex_array * +UNUSED static inline struct zn_gl_vertex_array * zn_xr_dispatcher_get_new_gl_vertex_array(struct zn_xr_dispatcher *self) { return self->impl->get_new_gl_vertex_array(self); } -UNUSED static void +UNUSED static inline void zn_xr_dispatcher_destroy_gl_vertex_array( struct zn_xr_dispatcher *self, struct zn_gl_vertex_array *gl_vertex_array) { From f0d0acc5ed975cc6afd4d01d9d03976efb8268e8 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Tue, 25 Jul 2023 23:05:11 +0900 Subject: [PATCH 48/49] rename header files --- .../immersive/remote/gl-base-technique.cc | 10 +++++----- ...l-base-technique.h => gl-base-technique.hh} | 2 +- zen/src/backend/immersive/remote/gl-buffer.cc | 4 ++-- .../remote/{gl-buffer.h => gl-buffer.hh} | 2 +- zen/src/backend/immersive/remote/gl-program.cc | 4 ++-- .../remote/{gl-program.h => gl-program.hh} | 2 +- .../immersive/remote/gl-rendering-unit.cc | 4 ++-- ...l-rendering-unit.h => gl-rendering-unit.hh} | 2 +- zen/src/backend/immersive/remote/gl-shader.cc | 2 +- .../remote/{gl-shader.h => gl-shader.hh} | 2 +- zen/src/backend/immersive/remote/gl-texture.cc | 4 ++-- .../remote/{gl-texture.h => gl-texture.hh} | 2 +- .../immersive/remote/gl-vertex-array.cc | 4 ++-- .../{gl-vertex-array.h => gl-vertex-array.hh} | 2 +- .../backend/immersive/remote/{log.h => log.hh} | 3 ++- zen/src/backend/immersive/remote/loop.cc | 2 +- .../immersive/remote/{loop.h => loop.hh} | 0 .../backend/immersive/remote/virtual-object.cc | 2 +- .../{virtual-object.h => virtual-object.hh} | 2 +- .../backend/immersive/remote/xr-dispatcher.cc | 18 +++++++++--------- .../{xr-dispatcher.h => xr-dispatcher.hh} | 2 +- .../immersive/remote/xr-system-manager.cc | 8 ++++---- ...r-system-manager.h => xr-system-manager.hh} | 0 zen/src/backend/immersive/remote/xr-system.cc | 10 +++++----- .../remote/{xr-system.h => xr-system.hh} | 0 zen/src/gl-base-technique.c | 3 ++- ...technique-private.h => gl-base-technique.h} | 0 zen/src/gl-buffer.c | 3 ++- zen/src/{gl-buffer-private.h => gl-buffer.h} | 0 zen/src/gl-program.c | 3 ++- zen/src/{gl-program-private.h => gl-program.h} | 0 zen/src/gl-rendering-unit.c | 3 ++- ...ring-unit-private.h => gl-rendering-unit.h} | 0 zen/src/gl-shader.c | 3 ++- zen/src/{gl-shader-private.h => gl-shader.h} | 0 zen/src/gl-texture.c | 3 ++- zen/src/{gl-texture-private.h => gl-texture.h} | 0 zen/src/gl-vertex-array.c | 3 ++- ...ertex-array-private.h => gl-vertex-array.h} | 0 ...rtual-object-private.h => virtual-object.h} | 0 zen/src/xr-dispatcher.c | 3 ++- ...xr-dispatcher-private.h => xr-dispatcher.h} | 0 42 files changed, 63 insertions(+), 54 deletions(-) rename zen/src/backend/immersive/remote/{gl-base-technique.h => gl-base-technique.hh} (98%) rename zen/src/backend/immersive/remote/{gl-buffer.h => gl-buffer.hh} (97%) rename zen/src/backend/immersive/remote/{gl-program.h => gl-program.hh} (97%) rename zen/src/backend/immersive/remote/{gl-rendering-unit.h => gl-rendering-unit.hh} (96%) rename zen/src/backend/immersive/remote/{gl-shader.h => gl-shader.hh} (96%) rename zen/src/backend/immersive/remote/{gl-texture.h => gl-texture.hh} (97%) rename zen/src/backend/immersive/remote/{gl-vertex-array.h => gl-vertex-array.hh} (97%) rename zen/src/backend/immersive/remote/{log.h => log.hh} (97%) rename zen/src/backend/immersive/remote/{loop.h => loop.hh} (100%) rename zen/src/backend/immersive/remote/{virtual-object.h => virtual-object.hh} (96%) rename zen/src/backend/immersive/remote/{xr-dispatcher.h => xr-dispatcher.hh} (98%) rename zen/src/backend/immersive/remote/{xr-system-manager.h => xr-system-manager.hh} (100%) rename zen/src/backend/immersive/remote/{xr-system.h => xr-system.hh} (100%) rename zen/src/{gl-base-technique-private.h => gl-base-technique.h} (100%) rename zen/src/{gl-buffer-private.h => gl-buffer.h} (100%) rename zen/src/{gl-program-private.h => gl-program.h} (100%) rename zen/src/{gl-rendering-unit-private.h => gl-rendering-unit.h} (100%) rename zen/src/{gl-shader-private.h => gl-shader.h} (100%) rename zen/src/{gl-texture-private.h => gl-texture.h} (100%) rename zen/src/{gl-vertex-array-private.h => gl-vertex-array.h} (100%) rename zen/src/{virtual-object-private.h => virtual-object.h} (100%) rename zen/src/{xr-dispatcher-private.h => xr-dispatcher.h} (100%) diff --git a/zen/src/backend/immersive/remote/gl-base-technique.cc b/zen/src/backend/immersive/remote/gl-base-technique.cc index 024f96bf..5ee584ae 100644 --- a/zen/src/backend/immersive/remote/gl-base-technique.cc +++ b/zen/src/backend/immersive/remote/gl-base-technique.cc @@ -1,11 +1,11 @@ -#include "gl-base-technique.h" +#include "gl-base-technique.hh" #include -#include "gl-buffer.h" -#include "gl-program.h" -#include "gl-rendering-unit.h" -#include "gl-vertex-array.h" +#include "gl-buffer.hh" +#include "gl-program.hh" +#include "gl-rendering-unit.hh" +#include "gl-vertex-array.hh" #include "zen-common/log.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-base-technique.h b/zen/src/backend/immersive/remote/gl-base-technique.hh similarity index 98% rename from zen/src/backend/immersive/remote/gl-base-technique.h rename to zen/src/backend/immersive/remote/gl-base-technique.hh index f057e1ac..557ee1e6 100644 --- a/zen/src/backend/immersive/remote/gl-base-technique.h +++ b/zen/src/backend/immersive/remote/gl-base-technique.hh @@ -1,6 +1,6 @@ #pragma once -#include "gl-base-technique-private.h" +#include "gl-base-technique.h" #include "zen-common/cpp-util.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-buffer.cc b/zen/src/backend/immersive/remote/gl-buffer.cc index 1525a6ec..30ea1797 100644 --- a/zen/src/backend/immersive/remote/gl-buffer.cc +++ b/zen/src/backend/immersive/remote/gl-buffer.cc @@ -1,6 +1,6 @@ -#include "gl-buffer.h" +#include "gl-buffer.hh" -#include "loop.h" +#include "loop.hh" #include "zen-common/log.h" #include "zen/buffer.h" diff --git a/zen/src/backend/immersive/remote/gl-buffer.h b/zen/src/backend/immersive/remote/gl-buffer.hh similarity index 97% rename from zen/src/backend/immersive/remote/gl-buffer.h rename to zen/src/backend/immersive/remote/gl-buffer.hh index 7bdc8753..45b4acc3 100644 --- a/zen/src/backend/immersive/remote/gl-buffer.h +++ b/zen/src/backend/immersive/remote/gl-buffer.hh @@ -1,6 +1,6 @@ #pragma once -#include "gl-buffer-private.h" +#include "gl-buffer.h" #include "zen-common/cpp-util.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-program.cc b/zen/src/backend/immersive/remote/gl-program.cc index b6275022..f4d6d336 100644 --- a/zen/src/backend/immersive/remote/gl-program.cc +++ b/zen/src/backend/immersive/remote/gl-program.cc @@ -1,6 +1,6 @@ -#include "gl-program.h" +#include "gl-program.hh" -#include "gl-shader.h" +#include "gl-shader.hh" #include "zen-common/log.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-program.h b/zen/src/backend/immersive/remote/gl-program.hh similarity index 97% rename from zen/src/backend/immersive/remote/gl-program.h rename to zen/src/backend/immersive/remote/gl-program.hh index e2a5390f..19c1ee5e 100644 --- a/zen/src/backend/immersive/remote/gl-program.h +++ b/zen/src/backend/immersive/remote/gl-program.hh @@ -1,6 +1,6 @@ #pragma once -#include "gl-program-private.h" +#include "gl-program.h" #include "zen-common/cpp-util.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-rendering-unit.cc b/zen/src/backend/immersive/remote/gl-rendering-unit.cc index 415b3c8b..72802790 100644 --- a/zen/src/backend/immersive/remote/gl-rendering-unit.cc +++ b/zen/src/backend/immersive/remote/gl-rendering-unit.cc @@ -1,6 +1,6 @@ -#include "gl-rendering-unit.h" +#include "gl-rendering-unit.hh" -#include "virtual-object.h" +#include "virtual-object.hh" #include "zen-common/log.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-rendering-unit.h b/zen/src/backend/immersive/remote/gl-rendering-unit.hh similarity index 96% rename from zen/src/backend/immersive/remote/gl-rendering-unit.h rename to zen/src/backend/immersive/remote/gl-rendering-unit.hh index 7af90c48..65196d10 100644 --- a/zen/src/backend/immersive/remote/gl-rendering-unit.h +++ b/zen/src/backend/immersive/remote/gl-rendering-unit.hh @@ -1,6 +1,6 @@ #pragma once -#include "gl-rendering-unit-private.h" +#include "gl-rendering-unit.h" #include "zen-common/cpp-util.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-shader.cc b/zen/src/backend/immersive/remote/gl-shader.cc index be065d3f..436a7a1a 100644 --- a/zen/src/backend/immersive/remote/gl-shader.cc +++ b/zen/src/backend/immersive/remote/gl-shader.cc @@ -1,4 +1,4 @@ -#include "gl-shader.h" +#include "gl-shader.hh" #include "zen-common/log.h" diff --git a/zen/src/backend/immersive/remote/gl-shader.h b/zen/src/backend/immersive/remote/gl-shader.hh similarity index 96% rename from zen/src/backend/immersive/remote/gl-shader.h rename to zen/src/backend/immersive/remote/gl-shader.hh index f121ed5c..ad17bf5a 100644 --- a/zen/src/backend/immersive/remote/gl-shader.h +++ b/zen/src/backend/immersive/remote/gl-shader.hh @@ -1,6 +1,6 @@ #pragma once -#include "gl-shader-private.h" +#include "gl-shader.h" #include "zen-common/cpp-util.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-texture.cc b/zen/src/backend/immersive/remote/gl-texture.cc index 2ae7cdef..c1fd2997 100644 --- a/zen/src/backend/immersive/remote/gl-texture.cc +++ b/zen/src/backend/immersive/remote/gl-texture.cc @@ -1,6 +1,6 @@ -#include "gl-texture.h" +#include "gl-texture.hh" -#include "loop.h" +#include "loop.hh" #include "zen-common/log.h" #include "zen/buffer.h" diff --git a/zen/src/backend/immersive/remote/gl-texture.h b/zen/src/backend/immersive/remote/gl-texture.hh similarity index 97% rename from zen/src/backend/immersive/remote/gl-texture.h rename to zen/src/backend/immersive/remote/gl-texture.hh index 6ea00e15..d1fca51a 100644 --- a/zen/src/backend/immersive/remote/gl-texture.h +++ b/zen/src/backend/immersive/remote/gl-texture.hh @@ -1,6 +1,6 @@ #pragma once -#include "gl-texture-private.h" +#include "gl-texture.h" #include "zen-common/cpp-util.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-vertex-array.cc b/zen/src/backend/immersive/remote/gl-vertex-array.cc index 33aada0e..07245027 100644 --- a/zen/src/backend/immersive/remote/gl-vertex-array.cc +++ b/zen/src/backend/immersive/remote/gl-vertex-array.cc @@ -1,6 +1,6 @@ -#include "gl-vertex-array.h" +#include "gl-vertex-array.hh" -#include "gl-buffer.h" +#include "gl-buffer.hh" #include "zen-common/log.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/gl-vertex-array.h b/zen/src/backend/immersive/remote/gl-vertex-array.hh similarity index 97% rename from zen/src/backend/immersive/remote/gl-vertex-array.h rename to zen/src/backend/immersive/remote/gl-vertex-array.hh index 63e82dce..206157e1 100644 --- a/zen/src/backend/immersive/remote/gl-vertex-array.h +++ b/zen/src/backend/immersive/remote/gl-vertex-array.hh @@ -1,6 +1,6 @@ #pragma once -#include "gl-vertex-array-private.h" +#include "gl-vertex-array.h" #include "zen-common/cpp-util.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/log.h b/zen/src/backend/immersive/remote/log.hh similarity index 97% rename from zen/src/backend/immersive/remote/log.h rename to zen/src/backend/immersive/remote/log.hh index f38a7f3f..4185cab2 100644 --- a/zen/src/backend/immersive/remote/log.h +++ b/zen/src/backend/immersive/remote/log.hh @@ -1,10 +1,11 @@ #pragma once -#include #include #include +#include "zen-common/log.h" + namespace zen::backend::immersive::remote { class LogSink : public zen::remote::ILogSink diff --git a/zen/src/backend/immersive/remote/loop.cc b/zen/src/backend/immersive/remote/loop.cc index bc53c588..88eea0f8 100644 --- a/zen/src/backend/immersive/remote/loop.cc +++ b/zen/src/backend/immersive/remote/loop.cc @@ -1,4 +1,4 @@ -#include "loop.h" +#include "loop.hh" #include "zen-common/terminate.h" diff --git a/zen/src/backend/immersive/remote/loop.h b/zen/src/backend/immersive/remote/loop.hh similarity index 100% rename from zen/src/backend/immersive/remote/loop.h rename to zen/src/backend/immersive/remote/loop.hh diff --git a/zen/src/backend/immersive/remote/virtual-object.cc b/zen/src/backend/immersive/remote/virtual-object.cc index 2d0927e5..53f12f06 100644 --- a/zen/src/backend/immersive/remote/virtual-object.cc +++ b/zen/src/backend/immersive/remote/virtual-object.cc @@ -1,4 +1,4 @@ -#include "virtual-object.h" +#include "virtual-object.hh" #include "zen-common/log.h" diff --git a/zen/src/backend/immersive/remote/virtual-object.h b/zen/src/backend/immersive/remote/virtual-object.hh similarity index 96% rename from zen/src/backend/immersive/remote/virtual-object.h rename to zen/src/backend/immersive/remote/virtual-object.hh index 2577f8d9..494e99af 100644 --- a/zen/src/backend/immersive/remote/virtual-object.h +++ b/zen/src/backend/immersive/remote/virtual-object.hh @@ -1,6 +1,6 @@ #pragma once -#include "virtual-object-private.h" +#include "virtual-object.h" #include "zen-common/cpp-util.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index 565aa483..67ef5b23 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -1,15 +1,15 @@ -#include "xr-dispatcher.h" +#include "xr-dispatcher.hh" #include -#include "gl-base-technique.h" -#include "gl-buffer.h" -#include "gl-program.h" -#include "gl-rendering-unit.h" -#include "gl-shader.h" -#include "gl-texture.h" -#include "gl-vertex-array.h" -#include "virtual-object.h" +#include "gl-base-technique.hh" +#include "gl-buffer.hh" +#include "gl-program.hh" +#include "gl-rendering-unit.hh" +#include "gl-shader.hh" +#include "gl-texture.hh" +#include "gl-vertex-array.hh" +#include "virtual-object.hh" #include "zen-common/log.h" #include "zen/buffer.h" diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.h b/zen/src/backend/immersive/remote/xr-dispatcher.hh similarity index 98% rename from zen/src/backend/immersive/remote/xr-dispatcher.h rename to zen/src/backend/immersive/remote/xr-dispatcher.hh index 3d211b57..b74367f5 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.h +++ b/zen/src/backend/immersive/remote/xr-dispatcher.hh @@ -1,6 +1,6 @@ #pragma once -#include "xr-dispatcher-private.h" +#include "xr-dispatcher.h" #include "zen-common/cpp-util.h" namespace zen::backend::immersive::remote { diff --git a/zen/src/backend/immersive/remote/xr-system-manager.cc b/zen/src/backend/immersive/remote/xr-system-manager.cc index f04de3a2..d7fb20f6 100644 --- a/zen/src/backend/immersive/remote/xr-system-manager.cc +++ b/zen/src/backend/immersive/remote/xr-system-manager.cc @@ -1,8 +1,8 @@ -#include "xr-system-manager.h" +#include "xr-system-manager.hh" -#include "log.h" -#include "loop.h" -#include "xr-system.h" +#include "log.hh" +#include "loop.hh" +#include "xr-system.hh" #include "zen-common/log.h" static void zn_xr_system_manager_destroy_remote( diff --git a/zen/src/backend/immersive/remote/xr-system-manager.h b/zen/src/backend/immersive/remote/xr-system-manager.hh similarity index 100% rename from zen/src/backend/immersive/remote/xr-system-manager.h rename to zen/src/backend/immersive/remote/xr-system-manager.hh diff --git a/zen/src/backend/immersive/remote/xr-system.cc b/zen/src/backend/immersive/remote/xr-system.cc index 5e5a1bd2..7ebad8a0 100644 --- a/zen/src/backend/immersive/remote/xr-system.cc +++ b/zen/src/backend/immersive/remote/xr-system.cc @@ -1,9 +1,9 @@ -#include "xr-system.h" +#include "xr-system.hh" -#include "loop.h" -#include "virtual-object.h" -#include "xr-dispatcher.h" -#include "xr-system-manager.h" +#include "loop.hh" +#include "virtual-object.hh" +#include "xr-dispatcher.hh" +#include "xr-system-manager.hh" #include "zen-common/log.h" #include "zen-common/signal.h" diff --git a/zen/src/backend/immersive/remote/xr-system.h b/zen/src/backend/immersive/remote/xr-system.hh similarity index 100% rename from zen/src/backend/immersive/remote/xr-system.h rename to zen/src/backend/immersive/remote/xr-system.hh diff --git a/zen/src/gl-base-technique.c b/zen/src/gl-base-technique.c index 80835cbe..d7ab9ee7 100644 --- a/zen/src/gl-base-technique.c +++ b/zen/src/gl-base-technique.c @@ -1,4 +1,5 @@ -#include "gl-base-technique-private.h" +#include "gl-base-technique.h" + #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" diff --git a/zen/src/gl-base-technique-private.h b/zen/src/gl-base-technique.h similarity index 100% rename from zen/src/gl-base-technique-private.h rename to zen/src/gl-base-technique.h diff --git a/zen/src/gl-buffer.c b/zen/src/gl-buffer.c index 7fa8411a..56243346 100644 --- a/zen/src/gl-buffer.c +++ b/zen/src/gl-buffer.c @@ -1,4 +1,5 @@ -#include "gl-buffer-private.h" +#include "gl-buffer.h" + #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" diff --git a/zen/src/gl-buffer-private.h b/zen/src/gl-buffer.h similarity index 100% rename from zen/src/gl-buffer-private.h rename to zen/src/gl-buffer.h diff --git a/zen/src/gl-program.c b/zen/src/gl-program.c index be1e310a..3e95bcf5 100644 --- a/zen/src/gl-program.c +++ b/zen/src/gl-program.c @@ -1,4 +1,5 @@ -#include "gl-program-private.h" +#include "gl-program.h" + #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" diff --git a/zen/src/gl-program-private.h b/zen/src/gl-program.h similarity index 100% rename from zen/src/gl-program-private.h rename to zen/src/gl-program.h diff --git a/zen/src/gl-rendering-unit.c b/zen/src/gl-rendering-unit.c index ed4f957c..011327d7 100644 --- a/zen/src/gl-rendering-unit.c +++ b/zen/src/gl-rendering-unit.c @@ -1,4 +1,5 @@ -#include "gl-rendering-unit-private.h" +#include "gl-rendering-unit.h" + #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" diff --git a/zen/src/gl-rendering-unit-private.h b/zen/src/gl-rendering-unit.h similarity index 100% rename from zen/src/gl-rendering-unit-private.h rename to zen/src/gl-rendering-unit.h diff --git a/zen/src/gl-shader.c b/zen/src/gl-shader.c index 851d0c40..1dc587d8 100644 --- a/zen/src/gl-shader.c +++ b/zen/src/gl-shader.c @@ -1,4 +1,5 @@ -#include "gl-shader-private.h" +#include "gl-shader.h" + #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" diff --git a/zen/src/gl-shader-private.h b/zen/src/gl-shader.h similarity index 100% rename from zen/src/gl-shader-private.h rename to zen/src/gl-shader.h diff --git a/zen/src/gl-texture.c b/zen/src/gl-texture.c index caa18a02..f8cfeed5 100644 --- a/zen/src/gl-texture.c +++ b/zen/src/gl-texture.c @@ -1,4 +1,5 @@ -#include "gl-texture-private.h" +#include "gl-texture.h" + #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" diff --git a/zen/src/gl-texture-private.h b/zen/src/gl-texture.h similarity index 100% rename from zen/src/gl-texture-private.h rename to zen/src/gl-texture.h diff --git a/zen/src/gl-vertex-array.c b/zen/src/gl-vertex-array.c index 277e1547..71539bc2 100644 --- a/zen/src/gl-vertex-array.c +++ b/zen/src/gl-vertex-array.c @@ -1,4 +1,5 @@ -#include "gl-vertex-array-private.h" +#include "gl-vertex-array.h" + #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" diff --git a/zen/src/gl-vertex-array-private.h b/zen/src/gl-vertex-array.h similarity index 100% rename from zen/src/gl-vertex-array-private.h rename to zen/src/gl-vertex-array.h diff --git a/zen/src/virtual-object-private.h b/zen/src/virtual-object.h similarity index 100% rename from zen/src/virtual-object-private.h rename to zen/src/virtual-object.h diff --git a/zen/src/xr-dispatcher.c b/zen/src/xr-dispatcher.c index 99862f7e..a8ba71fb 100644 --- a/zen/src/xr-dispatcher.c +++ b/zen/src/xr-dispatcher.c @@ -1,4 +1,5 @@ -#include "xr-dispatcher-private.h" +#include "xr-dispatcher.h" + #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" diff --git a/zen/src/xr-dispatcher-private.h b/zen/src/xr-dispatcher.h similarity index 100% rename from zen/src/xr-dispatcher-private.h rename to zen/src/xr-dispatcher.h From ff2640c4c047d6ba2f92bba87e7c780a45b35571 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Sun, 28 Jan 2024 09:16:41 +0900 Subject: [PATCH 49/49] draw box --- common/include/zen-common/log.h | 8 +- common/include/zen-common/util.h | 8 + common/src/log.c | 6 +- zen/include/zen/inode.h | 9 +- zen/include/zen/server.h | 5 +- zen/include/zen/virtual-object.h | 25 +- zen/include/zen/xr-dispatcher.h | 29 ++- zen/meson.build | 1 + zen/src/backend/default-backend.c | 49 ++-- zen/src/backend/default-backend.h | 7 +- .../backend/immersive/client-virtual-object.c | 44 +--- .../backend/immersive/client-virtual-object.h | 9 +- zen/src/backend/immersive/gl-context.h | 27 ++ .../immersive/gl/client-gl-base-technique.c | 25 +- .../backend/immersive/gl/client-gl-context.c | 191 -------------- .../backend/immersive/gl/client-gl-context.h | 23 -- .../immersive/gl/client-gl-rendering-unit.c | 22 +- zen/src/backend/immersive/gl/gl-context.c | 241 ++++++++++++++++++ zen/src/backend/immersive/gl/meson.build | 3 +- zen/src/backend/immersive/gl/xr-gl.c | 79 ------ .../immersive/remote/gl-rendering-unit.cc | 6 +- .../immersive/remote/gl-rendering-unit.hh | 6 +- .../immersive/remote/gl-virtual-object.cc | 76 ++++++ .../immersive/remote/gl-virtual-object.hh | 50 ++++ zen/src/backend/immersive/remote/meson.build | 2 +- .../immersive/remote/virtual-object.cc | 72 ------ .../immersive/remote/virtual-object.hh | 48 ---- .../backend/immersive/remote/xr-dispatcher.cc | 25 +- .../backend/immersive/remote/xr-dispatcher.hh | 13 +- zen/src/backend/immersive/remote/xr-system.cc | 2 +- zen/src/backend/immersive/xr-compositor.c | 56 +--- zen/src/backend/immersive/xr-compositor.h | 11 +- zen/src/backend/immersive/xr-gl.h | 11 - zen/src/backend/immersive/xr.c | 16 +- zen/src/backend/immersive/xr.h | 6 +- zen/src/backend/screen/xdg-toplevel.c | 2 +- zen/src/gl-virtual-object.c | 36 +++ zen/src/gl-virtual-object.h | 52 ++++ zen/src/inode.c | 22 +- zen/src/server.c | 17 +- zen/src/virtual-object.c | 91 ++++++- zen/src/virtual-object.h | 16 -- zen/tests/inode/inode-map.c | 15 +- zen/tests/inode/inode-move.c | 121 ++++++++- zen/tests/inode/inode-set-xr-system.c | 87 +++++-- 45 files changed, 954 insertions(+), 716 deletions(-) create mode 100644 zen/src/backend/immersive/gl-context.h delete mode 100644 zen/src/backend/immersive/gl/client-gl-context.c delete mode 100644 zen/src/backend/immersive/gl/client-gl-context.h create mode 100644 zen/src/backend/immersive/gl/gl-context.c delete mode 100644 zen/src/backend/immersive/gl/xr-gl.c create mode 100644 zen/src/backend/immersive/remote/gl-virtual-object.cc create mode 100644 zen/src/backend/immersive/remote/gl-virtual-object.hh delete mode 100644 zen/src/backend/immersive/remote/virtual-object.cc delete mode 100644 zen/src/backend/immersive/remote/virtual-object.hh delete mode 100644 zen/src/backend/immersive/xr-gl.h create mode 100644 zen/src/gl-virtual-object.c create mode 100644 zen/src/gl-virtual-object.h delete mode 100644 zen/src/virtual-object.h diff --git a/common/include/zen-common/log.h b/common/include/zen-common/log.h index c41e0060..fb22e803 100644 --- a/common/include/zen-common/log.h +++ b/common/include/zen-common/log.h @@ -5,6 +5,8 @@ #include #include +#include "util.h" + #ifdef __cplusplus extern "C" { #endif @@ -36,7 +38,8 @@ void zn_vlog_(zn_log_importance_t verbosity, const char *format, va_list args) void zn_abort_(const char *format, ...) ATTRIB_PRINTF(1, 2); -bool zn_assert_(bool condition, const char *format, ...) ATTRIB_PRINTF(2, 3); +bool zn_assert_handler_(const char *format, ...) + ATTRIB_PRINTF(1, 2) CLANG_ANALYZER_NORETURN; #define zn_log(verb, fmt, ...) \ zn_log_(verb, "[zen] [%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__) @@ -60,7 +63,8 @@ bool zn_assert_(bool condition, const char *format, ...) ATTRIB_PRINTF(2, 3); zn_abort_("[zen] [%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__) #define zn_assert(cond, fmt, ...) \ - zn_assert_(cond, "[zen] [%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__) + (cond || zn_assert_handler_( \ + "[zen] [%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__)) #define zn_warn_once(fmt, ...) \ { \ diff --git a/common/include/zen-common/util.h b/common/include/zen-common/util.h index 79fc51fd..32916af8 100644 --- a/common/include/zen-common/util.h +++ b/common/include/zen-common/util.h @@ -28,6 +28,14 @@ extern "C" { #endif #endif +#ifndef CLANG_ANALYZER_NORETURN +#if __has_feature(attribute_analyzer_noreturn) +#define CLANG_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) +#else +#define CLANG_ANALYZER_NORETURN +#endif +#endif + /** Allocate memory and set to zero */ UNUSED static inline void * zalloc(size_t size) diff --git a/common/src/log.c b/common/src/log.c index ef7fe7df..07cb9527 100644 --- a/common/src/log.c +++ b/common/src/log.c @@ -121,12 +121,8 @@ zn_abort_(const char *format, ...) } bool -zn_assert_(bool condition, const char *format, ...) +zn_assert_handler_(const char *format, ...) { - if (condition) { - return true; - } - va_list args; va_start(args, format); zn_vlog_(ZEN_ERROR, format, args); diff --git a/zen/include/zen/inode.h b/zen/include/zen/inode.h index 5d7f162a..cc8f7ef7 100644 --- a/zen/include/zen/inode.h +++ b/zen/include/zen/inode.h @@ -46,12 +46,6 @@ struct zn_inode { struct zn_inode *parent; // @nullable, @ref struct wl_list link; // zn_inode::child_list struct wl_list child_list; // zn_inode::link - - struct wl_listener parent_destroy_listener; - - struct { - struct wl_signal destroy; // (NULL) - } events; }; UNUSED static inline bool @@ -63,7 +57,7 @@ zn_inode_is_mapped(struct zn_inode *self) UNUSED static inline bool zn_inode_is_active(struct zn_inode *self) { - return self->mapped && self->xr_system != NULL; + return self->xr_system != NULL; } void zn_inode_move(struct zn_inode *self, struct zn_inode *parent, @@ -78,4 +72,5 @@ void zn_inode_map(struct zn_inode *self); struct zn_inode *zn_inode_create( void *impl_data, const struct zn_inode_interface *implementation); +/// Destroy child inodes before the parent inode void zn_inode_destroy(struct zn_inode *self); diff --git a/zen/include/zen/server.h b/zen/include/zen/server.h index fceca3ab..24d06a88 100644 --- a/zen/include/zen/server.h +++ b/zen/include/zen/server.h @@ -16,9 +16,10 @@ struct zn_server { struct zn_binding *binding; // @nonnull, @owning struct zn_config *config; // @nonnull, @outlive - // zn_inode_set_xr_system for this root inode is called in the backend + // zn_inode_set_xr_system for these root inodes is called in the backend // implementation - struct zn_inode *inode_root; // @nonnull, @owning + struct zn_inode *inode_root; // @nonnull, @owning + struct zn_inode *inode_invisible_root; // @nonnull, @owning bool running; int exit_status; diff --git a/zen/include/zen/virtual-object.h b/zen/include/zen/virtual-object.h index 4ddec4ca..f8a2c91e 100644 --- a/zen/include/zen/virtual-object.h +++ b/zen/include/zen/virtual-object.h @@ -8,22 +8,19 @@ extern "C" { #endif -struct zn_virtual_object; struct zn_bounded; +struct zn_gl_virtual_object; +struct zn_inode; enum zn_virtual_object_role { ZN_VIRTUAL_OBJECT_ROLE_NONE = 0, ZN_VIRTUAL_OBJECT_ROLE_BOUNDED, }; -struct zn_virtual_object_interface { - void (*committed)(struct zn_virtual_object *self); - void (*change_visibility)(struct zn_virtual_object *self, bool visible); -}; - struct zn_virtual_object { - void *impl_data; // @nullable, @outlive - const struct zn_virtual_object_interface *impl; // @nonnull, @outlive + struct zn_inode *inode; // @nonnull, @owning + + struct zn_gl_virtual_object *gl_virtual_object; // @nullable, @ref union { void *role_object; // @nullable, @ref @@ -41,17 +38,17 @@ struct zn_virtual_object { void zn_virtual_object_commit(struct zn_virtual_object *self); -UNUSED static inline void -zn_virtual_object_change_visibility( - struct zn_virtual_object *self, bool visible) -{ - self->impl->change_visibility(self, visible); -} +void zn_virtual_object_change_visibility( + struct zn_virtual_object *self, bool visible); /// @return true if successful, false otherwise bool zn_virtual_object_set_role(struct zn_virtual_object *self, enum zn_virtual_object_role role, void *role_object); +struct zn_virtual_object *zn_virtual_object_create(void); + +void zn_virtual_object_destroy(struct zn_virtual_object *self); + #ifdef __cplusplus } #endif diff --git a/zen/include/zen/xr-dispatcher.h b/zen/include/zen/xr-dispatcher.h index 1e833145..b470960b 100644 --- a/zen/include/zen/xr-dispatcher.h +++ b/zen/include/zen/xr-dispatcher.h @@ -16,17 +16,18 @@ struct zn_gl_rendering_unit; struct zn_gl_shader; struct zn_gl_texture; struct zn_gl_vertex_array; -struct zn_virtual_object; +struct zn_gl_virtual_object; struct zn_xr_dispatcher; struct zn_xr_dispatcher_interface { - struct zn_virtual_object *(*get_new_virtual_object)( + struct zn_gl_virtual_object *(*get_new_gl_virtual_object)( struct zn_xr_dispatcher *self); - void (*destroy_virtual_object)( - struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object); + void (*destroy_gl_virtual_object)(struct zn_xr_dispatcher *self, + struct zn_gl_virtual_object *gl_virtual_object); struct zn_gl_rendering_unit *(*get_new_gl_rendering_unit)( - struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object); + struct zn_xr_dispatcher *self, + struct zn_gl_virtual_object *gl_virtual_object); void (*destroy_gl_rendering_unit)(struct zn_xr_dispatcher *self, struct zn_gl_rendering_unit *gl_rendering_unit); @@ -68,24 +69,24 @@ struct zn_xr_dispatcher { } events; }; -UNUSED static inline struct zn_virtual_object * -zn_xr_dispatcher_get_new_virtual_object(struct zn_xr_dispatcher *self) +UNUSED static inline struct zn_gl_virtual_object * +zn_xr_dispatcher_get_new_gl_virtual_object(struct zn_xr_dispatcher *self) { - return self->impl->get_new_virtual_object(self); + return self->impl->get_new_gl_virtual_object(self); } UNUSED static inline void -zn_xr_dispatcher_destroy_virtual_object( - struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object) +zn_xr_dispatcher_destroy_gl_virtual_object(struct zn_xr_dispatcher *self, + struct zn_gl_virtual_object *gl_virtual_object) { - self->impl->destroy_virtual_object(self, virtual_object); + self->impl->destroy_gl_virtual_object(self, gl_virtual_object); } UNUSED static inline struct zn_gl_rendering_unit * -zn_xr_dispatcher_get_new_gl_rendering_unit( - struct zn_xr_dispatcher *self, struct zn_virtual_object *virtual_object) +zn_xr_dispatcher_get_new_gl_rendering_unit(struct zn_xr_dispatcher *self, + struct zn_gl_virtual_object *gl_virtual_object) { - return self->impl->get_new_gl_rendering_unit(self, virtual_object); + return self->impl->get_new_gl_rendering_unit(self, gl_virtual_object); } UNUSED static inline void diff --git a/zen/meson.build b/zen/meson.build index 8781684a..dc81b4e6 100644 --- a/zen/meson.build +++ b/zen/meson.build @@ -10,6 +10,7 @@ _zen_srcs = [ 'src/gl-shader.c', 'src/gl-texture.c', 'src/gl-vertex-array.c', + 'src/gl-virtual-object.c', 'src/inode.c', 'src/screen.c', 'src/seat.c', diff --git a/zen/src/backend/default-backend.c b/zen/src/backend/default-backend.c index cc97819d..c41cb9a1 100644 --- a/zen/src/backend/default-backend.c +++ b/zen/src/backend/default-backend.c @@ -7,8 +7,8 @@ #include #include +#include "immersive/gl-context.h" #include "immersive/shm.h" -#include "immersive/xr-compositor.h" #include "immersive/xr-system-manager.h" #include "immersive/xr.h" #include "inode.h" @@ -86,37 +86,39 @@ zn_default_backend_set_xr_system( struct zn_server *server = zn_server_get_singleton(); - if (self->xr_compositor) { - wl_list_remove(&self->xr_compositor_destroy_listener.link); - wl_list_init(&self->xr_compositor_destroy_listener.link); - zn_xr_compositor_destroy(self->xr_compositor); - self->xr_compositor = NULL; + if (self->gl_context) { + wl_list_remove(&self->gl_context_destroy_listener.link); + wl_list_init(&self->gl_context_destroy_listener.link); + zn_gl_context_destroy(self->gl_context); + self->gl_context = NULL; } if (xr_system) { - self->xr_compositor = zn_xr_compositor_create(self->display, xr_system); - wl_signal_add(&self->xr_compositor->events.destroy, - &self->xr_compositor_destroy_listener); + self->gl_context = zn_gl_context_create(self->display, xr_system); + wl_signal_add( + &self->gl_context->events.destroy, &self->gl_context_destroy_listener); } zn_inode_set_xr_system(server->inode_root, xr_system); + zn_inode_set_xr_system(server->inode_invisible_root, xr_system); zn_signal_emit_mutable(&self->base.events.xr_system_changed, xr_system); } static void -zn_default_backend_handle_xr_compositor_destroy( +zn_default_backend_handle_gl_context_destroy( struct wl_listener *listener, void *data UNUSED) { struct zn_default_backend *self = - zn_container_of(listener, self, xr_compositor_destroy_listener); + zn_container_of(listener, self, gl_context_destroy_listener); struct zn_server *server = zn_server_get_singleton(); - wl_list_remove(&self->xr_compositor_destroy_listener.link); - wl_list_init(&self->xr_compositor_destroy_listener.link); - self->xr_compositor = NULL; + wl_list_remove(&self->gl_context_destroy_listener.link); + wl_list_init(&self->gl_context_destroy_listener.link); + self->gl_context = NULL; zn_inode_set_xr_system(server->inode_root, NULL); + zn_inode_set_xr_system(server->inode_invisible_root, NULL); zn_signal_emit_mutable(&self->base.events.xr_system_changed, NULL); } @@ -229,7 +231,7 @@ static struct zn_xr_system * zn_default_backend_handle_get_xr_system(struct zn_backend *base) { struct zn_default_backend *self = zn_container_of(base, self, base); - return self->xr_compositor ? self->xr_compositor->xr_system : NULL; + return self->gl_context ? self->gl_context->xr_system : NULL; } static bool @@ -281,7 +283,7 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) wl_signal_init(&self->base.events.xr_system_changed); self->base.impl = &implementation; self->display = display; - self->xr_compositor = NULL; + self->gl_context = NULL; wl_list_init(&self->input_device_list); self->wlr_backend = wlr_backend_autocreate(display); @@ -342,9 +344,9 @@ zn_default_backend_create(struct wl_display *display, struct zn_seat *zn_seat) wl_signal_add(&self->xr->xr_system_manager->events.new_system, &self->new_xr_system_listener); - self->xr_compositor_destroy_listener.notify = - zn_default_backend_handle_xr_compositor_destroy; - wl_list_init(&self->xr_compositor_destroy_listener.link); + self->gl_context_destroy_listener.notify = + zn_default_backend_handle_gl_context_destroy; + wl_list_init(&self->gl_context_destroy_listener.link); return &self->base; @@ -372,11 +374,12 @@ zn_default_backend_destroy(struct zn_default_backend *self) { zn_signal_emit_mutable(&self->base.events.destroy, NULL); - if (self->xr_compositor) { - zn_xr_compositor_destroy(self->xr_compositor); - self->xr_compositor = NULL; + if (self->gl_context) { + zn_gl_context_destroy(self->gl_context); + self->gl_context = NULL; } - wl_list_remove(&self->xr_compositor_destroy_listener.link); + + wl_list_remove(&self->gl_context_destroy_listener.link); wl_list_remove(&self->new_xr_system_listener.link); wl_list_remove(&self->new_input_listener.link); wl_list_remove(&self->new_output_listener.link); diff --git a/zen/src/backend/default-backend.h b/zen/src/backend/default-backend.h index 0c7b7eb3..449e92f5 100644 --- a/zen/src/backend/default-backend.h +++ b/zen/src/backend/default-backend.h @@ -4,6 +4,7 @@ struct zn_bounded; struct zn_compositor; +struct zn_gl_context; struct zn_view; struct zn_xr; @@ -21,8 +22,8 @@ struct zn_default_backend { struct zn_compositor *compositor; // @nonnull, @owning // Basically owned by zn_default_backend, but can be destroyed when given - // xr_system is destroyed. - struct zn_xr_compositor *xr_compositor; // @nullable + // xr_system is disconnected or destroyed. + struct zn_gl_context *gl_context; // @nullable struct zn_xr *xr; // @nonnull, @owing @@ -31,7 +32,7 @@ struct zn_default_backend { struct wl_listener new_input_listener; struct wl_listener new_output_listener; struct wl_listener new_xr_system_listener; - struct wl_listener xr_compositor_destroy_listener; + struct wl_listener gl_context_destroy_listener; }; struct zn_default_backend *zn_default_backend_get(struct zn_backend *base); diff --git a/zen/src/backend/immersive/client-virtual-object.c b/zen/src/backend/immersive/client-virtual-object.c index ec3a6af0..0506bfbe 100644 --- a/zen/src/backend/immersive/client-virtual-object.c +++ b/zen/src/backend/immersive/client-virtual-object.c @@ -6,7 +6,6 @@ #include "zen-common/signal.h" #include "zen-common/util.h" #include "zen/virtual-object.h" -#include "zen/xr-dispatcher.h" static void zn_client_virtual_object_destroy( struct zn_client_virtual_object *self); @@ -67,29 +66,8 @@ zn_client_virtual_object_get(struct wl_resource *resource) return wl_resource_get_user_data(resource); } -static void -zn_client_virtual_object_handle_dispatcher_destroy( - struct wl_listener *listener, void *data UNUSED) -{ - struct zn_client_virtual_object *self = - zn_container_of(listener, self, dispatcher_destroy_listener); - - zn_client_virtual_object_destroy(self); -} - -static void -zn_client_virtual_object_handle_zn_virtual_object_destroy( - struct wl_listener *listener, void *data UNUSED) -{ - struct zn_client_virtual_object *self = - zn_container_of(listener, self, zn_virtual_object_destroy_listener); - - zn_client_virtual_object_destroy(self); -} - struct zn_client_virtual_object * -zn_client_virtual_object_create( - struct wl_client *client, uint32_t id, struct zn_xr_dispatcher *dispatcher) +zn_client_virtual_object_create(struct wl_client *client, uint32_t id) { struct zn_client_virtual_object *self = zalloc(sizeof *self); if (self == NULL) { @@ -97,10 +75,9 @@ zn_client_virtual_object_create( goto err; } - self->dispatcher = dispatcher; wl_signal_init(&self->events.destroy); - self->zn_virtual_object = zn_xr_dispatcher_get_new_virtual_object(dispatcher); + self->zn_virtual_object = zn_virtual_object_create(); if (self->zn_virtual_object == NULL) { zn_error("Failed to get new zn_virtual_object"); wl_client_post_no_memory(client); @@ -118,20 +95,10 @@ zn_client_virtual_object_create( wl_resource_set_implementation(self->resource, &implementation, self, &zn_client_virtual_object_handle_destroy); - self->zn_virtual_object_destroy_listener.notify = - zn_client_virtual_object_handle_zn_virtual_object_destroy; - wl_signal_add(&self->zn_virtual_object->events.destroy, - &self->zn_virtual_object_destroy_listener); - - self->dispatcher_destroy_listener.notify = - zn_client_virtual_object_handle_dispatcher_destroy; - wl_signal_add( - &self->dispatcher->events.destroy, &self->dispatcher_destroy_listener); - return self; err_zn_virtual_object: - zn_xr_dispatcher_destroy_virtual_object(dispatcher, self->zn_virtual_object); + zn_virtual_object_destroy(self->zn_virtual_object); err_free: free(self); @@ -146,10 +113,7 @@ zn_client_virtual_object_destroy(struct zn_client_virtual_object *self) zn_signal_emit_mutable(&self->events.destroy, NULL); wl_list_remove(&self->events.destroy.listener_list); - wl_list_remove(&self->zn_virtual_object_destroy_listener.link); - wl_list_remove(&self->dispatcher_destroy_listener.link); - zn_xr_dispatcher_destroy_virtual_object( - self->dispatcher, self->zn_virtual_object); + zn_virtual_object_destroy(self->zn_virtual_object); wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); free(self); } diff --git a/zen/src/backend/immersive/client-virtual-object.h b/zen/src/backend/immersive/client-virtual-object.h index bab8e5e9..e84ac06f 100644 --- a/zen/src/backend/immersive/client-virtual-object.h +++ b/zen/src/backend/immersive/client-virtual-object.h @@ -8,12 +8,7 @@ struct zn_xr_dispatcher; struct zn_client_virtual_object { struct wl_resource *resource; // @nonnull, @outlive - struct zn_xr_dispatcher *dispatcher; // @nonnull, @outlive - - struct zn_virtual_object *zn_virtual_object; // @nonnull, @outlive - - struct wl_listener dispatcher_destroy_listener; - struct wl_listener zn_virtual_object_destroy_listener; + struct zn_virtual_object *zn_virtual_object; // @nonnull, @owning struct { struct wl_signal destroy; // (NULL) @@ -21,7 +16,7 @@ struct zn_client_virtual_object { }; struct zn_client_virtual_object *zn_client_virtual_object_create( - struct wl_client *client, uint32_t id, struct zn_xr_dispatcher *dispatcher); + struct wl_client *client, uint32_t id); struct zn_client_virtual_object *zn_client_virtual_object_get( struct wl_resource *resource); diff --git a/zen/src/backend/immersive/gl-context.h b/zen/src/backend/immersive/gl-context.h new file mode 100644 index 00000000..f93fa57e --- /dev/null +++ b/zen/src/backend/immersive/gl-context.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +struct zn_xr_system; + +struct zn_gl_context { + struct wl_global *global; // @nonnull, @owning + + struct wl_list resource_list; // wl_resource::link of zwn_gl_context + + // must be connected state + struct zn_xr_system *xr_system; // @nonnull, @outlive + + struct wl_listener xr_system_session_state_changed_listener; + + bool destroying; + + struct { + struct wl_signal destroy; + } events; +}; + +struct zn_gl_context *zn_gl_context_create( + struct wl_display *display, struct zn_xr_system *xr_system); + +void zn_gl_context_destroy(struct zn_gl_context *self); diff --git a/zen/src/backend/immersive/gl/client-gl-base-technique.c b/zen/src/backend/immersive/gl/client-gl-base-technique.c index 3fb4861d..ed2e0e3d 100644 --- a/zen/src/backend/immersive/gl/client-gl-base-technique.c +++ b/zen/src/backend/immersive/gl/client-gl-base-technique.c @@ -8,10 +8,12 @@ #include "client-gl-program.h" #include "client-gl-rendering-unit.h" #include "client-gl-vertex-array.h" +#include "gl-virtual-object.h" #include "zen-common/log.h" #include "zen-common/util.h" #include "zen-common/wl-array.h" #include "zen/gl-base-technique.h" +#include "zen/virtual-object.h" #include "zen/xr-dispatcher.h" static void zn_client_gl_base_technique_destroy( @@ -234,6 +236,13 @@ struct zn_client_gl_base_technique * zn_client_gl_base_technique_create(struct wl_client *client, uint32_t id, struct zn_client_gl_rendering_unit *rendering_unit) { + struct zn_gl_virtual_object *gl_virtual_object = + rendering_unit->virtual_object->zn_virtual_object->gl_virtual_object; + if (gl_virtual_object == NULL) { + zn_error("Failed to get gl_virtual_object"); + return NULL; + } + struct zn_client_gl_base_technique *self = zalloc(sizeof *self); if (self == NULL) { zn_error("Failed to allocate memory"); @@ -244,8 +253,7 @@ zn_client_gl_base_technique_create(struct wl_client *client, uint32_t id, self->rendering_unit = rendering_unit; self->zn_gl_base_technique = zn_xr_dispatcher_get_new_gl_base_technique( - rendering_unit->virtual_object->dispatcher, - rendering_unit->zn_gl_rendering_unit); + gl_virtual_object->dispatcher, rendering_unit->zn_gl_rendering_unit); if (self->zn_gl_base_technique == NULL) { zn_error("Failed to get new zn_gl_base_technique"); wl_client_post_no_memory(client); @@ -277,7 +285,7 @@ zn_client_gl_base_technique_create(struct wl_client *client, uint32_t id, err_gl_base_technique: zn_xr_dispatcher_destroy_gl_base_technique( - rendering_unit->virtual_object->dispatcher, self->zn_gl_base_technique); + gl_virtual_object->dispatcher, self->zn_gl_base_technique); err_free: free(self); @@ -289,11 +297,16 @@ zn_client_gl_base_technique_create(struct wl_client *client, uint32_t id, static void zn_client_gl_base_technique_destroy(struct zn_client_gl_base_technique *self) { + struct zn_gl_virtual_object *gl_virtual_object = + self->rendering_unit->virtual_object->zn_virtual_object + ->gl_virtual_object; + wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); wl_list_remove(&self->rendering_unit_destroy_listener.link); wl_list_remove(&self->zn_gl_base_technique_destroy_listener.link); - zn_xr_dispatcher_destroy_gl_base_technique( - self->rendering_unit->virtual_object->dispatcher, - self->zn_gl_base_technique); + if (gl_virtual_object) { + zn_xr_dispatcher_destroy_gl_base_technique( + gl_virtual_object->dispatcher, self->zn_gl_base_technique); + } free(self); } diff --git a/zen/src/backend/immersive/gl/client-gl-context.c b/zen/src/backend/immersive/gl/client-gl-context.c deleted file mode 100644 index 4223fa53..00000000 --- a/zen/src/backend/immersive/gl/client-gl-context.c +++ /dev/null @@ -1,191 +0,0 @@ -#include "client-gl-context.h" - -#include -#include - -#include "backend/immersive/client-virtual-object.h" -#include "backend/immersive/shm-buffer.h" -#include "backend/immersive/xr-compositor.h" -#include "client-gl-base-technique.h" -#include "client-gl-buffer.h" -#include "client-gl-program.h" -#include "client-gl-rendering-unit.h" -#include "client-gl-shader.h" -#include "client-gl-texture.h" -#include "client-gl-vertex-array.h" -#include "zen-common/log.h" -#include "zen-common/util.h" - -static void -zn_client_gl_context_handle_destroy(struct wl_resource *resource) -{ - struct zn_client_gl_context *self = zn_client_gl_context_get(resource); - - zn_client_gl_context_destroy(self); -} - -/// @param resource can be inert (resource->user_data == NULL) -static void -zn_client_gl_context_protocol_destroy( - struct wl_client *client UNUSED, struct wl_resource *resource) -{ - wl_resource_destroy(resource); -} - -/// @param resource can be inert (resource->user_data == NULL) -static void -zn_client_gl_context_protocol_create_gl_rendering_unit(struct wl_client *client, - struct wl_resource *resource, uint32_t id, - struct wl_resource *virtual_object_resource) -{ - if (zn_client_gl_context_get(resource) == NULL) { - return; - } - - struct zn_client_virtual_object *client_virtual_object = - zn_client_virtual_object_get(virtual_object_resource); - - zn_client_gl_rendering_unit_create(client, id, client_virtual_object); -} - -/// @param resource can be inert (resource->user_data == NULL) -static void -zn_client_gl_context_protocol_create_gl_buffer( - struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) -{ - zn_client_gl_buffer_create(client, id); -} - -/// @param resource can be inert (resource->user_data == NULL) -static void -zn_client_gl_context_protocol_create_gl_shader(struct wl_client *client, - struct wl_resource *resource UNUSED, uint32_t id, - struct wl_resource *buffer_resource, uint32_t type) -{ - struct zn_shm_buffer *shm_buffer = zn_shm_buffer_get(buffer_resource); - - zn_client_gl_shader_create(client, id, shm_buffer->zn_buffer, type); -} - -/// @param resource can be inert (resource->user_data == NULL) -static void -zn_client_gl_context_protocol_create_gl_program( - struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) -{ - zn_client_gl_program_create(client, id); -} - -/// @param resource can be inert (resource->user_data == NULL) -static void -zn_client_gl_context_protocol_create_gl_texture( - struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) -{ - zn_client_gl_texture_create(client, id); -} - -/// @param resource can be inert (resource->user_data == NULL) -static void -zn_client_gl_context_protocol_create_gl_sampler(struct wl_client *client UNUSED, - struct wl_resource *resource UNUSED, uint32_t id UNUSED) -{} - -/// @param resource can be inert (resource->user_data == NULL) -static void -zn_client_gl_context_protocol_create_gl_vertex_array( - struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) -{ - zn_client_gl_vertex_array_create(client, id); -} - -/// @param resource can be inert (resource->user_data == NULL) -static void -zn_client_gl_context_protocol_create_gl_base_technique(struct wl_client *client, - struct wl_resource *resource, uint32_t id, - struct wl_resource *rendering_unit_resource) -{ - if (zn_client_gl_context_get(resource) == NULL) { - return; - } - - struct zn_client_gl_rendering_unit *rendering_unit = - zn_client_gl_rendering_unit_get(rendering_unit_resource); - - zn_client_gl_base_technique_create(client, id, rendering_unit); -} - -static const struct zwn_gl_context_interface implementation = { - .destroy = zn_client_gl_context_protocol_destroy, - .create_gl_rendering_unit = - zn_client_gl_context_protocol_create_gl_rendering_unit, - .create_gl_buffer = zn_client_gl_context_protocol_create_gl_buffer, - .create_gl_shader = zn_client_gl_context_protocol_create_gl_shader, - .create_gl_program = zn_client_gl_context_protocol_create_gl_program, - .create_gl_texture = zn_client_gl_context_protocol_create_gl_texture, - .create_gl_sampler = zn_client_gl_context_protocol_create_gl_sampler, - .create_gl_vertex_array = - zn_client_gl_context_protocol_create_gl_vertex_array, - .create_gl_base_technique = - zn_client_gl_context_protocol_create_gl_base_technique, -}; - -struct zn_client_gl_context * -zn_client_gl_context_get(struct wl_resource *resource) -{ - return wl_resource_get_user_data(resource); -} - -static void -zn_client_gl_context_handle_xr_compositor_destroy( - struct wl_listener *listener, void *data UNUSED) -{ - struct zn_client_gl_context *self = - zn_container_of(listener, self, xr_compositor_destroy_listener); - - zn_client_gl_context_destroy(self); -} - -struct zn_client_gl_context * -zn_client_gl_context_create(struct wl_client *client, uint32_t id, - struct zn_xr_compositor *xr_compositor) -{ - struct zn_client_gl_context *self = zalloc(sizeof *self); - if (self == NULL) { - zn_error("Failed to allocate memory"); - goto err; - } - - self->xr_compositor = xr_compositor; - - self->resource = wl_resource_create(client, &zwn_gl_context_interface, 1, id); - if (self->resource == NULL) { - zn_error("Failed to create a wl_resource"); - wl_client_post_no_memory(client); - goto err_free; - } - - wl_resource_set_implementation(self->resource, &implementation, self, - zn_client_gl_context_handle_destroy); - - self->xr_compositor_destroy_listener.notify = - zn_client_gl_context_handle_xr_compositor_destroy; - wl_signal_add(&self->xr_compositor->events.destroy, - &self->xr_compositor_destroy_listener); - - return self; - -err_free: - free(self); - -err: - return NULL; -} - -void -zn_client_gl_context_destroy(struct zn_client_gl_context *self) -{ - zwn_gl_context_send_destroyed(self->resource); - - wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); - wl_list_remove(&self->xr_compositor_destroy_listener.link); - free(self); -} diff --git a/zen/src/backend/immersive/gl/client-gl-context.h b/zen/src/backend/immersive/gl/client-gl-context.h deleted file mode 100644 index 03d0c62c..00000000 --- a/zen/src/backend/immersive/gl/client-gl-context.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -struct zn_xr_compositor; - -struct zn_client_gl_context { - struct wl_resource *resource; // @nonnull, @outlive - - struct zn_xr_compositor *xr_compositor; // @nonnull, @outlive - - struct wl_listener xr_compositor_destroy_listener; -}; - -struct zn_client_gl_context *zn_client_gl_context_create( - struct wl_client *client, uint32_t id, - struct zn_xr_compositor *xr_compositor); - -/// @return value is nullable -struct zn_client_gl_context *zn_client_gl_context_get( - struct wl_resource *resource); - -void zn_client_gl_context_destroy(struct zn_client_gl_context *self); diff --git a/zen/src/backend/immersive/gl/client-gl-rendering-unit.c b/zen/src/backend/immersive/gl/client-gl-rendering-unit.c index 4a2e5ba8..8d52bdb7 100644 --- a/zen/src/backend/immersive/gl/client-gl-rendering-unit.c +++ b/zen/src/backend/immersive/gl/client-gl-rendering-unit.c @@ -3,10 +3,12 @@ #include #include "backend/immersive/client-virtual-object.h" +#include "gl-virtual-object.h" #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" #include "zen/gl-rendering-unit.h" +#include "zen/virtual-object.h" #include "zen/xr-dispatcher.h" static void zn_client_gl_rendering_unit_destroy( @@ -79,6 +81,13 @@ struct zn_client_gl_rendering_unit * zn_client_gl_rendering_unit_create(struct wl_client *client, uint32_t id, struct zn_client_virtual_object *virtual_object) { + struct zn_gl_virtual_object *gl_virtual_object = + virtual_object->zn_virtual_object->gl_virtual_object; + if (gl_virtual_object == NULL) { + zn_error("Failed to get gl_virtual_object"); + goto err; + } + struct zn_client_gl_rendering_unit *self = zalloc(sizeof *self); if (self == NULL) { zn_error("Failed to allocate memory"); @@ -90,7 +99,7 @@ zn_client_gl_rendering_unit_create(struct wl_client *client, uint32_t id, wl_signal_init(&self->events.destroy); self->zn_gl_rendering_unit = zn_xr_dispatcher_get_new_gl_rendering_unit( - virtual_object->dispatcher, virtual_object->zn_virtual_object); + gl_virtual_object->dispatcher, gl_virtual_object); if (self->zn_gl_rendering_unit == NULL) { zn_error("Failed to get new zn_gl_rendering_unit"); wl_client_post_no_memory(client); @@ -122,7 +131,7 @@ zn_client_gl_rendering_unit_create(struct wl_client *client, uint32_t id, err_gl_rendering_unit: zn_xr_dispatcher_destroy_gl_rendering_unit( - virtual_object->dispatcher, self->zn_gl_rendering_unit); + gl_virtual_object->dispatcher, self->zn_gl_rendering_unit); err_free: free(self); @@ -134,13 +143,18 @@ zn_client_gl_rendering_unit_create(struct wl_client *client, uint32_t id, static void zn_client_gl_rendering_unit_destroy(struct zn_client_gl_rendering_unit *self) { + struct zn_gl_virtual_object *gl_virtual_object = + self->virtual_object->zn_virtual_object->gl_virtual_object; + zn_signal_emit_mutable(&self->events.destroy, NULL); wl_resource_set_implementation(self->resource, &implementation, NULL, NULL); wl_list_remove(&self->virtual_object_destroy_listener.link); wl_list_remove(&self->zn_gl_rendering_unit_destroy_listener.link); wl_list_remove(&self->events.destroy.listener_list); - zn_xr_dispatcher_destroy_gl_rendering_unit( - self->virtual_object->dispatcher, self->zn_gl_rendering_unit); + if (gl_virtual_object) { + zn_xr_dispatcher_destroy_gl_rendering_unit( + gl_virtual_object->dispatcher, self->zn_gl_rendering_unit); + } free(self); } diff --git a/zen/src/backend/immersive/gl/gl-context.c b/zen/src/backend/immersive/gl/gl-context.c new file mode 100644 index 00000000..255faf30 --- /dev/null +++ b/zen/src/backend/immersive/gl/gl-context.c @@ -0,0 +1,241 @@ +#include "backend/immersive/gl-context.h" + +#include + +#include "backend/immersive/client-virtual-object.h" +#include "backend/immersive/shm-buffer.h" +#include "client-gl-base-technique.h" +#include "client-gl-buffer.h" +#include "client-gl-program.h" +#include "client-gl-rendering-unit.h" +#include "client-gl-shader.h" +#include "client-gl-texture.h" +#include "client-gl-vertex-array.h" +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" +#include "zen/xr-system.h" + +static struct zn_cl_context * +zn_gl_context_get(struct wl_resource *resource) +{ + return wl_resource_get_user_data(resource); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_gl_context_protocol_destroy( + struct wl_client *client UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_gl_context_protocol_create_gl_rendering_unit(struct wl_client *client UNUSED, + struct wl_resource *resource, uint32_t id UNUSED, + struct wl_resource *virtual_object_resource UNUSED) +{ + if (zn_gl_context_get(resource) == NULL) { + return; + } + + struct zn_client_virtual_object *client_virtual_object = + zn_client_virtual_object_get(virtual_object_resource); + + zn_client_gl_rendering_unit_create(client, id, client_virtual_object); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_gl_context_protocol_create_gl_buffer( + struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) +{ + if (zn_gl_context_get(resource) == NULL) { + return; + } + + zn_client_gl_buffer_create(client, id); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_gl_context_protocol_create_gl_shader(struct wl_client *client, + struct wl_resource *resource UNUSED, uint32_t id, + struct wl_resource *buffer_resource, uint32_t type) +{ + if (zn_gl_context_get(resource) == NULL) { + return; + } + + struct zn_shm_buffer *shm_buffer = zn_shm_buffer_get(buffer_resource); + + zn_client_gl_shader_create(client, id, shm_buffer->zn_buffer, type); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_gl_context_protocol_create_gl_program( + struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) +{ + if (zn_gl_context_get(resource) == NULL) { + return; + } + + zn_client_gl_program_create(client, id); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_gl_context_protocol_create_gl_texture( + struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) +{ + if (zn_gl_context_get(resource) == NULL) { + return; + } + + zn_client_gl_texture_create(client, id); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_gl_context_protocol_create_gl_sampler(struct wl_client *client UNUSED, + struct wl_resource *resource UNUSED, uint32_t id UNUSED) +{ + if (zn_gl_context_get(resource) == NULL) { + return; + } +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_gl_context_protocol_create_gl_vertex_array( + struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) +{ + if (zn_gl_context_get(resource) == NULL) { + return; + } + + zn_client_gl_vertex_array_create(client, id); +} + +/// @param resource can be inert (resource->user_data == NULL) +static void +zn_gl_context_protocol_create_gl_base_technique(struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *rendering_unit_resource) +{ + if (zn_gl_context_get(resource) == NULL) { + return; + } + + struct zn_client_gl_rendering_unit *rendering_unit = + zn_client_gl_rendering_unit_get(rendering_unit_resource); + + zn_client_gl_base_technique_create(client, id, rendering_unit); +} + +static const struct zwn_gl_context_interface implementation = { + .destroy = zn_gl_context_protocol_destroy, + .create_gl_rendering_unit = zn_gl_context_protocol_create_gl_rendering_unit, + .create_gl_buffer = zn_gl_context_protocol_create_gl_buffer, + .create_gl_shader = zn_gl_context_protocol_create_gl_shader, + .create_gl_program = zn_gl_context_protocol_create_gl_program, + .create_gl_texture = zn_gl_context_protocol_create_gl_texture, + .create_gl_sampler = zn_gl_context_protocol_create_gl_sampler, + .create_gl_vertex_array = zn_gl_context_protocol_create_gl_vertex_array, + .create_gl_base_technique = zn_gl_context_protocol_create_gl_base_technique, +}; + +static void +zn_gl_context_handle_xr_system_session_state_changed( + struct wl_listener *listener, void *data UNUSED) +{ + struct zn_gl_context *self = + zn_container_of(listener, self, xr_system_session_state_changed_listener); + + if (!zn_xr_system_is_connected(self->xr_system)) { + zn_gl_context_destroy(self); + } +} + +static void +zn_gl_context_bind( + struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + struct zn_gl_context *self = data; + + struct wl_resource *resource = + wl_resource_create(client, &zwn_gl_context_interface, (int)version, id); + if (resource == NULL) { + zn_error("Failed to create a wl_resource"); + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &implementation, self, NULL); + + wl_list_insert(&self->resource_list, wl_resource_get_link(resource)); +} + +struct zn_gl_context * +zn_gl_context_create(struct wl_display *display, struct zn_xr_system *xr_system) +{ + if (!zn_assert(zn_xr_system_is_connected(xr_system), + "xr_system must be connected")) { + goto err; + } + + struct zn_gl_context *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + wl_list_init(&self->resource_list); + self->xr_system = xr_system; + wl_signal_init(&self->events.destroy); + self->destroying = false; + + self->global = wl_global_create( + display, &zwn_gl_context_interface, 1, self, zn_gl_context_bind); + if (self->global == NULL) { + zn_error("Failed to create zwn_gl_context global"); + goto err_free; + } + + self->xr_system_session_state_changed_listener.notify = + zn_gl_context_handle_xr_system_session_state_changed; + wl_signal_add(&xr_system->events.session_state_changed, + &self->xr_system_session_state_changed_listener); + + return self; + +err_free: + free(self); + +err: + return NULL; +} + +void +zn_gl_context_destroy(struct zn_gl_context *self UNUSED) +{ + if (self->destroying) { + return; + } + + self->destroying = true; + + zn_signal_emit_mutable(&self->events.destroy, NULL); + + struct wl_resource *resource = NULL; + wl_resource_for_each (resource, &self->resource_list) { + wl_resource_set_implementation(resource, &implementation, NULL, NULL); + } + + wl_global_destroy(self->global); + wl_list_remove(&self->xr_system_session_state_changed_listener.link); + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} diff --git a/zen/src/backend/immersive/gl/meson.build b/zen/src/backend/immersive/gl/meson.build index 165cd525..20d8437d 100644 --- a/zen/src/backend/immersive/gl/meson.build +++ b/zen/src/backend/immersive/gl/meson.build @@ -1,13 +1,12 @@ _zen_gl_immersive_backend_srcs = [ 'client-gl-base-technique.c', 'client-gl-buffer.c', - 'client-gl-context.c', 'client-gl-program.c', 'client-gl-rendering-unit.c', 'client-gl-shader.c', 'client-gl-texture.c', 'client-gl-vertex-array.c', - 'xr-gl.c', + 'gl-context.c', protocols_code['zwin-gl'], protocols_server_header['zwin-gl'], diff --git a/zen/src/backend/immersive/gl/xr-gl.c b/zen/src/backend/immersive/gl/xr-gl.c deleted file mode 100644 index 37d382e3..00000000 --- a/zen/src/backend/immersive/gl/xr-gl.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "backend/immersive/xr-gl.h" - -#include - -#include "client-gl-context.h" -#include "zen-common/log.h" -#include "zen-common/util.h" - -static void -zn_xr_gl_protocol_destroy( - struct wl_client *client UNUSED, struct wl_resource *resource) -{ - wl_resource_destroy(resource); -} - -static void -zn_xr_gl_protocol_create_gl_context(struct wl_client *client, - struct wl_resource *resource UNUSED, uint32_t id, - struct wl_resource *zwn_compositor) -{ - struct zn_xr_compositor *xr_compositor = - wl_resource_get_user_data(zwn_compositor); - - zn_client_gl_context_create(client, id, xr_compositor); -} - -static const struct zwn_gl_interface implementation = { - .destroy = zn_xr_gl_protocol_destroy, - .create_gl_context = zn_xr_gl_protocol_create_gl_context, -}; - -static void -zn_xr_gl_bind( - struct wl_client *client, void *data, uint32_t version, uint32_t id) -{ - struct zn_xr_gl *self = data; - - struct wl_resource *resource = - wl_resource_create(client, &zwn_gl_interface, (int)version, id); - if (resource == NULL) { - zn_error("Failed to create a wl_resource"); - wl_client_post_no_memory(client); - return; - } - - wl_resource_set_implementation(resource, &implementation, self, NULL); -} - -struct zn_xr_gl * -zn_xr_gl_create(struct wl_display *display) -{ - struct zn_xr_gl *self = zalloc(sizeof *self); - if (self == NULL) { - zn_error("Failed to allocate memory"); - goto err; - } - - self->global = - wl_global_create(display, &zwn_gl_interface, 1, self, zn_xr_gl_bind); - if (self->global == NULL) { - zn_error("Failed to create zwn_gl global"); - goto err_free; - } - - return self; - -err_free: - free(self); - -err: - return NULL; -} - -void -zn_xr_gl_destroy(struct zn_xr_gl *self) -{ - wl_global_destroy(self->global); - free(self); -} diff --git a/zen/src/backend/immersive/remote/gl-rendering-unit.cc b/zen/src/backend/immersive/remote/gl-rendering-unit.cc index 72802790..c3eed47a 100644 --- a/zen/src/backend/immersive/remote/gl-rendering-unit.cc +++ b/zen/src/backend/immersive/remote/gl-rendering-unit.cc @@ -1,6 +1,6 @@ #include "gl-rendering-unit.hh" -#include "virtual-object.hh" +#include "gl-virtual-object.hh" #include "zen-common/log.h" namespace zen::backend::immersive::remote { @@ -18,7 +18,7 @@ GlRenderingUnit::~GlRenderingUnit() std::unique_ptr GlRenderingUnit::New(std::shared_ptr channel, - std::unique_ptr &virtual_object) + std::unique_ptr &virtual_object) { auto self = std::unique_ptr(new GlRenderingUnit()); if (!self) { @@ -36,7 +36,7 @@ GlRenderingUnit::New(std::shared_ptr channel, bool GlRenderingUnit::Init(std::shared_ptr channel, - std::unique_ptr &virtual_object) + std::unique_ptr &virtual_object) { c_obj_ = zn_gl_rendering_unit_create(this, &c_implementation_); if (c_obj_ == nullptr) { diff --git a/zen/src/backend/immersive/remote/gl-rendering-unit.hh b/zen/src/backend/immersive/remote/gl-rendering-unit.hh index 65196d10..e34d9dd4 100644 --- a/zen/src/backend/immersive/remote/gl-rendering-unit.hh +++ b/zen/src/backend/immersive/remote/gl-rendering-unit.hh @@ -5,7 +5,7 @@ namespace zen::backend::immersive::remote { -class VirtualObject; +class GlVirtualObject; class GlRenderingUnit { @@ -15,7 +15,7 @@ class GlRenderingUnit static std::unique_ptr New( std::shared_ptr channel, - std::unique_ptr &virtual_object); + std::unique_ptr &virtual_object); inline std::unique_ptr &remote_obj(); inline zn_gl_rendering_unit *c_obj(); @@ -24,7 +24,7 @@ class GlRenderingUnit GlRenderingUnit() = default; bool Init(std::shared_ptr channel, - std::unique_ptr &virtual_object); + std::unique_ptr &virtual_object); static void HandleChangeVisibility(zn_gl_rendering_unit *c_obj, bool visible); diff --git a/zen/src/backend/immersive/remote/gl-virtual-object.cc b/zen/src/backend/immersive/remote/gl-virtual-object.cc new file mode 100644 index 00000000..d313a568 --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-virtual-object.cc @@ -0,0 +1,76 @@ +#include "gl-virtual-object.hh" + +#include "zen-common/log.h" + +namespace zen::backend::immersive::remote { + +const zn_gl_virtual_object_interface GlVirtualObject::c_implementation_ = { + GlVirtualObject::HandleCommitted, + GlVirtualObject::HandleChangeVisibility, +}; + +GlVirtualObject::~GlVirtualObject() +{ + if (c_obj_ != nullptr) { + zn_gl_virtual_object_destroy(c_obj_); + } +} + +std::unique_ptr +GlVirtualObject::New(std::shared_ptr channel, + struct zn_xr_dispatcher *xr_dispatcher_c_obj) +{ + auto self = std::unique_ptr(new GlVirtualObject()); + if (!self) { + zn_error("Failed to allocate memory"); + return nullptr; + } + + if (!self->Init(std::move(channel), xr_dispatcher_c_obj)) { + zn_error("Failed to initialize a remote VirtualObject"); + return nullptr; + } + + return self; +} + +bool +GlVirtualObject::Init(std::shared_ptr channel, + struct zn_xr_dispatcher *xr_dispatcher_c_obj) +{ + c_obj_ = zn_gl_virtual_object_create( + this, &c_implementation_, xr_dispatcher_c_obj); + if (c_obj_ == nullptr) { + zn_error("Failed to create a zn_virtual_object"); + return false; + } + + remote_obj_ = zen::remote::server::CreateVirtualObject(std::move(channel)); + if (!remote_obj_) { + zn_error("Failed to create a remote Virtual Object"); + zn_gl_virtual_object_destroy(c_obj_); + c_obj_ = nullptr; + return false; + } + + return true; +} + +void +GlVirtualObject::HandleCommitted(zn_gl_virtual_object *c_obj) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->Commit(); +} + +void +GlVirtualObject::HandleChangeVisibility( + zn_gl_virtual_object *c_obj, bool visible) +{ + auto *self = static_cast(c_obj->impl_data); + + self->remote_obj_->ChangeVisibility(visible); +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/gl-virtual-object.hh b/zen/src/backend/immersive/remote/gl-virtual-object.hh new file mode 100644 index 00000000..d81dd01b --- /dev/null +++ b/zen/src/backend/immersive/remote/gl-virtual-object.hh @@ -0,0 +1,50 @@ +#pragma once + +#include "gl-virtual-object.h" +#include "zen-common/cpp-util.h" + +namespace zen::backend::immersive::remote { + +class GlVirtualObject +{ + public: + DISABLE_MOVE_AND_COPY(GlVirtualObject); + ~GlVirtualObject(); + + static std::unique_ptr New( + std::shared_ptr channel, + struct zn_xr_dispatcher *xr_dispatcher_c_obj); + + inline std::unique_ptr &remote_obj(); + inline zn_gl_virtual_object *c_obj(); + + private: + GlVirtualObject() = default; + + bool Init(std::shared_ptr channel, + struct zn_xr_dispatcher *xr_dispatcher_c_obj); + + static void HandleCommitted(zn_gl_virtual_object *c_obj); + + static void HandleChangeVisibility(zn_gl_virtual_object *c_obj, bool visible); + + std::unique_ptr remote_obj_; + + static const zn_gl_virtual_object_interface c_implementation_; + + zn_gl_virtual_object *c_obj_ = nullptr; // @nonnull after Init(), @owning +}; + +inline zn_gl_virtual_object * +GlVirtualObject::c_obj() +{ + return c_obj_; +} + +inline std::unique_ptr & +GlVirtualObject::remote_obj() +{ + return remote_obj_; +} + +} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/meson.build b/zen/src/backend/immersive/remote/meson.build index e640ef7c..d90a4044 100644 --- a/zen/src/backend/immersive/remote/meson.build +++ b/zen/src/backend/immersive/remote/meson.build @@ -6,8 +6,8 @@ _zen_remote_immersive_backend_srcs = [ 'gl-shader.cc', 'gl-texture.cc', 'gl-vertex-array.cc', + 'gl-virtual-object.cc', 'loop.cc', - 'virtual-object.cc', 'xr-dispatcher.cc', 'xr-system.cc', 'xr-system-manager.cc', diff --git a/zen/src/backend/immersive/remote/virtual-object.cc b/zen/src/backend/immersive/remote/virtual-object.cc deleted file mode 100644 index 53f12f06..00000000 --- a/zen/src/backend/immersive/remote/virtual-object.cc +++ /dev/null @@ -1,72 +0,0 @@ -#include "virtual-object.hh" - -#include "zen-common/log.h" - -namespace zen::backend::immersive::remote { - -const zn_virtual_object_interface VirtualObject::c_implementation_ = { - VirtualObject::HandleCommitted, - VirtualObject::HandleChangeVisibility, -}; - -VirtualObject::~VirtualObject() -{ - if (c_obj_ != nullptr) { - zn_virtual_object_destroy(c_obj_); - } -} - -std::unique_ptr -VirtualObject::New(std::shared_ptr channel) -{ - auto self = std::unique_ptr(new VirtualObject()); - if (!self) { - zn_error("Failed to allocate memory"); - return nullptr; - } - - if (!self->Init(std::move(channel))) { - zn_error("Failed to initialize a remote VirtualObject"); - return nullptr; - } - - return self; -} - -bool -VirtualObject::Init(std::shared_ptr channel) -{ - c_obj_ = zn_virtual_object_create(this, &c_implementation_); - if (c_obj_ == nullptr) { - zn_error("Failed to create a zn_virtual_object"); - return false; - } - - remote_obj_ = zen::remote::server::CreateVirtualObject(std::move(channel)); - if (!remote_obj_) { - zn_error("Failed to create a remote Virtual Object"); - zn_virtual_object_destroy(c_obj_); - c_obj_ = nullptr; - return false; - } - - return true; -} - -void -VirtualObject::HandleCommitted(zn_virtual_object *c_obj) -{ - auto *self = static_cast(c_obj->impl_data); - - self->remote_obj_->Commit(); -} - -void -VirtualObject::HandleChangeVisibility(zn_virtual_object *c_obj, bool visible) -{ - auto *self = static_cast(c_obj->impl_data); - - self->remote_obj_->ChangeVisibility(visible); -} - -} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/virtual-object.hh b/zen/src/backend/immersive/remote/virtual-object.hh deleted file mode 100644 index 494e99af..00000000 --- a/zen/src/backend/immersive/remote/virtual-object.hh +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "virtual-object.h" -#include "zen-common/cpp-util.h" - -namespace zen::backend::immersive::remote { - -class VirtualObject -{ - public: - DISABLE_MOVE_AND_COPY(VirtualObject); - ~VirtualObject(); - - static std::unique_ptr New( - std::shared_ptr channel); - - inline std::unique_ptr &remote_obj(); - inline zn_virtual_object *c_obj(); - - private: - VirtualObject() = default; - - bool Init(std::shared_ptr channel); - - static void HandleCommitted(zn_virtual_object *c_obj); - - static void HandleChangeVisibility(zn_virtual_object *c_obj, bool visible); - - std::unique_ptr remote_obj_; - - static const zn_virtual_object_interface c_implementation_; - - zn_virtual_object *c_obj_ = nullptr; // @nonnull after Init(), @owning -}; - -inline zn_virtual_object * -VirtualObject::c_obj() -{ - return c_obj_; -} - -inline std::unique_ptr & -VirtualObject::remote_obj() -{ - return remote_obj_; -} - -} // namespace zen::backend::immersive::remote diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.cc b/zen/src/backend/immersive/remote/xr-dispatcher.cc index 67ef5b23..45a66954 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.cc +++ b/zen/src/backend/immersive/remote/xr-dispatcher.cc @@ -9,15 +9,15 @@ #include "gl-shader.hh" #include "gl-texture.hh" #include "gl-vertex-array.hh" -#include "virtual-object.hh" +#include "gl-virtual-object.hh" #include "zen-common/log.h" #include "zen/buffer.h" namespace zen::backend::immersive::remote { const zn_xr_dispatcher_interface XrDispatcher::c_implementation_ = { - XrDispatcher::HandleGetNewVirtualObject, - XrDispatcher::HandleDestroyVirtualObject, + XrDispatcher::HandleGetNewGlVirtualObject, + XrDispatcher::HandleDestroyGlVirtualObject, XrDispatcher::HandleGetNewGlRenderingUnit, XrDispatcher::HandleDestroyGlRenderingUnit, XrDispatcher::HandleGetNewGlBaseTechnique, @@ -81,12 +81,12 @@ XrDispatcher::Init(std::shared_ptr session) return true; } -zn_virtual_object * -XrDispatcher::HandleGetNewVirtualObject(zn_xr_dispatcher *c_obj) +zn_gl_virtual_object * +XrDispatcher::HandleGetNewGlVirtualObject(zn_xr_dispatcher *c_obj) { auto *self = static_cast(c_obj->impl_data); - auto virtual_object = VirtualObject::New(self->channel_); + auto virtual_object = GlVirtualObject::New(self->channel_, c_obj); if (!virtual_object) { zn_error("Failed to create a remote virtual object"); return nullptr; @@ -100,15 +100,16 @@ XrDispatcher::HandleGetNewVirtualObject(zn_xr_dispatcher *c_obj) } void -XrDispatcher::HandleDestroyVirtualObject( - zn_xr_dispatcher *c_obj, zn_virtual_object *virtual_object_c_obj) +XrDispatcher::HandleDestroyGlVirtualObject( + zn_xr_dispatcher *c_obj, zn_gl_virtual_object *gl_virtual_object_c_obj) { auto *self = static_cast(c_obj->impl_data); auto result = std::remove_if(self->virtual_objects_.begin(), self->virtual_objects_.end(), - [virtual_object_c_obj](std::unique_ptr &virtual_object) { - return virtual_object->c_obj() == virtual_object_c_obj; + [gl_virtual_object_c_obj]( + std::unique_ptr &gl_virtual_object) { + return gl_virtual_object->c_obj() == gl_virtual_object_c_obj; }); self->virtual_objects_.erase(result, self->virtual_objects_.end()); @@ -116,12 +117,12 @@ XrDispatcher::HandleDestroyVirtualObject( zn_gl_rendering_unit * XrDispatcher::HandleGetNewGlRenderingUnit( - zn_xr_dispatcher *c_obj, zn_virtual_object *virtual_object_c_obj) + zn_xr_dispatcher *c_obj, zn_gl_virtual_object *gl_virtual_object_c_obj) { auto *self = static_cast(c_obj->impl_data); for (auto &virtual_object : self->virtual_objects_) { - if (virtual_object->c_obj() != virtual_object_c_obj) { + if (virtual_object->c_obj() != gl_virtual_object_c_obj) { continue; } diff --git a/zen/src/backend/immersive/remote/xr-dispatcher.hh b/zen/src/backend/immersive/remote/xr-dispatcher.hh index b74367f5..4062e51e 100644 --- a/zen/src/backend/immersive/remote/xr-dispatcher.hh +++ b/zen/src/backend/immersive/remote/xr-dispatcher.hh @@ -12,7 +12,7 @@ class GlRenderingUnit; class GlShader; class GlTexture; class GlVertexArray; -class VirtualObject; +class GlVirtualObject; class XrDispatcher { @@ -31,13 +31,14 @@ class XrDispatcher bool Init(std::shared_ptr session); - static zn_virtual_object *HandleGetNewVirtualObject(zn_xr_dispatcher *c_obj); + static zn_gl_virtual_object *HandleGetNewGlVirtualObject( + zn_xr_dispatcher *c_obj); - static void HandleDestroyVirtualObject( - zn_xr_dispatcher *c_obj, zn_virtual_object *virtual_object_c_obj); + static void HandleDestroyGlVirtualObject( + zn_xr_dispatcher *c_obj, zn_gl_virtual_object *gl_virtual_object_c_obj); static zn_gl_rendering_unit *HandleGetNewGlRenderingUnit( - zn_xr_dispatcher *c_obj, zn_virtual_object *virtual_object_c_obj); + zn_xr_dispatcher *c_obj, zn_gl_virtual_object *gl_virtual_object_c_obj); static void HandleDestroyGlRenderingUnit( zn_xr_dispatcher *c_obj, zn_gl_rendering_unit *gl_rendering_unit_c_obj); @@ -79,7 +80,7 @@ class XrDispatcher std::shared_ptr channel_; - std::vector> virtual_objects_; + std::vector> virtual_objects_; std::vector> gl_rendering_units_; diff --git a/zen/src/backend/immersive/remote/xr-system.cc b/zen/src/backend/immersive/remote/xr-system.cc index 7ebad8a0..807bf2b7 100644 --- a/zen/src/backend/immersive/remote/xr-system.cc +++ b/zen/src/backend/immersive/remote/xr-system.cc @@ -1,7 +1,7 @@ #include "xr-system.hh" +#include "gl-virtual-object.hh" #include "loop.hh" -#include "virtual-object.hh" #include "xr-dispatcher.hh" #include "xr-system-manager.hh" #include "zen-common/log.h" diff --git a/zen/src/backend/immersive/xr-compositor.c b/zen/src/backend/immersive/xr-compositor.c index 49f0cd08..a6884315 100644 --- a/zen/src/backend/immersive/xr-compositor.c +++ b/zen/src/backend/immersive/xr-compositor.c @@ -8,41 +8,11 @@ #include "zen-common/util.h" #include "zen/xr-system.h" -static void -zn_xr_compositor_handle_destroy(struct wl_resource *resource) -{ - wl_list_remove(wl_resource_get_link(resource)); -} - -static void -zn_xr_compositor_handle_xr_system_session_state_changed( - struct wl_listener *listener, void *data UNUSED) -{ - struct zn_xr_compositor *self = - zn_container_of(listener, self, xr_system_session_state_changed_listener); - - if (!zn_xr_system_is_connected(self->xr_system)) { - zn_xr_compositor_destroy(self); - } -} - static void zn_xr_compositor_protocol_create_virtual_object( - struct wl_client *client, struct wl_resource *resource, uint32_t id) + struct wl_client *client, struct wl_resource *resource UNUSED, uint32_t id) { - struct zn_xr_compositor *self = wl_resource_get_user_data(resource); - - if (!zn_assert(self->xr_system->default_dispatcher != NULL, - "xr system must be connected")) { - return; - } - - struct zn_client_virtual_object *virtual_object = - zn_client_virtual_object_create( - client, id, self->xr_system->default_dispatcher); - if (virtual_object == NULL) { - zn_error("Failed to create zn_client_virtual_object"); - } + zn_client_virtual_object_create(client, id); } static void @@ -69,30 +39,19 @@ zn_xr_compositor_bind( return; } - wl_resource_set_implementation( - resource, &implementation, self, zn_xr_compositor_handle_destroy); - - wl_list_insert(&self->resource_list, wl_resource_get_link(resource)); + wl_resource_set_implementation(resource, &implementation, self, NULL); } struct zn_xr_compositor * -zn_xr_compositor_create( - struct wl_display *display UNUSED, struct zn_xr_system *xr_system) +zn_xr_compositor_create(struct wl_display *display UNUSED) { - if (!zn_assert(zn_xr_system_is_connected(xr_system), - "xr_system must be connected")) { - goto err; - } - struct zn_xr_compositor *self = zalloc(sizeof *self); if (self == NULL) { zn_error("Failed to allocate memory"); goto err; } - self->xr_system = xr_system; wl_signal_init(&self->events.destroy); - wl_list_init(&self->resource_list); self->global = wl_global_create( display, &zwn_compositor_interface, 1, self, zn_xr_compositor_bind); @@ -101,11 +60,6 @@ zn_xr_compositor_create( goto err_free; } - self->xr_system_session_state_changed_listener.notify = - zn_xr_compositor_handle_xr_system_session_state_changed; - wl_signal_add(&xr_system->events.session_state_changed, - &self->xr_system_session_state_changed_listener); - return self; err_free: @@ -121,8 +75,6 @@ zn_xr_compositor_destroy(struct zn_xr_compositor *self) zn_signal_emit_mutable(&self->events.destroy, NULL); wl_global_destroy(self->global); - wl_list_remove(&self->resource_list); - wl_list_remove(&self->xr_system_session_state_changed_listener.link); wl_list_remove(&self->events.destroy.listener_list); free(self); } diff --git a/zen/src/backend/immersive/xr-compositor.h b/zen/src/backend/immersive/xr-compositor.h index 06dce597..342a4388 100644 --- a/zen/src/backend/immersive/xr-compositor.h +++ b/zen/src/backend/immersive/xr-compositor.h @@ -3,22 +3,13 @@ #include struct zn_xr_compositor { - // must be connected state - struct zn_xr_system *xr_system; // @nonnull, @outlive - - struct wl_listener xr_system_session_state_changed_listener; - struct wl_global *global; // @nonnull, @owning - struct wl_list resource_list; // wl_resource::link of zwn_compositor - struct { struct wl_signal destroy; } events; }; -/// @param xr_system must be in connected state -struct zn_xr_compositor *zn_xr_compositor_create( - struct wl_display *display, struct zn_xr_system *xr_system); +struct zn_xr_compositor *zn_xr_compositor_create(struct wl_display *display); void zn_xr_compositor_destroy(struct zn_xr_compositor *self); diff --git a/zen/src/backend/immersive/xr-gl.h b/zen/src/backend/immersive/xr-gl.h deleted file mode 100644 index 11bfe977..00000000 --- a/zen/src/backend/immersive/xr-gl.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -struct zn_xr_gl { - struct wl_global *global; // @nonnull, @owning -}; - -struct zn_xr_gl *zn_xr_gl_create(struct wl_display *display); - -void zn_xr_gl_destroy(struct zn_xr_gl *self); diff --git a/zen/src/backend/immersive/xr.c b/zen/src/backend/immersive/xr.c index b2d645ad..809f690b 100644 --- a/zen/src/backend/immersive/xr.c +++ b/zen/src/backend/immersive/xr.c @@ -1,6 +1,6 @@ #include "xr.h" -#include "xr-gl.h" +#include "xr-compositor.h" #include "xr-shell.h" #include "xr-system-manager.h" #include "zen-common/log.h" @@ -21,22 +21,22 @@ zn_xr_create(struct wl_display *display) goto err_free; } - self->xr_gl = zn_xr_gl_create(display); - if (self->xr_gl == NULL) { - zn_error("Failed to create zn_xr_gl"); + self->xr_compositor = zn_xr_compositor_create(display); + if (self->xr_compositor == NULL) { + zn_error("Failed to create zn_xr_compositor"); goto err_free_system_manager; } self->xr_shell = zn_xr_shell_create(display); if (self->xr_shell == NULL) { zn_error("Failed to create zn_xr_shell"); - goto err_xr_gl; + goto err_xr_compositor; } return self; -err_xr_gl: - zn_xr_gl_destroy(self->xr_gl); +err_xr_compositor: + zn_xr_compositor_destroy(self->xr_compositor); err_free_system_manager: zn_xr_system_manager_destroy(self->xr_system_manager); @@ -52,7 +52,7 @@ void zn_xr_destroy(struct zn_xr *self) { zn_xr_shell_destroy(self->xr_shell); - zn_xr_gl_destroy(self->xr_gl); + zn_xr_compositor_destroy(self->xr_compositor); zn_xr_system_manager_destroy(self->xr_system_manager); free(self); } diff --git a/zen/src/backend/immersive/xr.h b/zen/src/backend/immersive/xr.h index 6b6df91f..0057cc5a 100644 --- a/zen/src/backend/immersive/xr.h +++ b/zen/src/backend/immersive/xr.h @@ -3,14 +3,14 @@ #include struct zn_xr_system_manager; -struct zn_xr_gl; +struct zn_xr_compositor; struct zn_xr_shell; struct zn_xr { struct zn_xr_system_manager *xr_system_manager; // @nonnull, @owning - struct zn_xr_gl *xr_gl; // @nonnull, @owning - struct zn_xr_shell *xr_shell; // @nonnull, @owning + struct zn_xr_compositor *xr_compositor; // @nonnull, @owning + struct zn_xr_shell *xr_shell; // @nonnull, @owning }; struct zn_xr *zn_xr_create(struct wl_display *display); diff --git a/zen/src/backend/screen/xdg-toplevel.c b/zen/src/backend/screen/xdg-toplevel.c index c5e362af..6e1b1437 100644 --- a/zen/src/backend/screen/xdg-toplevel.c +++ b/zen/src/backend/screen/xdg-toplevel.c @@ -182,7 +182,7 @@ zn_xdg_toplevel_handle_surface_commit( struct zn_xdg_toplevel *self = zn_container_of(listener, self, surface_commit_listener); - if (!zn_assert_(self->surface_snode, + if (!zn_assert(self->surface_snode, "Commit signal must be handled only when the view is mapped")) { return; } diff --git a/zen/src/gl-virtual-object.c b/zen/src/gl-virtual-object.c new file mode 100644 index 00000000..25917362 --- /dev/null +++ b/zen/src/gl-virtual-object.c @@ -0,0 +1,36 @@ +#include "gl-virtual-object.h" + +#include "zen-common/log.h" +#include "zen-common/signal.h" +#include "zen-common/util.h" + +struct zn_gl_virtual_object * +zn_gl_virtual_object_create(void *impl_data, + const struct zn_gl_virtual_object_interface *implementation, + struct zn_xr_dispatcher *dispatcher) +{ + struct zn_gl_virtual_object *self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + self->impl_data = impl_data; + self->impl = implementation; + self->dispatcher = dispatcher; + wl_signal_init(&self->events.destroy); + + return self; + +err: + return NULL; +} + +void +zn_gl_virtual_object_destroy(struct zn_gl_virtual_object *self) +{ + zn_signal_emit_mutable(&self->events.destroy, NULL); + + wl_list_remove(&self->events.destroy.listener_list); + free(self); +} diff --git a/zen/src/gl-virtual-object.h b/zen/src/gl-virtual-object.h new file mode 100644 index 00000000..dd4b0588 --- /dev/null +++ b/zen/src/gl-virtual-object.h @@ -0,0 +1,52 @@ +#pragma once + +#include + +#include "zen-common/util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct zn_gl_virtual_object; + +struct zn_gl_virtual_object_interface { + void (*commited)(struct zn_gl_virtual_object *self); + void (*change_visibility)(struct zn_gl_virtual_object *self, bool visible); +}; + +struct zn_gl_virtual_object { + void *impl_data; // @nullable, @outlive if exists + const struct zn_gl_virtual_object_interface *impl; // @nonnull, @outlive + + struct zn_xr_dispatcher *dispatcher; // @nonnull, @outlive + + struct { + struct wl_signal destroy; // (NULL) + } events; +}; + +UNUSED static inline void +zn_gl_virtual_object_change_visibility( + struct zn_gl_virtual_object *self, bool visible) +{ + self->impl->change_visibility(self, visible); +} + +UNUSED static inline void +zn_gl_virtual_object_committed(struct zn_gl_virtual_object *self) +{ + self->impl->commited(self); +} + +/// Called by impl object +struct zn_gl_virtual_object *zn_gl_virtual_object_create(void *impl_data, + const struct zn_gl_virtual_object_interface *implementation, + struct zn_xr_dispatcher *dispatcher); + +/// Called by impl object +void zn_gl_virtual_object_destroy(struct zn_gl_virtual_object *self); + +#ifdef __cplusplus +} +#endif diff --git a/zen/src/inode.c b/zen/src/inode.c index da59995d..65024a89 100644 --- a/zen/src/inode.c +++ b/zen/src/inode.c @@ -139,8 +139,6 @@ zn_inode_move(struct zn_inode *self, struct zn_inode *parent, vec3 position, if (self->parent != parent) { if (self->parent) { - wl_list_remove(&self->parent_destroy_listener.link); - wl_list_init(&self->parent_destroy_listener.link); wl_list_remove(&self->link); wl_list_init(&self->link); } @@ -148,8 +146,6 @@ zn_inode_move(struct zn_inode *self, struct zn_inode *parent, vec3 position, self->parent = parent; if (self->parent) { - wl_signal_add( - &self->parent->events.destroy, &self->parent_destroy_listener); wl_list_insert(&self->parent->child_list, &self->link); } @@ -162,15 +158,6 @@ zn_inode_move(struct zn_inode *self, struct zn_inode *parent, vec3 position, self, self->parent ? self->parent->transform_abs : GLM_MAT4_IDENTITY); } -static void -zn_inode_handle_parent_destroy(struct wl_listener *listener, void *data UNUSED) -{ - struct zn_inode *self = - zn_container_of(listener, self, parent_destroy_listener); - - zn_inode_move(self, NULL, self->position, self->quaternion); -} - struct zn_inode * zn_inode_create( void *impl_data, const struct zn_inode_interface *implementation) @@ -191,10 +178,6 @@ zn_inode_create( self->parent = NULL; wl_list_init(&self->link); wl_list_init(&self->child_list); - wl_signal_init(&self->events.destroy); - - self->parent_destroy_listener.notify = zn_inode_handle_parent_destroy; - wl_list_init(&self->parent_destroy_listener.link); return self; @@ -205,10 +188,9 @@ zn_inode_create( void zn_inode_destroy(struct zn_inode *self) { - zn_signal_emit_mutable(&self->events.destroy, NULL); + zn_assert(wl_list_empty(&self->child_list), + "Destroy child inodes before the parent inode"); - wl_list_remove(&self->events.destroy.listener_list); - wl_list_remove(&self->parent_destroy_listener.link); wl_list_remove(&self->child_list); wl_list_remove(&self->link); free(self); diff --git a/zen/src/server.c b/zen/src/server.c index a0ae4e40..dba4eda3 100644 --- a/zen/src/server.c +++ b/zen/src/server.c @@ -137,6 +137,13 @@ zn_server_create(struct wl_display *display, struct zn_backend *backend, goto err_seat; } + self->inode_invisible_root = + zn_inode_create(self, &zn_inode_noop_implementation); + if (self->inode_invisible_root == NULL) { + zn_error("Failed to create a root inode"); + goto err_inode_root; + } + if (backend) { self->backend = backend; } else { @@ -144,17 +151,20 @@ zn_server_create(struct wl_display *display, struct zn_backend *backend, } if (self->backend == NULL) { zn_error("Failed to create a zn_backend"); - goto err_inode_root; + goto err_inode_invisible_root; } return self; -err_seat: - zn_seat_destroy(self->seat); +err_inode_invisible_root: + zn_inode_destroy(self->inode_invisible_root); err_inode_root: zn_inode_destroy(self->inode_root); +err_seat: + zn_seat_destroy(self->seat); + err_binding: zn_binding_destroy(self->binding); @@ -171,6 +181,7 @@ zn_server_destroy(struct zn_server *self) zn_backend_destroy(self->backend); zn_seat_destroy(self->seat); zn_inode_destroy(self->inode_root); + zn_inode_destroy(self->inode_invisible_root); zn_binding_destroy(self->binding); server_singleton = NULL; wl_list_remove(&self->events.start.listener_list); diff --git a/zen/src/virtual-object.c b/zen/src/virtual-object.c index d7ec1ea2..b8cc64e6 100644 --- a/zen/src/virtual-object.c +++ b/zen/src/virtual-object.c @@ -1,9 +1,17 @@ #include "zen/virtual-object.h" +#include +#include + +#include "gl-virtual-object.h" #include "zen-common/log.h" #include "zen-common/signal.h" #include "zen-common/util.h" #include "zen/bounded.h" +#include "zen/inode.h" +#include "zen/server.h" +#include "zen/xr-dispatcher.h" +#include "zen/xr-system.h" bool zn_virtual_object_set_role(struct zn_virtual_object *self, @@ -51,25 +59,86 @@ zn_virtual_object_handle_role_object_destroy( wl_list_init(&self->role_object_destroy_listener.link); } +void +zn_virtual_object_change_visibility( + struct zn_virtual_object *self, bool visible) +{ + if (self->gl_virtual_object) { + zn_gl_virtual_object_change_visibility(self->gl_virtual_object, visible); + } +} + void zn_virtual_object_commit(struct zn_virtual_object *self) { zn_signal_emit_mutable(&self->events.commit, NULL); - self->impl->committed(self); + + if (self->gl_virtual_object) { + zn_gl_virtual_object_committed(self->gl_virtual_object); + } +} + +static void +zn_virtual_object_inode_mapped(void *impl_data UNUSED) +{} + +static void +zn_virtual_object_inode_unmapped(void *impl_data UNUSED) +{} + +static void +zn_virtual_object_inode_activated(void *impl_data) +{ + struct zn_virtual_object *self = impl_data; + struct zn_xr_system *xr_system = self->inode->xr_system; + + zn_assert(xr_system != NULL, "active inode must have xr_system"); + zn_assert(self->gl_virtual_object == NULL, + "gl_virtual_object must be NULL before being activated"); + + self->gl_virtual_object = + zn_xr_dispatcher_get_new_gl_virtual_object(xr_system->default_dispatcher); +} + +static void +zn_virtual_object_inode_deactivated(void *impl_data) +{ + struct zn_virtual_object *self = impl_data; + self->gl_virtual_object = NULL; } +static void +zn_virtual_object_inode_moved(void *impl_data UNUSED) +{} + +static const struct zn_inode_interface inode_implementation = { + .mapped = zn_virtual_object_inode_mapped, + .unmapped = zn_virtual_object_inode_unmapped, + .activated = zn_virtual_object_inode_activated, + .deactivated = zn_virtual_object_inode_deactivated, + .moved = zn_virtual_object_inode_moved, +}; + struct zn_virtual_object * -zn_virtual_object_create( - void *impl_data, const struct zn_virtual_object_interface *implementation) +zn_virtual_object_create(void) { + struct zn_server *server = zn_server_get_singleton(); + struct zn_virtual_object *self = zalloc(sizeof *self); if (self == NULL) { zn_error("Failed to allocate memory"); goto err; } - self->impl_data = impl_data; - self->impl = implementation; + self->inode = zn_inode_create(self, &inode_implementation); + if (self->inode == NULL) { + zn_error("Failed to create a inode"); + goto err_free; + } + + self->gl_virtual_object = NULL; + self->role = ZN_VIRTUAL_OBJECT_ROLE_NONE; + wl_signal_init(&self->events.destroy); wl_signal_init(&self->events.commit); @@ -77,8 +146,14 @@ zn_virtual_object_create( zn_virtual_object_handle_role_object_destroy; wl_list_init(&self->role_object_destroy_listener.link); + zn_inode_move(self->inode, server->inode_invisible_root, GLM_VEC3_ZERO, + GLM_QUAT_IDENTITY); + return self; +err_free: + free(self); + err: return NULL; } @@ -88,6 +163,12 @@ zn_virtual_object_destroy(struct zn_virtual_object *self) { zn_signal_emit_mutable(&self->events.destroy, NULL); + if (self->gl_virtual_object) { + zn_xr_dispatcher_destroy_gl_virtual_object( + self->gl_virtual_object->dispatcher, self->gl_virtual_object); + } + + zn_inode_destroy(self->inode); wl_list_remove(&self->role_object_destroy_listener.link); wl_list_remove(&self->events.destroy.listener_list); wl_list_remove(&self->events.commit.listener_list); diff --git a/zen/src/virtual-object.h b/zen/src/virtual-object.h deleted file mode 100644 index a240cb32..00000000 --- a/zen/src/virtual-object.h +++ /dev/null @@ -1,16 +0,0 @@ -#include "zen/virtual-object.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/// Called by impl object -struct zn_virtual_object *zn_virtual_object_create( - void *impl_data, const struct zn_virtual_object_interface *implementation); - -/// Called by impl object -void zn_virtual_object_destroy(struct zn_virtual_object *self); - -#ifdef __cplusplus -} -#endif diff --git a/zen/tests/inode/inode-map.c b/zen/tests/inode/inode-map.c index 03a392c5..592d8008 100644 --- a/zen/tests/inode/inode-map.c +++ b/zen/tests/inode/inode-map.c @@ -145,9 +145,18 @@ TEST(destroy) zn_inode_map(root); ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(node)); +} + +FAIL_TEST(destroy_parent) +{ + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *parent = + zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(NULL, &zn_inode_noop_implementation); - zn_inode_destroy(root); + // NOLINTNEXTLINE(readability-suspicious-call-argument) + zn_inode_move(parent, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + zn_inode_move(node, parent, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); - ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(node)); - ASSERT_EQUAL_POINTER(NULL, node->parent); + zn_inode_destroy(parent); } diff --git a/zen/tests/inode/inode-move.c b/zen/tests/inode/inode-move.c index e564aea1..16b742be 100644 --- a/zen/tests/inode/inode-move.c +++ b/zen/tests/inode/inode-move.c @@ -1,8 +1,9 @@ #include #include +#include +#include "inode.h" #include "test-harness.h" -#include "zen/inode.h" TEST(general) { @@ -40,3 +41,121 @@ TEST(general) ASSERT_EQUAL_VEC3(((vec3){80, 10, 101}), global); } + +struct test_data { + bool mapped; + bool unmapped; + bool activated; + bool deactivated; + bool moved; +}; + +static void +mapped(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->mapped = true; +} + +static void +unmapped(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->unmapped = true; +} + +static void +activated(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->activated = true; +} + +static void +deactivated(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->deactivated = true; +} + +static void +moved(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->moved = true; +} + +TEST(signal) +{ + static const struct zn_inode_interface implementation = { + .mapped = mapped, + .unmapped = unmapped, + .activated = activated, + .deactivated = deactivated, + .moved = moved, + }; + + struct test_data data = {0}; + + struct zn_xr_system *xr_system = (void *)1; + + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *root2 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(&data, &implementation); + + zn_inode_map(root); + zn_inode_set_xr_system(root, xr_system); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(true, data.mapped); + ASSERT_EQUAL_BOOL(true, data.activated); + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(node)); + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(node)); + + zn_inode_move(node, root2, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(true, data.unmapped); + ASSERT_EQUAL_BOOL(true, data.deactivated); + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(node)); + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(node)); +} + +TEST(map) +{ + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *root2 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(NULL, &zn_inode_noop_implementation); + + zn_inode_map(root); + + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(node)); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(true, zn_inode_is_mapped(node)); + + zn_inode_move(node, root2, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(false, zn_inode_is_mapped(node)); +} + +TEST(active) +{ + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *root2 = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_xr_system *xr_system = (void *)1; + + zn_inode_set_xr_system(root, xr_system); + + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(node)); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(true, zn_inode_is_active(node)); + + zn_inode_move(node, root2, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(false, zn_inode_is_active(node)); +} diff --git a/zen/tests/inode/inode-set-xr-system.c b/zen/tests/inode/inode-set-xr-system.c index 0664bf6f..77f22391 100644 --- a/zen/tests/inode/inode-set-xr-system.c +++ b/zen/tests/inode/inode-set-xr-system.c @@ -1,5 +1,6 @@ #include #include +#include #include "inode.h" #include "test-harness.h" @@ -26,7 +27,6 @@ TEST(map) zn_inode_move(n21, n2, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); zn_inode_move(n211, n21, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); - zn_inode_map(root); zn_inode_set_xr_system(root, xr_system); ASSERT_EQUAL_BOOL(true, zn_inode_is_active(root)); @@ -94,17 +94,79 @@ TEST(map) ASSERT_EQUAL_BOOL(true, zn_inode_is_active(n12)); ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n21)); ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n211)); +} - zn_inode_unmap(root); +struct test_data { + bool mapped; + bool unmapped; + bool activated; + bool deactivated; + bool moved; +}; - ASSERT_EQUAL_BOOL(false, zn_inode_is_active(root)); - ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n1)); - ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n2)); - ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n3)); - ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n11)); - ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n12)); - ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n21)); - ASSERT_EQUAL_BOOL(false, zn_inode_is_active(n211)); +static void +mapped(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->mapped = true; +} + +static void +unmapped(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->unmapped = true; +} + +static void +activated(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->activated = true; +} + +static void +deactivated(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->deactivated = true; +} + +static void +moved(void *impl_data UNUSED) +{ + struct test_data *data = impl_data; + data->moved = true; +} + +TEST(signal) +{ + static const struct zn_inode_interface implementation = { + .mapped = mapped, + .unmapped = unmapped, + .activated = activated, + .deactivated = deactivated, + .moved = moved, + }; + + struct test_data data = {0}; + + struct zn_xr_system *xr_system = (void *)1; + + struct zn_inode *root = zn_inode_create(NULL, &zn_inode_noop_implementation); + struct zn_inode *node = zn_inode_create(&data, &implementation); + + zn_inode_move(node, root, GLM_VEC3_ZERO, GLM_QUAT_IDENTITY); + + ASSERT_EQUAL_BOOL(true, data.moved); + + ASSERT_EQUAL_BOOL(false, data.activated); + zn_inode_set_xr_system(root, xr_system); + ASSERT_EQUAL_BOOL(true, data.activated); + + ASSERT_EQUAL_BOOL(false, data.deactivated); + zn_inode_set_xr_system(root, NULL); + ASSERT_EQUAL_BOOL(true, data.deactivated); } FAIL_TEST(non_root_map) @@ -132,9 +194,4 @@ TEST(destroy) zn_inode_set_xr_system(root, xr_system); ASSERT_EQUAL_BOOL(true, zn_inode_is_active(node)); - - zn_inode_destroy(root); - - ASSERT_EQUAL_BOOL(false, zn_inode_is_active(node)); - ASSERT_EQUAL_POINTER(NULL, node->parent); }