-
-
Save jonathan-daniel/9440228 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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 :*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello: Can this code really change the FPS. I use vsync for video playback, and try to synchronize it with the timeline;