summaryrefslogtreecommitdiffstats
path: root/video/out
diff options
context:
space:
mode:
Diffstat (limited to 'video/out')
-rw-r--r--video/out/opengl/context_wayland.c35
-rw-r--r--video/out/vo_wlshm.c34
-rw-r--r--video/out/vulkan/context.c5
-rw-r--r--video/out/vulkan/context.h3
-rw-r--r--video/out/vulkan/context_wayland.c23
-rw-r--r--video/out/wayland_common.c39
-rw-r--r--video/out/wayland_common.h6
7 files changed, 108 insertions, 37 deletions
diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c
index 410a490ee7..13040b54d8 100644
--- a/video/out/opengl/context_wayland.c
+++ b/video/out/opengl/context_wayland.c
@@ -73,7 +73,6 @@ static void feedback_presented(void *data, struct wp_presentation_feedback *fbac
index = 0;
}
int64_t sec = (uint64_t) tv_sec_lo + ((uint64_t) tv_sec_hi << 32);
- wl->sync[index].sbc = wl->user_sbc;
wl->sync[index].ust = sec * 1000000LL + (uint64_t) tv_nsec / 1000;
wl->sync[index].msc = (uint64_t) seq_lo + ((uint64_t) seq_hi << 32);
wl->sync[index].filled = true;
@@ -134,8 +133,25 @@ static void resize(struct ra_ctx *ctx)
wl->vo->dheight = height;
}
-static void wayland_egl_swap_buffers(struct ra_ctx *ctx)
+static bool wayland_egl_start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo)
{
+ struct ra_ctx *ctx = sw->ctx;
+ struct vo_wayland_state *wl = ctx->vo->wl;
+
+ bool render = !wl->frame_wait || wl->opts->disable_vsync;
+
+ if (wl->frame_wait && wl->presentation)
+ vo_wayland_sync_clear(wl);
+
+ if (render)
+ wl->frame_wait = true;
+
+ return render ? ra_gl_ctx_start_frame(sw, out_fbo) : false;
+}
+
+static void wayland_egl_swap_buffers(struct ra_swapchain *sw)
+{
+ struct ra_ctx *ctx = sw->ctx;
struct priv *p = ctx->priv;
struct vo_wayland_state *wl = ctx->vo->wl;
@@ -144,14 +160,15 @@ static void wayland_egl_swap_buffers(struct ra_ctx *ctx)
if (!wl->opts->disable_vsync)
vo_wayland_wait_frame(wl);
- if (wl->presentation) {
- wl->user_sbc += 1;
+ if (wl->presentation)
wayland_sync_swap(wl);
- }
-
- wl->frame_wait = true;
}
+static const struct ra_swapchain_fns wayland_egl_swapchain = {
+ .start_frame = wayland_egl_start_frame,
+ .swap_buffers = wayland_egl_swap_buffers,
+};
+
static void wayland_egl_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
{
struct vo_wayland_state *wl = ctx->vo->wl;
@@ -184,8 +201,8 @@ static bool egl_create_context(struct ra_ctx *ctx)
mpegl_load_functions(&p->gl, wl->log);
struct ra_gl_ctx_params params = {
- .swap_buffers = wayland_egl_swap_buffers,
- .get_vsync = wayland_egl_get_vsync,
+ .external_swapchain = &wayland_egl_swapchain,
+ .get_vsync = &wayland_egl_get_vsync,
};
if (!ra_gl_ctx_init(ctx, &p->gl, params))
diff --git a/video/out/vo_wlshm.c b/video/out/vo_wlshm.c
index 16669466dd..3b328faee6 100644
--- a/video/out/vo_wlshm.c
+++ b/video/out/vo_wlshm.c
@@ -73,6 +73,25 @@ static void buffer_destroy(void *p)
munmap(buf->mpi.planes[0], buf->size);
}
+static const struct wl_callback_listener frame_listener;
+
+static void frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct vo_wayland_state *wl = data;
+
+ if (callback)
+ wl_callback_destroy(callback);
+
+ wl->frame_callback = wl_surface_frame(wl->surface);
+ wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
+
+ wl->frame_wait = false;
+}
+
+static const struct wl_callback_listener frame_listener = {
+ frame_callback,
+};
+
static int allocate_memfd(size_t size)
{
int fd = memfd_create("mpv", MFD_CLOEXEC | MFD_ALLOW_SEALING);
@@ -123,6 +142,11 @@ static struct buffer *buffer_create(struct vo *vo, int width, int height)
if (!buf->buffer)
goto error4;
wl_buffer_add_listener(buf->buffer, &buffer_listener, buf);
+ if (!wl->frame_callback) {
+ wl->frame_callback = wl_surface_frame(wl->surface);
+ wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
+ }
+
close(fd);
talloc_set_destructor(buf, buffer_destroy);
@@ -207,6 +231,8 @@ static int control(struct vo *vo, uint32_t request, void *data)
if (events & VO_EVENT_RESIZE)
ret = resize(vo);
+ if (events & VO_EVENT_EXPOSE)
+ vo->want_redraw = true;
vo_event(vo, events);
return ret;
}
@@ -217,6 +243,11 @@ static void draw_image(struct vo *vo, struct mp_image *src)
struct vo_wayland_state *wl = vo->wl;
struct buffer *buf;
+ if (wl->frame_wait)
+ return;
+
+ wl->frame_wait = true;
+
buf = p->free_buffers;
if (buf) {
p->free_buffers = buf->next;
@@ -266,6 +297,9 @@ static void flip_page(struct vo *vo)
wl_surface_damage(wl->surface, 0, 0, mp_rect_w(wl->geometry),
mp_rect_h(wl->geometry));
wl_surface_commit(wl->surface);
+
+ if (!wl->opts->disable_vsync)
+ vo_wayland_wait_frame(wl);
}
static void uninit(struct vo *vo)
diff --git a/video/out/vulkan/context.c b/video/out/vulkan/context.c
index 4d94c6fb77..3518d3efd2 100644
--- a/video/out/vulkan/context.c
+++ b/video/out/vulkan/context.c
@@ -229,6 +229,11 @@ static bool start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo)
{
struct priv *p = sw->priv;
struct pl_swapchain_frame frame;
+ bool start = true;
+ if (p->params.start_frame)
+ start = p->params.start_frame(sw->ctx);
+ if (!start)
+ return false;
if (!pl_swapchain_start_frame(p->swapchain, &frame))
return false;
if (!mppl_wrap_tex(sw->ctx->ra, frame.fbo, &p->proxy_tex))
diff --git a/video/out/vulkan/context.h b/video/out/vulkan/context.h
index 0b420e2daa..6ae64bb0f5 100644
--- a/video/out/vulkan/context.h
+++ b/video/out/vulkan/context.h
@@ -7,6 +7,9 @@ struct ra_vk_ctx_params {
// See ra_swapchain_fns.get_vsync.
void (*get_vsync)(struct ra_ctx *ctx, struct vo_vsync_info *info);
+ // In case something special needs to be done when starting a frame.
+ bool (*start_frame)(struct ra_ctx *ctx);
+
// In case something special needs to be done on the buffer swap.
void (*swap_buffers)(struct ra_ctx *ctx);
};
diff --git a/video/out/vulkan/context_wayland.c b/video/out/vulkan/context_wayland.c
index ab295152dd..481c1005e1 100644
--- a/video/out/vulkan/context_wayland.c
+++ b/video/out/vulkan/context_wayland.c
@@ -63,7 +63,6 @@ static void feedback_presented(void *data, struct wp_presentation_feedback *fbac
index = 0;
}
int64_t sec = (uint64_t) tv_sec_lo + ((uint64_t) tv_sec_hi << 32);
- wl->sync[index].sbc = wl->user_sbc;
wl->sync[index].ust = sec * 1000000LL + (uint64_t) tv_nsec / 1000;
wl->sync[index].msc = (uint64_t) seq_lo + ((uint64_t) seq_hi << 32);
wl->sync[index].filled = true;
@@ -103,6 +102,21 @@ static const struct wl_callback_listener frame_listener = {
frame_callback,
};
+static bool wayland_vk_start_frame(struct ra_ctx *ctx)
+{
+ struct vo_wayland_state *wl = ctx->vo->wl;
+
+ bool render = !wl->frame_wait || wl->opts->disable_vsync;
+
+ if (wl->frame_wait && wl->presentation)
+ vo_wayland_sync_clear(wl);
+
+ if (render)
+ wl->frame_wait = true;
+
+ return render;
+}
+
static void wayland_vk_swap_buffers(struct ra_ctx *ctx)
{
struct vo_wayland_state *wl = ctx->vo->wl;
@@ -110,12 +124,8 @@ static void wayland_vk_swap_buffers(struct ra_ctx *ctx)
if (!wl->opts->disable_vsync)
vo_wayland_wait_frame(wl);
- if (wl->presentation) {
- wl->user_sbc += 1;
+ if (wl->presentation)
wayland_sync_swap(wl);
- }
-
- wl->frame_wait = true;
}
static void wayland_vk_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
@@ -156,6 +166,7 @@ static bool wayland_vk_init(struct ra_ctx *ctx)
};
struct ra_vk_ctx_params params = {
+ .start_frame = wayland_vk_start_frame,
.swap_buffers = wayland_vk_swap_buffers,
.get_vsync = wayland_vk_get_vsync,
};
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index c6c0e342c9..eb1e0f8c21 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -1005,6 +1005,11 @@ 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. */
+ wl->pending_vo_events |= VO_EVENT_EXPOSE;
+ }
}
}
@@ -1607,6 +1612,13 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
return VO_NOTIMPL;
}
+void vo_wayland_sync_clear(struct vo_wayland_state *wl)
+{
+ struct vo_wayland_sync sync = {0, 0, 0, 0};
+ for (int i = 0; i < wl->sync_size; ++i)
+ wl->sync[i] = sync;
+}
+
void vo_wayland_sync_shift(struct vo_wayland_state *wl)
{
for (int i = wl->sync_size - 1; i > 0; --i) {
@@ -1630,7 +1642,6 @@ void queue_new_sync(struct vo_wayland_state *wl)
wl->sync_size += 1;
wl->sync = talloc_realloc(wl, wl->sync, struct vo_wayland_sync, wl->sync_size);
vo_wayland_sync_shift(wl);
- wl->sync[0].sbc = wl->user_sbc;
}
void wayland_sync_swap(struct vo_wayland_state *wl)
@@ -1638,10 +1649,10 @@ void wayland_sync_swap(struct vo_wayland_state *wl)
int index = wl->sync_size - 1;
// If these are the same, presentation feedback has not been received.
- // This will happen if the window is obscured/hidden in some way. Set
- // these values to -1 to disable presentation feedback in mpv's core.
+ // This can happen if a frame takes too long and misses vblank. Don't
+ // attempt to use these statistics and wait until the next presentation
+ // event arrives.
if (wl->sync[index].ust == wl->last_ust) {
- wl->last_sbc += 1;
wl->last_skipped_vsyncs = -1;
wl->vsync_duration = -1;
wl->last_queue_display_time = -1;
@@ -1654,27 +1665,19 @@ void wayland_sync_swap(struct vo_wayland_state *wl)
wl->last_ust = wl->sync[index].ust;
int64_t msc_passed = wl->sync[index].msc ? wl->sync[index].msc - wl->last_msc: 0;
wl->last_msc = wl->sync[index].msc;
- int64_t sbc_passed = wl->sync[index].sbc ? wl->sync[index].sbc - wl->last_sbc: 0;
- wl->last_sbc = wl->sync[index].sbc;
if (msc_passed && ust_passed)
wl->vsync_duration = ust_passed / msc_passed;
- if (sbc_passed) {
- struct timespec ts;
- if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
- return;
- }
-
- uint64_t now_monotonic = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
- uint64_t ust_mp_time = mp_time_us() - (now_monotonic - wl->sync[index].ust);
- wl->last_sbc_mp_time = ust_mp_time;
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
+ return;
}
- if (!wl->sync[index].sbc)
- return;
+ uint64_t now_monotonic = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
+ uint64_t ust_mp_time = mp_time_us() - (now_monotonic - wl->sync[index].ust);
- wl->last_queue_display_time = wl->last_sbc_mp_time + sbc_passed*wl->vsync_duration;
+ wl->last_queue_display_time = ust_mp_time + wl->vsync_duration;
}
void vo_wayland_wakeup(struct vo *vo)
diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h
index 7eec7be2d5..27f4f87b0e 100644
--- a/video/out/wayland_common.h
+++ b/video/out/wayland_common.h
@@ -110,14 +110,11 @@ struct vo_wayland_state {
/* Presentation Feedback */
struct vo_wayland_sync *sync;
int sync_size;
- int64_t user_sbc;
int64_t last_ust;
int64_t last_msc;
- int64_t last_sbc;
- int64_t last_sbc_mp_time;
- int64_t vsync_duration;
int64_t last_skipped_vsyncs;
int64_t last_queue_display_time;
+ int64_t vsync_duration;
/* Input */
struct wl_seat *seat;
@@ -154,6 +151,7 @@ void vo_wayland_uninit(struct vo *vo);
void vo_wayland_wakeup(struct vo *vo);
void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us);
void vo_wayland_wait_frame(struct vo_wayland_state *wl);
+void vo_wayland_sync_clear(struct vo_wayland_state *wl);
void wayland_sync_swap(struct vo_wayland_state *wl);
void vo_wayland_sync_shift(struct vo_wayland_state *wl);
void queue_new_sync(struct vo_wayland_state *wl);