Add support for (GLX|WGL)_EXT_swap_control_tear.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 01 Aug 2012 20:29:36 -0400
changeset 638264d54101773a
parent 6381 9da3d60cf531
child 6383 869effc44c41
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.
include/SDL_video.h
src/video/SDL_video.c
src/video/cocoa/SDL_cocoaopengl.m
src/video/directfb/SDL_DirectFB_opengl.c
src/video/pandora/SDL_pandora.c
src/video/windows/SDL_windowsopengl.c
src/video/windows/SDL_windowsopengl.h
src/video/x11/SDL_x11opengl.c
src/video/x11/SDL_x11opengl.h
test/testgl2.c
     1.1 --- a/include/SDL_video.h	Tue Jul 31 16:55:09 2012 -0700
     1.2 +++ b/include/SDL_video.h	Wed Aug 01 20:29:36 2012 -0400
     1.3 @@ -789,7 +789,9 @@
     1.4   *  \brief Set the swap interval for the current OpenGL context.
     1.5   *  
     1.6   *  \param interval 0 for immediate updates, 1 for updates synchronized with the
     1.7 - *                  vertical retrace.
     1.8 + *                  vertical retrace. If the system supports it, you may
     1.9 + *                  specify -1 to allow late swaps to happen immediately
    1.10 + *                  instead of waiting for the next retrace.
    1.11   *  
    1.12   *  \return 0 on success, or -1 if setting the swap interval is not supported.
    1.13   *  
    1.14 @@ -801,8 +803,10 @@
    1.15   *  \brief Get the swap interval for the current OpenGL context.
    1.16   *  
    1.17   *  \return 0 if there is no vertical retrace synchronization, 1 if the buffer 
    1.18 - *          swap is synchronized with the vertical retrace, and -1 if getting 
    1.19 - *          the swap interval is not supported.
    1.20 + *          swap is synchronized with the vertical retrace, and -1 if late
    1.21 + *          swaps happen immediately instead of waiting for the next retrace.
    1.22 + *          If the system can't determine the swap interval, or there isn't a
    1.23 + *          valid current context, this will return 0 as a safe default.
    1.24   *  
    1.25   *  \sa SDL_GL_SetSwapInterval()
    1.26   */
     2.1 --- a/src/video/SDL_video.c	Tue Jul 31 16:55:09 2012 -0700
     2.2 +++ b/src/video/SDL_video.c	Wed Aug 01 20:29:36 2012 -0400
     2.3 @@ -2578,16 +2578,13 @@
     2.4  SDL_GL_GetSwapInterval(void)
     2.5  {
     2.6      if (!_this) {
     2.7 -        SDL_UninitializedVideo();
     2.8 -        return -1;
     2.9 +        return 0;
    2.10      } else if (_this->current_glctx == NULL) {
    2.11 -        SDL_SetError("No OpenGL context has been made current");
    2.12 -        return -1;
    2.13 +        return 0;
    2.14      } else if (_this->GL_GetSwapInterval) {
    2.15          return _this->GL_GetSwapInterval(_this);
    2.16      } else {
    2.17 -        SDL_SetError("Getting the swap interval is not supported");
    2.18 -        return -1;
    2.19 +        return 0;
    2.20      }
    2.21  }
    2.22  
     3.1 --- a/src/video/cocoa/SDL_cocoaopengl.m	Tue Jul 31 16:55:09 2012 -0700
     3.2 +++ b/src/video/cocoa/SDL_cocoaopengl.m	Wed Aug 01 20:29:36 2012 -0400
     3.3 @@ -250,7 +250,7 @@
     3.4      NSAutoreleasePool *pool;
     3.5      NSOpenGLContext *nscontext;
     3.6      GLint value;
     3.7 -    int status;
     3.8 +    int status = 0;
     3.9  
    3.10      pool = [[NSAutoreleasePool alloc] init];
    3.11  
    3.12 @@ -258,9 +258,6 @@
    3.13      if (nscontext != nil) {
    3.14          [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
    3.15          status = (int)value;
    3.16 -    } else {
    3.17 -        SDL_SetError("No current OpenGL context");
    3.18 -        status = -1;
    3.19      }
    3.20  
    3.21      [pool release];
     4.1 --- a/src/video/directfb/SDL_DirectFB_opengl.c	Tue Jul 31 16:55:09 2012 -0700
     4.2 +++ b/src/video/directfb/SDL_DirectFB_opengl.c	Wed Aug 01 20:29:36 2012 -0400
     4.3 @@ -250,8 +250,7 @@
     4.4  int
     4.5  DirectFB_GL_GetSwapInterval(_THIS)
     4.6  {
     4.7 -    SDL_Unsupported();
     4.8 -    return -1;
     4.9 +    return 0;
    4.10  }
    4.11  
    4.12  void
     5.1 --- a/src/video/pandora/SDL_pandora.c	Tue Jul 31 16:55:09 2012 -0700
     5.2 +++ b/src/video/pandora/SDL_pandora.c	Wed Aug 01 20:29:36 2012 -0400
     5.3 @@ -796,15 +796,7 @@
     5.4  int
     5.5  PND_gl_getswapinterval(_THIS)
     5.6  {
     5.7 -    SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
     5.8 -
     5.9 -    if (phdata->egl_initialized != SDL_TRUE) {
    5.10 -        SDL_SetError("PND: GLES initialization failed, no OpenGL ES support");
    5.11 -        return -1;
    5.12 -    }
    5.13 -
    5.14 -    /* Return default swap interval value */
    5.15 -    return phdata->swapinterval;
    5.16 +    return ((SDL_VideoData *) _this->driverdata)->swapinterval;
    5.17  }
    5.18  
    5.19  void
     6.1 --- a/src/video/windows/SDL_windowsopengl.c	Tue Jul 31 16:55:09 2012 -0700
     6.2 +++ b/src/video/windows/SDL_windowsopengl.c	Wed Aug 01 20:29:36 2012 -0400
     6.3 @@ -112,10 +112,6 @@
     6.4          GetProcAddress(handle, "wglDeleteContext");
     6.5      _this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC))
     6.6          GetProcAddress(handle, "wglMakeCurrent");
     6.7 -    _this->gl_data->wglSwapIntervalEXT = (void (WINAPI *) (int))
     6.8 -        GetProcAddress(handle, "wglSwapIntervalEXT");
     6.9 -    _this->gl_data->wglGetSwapIntervalEXT = (int (WINAPI *) (void))
    6.10 -        GetProcAddress(handle, "wglGetSwapIntervalEXT");
    6.11  
    6.12      if (!_this->gl_data->wglGetProcAddress ||
    6.13          !_this->gl_data->wglCreateContext ||
    6.14 @@ -341,7 +337,7 @@
    6.15      }
    6.16  
    6.17      /* Check for WGL_ARB_pixel_format */
    6.18 -    _this->gl_data->WGL_ARB_pixel_format = 0;
    6.19 +    _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_FALSE;
    6.20      if (HasExtension("WGL_ARB_pixel_format", extensions)) {
    6.21          _this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *)
    6.22                                                     (HDC, const int *,
    6.23 @@ -354,16 +350,20 @@
    6.24  
    6.25          if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
    6.26              (_this->gl_data->wglGetPixelFormatAttribivARB != NULL)) {
    6.27 -            _this->gl_data->WGL_ARB_pixel_format = 1;
    6.28 +            _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_TRUE;
    6.29          }
    6.30      }
    6.31  
    6.32      /* Check for WGL_EXT_swap_control */
    6.33 +    _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_FALSE;
    6.34      if (HasExtension("WGL_EXT_swap_control", extensions)) {
    6.35          _this->gl_data->wglSwapIntervalEXT =
    6.36              WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
    6.37          _this->gl_data->wglGetSwapIntervalEXT =
    6.38              WIN_GL_GetProcAddress(_this, "wglGetSwapIntervalEXT");
    6.39 +        if (HasExtension("WGL_EXT_swap_control_tear", extensions)) {
    6.40 +            _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_TRUE;
    6.41 +        }
    6.42      } else {
    6.43          _this->gl_data->wglSwapIntervalEXT = NULL;
    6.44          _this->gl_data->wglGetSwapIntervalEXT = NULL;
    6.45 @@ -397,7 +397,7 @@
    6.46  
    6.47          WIN_GL_InitExtensions(_this, hdc);
    6.48  
    6.49 -        if (_this->gl_data->WGL_ARB_pixel_format) {
    6.50 +        if (_this->gl_data->HAS_WGL_ARB_pixel_format) {
    6.51              _this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
    6.52                                                      1, &pixel_format,
    6.53                                                      &matching);
    6.54 @@ -611,7 +611,9 @@
    6.55  int
    6.56  WIN_GL_SetSwapInterval(_THIS, int interval)
    6.57  {
    6.58 -    if (_this->gl_data->wglSwapIntervalEXT) {
    6.59 +    if ((interval < 0) && (!_this->gl_data->HAS_WGL_EXT_swap_control_tear)) {
    6.60 +        SDL_SetError("Negative swap interval unsupported in this GL");
    6.61 +    } else if (_this->gl_data->wglSwapIntervalEXT) {
    6.62          _this->gl_data->wglSwapIntervalEXT(interval);
    6.63          return 0;
    6.64      } else {
    6.65 @@ -626,8 +628,8 @@
    6.66      if (_this->gl_data->wglGetSwapIntervalEXT) {
    6.67          return _this->gl_data->wglGetSwapIntervalEXT();
    6.68      } else {
    6.69 -        SDL_Unsupported();
    6.70 -        return -1;
    6.71 +        /*SDL_Unsupported();*/
    6.72 +        return 0;  /* just say we're unsync'd. */
    6.73      }
    6.74  }
    6.75  
     7.1 --- a/src/video/windows/SDL_windowsopengl.h	Tue Jul 31 16:55:09 2012 -0700
     7.2 +++ b/src/video/windows/SDL_windowsopengl.h	Wed Aug 01 20:29:36 2012 -0400
     7.3 @@ -27,7 +27,8 @@
     7.4  
     7.5  struct SDL_GLDriverData
     7.6  {
     7.7 -    int WGL_ARB_pixel_format;
     7.8 +    SDL_bool HAS_WGL_ARB_pixel_format;
     7.9 +    SDL_bool HAS_WGL_EXT_swap_control_tear;
    7.10  
    7.11      void *(WINAPI * wglGetProcAddress) (const char *proc);
    7.12        HGLRC(WINAPI * wglCreateContext) (HDC hdc);
     8.1 --- a/src/video/x11/SDL_x11opengl.c	Tue Jul 31 16:55:09 2012 -0700
     8.2 +++ b/src/video/x11/SDL_x11opengl.c	Wed Aug 01 20:29:36 2012 -0400
     8.3 @@ -105,6 +105,10 @@
     8.4  #define GLX_MAX_SWAP_INTERVAL_EXT          0x20F2
     8.5  #endif
     8.6  
     8.7 +#ifndef GLX_EXT_swap_control_tear
     8.8 +#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
     8.9 +#endif
    8.10 +
    8.11  #define OPENGL_REQUIRES_DLOPEN
    8.12  #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
    8.13  #include <dlfcn.h>
    8.14 @@ -318,11 +322,15 @@
    8.15          extensions = NULL;
    8.16      }
    8.17  
    8.18 -    /* Check for GLX_EXT_swap_control */
    8.19 +    /* Check for GLX_EXT_swap_control(_tear) */
    8.20 +    _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
    8.21      if (HasExtension("GLX_EXT_swap_control", extensions)) {
    8.22          _this->gl_data->glXSwapIntervalEXT =
    8.23              (int (*)(Display*,GLXDrawable,int))
    8.24                  X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
    8.25 +        if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
    8.26 +            _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
    8.27 +        }
    8.28      }
    8.29  
    8.30      /* Check for GLX_MESA_swap_control */
    8.31 @@ -615,9 +623,11 @@
    8.32  int
    8.33  X11_GL_SetSwapInterval(_THIS, int interval)
    8.34  {
    8.35 -    int status;
    8.36 +    int status = -1;
    8.37  
    8.38 -    if (_this->gl_data->glXSwapIntervalEXT) {
    8.39 +    if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
    8.40 +        SDL_SetError("Negative swap interval unsupported in this GL");
    8.41 +    } else if (_this->gl_data->glXSwapIntervalEXT) {
    8.42          Display *display = ((SDL_VideoData *) _this->driverdata)->display;
    8.43          const SDL_WindowData *windowdata = (SDL_WindowData *)
    8.44              _this->current_glwin->driverdata;
    8.45 @@ -625,7 +635,6 @@
    8.46          status = _this->gl_data->glXSwapIntervalEXT(display,drawable,interval);
    8.47          if (status != 0) {
    8.48              SDL_SetError("glxSwapIntervalEXT failed");
    8.49 -            status = -1;
    8.50          } else {
    8.51              swapinterval = interval;
    8.52          }
    8.53 @@ -633,7 +642,6 @@
    8.54          status = _this->gl_data->glXSwapIntervalMESA(interval);
    8.55          if (status != 0) {
    8.56              SDL_SetError("glxSwapIntervalMESA failed");
    8.57 -            status = -1;
    8.58          } else {
    8.59              swapinterval = interval;
    8.60          }
    8.61 @@ -641,13 +649,11 @@
    8.62          status = _this->gl_data->glXSwapIntervalSGI(interval);
    8.63          if (status != 0) {
    8.64              SDL_SetError("glxSwapIntervalSGI failed");
    8.65 -            status = -1;
    8.66          } else {
    8.67              swapinterval = interval;
    8.68          }
    8.69      } else {
    8.70          SDL_Unsupported();
    8.71 -        status = -1;
    8.72      }
    8.73      return status;
    8.74  }
    8.75 @@ -660,10 +666,23 @@
    8.76          const SDL_WindowData *windowdata = (SDL_WindowData *)
    8.77              _this->current_glwin->driverdata;
    8.78          Window drawable = windowdata->xwindow;
    8.79 -        unsigned int value = 0;
    8.80 +        unsigned int allow_late_swap_tearing = 0;
    8.81 +        unsigned int interval = 0;
    8.82 +
    8.83 +        if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
    8.84 +            _this->gl_data->glXQueryDrawable(display, drawable,
    8.85 +                                            GLX_LATE_SWAPS_TEAR_EXT,
    8.86 +                                            &allow_late_swap_tearing);
    8.87 +        }
    8.88 +
    8.89          _this->gl_data->glXQueryDrawable(display, drawable,
    8.90 -                                         GLX_SWAP_INTERVAL_EXT, &value);
    8.91 -        return (int) value;
    8.92 +                                         GLX_SWAP_INTERVAL_EXT, &interval);
    8.93 +
    8.94 +        if ((allow_late_swap_tearing) && (interval > 0)) {
    8.95 +            return -((int) interval);
    8.96 +        }
    8.97 +
    8.98 +        return (int) interval;
    8.99      } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   8.100          return _this->gl_data->glXGetSwapIntervalMESA();
   8.101      } else {
     9.1 --- a/src/video/x11/SDL_x11opengl.h	Tue Jul 31 16:55:09 2012 -0700
     9.2 +++ b/src/video/x11/SDL_x11opengl.h	Wed Aug 01 20:29:36 2012 -0400
     9.3 @@ -30,6 +30,7 @@
     9.4  struct SDL_GLDriverData
     9.5  {
     9.6      SDL_bool HAS_GLX_EXT_visual_rating;
     9.7 +    SDL_bool HAS_GLX_EXT_swap_control_tear;
     9.8  
     9.9      void *(*glXGetProcAddress) (const GLubyte*);
    9.10      XVisualInfo *(*glXChooseVisual) (Display*,int,int*);
    10.1 --- a/test/testgl2.c	Tue Jul 31 16:55:09 2012 -0700
    10.2 +++ b/test/testgl2.c	Wed Aug 01 20:29:36 2012 -0400
    10.3 @@ -240,18 +240,21 @@
    10.4      }
    10.5  
    10.6      if (state->render_flags & SDL_RENDERER_PRESENTVSYNC) {
    10.7 -        SDL_GL_SetSwapInterval(1);
    10.8 +        /* try late-swap-tearing first. If not supported, try normal vsync. */
    10.9 +        if (SDL_GL_SetSwapInterval(-1) == -1) {
   10.10 +            SDL_GL_SetSwapInterval(1);
   10.11 +        }
   10.12      } else {
   10.13 -        SDL_GL_SetSwapInterval(0);
   10.14 +        SDL_GL_SetSwapInterval(0);  /* disable vsync. */
   10.15      }
   10.16  
   10.17      SDL_GetCurrentDisplayMode(0, &mode);
   10.18 -    printf("Screen BPP: %d\n", SDL_BITSPERPIXEL(mode.format));
   10.19 +    printf("Screen BPP    : %d\n", SDL_BITSPERPIXEL(mode.format));
   10.20 +    printf("Swap Interval : %d\n", SDL_GL_GetSwapInterval());
   10.21      printf("\n");
   10.22 -    printf("Vendor     : %s\n", glGetString(GL_VENDOR));
   10.23 -    printf("Renderer   : %s\n", glGetString(GL_RENDERER));
   10.24 -    printf("Version    : %s\n", glGetString(GL_VERSION));
   10.25 -    printf("Extensions : %s\n", glGetString(GL_EXTENSIONS));
   10.26 +    printf("Vendor        : %s\n", glGetString(GL_VENDOR));
   10.27 +    printf("Renderer      : %s\n", glGetString(GL_RENDERER));
   10.28 +    printf("Version       : %s\n", glGetString(GL_VERSION));
   10.29      printf("\n");
   10.30  
   10.31      status = SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value);