Skip to content

Commit

Permalink
wayland: add wp-fractional-scale-v1 support
Browse files Browse the repository at this point in the history
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 mpv-player#9443.
  • Loading branch information
Dudemanguy committed Jan 23, 2023
1 parent ad0dd0b commit cc93fb6
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 9 deletions.
4 changes: 4 additions & 0 deletions DOCS/interface-changes.rst
Expand Up @@ -46,6 +46,10 @@ Interface changes
need to explictly add `start` depending on how you have
`--watch-later-options` configured.
- add `--vd-lavc-dr=auto` and make it the default
- add support for the fractional scale protocol in wayland
- in wayland, hidpi window scaling now scales the window by the compositor's
dpi scale factor by default (can be disabled with --no-hidpi-window-scale
if fractional scaling support exists).
--- mpv 0.35.0 ---
- add the `--vo=gpu-next` video output driver, as well as the options
`--allow-delayed-peak-detect`, `--builtin-scalers`,
Expand Down
5 changes: 5 additions & 0 deletions generated/wayland/meson.build
Expand Up @@ -16,6 +16,11 @@ if features['wayland_protocols_1_27']
[wl_protocol_dir, 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml']]
endif

features += {'wayland_protocols_1_31': wayland['deps'][2].version().version_compare('>=1.31')}
if features['wayland_protocols_1_31']
protocols += [[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml']]
endif

foreach p: protocols
xml = join_paths(p)
wl_protocols_source += custom_target(xml.underscorify() + '_c',
Expand Down
2 changes: 2 additions & 0 deletions video/out/opengl/context_wayland.c
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions video/out/vo_wlshm.c
Expand Up @@ -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);
}

Expand Down
1 change: 1 addition & 0 deletions video/out/vulkan/context_wayland.c
Expand Up @@ -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);
}

Expand Down
92 changes: 84 additions & 8 deletions video/out/wayland_common.c
Expand Up @@ -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
Expand Down Expand Up @@ -753,7 +757,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;
Expand All @@ -768,7 +772,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;
Expand Down Expand Up @@ -964,6 +968,28 @@ 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;

// 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)
set_geometry(wl);
}

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) {
Expand Down Expand Up @@ -1225,6 +1251,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);
Expand Down Expand Up @@ -1363,6 +1395,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);
Expand All @@ -1371,8 +1417,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;
}

Expand Down Expand Up @@ -1623,6 +1671,10 @@ 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;
if (wl->vo_opts->hidpi_window_scale && !dmabuf_wayland) {
Expand Down Expand Up @@ -1950,6 +2002,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);
Expand Down Expand Up @@ -2004,6 +2064,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;

Expand All @@ -2012,11 +2075,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);
Expand All @@ -2031,6 +2089,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);
Expand Down Expand Up @@ -2210,6 +2278,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);

Expand Down
8 changes: 7 additions & 1 deletion video/out/wayland_common.h
Expand Up @@ -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];

Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions wscript
Expand Up @@ -540,6 +540,11 @@ video_output_features = [
'desc': 'wayland-protocols version 1.27+',
'deps': 'wayland',
'func': check_pkg_config('wayland-protocols >= 1.27'),
} , {
'name': 'wayland-protocols-1-31',
'desc': 'wayland-protocols version 1.31+',
'deps': 'wayland',
'func': check_pkg_config('wayland-protocols >= 1.31'),
} , {
'name': 'memfd_create',
'desc': "Linux's memfd_create()",
Expand Down
10 changes: 10 additions & 0 deletions wscript_build.py
Expand Up @@ -154,6 +154,15 @@ def build(ctx):
protocol = "staging/single-pixel-buffer/single-pixel-buffer-v1",
target = "generated/wayland/single-pixel-buffer-v1.h")


if ctx.dependency_satisfied('wayland-protocols-1-31'):
ctx.wayland_protocol_code(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "staging/fractional-scale/fractional-scale-v1",
target = "generated/wayland/fractional-scale-v1.c")
ctx.wayland_protocol_header(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "staging/fractional-scale/fractional-scale-v1",
target = "generated/wayland/fractional-scale-v1.h")

ctx(features = "ebml_header", target = "generated/ebml_types.h")
ctx(features = "ebml_definitions", target = "generated/ebml_defs.inc")

Expand Down Expand Up @@ -557,6 +566,7 @@ def swift(task):
( "video/out/w32_common.c", "win32-desktop" ),
( "generated/wayland/single-pixel-buffer-v1.c", "wayland-protocols-1-27" ),
( "generated/wayland/content-type-v1.c", "wayland-protocols-1-27" ),
( "generated/wayland/fractional-scale-v1.c", "wayland-protocols-1-31"),
( "generated/wayland/idle-inhibit-unstable-v1.c", "wayland" ),
( "generated/wayland/presentation-time.c", "wayland" ),
( "generated/wayland/xdg-decoration-unstable-v1.c", "wayland" ),
Expand Down

0 comments on commit cc93fb6

Please sign in to comment.