From ba39bde7c918fd08806d8f606dff00c4740119f5 Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Mon, 28 Nov 2022 11:05:13 -0600 Subject: [PATCH] wayland: add wp-fractional-scale-v1 support This protocol is pretty important since it finally lets us solve the longstanding issue of fractional scaling in wayland (no more mpv doing rendering over the target resolution and then being scaled down). This protocol also can completely replace the buffer_scale usage that we are currently using for integer scaling so hopefully this can be removed sometime in the future. Note that vo_dmabuf_wayland is omitted because we want the compositor to handle all the scaling for that VO (i.e. just leave the default buffer scale of one). Fixes #9443. --- generated/wayland/meson.build | 1 + video/out/opengl/context_wayland.c | 7 +++- video/out/vo_wlshm.c | 4 ++ video/out/vulkan/context_wayland.c | 4 ++ video/out/wayland_common.c | 64 ++++++++++++++++++++++++++---- video/out/wayland_common.h | 8 +++- 6 files changed, 78 insertions(+), 10 deletions(-) diff --git a/generated/wayland/meson.build b/generated/wayland/meson.build index 423fc7c76ea3..27a96d2355e1 100644 --- a/generated/wayland/meson.build +++ b/generated/wayland/meson.build @@ -2,6 +2,7 @@ wl_protocol_dir = wayland['deps'][2].get_variable(pkgconfig: 'pkgdatadir', inter protocols = [[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'], [wl_protocol_dir, 'stable/viewporter/viewporter.xml'], [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], + [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], #TODO: guard this [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], [wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml']] diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c index 2782d465090a..79343fcc7e41 100644 --- a/video/out/opengl/context_wayland.c +++ b/video/out/opengl/context_wayland.c @@ -75,8 +75,8 @@ static void resize(struct ra_ctx *ctx) if (!p->egl_window) egl_create_window(ctx); - const int32_t width = wl->scaling * mp_rect_w(wl->geometry); - const int32_t height = wl->scaling * mp_rect_h(wl->geometry); + const int32_t width = round(wl->scaling * mp_rect_w(wl->geometry)); + const int32_t height = round(wl->scaling * mp_rect_h(wl->geometry)); vo_wayland_set_opaque_region(wl, ctx->opts.want_alpha); if (p->egl_window) @@ -84,6 +84,9 @@ static void resize(struct ra_ctx *ctx) wl->vo->dwidth = width; wl->vo->dheight = height; + + if (wl->fractional_viewport) + vo_wayland_handle_fractional_scale(wl); } static bool wayland_egl_check_visible(struct ra_ctx *ctx) diff --git a/video/out/vo_wlshm.c b/video/out/vo_wlshm.c index fc9fc705fc1a..52b72e2f456b 100644 --- a/video/out/vo_wlshm.c +++ b/video/out/vo_wlshm.c @@ -188,6 +188,10 @@ static int resize(struct vo *vo) p->free_buffers = buf->next; talloc_free(buf); } + + if (wl->fractional_viewport) + vo_wayland_handle_fractional_scale(wl); + return mp_sws_reinit(p->sws); } diff --git a/video/out/vulkan/context_wayland.c b/video/out/vulkan/context_wayland.c index fe20336a9ef4..cae0058ab09a 100644 --- a/video/out/vulkan/context_wayland.c +++ b/video/out/vulkan/context_wayland.c @@ -118,6 +118,10 @@ static bool resize(struct ra_ctx *ctx) const int32_t height = wl->scaling * mp_rect_h(wl->geometry); vo_wayland_set_opaque_region(wl, ctx->opts.want_alpha); + + if (wl->fractional_viewport) + vo_wayland_handle_fractional_scale(wl); + return ra_vk_ctx_resize(ctx, width, height); } diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index 7987dcef44d4..e5d004e8a18d 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -47,6 +47,9 @@ #include "generated/wayland/single-pixel-buffer-v1.h" #endif +//TODO: guard +#include "generated/wayland/fractional-scale-v1.h" + #if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 20 #define HAVE_WAYLAND_1_20 #endif @@ -757,7 +760,7 @@ static void surface_handle_enter(void *data, struct wl_surface *wl_surface, if (!mp_rect_equals(&old_geometry, &wl->geometry) || force_resize) wl->pending_vo_events |= VO_EVENT_RESIZE; - MP_VERBOSE(wl, "Surface entered output %s %s (0x%x), scale = %i, refresh rate = %f Hz\n", + MP_VERBOSE(wl, "Surface entered output %s %s (0x%x), scale = %f, refresh rate = %f Hz\n", o->make, o->model, o->id, wl->scaling, o->refresh_rate); wl->pending_vo_events |= VO_EVENT_WIN_STATE; @@ -922,8 +925,8 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel, resize: MP_VERBOSE(wl, "Resizing due to xdg from %ix%i to %ix%i\n", - mp_rect_w(old_geometry)*wl->scaling, mp_rect_h(old_geometry)*wl->scaling, - mp_rect_w(wl->geometry)*wl->scaling, mp_rect_h(wl->geometry)*wl->scaling); + (int)round(mp_rect_w(old_geometry) * wl->scaling), (int)round(mp_rect_h(old_geometry) * wl->scaling), + (int)round(mp_rect_w(wl->geometry) * wl->scaling), (int)round(mp_rect_h(wl->geometry) * wl->scaling)); wl->pending_vo_events |= VO_EVENT_RESIZE; wl->toplevel_configured = true; @@ -953,6 +956,21 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = { #endif }; +//TODO: Guard +static void preferred_scale(void *data, + struct wp_fractional_scale_v1 *fractional_scale, + uint32_t scale) +{ + struct vo_wayland_state *wl = data; + wl->scaling = (double)scale / 120; + MP_VERBOSE(wl, "Obtained preferred scale, %f, from the compositor.\n", + wl->scaling); +} + +static const struct wp_fractional_scale_v1_listener fractional_scale_listener = { + preferred_scale, +}; + static const char *zxdg_decoration_mode_to_str(const uint32_t mode) { switch (mode) { @@ -1247,6 +1265,11 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id } #endif + //TODO: guard this + if (!strcmp(interface, wp_fractional_scale_manager_v1_interface.name) && found++) { + wl->fractional_scale_manager = wl_registry_bind(reg, id, &wp_fractional_scale_manager_v1_interface, 1); + } + if (!strcmp(interface, wp_presentation_interface.name) && found++) { wl->presentation = wl_registry_bind(reg, id, &wp_presentation_interface, 1); wp_presentation_add_listener(wl->presentation, &pres_listener, wl); @@ -1612,19 +1635,20 @@ static int set_screensaver_inhibitor(struct vo_wayland_state *wl, int state) static void set_surface_scaling(struct vo_wayland_state *wl) { bool dmabuf_wayland = !strcmp(wl->vo->driver->name, "dmabuf-wayland"); - int old_scale = wl->scaling; - if (wl->vo_opts->hidpi_window_scale && !dmabuf_wayland) { + double old_scale = wl->scaling; + if (wl->vo_opts->hidpi_window_scale && !dmabuf_wayland && !wl->fractional_scale_manager) { wl->scaling = wl->current_output->scale; } else { wl->scaling = 1; } - double factor = (double)old_scale / wl->scaling; + double factor = old_scale / wl->scaling; wl->vdparams.x1 *= factor; wl->vdparams.y1 *= factor; wl->window_size.x1 *= factor; wl->window_size.y1 *= factor; - wl_surface_set_buffer_scale(wl->surface, wl->scaling); + if (!wl->fractional_scale_manager) + wl_surface_set_buffer_scale(wl->surface, wl->scaling); } static void set_window_bounds(struct vo_wayland_state *wl) @@ -1935,6 +1959,12 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg) return VO_NOTIMPL; } +void vo_wayland_handle_fractional_scale(struct vo_wayland_state *wl) +{ + wp_viewport_set_destination(wl->fractional_viewport, mp_rect_w(wl->geometry), + mp_rect_h(wl->geometry)); +} + int vo_wayland_init(struct vo *vo) { vo->wl = talloc_zero(NULL, struct vo_wayland_state); @@ -1997,6 +2027,7 @@ int vo_wayland_init(struct vo *vo) } if (wl->viewporter) { + wl->fractional_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface); wl->viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface); wl->video_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->video_surface); } @@ -2019,6 +2050,15 @@ int vo_wayland_init(struct vo *vo) } #endif + //TODO: guard + if (wl->fractional_scale_manager) { + wl->fractional_scale = wp_fractional_scale_manager_v1_get_fractional_scale(wl->fractional_scale_manager, wl->surface); + wp_fractional_scale_v1_add_listener(wl->fractional_scale, &fractional_scale_listener, wl); + } else { + MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n", + wp_fractional_scale_manager_v1_interface.name); + } + if (wl->dnd_devman && wl->seat) { wl->dnd_ddev = wl_data_device_manager_get_data_device(wl->dnd_devman, wl->seat); wl_data_device_add_listener(wl->dnd_ddev, &data_device_listener, wl); @@ -2194,6 +2234,13 @@ void vo_wayland_uninit(struct vo *vo) if (wl->frame_callback) wl_callback_destroy(wl->frame_callback); + //TODO: guard these + if (wl->fractional_scale) + wp_fractional_scale_v1_destroy(wl->fractional_scale); + + if (wl->fractional_scale_manager) + wp_fractional_scale_manager_v1_destroy(wl->fractional_scale_manager); + if (wl->idle_inhibitor) zwp_idle_inhibitor_v1_destroy(wl->idle_inhibitor); @@ -2215,6 +2262,9 @@ void vo_wayland_uninit(struct vo *vo) if (wl->viewporter) wp_viewporter_destroy(wl->viewporter); + if (wl->fractional_viewport) + wp_viewport_destroy(wl->fractional_viewport); + if (wl->viewport) wp_viewport_destroy(wl->viewport); diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h index 4f505b903bad..e4ba32357e7c 100644 --- a/video/out/wayland_common.h +++ b/video/out/wayland_common.h @@ -74,7 +74,7 @@ struct vo_wayland_state { int mouse_x; int mouse_y; int pending_vo_events; - int scaling; + double scaling; int timeout_count; int wakeup_pipe[2]; @@ -84,6 +84,10 @@ struct vo_wayland_state { void *content_type; int current_content_type; + /* fractional-scale */ + void *fractional_scale_manager; + void *fractional_scale; + /* idle-inhibit */ struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager; struct zwp_idle_inhibitor_v1 *idle_inhibitor; @@ -122,6 +126,7 @@ struct vo_wayland_state { /* viewporter */ struct wp_viewporter *viewporter; + struct wp_viewport *fractional_viewport; struct wp_viewport *viewport; struct wp_viewport *video_viewport; @@ -161,6 +166,7 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg); int vo_wayland_init(struct vo *vo); int vo_wayland_reconfig(struct vo *vo); +void vo_wayland_handle_fractional_scale(struct vo_wayland_state *wl); void vo_wayland_set_opaque_region(struct vo_wayland_state *wl, int alpha); void vo_wayland_sync_swap(struct vo_wayland_state *wl); void vo_wayland_uninit(struct vo *vo);