Skip to content

Instantly share code, notes, and snippets.

@jonathan-daniel
Forked from Cloudef/glvsync.c
Created March 8, 2014 22:52
Show Gist options
  • Save jonathan-daniel/9440228 to your computer and use it in GitHub Desktop.
Save jonathan-daniel/9440228 to your computer and use it in GitHub Desktop.
/* gcc -std=c99 -fPIC -shared -Wl,-soname,glvsync.so glvsync.c -o glvsync.so
* gcc -m32 -std=c99 -fPIC -shared -Wl,-soname,glvsync.so glvsync.c -o glvsync.so (for 32bit)
*
* Force VSYNC interval on OpenGL applications
* Usage: LD_PRELOAD="/path/to/glvsync.so" ./program
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <GL/glx.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static int SYNC_INTERVAL = 2; // 30 FPS @ 60hz (override with _GLVSYNC_INTERVAL env variable)
extern void *_dl_sym(void*, const char*, void*);
static int (*_glXSwapIntervalEXT)(Display*, GLXDrawable, int interval) = NULL;
static int (*_glXSwapIntervalSGI)(unsigned int interval) = NULL;
static int (*_glXSwapIntervalMESA)(unsigned int interval) = NULL;
static void (*_glXSwapBuffers)(Display*, GLXDrawable) = NULL;
static void* (*_glXGetProcAddress)(const GLubyte*) = NULL;
static void* (*_glXGetProcAddressARB)(const GLubyte*) = NULL;
static void* (*_glXGetProcAddressEXT)(const GLubyte*) = NULL;
int glXSwapIntervalEXT(Display *dpy, GLXDrawable drawable, int interval)
{
(void)interval;
if (!_glXSwapIntervalEXT) _glXSwapIntervalEXT = _dl_sym(RTLD_NEXT, __FUNCTION__, glXSwapIntervalEXT);
return _glXSwapIntervalEXT(dpy, drawable, SYNC_INTERVAL);
}
int glXSwapIntervalSGI(unsigned int interval)
{
(void)interval;
if (!_glXSwapIntervalSGI) _glXSwapIntervalSGI = _dl_sym(RTLD_NEXT, __FUNCTION__, glXSwapIntervalSGI);
return _glXSwapIntervalSGI(SYNC_INTERVAL);
}
int glXSwapIntervalMESA(unsigned int interval)
{
(void)interval;
if (!_glXSwapIntervalMESA) _glXSwapIntervalMESA = _dl_sym(RTLD_NEXT, __FUNCTION__, glXSwapIntervalMESA);
return _glXSwapIntervalMESA(SYNC_INTERVAL);
}
static __GLXextFuncPtr hookedProc(const GLubyte *procname, __GLXextFuncPtr ret)
{
if (!strcmp((const char*)procname, "glXSwapIntervalEXT")) {
printf("--- HOOK GLXSWAPINTERVALEXT\n");
_glXSwapIntervalEXT = (void*)ret;
return (__GLXextFuncPtr)_glXSwapIntervalEXT;
} else if (!strcmp((const char*)procname, "glXSwapIntervalSGI")) {
printf("--- HOOK GLXSWAPINTERVALSGI\n");
_glXSwapIntervalSGI = (void*)ret;
return (__GLXextFuncPtr)glXSwapIntervalSGI;
} else if (!strcmp((const char*)procname, "glXSwapIntervalMESA")) {
printf("--- HOOK GLXSWAPINTERVALMESA\n");
_glXSwapIntervalMESA = (void*)ret;
return (__GLXextFuncPtr)glXSwapIntervalMESA;
}
return ret;
}
__GLXextFuncPtr glXGetProcAddressEXT(const GLubyte *procname)
{
__GLXextFuncPtr ret = NULL;
if (!_glXGetProcAddressEXT) _glXGetProcAddressEXT = _dl_sym(RTLD_NEXT, __FUNCTION__, glXGetProcAddressEXT);
if (!(ret = _glXGetProcAddressEXT(procname))) return ret;
return hookedProc(procname, ret);
}
__GLXextFuncPtr glXGetProcAddressARB(const GLubyte *procname)
{
__GLXextFuncPtr ret = NULL;
if (!_glXGetProcAddressARB) _glXGetProcAddressARB = _dl_sym(RTLD_NEXT, __FUNCTION__, glXGetProcAddressARB);
if (!(ret = _glXGetProcAddressARB(procname))) return ret;
return hookedProc(procname, ret);
}
__GLXextFuncPtr glXGetProcAddress(const GLubyte *procname)
{
__GLXextFuncPtr ret = NULL;
if (!_glXGetProcAddress) _glXGetProcAddress = _dl_sym(RTLD_NEXT, __FUNCTION__, glXGetProcAddress);
if (!(ret = _glXGetProcAddress(procname))) return ret;
return hookedProc(procname, ret);
}
void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
{
static int once = 0;
static int counter = 0;
if (!_glXSwapBuffers) _glXSwapBuffers = _dl_sym(RTLD_NEXT, __FUNCTION__, glXSwapBuffers);
if (!once) {
const char *swap = getenv("_GLVSYNC_INTERVAL");
if (swap) SYNC_INTERVAL = strtol(swap, NULL, 10);
}
if (_glXSwapIntervalEXT) {
if (!once) printf("--- FORCE SWAP (EXT)\n");
_glXSwapIntervalEXT(dpy, drawable, SYNC_INTERVAL);
} else if (_glXSwapIntervalSGI) {
if (!once) printf("--- FORCE SWAP (SGI)\n");
_glXSwapIntervalSGI(SYNC_INTERVAL);
} else if (_glXSwapIntervalMESA) {
if (!once) printf("--- FORCE SWAP (MESA)\n");
_glXSwapIntervalMESA(SYNC_INTERVAL);
}
_glXSwapBuffers(dpy, drawable);
once = 1;
}
void *dlsym(void *handle, const char *symbol)
{
void *ret = NULL;
if (symbol && !strcmp(symbol, "dlsym")) return dlsym;
if (!(ret = _dl_sym(handle, symbol, dlsym))) return ret;
if (!strcmp(symbol, "glXGetProcAddressARB")) {
printf("--- HOOK GLXGETPROCADDRESSARB\n");
_glXGetProcAddressARB = ret;
return glXGetProcAddressARB;
} else if (!strcmp(symbol, "glXGetProcAddress")) {
printf("--- HOOK GLXGETPROCADDRESS\n");
_glXGetProcAddress = ret;
return glXGetProcAddress;
} else if (!strcmp(symbol, "glXGetProcAddressEXT")) {
printf("--- HOOK GLXGETPROCADDRESSEXT\n");
_glXGetProcAddressEXT = ret;
return glXGetProcAddressEXT;
} else if (!strcmp(symbol, "glXSwapBuffers")) {
printf("--- HOOK GLXSWAPBUFFERS\n");
_glXSwapBuffers = ret;
return glXSwapBuffers;
} else if (!strcmp(symbol, "glXSwapIntervalEXT")) {
printf("--- HOOK GLXSWAPINTERVALEXT\n");
_glXSwapIntervalEXT = ret;
return _glXSwapIntervalEXT;
} else if (!strcmp(symbol, "glXSwapIntervalSGI")) {
printf("--- HOOK GLXSWAPINTERVALSGI\n");
_glXSwapIntervalSGI = ret;
return _glXSwapIntervalSGI;
} else if (!strcmp(symbol, "glXSwapIntervalMESA")) {
printf("--- HOOK GLXSWAPINTERVALMESA\n");
_glXSwapIntervalMESA = ret;
return _glXSwapIntervalMESA;
}
return ret;
}
/* vim: set ts=8 sw=3 tw=0 :*/
@xuandu
Copy link

xuandu commented Nov 22, 2022

Hello: Can this code really change the FPS. I use vsync for video playback, and try to synchronize it with the timeline;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment