From edf88d9cf506f8e9f509cc3a5de4f91206ab14d2 Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Sun, 16 Oct 2022 00:23:21 -0500 Subject: [PATCH] wayland: add support for content-type protocol 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. --- DOCS/man/options.rst | 6 +++++ generated/wayland/meson.build | 5 ++++ options/options.c | 5 ++++ options/options.h | 1 + video/out/wayland_common.c | 49 +++++++++++++++++++++++++++++++++++ video/out/wayland_common.h | 7 +++++ wscript | 5 ++++ wscript_build.py | 9 +++++++ 8 files changed, 87 insertions(+) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 278a5e4d8774f..800c35e95786d 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -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=`` + 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=`` Disable mpv's internal vsync for Wayland-based video output (default: no). This is mainly useful for benchmarking wayland VOs when combined with diff --git a/generated/wayland/meson.build b/generated/wayland/meson.build index 7811f849e950f..919a280107621 100644 --- a/generated/wayland/meson.build +++ b/generated/wayland/meson.build @@ -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', diff --git a/options/options.c b/options/options.c index 0b1c58d9a605b..4807b7439e28b 100644 --- a/options/options.c +++ b/options/options.c @@ -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 @@ -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, diff --git a/options/options.h b/options/options.h index f38f3b6bfb1bf..b43f3bf63a235 100644 --- a/options/options.h +++ b/options/options.h @@ -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; diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index 51f68a46a6d2f..65e243da3490e 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -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 @@ -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); } @@ -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; @@ -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) @@ -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; @@ -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); @@ -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); diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h index 541b4d0d283dc..627ea0d057ed8 100644 --- a/video/out/wayland_common.h +++ b/video/out/wayland_common.h @@ -24,6 +24,7 @@ struct wayland_opts { int configure_bounds; + int content_type; int disable_vsync; int edge_pixels_pointer; int edge_pixels_touch; @@ -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; diff --git a/wscript b/wscript index e349d4103ecd9..9fc7583225a14 100644 --- a/wscript +++ b/wscript @@ -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()", diff --git a/wscript_build.py b/wscript_build.py index 16c8cf0895960..1621b94b977a2 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -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") @@ -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" ),