summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRostislav Pehlivanov <atomnuker@gmail.com>2017-12-05 08:26:24 +0000
committerRostislav Pehlivanov <atomnuker@gmail.com>2017-12-05 08:26:24 +0000
commita743fef837bcab206b1e576db7e7a64b02890449 (patch)
tree875105fee109e9e6604af5d117c84e8e883c9375
parent713668b99a201a3ca33780d64bd4072ed966f406 (diff)
downloadmpv-a743fef837bcab206b1e576db7e7a64b02890449.tar.bz2
mpv-a743fef837bcab206b1e576db7e7a64b02890449.tar.xz
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.
-rw-r--r--video/out/vo.c54
-rw-r--r--video/out/vo.h3
-rw-r--r--video/out/vo_gpu.c2
-rw-r--r--video/out/wayland_common.c15
4 files changed, 70 insertions, 4 deletions
diff --git a/video/out/vo.c b/video/out/vo.c
index f195568eaa..8e63be75e6 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -134,6 +134,8 @@ struct vo_internal {
int64_t nominal_vsync_interval;
+ bool external_renderloop_drive;
+
int64_t vsync_interval;
int64_t *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);
}
-static bool render_frame(struct vo *vo)
+bool vo_render_frame_external(struct vo *vo)
{
struct vo_internal *in = vo->in;
struct vo_frame *frame = NULL;
bool got_frame = false;
+ bool flipped = false;
update_display_fps(vo);
@@ -854,6 +857,7 @@ static bool render_frame(struct vo *vo)
if (in->dropped_frame) {
in->drop_count += 1;
} else {
+ flipped = true;
in->rendering = true;
in->hasframe_rendered = true;
int64_t prev_drop_count = vo->in->drop_count;
@@ -904,6 +908,8 @@ static bool render_frame(struct vo *vo)
done:
talloc_free(frame);
pthread_mutex_unlock(&in->lock);
+ if (in->external_renderloop_drive)
+ return flipped;
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);
}
+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)
{
struct vo *vo = ptr;
@@ -967,7 +1011,11 @@ static void *vo_thread(void *ptr)
if (in->terminate)
break;
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 wait_until = now + (working ? 0 : (int64_t)1e9);
@@ -980,7 +1028,7 @@ static void *vo_thread(void *ptr)
wakeup_core(vo);
}
}
- if (vo->want_redraw && !in->want_redraw) {
+ if (vo->want_redraw) {
vo->want_redraw = false;
in->want_redraw = true;
wakeup_core(vo);
diff --git a/video/out/vo.h b/video/out/vo.h
index fc6cf394e4..995d6b97f5 100644
--- a/video/out/vo.h
+++ b/video/out/vo.h
@@ -433,6 +433,9 @@ void vo_query_formats(struct vo *vo, uint8_t *list);
void vo_event(struct vo *vo, int event);
int vo_query_and_reset_events(struct vo *vo, int events);
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);
int vo_get_num_req_frames(struct vo *vo);
int64_t vo_get_vsync_interval(struct vo *vo);
diff --git a/video/out/vo_gpu.c b/video/out/vo_gpu.c
index 6a971dd94b..95318d36df 100644
--- a/video/out/vo_gpu.c
+++ b/video/out/vo_gpu.c
@@ -203,7 +203,7 @@ static int control(struct vo *vo, uint32_t request, void *data)
case VOCTRL_PAUSE:
if (gl_video_showing_interpolated_frame(p->renderer))
vo->want_redraw = true;
- return true;
+ break;
case VOCTRL_PERFORMANCE_DATA:
gl_video_perfdata(p->renderer, (struct voctrl_performance_data *)data);
return true;
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index a0e734703b..19adf01df0 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -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_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 = {
@@ -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->cursor_surface = wl_compositor_create_surface(wl->compositor);
wl_surface_add_listener(wl->surface, &surface_listener, wl);
+ vo_enable_external_renderloop(wl->vo);
wl->frame_callback = wl_surface_frame(wl->surface);
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);
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: {
int *s = arg;
s[0] = mp_rect_w(wl->geometry)*wl->scaling;