Implemented bug #2, 117:
Date: Mon, 21 Mar 2005 12:06:14 +0100
From: Per Inge Mathisen
Subject: Re: [SDL] Outstanding patches?
The patch adds support for setting SDL_GL_SWAP_CONTROL to Windows and
X11. In Windows you can also query this enum to check that it is
working, or see what the default is - such functionality does not
exist in GLX. For more information on the standards implemented:
http://oss.sgi.com/projects/ogl-sample/registry/SGI/swap_control.txt
http://oss.sgi.com/projects/ogl-sample/registry/EXT/wgl_swap_control.txt
--- a/WhatsNew Wed Apr 26 23:17:39 2006 +0000
+++ b/WhatsNew Thu Apr 27 07:59:16 2006 +0000
@@ -4,6 +4,8 @@
Version 1.0:
1.2.10:
+ Added SDL_GL_SWAP_CONTROL to wait for vsync in OpenGL applications.
+
Added current_w and current_h to the SDL_VideoInfo structure,
which is set to the desktop resolution during video intialization,
and then set to the current resolution when a video mode is set.
--- a/include/SDL_video.h Wed Apr 26 23:17:39 2006 +0000
+++ b/include/SDL_video.h Thu Apr 27 07:59:16 2006 +0000
@@ -213,7 +213,8 @@
SDL_GL_ACCUM_ALPHA_SIZE,
SDL_GL_STEREO,
SDL_GL_MULTISAMPLEBUFFERS,
- SDL_GL_MULTISAMPLESAMPLES
+ SDL_GL_MULTISAMPLESAMPLES,
+ SDL_GL_SWAP_CONTROL
} SDL_GLattr;
/* flags for SDL_SetPalette() */
--- a/src/video/SDL_sysvideo.h Wed Apr 26 23:17:39 2006 +0000
+++ b/src/video/SDL_sysvideo.h Thu Apr 27 07:59:16 2006 +0000
@@ -292,6 +292,7 @@
int stereo;
int multisamplebuffers;
int multisamplesamples;
+ int swap_control;
int driver_loaded;
char driver_path[256];
void* dll_handle;
--- a/src/video/SDL_video.c Wed Apr 26 23:17:39 2006 +0000
+++ b/src/video/SDL_video.c Thu Apr 27 07:59:16 2006 +0000
@@ -233,6 +233,7 @@
video->gl_config.stereo = 0;
video->gl_config.multisamplebuffers = 0;
video->gl_config.multisamplesamples = 0;
+ video->gl_config.swap_control = -1; /* not known, don't set */
/* Initialize the video subsystem */
SDL_memset(&vformat, 0, sizeof(vformat));
@@ -1474,6 +1475,9 @@
case SDL_GL_MULTISAMPLESAMPLES:
video->gl_config.multisamplesamples = value;
break;
+ case SDL_GL_SWAP_CONTROL:
+ video->gl_config.swap_control = value;
+ break;
default:
SDL_SetError("Unknown OpenGL attribute");
retval = -1;
--- a/src/video/quartz/SDL_QuartzGL.m Wed Apr 26 23:17:39 2006 +0000
+++ b/src/video/quartz/SDL_QuartzGL.m Thu Apr 27 07:59:16 2006 +0000
@@ -132,6 +132,17 @@
return 0;
}
+ /* Synchronize QZ_GL_SwapBuffers() to vertical retrace.
+ * (Apple's documentation is not completely clear about what this setting
+ * exactly does, IMHO - for a detailed explanation see
+ * http://lists.apple.com/archives/mac-opengl/2006/Jan/msg00080.html )
+ */
+ if ( this->gl_config.swap_control >= 0 ) {
+ long value;
+ value = this->gl_config.swap_control;
+ [ gl_context setValues: &value forParameter: NSOpenGLCPSwapInterval ];
+ }
+
/*
* Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
* "You are blowing a couple of the internal OpenGL function caches. This
--- a/src/video/wincommon/SDL_wingl.c Wed Apr 26 23:17:39 2006 +0000
+++ b/src/video/wincommon/SDL_wingl.c Thu Apr 27 07:59:16 2006 +0000
@@ -177,6 +177,7 @@
int iAttribs[64];
int *iAttr;
float fAttribs[1] = { 0 };
+ const char *wglext;
/* load the gl driver from a default path */
if ( ! this->gl_config.driver_loaded ) {
@@ -323,7 +324,25 @@
SDL_SetError("Unable to create GL context");
return(-1);
}
+ if ( WIN_GL_MakeCurrent(this) < 0 ) {
+ return(-1);
+ }
gl_active = 1;
+
+ /* Vsync control under Windows. Checking glGetString here is
+ * somewhat a documented and reliable hack - it was originally
+ * as a feature added by mistake, but since so many people rely
+ * on it, it will not be removed. strstr should be safe here.*/
+ wglext = (const char *)this->glGetString(GL_EXTENSIONS);
+ if ( !SDL_strstr(wglext, "WGL_EXT_swap_control") ) {
+ this->gl_data->wglSwapIntervalEXT = NULL;
+ this->gl_data->wglGetSwapIntervalEXT = NULL;
+ }
+ if ( this->gl_config.swap_control >= 0 ) {
+ if ( this->gl_data->wglSwapIntervalEXT ) {
+ this->gl_data->wglSwapIntervalEXT(this->gl_config.swap_control);
+ }
+ }
#else
SDL_SetError("WIN driver not configured with OpenGL");
#endif
@@ -423,6 +442,12 @@
case SDL_GL_MULTISAMPLESAMPLES:
wgl_attrib = WGL_SAMPLES_ARB;
break;
+ case SDL_GL_SWAP_CONTROL:
+ if ( this->gl_data->wglGetSwapIntervalEXT ) {
+ return this->gl_data->wglGetSwapIntervalEXT();
+ } else {
+ return -1;
+ }
default:
return(-1);
}
@@ -509,6 +534,8 @@
this->gl_data->wglMakeCurrent = NULL;
this->gl_data->wglChoosePixelFormatARB = NULL;
this->gl_data->wglGetPixelFormatAttribivARB = NULL;
+ this->gl_data->wglSwapIntervalEXT = NULL;
+ this->gl_data->wglGetSwapIntervalEXT = NULL;
this->gl_config.dll_handle = NULL;
this->gl_config.driver_loaded = 0;
@@ -547,6 +574,10 @@
GetProcAddress(handle, "wglDeleteContext");
this->gl_data->wglMakeCurrent = (BOOL (WINAPI *)(HDC, HGLRC))
GetProcAddress(handle, "wglMakeCurrent");
+ this->gl_data->wglSwapIntervalEXT = (void (WINAPI *)(int))
+ GetProcAddress(handle, "wglSwapIntervalEXT");
+ this->gl_data->wglGetSwapIntervalEXT = (int (WINAPI *)(void))
+ GetProcAddress(handle, "wglGetSwapIntervalEXT");
if ( (this->gl_data->wglGetProcAddress == NULL) ||
(this->gl_data->wglCreateContext == NULL) ||
--- a/src/video/wincommon/SDL_wingl_c.h Wed Apr 26 23:17:39 2006 +0000
+++ b/src/video/wincommon/SDL_wingl_c.h Thu Apr 27 07:59:16 2006 +0000
@@ -53,6 +53,8 @@
UINT nAttributes,
const int *piAttributes,
int *piValues);
+ void (WINAPI *wglSwapIntervalEXT)(int interval);
+ int (WINAPI *wglGetSwapIntervalEXT)(void);
#endif /* SDL_VIDEO_OPENGL */
};
--- a/src/video/x11/SDL_x11gl.c Wed Apr 26 23:17:39 2006 +0000
+++ b/src/video/x11/SDL_x11gl.c Thu Apr 27 07:59:16 2006 +0000
@@ -205,18 +205,39 @@
{
int retval;
#if SDL_VIDEO_OPENGL_GLX
+ const char *glXext;
+
/* We do this to create a clean separation between X and GLX errors. */
XSync( SDL_Display, False );
glx_context = this->gl_data->glXCreateContext(GFX_Display,
glx_visualinfo, NULL, True);
XSync( GFX_Display, False );
- if (glx_context == NULL) {
+ if ( glx_context == NULL ) {
SDL_SetError("Could not create GL context");
- return -1;
+ return(-1);
+ }
+ if ( X11_GL_MakeCurrent(this) < 0 ) {
+ return(-1);
+ }
+ gl_active = 1;
+
+ /* The use of strstr here should be safe */
+ glXext = this->gl_data->glXQueryExtensionsString(GFX_Display, DefaultScreen(GFX_Display));
+ if ( !SDL_strstr(glXext, "SGI_swap_control") ) {
+ this->gl_data->glXSwapIntervalSGI = NULL;
}
-
- gl_active = 1;
+ if ( !SDL_strstr(glXext, "GLX_MESA_swap_control") ) {
+ this->gl_data->glXSwapIntervalMESA = NULL;
+ this->gl_data->glXGetSwapIntervalMESA = NULL;
+ }
+ if ( this->gl_config.swap_control >= 0 ) {
+ if ( this->gl_data->glXSwapIntervalMESA ) {
+ this->gl_data->glXSwapIntervalMESA(this->gl_config.swap_control);
+ } else if ( this->gl_data->glXSwapIntervalSGI ) {
+ this->gl_data->glXSwapIntervalSGI(this->gl_config.swap_control);
+ }
+ }
#else
SDL_SetError("X11 driver not configured with OpenGL");
#endif
@@ -319,6 +340,13 @@
case SDL_GL_MULTISAMPLESAMPLES:
glx_attrib = GLX_SAMPLES_ARB;
break;
+ case SDL_GL_SWAP_CONTROL:
+ if ( this->gl_data->glXGetSwapIntervalMESA ) {
+ return this->gl_data->glXGetSwapIntervalMESA();
+ } else {
+ return -1 /*(this->gl_config.swap_control > 0)*/;
+ }
+ break;
default:
return(-1);
}
@@ -348,6 +376,9 @@
this->gl_data->glXDestroyContext = NULL;
this->gl_data->glXMakeCurrent = NULL;
this->gl_data->glXSwapBuffers = NULL;
+ this->gl_data->glXSwapIntervalSGI = NULL;
+ this->gl_data->glXSwapIntervalMESA = NULL;
+ this->gl_data->glXGetSwapIntervalMESA = NULL;
this->gl_config.dll_handle = NULL;
this->gl_config.driver_loaded = 0;
@@ -400,7 +431,12 @@
(int (*)(Display *, XVisualInfo *, int, int *)) SDL_LoadFunction(handle, "glXGetConfig");
this->gl_data->glXQueryExtensionsString =
(const char *(*)(Display *, int)) SDL_LoadFunction(handle, "glXQueryExtensionsString");
-
+ this->gl_data->glXSwapIntervalSGI =
+ (int (*)(int)) SDL_LoadFunction(handle, "glXSwapIntervalSGI");
+ this->gl_data->glXSwapIntervalMESA =
+ (GLint (*)(unsigned)) SDL_LoadFunction(handle, "glXSwapIntervalMESA");
+ this->gl_data->glXGetSwapIntervalMESA =
+ (GLint (*)(void)) SDL_LoadFunction(handle, "glXGetSwapIntervalMESA");
if ( (this->gl_data->glXChooseVisual == NULL) ||
(this->gl_data->glXCreateContext == NULL) ||
--- a/src/video/x11/SDL_x11gl_c.h Wed Apr 26 23:17:39 2006 +0000
+++ b/src/video/x11/SDL_x11gl_c.h Thu Apr 27 07:59:16 2006 +0000
@@ -71,7 +71,10 @@
( Display* dpy,
int screen );
-
+ int (*glXSwapIntervalSGI) ( int interval );
+ GLint (*glXSwapIntervalMESA) ( unsigned interval );
+ GLint (*glXGetSwapIntervalMESA) ( void );
+
#endif /* SDL_VIDEO_OPENGL_GLX */
};
--- a/test/testgl.c Wed Apr 26 23:17:39 2006 +0000
+++ b/test/testgl.c Thu Apr 27 07:59:16 2006 +0000
@@ -445,7 +445,7 @@
}
int RunGLTest( int argc, char* argv[],
- int logo, int logocursor, int slowly, int bpp, float gamma, int noframe, int fsaa )
+ int logo, int logocursor, int slowly, int bpp, float gamma, int noframe, int fsaa, int sync )
{
int i;
int rgb_size[3];
@@ -531,6 +531,11 @@
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, fsaa );
}
+ if ( sync ) {
+ SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1 );
+ } else {
+ SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 0 );
+ }
if ( SDL_SetVideoMode( w, h, bpp, video_flags ) == NULL ) {
fprintf(stderr, "Couldn't set GL mode: %s\n", SDL_GetError());
SDL_Quit();
@@ -557,9 +562,13 @@
printf( "SDL_GL_DOUBLEBUFFER: requested 1, got %d\n", value );
if ( fsaa ) {
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &value );
- printf( "SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value );
+ printf("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value );
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &value );
- printf( "SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, value );
+ printf("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, value );
+ }
+ if ( sync ) {
+ SDL_GL_GetAttribute( SDL_GL_SWAP_CONTROL, &value );
+ printf( "SDL_GL_SWAP_CONTROL: requested 1, got %d\n", value );
}
/* Set the window manager title bar */
@@ -770,6 +779,7 @@
float gamma = 0.0;
int noframe = 0;
int fsaa = 0;
+ int sync = 0;
logo = 0;
slowly = 0;
@@ -804,6 +814,9 @@
if ( strcmp(argv[i], "-fsaa") == 0 ) {
++fsaa;
}
+ if ( strcmp(argv[i], "-sync") == 0 ) {
+ ++sync;
+ }
if ( strncmp(argv[i], "-h", 2) == 0 ) {
printf(
"Usage: %s [-twice] [-logo] [-logocursor] [-slow] [-bpp n] [-gamma n] [-noframe] [-fsaa] [-fullscreen]\n",
@@ -812,7 +825,7 @@
}
}
for ( i=0; i<numtests; ++i ) {
- RunGLTest(argc, argv, logo, logocursor, slowly, bpp, gamma, noframe, fsaa);
+ RunGLTest(argc, argv, logo, logocursor, slowly, bpp, gamma, noframe, fsaa, sync);
}
return 0;
}