src/video/x11/SDL_x11opengl.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 11 Jul 2013 22:59:20 -0700
changeset 7412 50211a1fd557
parent 7191 75360622e65f
child 7413 30d42f6f2e8d
permissions -rw-r--r--
Fixed bug 1946 - OpenGL contexts in threads

The SDL OpenGL context code is now properly thread aware. There are two new functions which return the current OpenGL window and context for the current thread.

There are still places in the cocoa driver where the OpenGL context needs to be updated when the view changes. These will need a different solution and still use the last globally set context to avoid changing behavior.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_X11
    24 
    25 #include "SDL_x11video.h"
    26 #include "SDL_assert.h"
    27 
    28 /* GLX implementation of SDL OpenGL support */
    29 
    30 #if SDL_VIDEO_OPENGL_GLX
    31 #include "SDL_loadso.h"
    32 #include "SDL_x11opengles.h"
    33 
    34 #if defined(__IRIX__)
    35 /* IRIX doesn't have a GL library versioning system */
    36 #define DEFAULT_OPENGL  "libGL.so"
    37 #elif defined(__MACOSX__)
    38 #define DEFAULT_OPENGL  "/usr/X11R6/lib/libGL.1.dylib"
    39 #elif defined(__QNXNTO__)
    40 #define DEFAULT_OPENGL  "libGL.so.3"
    41 #else
    42 #define DEFAULT_OPENGL  "libGL.so.1"
    43 #endif
    44 
    45 #ifndef GLX_NONE_EXT
    46 #define GLX_NONE_EXT                       0x8000
    47 #endif
    48 
    49 #ifndef GLX_ARB_multisample
    50 #define GLX_ARB_multisample
    51 #define GLX_SAMPLE_BUFFERS_ARB             100000
    52 #define GLX_SAMPLES_ARB                    100001
    53 #endif
    54 
    55 #ifndef GLX_EXT_visual_rating
    56 #define GLX_EXT_visual_rating
    57 #define GLX_VISUAL_CAVEAT_EXT              0x20
    58 #define GLX_NONE_EXT                       0x8000
    59 #define GLX_SLOW_VISUAL_EXT                0x8001
    60 #define GLX_NON_CONFORMANT_VISUAL_EXT      0x800D
    61 #endif
    62 
    63 #ifndef GLX_EXT_visual_info
    64 #define GLX_EXT_visual_info
    65 #define GLX_X_VISUAL_TYPE_EXT              0x22
    66 #define GLX_DIRECT_COLOR_EXT               0x8003
    67 #endif
    68 
    69 #ifndef GLX_ARB_create_context
    70 #define GLX_ARB_create_context
    71 #define GLX_CONTEXT_MAJOR_VERSION_ARB      0x2091
    72 #define GLX_CONTEXT_MINOR_VERSION_ARB      0x2092
    73 #define GLX_CONTEXT_FLAGS_ARB              0x2094
    74 #define GLX_CONTEXT_DEBUG_BIT_ARB          0x0001
    75 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
    76 
    77 /* Typedef for the GL 3.0 context creation function */
    78 typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
    79                                                         GLXFBConfig config,
    80                                                         GLXContext
    81                                                         share_context,
    82                                                         Bool direct,
    83                                                         const int
    84                                                         *attrib_list);
    85 #endif
    86 
    87 #ifndef GLX_ARB_create_context_profile
    88 #define GLX_ARB_create_context_profile
    89 #define GLX_CONTEXT_PROFILE_MASK_ARB       0x9126
    90 #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB   0x00000001
    91 #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
    92 #endif
    93 
    94 #ifndef GLX_ARB_create_context_robustness
    95 #define GLX_ARB_create_context_robustness
    96 #define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB  0x00000004
    97 #define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB     0x8256
    98 #define GLX_NO_RESET_NOTIFICATION_ARB                   0x8261
    99 #define GLX_LOSE_CONTEXT_ON_RESET_ARB                   0x8252
   100 #endif
   101 
   102 #ifndef GLX_EXT_create_context_es2_profile
   103 #define GLX_EXT_create_context_es2_profile
   104 #ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
   105 #define GLX_CONTEXT_ES2_PROFILE_BIT_EXT    0x00000002
   106 #endif
   107 #endif
   108 
   109 #ifndef GLX_EXT_swap_control
   110 #define GLX_SWAP_INTERVAL_EXT              0x20F1
   111 #define GLX_MAX_SWAP_INTERVAL_EXT          0x20F2
   112 #endif
   113 
   114 #ifndef GLX_EXT_swap_control_tear
   115 #define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
   116 #endif
   117 
   118 #define OPENGL_REQUIRES_DLOPEN
   119 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   120 #include <dlfcn.h>
   121 #define GL_LoadObject(X)    dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
   122 #define GL_LoadFunction     dlsym
   123 #define GL_UnloadObject     dlclose
   124 #else
   125 #define GL_LoadObject   SDL_LoadObject
   126 #define GL_LoadFunction SDL_LoadFunction
   127 #define GL_UnloadObject SDL_UnloadObject
   128 #endif
   129 
   130 static void X11_GL_InitExtensions(_THIS);
   131 
   132 
   133 int
   134 X11_GL_LoadLibrary(_THIS, const char *path)
   135 {
   136     void *handle;
   137 
   138     if (_this->gl_data) {
   139         return SDL_SetError("OpenGL context already created");
   140     }
   141 
   142     /* If SDL_GL_CONTEXT_EGL has been changed to 1, switch over to X11_GLES functions  */
   143     if (_this->gl_config.use_egl == 1) {
   144 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   145         _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
   146         _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
   147         _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
   148         _this->GL_CreateContext = X11_GLES_CreateContext;
   149         _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
   150         _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
   151         _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
   152         _this->GL_SwapWindow = X11_GLES_SwapWindow;
   153         _this->GL_DeleteContext = X11_GLES_DeleteContext;
   154         return X11_GLES_LoadLibrary(_this, path);
   155 #else
   156         return SDL_SetError("SDL not configured with OpenGL ES/EGL support");
   157 #endif
   158     }
   159 
   160 
   161     /* Load the OpenGL library */
   162     if (path == NULL) {
   163         path = SDL_getenv("SDL_OPENGL_LIBRARY");
   164     }
   165     if (path == NULL) {
   166         path = DEFAULT_OPENGL;
   167     }
   168     _this->gl_config.dll_handle = GL_LoadObject(path);
   169     if (!_this->gl_config.dll_handle) {
   170 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   171         SDL_SetError("Failed loading %s: %s", path, dlerror());
   172 #endif
   173         return -1;
   174     }
   175     SDL_strlcpy(_this->gl_config.driver_path, path,
   176                 SDL_arraysize(_this->gl_config.driver_path));
   177 
   178     /* Allocate OpenGL memory */
   179     _this->gl_data =
   180         (struct SDL_GLDriverData *) SDL_calloc(1,
   181                                                sizeof(struct
   182                                                       SDL_GLDriverData));
   183     if (!_this->gl_data) {
   184         return SDL_OutOfMemory();
   185     }
   186 
   187     /* Load function pointers */
   188     handle = _this->gl_config.dll_handle;
   189     _this->gl_data->glXGetProcAddress =
   190         (void *(*)(const GLubyte *))
   191             GL_LoadFunction(handle, "glXGetProcAddressARB");
   192     _this->gl_data->glXChooseVisual =
   193         (XVisualInfo * (*)(Display *, int, int *))
   194             X11_GL_GetProcAddress(_this, "glXChooseVisual");
   195     _this->gl_data->glXCreateContext =
   196         (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
   197             X11_GL_GetProcAddress(_this, "glXCreateContext");
   198     _this->gl_data->glXDestroyContext =
   199         (void (*)(Display *, GLXContext))
   200             X11_GL_GetProcAddress(_this, "glXDestroyContext");
   201     _this->gl_data->glXMakeCurrent =
   202         (int (*)(Display *, GLXDrawable, GLXContext))
   203             X11_GL_GetProcAddress(_this, "glXMakeCurrent");
   204     _this->gl_data->glXSwapBuffers =
   205         (void (*)(Display *, GLXDrawable))
   206             X11_GL_GetProcAddress(_this, "glXSwapBuffers");
   207     _this->gl_data->glXQueryDrawable =
   208         (void (*)(Display*,GLXDrawable,int,unsigned int*))
   209             X11_GL_GetProcAddress(_this, "glXQueryDrawable");
   210 
   211     if (!_this->gl_data->glXChooseVisual ||
   212         !_this->gl_data->glXCreateContext ||
   213         !_this->gl_data->glXDestroyContext ||
   214         !_this->gl_data->glXMakeCurrent ||
   215         !_this->gl_data->glXSwapBuffers) {
   216         return SDL_SetError("Could not retrieve OpenGL functions");
   217     }
   218 
   219     /* Initialize extensions */
   220     X11_GL_InitExtensions(_this);
   221 
   222     return 0;
   223 }
   224 
   225 void *
   226 X11_GL_GetProcAddress(_THIS, const char *proc)
   227 {
   228     if (_this->gl_data->glXGetProcAddress) {
   229         return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
   230     }
   231     return GL_LoadFunction(_this->gl_config.dll_handle, proc);
   232 }
   233 
   234 void
   235 X11_GL_UnloadLibrary(_THIS)
   236 {
   237     /* Don't actually unload the library, since it may have registered
   238      * X11 shutdown hooks, per the notes at:
   239      * http://dri.sourceforge.net/doc/DRIuserguide.html
   240      */
   241 #if 0
   242     GL_UnloadObject(_this->gl_config.dll_handle);
   243     _this->gl_config.dll_handle = NULL;
   244 #endif
   245 
   246     /* Free OpenGL memory */
   247     if (_this->gl_data) {
   248         SDL_free(_this->gl_data);
   249         _this->gl_data = NULL;
   250     }
   251 }
   252 
   253 static SDL_bool
   254 HasExtension(const char *extension, const char *extensions)
   255 {
   256     const char *start;
   257     const char *where, *terminator;
   258 
   259     /* Extension names should not have spaces. */
   260     where = SDL_strchr(extension, ' ');
   261     if (where || *extension == '\0')
   262         return SDL_FALSE;
   263 
   264     if (!extensions)
   265         return SDL_FALSE;
   266 
   267     /* It takes a bit of care to be fool-proof about parsing the
   268      * OpenGL extensions string. Don't be fooled by sub-strings,
   269      * etc. */
   270 
   271     start = extensions;
   272 
   273     for (;;) {
   274         where = SDL_strstr(start, extension);
   275         if (!where)
   276             break;
   277 
   278         terminator = where + SDL_strlen(extension);
   279         if (where == start || *(where - 1) == ' ')
   280             if (*terminator == ' ' || *terminator == '\0')
   281                 return SDL_TRUE;
   282 
   283         start = terminator;
   284     }
   285     return SDL_FALSE;
   286 }
   287 
   288 static void
   289 X11_GL_InitExtensions(_THIS)
   290 {
   291     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   292     int screen = DefaultScreen(display);
   293     XVisualInfo *vinfo;
   294     XSetWindowAttributes xattr;
   295     Window w;
   296     GLXContext context;
   297     const char *(*glXQueryExtensionsStringFunc) (Display *, int);
   298     const char *extensions;
   299 
   300     vinfo = X11_GL_GetVisual(_this, display, screen);
   301     if (!vinfo) {
   302         return;
   303     }
   304     xattr.background_pixel = 0;
   305     xattr.border_pixel = 0;
   306     xattr.colormap =
   307         XCreateColormap(display, RootWindow(display, screen), vinfo->visual,
   308                         AllocNone);
   309     w = XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0,
   310                       vinfo->depth, InputOutput, vinfo->visual,
   311                       (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
   312     context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   313     if (context) {
   314         _this->gl_data->glXMakeCurrent(display, w, context);
   315     }
   316     XFree(vinfo);
   317 
   318     glXQueryExtensionsStringFunc =
   319         (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
   320                                                                 "glXQueryExtensionsString");
   321     if (glXQueryExtensionsStringFunc) {
   322         extensions = glXQueryExtensionsStringFunc(display, screen);
   323     } else {
   324         extensions = NULL;
   325     }
   326 
   327     /* Check for GLX_EXT_swap_control(_tear) */
   328     _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
   329     if (HasExtension("GLX_EXT_swap_control", extensions)) {
   330         _this->gl_data->glXSwapIntervalEXT =
   331             (void (*)(Display*,GLXDrawable,int))
   332                 X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
   333         if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
   334             _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
   335         }
   336     }
   337 
   338     /* Check for GLX_MESA_swap_control */
   339     if (HasExtension("GLX_MESA_swap_control", extensions)) {
   340         _this->gl_data->glXSwapIntervalMESA =
   341             (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
   342         _this->gl_data->glXGetSwapIntervalMESA =
   343             (int(*)(void)) X11_GL_GetProcAddress(_this,
   344                                                    "glXGetSwapIntervalMESA");
   345     }
   346 
   347     /* Check for GLX_SGI_swap_control */
   348     if (HasExtension("GLX_SGI_swap_control", extensions)) {
   349         _this->gl_data->glXSwapIntervalSGI =
   350             (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
   351     }
   352 
   353     /* Check for GLX_EXT_visual_rating */
   354     if (HasExtension("GLX_EXT_visual_rating", extensions)) {
   355         _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
   356     }
   357 
   358     /* Check for GLX_EXT_visual_info */
   359     if (HasExtension("GLX_EXT_visual_info", extensions)) {
   360         _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
   361     }
   362 
   363     if (context) {
   364         _this->gl_data->glXMakeCurrent(display, None, NULL);
   365         _this->gl_data->glXDestroyContext(display, context);
   366     }
   367     XDestroyWindow(display, w);
   368     X11_PumpEvents(_this);
   369 }
   370 
   371 /* glXChooseVisual and glXChooseFBConfig have some small differences in
   372  * the attribute encoding, it can be chosen with the for_FBConfig parameter.
   373  */
   374 int
   375 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig)
   376 {
   377     int i = 0;
   378     const int MAX_ATTRIBUTES = 64;
   379 
   380     /* assert buffer is large enough to hold all SDL attributes. */
   381     SDL_assert(size >= MAX_ATTRIBUTES);
   382 
   383     /* Setup our GLX attributes according to the gl_config. */
   384     if( for_FBConfig ) {
   385         attribs[i++] = GLX_RENDER_TYPE;
   386     attribs[i++] = GLX_RGBA_BIT;
   387     } else {
   388         attribs[i++] = GLX_RGBA;
   389     }
   390     attribs[i++] = GLX_RED_SIZE;
   391     attribs[i++] = _this->gl_config.red_size;
   392     attribs[i++] = GLX_GREEN_SIZE;
   393     attribs[i++] = _this->gl_config.green_size;
   394     attribs[i++] = GLX_BLUE_SIZE;
   395     attribs[i++] = _this->gl_config.blue_size;
   396 
   397     if (_this->gl_config.alpha_size) {
   398         attribs[i++] = GLX_ALPHA_SIZE;
   399         attribs[i++] = _this->gl_config.alpha_size;
   400     }
   401 
   402     if (_this->gl_config.double_buffer) {
   403         attribs[i++] = GLX_DOUBLEBUFFER;
   404     if( for_FBConfig )
   405         attribs[i++] = True;
   406     }
   407 
   408     attribs[i++] = GLX_DEPTH_SIZE;
   409     attribs[i++] = _this->gl_config.depth_size;
   410 
   411     if (_this->gl_config.stencil_size) {
   412         attribs[i++] = GLX_STENCIL_SIZE;
   413         attribs[i++] = _this->gl_config.stencil_size;
   414     }
   415 
   416     if (_this->gl_config.accum_red_size) {
   417         attribs[i++] = GLX_ACCUM_RED_SIZE;
   418         attribs[i++] = _this->gl_config.accum_red_size;
   419     }
   420 
   421     if (_this->gl_config.accum_green_size) {
   422         attribs[i++] = GLX_ACCUM_GREEN_SIZE;
   423         attribs[i++] = _this->gl_config.accum_green_size;
   424     }
   425 
   426     if (_this->gl_config.accum_blue_size) {
   427         attribs[i++] = GLX_ACCUM_BLUE_SIZE;
   428         attribs[i++] = _this->gl_config.accum_blue_size;
   429     }
   430 
   431     if (_this->gl_config.accum_alpha_size) {
   432         attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
   433         attribs[i++] = _this->gl_config.accum_alpha_size;
   434     }
   435 
   436     if (_this->gl_config.stereo) {
   437         attribs[i++] = GLX_STEREO;
   438     if( for_FBConfig )
   439         attribs[i++] = True;
   440     }
   441 
   442     if (_this->gl_config.multisamplebuffers) {
   443         attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
   444         attribs[i++] = _this->gl_config.multisamplebuffers;
   445     }
   446 
   447     if (_this->gl_config.multisamplesamples) {
   448         attribs[i++] = GLX_SAMPLES_ARB;
   449         attribs[i++] = _this->gl_config.multisamplesamples;
   450     }
   451 
   452     if (_this->gl_config.accelerated >= 0 &&
   453         _this->gl_data->HAS_GLX_EXT_visual_rating) {
   454         attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
   455         attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
   456                                                       GLX_SLOW_VISUAL_EXT;
   457     }
   458 
   459     /* If we're supposed to use DirectColor visuals, and we've got the
   460        EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
   461     if (X11_UseDirectColorVisuals() &&
   462         _this->gl_data->HAS_GLX_EXT_visual_info) {
   463         attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
   464         attribs[i++] = GLX_DIRECT_COLOR_EXT;
   465     }
   466 
   467     attribs[i++] = None;
   468 
   469     SDL_assert(i <= MAX_ATTRIBUTES);
   470 
   471     return i;
   472 }
   473 
   474 XVisualInfo *
   475 X11_GL_GetVisual(_THIS, Display * display, int screen)
   476 {
   477     XVisualInfo *vinfo;
   478 
   479     /* 64 seems nice. */
   480     int attribs[64];
   481     X11_GL_GetAttributes(_this,display,screen,attribs,64,SDL_FALSE);
   482 
   483     if (!_this->gl_data) {
   484         /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
   485         return NULL;
   486     }
   487 
   488     vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   489     if (!vinfo) {
   490         SDL_SetError("Couldn't find matching GLX visual");
   491     }
   492     return vinfo;
   493 }
   494 
   495 #ifndef GLXBadContext
   496 #define GLXBadContext 0
   497 #endif
   498 #ifndef GLXBadFBConfig
   499 #define GLXBadFBConfig 9
   500 #endif
   501 #ifndef GLXBadProfileARB
   502 #define GLXBadProfileARB 13
   503 #endif
   504 static int (*handler) (Display *, XErrorEvent *) = NULL;
   505 static int
   506 X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e)
   507 {
   508     switch (e->error_code) {
   509     case GLXBadContext:
   510     case GLXBadFBConfig:
   511     case GLXBadProfileARB:
   512     case BadRequest:
   513     case BadMatch:
   514     case BadValue:
   515     case BadAlloc:
   516         return (0);
   517     default:
   518         return (handler(d, e));
   519     }
   520 }
   521 
   522 SDL_GLContext
   523 X11_GL_CreateContext(_THIS, SDL_Window * window)
   524 {
   525     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   526     Display *display = data->videodata->display;
   527     int screen =
   528         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
   529     XWindowAttributes xattr;
   530     XVisualInfo v, *vinfo;
   531     int n;
   532     GLXContext context = NULL, share_context;
   533 
   534     if (_this->gl_config.share_with_current_context) {
   535         share_context = SDL_GL_GetCurrentContext();
   536     } else {
   537         share_context = NULL;
   538     }
   539 
   540     /* We do this to create a clean separation between X and GLX errors. */
   541     XSync(display, False);
   542     handler = XSetErrorHandler(X11_GL_CreateContextErrorHandler);
   543     XGetWindowAttributes(display, data->xwindow, &xattr);
   544     v.screen = screen;
   545     v.visualid = XVisualIDFromVisual(xattr.visual);
   546     vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   547     if (vinfo) {
   548         if (_this->gl_config.major_version < 3 &&
   549             _this->gl_config.profile_mask == 0 &&
   550             _this->gl_config.flags == 0) {
   551             /* Create legacy context */
   552             context =
   553                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   554         } else {
   555             /* If we want a GL 3.0 context or later we need to get a temporary
   556                context to grab the new context creation function */
   557             GLXContext temp_context =
   558                 _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   559             if (temp_context) {
   560                 /* max 8 attributes plus terminator */
   561                 int attribs[9] = {
   562                     GLX_CONTEXT_MAJOR_VERSION_ARB,
   563                     _this->gl_config.major_version,
   564                     GLX_CONTEXT_MINOR_VERSION_ARB,
   565                     _this->gl_config.minor_version,
   566                     0
   567                 };
   568                 int iattr = 4;
   569 
   570                 /* SDL profile bits match GLX profile bits */
   571                 if( _this->gl_config.profile_mask != 0 ) {
   572                     attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   573                     attribs[iattr++] = _this->gl_config.profile_mask;
   574                 }
   575 
   576                 /* SDL flags match GLX flags */
   577                 if( _this->gl_config.flags != 0 ) {
   578                     attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   579                     attribs[iattr++] = _this->gl_config.flags;
   580                 }
   581 
   582                 attribs[iattr++] = 0;
   583 
   584                 /* Get a pointer to the context creation function for GL 3.0 */
   585                 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs =
   586                     (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   587                     glXGetProcAddress((GLubyte *)
   588                                       "glXCreateContextAttribsARB");
   589                 if (!glXCreateContextAttribs) {
   590                     SDL_SetError("GL 3.x is not supported");
   591                     context = temp_context;
   592                 } else {
   593                     int glxAttribs[64];
   594 
   595                     /* Create a GL 3.x context */
   596                     GLXFBConfig *framebuffer_config = NULL;
   597                     int fbcount = 0;
   598                     GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
   599                                                        int screen,
   600                                                        const int *attrib_list,
   601                                                        int *nelements);
   602 
   603                     glXChooseFBConfig =
   604                         (GLXFBConfig *
   605                          (*)(Display *, int, const int *,
   606                              int *)) _this->gl_data->
   607                         glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
   608 
   609                     X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
   610 
   611                     if (!glXChooseFBConfig
   612                         || !(framebuffer_config =
   613                              glXChooseFBConfig(display,
   614                                                DefaultScreen(display), glxAttribs,
   615                                                &fbcount))) {
   616                         SDL_SetError
   617                             ("No good framebuffers found. GL 3.x disabled");
   618                         context = temp_context;
   619                     } else {
   620                         context =
   621                             glXCreateContextAttribs(display,
   622                                                     framebuffer_config[0],
   623                                                     share_context, True, attribs);
   624                         _this->gl_data->glXDestroyContext(display,
   625                                                           temp_context);
   626                     }
   627                 }
   628             }
   629         }
   630         XFree(vinfo);
   631     }
   632     XSync(display, False);
   633     XSetErrorHandler(handler);
   634 
   635     if (!context) {
   636         SDL_SetError("Could not create GL context");
   637         return NULL;
   638     }
   639 
   640     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   641         X11_GL_DeleteContext(_this, context);
   642         return NULL;
   643     }
   644 
   645     return context;
   646 }
   647 
   648 int
   649 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   650 {
   651     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   652     Window drawable =
   653         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   654     GLXContext glx_context = (GLXContext) context;
   655 
   656     if (!_this->gl_data) {
   657         return SDL_SetError("OpenGL not initialized");
   658     }
   659 
   660     if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
   661         return SDL_SetError("Unable to make GL context current");
   662     }
   663 
   664     return 0;
   665 }
   666 
   667 /*
   668    0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
   669    will undo the effect of a previous call with a value that is greater
   670    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   671    argument to glxSwapIntervalSGI and it returns an error if you call it
   672    with 0 as an argument.
   673 */
   674 
   675 static int swapinterval = -1;
   676 int
   677 X11_GL_SetSwapInterval(_THIS, int interval)
   678 {
   679     int status = -1;
   680 
   681     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   682         SDL_SetError("Negative swap interval unsupported in this GL");
   683     } else if (_this->gl_data->glXSwapIntervalEXT) {
   684         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   685         const SDL_WindowData *windowdata = (SDL_WindowData *)
   686             SDL_GL_GetCurrentWindow()->driverdata;
   687 
   688         Window drawable = windowdata->xwindow;
   689 
   690         /*
   691          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   692          * and will be fixed in a future release (probably 319.xx).
   693          *
   694          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   695          * it has the wrong value cached. To work around it, we just run a no-op
   696          * update to the current value.
   697          */
   698         int currentInterval = X11_GL_GetSwapInterval(_this);
   699         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   700         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   701 
   702         status = 0;
   703         swapinterval = interval;
   704     } else if (_this->gl_data->glXSwapIntervalMESA) {
   705         status = _this->gl_data->glXSwapIntervalMESA(interval);
   706         if (status != 0) {
   707             SDL_SetError("glxSwapIntervalMESA failed");
   708         } else {
   709             swapinterval = interval;
   710         }
   711     } else if (_this->gl_data->glXSwapIntervalSGI) {
   712         status = _this->gl_data->glXSwapIntervalSGI(interval);
   713         if (status != 0) {
   714             SDL_SetError("glxSwapIntervalSGI failed");
   715         } else {
   716             swapinterval = interval;
   717         }
   718     } else {
   719         SDL_Unsupported();
   720     }
   721     return status;
   722 }
   723 
   724 int
   725 X11_GL_GetSwapInterval(_THIS)
   726 {
   727     if (_this->gl_data->glXSwapIntervalEXT) {
   728         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   729         const SDL_WindowData *windowdata = (SDL_WindowData *)
   730             SDL_GL_GetCurrentWindow()->driverdata;
   731         Window drawable = windowdata->xwindow;
   732         unsigned int allow_late_swap_tearing = 0;
   733         unsigned int interval = 0;
   734 
   735         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   736             _this->gl_data->glXQueryDrawable(display, drawable,
   737                                             GLX_LATE_SWAPS_TEAR_EXT,
   738                                             &allow_late_swap_tearing);
   739         }
   740 
   741         _this->gl_data->glXQueryDrawable(display, drawable,
   742                                          GLX_SWAP_INTERVAL_EXT, &interval);
   743 
   744         if ((allow_late_swap_tearing) && (interval > 0)) {
   745             return -((int) interval);
   746         }
   747 
   748         return (int) interval;
   749     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   750         return _this->gl_data->glXGetSwapIntervalMESA();
   751     } else {
   752         return swapinterval;
   753     }
   754 }
   755 
   756 void
   757 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   758 {
   759     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   760     Display *display = data->videodata->display;
   761 
   762     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   763 }
   764 
   765 void
   766 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   767 {
   768     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   769     GLXContext glx_context = (GLXContext) context;
   770 
   771     if (!_this->gl_data) {
   772         return;
   773     }
   774     _this->gl_data->glXDestroyContext(display, glx_context);
   775     XSync(display, False);
   776 }
   777 
   778 #endif /* SDL_VIDEO_OPENGL_GLX */
   779 
   780 #endif /* SDL_VIDEO_DRIVER_X11 */
   781 
   782 /* vi: set ts=4 sw=4 expandtab: */