vo: allow VOs to request waiting before advancing frames

This is essentially for vo_dmabuf_wayland, but there is a race condition
during initialization where we should wait on an event from the
compositor to set the appropriate description for the image (namely for
color management) before flipping the page. Previously, there was an
off-by-one frame difference which resulted in the initial frame not
being appropriately color managed. Fix this by telling the core render
loop that it is not ready for the next frame. This keeps the frame queue
from advancing and allows the backend to process events appropriately
until it signals that it is ready.
This commit is contained in:
Dudemanguy committed 2026-01-17 04:58:17 +00:00
1 parent 1af136bceb
commit 468d34c9bd
5 files changed
+27 -4

No files matched your search

+10 -1
View File
@@ -138,6 +138,7 @@ struct vo_internal {
bool send_reset; // send VOCTRL_RESET
bool paused;
bool visible;
bool wait_on_vo;
bool wakeup_on_done;
int queued_events; // event mask for the user
int internal_events; // event mask for us
@@ -836,7 +837,7 @@ bool vo_is_ready_for_frame(struct vo *vo, int64_t next_pts)
{
struct vo_internal *in = vo->in;
mp_mutex_lock(&in->lock);
bool r = vo->config_ok && !in->frame_queued &&
bool r = vo->config_ok && !in->wait_on_vo && !in->frame_queued &&
(!in->current_frame || in->current_frame->num_vsyncs < 1);
if (r && next_pts >= 0) {
// Don't show the frame too early - it would basically freeze the
@@ -898,6 +899,14 @@ void vo_wait_frame(struct vo *vo)
mp_mutex_unlock(&in->lock);
}
void vo_wait_on_vo(struct vo *vo, bool wait)
{
struct vo_internal *in = vo->in;
mp_mutex_lock(&in->lock);
in->wait_on_vo = wait;
mp_mutex_unlock(&in->lock);
}
// Wait until realtime is >= ts
// called without lock
static void wait_until(struct vo *vo, int64_t target)
+1
View File
@@ -533,6 +533,7 @@ bool vo_is_ready_for_frame(struct vo *vo, int64_t next_pts);
bool vo_is_visible(struct vo *vo);
void vo_queue_frame(struct vo *vo, struct vo_frame *frame);
void vo_wait_frame(struct vo *vo);
void vo_wait_on_vo(struct vo *vo, bool wait);
bool vo_still_displaying(struct vo *vo);
void vo_request_wakeup_on_done(struct vo *vo);
bool vo_has_frame(struct vo *vo);
+12 -3
View File
@@ -103,6 +103,7 @@ struct priv {
bool destroy_buffers;
bool force_window;
bool vo_is_waiting;
enum hwdec_type hwdec_type;
struct mp_image_params target_params;
@@ -626,6 +627,11 @@ static bool draw_frame(struct vo *vo, struct vo_frame *frame)
wl_surface_damage_buffer(wl->video_surface, 0, 0, 1, 1);
}
if (wl->color_surface && (!wl->image_description_processed || p->vo_is_waiting)) {
vo_wait_on_vo(vo, !wl->image_description_processed);
p->vo_is_waiting = !wl->image_description_processed;
}
pts = frame->current ? frame->current->pts : 0;
if (frame->current) {
buf = buffer_get(vo, frame);
@@ -660,10 +666,13 @@ static bool draw_frame(struct vo *vo, struct vo_frame *frame)
static void flip_page(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wl;
struct priv *p = vo->priv;
wl_surface_commit(wl->osd_surface);
wl_surface_commit(wl->video_surface);
wl_surface_commit(wl->surface);
if (!p->vo_is_waiting) {
wl_surface_commit(wl->osd_surface);
wl_surface_commit(wl->video_surface);
wl_surface_commit(wl->surface);
}
if (wl->opts->wl_internal_vsync)
vo_wayland_wait_frame(wl);
+3
View File
@@ -2108,6 +2108,7 @@ static void image_description_failed(void *data, struct wp_image_description_v1
MP_VERBOSE(wl, "Image description failed: %d, %s\n", cause, msg);
wp_color_management_surface_v1_unset_image_description(wl->color_surface);
wp_image_description_v1_destroy(image_description);
wl->image_description_processed = true;
}
static void image_description_ready2(void *data, struct wp_image_description_v1 *image_description,
@@ -2118,6 +2119,7 @@ static void image_description_ready2(void *data, struct wp_image_description_v1
WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL);
MP_TRACE(wl, "Image description set on color surface.\n");
wp_image_description_v1_destroy(image_description);
wl->image_description_processed = true;
}
static void image_description_ready(void *data, struct wp_image_description_v1 *image_description,
@@ -3538,6 +3540,7 @@ static void set_color_management(struct vo_wayland_state *wl)
wp_image_description_creator_params_v1_set_max_fall(image_creator_params, lrintf(hdr.max_fall));
}
struct wp_image_description_v1 *image_description = wp_image_description_creator_params_v1_create(image_creator_params);
wl->image_description_processed = false;
wp_image_description_v1_add_listener(image_description, &image_description_listener, wl);
#endif
}
+1
View File
@@ -95,6 +95,7 @@ struct vo_wayland_state {
struct wp_color_management_surface_feedback_v1 *color_surface_feedback;
struct wp_image_description_creator_icc_v1 *icc_creator;
struct mp_image_params target_params;
bool image_description_processed;
bool supports_parametric;
bool supports_display_primaries;
int primaries_map[PL_COLOR_PRIM_COUNT];