mirror of https://github.com/mpv-player/mpv
vo: add support for externally driven renderloop and make wayland use it
Fixes display-sync (though if you change virtual desktops you'll need to seek to re-enable display-sync) partially under wayland. As an advantage, rendering is completely disabled if you change desktops or alt+tab so you lose no performance if you leave mpv running elsewhere as long as it isn't visible. This could also be ported to other VOs which supports it.
This commit is contained in:
parent
713668b99a
commit
a743fef837
|
@ -134,6 +134,8 @@ struct vo_internal {
|
||||||
|
|
||||||
int64_t nominal_vsync_interval;
|
int64_t nominal_vsync_interval;
|
||||||
|
|
||||||
|
bool external_renderloop_drive;
|
||||||
|
|
||||||
int64_t vsync_interval;
|
int64_t vsync_interval;
|
||||||
int64_t *vsync_samples;
|
int64_t *vsync_samples;
|
||||||
int num_vsync_samples;
|
int num_vsync_samples;
|
||||||
|
@ -788,11 +790,12 @@ static void wait_until(struct vo *vo, int64_t target)
|
||||||
pthread_mutex_unlock(&in->lock);
|
pthread_mutex_unlock(&in->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool render_frame(struct vo *vo)
|
bool vo_render_frame_external(struct vo *vo)
|
||||||
{
|
{
|
||||||
struct vo_internal *in = vo->in;
|
struct vo_internal *in = vo->in;
|
||||||
struct vo_frame *frame = NULL;
|
struct vo_frame *frame = NULL;
|
||||||
bool got_frame = false;
|
bool got_frame = false;
|
||||||
|
bool flipped = false;
|
||||||
|
|
||||||
update_display_fps(vo);
|
update_display_fps(vo);
|
||||||
|
|
||||||
|
@ -854,6 +857,7 @@ static bool render_frame(struct vo *vo)
|
||||||
if (in->dropped_frame) {
|
if (in->dropped_frame) {
|
||||||
in->drop_count += 1;
|
in->drop_count += 1;
|
||||||
} else {
|
} else {
|
||||||
|
flipped = true;
|
||||||
in->rendering = true;
|
in->rendering = true;
|
||||||
in->hasframe_rendered = true;
|
in->hasframe_rendered = true;
|
||||||
int64_t prev_drop_count = vo->in->drop_count;
|
int64_t prev_drop_count = vo->in->drop_count;
|
||||||
|
@ -904,6 +908,8 @@ static bool render_frame(struct vo *vo)
|
||||||
done:
|
done:
|
||||||
talloc_free(frame);
|
talloc_free(frame);
|
||||||
pthread_mutex_unlock(&in->lock);
|
pthread_mutex_unlock(&in->lock);
|
||||||
|
if (in->external_renderloop_drive)
|
||||||
|
return flipped;
|
||||||
return got_frame || (in->frame_queued && in->frame_queued->display_synced);
|
return got_frame || (in->frame_queued && in->frame_queued->display_synced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -946,6 +952,44 @@ static void do_redraw(struct vo *vo)
|
||||||
talloc_free(frame);
|
talloc_free(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drop_unrendered_frame(struct vo *vo)
|
||||||
|
{
|
||||||
|
struct vo_internal *in = vo->in;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&in->lock);
|
||||||
|
|
||||||
|
if (!in->frame_queued)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if ((in->frame_queued->pts + in->frame_queued->duration) > mp_time_us())
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
MP_VERBOSE(vo, "Dropping unrendered frame (pts %li)\n", in->frame_queued->pts);
|
||||||
|
|
||||||
|
talloc_free(in->frame_queued);
|
||||||
|
in->frame_queued = NULL;
|
||||||
|
in->hasframe = false;
|
||||||
|
pthread_cond_broadcast(&in->wakeup);
|
||||||
|
wakeup_core(vo);
|
||||||
|
|
||||||
|
end:
|
||||||
|
pthread_mutex_unlock(&in->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vo_enable_external_renderloop(struct vo *vo)
|
||||||
|
{
|
||||||
|
struct vo_internal *in = vo->in;
|
||||||
|
MP_VERBOSE(vo, "Enabling event driven renderloop!\n");
|
||||||
|
in->external_renderloop_drive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vo_disable_external_renderloop(struct vo *vo)
|
||||||
|
{
|
||||||
|
struct vo_internal *in = vo->in;
|
||||||
|
MP_VERBOSE(vo, "Disabling event driven renderloop!\n");
|
||||||
|
in->external_renderloop_drive = false;
|
||||||
|
}
|
||||||
|
|
||||||
static void *vo_thread(void *ptr)
|
static void *vo_thread(void *ptr)
|
||||||
{
|
{
|
||||||
struct vo *vo = ptr;
|
struct vo *vo = ptr;
|
||||||
|
@ -967,7 +1011,11 @@ static void *vo_thread(void *ptr)
|
||||||
if (in->terminate)
|
if (in->terminate)
|
||||||
break;
|
break;
|
||||||
vo->driver->control(vo, VOCTRL_CHECK_EVENTS, NULL);
|
vo->driver->control(vo, VOCTRL_CHECK_EVENTS, NULL);
|
||||||
bool working = render_frame(vo);
|
bool working = false;
|
||||||
|
if (!in->external_renderloop_drive || !in->hasframe_rendered)
|
||||||
|
working = vo_render_frame_external(vo);
|
||||||
|
else
|
||||||
|
drop_unrendered_frame(vo);
|
||||||
int64_t now = mp_time_us();
|
int64_t now = mp_time_us();
|
||||||
int64_t wait_until = now + (working ? 0 : (int64_t)1e9);
|
int64_t wait_until = now + (working ? 0 : (int64_t)1e9);
|
||||||
|
|
||||||
|
@ -980,7 +1028,7 @@ static void *vo_thread(void *ptr)
|
||||||
wakeup_core(vo);
|
wakeup_core(vo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vo->want_redraw && !in->want_redraw) {
|
if (vo->want_redraw) {
|
||||||
vo->want_redraw = false;
|
vo->want_redraw = false;
|
||||||
in->want_redraw = true;
|
in->want_redraw = true;
|
||||||
wakeup_core(vo);
|
wakeup_core(vo);
|
||||||
|
|
|
@ -433,6 +433,9 @@ void vo_query_formats(struct vo *vo, uint8_t *list);
|
||||||
void vo_event(struct vo *vo, int event);
|
void vo_event(struct vo *vo, int event);
|
||||||
int vo_query_and_reset_events(struct vo *vo, int events);
|
int vo_query_and_reset_events(struct vo *vo, int events);
|
||||||
struct mp_image *vo_get_current_frame(struct vo *vo);
|
struct mp_image *vo_get_current_frame(struct vo *vo);
|
||||||
|
void vo_enable_external_renderloop(struct vo *vo);
|
||||||
|
void vo_disable_external_renderloop(struct vo *vo);
|
||||||
|
bool vo_render_frame_external(struct vo *vo);
|
||||||
void vo_set_queue_params(struct vo *vo, int64_t offset_us, int num_req_frames);
|
void vo_set_queue_params(struct vo *vo, int64_t offset_us, int num_req_frames);
|
||||||
int vo_get_num_req_frames(struct vo *vo);
|
int vo_get_num_req_frames(struct vo *vo);
|
||||||
int64_t vo_get_vsync_interval(struct vo *vo);
|
int64_t vo_get_vsync_interval(struct vo *vo);
|
||||||
|
|
|
@ -203,7 +203,7 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
||||||
case VOCTRL_PAUSE:
|
case VOCTRL_PAUSE:
|
||||||
if (gl_video_showing_interpolated_frame(p->renderer))
|
if (gl_video_showing_interpolated_frame(p->renderer))
|
||||||
vo->want_redraw = true;
|
vo->want_redraw = true;
|
||||||
return true;
|
break;
|
||||||
case VOCTRL_PERFORMANCE_DATA:
|
case VOCTRL_PERFORMANCE_DATA:
|
||||||
gl_video_perfdata(p->renderer, (struct voctrl_performance_data *)data);
|
gl_video_perfdata(p->renderer, (struct voctrl_performance_data *)data);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -767,6 +767,9 @@ static void frame_callback(void *data, struct wl_callback *callback, uint32_t ti
|
||||||
|
|
||||||
wl->frame_callback = wl_surface_frame(wl->surface);
|
wl->frame_callback = wl_surface_frame(wl->surface);
|
||||||
wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
|
wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
|
||||||
|
|
||||||
|
if (!vo_render_frame_external(wl->vo))
|
||||||
|
wl_surface_commit(wl->surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_callback_listener frame_listener = {
|
static const struct wl_callback_listener frame_listener = {
|
||||||
|
@ -785,6 +788,7 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
|
||||||
wl->surface = wl_compositor_create_surface(wl->compositor);
|
wl->surface = wl_compositor_create_surface(wl->compositor);
|
||||||
wl->cursor_surface = wl_compositor_create_surface(wl->compositor);
|
wl->cursor_surface = wl_compositor_create_surface(wl->compositor);
|
||||||
wl_surface_add_listener(wl->surface, &surface_listener, wl);
|
wl_surface_add_listener(wl->surface, &surface_listener, wl);
|
||||||
|
vo_enable_external_renderloop(wl->vo);
|
||||||
wl->frame_callback = wl_surface_frame(wl->surface);
|
wl->frame_callback = wl_surface_frame(wl->surface);
|
||||||
wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
|
wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
|
||||||
}
|
}
|
||||||
|
@ -1295,6 +1299,17 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
|
||||||
*(char ***)arg = get_displays_spanned(wl);
|
*(char ***)arg = get_displays_spanned(wl);
|
||||||
return VO_TRUE;
|
return VO_TRUE;
|
||||||
}
|
}
|
||||||
|
case VOCTRL_PAUSE: {
|
||||||
|
wl_callback_destroy(wl->frame_callback);
|
||||||
|
wl->frame_callback = NULL;
|
||||||
|
vo_disable_external_renderloop(wl->vo);
|
||||||
|
return VO_TRUE;
|
||||||
|
}
|
||||||
|
case VOCTRL_RESUME: {
|
||||||
|
vo_enable_external_renderloop(wl->vo);
|
||||||
|
frame_callback(wl, NULL, 0);
|
||||||
|
return VO_TRUE;
|
||||||
|
}
|
||||||
case VOCTRL_GET_UNFS_WINDOW_SIZE: {
|
case VOCTRL_GET_UNFS_WINDOW_SIZE: {
|
||||||
int *s = arg;
|
int *s = arg;
|
||||||
s[0] = mp_rect_w(wl->geometry)*wl->scaling;
|
s[0] = mp_rect_w(wl->geometry)*wl->scaling;
|
||||||
|
|
Loading…
Reference in New Issue