From e22d788567be709ab75e93e54f9fa82d1b0a7184 Mon Sep 17 00:00:00 2001 From: Colin Kinloch Date: Tue, 31 Dec 2024 20:17:36 +0000 Subject: [PATCH] wayland: Dedupe wayland GL/VK configure code again Configurations of xdg_toplevels are pending until acked on xdg_surface configure. The vulkan backend doesn't need to take additional actions on configure. --- gfx/common/wayland_common.c | 195 +++++++++++++++++++-------- gfx/common/wayland_common.h | 41 +----- gfx/drivers_context/wayland_ctx.c | 61 +-------- gfx/drivers_context/wayland_vk_ctx.c | 45 +------ input/common/wayland_common.c | 11 -- input/common/wayland_common.h | 11 +- 6 files changed, 150 insertions(+), 214 deletions(-) diff --git a/gfx/common/wayland_common.c b/gfx/common/wayland_common.c index 8b0f557bcb2..359e7c1fd42 100644 --- a/gfx/common/wayland_common.c +++ b/gfx/common/wayland_common.c @@ -82,53 +82,125 @@ static const unsigned long retroarch_icon_data[] = { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000 }; -void xdg_toplevel_handle_configure_common(gfx_ctx_wayland_data_t *wl, - void *toplevel, +typedef struct shm_buffer +{ + struct wl_buffer *wl_buffer; + void *data; + size_t data_size; +} shm_buffer_t; + +#ifdef HAVE_LIBDECOR_H +static void libdecor_handle_error(struct libdecor *context, + enum libdecor_error error, const char *message) +{ + RARCH_ERR("[Wayland]: libdecor Caught error (%d): %s\n", error, message); +} + +const struct libdecor_interface libdecor_interface = { + .error = libdecor_handle_error, +}; +#endif + +typedef struct wayland_configuration +{ + unsigned width; + unsigned height; + bool fullscreen; + bool maximized; + bool floating; + bool resizing; + bool activated; + bool has_size; + bool has_window_state; +} wayland_configuration_t; + +void xdg_toplevel_handle_configure(void *data, + struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states) { + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; const uint32_t *state; - bool floating = true; - wl->fullscreen = false; - wl->maximized = false; + wl->pending_configuration = (wayland_configuration_t*)calloc(1, sizeof(wayland_configuration_t)); + wayland_configuration_t *conf = wl->pending_configuration; + + conf->has_window_state = true; + + conf->floating = true; WL_ARRAY_FOR_EACH(state, states, const uint32_t*) { switch (*state) { case XDG_TOPLEVEL_STATE_FULLSCREEN: - wl->fullscreen = true; - floating = false; + conf->fullscreen = true; + conf->floating = false; break; case XDG_TOPLEVEL_STATE_MAXIMIZED: - wl->maximized = true; + conf->maximized = true; /* fall-through */ case XDG_TOPLEVEL_STATE_TILED_LEFT: case XDG_TOPLEVEL_STATE_TILED_RIGHT: case XDG_TOPLEVEL_STATE_TILED_TOP: case XDG_TOPLEVEL_STATE_TILED_BOTTOM: - floating = false; + conf->floating = false; break; case XDG_TOPLEVEL_STATE_RESIZING: - wl->resize = true; + conf->resizing = true; break; case XDG_TOPLEVEL_STATE_ACTIVATED: - wl->activated = true; + conf->activated = true; break; } } - if (width == 0 || height == 0) + conf->has_size = true; + conf->width = width; + conf->height = height; +} + +void xdg_toplevel_handle_close(void *data, + struct xdg_toplevel *xdg_toplevel) +{ + frontend_driver_set_signal_handler_state(1); +} + +static struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_handle_configure, + .close = xdg_toplevel_handle_close, +}; + +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) +{ + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + bool floating = true; + wayland_configuration_t *conf; + + conf = wl->pending_configuration; + wl->pending_configuration = NULL; + + if (conf == NULL) + conf = (wayland_configuration_t*)calloc(1, sizeof(wayland_configuration_t)); + + if (conf->has_window_state) { + wl->fullscreen = conf->fullscreen; + wl->maximized = conf->maximized; + wl->activated = conf->activated; + floating = conf->floating; + } + + if (conf->width == 0 || conf->height == 0) { - width = wl->floating_width; - height = wl->floating_height; + conf->width = wl->floating_width; + conf->height = wl->floating_height; } - if ( (width > 0) - && (height > 0)) + if ( (conf->width > 0) + && (conf->height > 0)) { - wl->width = width; - wl->height = height; + wl->width = conf->width; + wl->height = conf->height; wl->buffer_width = wl->fractional_scale ? FRACTIONAL_SCALE_MULT(wl->width, wl->fractional_scale_num) : wl->width * wl->buffer_scale; wl->buffer_height = wl->fractional_scale ? @@ -138,28 +210,38 @@ void xdg_toplevel_handle_configure_common(gfx_ctx_wayland_data_t *wl, { /* Stretch old buffer to fill new size, commit/roundtrip to apply */ wp_viewport_set_destination(wl->viewport, wl->width, wl->height); - wl_surface_commit(wl->surface); } } if (floating) { - wl->floating_width = width; - wl->floating_height = height; + wl->floating_width = conf->width; + wl->floating_height = conf->height; } -} -void xdg_toplevel_handle_close(void *data, - struct xdg_toplevel *xdg_toplevel) -{ - frontend_driver_set_signal_handler_state(1); + if (wl->driver_configure_handler != NULL) + wl->driver_configure_handler(wl); + xdg_surface_ack_configure(xdg_surface, serial); + + wl_surface_commit(wl->surface); + + if (conf != NULL) + free(conf); + + wl->configured = false; } +static struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + #ifdef HAVE_LIBDECOR_H -void libdecor_frame_handle_configure_common(struct libdecor_frame *frame, +void libdecor_frame_handle_configure(struct libdecor_frame *frame, struct libdecor_configuration *configuration, - gfx_ctx_wayland_data_t *wl) + void *data) { + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + int width = 0, height = 0; struct libdecor_state *state = NULL; enum libdecor_window_state window_state; @@ -210,7 +292,6 @@ void libdecor_frame_handle_configure_common(struct libdecor_frame *frame, { /* Stretch old buffer to fill new size, commit/roundtrip to apply */ wp_viewport_set_destination(wl->viewport, wl->width, wl->height); - wl_surface_commit(wl->surface); } } @@ -223,6 +304,13 @@ void libdecor_frame_handle_configure_common(struct libdecor_frame *frame, wl->floating_width = width; wl->floating_height = height; } + + if (wl->driver_configure_handler != NULL) + wl->driver_configure_handler(wl); + + wl_surface_commit(wl->surface); + + wl->configured = false; } void libdecor_frame_handle_close(struct libdecor_frame *frame, @@ -231,7 +319,17 @@ void libdecor_frame_handle_close(struct libdecor_frame *frame, frontend_driver_set_signal_handler_state(1); } void libdecor_frame_handle_commit(struct libdecor_frame *frame, - void *data) { } + void *data) +{ + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + wl_surface_commit(wl->surface); +} + +static struct libdecor_frame_interface libdecor_frame_interface = { + .configure = libdecor_frame_handle_configure, + .close = libdecor_frame_handle_close, + .commit = libdecor_frame_handle_commit, +}; #endif void gfx_ctx_wl_get_video_size_common(void *data, @@ -662,7 +760,7 @@ static bool wl_draw_splash_screen(gfx_ctx_wayland_data_t *wl) } bool gfx_ctx_wl_init_common( - const toplevel_listener_t *toplevel_listener, gfx_ctx_wayland_data_t **wwl) + const driver_configure_handler_t driver_configure_handler, gfx_ctx_wayland_data_t **wwl) { int i; gfx_ctx_wayland_data_t *wl; @@ -802,7 +900,7 @@ bool gfx_ctx_wl_init_common( { wl->libdecor_context = wl->libdecor_new(wl->input.dpy, &libdecor_interface); - wl->libdecor_frame = wl->libdecor_decorate(wl->libdecor_context, wl->surface, &toplevel_listener->libdecor_frame_interface, wl); + wl->libdecor_frame = wl->libdecor_decorate(wl->libdecor_context, wl->surface, &libdecor_frame_interface, wl); if (!wl->libdecor_frame) { RARCH_ERR("[Wayland]: Failed to create libdecor frame\n"); @@ -814,7 +912,6 @@ bool gfx_ctx_wl_init_common( wl->libdecor_frame_map(wl->libdecor_frame); /* Waiting for libdecor to be configured before starting to draw */ - wl_surface_commit(wl->surface); wl->configured = true; while (wl->configured) @@ -832,8 +929,10 @@ bool gfx_ctx_wl_init_common( wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->xdg_shell, wl->surface); xdg_surface_add_listener(wl->xdg_surface, &xdg_surface_listener, wl); + wl->driver_configure_handler = driver_configure_handler; + wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface); - xdg_toplevel_add_listener(wl->xdg_toplevel, &toplevel_listener->xdg_toplevel_listener, wl); + xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl); xdg_toplevel_set_app_id(wl->xdg_toplevel, WAYLAND_APP_ID); xdg_toplevel_set_title(wl->xdg_toplevel, WINDOW_TITLE); @@ -880,9 +979,6 @@ bool gfx_ctx_wl_init_common( } } - // Ignore configure events until splash screen has been replaced - wl->ignore_configuration = true; - wl->input.fd = wl_display_get_fd(wl->input.dpy); wl->input.keyboard_focus = true; @@ -946,6 +1042,8 @@ bool gfx_ctx_wl_set_video_mode_common_size(gfx_ctx_wayland_data_t *wl, } #endif + wl_surface_commit(wl->surface); + return true; } @@ -1089,28 +1187,7 @@ static void shm_buffer_handle_release(void *data, free(buffer); } -#if 0 -static void xdg_surface_handle_configure(void *data, - struct xdg_surface *surface, uint32_t serial) -{ - xdg_surface_ack_configure(surface, serial); -} -#endif - -#ifdef HAVE_LIBDECOR_H -static void libdecor_handle_error(struct libdecor *context, - enum libdecor_error error, const char *message) -{ - RARCH_ERR("[Wayland]: libdecor Caught error (%d): %s\n", error, message); -} -#endif - const struct wl_buffer_listener shm_buffer_listener = { - shm_buffer_handle_release, + .release = shm_buffer_handle_release, }; -#ifdef HAVE_LIBDECOR_H -const struct libdecor_interface libdecor_interface = { - .error = libdecor_handle_error, -}; -#endif diff --git a/gfx/common/wayland_common.h b/gfx/common/wayland_common.h index 41f32a9e2e4..da6b4aec5de 100644 --- a/gfx/common/wayland_common.h +++ b/gfx/common/wayland_common.h @@ -15,46 +15,10 @@ #pragma once -#ifdef HAVE_LIBDECOR_H -#include -#endif - #include "../../input/common/wayland_common.h" #define WAYLAND_APP_ID "com.libretro.RetroArch" -typedef struct toplevel_listener -{ -#ifdef HAVE_LIBDECOR_H - struct libdecor_frame_interface libdecor_frame_interface; -#endif - struct xdg_toplevel_listener xdg_toplevel_listener; -} toplevel_listener_t; - -typedef struct shm_buffer -{ - struct wl_buffer *wl_buffer; - void *data; - size_t data_size; -} shm_buffer_t; - -void xdg_toplevel_handle_configure_common(gfx_ctx_wayland_data_t *wl, void *toplevel, - int32_t width, int32_t height, struct wl_array *states); - -void xdg_toplevel_handle_close(void *data, - struct xdg_toplevel *xdg_toplevel); - -#ifdef HAVE_LIBDECOR_H -void libdecor_frame_handle_configure_common(struct libdecor_frame *frame, - struct libdecor_configuration *configuration, gfx_ctx_wayland_data_t *wl); - -void libdecor_frame_handle_close(struct libdecor_frame *frame, - void *data); - -void libdecor_frame_handle_commit(struct libdecor_frame *frame, - void *data); -#endif - void gfx_ctx_wl_get_video_size_common(void *data, unsigned *width, unsigned *height); @@ -66,7 +30,7 @@ bool gfx_ctx_wl_get_metrics_common(void *data, enum display_metric_types type, float *value); bool gfx_ctx_wl_init_common( - const toplevel_listener_t *toplevel_listener, + const driver_configure_handler_t driver_configure_handler, gfx_ctx_wayland_data_t **wl); bool gfx_ctx_wl_set_video_mode_common_size(gfx_ctx_wayland_data_t *wl, @@ -89,6 +53,3 @@ void gfx_ctx_wl_check_window_common(gfx_ctx_wayland_data_t *wl, void (*get_video_size)(void*, unsigned*, unsigned*), bool *quit, bool *resize, unsigned *width, unsigned *height); -#ifdef HAVE_LIBDECOR_H -extern const struct libdecor_interface libdecor_interface; -#endif diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 2d70ae68b10..c9214d9fb75 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -49,14 +49,8 @@ static enum gfx_ctx_api wl_api = GFX_CTX_NONE; /* Shell surface callbacks. */ -static void xdg_toplevel_handle_configure(void *data, - struct xdg_toplevel *toplevel, - int32_t width, int32_t height, struct wl_array *states) +static void xdg_surface_handle_configure(gfx_ctx_wayland_data_t *wl) { - gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; - if (wl->ignore_configuration) - return; - xdg_toplevel_handle_configure_common(wl, toplevel, width, height, states); #ifdef HAVE_EGL if (wl->win) wl_egl_window_resize(wl->win, @@ -68,8 +62,6 @@ static void xdg_toplevel_handle_configure(void *data, wl->buffer_width, wl->buffer_height); #endif - - wl->configured = false; } static void gfx_ctx_wl_destroy_resources(gfx_ctx_wayland_data_t *wl) @@ -106,7 +98,6 @@ static bool gfx_ctx_wl_set_resize(void *data, unsigned width, unsigned height) if (!wl->fractional_scale) wl_surface_set_buffer_scale(wl->surface, wl->buffer_scale); - wl->ignore_configuration = false; #ifdef HAVE_EGL wl_egl_window_resize(wl->win, width, height, 0, 0); #endif @@ -114,50 +105,6 @@ static bool gfx_ctx_wl_set_resize(void *data, unsigned width, unsigned height) return true; } -#ifdef HAVE_LIBDECOR_H -static void -libdecor_frame_handle_configure(struct libdecor_frame *frame, - struct libdecor_configuration *configuration, void *data) -{ - gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; - if (wl->ignore_configuration) - return; - libdecor_frame_handle_configure_common(frame, configuration, wl); - -#ifdef HAVE_EGL - if (wl->win) - wl_egl_window_resize(wl->win, - wl->buffer_width, - wl->buffer_height, - 0, 0); - else - wl->win = wl_egl_window_create( - wl->surface, - wl->buffer_width, - wl->buffer_height); -#endif - - wl->configured = false; -} -#endif - -static const toplevel_listener_t toplevel_listener = { -#ifdef HAVE_LIBDECOR_H - .libdecor_frame_interface = { - libdecor_frame_handle_configure, - libdecor_frame_handle_close, - libdecor_frame_handle_commit, - }, -#endif - .xdg_toplevel_listener = { - xdg_toplevel_handle_configure, - xdg_toplevel_handle_close, - }, -}; - -static const toplevel_listener_t xdg_toplevel_listener = { -}; - #ifdef HAVE_EGL #define WL_EGL_ATTRIBS_BASE \ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, \ @@ -256,7 +203,7 @@ static void *gfx_ctx_wl_init(void *data) { int i; gfx_ctx_wayland_data_t *wl = NULL; - if (!gfx_ctx_wl_init_common(&toplevel_listener, &wl)) + if (!gfx_ctx_wl_init_common(&xdg_surface_handle_configure, &wl)) goto error; #ifdef HAVE_EGL if (!gfx_ctx_wl_egl_init_context(wl)) @@ -496,14 +443,14 @@ static void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t t wl_callback_destroy(cb); } -static const struct wl_callback_listener wl_surface_frame_listener = { +static const struct wl_callback_listener wl_surface_frame_listener = { .done = wl_surface_frame_done, }; static void gfx_ctx_wl_swap_buffers(void *data) { #ifdef HAVE_EGL - struct wl_callback *cb; + struct wl_callback *cb; gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; settings_t *settings = config_get_ptr(); unsigned max_swapchain_images = settings->uints.video_max_swapchain_images; diff --git a/gfx/drivers_context/wayland_vk_ctx.c b/gfx/drivers_context/wayland_vk_ctx.c index 5cfcdd8626f..eb46b520d6b 100644 --- a/gfx/drivers_context/wayland_vk_ctx.c +++ b/gfx/drivers_context/wayland_vk_ctx.c @@ -40,18 +40,6 @@ #define EGL_PLATFORM_WAYLAND_KHR 0x31D8 #endif -/* Shell surface callbacks. */ -static void xdg_toplevel_handle_configure(void *data, - struct xdg_toplevel *toplevel, - int32_t width, int32_t height, struct wl_array *states) -{ - gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; - if (wl->ignore_configuration) - return; - xdg_toplevel_handle_configure_common(wl, toplevel, width, height, states); - wl->configured = false; -} - static void gfx_ctx_wl_destroy_resources(gfx_ctx_wayland_data_t *wl) { if (!wl) @@ -69,7 +57,7 @@ static void gfx_ctx_wl_check_window(void *data, bool *quit, * central place, so use that to trigger swapchain reinit. */ *resize = wl->vk.flags & VK_DATA_FLAG_NEED_NEW_SWAPCHAIN; - gfx_ctx_wl_check_window_common(wl, gfx_ctx_wl_get_video_size_common, quit, resize, + gfx_ctx_wl_check_window_common(wl, gfx_ctx_wl_get_video_size_common, quit, resize, width, height); } @@ -85,7 +73,6 @@ static bool gfx_ctx_wl_set_resize(void *data, unsigned width, unsigned height) if (vulkan_create_swapchain(&wl->vk, width, height, wl->swap_interval)) { - wl->ignore_configuration = false; wl->vk.context.flags |= VK_CTX_FLAG_INVALID_SWAPCHAIN; if (wl->vk.flags & VK_DATA_FLAG_CREATED_NEW_SWAPCHAIN) vulkan_acquire_next_image(&wl->vk); @@ -99,40 +86,12 @@ static bool gfx_ctx_wl_set_resize(void *data, unsigned width, unsigned height) return false; } -#ifdef HAVE_LIBDECOR_H -static void -libdecor_frame_handle_configure(struct libdecor_frame *frame, - struct libdecor_configuration *configuration, void *data) -{ - gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; - if (wl->ignore_configuration) - return; - libdecor_frame_handle_configure_common(frame, configuration, wl); - - wl->configured = false; -} -#endif - -static const toplevel_listener_t toplevel_listener = { -#ifdef HAVE_LIBDECOR_H - .libdecor_frame_interface = { - libdecor_frame_handle_configure, - libdecor_frame_handle_close, - libdecor_frame_handle_commit, - }, -#endif - .xdg_toplevel_listener = { - xdg_toplevel_handle_configure, - xdg_toplevel_handle_close, - }, -}; - static void *gfx_ctx_wl_init(void *data) { int i; gfx_ctx_wayland_data_t *wl = NULL; - if (!gfx_ctx_wl_init_common(&toplevel_listener, &wl)) + if (!gfx_ctx_wl_init_common(NULL, &wl)) goto error; if (!vulkan_context_init(&wl->vk, VULKAN_WSI_WAYLAND)) diff --git a/input/common/wayland_common.c b/input/common/wayland_common.c index 9f5d2737358..d860303f0ba 100644 --- a/input/common/wayland_common.c +++ b/input/common/wayland_common.c @@ -661,13 +661,6 @@ static void xdg_shell_ping( xdg_wm_base_pong(shell, serial); } -static void xdg_surface_handle_configure( - void *data, struct xdg_surface *surface, - uint32_t serial) -{ - xdg_surface_ack_configure(surface, serial); -} - static void wl_output_handle_geometry(void *data, struct wl_output *output, int x, int y, @@ -1088,10 +1081,6 @@ const struct xdg_wm_base_listener xdg_shell_listener = { xdg_shell_ping, }; -const struct xdg_surface_listener xdg_surface_listener = { - xdg_surface_handle_configure, -}; - const struct wp_fractional_scale_v1_listener wp_fractional_scale_v1_listener = { wp_fractional_scale_v1_preferred_scale, }; diff --git a/input/common/wayland_common.h b/input/common/wayland_common.h index 8ccae5f2fda..bafaad623e5 100644 --- a/input/common/wayland_common.h +++ b/input/common/wayland_common.h @@ -104,7 +104,7 @@ typedef struct surface_output struct wl_list link; } surface_output_t; -struct gfx_ctx_wayland_data; +typedef struct gfx_ctx_wayland_data gfx_ctx_wayland_data_t; typedef struct input_ctx_wayland_data { @@ -143,6 +143,10 @@ typedef struct data_offer_ctx enum wl_data_device_manager_dnd_action supported_actions; } data_offer_ctx; +typedef struct wayland_configuration wayland_configuration_t; + +typedef void (*driver_configure_handler_t)(gfx_ctx_wayland_data_t *wl); + typedef struct gfx_ctx_wayland_data { #ifdef HAVE_EGL @@ -209,6 +213,8 @@ typedef struct gfx_ctx_wayland_data int num_active_touches; int swap_interval; touch_pos_t active_touch_positions[MAX_TOUCHES]; /* int32_t alignment */ + wayland_configuration_t *pending_configuration; + driver_configure_handler_t driver_configure_handler; unsigned width; unsigned height; unsigned buffer_width; @@ -227,7 +233,6 @@ typedef struct gfx_ctx_wayland_data bool maximized; bool resize; bool configured; - bool ignore_configuration; bool activated; bool reported_display_size; bool swap_complete; @@ -264,8 +269,6 @@ extern const struct wl_surface_listener wl_surface_listener; extern const struct xdg_wm_base_listener xdg_shell_listener; -extern const struct xdg_surface_listener xdg_surface_listener; - extern const struct wl_output_listener output_listener; extern const struct wl_registry_listener registry_listener;