Skip to content

Commit

Permalink
wayland: add support for content-type protocol
Browse files Browse the repository at this point in the history
The content-type protocol allows mpv to send compositor a hint about the
type of content being displayed on its surface so it could potentially
make some sort of optimization. Fundamentally, this is pretty simple but
since this requires a very new wayland-protocols version (1.27), we have
to mess with the build to add a new define and add a bunch of if's in
here. The protocol itself exposes 4 different types of content: none,
photo, video, and game.

To do that, let's add a new option (wayland-content-type) that lets
users control what hint to send to the compossitor. Since the previous
commit adds a VOCTRL that notifies us about whether or not if the
current thing being displayed is an image, we can also add an auto value
to this option. As you'd expect, this sets the compositor hint to photo
if mpv's core detects an image and video otherwise. For completion's
sake, game is also allowed as a value for this option, but in practice
there shouldn't be a reason to use that.
  • Loading branch information
Dudemanguy committed Nov 7, 2022
1 parent d4adc46 commit edf88d9
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 0 deletions.
6 changes: 6 additions & 0 deletions DOCS/man/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5581,6 +5581,12 @@ them.
it first renders. This option will take precedence over any ``autofit`` or
``geometry`` type settings if the configure bounds are used.

``--wayland-content-type=<auto|none|photo|video|game>``
If supported by the compositor, mpv will send a hint using the content-type
protocol telling the compositor what type of content is being displayed. ``auto``
(default) will automatically switch between telling the compositor if a photo or
video is being displayed depending on the content being played.

``--wayland-disable-vsync=<yes|no>``
Disable mpv's internal vsync for Wayland-based video output (default: no).
This is mainly useful for benchmarking wayland VOs when combined with
Expand Down
5 changes: 5 additions & 0 deletions generated/wayland/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ wl_protocols_headers = []

features += {'wayland_protocols_1_24': wayland['deps'][2].version().version_compare('>=1.24')}

features += {'wayland_protocols_1_27': wayland['deps'][2].version().version_compare('>=1.27')}
if features['wayland_protocols_1_27']
protocols += [[wl_protocol_dir, 'staging/content-type/content-type-v1.xml']]
endif

foreach p: protocols
xml = join_paths(p)
wl_protocols_source += custom_target(xml.underscorify() + '_c',
Expand Down
5 changes: 5 additions & 0 deletions options/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ static const m_option_t mp_vo_opt_list[] = {
{"x11-present", OPT_CHOICE(x11_present,
{"no", 0}, {"auto", 1}, {"yes", 2})},
#endif
#if HAVE_WAYLAND
{"wayland-content-type", OPT_CHOICE(content_type, {"auto", -1}, {"none", 0},
{"photo", 1}, {"video", 2}, {"game", 3})},
#endif
#if HAVE_WIN32_DESKTOP
{"vo-mmcss-profile", OPT_STRING(mmcss_profile)},
#endif
Expand Down Expand Up @@ -211,6 +215,7 @@ const struct m_sub_options vo_sub_opts = {
.border = 1,
.fit_border = 1,
.appid = "mpv",
.content_type = -1,
.WinID = -1,
.window_scale = 1.0,
.x11_bypass_compositor = 2,
Expand Down
1 change: 1 addition & 0 deletions options/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ typedef struct mp_vo_opts {
char *fsscreen_name;
char *winname;
char *appid;
int content_type;
int x11_netwm;
int x11_bypass_compositor;
int x11_present;
Expand Down
49 changes: 49 additions & 0 deletions video/out/wayland_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
#include "generated/wayland/xdg-shell.h"
#include "generated/wayland/viewporter.h"

#if HAVE_WAYLAND_PROTOCOLS_1_27
#include "generated/wayland/content-type-v1.h"
#endif

#if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 20
#define HAVE_WAYLAND_1_20
#endif
Expand Down Expand Up @@ -1251,6 +1255,12 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
wl->idle_inhibit_manager = wl_registry_bind(reg, id, &zwp_idle_inhibit_manager_v1_interface, 1);
}

#if HAVE_WAYLAND_PROTOCOLS_1_27
if (!strcmp(interface, wp_content_type_manager_v1_interface.name) && found++) {
wl->content_type_manager = wl_registry_bind(reg, id, &wp_content_type_manager_v1_interface, 1);
}
#endif

if (found > 1)
MP_VERBOSE(wl, "Registered for protocol %s\n", interface);
}
Expand Down Expand Up @@ -1520,6 +1530,20 @@ static void remove_output(struct vo_wayland_output *out)
return;
}

static void set_content_type(struct vo_wayland_state *wl)
{
if (!wl->content_type_manager)
return;
#if HAVE_WAYLAND_PROTOCOLS_1_27
// handle auto;
if (wl->vo_opts->content_type == -1) {
wp_content_type_v1_set_content_type(wl->content_type, wl->current_content_type);
} else {
wp_content_type_v1_set_content_type(wl->content_type, wl->vo_opts->content_type);
}
#endif
}

static int set_cursor_visibility(struct vo_wayland_state *wl, bool on)
{
wl->cursor_visible = on;
Expand Down Expand Up @@ -1803,6 +1827,8 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
&wl->vo_opts->border);
}
}
if (opt == &opts->content_type)
set_content_type(wl);
if (opt == &opts->fullscreen)
toggle_fullscreen(wl);
if (opt == &opts->hidpi_window_scale)
Expand All @@ -1825,6 +1851,12 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
}
return VO_TRUE;
}
case VOCTRL_IS_IMAGE: {
wl->current_content_type = (bool)arg ? WP_CONTENT_TYPE_V1_TYPE_PHOTO :
WP_CONTENT_TYPE_V1_TYPE_VIDEO;
set_content_type(wl);
return VO_TRUE;
}
case VOCTRL_GET_FOCUSED: {
*(bool *)arg = wl->focused;
return VO_TRUE;
Expand Down Expand Up @@ -1961,6 +1993,15 @@ int vo_wayland_init(struct vo *vo)
if (xdg_current_desktop != NULL && strstr(xdg_current_desktop, "GNOME"))
MP_WARN(wl, "GNOME's wayland compositor lacks support for the idle inhibit protocol. This means the screen can blank during playback.\n");

#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);
} else {
MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
wp_content_type_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 @@ -2113,6 +2154,14 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->cursor_theme)
wl_cursor_theme_destroy(wl->cursor_theme);

#if HAVE_WAYLAND_PROTOCOLS_1_27
if (wl->content_type)
wp_content_type_v1_destroy(wl->content_type);

if (wl->content_type_manager)
wp_content_type_manager_v1_destroy(wl->content_type_manager);
#endif

if (wl->dnd_ddev)
wl_data_device_destroy(wl->dnd_ddev);

Expand Down
7 changes: 7 additions & 0 deletions video/out/wayland_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

struct wayland_opts {
int configure_bounds;
int content_type;
int disable_vsync;
int edge_pixels_pointer;
int edge_pixels_touch;
Expand Down Expand Up @@ -77,6 +78,12 @@ struct vo_wayland_state {
int timeout_count;
int wakeup_pipe[2];

/* content-type */
/* TODO: unvoid these if required wayland protocols is bumped to 1.27+ */
void *content_type_manager;
void *content_type;
int current_content_type;

/* idle-inhibit */
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
Expand Down
5 changes: 5 additions & 0 deletions wscript
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,11 @@ video_output_features = [
'desc': 'wayland-protocols version 1.24+',
'deps': 'wayland',
'func': check_pkg_config('wayland-protocols >= 1.24'),
} , {
'name': 'wayland-protocols-1-27',
'desc': 'wayland-protocols version 1.27+',
'deps': 'wayland',
'func': check_pkg_config('wayland-protocols >= 1.27'),
} , {
'name': 'memfd_create',
'desc': "Linux's memfd_create()",
Expand Down
9 changes: 9 additions & 0 deletions wscript_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,14 @@ def build(ctx):
protocol = "stable/viewporter/viewporter",
target = "generated/wayland/viewporter.h")

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

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

Expand Down Expand Up @@ -540,6 +548,7 @@ def swift(task):
( "video/out/vulkan/context_xlib.c", "vulkan && x11" ),
( "video/out/vulkan/utils.c", "vulkan" ),
( "video/out/w32_common.c", "win32-desktop" ),
( "generated/wayland/content-type-v1.c", "wayland-protocols-1-27" ),
( "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 edf88d9

Please sign in to comment.