Add support for (GLX|WGL)_EXT_swap_control_tear.
This required a small public API change: SDL_GL_SetSwapInterval() now accepts
negative values, and SDL_GL_GetSwapInterval() doesn't report errors anymore
(if it can't work, it'll return zero as a reasonable default).
If you need to test for errors, such as a lack of swap_control_tear support,
check the results of SDL_GL_SetSwapInterval() when you set your desired
value.
--- a/include/SDL_video.h Tue Jul 31 16:55:09 2012 -0700
+++ b/include/SDL_video.h Wed Aug 01 20:29:36 2012 -0400
@@ -789,7 +789,9 @@
* \brief Set the swap interval for the current OpenGL context.
*
* \param interval 0 for immediate updates, 1 for updates synchronized with the
- * vertical retrace.
+ * vertical retrace. If the system supports it, you may
+ * specify -1 to allow late swaps to happen immediately
+ * instead of waiting for the next retrace.
*
* \return 0 on success, or -1 if setting the swap interval is not supported.
*
@@ -801,8 +803,10 @@
* \brief Get the swap interval for the current OpenGL context.
*
* \return 0 if there is no vertical retrace synchronization, 1 if the buffer
- * swap is synchronized with the vertical retrace, and -1 if getting
- * the swap interval is not supported.
+ * swap is synchronized with the vertical retrace, and -1 if late
+ * swaps happen immediately instead of waiting for the next retrace.
+ * If the system can't determine the swap interval, or there isn't a
+ * valid current context, this will return 0 as a safe default.
*
* \sa SDL_GL_SetSwapInterval()
*/
--- a/src/video/SDL_video.c Tue Jul 31 16:55:09 2012 -0700
+++ b/src/video/SDL_video.c Wed Aug 01 20:29:36 2012 -0400
@@ -2578,16 +2578,13 @@
SDL_GL_GetSwapInterval(void)
{
if (!_this) {
- SDL_UninitializedVideo();
- return -1;
+ return 0;
} else if (_this->current_glctx == NULL) {
- SDL_SetError("No OpenGL context has been made current");
- return -1;
+ return 0;
} else if (_this->GL_GetSwapInterval) {
return _this->GL_GetSwapInterval(_this);
} else {
- SDL_SetError("Getting the swap interval is not supported");
- return -1;
+ return 0;
}
}
--- a/src/video/cocoa/SDL_cocoaopengl.m Tue Jul 31 16:55:09 2012 -0700
+++ b/src/video/cocoa/SDL_cocoaopengl.m Wed Aug 01 20:29:36 2012 -0400
@@ -250,7 +250,7 @@
NSAutoreleasePool *pool;
NSOpenGLContext *nscontext;
GLint value;
- int status;
+ int status = 0;
pool = [[NSAutoreleasePool alloc] init];
@@ -258,9 +258,6 @@
if (nscontext != nil) {
[nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
status = (int)value;
- } else {
- SDL_SetError("No current OpenGL context");
- status = -1;
}
[pool release];
--- a/src/video/directfb/SDL_DirectFB_opengl.c Tue Jul 31 16:55:09 2012 -0700
+++ b/src/video/directfb/SDL_DirectFB_opengl.c Wed Aug 01 20:29:36 2012 -0400
@@ -250,8 +250,7 @@
int
DirectFB_GL_GetSwapInterval(_THIS)
{
- SDL_Unsupported();
- return -1;
+ return 0;
}
void
--- a/src/video/pandora/SDL_pandora.c Tue Jul 31 16:55:09 2012 -0700
+++ b/src/video/pandora/SDL_pandora.c Wed Aug 01 20:29:36 2012 -0400
@@ -796,15 +796,7 @@
int
PND_gl_getswapinterval(_THIS)
{
- SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
-
- if (phdata->egl_initialized != SDL_TRUE) {
- SDL_SetError("PND: GLES initialization failed, no OpenGL ES support");
- return -1;
- }
-
- /* Return default swap interval value */
- return phdata->swapinterval;
+ return ((SDL_VideoData *) _this->driverdata)->swapinterval;
}
void
--- a/src/video/windows/SDL_windowsopengl.c Tue Jul 31 16:55:09 2012 -0700
+++ b/src/video/windows/SDL_windowsopengl.c Wed Aug 01 20:29:36 2012 -0400
@@ -112,10 +112,6 @@
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 ||
!_this->gl_data->wglCreateContext ||
@@ -341,7 +337,7 @@
}
/* Check for WGL_ARB_pixel_format */
- _this->gl_data->WGL_ARB_pixel_format = 0;
+ _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_FALSE;
if (HasExtension("WGL_ARB_pixel_format", extensions)) {
_this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *)
(HDC, const int *,
@@ -354,16 +350,20 @@
if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
(_this->gl_data->wglGetPixelFormatAttribivARB != NULL)) {
- _this->gl_data->WGL_ARB_pixel_format = 1;
+ _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_TRUE;
}
}
/* Check for WGL_EXT_swap_control */
+ _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_FALSE;
if (HasExtension("WGL_EXT_swap_control", extensions)) {
_this->gl_data->wglSwapIntervalEXT =
WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
_this->gl_data->wglGetSwapIntervalEXT =
WIN_GL_GetProcAddress(_this, "wglGetSwapIntervalEXT");
+ if (HasExtension("WGL_EXT_swap_control_tear", extensions)) {
+ _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_TRUE;
+ }
} else {
_this->gl_data->wglSwapIntervalEXT = NULL;
_this->gl_data->wglGetSwapIntervalEXT = NULL;
@@ -397,7 +397,7 @@
WIN_GL_InitExtensions(_this, hdc);
- if (_this->gl_data->WGL_ARB_pixel_format) {
+ if (_this->gl_data->HAS_WGL_ARB_pixel_format) {
_this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
1, &pixel_format,
&matching);
@@ -611,7 +611,9 @@
int
WIN_GL_SetSwapInterval(_THIS, int interval)
{
- if (_this->gl_data->wglSwapIntervalEXT) {
+ if ((interval < 0) && (!_this->gl_data->HAS_WGL_EXT_swap_control_tear)) {
+ SDL_SetError("Negative swap interval unsupported in this GL");
+ } else if (_this->gl_data->wglSwapIntervalEXT) {
_this->gl_data->wglSwapIntervalEXT(interval);
return 0;
} else {
@@ -626,8 +628,8 @@
if (_this->gl_data->wglGetSwapIntervalEXT) {
return _this->gl_data->wglGetSwapIntervalEXT();
} else {
- SDL_Unsupported();
- return -1;
+ /*SDL_Unsupported();*/
+ return 0; /* just say we're unsync'd. */
}
}
--- a/src/video/windows/SDL_windowsopengl.h Tue Jul 31 16:55:09 2012 -0700
+++ b/src/video/windows/SDL_windowsopengl.h Wed Aug 01 20:29:36 2012 -0400
@@ -27,7 +27,8 @@
struct SDL_GLDriverData
{
- int WGL_ARB_pixel_format;
+ SDL_bool HAS_WGL_ARB_pixel_format;
+ SDL_bool HAS_WGL_EXT_swap_control_tear;
void *(WINAPI * wglGetProcAddress) (const char *proc);
HGLRC(WINAPI * wglCreateContext) (HDC hdc);
--- a/src/video/x11/SDL_x11opengl.c Tue Jul 31 16:55:09 2012 -0700
+++ b/src/video/x11/SDL_x11opengl.c Wed Aug 01 20:29:36 2012 -0400
@@ -105,6 +105,10 @@
#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
#endif
+#ifndef GLX_EXT_swap_control_tear
+#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
+#endif
+
#define OPENGL_REQUIRES_DLOPEN
#if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
#include <dlfcn.h>
@@ -318,11 +322,15 @@
extensions = NULL;
}
- /* Check for GLX_EXT_swap_control */
+ /* Check for GLX_EXT_swap_control(_tear) */
+ _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
if (HasExtension("GLX_EXT_swap_control", extensions)) {
_this->gl_data->glXSwapIntervalEXT =
(int (*)(Display*,GLXDrawable,int))
X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
+ if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
+ _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
+ }
}
/* Check for GLX_MESA_swap_control */
@@ -615,9 +623,11 @@
int
X11_GL_SetSwapInterval(_THIS, int interval)
{
- int status;
+ int status = -1;
- if (_this->gl_data->glXSwapIntervalEXT) {
+ if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
+ SDL_SetError("Negative swap interval unsupported in this GL");
+ } else if (_this->gl_data->glXSwapIntervalEXT) {
Display *display = ((SDL_VideoData *) _this->driverdata)->display;
const SDL_WindowData *windowdata = (SDL_WindowData *)
_this->current_glwin->driverdata;
@@ -625,7 +635,6 @@
status = _this->gl_data->glXSwapIntervalEXT(display,drawable,interval);
if (status != 0) {
SDL_SetError("glxSwapIntervalEXT failed");
- status = -1;
} else {
swapinterval = interval;
}
@@ -633,7 +642,6 @@
status = _this->gl_data->glXSwapIntervalMESA(interval);
if (status != 0) {
SDL_SetError("glxSwapIntervalMESA failed");
- status = -1;
} else {
swapinterval = interval;
}
@@ -641,13 +649,11 @@
status = _this->gl_data->glXSwapIntervalSGI(interval);
if (status != 0) {
SDL_SetError("glxSwapIntervalSGI failed");
- status = -1;
} else {
swapinterval = interval;
}
} else {
SDL_Unsupported();
- status = -1;
}
return status;
}
@@ -660,10 +666,23 @@
const SDL_WindowData *windowdata = (SDL_WindowData *)
_this->current_glwin->driverdata;
Window drawable = windowdata->xwindow;
- unsigned int value = 0;
+ unsigned int allow_late_swap_tearing = 0;
+ unsigned int interval = 0;
+
+ if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
+ _this->gl_data->glXQueryDrawable(display, drawable,
+ GLX_LATE_SWAPS_TEAR_EXT,
+ &allow_late_swap_tearing);
+ }
+
_this->gl_data->glXQueryDrawable(display, drawable,
- GLX_SWAP_INTERVAL_EXT, &value);
- return (int) value;
+ GLX_SWAP_INTERVAL_EXT, &interval);
+
+ if ((allow_late_swap_tearing) && (interval > 0)) {
+ return -((int) interval);
+ }
+
+ return (int) interval;
} else if (_this->gl_data->glXGetSwapIntervalMESA) {
return _this->gl_data->glXGetSwapIntervalMESA();
} else {
--- a/src/video/x11/SDL_x11opengl.h Tue Jul 31 16:55:09 2012 -0700
+++ b/src/video/x11/SDL_x11opengl.h Wed Aug 01 20:29:36 2012 -0400
@@ -30,6 +30,7 @@
struct SDL_GLDriverData
{
SDL_bool HAS_GLX_EXT_visual_rating;
+ SDL_bool HAS_GLX_EXT_swap_control_tear;
void *(*glXGetProcAddress) (const GLubyte*);
XVisualInfo *(*glXChooseVisual) (Display*,int,int*);
--- a/test/testgl2.c Tue Jul 31 16:55:09 2012 -0700
+++ b/test/testgl2.c Wed Aug 01 20:29:36 2012 -0400
@@ -240,18 +240,21 @@
}
if (state->render_flags & SDL_RENDERER_PRESENTVSYNC) {
- SDL_GL_SetSwapInterval(1);
+ /* try late-swap-tearing first. If not supported, try normal vsync. */
+ if (SDL_GL_SetSwapInterval(-1) == -1) {
+ SDL_GL_SetSwapInterval(1);
+ }
} else {
- SDL_GL_SetSwapInterval(0);
+ SDL_GL_SetSwapInterval(0); /* disable vsync. */
}
SDL_GetCurrentDisplayMode(0, &mode);
- printf("Screen BPP: %d\n", SDL_BITSPERPIXEL(mode.format));
+ printf("Screen BPP : %d\n", SDL_BITSPERPIXEL(mode.format));
+ printf("Swap Interval : %d\n", SDL_GL_GetSwapInterval());
printf("\n");
- printf("Vendor : %s\n", glGetString(GL_VENDOR));
- printf("Renderer : %s\n", glGetString(GL_RENDERER));
- printf("Version : %s\n", glGetString(GL_VERSION));
- printf("Extensions : %s\n", glGetString(GL_EXTENSIONS));
+ printf("Vendor : %s\n", glGetString(GL_VENDOR));
+ printf("Renderer : %s\n", glGetString(GL_RENDERER));
+ printf("Version : %s\n", glGetString(GL_VERSION));
printf("\n");
status = SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value);