Navigation Menu

Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
Add support for (GLX|WGL)_EXT_swap_control_tear.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
icculus committed Aug 2, 2012
1 parent be11e0f commit e5c2fb9
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 52 deletions.
10 changes: 7 additions & 3 deletions include/SDL_video.h
Expand Up @@ -789,7 +789,9 @@ extern DECLSPEC int SDLCALL SDL_GL_MakeCurrent(SDL_Window * window,
* \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.
*
Expand All @@ -801,8 +803,10 @@ extern DECLSPEC int SDLCALL SDL_GL_SetSwapInterval(int interval);
* \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()
*/
Expand Down
9 changes: 3 additions & 6 deletions src/video/SDL_video.c
Expand Up @@ -2578,16 +2578,13 @@ int
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;
}
}

Expand Down
5 changes: 1 addition & 4 deletions src/video/cocoa/SDL_cocoaopengl.m
Expand Up @@ -250,17 +250,14 @@
NSAutoreleasePool *pool;
NSOpenGLContext *nscontext;
GLint value;
int status;
int status = 0;

pool = [[NSAutoreleasePool alloc] init];

nscontext = [NSOpenGLContext currentContext];
if (nscontext != nil) {
[nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
status = (int)value;
} else {
SDL_SetError("No current OpenGL context");
status = -1;
}

[pool release];
Expand Down
3 changes: 1 addition & 2 deletions src/video/directfb/SDL_DirectFB_opengl.c
Expand Up @@ -250,8 +250,7 @@ DirectFB_GL_SetSwapInterval(_THIS, int interval)
int
DirectFB_GL_GetSwapInterval(_THIS)
{
SDL_Unsupported();
return -1;
return 0;
}

void
Expand Down
10 changes: 1 addition & 9 deletions src/video/pandora/SDL_pandora.c
Expand Up @@ -796,15 +796,7 @@ PND_gl_setswapinterval(_THIS, int interval)
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
Expand Down
22 changes: 12 additions & 10 deletions src/video/windows/SDL_windowsopengl.c
Expand Up @@ -112,10 +112,6 @@ WIN_GL_LoadLibrary(_THIS, const char *path)
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 ||
Expand Down Expand Up @@ -341,7 +337,7 @@ WIN_GL_InitExtensions(_THIS, HDC hdc)
}

/* 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 *,
Expand All @@ -354,16 +350,20 @@ WIN_GL_InitExtensions(_THIS, HDC hdc)

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;
Expand Down Expand Up @@ -397,7 +397,7 @@ WIN_GL_ChoosePixelFormatARB(_THIS, int *iAttribs, float *fAttribs)

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);
Expand Down Expand Up @@ -611,7 +611,9 @@ WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
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 {
Expand All @@ -626,8 +628,8 @@ WIN_GL_GetSwapInterval(_THIS)
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. */
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/video/windows/SDL_windowsopengl.h
Expand Up @@ -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);
Expand Down
39 changes: 29 additions & 10 deletions src/video/x11/SDL_x11opengl.c
Expand Up @@ -105,6 +105,10 @@ typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
#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>
Expand Down Expand Up @@ -318,11 +322,15 @@ X11_GL_InitExtensions(_THIS)
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 */
Expand Down Expand Up @@ -615,39 +623,37 @@ static int swapinterval = -1;
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;
Window drawable = windowdata->xwindow;
status = _this->gl_data->glXSwapIntervalEXT(display,drawable,interval);
if (status != 0) {
SDL_SetError("glxSwapIntervalEXT failed");
status = -1;
} else {
swapinterval = interval;
}
} else if (_this->gl_data->glXSwapIntervalMESA) {
status = _this->gl_data->glXSwapIntervalMESA(interval);
if (status != 0) {
SDL_SetError("glxSwapIntervalMESA failed");
status = -1;
} else {
swapinterval = interval;
}
} else if (_this->gl_data->glXSwapIntervalSGI) {
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;
}
Expand All @@ -660,10 +666,23 @@ X11_GL_GetSwapInterval(_THIS)
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 {
Expand Down
1 change: 1 addition & 0 deletions src/video/x11/SDL_x11opengl.h
Expand Up @@ -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*);
Expand Down
17 changes: 10 additions & 7 deletions test/testgl2.c
Expand Up @@ -240,18 +240,21 @@ main(int argc, char *argv[])
}

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);
Expand Down

0 comments on commit e5c2fb9

Please sign in to comment.