diff options
| author | Allusive_ <[email protected]> | 2023-08-01 09:00:18 +1000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-08-01 09:00:18 +1000 |
| commit | 0147e7dd165f837662a480938e2083a5ac707586 (patch) | |
| tree | 3e38624c86c7119703cddb524ac01278491c8a3f /src/vsync.c | |
| parent | Add files via upload (diff) | |
| download | compfy-0147e7dd165f837662a480938e2083a5ac707586.tar.xz compfy-0147e7dd165f837662a480938e2083a5ac707586.zip | |
Add files via upload
Diffstat (limited to 'src/vsync.c')
| -rw-r--r-- | src/vsync.c | 204 |
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; +} |