From: Alexandros Frantzis alexandros.frantzis@collabora.com
We need the fractional-scale-v1 and viewporter protocols to enable the application to access the native output resolution and support application side scaling. If this protocol is not available, fall back to compositor scaling which requires that we deal with all coordinates and sizes as if they were expressed in the logical compositor space. --- dlls/winewayland.drv/wayland.c | 9 ++++ dlls/winewayland.drv/wayland_output.c | 65 ++++++++++++++++++++++++++ dlls/winewayland.drv/wayland_surface.c | 3 +- dlls/winewayland.drv/waylanddrv.h | 3 ++ dlls/winewayland.drv/waylanddrv_main.c | 2 + 5 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index 4a09567ba0c..846ebbd8940 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -230,6 +230,15 @@ BOOL wayland_process_init(void) /* We need two roundtrips. One to get and bind globals, one to handle all * initial events produced from registering the globals. */ wl_display_roundtrip_queue(process_wayland.wl_display, process_wayland.wl_event_queue); + /* Check for optional protocol globals after the first roundtrip, since + * subsequent events may rely on options we set here. */ + if (!process_wayland.wp_fractional_scale_manager_v1 || + !process_wayland.wp_viewporter) + { + WARN("Wayland compositor doesn't support required protocols for" + " application scaling, falling back to compositor scaling\n"); + option_use_compositor_scaling = TRUE; + } wl_display_roundtrip_queue(process_wayland.wl_display, process_wayland.wl_event_queue);
/* Check for required protocol globals. */ diff --git a/dlls/winewayland.drv/wayland_output.c b/dlls/winewayland.drv/wayland_output.c index f5941c10f6f..a72e37de1a5 100644 --- a/dlls/winewayland.drv/wayland_output.c +++ b/dlls/winewayland.drv/wayland_output.c @@ -39,6 +39,7 @@ static uint32_t next_output_id = 0; #define WAYLAND_OUTPUT_CHANGED_NAME 0x02 #define WAYLAND_OUTPUT_CHANGED_LOGICAL_XY 0x04 #define WAYLAND_OUTPUT_CHANGED_LOGICAL_WH 0x08 +#define WAYLAND_OUTPUT_CHANGED_SCALE 0x10
/********************************************************************** * Output handling @@ -102,6 +103,25 @@ static void wayland_output_state_add_mode(struct wayland_output_state *state, if (current) state->current_mode = mode; }
+static void wayland_output_set_native_mode(struct wayland_output *output, + struct wayland_output_mode *mode) +{ + free(output->native_mode); + output->native_mode = NULL; + if (mode) + { + output->native_mode = calloc(1, sizeof(*output->native_mode)); + if (!output->native_mode) + { + ERR("Failed to allocate space for native wayland_output_mode\n"); + return; + } + output->native_mode->width = mode->width; + output->native_mode->height = mode->height; + output->native_mode->refresh = mode->refresh; + } +} + static void maybe_init_display_devices(void) { DWORD desktop_pid = 0; @@ -144,6 +164,7 @@ static void wayland_output_done(struct wayland_output *output) } rb_destroy(&output->pending.modes, wayland_output_mode_free_rb, NULL); rb_init(&output->pending.modes, wayland_output_mode_cmp_rb); + wayland_output_set_native_mode(output, output->current.current_mode); }
if (output->pending_flags & WAYLAND_OUTPUT_CHANGED_NAME) @@ -165,8 +186,45 @@ static void wayland_output_done(struct wayland_output *output) output->current.logical_h = output->pending.logical_h; }
+ if (output->pending_flags & WAYLAND_OUTPUT_CHANGED_SCALE) + output->current.scale = output->pending.scale; + output->pending_flags = 0;
+ /* When compositor scaling is used, the current and only mode + * corresponds to the logical width and height. */ + if (option_use_compositor_scaling) + { + int refresh = default_refresh; + int width = output->current.logical_w; + int height = output->current.logical_h; + + if (output->native_mode) + { + refresh = output->native_mode->refresh; + /* Some compositors report logical dimensions that match + * the native ones even when the output is scaled. We + * can't use these, so infer the actual logical dimensions + * on our own. */ + if (output->current.scale != 1 && + width == output->native_mode->width && + height == output->native_mode->height) + { + width = output->native_mode->width / output->current.scale; + height = output->native_mode->height / output->current.scale; + } + } + + output->current.current_mode = NULL; + rb_destroy(&output->current.modes, wayland_output_mode_free_rb, NULL); + + if (width && height) + { + wayland_output_state_add_mode(&output->current, width, height, + refresh, TRUE); + } + } + /* Ensure the logical dimensions have sane values. */ if ((!output->current.logical_w || !output->current.logical_h) && output->current.current_mode) @@ -229,6 +287,10 @@ static void output_handle_done(void *data, struct wl_output *wl_output) static void output_handle_scale(void *data, struct wl_output *wl_output, int32_t scale) { + struct wayland_output *output = data; + + output->pending.scale = scale; + output->pending_flags |= WAYLAND_OUTPUT_CHANGED_SCALE; }
static const struct wl_output_listener output_listener = { @@ -336,6 +398,8 @@ BOOL wayland_output_create(uint32_t id, uint32_t version) goto err; }
+ output->current.scale = 1; + if (process_wayland.zxdg_output_manager_v1) wayland_output_use_xdg_extension(output);
@@ -369,6 +433,7 @@ void wayland_output_destroy(struct wayland_output *output)
wayland_output_state_deinit(&output->pending); wayland_output_state_deinit(&output->current); + free(output->native_mode); if (output->zxdg_output_v1) zxdg_output_v1_destroy(output->zxdg_output_v1); wl_output_destroy(output->wl_output); diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 354a7990245..8ed18745e2b 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -184,7 +184,8 @@ struct wayland_surface *wayland_surface_create(HWND hwnd) wl_surface_set_user_data(surface->wl_surface, hwnd);
surface->preferred_scale = 1.0; - if (process_wayland.wp_fractional_scale_manager_v1) + if (process_wayland.wp_fractional_scale_manager_v1 && + !option_use_compositor_scaling) { surface->wp_fractional_scale_v1 = wp_fractional_scale_manager_v1_get_fractional_scale( diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 284d42ef8eb..5a85137ff85 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -48,6 +48,7 @@ */
extern struct wayland process_wayland DECLSPEC_HIDDEN; +extern BOOL option_use_compositor_scaling DECLSPEC_HIDDEN;
/********************************************************************** * Definitions for wayland types @@ -126,6 +127,7 @@ struct wayland_output_state char *name; int logical_x, logical_y; int logical_w, logical_h; + int scale; };
struct wayland_output @@ -137,6 +139,7 @@ struct wayland_output unsigned int pending_flags; struct wayland_output_state pending; struct wayland_output_state current; + struct wayland_output_mode *native_mode; };
struct wayland_surface_config diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index 7151d7b931a..12b81fd1f0f 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -29,6 +29,8 @@
#include "waylanddrv.h"
+BOOL option_use_compositor_scaling = FALSE; + static const struct user_driver_funcs waylanddrv_funcs = { .pDesktopWindowProc = WAYLAND_DesktopWindowProc,