Export GLX functions we don't intercept as pass-through functions

This commit is contained in:
baldurk
2016-11-19 15:13:55 +01:00
parent 0a4f79ce8d
commit 512906c104
6 changed files with 233 additions and 134 deletions
+1
View File
@@ -47,6 +47,7 @@ elseif(APPLE)
elseif(UNIX)
list(APPEND sources
gl_replay_linux.cpp
glx_hooks_linux.cpp
gl_hooks_linux.cpp)
endif()
+65 -132
View File
@@ -54,9 +54,6 @@ typedef XVisualInfo *(*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display *dpy, GLXFBConfi
typedef int (*PFNGLXGETCONFIGPROC)(Display *dpy, XVisualInfo *vis, int attrib, int *value);
typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display *dpy, int *errorBase, int *eventBase);
typedef Bool (*PFNGLXISDIRECTPROC)(Display *dpy, GLXContext ctx);
typedef const char *(*PFNGLXGETCLIENTSTRINGPROC)(Display *dpy, int name);
typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display *dpy, int *maj, int *min);
typedef const char *(*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display *dpy, int screen);
void *libGLdlsymHandle =
RTLD_NEXT; // default to RTLD_NEXT, but overwritten if app calls dlopen() on real libGL
@@ -544,17 +541,10 @@ public:
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB_real;
PFNGLXGETPROCADDRESSPROC glXGetProcAddress_real;
PFNGLXMAKECURRENTPROC glXMakeCurrent_real;
PFNGLXMAKECONTEXTCURRENTPROC glXMakeContextCurrent_real;
PFNGLXSWAPBUFFERSPROC glXSwapBuffers_real;
PFNGLXGETCONFIGPROC glXGetConfig_real;
PFNGLXGETVISUALFROMFBCONFIGPROC glXGetVisualFromFBConfig_real;
PFNGLXQUERYEXTENSIONPROC glXQueryExtension_real;
PFNGLXGETFBCONFIGSPROC glXGetFBConfigs_real;
PFNGLXGETFBCONFIGATTRIBPROC glXGetFBConfigAttrib_real;
PFNGLXGETCLIENTSTRINGPROC glXGetClientString_real;
PFNGLXQUERYVERSIONPROC glXQueryVersion_real;
PFNGLXQUERYEXTENSIONSSTRINGPROC glXQueryExtensionsString_real;
PFNGLXCREATENEWCONTEXTPROC glXCreateNewContext_real;
PFNGLXCREATEWINDOWPROC glXCreateWindow_real;
PFNGLXDESTROYWINDOWPROC glXDestroyWindow_real;
@@ -570,7 +560,41 @@ public:
bool m_HasHooks;
bool m_EnabledHooks;
bool SetupHooks(GLHookSet &GL);
bool SetupHooks(GLHookSet &GL)
{
bool success = true;
if(glXGetProcAddress_real == NULL)
glXGetProcAddress_real =
(PFNGLXGETPROCADDRESSPROC)dlsym(libGLdlsymHandle, "glXGetProcAddress");
if(glXCreateContext_real == NULL)
glXCreateContext_real = (PFNGLXCREATECONTEXTPROC)dlsym(libGLdlsymHandle, "glXCreateContext");
if(glXDestroyContext_real == NULL)
glXDestroyContext_real =
(PFNGLXDESTROYCONTEXTPROC)dlsym(libGLdlsymHandle, "glXDestroyContext");
if(glXCreateContextAttribsARB_real == NULL)
glXCreateContextAttribsARB_real =
(PFNGLXCREATECONTEXTATTRIBSARBPROC)dlsym(libGLdlsymHandle, "glXCreateContextAttribsARB");
if(glXMakeCurrent_real == NULL)
glXMakeCurrent_real = (PFNGLXMAKECURRENTPROC)dlsym(libGLdlsymHandle, "glXMakeCurrent");
if(glXMakeContextCurrent_real == NULL)
glXMakeContextCurrent_real =
(PFNGLXMAKECONTEXTCURRENTPROC)dlsym(libGLdlsymHandle, "glXMakeContextCurrent");
if(glXSwapBuffers_real == NULL)
glXSwapBuffers_real = (PFNGLXSWAPBUFFERSPROC)dlsym(libGLdlsymHandle, "glXSwapBuffers");
if(glXGetConfig_real == NULL)
glXGetConfig_real = (PFNGLXGETCONFIGPROC)dlsym(libGLdlsymHandle, "glXGetConfig");
if(glXGetVisualFromFBConfig_real == NULL)
glXGetVisualFromFBConfig_real =
(PFNGLXGETVISUALFROMFBCONFIGPROC)dlsym(libGLdlsymHandle, "glXGetVisualFromFBConfig");
if(glXCreateWindow_real == NULL)
glXCreateWindow_real = (PFNGLXCREATEWINDOWPROC)dlsym(libGLdlsymHandle, "glXCreateWindow");
if(glXDestroyWindow_real == NULL)
glXDestroyWindow_real = (PFNGLXDESTROYWINDOWPROC)dlsym(libGLdlsymHandle, "glXDestroyWindow");
return success;
}
bool PopulateHooks();
};
@@ -875,6 +899,9 @@ DefineGLExtensionHooks();
DefineUnsupportedDummies();
// everything below here needs to have C linkage
extern "C" {
__attribute__((visibility("default"))) GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis,
GLXContext shareList, Bool direct)
{
@@ -1060,6 +1087,31 @@ __attribute__((visibility("default"))) Bool glXMakeCurrent(Display *dpy, GLXDraw
return ret;
}
__attribute__((visibility("default"))) Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw,
GLXDrawable read, GLXContext ctx)
{
if(OpenGLHook::glhooks.glXMakeContextCurrent_real == NULL)
OpenGLHook::glhooks.SetupExportedFunctions();
Bool ret = OpenGLHook::glhooks.glXMakeContextCurrent_real(dpy, draw, read, ctx);
if(ctx && OpenGLHook::glhooks.m_Contexts.find(ctx) == OpenGLHook::glhooks.m_Contexts.end())
{
OpenGLHook::glhooks.m_Contexts.insert(ctx);
OpenGLHook::glhooks.PopulateHooks();
}
GLWindowingData data;
data.dpy = dpy;
data.wnd = draw;
data.ctx = ctx;
OpenGLHook::glhooks.GetDriver()->ActivateContext(data);
return ret;
}
__attribute__((visibility("default"))) void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
{
if(OpenGLHook::glhooks.glXSwapBuffers_real == NULL)
@@ -1087,54 +1139,6 @@ __attribute__((visibility("default"))) void glXSwapBuffers(Display *dpy, GLXDraw
OpenGLHook::glhooks.glXSwapBuffers_real(dpy, drawable);
}
bool OpenGLHook::SetupHooks(GLHookSet &GL)
{
bool success = true;
if(glXGetProcAddress_real == NULL)
glXGetProcAddress_real = (PFNGLXGETPROCADDRESSPROC)dlsym(libGLdlsymHandle, "glXGetProcAddress");
if(glXCreateContext_real == NULL)
glXCreateContext_real = (PFNGLXCREATECONTEXTPROC)dlsym(libGLdlsymHandle, "glXCreateContext");
if(glXDestroyContext_real == NULL)
glXDestroyContext_real = (PFNGLXDESTROYCONTEXTPROC)dlsym(libGLdlsymHandle, "glXDestroyContext");
if(glXCreateContextAttribsARB_real == NULL)
glXCreateContextAttribsARB_real =
(PFNGLXCREATECONTEXTATTRIBSARBPROC)dlsym(libGLdlsymHandle, "glXCreateContextAttribsARB");
if(glXMakeCurrent_real == NULL)
glXMakeCurrent_real = (PFNGLXMAKECURRENTPROC)dlsym(libGLdlsymHandle, "glXMakeCurrent");
if(glXSwapBuffers_real == NULL)
glXSwapBuffers_real = (PFNGLXSWAPBUFFERSPROC)dlsym(libGLdlsymHandle, "glXSwapBuffers");
if(glXGetConfig_real == NULL)
glXGetConfig_real = (PFNGLXGETCONFIGPROC)dlsym(libGLdlsymHandle, "glXGetConfig");
if(glXGetVisualFromFBConfig_real == NULL)
glXGetVisualFromFBConfig_real =
(PFNGLXGETVISUALFROMFBCONFIGPROC)dlsym(libGLdlsymHandle, "glXGetVisualFromFBConfig");
if(glXQueryExtension_real == NULL)
glXQueryExtension_real = (PFNGLXQUERYEXTENSIONPROC)dlsym(libGLdlsymHandle, "glXQueryExtension");
if(glXGetFBConfigs_real == NULL)
glXGetFBConfigs_real = (PFNGLXGETFBCONFIGSPROC)dlsym(libGLdlsymHandle, "glXGetFBConfigs");
if(glXGetFBConfigAttrib_real == NULL)
glXGetFBConfigAttrib_real =
(PFNGLXGETFBCONFIGATTRIBPROC)dlsym(libGLdlsymHandle, "glXGetFBConfigAttrib");
if(glXGetClientString_real == NULL)
glXGetClientString_real =
(PFNGLXGETCLIENTSTRINGPROC)dlsym(libGLdlsymHandle, "glXGetClientString");
if(glXQueryVersion_real == NULL)
glXQueryVersion_real = (PFNGLXQUERYVERSIONPROC)dlsym(libGLdlsymHandle, "glXQueryVersion");
if(glXQueryExtensionsString_real == NULL)
glXQueryExtensionsString_real =
(PFNGLXQUERYEXTENSIONSSTRINGPROC)dlsym(libGLdlsymHandle, "glXQueryExtensionsString");
if(glXCreateNewContext_real == NULL)
glXCreateNewContext_real =
(PFNGLXCREATENEWCONTEXTPROC)dlsym(libGLdlsymHandle, "glXCreateNewContext");
if(glXCreateWindow_real == NULL)
glXCreateWindow_real = (PFNGLXCREATEWINDOWPROC)dlsym(libGLdlsymHandle, "glXCreateWindow");
if(glXDestroyWindow_real == NULL)
glXDestroyWindow_real = (PFNGLXDESTROYWINDOWPROC)dlsym(libGLdlsymHandle, "glXDestroyWindow");
return success;
}
__attribute__((visibility("default"))) __GLXextFuncPtr glXGetProcAddress(const GLubyte *f)
{
if(OpenGLHook::glhooks.glXGetProcAddress_real == NULL)
@@ -1223,78 +1227,7 @@ __attribute__((visibility("default"))) void glXDestroyWindow(Display *dpy, GLXWi
return OpenGLHook::glhooks.glXDestroyWindow_real(dpy, window);
}
// we also need to export the rest of the glX API, since we will have redirected any dlopen()
// for libGL.so to ourselves, and dlsym() for any of these entry points must return a valid
// function. We don't need to intercept them, so we just pass it along
__attribute__((visibility("default"))) Bool glXQueryExtension(Display *dpy, int *errorBase,
int *eventBase)
{
if(OpenGLHook::glhooks.glXQueryExtension_real == NULL)
OpenGLHook::glhooks.SetupExportedFunctions();
return OpenGLHook::glhooks.glXQueryExtension_real(dpy, errorBase, eventBase);
}
__attribute__((visibility("default"))) GLXFBConfig *glXGetFBConfigs(Display *dpy, int screen,
int *nelements)
{
if(OpenGLHook::glhooks.glXGetFBConfigs_real == NULL)
OpenGLHook::glhooks.SetupExportedFunctions();
return OpenGLHook::glhooks.glXGetFBConfigs_real(dpy, screen, nelements);
}
__attribute__((visibility("default"))) int glXGetFBConfigAttrib(Display *dpy, GLXFBConfig config,
int attribute, int *value)
{
if(OpenGLHook::glhooks.glXGetFBConfigAttrib_real == NULL)
OpenGLHook::glhooks.SetupExportedFunctions();
return OpenGLHook::glhooks.glXGetFBConfigAttrib_real(dpy, config, attribute, value);
}
__attribute__((visibility("default"))) const char *glXGetClientString(Display *dpy, int name)
{
if(OpenGLHook::glhooks.glXGetClientString_real == NULL)
OpenGLHook::glhooks.SetupExportedFunctions();
return OpenGLHook::glhooks.glXGetClientString_real(dpy, name);
}
__attribute__((visibility("default"))) Bool glXQueryVersion(Display *dpy, int *maj, int *min)
{
if(OpenGLHook::glhooks.glXQueryVersion_real == NULL)
OpenGLHook::glhooks.SetupExportedFunctions();
return OpenGLHook::glhooks.glXQueryVersion_real(dpy, maj, min);
}
__attribute__((visibility("default"))) const char *glXQueryExtensionsString(Display *dpy, int screen)
{
if(OpenGLHook::glhooks.glXQueryExtensionsString_real == NULL)
OpenGLHook::glhooks.SetupExportedFunctions();
return OpenGLHook::glhooks.glXQueryExtensionsString_real(dpy, screen);
}
__attribute__((visibility("default"))) GLXContext glXCreateNewContext(
Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool direct)
{
if(OpenGLHook::glhooks.glXCreateNewContext_real == NULL)
OpenGLHook::glhooks.SetupExportedFunctions();
return OpenGLHook::glhooks.glXCreateNewContext_real(dpy, config, renderType, shareList, direct);
}
__attribute__((visibility("default"))) XVisualInfo *glXGetVisualFromFBConfig(Display *dpy,
GLXFBConfig config)
{
if(OpenGLHook::glhooks.glXGetVisualFromFBConfig_real == NULL)
OpenGLHook::glhooks.SetupExportedFunctions();
return OpenGLHook::glhooks.glXGetVisualFromFBConfig_real(dpy, config);
}
}; // extern "C"
bool OpenGLHook::PopulateHooks()
{
+159
View File
@@ -0,0 +1,159 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2016 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include <dlfcn.h>
#include <stdio.h>
#include "driver/gl/gl_common.h"
// we need to export the whole of the GLX API, since we will have redirected any dlopen()
// for libGL.so to ourselves, and dlsym() for any of these entry points must return a valid
// function. We don't need to intercept them, so we just pass it along
extern void *libGLdlsymHandle;
/*
in bash:
function GLXHook()
{
N=$1;
echo -n "#define GLX_PASSTHRU_$N(ret, function";
for I in `seq 1 $N`; do echo -n ", t$I, p$I"; done;
echo ") \\";
echo -en "\ttypedef ret (*CONCAT(function, _hooktype)) (";
for I in `seq 1 $N`; do echo -n "t$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done;
echo "); \\";
echo -e "\textern \"C\" __attribute__ ((visibility (\"default\"))) \\";
echo -en "\tret function(";
for I in `seq 1 $N`; do echo -n "t$I p$I"; if [ $I -ne $N ]; then echo -n ", "; fi;
done;
echo ") \\";
echo -en "\t{ CONCAT(function, _hooktype) real = (CONCAT(function, _hooktype))";
echo "dlsym(libGLdlsymHandle, #function); \\";
echo -en "\treturn real(";
for I in `seq 1 $N`; do echo -n "p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done;
echo "); }";
}
for I in `seq 0 5`; do GLXHook $I; echo; done
*/
#define GLX_PASSTHRU_0(ret, function) \
typedef ret (*CONCAT(function, _hooktype))(); \
extern "C" __attribute__((visibility("default"))) ret function() \
{ \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(libGLdlsymHandle, #function); \
return real(); \
}
#define GLX_PASSTHRU_1(ret, function, t1, p1) \
typedef ret (*CONCAT(function, _hooktype))(t1); \
extern "C" __attribute__((visibility("default"))) ret function(t1 p1) \
{ \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(libGLdlsymHandle, #function); \
return real(p1); \
}
#define GLX_PASSTHRU_2(ret, function, t1, p1, t2, p2) \
typedef ret (*CONCAT(function, _hooktype))(t1, t2); \
extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2) \
{ \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(libGLdlsymHandle, #function); \
return real(p1, p2); \
}
#define GLX_PASSTHRU_3(ret, function, t1, p1, t2, p2, t3, p3) \
typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3); \
extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3) \
{ \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(libGLdlsymHandle, #function); \
return real(p1, p2, p3); \
}
#define GLX_PASSTHRU_4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \
typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3, t4); \
extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4) \
{ \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(libGLdlsymHandle, #function); \
return real(p1, p2, p3, p4); \
}
#define GLX_PASSTHRU_5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \
extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \
{ \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(libGLdlsymHandle, #function); \
return real(p1, p2, p3, p4, p5); \
}
GLX_PASSTHRU_3(GLXFBConfig *, glXGetFBConfigs, Display *, dpy, int, screen, int *, nelements);
GLX_PASSTHRU_4(int, glXGetFBConfigAttrib, Display *, dpy, GLXFBConfig, config, int, attribute,
int *, value);
GLX_PASSTHRU_2(XVisualInfo *, glXGetVisualFromFBConfig, Display *, dpy, GLXFBConfig, config);
GLX_PASSTHRU_4(GLXFBConfig *, glXChooseFBConfig, Display *, dpy, int, screen, const int *,
attrib_list, int *, nelements);
GLX_PASSTHRU_3(XVisualInfo *, glXChooseVisual, Display *, dpy, int, screen, int *, attrib_list);
GLX_PASSTHRU_4(int, glXGetConfig, Display *, dpy, XVisualInfo *, visual, int, attribute, int *,
value);
GLX_PASSTHRU_5(GLXContext, glXCreateNewContext, Display *, dpy, GLXFBConfig, config, int,
renderType, GLXContext, shareList, Bool, direct);
GLX_PASSTHRU_4(void, glXCopyContext, Display *, dpy, GLXContext, source, GLXContext, dest,
unsigned long, mask);
GLX_PASSTHRU_4(int, glXQueryContext, Display *, dpy, GLXContext, ctx, int, attribute, int *, value);
GLX_PASSTHRU_3(void, glXSelectEvent, Display *, dpy, GLXDrawable, draw, unsigned long, event_mask);
GLX_PASSTHRU_3(void, glXGetSelectedEvent, Display *, dpy, GLXDrawable, draw, unsigned long *,
event_mask);
GLX_PASSTHRU_4(void, glXQueryDrawable, Display *, dpy, GLXDrawable, draw, int, attribute,
unsigned int *, value);
GLX_PASSTHRU_0(GLXContext, glXGetCurrentContext);
GLX_PASSTHRU_0(GLXDrawable, glXGetCurrentDrawable);
GLX_PASSTHRU_0(GLXDrawable, glXGetCurrentReadDrawable);
GLX_PASSTHRU_0(Display *, glXGetCurrentDisplay);
GLX_PASSTHRU_3(const char *, glXQueryServerString, Display *, dpy, int, screen, int, name);
GLX_PASSTHRU_2(const char *, glXGetClientString, Display *, dpy, int, name);
GLX_PASSTHRU_2(const char *, glXQueryExtensionsString, Display *, dpy, int, screen);
GLX_PASSTHRU_3(Bool, glXQueryExtension, Display *, dpy, int *, errorBase, int *, eventBase);
GLX_PASSTHRU_3(Bool, glXQueryVersion, Display *, dpy, int *, maj, int *, min);
GLX_PASSTHRU_2(Bool, glXIsDirect, Display *, dpy, GLXContext, ctx);
GLX_PASSTHRU_0(void, glXWaitGL);
GLX_PASSTHRU_4(void, glXUseXFont, Font, font, int, first, int, count, int, list_base);
GLX_PASSTHRU_3(GLXPixmap, glXCreateGLXPixmap, Display *, dpy, XVisualInfo *, visual, Pixmap, pixmap);
GLX_PASSTHRU_2(void, glXDestroyGLXPixmap, Display *, dpy, GLXPixmap, pixmap);
GLX_PASSTHRU_4(GLXPixmap, glXCreatePixmap, Display *, dpy, GLXFBConfig, config, Pixmap, pixmap,
const int *, attrib_list);
GLX_PASSTHRU_2(void, glXDestroyPixmap, Display *, dpy, GLXPixmap, pixmap);
GLX_PASSTHRU_3(GLXPbuffer, glXCreatePbuffer, Display *, dpy, GLXFBConfig, config, const int *,
attrib_list);
GLX_PASSTHRU_2(void, glXDestroyPbuffer, Display *, dpy, GLXPbuffer, pbuf);
+3
View File
@@ -34,6 +34,9 @@
<ClInclude Include="official\wglext.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="glx_hooks_linux.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="gl_common.cpp" />
<ClCompile Include="gl_counters.cpp" />
<ClCompile Include="gl_debug.cpp" />
@@ -152,5 +152,8 @@
<ClCompile Include="wrappers\gl_interop_funcs.cpp">
<Filter>Function Wrappers</Filter>
</ClCompile>
<ClCompile Include="glx_hooks_linux.cpp">
<Filter>OS\Linux</Filter>
</ClCompile>
</ItemGroup>
</Project>
+2 -2
View File
@@ -704,7 +704,7 @@ void DisplayRendererPreview(ReplayRenderer *renderer, TextureDisplay &displayCfg
// symbol defined in libGL but not librenderdoc.
// Forces link of libGL after renderdoc (otherwise all symbols would
// be resolved and libGL wouldn't link, meaning dlsym(RTLD_NEXT) would fai
extern "C" void glXWaitGL();
extern "C" void glXWaitX();
#endif
@@ -724,7 +724,7 @@ int main(int argc, char *argv[])
volatile bool never_run = false;
if(never_run)
glXWaitGL();
glXWaitX();
#endif