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.
This commit is contained in:
Ryan C. Gordon 2012-08-01 20:29:36 -04:00
parent 706ea79345
commit 2cd5fc4e97
10 changed files with 67 additions and 52 deletions

View file

@ -789,7 +789,9 @@ extern DECLSPEC int SDLCALL SDL_GL_MakeCurrent(SDL_Window * window,
* \brief Set the swap interval for the current OpenGL context. * \brief Set the swap interval for the current OpenGL context.
* *
* \param interval 0 for immediate updates, 1 for updates synchronized with the * \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. * \return 0 on success, or -1 if setting the swap interval is not supported.
* *
@ -801,8 +803,10 @@ extern DECLSPEC int SDLCALL SDL_GL_SetSwapInterval(int interval);
* \brief Get the swap interval for the current OpenGL context. * \brief Get the swap interval for the current OpenGL context.
* *
* \return 0 if there is no vertical retrace synchronization, 1 if the buffer * \return 0 if there is no vertical retrace synchronization, 1 if the buffer
* swap is synchronized with the vertical retrace, and -1 if getting * swap is synchronized with the vertical retrace, and -1 if late
* the swap interval is not supported. * 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() * \sa SDL_GL_SetSwapInterval()
*/ */

View file

@ -2578,16 +2578,13 @@ int
SDL_GL_GetSwapInterval(void) SDL_GL_GetSwapInterval(void)
{ {
if (!_this) { if (!_this) {
SDL_UninitializedVideo(); return 0;
return -1;
} else if (_this->current_glctx == NULL) { } else if (_this->current_glctx == NULL) {
SDL_SetError("No OpenGL context has been made current"); return 0;
return -1;
} else if (_this->GL_GetSwapInterval) { } else if (_this->GL_GetSwapInterval) {
return _this->GL_GetSwapInterval(_this); return _this->GL_GetSwapInterval(_this);
} else { } else {
SDL_SetError("Getting the swap interval is not supported"); return 0;
return -1;
} }
} }

View file

@ -250,7 +250,7 @@ Cocoa_GL_GetSwapInterval(_THIS)
NSAutoreleasePool *pool; NSAutoreleasePool *pool;
NSOpenGLContext *nscontext; NSOpenGLContext *nscontext;
GLint value; GLint value;
int status; int status = 0;
pool = [[NSAutoreleasePool alloc] init]; pool = [[NSAutoreleasePool alloc] init];
@ -258,9 +258,6 @@ Cocoa_GL_GetSwapInterval(_THIS)
if (nscontext != nil) { if (nscontext != nil) {
[nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval]; [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
status = (int)value; status = (int)value;
} else {
SDL_SetError("No current OpenGL context");
status = -1;
} }
[pool release]; [pool release];

View file

@ -250,8 +250,7 @@ DirectFB_GL_SetSwapInterval(_THIS, int interval)
int int
DirectFB_GL_GetSwapInterval(_THIS) DirectFB_GL_GetSwapInterval(_THIS)
{ {
SDL_Unsupported(); return 0;
return -1;
} }
void void

View file

@ -796,15 +796,7 @@ PND_gl_setswapinterval(_THIS, int interval)
int int
PND_gl_getswapinterval(_THIS) PND_gl_getswapinterval(_THIS)
{ {
SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata; return ((SDL_VideoData *) _this->driverdata)->swapinterval;
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;
} }
void void

View file

@ -112,10 +112,6 @@ WIN_GL_LoadLibrary(_THIS, const char *path)
GetProcAddress(handle, "wglDeleteContext"); GetProcAddress(handle, "wglDeleteContext");
_this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC)) _this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC))
GetProcAddress(handle, "wglMakeCurrent"); 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 || if (!_this->gl_data->wglGetProcAddress ||
!_this->gl_data->wglCreateContext || !_this->gl_data->wglCreateContext ||
@ -341,7 +337,7 @@ WIN_GL_InitExtensions(_THIS, HDC hdc)
} }
/* Check for WGL_ARB_pixel_format */ /* 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)) { if (HasExtension("WGL_ARB_pixel_format", extensions)) {
_this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *) _this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *)
(HDC, const int *, (HDC, const int *,
@ -354,16 +350,20 @@ WIN_GL_InitExtensions(_THIS, HDC hdc)
if ((_this->gl_data->wglChoosePixelFormatARB != NULL) && if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
(_this->gl_data->wglGetPixelFormatAttribivARB != 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 */ /* Check for WGL_EXT_swap_control */
_this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_FALSE;
if (HasExtension("WGL_EXT_swap_control", extensions)) { if (HasExtension("WGL_EXT_swap_control", extensions)) {
_this->gl_data->wglSwapIntervalEXT = _this->gl_data->wglSwapIntervalEXT =
WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT"); WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
_this->gl_data->wglGetSwapIntervalEXT = _this->gl_data->wglGetSwapIntervalEXT =
WIN_GL_GetProcAddress(_this, "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 { } else {
_this->gl_data->wglSwapIntervalEXT = NULL; _this->gl_data->wglSwapIntervalEXT = NULL;
_this->gl_data->wglGetSwapIntervalEXT = NULL; _this->gl_data->wglGetSwapIntervalEXT = NULL;
@ -397,7 +397,7 @@ WIN_GL_ChoosePixelFormatARB(_THIS, int *iAttribs, float *fAttribs)
WIN_GL_InitExtensions(_this, hdc); 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, _this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
1, &pixel_format, 1, &pixel_format,
&matching); &matching);
@ -611,7 +611,9 @@ WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
int int
WIN_GL_SetSwapInterval(_THIS, int interval) 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); _this->gl_data->wglSwapIntervalEXT(interval);
return 0; return 0;
} else { } else {
@ -626,8 +628,8 @@ WIN_GL_GetSwapInterval(_THIS)
if (_this->gl_data->wglGetSwapIntervalEXT) { if (_this->gl_data->wglGetSwapIntervalEXT) {
return _this->gl_data->wglGetSwapIntervalEXT(); return _this->gl_data->wglGetSwapIntervalEXT();
} else { } else {
SDL_Unsupported(); /*SDL_Unsupported();*/
return -1; return 0; /* just say we're unsync'd. */
} }
} }

View file

@ -27,7 +27,8 @@
struct SDL_GLDriverData 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); void *(WINAPI * wglGetProcAddress) (const char *proc);
HGLRC(WINAPI * wglCreateContext) (HDC hdc); HGLRC(WINAPI * wglCreateContext) (HDC hdc);

View file

@ -105,6 +105,10 @@ typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 #define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
#endif #endif
#ifndef GLX_EXT_swap_control_tear
#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
#endif
#define OPENGL_REQUIRES_DLOPEN #define OPENGL_REQUIRES_DLOPEN
#if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN) #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
#include <dlfcn.h> #include <dlfcn.h>
@ -318,11 +322,15 @@ X11_GL_InitExtensions(_THIS)
extensions = NULL; 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)) { if (HasExtension("GLX_EXT_swap_control", extensions)) {
_this->gl_data->glXSwapIntervalEXT = _this->gl_data->glXSwapIntervalEXT =
(int (*)(Display*,GLXDrawable,int)) (int (*)(Display*,GLXDrawable,int))
X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT"); 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 */ /* Check for GLX_MESA_swap_control */
@ -615,9 +623,11 @@ static int swapinterval = -1;
int int
X11_GL_SetSwapInterval(_THIS, int interval) 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; Display *display = ((SDL_VideoData *) _this->driverdata)->display;
const SDL_WindowData *windowdata = (SDL_WindowData *) const SDL_WindowData *windowdata = (SDL_WindowData *)
_this->current_glwin->driverdata; _this->current_glwin->driverdata;
@ -625,7 +635,6 @@ X11_GL_SetSwapInterval(_THIS, int interval)
status = _this->gl_data->glXSwapIntervalEXT(display,drawable,interval); status = _this->gl_data->glXSwapIntervalEXT(display,drawable,interval);
if (status != 0) { if (status != 0) {
SDL_SetError("glxSwapIntervalEXT failed"); SDL_SetError("glxSwapIntervalEXT failed");
status = -1;
} else { } else {
swapinterval = interval; swapinterval = interval;
} }
@ -633,7 +642,6 @@ X11_GL_SetSwapInterval(_THIS, int interval)
status = _this->gl_data->glXSwapIntervalMESA(interval); status = _this->gl_data->glXSwapIntervalMESA(interval);
if (status != 0) { if (status != 0) {
SDL_SetError("glxSwapIntervalMESA failed"); SDL_SetError("glxSwapIntervalMESA failed");
status = -1;
} else { } else {
swapinterval = interval; swapinterval = interval;
} }
@ -641,13 +649,11 @@ X11_GL_SetSwapInterval(_THIS, int interval)
status = _this->gl_data->glXSwapIntervalSGI(interval); status = _this->gl_data->glXSwapIntervalSGI(interval);
if (status != 0) { if (status != 0) {
SDL_SetError("glxSwapIntervalSGI failed"); SDL_SetError("glxSwapIntervalSGI failed");
status = -1;
} else { } else {
swapinterval = interval; swapinterval = interval;
} }
} else { } else {
SDL_Unsupported(); SDL_Unsupported();
status = -1;
} }
return status; return status;
} }
@ -660,10 +666,23 @@ X11_GL_GetSwapInterval(_THIS)
const SDL_WindowData *windowdata = (SDL_WindowData *) const SDL_WindowData *windowdata = (SDL_WindowData *)
_this->current_glwin->driverdata; _this->current_glwin->driverdata;
Window drawable = windowdata->xwindow; 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, _this->gl_data->glXQueryDrawable(display, drawable,
GLX_SWAP_INTERVAL_EXT, &value); GLX_LATE_SWAPS_TEAR_EXT,
return (int) value; &allow_late_swap_tearing);
}
_this->gl_data->glXQueryDrawable(display, drawable,
GLX_SWAP_INTERVAL_EXT, &interval);
if ((allow_late_swap_tearing) && (interval > 0)) {
return -((int) interval);
}
return (int) interval;
} else if (_this->gl_data->glXGetSwapIntervalMESA) { } else if (_this->gl_data->glXGetSwapIntervalMESA) {
return _this->gl_data->glXGetSwapIntervalMESA(); return _this->gl_data->glXGetSwapIntervalMESA();
} else { } else {

View file

@ -30,6 +30,7 @@
struct SDL_GLDriverData struct SDL_GLDriverData
{ {
SDL_bool HAS_GLX_EXT_visual_rating; SDL_bool HAS_GLX_EXT_visual_rating;
SDL_bool HAS_GLX_EXT_swap_control_tear;
void *(*glXGetProcAddress) (const GLubyte*); void *(*glXGetProcAddress) (const GLubyte*);
XVisualInfo *(*glXChooseVisual) (Display*,int,int*); XVisualInfo *(*glXChooseVisual) (Display*,int,int*);

View file

@ -240,18 +240,21 @@ main(int argc, char *argv[])
} }
if (state->render_flags & SDL_RENDERER_PRESENTVSYNC) { if (state->render_flags & SDL_RENDERER_PRESENTVSYNC) {
/* try late-swap-tearing first. If not supported, try normal vsync. */
if (SDL_GL_SetSwapInterval(-1) == -1) {
SDL_GL_SetSwapInterval(1); SDL_GL_SetSwapInterval(1);
}
} else { } else {
SDL_GL_SetSwapInterval(0); SDL_GL_SetSwapInterval(0); /* disable vsync. */
} }
SDL_GetCurrentDisplayMode(0, &mode); 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("\n");
printf("Vendor : %s\n", glGetString(GL_VENDOR)); printf("Vendor : %s\n", glGetString(GL_VENDOR));
printf("Renderer : %s\n", glGetString(GL_RENDERER)); printf("Renderer : %s\n", glGetString(GL_RENDERER));
printf("Version : %s\n", glGetString(GL_VERSION)); printf("Version : %s\n", glGetString(GL_VERSION));
printf("Extensions : %s\n", glGetString(GL_EXTENSIONS));
printf("\n"); printf("\n");
status = SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value); status = SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value);