aboutsummaryrefslogtreecommitdiff
path: root/src/vsync.c
diff options
context:
space:
mode:
authorAllusive_ <[email protected]>2023-08-01 09:00:18 +1000
committerGitHub <[email protected]>2023-08-01 09:00:18 +1000
commit0147e7dd165f837662a480938e2083a5ac707586 (patch)
tree3e38624c86c7119703cddb524ac01278491c8a3f /src/vsync.c
parentAdd files via upload (diff)
downloadcompfy-0147e7dd165f837662a480938e2083a5ac707586.tar.xz
compfy-0147e7dd165f837662a480938e2083a5ac707586.zip
Add files via upload
Diffstat (limited to 'src/vsync.c')
-rw-r--r--src/vsync.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/vsync.c b/src/vsync.c
new file mode 100644
index 0000000..5980155
--- /dev/null
+++ b/src/vsync.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: MPL-2.0
+// Copyright (c) Yuxuan Shui <[email protected]>
+
+/// Function pointers to init VSync modes.
+
+#include "common.h"
+#include "log.h"
+
+#ifdef CONFIG_OPENGL
+#include "backend/gl/glx.h"
+#include "opengl.h"
+#endif
+
+#ifdef CONFIG_VSYNC_DRM
+#include <drm.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+#include "config.h"
+#include "vsync.h"
+
+#ifdef CONFIG_VSYNC_DRM
+/**
+ * Wait for next VSync, DRM method.
+ *
+ * Stolen from:
+ * https://github.com/MythTV/mythtv/blob/master/mythtv/libs/libmythtv/vsync.cpp
+ */
+static int vsync_drm_wait(session_t *ps) {
+ int ret = -1;
+ drm_wait_vblank_t vbl;
+
+ vbl.request.type = _DRM_VBLANK_RELATIVE, vbl.request.sequence = 1;
+
+ do {
+ ret = ioctl(ps->drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl);
+ vbl.request.type &= ~(uint)_DRM_VBLANK_RELATIVE;
+ } while (ret && errno == EINTR);
+
+ if (ret)
+ log_error("VBlank ioctl did not work, unimplemented in this drmver?");
+
+ return ret;
+}
+
+/**
+ * Initialize DRM VSync.
+ *
+ * @return true for success, false otherwise
+ */
+static bool vsync_drm_init(session_t *ps) {
+ // Should we always open card0?
+ if (ps->drm_fd < 0 && (ps->drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) {
+ log_error("Failed to open device.");
+ return false;
+ }
+
+ if (vsync_drm_wait(ps))
+ return false;
+
+ return true;
+}
+#endif
+
+#ifdef CONFIG_OPENGL
+/**
+ * Initialize OpenGL VSync.
+ *
+ * Stolen from:
+ * http://git.tuxfamily.org/?p=ccm/cairocompmgr.git;a=commitdiff;h=efa4ceb97da501e8630ca7f12c99b1dce853c73e
+ * Possible original source: http://www.inb.uni-luebeck.de/~boehme/xvideo_sync.html
+ *
+ * @return true for success, false otherwise
+ */
+static bool vsync_opengl_init(session_t *ps) {
+ if (!ensure_glx_context(ps))
+ return false;
+
+ return glxext.has_GLX_SGI_video_sync;
+}
+
+static bool vsync_opengl_oml_init(session_t *ps) {
+ if (!ensure_glx_context(ps))
+ return false;
+
+ return glxext.has_GLX_OML_sync_control;
+}
+
+static inline bool vsync_opengl_swc_swap_interval(session_t *ps, int interval) {
+ if (glxext.has_GLX_MESA_swap_control)
+ return glXSwapIntervalMESA((uint)interval) == 0;
+ else if (glxext.has_GLX_SGI_swap_control)
+ return glXSwapIntervalSGI(interval) == 0;
+ else if (glxext.has_GLX_EXT_swap_control) {
+ GLXDrawable d = glXGetCurrentDrawable();
+ if (d == None) {
+ // We don't have a context??
+ return false;
+ }
+ glXSwapIntervalEXT(ps->dpy, glXGetCurrentDrawable(), interval);
+ return true;
+ }
+ return false;
+}
+
+static bool vsync_opengl_swc_init(session_t *ps) {
+ if (!bkend_use_glx(ps)) {
+ log_error("OpenGL swap control requires the GLX backend.");
+ return false;
+ }
+
+ if (!vsync_opengl_swc_swap_interval(ps, 1)) {
+ log_error("Failed to load a swap control extension.");
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Wait for next VSync, OpenGL method.
+ */
+static int vsync_opengl_wait(session_t *ps attr_unused) {
+ unsigned vblank_count = 0;
+
+ glXGetVideoSyncSGI(&vblank_count);
+ glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count);
+ return 0;
+}
+
+/**
+ * Wait for next VSync, OpenGL OML method.
+ *
+ * https://mail.gnome.org/archives/clutter-list/2012-November/msg00031.html
+ */
+static int vsync_opengl_oml_wait(session_t *ps) {
+ int64_t ust = 0, msc = 0, sbc = 0;
+
+ glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc);
+ glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc);
+ return 0;
+}
+#endif
+
+/**
+ * Initialize current VSync method.
+ */
+bool vsync_init(session_t *ps) {
+#ifdef CONFIG_OPENGL
+ if (bkend_use_glx(ps)) {
+ // Mesa turns on swap control by default, undo that
+ vsync_opengl_swc_swap_interval(ps, 0);
+ }
+#endif
+#ifdef CONFIG_VSYNC_DRM
+ log_warn("The DRM vsync method is deprecated, please don't enable it.");
+#endif
+
+ if (!ps->o.vsync) {
+ return true;
+ }
+
+#ifdef CONFIG_OPENGL
+ if (bkend_use_glx(ps)) {
+ if (!vsync_opengl_swc_init(ps)) {
+ return false;
+ }
+ ps->vsync_wait = NULL; // glXSwapBuffers will automatically wait
+ // for vsync, we don't need to do anything.
+ return true;
+ }
+#endif
+
+ // Oh no, we are not using glx backend.
+ // Throwing things at wall.
+#ifdef CONFIG_OPENGL
+ if (vsync_opengl_oml_init(ps)) {
+ log_info("Using the opengl-oml vsync method");
+ ps->vsync_wait = vsync_opengl_oml_wait;
+ return true;
+ }
+
+ if (vsync_opengl_init(ps)) {
+ log_info("Using the opengl vsync method");
+ ps->vsync_wait = vsync_opengl_wait;
+ return true;
+ }
+#endif
+
+#ifdef CONFIG_VSYNC_DRM
+ if (vsync_drm_init(ps)) {
+ log_info("Using the drm vsync method");
+ ps->vsync_wait = vsync_drm_wait;
+ return true;
+ }
+#endif
+
+ log_error("No supported vsync method found for this backend");
+ return false;
+}