diff options
-rw-r--r-- | video/out/opengl/context_wayland.c | 35 | ||||
-rw-r--r-- | video/out/vo_wlshm.c | 34 | ||||
-rw-r--r-- | video/out/vulkan/context.c | 5 | ||||
-rw-r--r-- | video/out/vulkan/context.h | 3 | ||||
-rw-r--r-- | video/out/vulkan/context_wayland.c | 23 | ||||
-rw-r--r-- | video/out/wayland_common.c | 39 | ||||
-rw-r--r-- | video/out/wayland_common.h | 6 |
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); |