Skip to content

Commit

Permalink
wayland: use the surface-suspension-v1 protocol
Browse files Browse the repository at this point in the history
Currently, mpv tries very hard to not do wasteful draws when the surface
is hidden. This is accomplished by abusing vo_wayland_wait_frame and
just guessing that consecutive timeouts == surface hidden. This works
but it's pretty ugly (explaining why wl->timeout_count > 1 is an entire
novel. Go dig up that commit if you're curious). Luckily, we now have
the ability to just get suspended events from the compositor. Delete the
entire timeout/hidden surface heuristic and use the surface_suspended
and surface_resumed events instead. As a side effect of this, this means
that mpv will always "overdraw" (i.e. render when not needed) if the
compositor does not implement this protocol. If this bothers you, go bug
your compositor developers to fix it and/or switch do a better one.
  • Loading branch information
Dudemanguy committed Jun 27, 2021
1 parent a02901c commit d31c7ac
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 30 deletions.
3 changes: 1 addition & 2 deletions video/out/opengl/context_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,9 @@ static bool wayland_egl_start_frame(struct ra_swapchain *sw, struct ra_fbo *out_
{
struct ra_ctx *ctx = sw->ctx;
struct vo_wayland_state *wl = ctx->vo->wl;
bool render = !wl->hidden || wl->opts->disable_vsync;
wl->frame_wait = true;

return render ? ra_gl_ctx_start_frame(sw, out_fbo) : false;
return !wl->suspended ? ra_gl_ctx_start_frame(sw, out_fbo) : false;
}

static void wayland_egl_swap_buffers(struct ra_swapchain *sw)
Expand Down
3 changes: 1 addition & 2 deletions video/out/vo_wlshm.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,9 @@ static void draw_image(struct vo *vo, struct mp_image *src)
struct priv *p = vo->priv;
struct vo_wayland_state *wl = vo->wl;
struct buffer *buf;
bool render = !wl->hidden || wl->opts->disable_vsync;
wl->frame_wait = true;

if (!render)
if (wl->suspended)
return;

buf = p->free_buffers;
Expand Down
4 changes: 1 addition & 3 deletions video/out/vulkan/context_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ struct priv {
static bool wayland_vk_start_frame(struct ra_ctx *ctx)
{
struct vo_wayland_state *wl = ctx->vo->wl;
bool render = !wl->hidden || wl->opts->disable_vsync;
wl->frame_wait = true;

return render;
return !wl->suspended;
}

static void wayland_vk_swap_buffers(struct ra_ctx *ctx)
Expand Down
60 changes: 39 additions & 21 deletions video/out/wayland_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
// Generated from wayland-protocols
#include "generated/wayland/idle-inhibit-unstable-v1.h"
#include "generated/wayland/presentation-time.h"
#include "generated/wayland/surface-suspension.h"
#include "generated/wayland/xdg-decoration-unstable-v1.h"
#include "generated/wayland/xdg-shell.h"

Expand Down Expand Up @@ -750,6 +751,26 @@ static const struct wl_surface_listener surface_listener = {
surface_handle_leave,
};

static void surface_suspended(void *data, struct wp_surface_suspension_v1 *surface_suspension)
{
struct vo_wayland_state *wl = data;
wl->suspended = true;
}

static void surface_resumed(void *data, struct wp_surface_suspension_v1 *surface_suspension)
{
struct vo_wayland_state *wl = data;
wl->suspended = false;

/* If the surface becomes unoccluded, force a redraw. */
wl->pending_vo_events |= VO_EVENT_EXPOSE;
}

static const struct wp_surface_suspension_v1_listener surface_suspension_listener = {
surface_suspended,
surface_resumed,
};

static void xdg_wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial)
{
xdg_wm_base_pong(wm_base, serial);
Expand Down Expand Up @@ -832,12 +853,6 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel,
{
wl->focused = !wl->focused;
wl->pending_vo_events |= VO_EVENT_FOCUS;

if (wl->activated) {
/* If the surface comes back into view, force a redraw. */
vo_wayland_wait_frame(wl);
wl->pending_vo_events |= VO_EVENT_EXPOSE;
}
}
}

Expand Down Expand Up @@ -1032,6 +1047,10 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
wp_presentation_add_listener(wl->presentation, &pres_listener, wl);
}

if (!strcmp(interface, wp_surface_suspension_manager_v1_interface.name) && found++) {
wl->surface_suspension_manager = wl_registry_bind(reg, id, &wp_surface_suspension_manager_v1_interface, 1);
}

if (!strcmp(interface, xdg_wm_base_interface.name) && found++) {
ver = MPMIN(ver, 2); /* We can use either 1 or 2 */
wl->wm_base = wl_registry_bind(reg, id, &xdg_wm_base_interface, ver);
Expand Down Expand Up @@ -1697,6 +1716,14 @@ int vo_wayland_init(struct vo *vo)
wp_presentation_interface.name);
}

if (wl->surface_suspension_manager) {
wl->surface_suspension = wp_surface_suspension_manager_v1_get_surface_suspension(wl->surface_suspension_manager, wl->surface);
wp_surface_suspension_v1_add_listener(wl->surface_suspension, &surface_suspension_listener, wl);
} else {
MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
wp_surface_suspension_manager_v1_interface.name);
}

if (wl->xdg_decoration_manager) {
wl->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(wl->xdg_decoration_manager, wl->xdg_toplevel);
set_border_decorations(wl, wl->vo_opts->border);
Expand Down Expand Up @@ -1884,6 +1911,12 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->surface)
wl_surface_destroy(wl->surface);

if (wl->surface_suspension)
wp_surface_suspension_v1_destroy(wl->surface_suspension);

if (wl->surface_suspension_manager)
wp_surface_suspension_manager_v1_destroy(wl->surface_suspension_manager);

if (wl->wm_base)
xdg_wm_base_destroy(wl->wm_base);

Expand Down Expand Up @@ -1962,21 +1995,6 @@ void vo_wayland_wait_frame(struct vo_wayland_state *wl)
* that this wait is accurate. Do a hacky block with wl_display_roundtrip. */
if (!wl->presentation && !wl_display_get_error(wl->display))
wl_display_roundtrip(wl->display);

if (wl->frame_wait) {
// Only consider consecutive missed callbacks.
if (wl->timeout_count > 1) {
wl->hidden = true;
return;
} else {
wl->timeout_count += 1;
wl->hidden = false;
return;
}
}

wl->timeout_count = 0;
wl->hidden = false;
}

void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us)
Expand Down
7 changes: 5 additions & 2 deletions video/out/wayland_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ struct vo_wayland_state {
bool has_keyboard_input;
bool focused;
bool frame_wait;
bool hidden;
bool state_change;
bool suspended;
bool toplevel_configured;
int display_fd;
int mouse_unscaled_x;
Expand All @@ -68,14 +68,17 @@ struct vo_wayland_state {
int mouse_y;
int pending_vo_events;
int scaling;
int timeout_count;
int touch_entries;
int wakeup_pipe[2];

/* idle-inhibit */
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct zwp_idle_inhibitor_v1 *idle_inhibitor;

/* surface-suspension */
struct wp_surface_suspension_manager_v1 *surface_suspension_manager;
struct wp_surface_suspension_v1 *surface_suspension;

/* xdg-decoration */
struct zxdg_decoration_manager_v1 *xdg_decoration_manager;
struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration;
Expand Down
1 change: 1 addition & 0 deletions wscript
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ video_output_features = [
'desc': 'wayland-scanner',
'func': check_program('wayland-scanner', 'WAYSCAN')
} , {
#TODO: add a version check here for whenever the protocol gets merged
'name': '--wayland-protocols',
'desc': 'wayland-protocols',
'func': check_wl_protocols
Expand Down
7 changes: 7 additions & 0 deletions wscript_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ def build(ctx):
ctx.wayland_protocol_header(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "stable/xdg-shell/xdg-shell",
target = "generated/wayland/xdg-shell.h")
ctx.wayland_protocol_code(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "staging/surface-suspension/surface-suspension-v1",
target = "generated/wayland/surface-suspension.c")
ctx.wayland_protocol_header(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "staging/surface-suspension/surface-suspension-v1",
target = "generated/wayland/surface-suspension.h")
ctx.wayland_protocol_code(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "unstable/idle-inhibit/idle-inhibit-unstable-v1",
target = "generated/wayland/idle-inhibit-unstable-v1.c")
Expand Down Expand Up @@ -515,6 +521,7 @@ def swift(task):
( "video/out/w32_common.c", "win32-desktop" ),
( "generated/wayland/idle-inhibit-unstable-v1.c", "wayland" ),
( "generated/wayland/presentation-time.c", "wayland" ),
( "generated/wayland/surface-suspension.c", "wayland" ),
( "generated/wayland/xdg-decoration-unstable-v1.c", "wayland" ),
( "generated/wayland/xdg-shell.c", "wayland" ),
( "video/out/wayland_common.c", "wayland" ),
Expand Down

0 comments on commit d31c7ac

Please sign in to comment.