summaryrefslogtreecommitdiffstats
path: root/video/out
diff options
context:
space:
mode:
Diffstat (limited to 'video/out')
-rw-r--r--video/out/opengl/context_glx.c38
-rw-r--r--video/out/opengl/context_x11egl.c25
-rw-r--r--video/out/opengl/oml_sync.c112
-rw-r--r--video/out/opengl/oml_sync.h28
-rw-r--r--video/out/vo_vaapi.c10
-rw-r--r--video/out/vo_x11.c10
-rw-r--r--video/out/vo_xv.c11
-rw-r--r--video/out/vulkan/context_xlib.c15
-rw-r--r--video/out/x11_common.c33
-rw-r--r--video/out/x11_common.h6
10 files changed, 97 insertions, 191 deletions
diff --git a/video/out/opengl/context_glx.c b/video/out/opengl/context_glx.c
index 6ca9f19d3e..affe7c0f27 100644
--- a/video/out/opengl/context_glx.c
+++ b/video/out/opengl/context_glx.c
@@ -38,9 +38,9 @@
#endif
#include "osdep/timer.h"
+#include "video/out/present_sync.h"
#include "video/out/x11_common.h"
#include "context.h"
-#include "oml_sync.h"
#include "utils.h"
struct priv {
@@ -48,9 +48,6 @@ struct priv {
XVisualInfo *vinfo;
GLXContext context;
GLXFBConfig fbc;
-
- Bool (*XGetSyncValues)(Display*, GLXDrawable, int64_t*, int64_t*, int64_t*);
- struct oml_sync sync;
};
static void glx_uninit(struct ra_ctx *ctx)
@@ -154,14 +151,6 @@ static bool create_context_x11(struct ra_ctx *ctx, GL *gl, bool es)
p->context = context;
mpgl_load_functions(gl, (void *)glXGetProcAddressARB, glxstr, vo->log);
-
- if (gl_check_extension(glxstr, "GLX_OML_sync_control")) {
- p->XGetSyncValues =
- (void *)glXGetProcAddressARB((const GLubyte *)"glXGetSyncValuesOML");
- }
- if (p->XGetSyncValues)
- MP_VERBOSE(vo, "Using GLX_OML_sync_control.\n");
-
return true;
}
@@ -209,20 +198,6 @@ static void set_glx_attrib(int *attribs, int name, int value)
}
}
-static void update_vsync_oml(struct ra_ctx *ctx)
-{
- struct priv *p = ctx->priv;
-
- assert(p->XGetSyncValues);
-
- int64_t ust, msc, sbc;
- if (!p->XGetSyncValues(ctx->vo->x11->display, ctx->vo->x11->window,
- &ust, &msc, &sbc))
- ust = msc = sbc = -1;
-
- oml_sync_swap(&p->sync, ust, msc, sbc);
-}
-
static bool glx_check_visible(struct ra_ctx *ctx)
{
return vo_x11_check_visible(ctx->vo);
@@ -230,18 +205,15 @@ static bool glx_check_visible(struct ra_ctx *ctx)
static void glx_swap_buffers(struct ra_ctx *ctx)
{
- struct priv *p = ctx->priv;
-
glXSwapBuffers(ctx->vo->x11->display, ctx->vo->x11->window);
-
- if (p->XGetSyncValues)
- update_vsync_oml(ctx);
+ vo_x11_present(ctx->vo);
+ present_sync_swap(ctx->vo->x11->present);
}
static void glx_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
{
- struct priv *p = ctx->priv;
- oml_sync_get_info(&p->sync, info);
+ struct vo_x11_state *x11 = ctx->vo->x11;
+ present_sync_get_info(x11->present, info);
}
static bool glx_init(struct ra_ctx *ctx)
diff --git a/video/out/opengl/context_x11egl.c b/video/out/opengl/context_x11egl.c
index 4e0b277da7..549498b435 100644
--- a/video/out/opengl/context_x11egl.c
+++ b/video/out/opengl/context_x11egl.c
@@ -18,14 +18,15 @@
#include <assert.h>
#include <X11/Xlib.h>
+#include <X11/extensions/Xpresent.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "common/common.h"
+#include "video/out/present_sync.h"
#include "video/out/x11_common.h"
#include "context.h"
#include "egl_helpers.h"
-#include "oml_sync.h"
#include "utils.h"
#define EGL_PLATFORM_X11_EXT 0x31D5
@@ -35,10 +36,6 @@ struct priv {
EGLDisplay egl_display;
EGLContext egl_context;
EGLSurface egl_surface;
-
- EGLBoolean (*GetSyncValues)(EGLDisplay, EGLSurface,
- int64_t*, int64_t*, int64_t*);
- struct oml_sync sync;
};
static void mpegl_uninit(struct ra_ctx *ctx)
@@ -83,20 +80,16 @@ static bool mpegl_check_visible(struct ra_ctx *ctx)
static void mpegl_swap_buffers(struct ra_ctx *ctx)
{
struct priv *p = ctx->priv;
- eglSwapBuffers(p->egl_display, p->egl_surface);
-
- int64_t ust, msc, sbc;
- if (!p->GetSyncValues || !p->GetSyncValues(p->egl_display, p->egl_surface,
- &ust, &msc, &sbc))
- ust = msc = sbc = -1;
- oml_sync_swap(&p->sync, ust, msc, sbc);
+ eglSwapBuffers(p->egl_display, p->egl_surface);
+ vo_x11_present(ctx->vo);
+ present_sync_swap(ctx->vo->x11->present);
}
static void mpegl_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
{
- struct priv *p = ctx->priv;
- oml_sync_get_info(&p->sync, info);
+ struct vo_x11_state *x11 = ctx->vo->x11;
+ present_sync_get_info(x11->present, info);
}
static bool mpegl_init(struct ra_ctx *ctx)
@@ -182,10 +175,6 @@ static bool mpegl_init(struct ra_ctx *ctx)
if (!ra_gl_ctx_init(ctx, &p->gl, params))
goto uninit;
- const char *exts = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);
- if (gl_check_extension(exts, "EGL_CHROMIUM_sync_control"))
- p->GetSyncValues = (void *)eglGetProcAddress("eglGetSyncValuesCHROMIUM");
-
ra_add_native_resource(ctx->ra, "x11", vo->x11->display);
return true;
diff --git a/video/out/opengl/oml_sync.c b/video/out/opengl/oml_sync.c
deleted file mode 100644
index 6efd4265d7..0000000000
--- a/video/out/opengl/oml_sync.c
+++ /dev/null
@@ -1,112 +0,0 @@
-#include <time.h>
-
-#include "osdep/timer.h"
-#include "oml_sync.h"
-#include "video/out/vo.h"
-
-// General nonsense about the associated extension.
-//
-// This extension returns two unrelated values:
-// (ust, msc): clock time and incrementing counter of last vsync (this is
-// reported continuously, even if we don't swap)
-// sbc: swap counter of frame that was last displayed (every swap
-// increments the user_sbc, and the reported sbc is the sbc
-// of the frame that was just displayed)
-// Invariants:
-// - ust and msc change in lockstep (no value can change without the other)
-// - msc is incremented; if you query it in a loop, and your thread isn't
-// frozen or starved by the scheduler, it will usually either not change, or
-// be incremented by 1 (while the ust will be incremented by vsync
-// duration)
-// - sbc is never higher than the user_sbc
-// - (ust, msc) are equal to or higher by vsync increments than the display
-// time of the frame referenced by the sbc
-// Note that (ust, msc) and sbc are not locked to each other. The following
-// can easily happen if vsync skips occur:
-// - you draw a frame, in the meantime hardware swaps sbc_1
-// - another display vsync happens during drawing
-// - you call swap()
-// - query (ust, msc) and sbc
-// - sbc contains sbc_1, but (ust, msc) contains the vsync after it
-// As a consequence, it's hard to detect the latency or vsync skips.
-
-static void oml_sync_reset(struct oml_sync *oml)
-{
- oml->vsync_duration = -1;
- oml->last_skipped_vsyncs = -1;
- oml->last_queue_display_time = -1;
-}
-
-void oml_sync_swap(struct oml_sync *oml, int64_t ust, int64_t msc, int64_t sbc)
-{
- if (!oml->state_ok)
- oml_sync_reset(oml);
-
- oml->last_skipped_vsyncs = 0;
- oml->user_sbc += 1;
-
- if (sbc < 0)
- return;
-
- oml->state_ok = true;
-
- int64_t ust_passed = oml->last_ust ? ust - oml->last_ust : 0;
- oml->last_ust = ust;
-
- int64_t msc_passed = oml->last_msc ? msc - oml->last_msc : 0;
- oml->last_msc = msc;
-
- int64_t sbc_passed = sbc - oml->last_sbc;
- oml->last_sbc = sbc;
-
- // Display frame duration. This makes assumptions about UST (see below).
- if (msc_passed && ust_passed)
- oml->vsync_duration = ust_passed / msc_passed;
-
- // Only if a new frame was displayed (sbc increased) we have sort-of a
- // chance that the current (ust, msc) is for the sbc. But this is racy,
- // because skipped frames drops could have increased the msc right after the
- // display event and before we queried the values. This code hopes for the
- // best and ignores this.
- if (sbc_passed) {
- // The GLX extension spec doesn't define what the UST is (not even its
- // unit). Simply assume UST is a simple CLOCK_MONOTONIC usec value. This
- // is what Mesa does, and what the Google EGL extension seems to imply
- // (they mention CLOCK_MONOTONIC, but not the unit).
- // The swap buffer call happened "some" but very small time ago, so we
- // can get away with querying the current time. There is also the
- // implicit assumption that mpv's timer and the UST use the same clock
- // (which it does on POSIX).
- 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 - ust);
-
- // Assume this is exactly when the actual display event for this sbc
- // happened. This is subject to the race mentioned above.
- oml->last_sbc_mp_time = ust_mp_time;
- }
-
- // At least one frame needs to be actually displayed before
- // oml->last_sbc_mp_time is set.
- if (!sbc)
- return;
-
- // Extrapolate from the last sbc time (when a frame was actually displayed),
- // and by adding the number of frames that were queued since to it.
- // For every unit the sbc is smaller than user_sbc, the actual display
- // is one frame ahead (assumes oml_sync_swap() is called for every
- // vsync).
- oml->last_queue_display_time =
- oml->last_sbc_mp_time + (oml->user_sbc - sbc) * oml->vsync_duration;
-}
-
-void oml_sync_get_info(struct oml_sync *oml, struct vo_vsync_info *info)
-{
- if (!oml->state_ok)
- oml_sync_reset(oml);
- info->vsync_duration = oml->vsync_duration;
- info->skipped_vsyncs = oml->last_skipped_vsyncs;
- info->last_queue_display_time = oml->last_queue_display_time;
-}
diff --git a/video/out/opengl/oml_sync.h b/video/out/opengl/oml_sync.h
deleted file mode 100644
index e27ccb943f..0000000000
--- a/video/out/opengl/oml_sync.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-#include <stdint.h>
-
-// Must be initialized to {0} by user.
-struct oml_sync {
- bool state_ok;
- int64_t last_ust;
- int64_t last_msc;
- int64_t last_sbc;
- int64_t last_sbc_mp_time;
- int64_t user_sbc;
- int64_t vsync_duration;
- int64_t last_skipped_vsyncs;
- int64_t last_queue_display_time;
-};
-
-struct vo_vsync_info;
-
-// This must be called on every SwapBuffer call. Pass the ust/msc/sbc values
-// returned by a successful GetSyncValues call. Pass -1 for all these 3 values
-// if GetSyncValues returned failure (but note that you need to set them to -1
-// manually).
-void oml_sync_swap(struct oml_sync *oml, int64_t ust, int64_t msc, int64_t sbc);
-
-// Can be called any time; returns state determined by last oml_sync_swap() call.
-void oml_sync_get_info(struct oml_sync *oml, struct vo_vsync_info *info);
diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c
index fc26135b7a..2766640e6c 100644
--- a/video/out/vo_vaapi.c
+++ b/video/out/vo_vaapi.c
@@ -36,6 +36,7 @@
#include "sub/draw_bmp.h"
#include "sub/img_convert.h"
#include "sub/osd.h"
+#include "present_sync.h"
#include "x11_common.h"
#include "video/mp_image.h"
@@ -553,6 +554,14 @@ static void flip_page(struct vo *vo)
p->visible_surface = p->output_surface;
render_to_screen(p, p->output_surfaces[p->output_surface]);
p->output_surface = (p->output_surface + 1) % MAX_OUTPUT_SURFACES;
+ vo_x11_present(vo);
+ present_sync_swap(vo->x11->present);
+}
+
+static void get_vsync(struct vo *vo, struct vo_vsync_info *info)
+{
+ struct vo_x11_state *x11 = vo->x11;
+ present_sync_get_info(x11->present, info);
}
static void draw_image(struct vo *vo, struct mp_image *mpi)
@@ -851,6 +860,7 @@ const struct vo_driver video_out_vaapi = {
.control = control,
.draw_image = draw_image,
.flip_page = flip_page,
+ .get_vsync = get_vsync,
.wakeup = vo_x11_wakeup,
.wait_events = vo_x11_wait_events,
.uninit = uninit,
diff --git a/video/out/vo_x11.c b/video/out/vo_x11.c
index 6b7a797412..461b05f22a 100644
--- a/video/out/vo_x11.c
+++ b/video/out/vo_x11.c
@@ -34,6 +34,7 @@
#include <errno.h>
+#include "present_sync.h"
#include "x11_common.h"
#include <sys/ipc.h>
@@ -307,6 +308,14 @@ static void flip_page(struct vo *vo)
struct priv *p = vo->priv;
Display_Image(p, p->myximage[p->current_buf]);
p->current_buf = (p->current_buf + 1) % 2;
+ vo_x11_present(vo);
+ present_sync_swap(vo->x11->present);
+}
+
+static void get_vsync(struct vo *vo, struct vo_vsync_info *info)
+{
+ struct vo_x11_state *x11 = vo->x11;
+ present_sync_get_info(x11->present, info);
}
// Note: REDRAW_FRAME can call this with NULL.
@@ -435,6 +444,7 @@ const struct vo_driver video_out_x11 = {
.control = control,
.draw_image = draw_image,
.flip_page = flip_page,
+ .get_vsync = get_vsync,
.wakeup = vo_x11_wakeup,
.wait_events = vo_x11_wait_events,
.uninit = uninit,
diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c
index d93673493f..8fe98839ca 100644
--- a/video/out/vo_xv.c
+++ b/video/out/vo_xv.c
@@ -45,6 +45,7 @@
#include "common/msg.h"
#include "vo.h"
#include "video/mp_image.h"
+#include "present_sync.h"
#include "x11_common.h"
#include "sub/osd.h"
#include "sub/draw_bmp.h"
@@ -689,6 +690,15 @@ static void flip_page(struct vo *vo)
if (!ctx->Shmem_Flag)
XSync(vo->x11->display, False);
+
+ vo_x11_present(vo);
+ present_sync_swap(vo->x11->present);
+}
+
+static void get_vsync(struct vo *vo, struct vo_vsync_info *info)
+{
+ struct vo_x11_state *x11 = vo->x11;
+ present_sync_get_info(x11->present, info);
}
// Note: REDRAW_FRAME can call this with NULL.
@@ -889,6 +899,7 @@ const struct vo_driver video_out_xv = {
.control = control,
.draw_image = draw_image,
.flip_page = flip_page,
+ .get_vsync = get_vsync,
.wakeup = vo_x11_wakeup,
.wait_events = vo_x11_wait_events,
.uninit = uninit,
diff --git a/video/out/vulkan/context_xlib.c b/video/out/vulkan/context_xlib.c
index 2d498723df..3392145e1a 100644
--- a/video/out/vulkan/context_xlib.c
+++ b/video/out/vulkan/context_xlib.c
@@ -16,6 +16,7 @@
*/
#include "video/out/gpu/context.h"
+#include "video/out/present_sync.h"
#include "video/out/x11_common.h"
#include "common.h"
@@ -31,6 +32,18 @@ static bool xlib_check_visible(struct ra_ctx *ctx)
return vo_x11_check_visible(ctx->vo);
}
+static void xlib_vk_swap_buffers(struct ra_ctx *ctx)
+{
+ vo_x11_present(ctx->vo);
+ present_sync_swap(ctx->vo->x11->present);
+}
+
+static void xlib_vk_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
+{
+ struct vo_x11_state *x11 = ctx->vo->x11;
+ present_sync_get_info(x11->present, info);
+}
+
static void xlib_uninit(struct ra_ctx *ctx)
{
struct priv *p = ctx->priv;
@@ -63,6 +76,8 @@ static bool xlib_init(struct ra_ctx *ctx)
struct ra_vk_ctx_params params = {
.check_visible = xlib_check_visible,
+ .swap_buffers = xlib_vk_swap_buffers,
+ .get_vsync = xlib_vk_get_vsync,
};
VkInstance inst = vk->vkinst->instance;
diff --git a/video/out/x11_common.c b/video/out/x11_common.c
index 802af60760..57e1fe6236 100644
--- a/video/out/x11_common.c
+++ b/video/out/x11_common.c
@@ -36,6 +36,7 @@
#include <X11/extensions/scrnsaver.h>
#include <X11/extensions/dpms.h>
#include <X11/extensions/Xinerama.h>
+#include <X11/extensions/Xpresent.h>
#include <X11/extensions/Xrandr.h>
#include "config.h"
@@ -48,6 +49,7 @@
#include "input/event.h"
#include "video/image_loader.h"
#include "video/mp_image.h"
+#include "present_sync.h"
#include "x11_common.h"
#include "mpv_talloc.h"
@@ -593,6 +595,7 @@ int vo_x11_init(struct vo *vo)
x11_error_output = x11->log;
XSetErrorHandler(x11_errorhandler);
+ x11->present = talloc_zero(x11, struct mp_present);
dispName = XDisplayName(NULL);
@@ -1277,6 +1280,21 @@ void vo_x11_check_events(struct vo *vo)
x11->pending_vo_events |= VO_EVENT_ICC_PROFILE_CHANGED;
}
break;
+ case GenericEvent: {
+ XGenericEventCookie *cookie = (XGenericEventCookie *)&Event.xcookie;
+ if (cookie->extension == x11->present_code && x11->have_present &&
+ x11->has_mesa && !x11->has_nvidia)
+ {
+ XGetEventData(x11->display, cookie);
+ if (cookie->evtype == PresentCompleteNotify) {
+ XPresentCompleteNotifyEvent *present_event;
+ present_event = (XPresentCompleteNotifyEvent *)cookie->data;
+ present_update_sync_values(x11->present, present_event->ust,
+ present_event->msc);
+ }
+ }
+ break;
+ }
default:
if (Event.type == x11->ShmCompletionEvent) {
if (x11->ShmCompletionWaitCount > 0)
@@ -1504,6 +1522,14 @@ static void vo_x11_create_window(struct vo *vo, XVisualInfo *vis,
Atom protos[1] = {XA(x11, WM_DELETE_WINDOW)};
XSetWMProtocols(x11->display, x11->window, protos, 1);
+ if (!XPresentQueryExtension(x11->display, &x11->present_code, NULL, NULL)) {
+ MP_VERBOSE(x11, "The XPresent extension is not supported.\n");
+ x11->have_present = false;
+ } else {
+ x11->have_present = true;
+ XPresentSelectInput(x11->display, x11->window, PresentCompleteNotifyMask);
+ }
+
x11->mouse_cursor_set = false;
x11->mouse_cursor_visible = true;
vo_update_cursor(vo);
@@ -2045,6 +2071,13 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg)
return VO_NOTIMPL;
}
+void vo_x11_present(struct vo *vo)
+{
+ struct vo_x11_state *x11 = vo->x11;
+ XPresentNotifyMSC(x11->display, x11->window,
+ 0, 0, 1, 0);
+}
+
void vo_x11_wakeup(struct vo *vo)
{
struct vo_x11_state *x11 = vo->x11;
diff --git a/video/out/x11_common.h b/video/out/x11_common.h
index e9abf51585..e08beca7b0 100644
--- a/video/out/x11_common.h
+++ b/video/out/x11_common.h
@@ -75,6 +75,10 @@ struct vo_x11_state {
bool dpms_touched;
double screensaver_time_last;
+ struct mp_present *present;
+ bool have_present;
+ int present_code;
+
XIM xim;
XIC xic;
bool no_autorepeat;
@@ -147,6 +151,8 @@ bool vo_x11_create_vo_window(struct vo *vo, XVisualInfo *vis,
void vo_x11_config_vo_window(struct vo *vo);
bool vo_x11_check_visible(struct vo *vo);
int vo_x11_control(struct vo *vo, int *events, int request, void *arg);
+void vo_x11_present(struct vo *vo);
+void vo_x11_sync_swap(struct vo *vo);
void vo_x11_wakeup(struct vo *vo);
void vo_x11_wait_events(struct vo *vo, int64_t until_time_us);