@@ -11,144 +11,135 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <err.h>
static int SYNC_INTERVAL = 2 ; // 30 FPS @ 60hz (override with _GLVSYNC_INTERVAL env variable)
static int SYNC_INTERVAL = 1 ; // 60 FPS @ 60Hz (override with _GLVSYNC_INTERVAL env variable)
// e.g. 2 would be 30 FPS @ 60Hz
extern void * _dl_sym (void * , const char * , void * );
static void * (* _dlsym )(void * , const char * ) = NULL ;
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 ;
static void * store_real_symbol_and_return_fake_symbol (const char * symbol , void * ret );
#define HOOK_DLSYM (x , y ) if (!x) { if ((x = _dl_sym(RTLD_NEXT, __func__, y))) warnx("glvsync: HOOK dlsym"); }
#define HOOK (x ) if (!x) if ((x = _dlsym(RTLD_NEXT, __func__))) { warnx("glvsync: HOOK %s", __func__); }
#define SET_IF_NOT_HOOKED (x , y ) if (!x) { x = y; warnx("glvsync: SET %s", #x); }
#define WARN_ONCE (x , ...) do { static bool o = false; if (!o) { warnx(x, ##__VA_ARGS__); o = true; } } while (0)
static int get_interval (void )
{
static const char * swap ;
if (!swap && (swap = getenv ("_GLVSYNC_INTERVAL" )))
SYNC_INTERVAL = strtol (swap , NULL , 10 );
return SYNC_INTERVAL ;
}
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 );
HOOK (_glXSwapIntervalEXT );
if (_glXSwapIntervalEXT ) WARN_ONCE ("glvsync: FORCE SWAP (EXT)" );
return (_glXSwapIntervalEXT ? _glXSwapIntervalEXT (dpy , drawable , get_interval ()) : 0 );
}
int glXSwapIntervalSGI (unsigned int interval )
{
(void )interval ;
if (!_glXSwapIntervalSGI ) _glXSwapIntervalSGI = _dl_sym (RTLD_NEXT , __FUNCTION__ , glXSwapIntervalSGI );
return _glXSwapIntervalSGI (SYNC_INTERVAL );
HOOK (_glXSwapIntervalSGI );
if (_glXSwapIntervalSGI ) WARN_ONCE ("glvsync: FORCE SWAP (SGI)" );
return (_glXSwapIntervalSGI ? _glXSwapIntervalSGI (get_interval ()) : 0 );
}
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 ;
HOOK (_glXSwapIntervalMESA );
if (_glXSwapIntervalMESA ) WARN_ONCE ("glvsync: FORCE SWAP (MESA)" );
return (_glXSwapIntervalMESA ? _glXSwapIntervalMESA (get_interval ()) : 0 );
}
__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 );
HOOK (_glXGetProcAddressEXT );
return (_glXGetProcAddressEXT ? store_real_symbol_and_return_fake_symbol (procname , _glXGetProcAddressEXT (procname )) : NULL );
}
__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 );
HOOK (_glXGetProcAddressARB );
return (_glXGetProcAddressARB ? store_real_symbol_and_return_fake_symbol (procname , _glXGetProcAddressARB (procname )) : NULL );
}
__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 );
HOOK (_glXGetProcAddress );
return (_glXGetProcAddress ? store_real_symbol_and_return_fake_symbol (procname , _glXGetProcAddress (procname )) : NULL );
}
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 );
HOOK (_glXSwapBuffers );
{
static bool once = false;
if (!once ) {
warnx ("glvsync: INITIAL SWAP" );
glXSwapIntervalEXT (dpy , drawable , 0 );
glXSwapIntervalSGI (0 );
glXSwapIntervalMESA (0 );
once = true;
}
}
_glXSwapBuffers (dpy , drawable );
once = 1 ;
}
void * dlsym ( void * handle , const char * symbol )
void * store_real_symbol_and_return_fake_symbol ( const char * symbol , void * ret )
{
void * ret = NULL ;
if (symbol && !strcmp (symbol , "dlsym" )) return dlsym ;
if (!(ret = _dl_sym (handle , symbol , dlsym ))) return ret ;
if (!ret || !symbol )
return ret ;
if (!strcmp (symbol , "glXGetProcAddressARB" )) {
printf ("--- HOOK GLXGETPROCADDRESSARB\n" );
_glXGetProcAddressARB = ret ;
if (!strcmp (symbol , "glXSwapIntervalEXT" )) {
SET_IF_NOT_HOOKED (_glXSwapIntervalEXT , ret );
return glXSwapIntervalEXT ;
} else if (!strcmp (symbol , "glXSwapIntervalSGI" )) {
SET_IF_NOT_HOOKED (_glXSwapIntervalSGI , ret );
return glXSwapIntervalSGI ;
} else if (!strcmp (symbol , "glXSwapIntervalMESA" )) {
SET_IF_NOT_HOOKED (_glXSwapIntervalMESA , ret );
return glXSwapIntervalMESA ;
} else if (!strcmp (symbol , "glXGetProcAddressEXT" )) {
SET_IF_NOT_HOOKED (_glXGetProcAddressEXT , ret );
return glXGetProcAddressEXT ;
} else if (!strcmp (symbol , "glXGetProcAddressARB" )) {
SET_IF_NOT_HOOKED (_glXGetProcAddressARB , ret );
return glXGetProcAddressARB ;
} else if (!strcmp (symbol , "glXGetProcAddress" )) {
printf ("--- HOOK GLXGETPROCADDRESS\n" );
_glXGetProcAddress = ret ;
SET_IF_NOT_HOOKED (_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 ;
SET_IF_NOT_HOOKED (_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 :*/
void * dlsym (void * handle , const char * symbol )
{
HOOK_DLSYM (_dlsym , dlsym );
if (symbol && !strcmp (symbol , "dlsym" ))
return dlsym ;
return store_real_symbol_and_return_fake_symbol (symbol , _dlsym (handle , symbol ));
}