summaryrefslogtreecommitdiffstats
path: root/video/out
diff options
context:
space:
mode:
authorDudemanguy <random342@airmail.cc>2023-01-23 14:16:43 -0600
committerDudemanguy <random342@airmail.cc>2023-01-24 00:04:39 +0000
commit879824a47f50f7e93f85992c92d03f37129605f4 (patch)
tree6e69209e1fe4fa0019fe51384ab15d1335f170ec /video/out
parent006ec9ce4357cd198955bc2e56caec34943db52d (diff)
downloadmpv-879824a47f50f7e93f85992c92d03f37129605f4.tar.bz2
mpv-879824a47f50f7e93f85992c92d03f37129605f4.tar.xz
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 from the fractional scale handling because we want the compositor to handle all the scaling for that VO. Fixes #9443.
Diffstat (limited to 'video/out')
-rw-r--r--video/out/opengl/context_wayland.c2
-rw-r--r--video/out/vo_wlshm.c3
-rw-r--r--video/out/vulkan/context_wayland.c1
-rw-r--r--video/out/wayland_common.c116
-rw-r--r--video/out/wayland_common.h8
5 files changed, 113 insertions, 17 deletions
diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c
index a932ca48fc..0380114e95 100644
--- a/video/out/opengl/context_wayland.c
+++ b/video/out/opengl/context_wayland.c
@@ -84,6 +84,8 @@ static void resize(struct ra_ctx *ctx)
wl->vo->dwidth = width;
wl->vo->dheight = height;
+
+ 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 6f70767b29..44983465da 100644
--- a/video/out/vo_wlshm.c
+++ b/video/out/vo_wlshm.c
@@ -204,6 +204,9 @@ static int resize(struct vo *vo)
p->free_buffers = buf->next;
talloc_free(buf);
}
+
+ 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 157c76855c..5ca6265a91 100644
--- a/video/out/vulkan/context_wayland.c
+++ b/video/out/vulkan/context_wayland.c
@@ -118,6 +118,7 @@ static bool resize(struct ra_ctx *ctx)
const int32_t height = mp_rect_h(wl->geometry);
vo_wayland_set_opaque_region(wl, ctx->opts.want_alpha);
+ 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 aa987480c3..e2ba998956 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -47,6 +47,10 @@
#include "generated/wayland/single-pixel-buffer-v1.h"
#endif
+#if HAVE_WAYLAND_PROTOCOLS_1_31
+#include "generated/wayland/fractional-scale-v1.h"
+#endif
+
#if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 20
#define HAVE_WAYLAND_1_20
#endif
@@ -181,6 +185,7 @@ static void remove_feedback(struct vo_wayland_feedback_pool *fback_pool,
struct wp_presentation_feedback *fback);
static void remove_output(struct vo_wayland_output *out);
static void request_decoration_mode(struct vo_wayland_state *wl, uint32_t mode);
+static void rescale_geometry(struct vo_wayland_state *wl, double old_scale);
static void set_geometry(struct vo_wayland_state *wl);
static void set_surface_scaling(struct vo_wayland_state *wl);
static void window_move(struct vo_wayland_state *wl, uint32_t serial);
@@ -753,7 +758,7 @@ static void surface_handle_enter(void *data, struct wl_surface *wl_surface,
wl->current_output->has_surface = true;
bool force_resize = false;
- if (wl->scaling != wl->current_output->scale) {
+ if (!wl->fractional_scale_manager && wl->scaling != wl->current_output->scale) {
set_surface_scaling(wl);
spawn_cursor(wl);
force_resize = true;
@@ -768,7 +773,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;
@@ -964,6 +969,32 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = {
#endif
};
+#if HAVE_WAYLAND_PROTOCOLS_1_31
+static void preferred_scale(void *data,
+ struct wp_fractional_scale_v1 *fractional_scale,
+ uint32_t scale)
+{
+ struct vo_wayland_state *wl = data;
+ double old_scale = wl->scaling;
+
+ // dmabuf_wayland is always wl->scaling = 1
+ bool dmabuf_wayland = !strcmp(wl->vo->driver->name, "dmabuf-wayland");
+ wl->scaling = !dmabuf_wayland ? (double)scale / 120 : 1;
+ MP_VERBOSE(wl, "Obtained preferred scale, %f, from the compositor.\n",
+ wl->scaling);
+ wl->pending_vo_events |= VO_EVENT_DPI;
+ if (wl->current_output) {
+ rescale_geometry(wl, old_scale);
+ set_geometry(wl);
+ wl->pending_vo_events |= VO_EVENT_RESIZE;
+ }
+}
+
+static const struct wp_fractional_scale_v1_listener fractional_scale_listener = {
+ preferred_scale,
+};
+#endif
+
static const char *zxdg_decoration_mode_to_str(const uint32_t mode)
{
switch (mode) {
@@ -1225,6 +1256,12 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
}
#endif
+#if HAVE_WAYLAND_PROTOCOLS_1_31
+ 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);
+ }
+#endif
+
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);
@@ -1363,6 +1400,20 @@ static bool create_input(struct vo_wayland_state *wl)
return 0;
}
+static int create_viewports(struct vo_wayland_state *wl)
+{
+ if (wl->viewporter) {
+ wl->viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface);
+ wl->video_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->video_surface);
+ }
+
+ if (wl->viewporter && (!wl->viewport || !wl->video_viewport)) {
+ MP_ERR(wl, "failed to create viewport interfaces!\n");
+ return 1;
+ }
+ return 0;
+}
+
static int create_xdg_surface(struct vo_wayland_state *wl)
{
wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->wm_base, wl->surface);
@@ -1371,8 +1422,10 @@ static int create_xdg_surface(struct vo_wayland_state *wl)
wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface);
xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl);
- if (!wl->xdg_surface || !wl->xdg_toplevel)
+ if (!wl->xdg_surface || !wl->xdg_toplevel) {
+ MP_ERR(wl, "failled to create xdg_surface and xdg_toplevel!\n");
return 1;
+ }
return 0;
}
@@ -1514,6 +1567,15 @@ static void request_decoration_mode(struct vo_wayland_state *wl, uint32_t mode)
zxdg_toplevel_decoration_v1_set_mode(wl->xdg_toplevel_decoration, mode);
}
+static void rescale_geometry(struct vo_wayland_state *wl, double old_scale)
+{
+ double factor = old_scale / wl->scaling;
+ wl->window_size.x1 /= factor;
+ wl->window_size.y1 /= factor;
+ wl->geometry.x1 /= factor;
+ wl->geometry.y1 /= factor;
+}
+
static void clean_feedback_pool(struct vo_wayland_feedback_pool *fback_pool)
{
for (int i = 0; i < fback_pool->len; ++i) {
@@ -1623,20 +1685,19 @@ static int set_screensaver_inhibitor(struct vo_wayland_state *wl, int state)
static void set_surface_scaling(struct vo_wayland_state *wl)
{
+ if (wl->fractional_scale_manager)
+ return;
+
+ // dmabuf_wayland is always wl->scaling = 1
bool dmabuf_wayland = !strcmp(wl->vo->driver->name, "dmabuf-wayland");
- int old_scale = wl->scaling;
+ double old_scale = wl->scaling;
if (wl->vo_opts->hidpi_window_scale && !dmabuf_wayland) {
wl->scaling = wl->current_output->scale;
} else {
wl->scaling = 1;
}
- double factor = (double)old_scale / wl->scaling;
- wl->window_size.x1 /= factor;
- wl->window_size.y1 /= factor;
- wl->geometry.x1 /= factor;
- wl->geometry.y1 /= factor;
-
+ rescale_geometry(wl, old_scale);
wl_surface_set_buffer_scale(wl->surface, wl->scaling);
}
@@ -1862,7 +1923,6 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
opt == &opts->autofit_smaller || opt == &opts->autofit_larger)
{
if (wl->current_output) {
- set_geometry(wl);
if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized)
wl->geometry = wl->window_size;
wl->pending_vo_events |= VO_EVENT_RESIZE;
@@ -1950,6 +2010,14 @@ 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)
+{
+ if (wl->fractional_scale_manager && wl->viewport)
+ wp_viewport_set_destination(wl->viewport,
+ round(mp_rect_w(wl->geometry) / wl->scaling),
+ round(mp_rect_h(wl->geometry) / wl->scaling));
+}
+
bool vo_wayland_init(struct vo *vo)
{
vo->wl = talloc_zero(NULL, struct vo_wayland_state);
@@ -2004,6 +2072,9 @@ bool vo_wayland_init(struct vo *vo)
}
/* Can't be initialized during registry due to multi-protocol dependence */
+ if (create_viewports(wl))
+ goto err;
+
if (create_xdg_surface(wl))
goto err;
@@ -2012,11 +2083,6 @@ bool vo_wayland_init(struct vo *vo)
wl_subsurface_set_desync(wl->video_subsurface);
}
- if (wl->viewporter) {
- wl->viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface);
- wl->video_viewport = wp_viewporter_get_viewport(wl->viewporter, wl->video_surface);
- }
-
#if HAVE_WAYLAND_PROTOCOLS_1_27
if (wl->content_type_manager) {
wl->content_type = wp_content_type_manager_v1_get_surface_content_type(wl->content_type_manager, wl->surface);
@@ -2031,6 +2097,16 @@ bool vo_wayland_init(struct vo *vo)
}
#endif
+#if HAVE_WAYLAND_PROTOCOLS_1_31
+ 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);
+ }
+#endif
+
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);
@@ -2210,6 +2286,14 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->fback_pool)
clean_feedback_pool(wl->fback_pool);
+#if HAVE_WAYLAND_PROTOCOLS_1_31
+ 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);
+#endif
+
if (wl->frame_callback)
wl_callback_destroy(wl->frame_callback);
diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h
index c073ae4250..fa65e80ac2 100644
--- a/video/out/wayland_common.h
+++ b/video/out/wayland_common.h
@@ -73,7 +73,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];
@@ -83,6 +83,11 @@ struct vo_wayland_state {
void *content_type;
int current_content_type;
+ /* fractional-scale */
+ /* TODO: unvoid these if required wayland protocols is bumped to 1.31+ */
+ 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;
@@ -156,6 +161,7 @@ bool vo_wayland_supported_format(struct vo *vo, uint32_t format, uint64_t modifi
int vo_wayland_allocate_memfd(struct vo *vo, size_t size);
int vo_wayland_control(struct vo *vo, int *events, int request, void *arg);
+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);