src/video/x11/SDL_x11opengl.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 10 Mar 2013 09:07:23 -0700
changeset 6988 2aed1beaf5bc
parent 6948 84a71440360d
child 7037 3fedf1f25b94
permissions -rw-r--r--
Fixed bug 1749 - SDL_GL_CreateContext() causes fatal X11 protocol errors that should just be caught instead

Lee Salzman

When using SDL_GL_CreateContext() to create a >= 3.0 version or core/forward-compatible context, internally glXCreateContextAttribsARB is used. Mesa in particular seems to be having trouble with this call and returning all sorts of errors, so it is dangerous to poll for the highest GL version by using calls to SDL_GL_CreateContext unless you are sure, a priori, that the call will suceed, defeating the point of its use.

X11 protocol errors are of the following form, with varying details depending on user, but the cause is always SDL_GL_CreateContext as above...

X Error of failed request: GLXBadFBConfig
Major opcode of failed request: 153 (GLX)
Minor opcode of failed request: 34 ()
Serial number of failed request: 215
Current serial number in output stream: 221

These sorts of errors can be temporarily filtered out by setting an X11 error handler to catch and ignore them, which is safe with respect to SDL_GL_CreateContext behavior because this function is allowed to return NULL to indicate failure.

A patch is attached to do this temporary filtering/catching of errors generated by trying to use glXCreateContextAttribs and friends...
     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         SDL_SetError("OpenGL context already created");
   140         return -1;
   141     }
   142 
   143     /* If SDL_GL_CONTEXT_EGL has been changed to 1, switch over to X11_GLES functions  */
   144     if (_this->gl_config.use_egl == 1) {
   145 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   146         _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
   147         _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
   148         _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
   149         _this->GL_CreateContext = X11_GLES_CreateContext;
   150         _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
   151         _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
   152         _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
   153         _this->GL_SwapWindow = X11_GLES_SwapWindow;
   154         _this->GL_DeleteContext = X11_GLES_DeleteContext;
   155         return X11_GLES_LoadLibrary(_this, path);
   156 #else
   157         SDL_SetError("SDL not configured with OpenGL ES/EGL support");
   158         return -1;
   159 #endif
   160     }
   161 
   162 
   163     /* Load the OpenGL library */
   164     if (path == NULL) {
   165         path = SDL_getenv("SDL_OPENGL_LIBRARY");
   166     }
   167     if (path == NULL) {
   168         path = DEFAULT_OPENGL;
   169     }
   170     _this->gl_config.dll_handle = GL_LoadObject(path);
   171     if (!_this->gl_config.dll_handle) {
   172 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   173         SDL_SetError("Failed loading %s: %s", path, dlerror());
   174 #endif
   175         return -1;
   176     }
   177     SDL_strlcpy(_this->gl_config.driver_path, path,
   178                 SDL_arraysize(_this->gl_config.driver_path));
   179 
   180     /* Allocate OpenGL memory */
   181     _this->gl_data =
   182         (struct SDL_GLDriverData *) SDL_calloc(1,
   183                                                sizeof(struct
   184                                                       SDL_GLDriverData));
   185     if (!_this->gl_data) {
   186         SDL_OutOfMemory();
   187         return -1;
   188     }
   189 
   190     /* Load function pointers */
   191     handle = _this->gl_config.dll_handle;
   192     _this->gl_data->glXGetProcAddress =
   193         (void *(*)(const GLubyte *))
   194             GL_LoadFunction(handle, "glXGetProcAddressARB");
   195     _this->gl_data->glXChooseVisual =
   196         (XVisualInfo * (*)(Display *, int, int *))
   197             X11_GL_GetProcAddress(_this, "glXChooseVisual");
   198     _this->gl_data->glXCreateContext =
   199         (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
   200             X11_GL_GetProcAddress(_this, "glXCreateContext");
   201     _this->gl_data->glXDestroyContext =
   202         (void (*)(Display *, GLXContext))
   203             X11_GL_GetProcAddress(_this, "glXDestroyContext");
   204     _this->gl_data->glXMakeCurrent =
   205         (int (*)(Display *, GLXDrawable, GLXContext))
   206             X11_GL_GetProcAddress(_this, "glXMakeCurrent");
   207     _this->gl_data->glXSwapBuffers =
   208         (void (*)(Display *, GLXDrawable))
   209             X11_GL_GetProcAddress(_this, "glXSwapBuffers");
   210     _this->gl_data->glXQueryDrawable =
   211         (void (*)(Display*,GLXDrawable,int,unsigned int*))
   212             X11_GL_GetProcAddress(_this, "glXQueryDrawable");
   213 
   214     if (!_this->gl_data->glXChooseVisual ||
   215         !_this->gl_data->glXCreateContext ||
   216         !_this->gl_data->glXDestroyContext ||
   217         !_this->gl_data->glXMakeCurrent ||
   218         !_this->gl_data->glXSwapBuffers) {
   219         SDL_SetError("Could not retrieve OpenGL functions");
   220         return -1;
   221     }
   222 
   223     /* Initialize extensions */
   224     X11_GL_InitExtensions(_this);
   225 
   226     return 0;
   227 }
   228 
   229 void *
   230 X11_GL_GetProcAddress(_THIS, const char *proc)
   231 {
   232     if (_this->gl_data->glXGetProcAddress) {
   233         return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
   234     }
   235     return GL_LoadFunction(_this->gl_config.dll_handle, proc);
   236 }
   237 
   238 void
   239 X11_GL_UnloadLibrary(_THIS)
   240 {
   241     /* Don't actually unload the library, since it may have registered
   242      * X11 shutdown hooks, per the notes at:
   243      * http://dri.sourceforge.net/doc/DRIuserguide.html
   244      */
   245 #if 0
   246     GL_UnloadObject(_this->gl_config.dll_handle);
   247     _this->gl_config.dll_handle = NULL;
   248 #endif
   249 
   250     /* Free OpenGL memory */
   251     if (_this->gl_data) {
   252         SDL_free(_this->gl_data);
   253         _this->gl_data = NULL;
   254     }
   255 }
   256 
   257 static SDL_bool
   258 HasExtension(const char *extension, const char *extensions)
   259 {
   260     const char *start;
   261     const char *where, *terminator;
   262 
   263     /* Extension names should not have spaces. */
   264     where = SDL_strchr(extension, ' ');
   265     if (where || *extension == '\0')
   266         return SDL_FALSE;
   267 
   268     if (!extensions)
   269         return SDL_FALSE;
   270 
   271     /* It takes a bit of care to be fool-proof about parsing the
   272      * OpenGL extensions string. Don't be fooled by sub-strings,
   273      * etc. */
   274 
   275     start = extensions;
   276 
   277     for (;;) {
   278         where = SDL_strstr(start, extension);
   279         if (!where)
   280             break;
   281 
   282         terminator = where + SDL_strlen(extension);
   283         if (where == start || *(where - 1) == ' ')
   284             if (*terminator == ' ' || *terminator == '\0')
   285                 return SDL_TRUE;
   286 
   287         start = terminator;
   288     }
   289     return SDL_FALSE;
   290 }
   291 
   292 static void
   293 X11_GL_InitExtensions(_THIS)
   294 {
   295     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   296     int screen = DefaultScreen(display);
   297     XVisualInfo *vinfo;
   298     XSetWindowAttributes xattr;
   299     Window w;
   300     GLXContext context;
   301     const char *(*glXQueryExtensionsStringFunc) (Display *, int);
   302     const char *extensions;
   303 
   304     vinfo = X11_GL_GetVisual(_this, display, screen);
   305     if (!vinfo) {
   306         return;
   307     }
   308     xattr.background_pixel = 0;
   309     xattr.border_pixel = 0;
   310     xattr.colormap =
   311         XCreateColormap(display, RootWindow(display, screen), vinfo->visual,
   312                         AllocNone);
   313     w = XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0,
   314                       vinfo->depth, InputOutput, vinfo->visual,
   315                       (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
   316     context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   317     if (context) {
   318         _this->gl_data->glXMakeCurrent(display, w, context);
   319     }
   320     XFree(vinfo);
   321 
   322     glXQueryExtensionsStringFunc =
   323         (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
   324                                                                 "glXQueryExtensionsString");
   325     if (glXQueryExtensionsStringFunc) {
   326         extensions = glXQueryExtensionsStringFunc(display, screen);
   327     } else {
   328         extensions = NULL;
   329     }
   330 
   331     /* Check for GLX_EXT_swap_control(_tear) */
   332     _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
   333     if (HasExtension("GLX_EXT_swap_control", extensions)) {
   334         _this->gl_data->glXSwapIntervalEXT =
   335             (void (*)(Display*,GLXDrawable,int))
   336                 X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
   337         if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
   338             _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
   339         }
   340     }
   341 
   342     /* Check for GLX_MESA_swap_control */
   343     if (HasExtension("GLX_MESA_swap_control", extensions)) {
   344         _this->gl_data->glXSwapIntervalMESA =
   345             (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
   346         _this->gl_data->glXGetSwapIntervalMESA =
   347             (int(*)(void)) X11_GL_GetProcAddress(_this,
   348                                                    "glXGetSwapIntervalMESA");
   349     }
   350 
   351     /* Check for GLX_SGI_swap_control */
   352     if (HasExtension("GLX_SGI_swap_control", extensions)) {
   353         _this->gl_data->glXSwapIntervalSGI =
   354             (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
   355     }
   356 
   357     /* Check for GLX_EXT_visual_rating */
   358     if (HasExtension("GLX_EXT_visual_rating", extensions)) {
   359         _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
   360     }
   361 
   362     /* Check for GLX_EXT_visual_info */
   363     if (HasExtension("GLX_EXT_visual_info", extensions)) {
   364         _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
   365     }
   366 
   367     if (context) {
   368         _this->gl_data->glXMakeCurrent(display, None, NULL);
   369         _this->gl_data->glXDestroyContext(display, context);
   370     }
   371     XDestroyWindow(display, w);
   372     X11_PumpEvents(_this);
   373 }
   374 
   375 /* glXChooseVisual and glXChooseFBConfig have some small differences in
   376  * the attribute encoding, it can be chosen with the for_FBConfig parameter. 
   377  */
   378 int 
   379 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig)
   380 {
   381     int i = 0;
   382 	const int MAX_ATTRIBUTES = 64;
   383 
   384     /* assert buffer is large enough to hold all SDL attributes. */ 
   385     SDL_assert(size >= MAX_ATTRIBUTES);
   386 
   387     /* Setup our GLX attributes according to the gl_config. */
   388     if( for_FBConfig ) {
   389         attribs[i++] = GLX_RENDER_TYPE;
   390 	attribs[i++] = GLX_RGBA_BIT;
   391     } else {
   392         attribs[i++] = GLX_RGBA;
   393     }
   394     attribs[i++] = GLX_RED_SIZE;
   395     attribs[i++] = _this->gl_config.red_size;
   396     attribs[i++] = GLX_GREEN_SIZE;
   397     attribs[i++] = _this->gl_config.green_size;
   398     attribs[i++] = GLX_BLUE_SIZE;
   399     attribs[i++] = _this->gl_config.blue_size;
   400 
   401     if (_this->gl_config.alpha_size) {
   402         attribs[i++] = GLX_ALPHA_SIZE;
   403         attribs[i++] = _this->gl_config.alpha_size;
   404     }
   405 
   406     if (_this->gl_config.double_buffer) {
   407         attribs[i++] = GLX_DOUBLEBUFFER;
   408 	if( for_FBConfig )
   409 	    attribs[i++] = True;
   410     }
   411 
   412     attribs[i++] = GLX_DEPTH_SIZE;
   413     attribs[i++] = _this->gl_config.depth_size;
   414 
   415     if (_this->gl_config.stencil_size) {
   416         attribs[i++] = GLX_STENCIL_SIZE;
   417         attribs[i++] = _this->gl_config.stencil_size;
   418     }
   419 
   420     if (_this->gl_config.accum_red_size) {
   421         attribs[i++] = GLX_ACCUM_RED_SIZE;
   422         attribs[i++] = _this->gl_config.accum_red_size;
   423     }
   424 
   425     if (_this->gl_config.accum_green_size) {
   426         attribs[i++] = GLX_ACCUM_GREEN_SIZE;
   427         attribs[i++] = _this->gl_config.accum_green_size;
   428     }
   429 
   430     if (_this->gl_config.accum_blue_size) {
   431         attribs[i++] = GLX_ACCUM_BLUE_SIZE;
   432         attribs[i++] = _this->gl_config.accum_blue_size;
   433     }
   434 
   435     if (_this->gl_config.accum_alpha_size) {
   436         attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
   437         attribs[i++] = _this->gl_config.accum_alpha_size;
   438     }
   439 
   440     if (_this->gl_config.stereo) {
   441         attribs[i++] = GLX_STEREO;
   442 	if( for_FBConfig )
   443 	    attribs[i++] = True;
   444     }
   445 
   446     if (_this->gl_config.multisamplebuffers) {
   447         attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
   448         attribs[i++] = _this->gl_config.multisamplebuffers;
   449     }
   450 
   451     if (_this->gl_config.multisamplesamples) {
   452         attribs[i++] = GLX_SAMPLES_ARB;
   453         attribs[i++] = _this->gl_config.multisamplesamples;
   454     }
   455 
   456     if (_this->gl_config.accelerated >= 0 &&
   457         _this->gl_data->HAS_GLX_EXT_visual_rating) {
   458         attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
   459         attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
   460                                                       GLX_SLOW_VISUAL_EXT;
   461     }
   462 
   463     /* If we're supposed to use DirectColor visuals, and we've got the
   464        EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
   465     if (X11_UseDirectColorVisuals() &&
   466         _this->gl_data->HAS_GLX_EXT_visual_info) {
   467         attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
   468         attribs[i++] = GLX_DIRECT_COLOR_EXT;
   469     }
   470 
   471     attribs[i++] = None;
   472 
   473     SDL_assert(i <= MAX_ATTRIBUTES);
   474  
   475     return i;
   476 }
   477 
   478 XVisualInfo *
   479 X11_GL_GetVisual(_THIS, Display * display, int screen)
   480 {
   481     XVisualInfo *vinfo;
   482 
   483     /* 64 seems nice. */
   484     int attribs[64];
   485     X11_GL_GetAttributes(_this,display,screen,attribs,64,SDL_FALSE);
   486 
   487     if (!_this->gl_data) {
   488         /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
   489         return NULL;
   490     }
   491 
   492     vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   493     if (!vinfo) {
   494         SDL_SetError("Couldn't find matching GLX visual");
   495     }
   496     return vinfo;
   497 }
   498 
   499 #ifndef GLXBadContext
   500 #define GLXBadContext 0
   501 #endif
   502 #ifndef GLXBadFBConfig
   503 #define GLXBadFBConfig 9
   504 #endif
   505 #ifndef GLXBadProfileARB
   506 #define GLXBadProfileARB 13
   507 #endif
   508 static int (*handler) (Display *, XErrorEvent *) = NULL;
   509 static int
   510 X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e)
   511 {
   512     switch (e->error_code) {
   513     case GLXBadContext:
   514     case GLXBadFBConfig:
   515     case GLXBadProfileARB:
   516     case BadRequest:
   517     case BadMatch:
   518     case BadValue:
   519     case BadAlloc:
   520         return (0);
   521     default:
   522         return (handler(d, e));
   523     }
   524 }
   525 
   526 SDL_GLContext
   527 X11_GL_CreateContext(_THIS, SDL_Window * window)
   528 {
   529     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   530     Display *display = data->videodata->display;
   531     int screen =
   532         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
   533     XWindowAttributes xattr;
   534     XVisualInfo v, *vinfo;
   535     int n;
   536     GLXContext context = NULL, share_context;
   537 
   538     if (_this->gl_config.share_with_current_context) {
   539         share_context = (GLXContext)(_this->current_glctx);
   540     } else {
   541         share_context = NULL;
   542     }
   543 
   544     /* We do this to create a clean separation between X and GLX errors. */
   545     XSync(display, False);
   546     handler = XSetErrorHandler(X11_GL_CreateContextErrorHandler);
   547     XGetWindowAttributes(display, data->xwindow, &xattr);
   548     v.screen = screen;
   549     v.visualid = XVisualIDFromVisual(xattr.visual);
   550     vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   551     if (vinfo) {
   552         if (_this->gl_config.major_version < 3 &&
   553             _this->gl_config.profile_mask == 0 &&
   554             _this->gl_config.flags == 0) {
   555             /* Create legacy context */
   556             context =
   557                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   558         } else {
   559             /* If we want a GL 3.0 context or later we need to get a temporary
   560                context to grab the new context creation function */
   561             GLXContext temp_context =
   562                 _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   563             if (temp_context) {
   564                 /* max 8 attributes plus terminator */
   565                 int attribs[9] = {
   566                     GLX_CONTEXT_MAJOR_VERSION_ARB,
   567                     _this->gl_config.major_version,
   568                     GLX_CONTEXT_MINOR_VERSION_ARB,
   569                     _this->gl_config.minor_version,
   570                     0
   571                 };
   572                 int iattr = 4;
   573 
   574                 /* SDL profile bits match GLX profile bits */
   575                 if( _this->gl_config.profile_mask != 0 ) {
   576                     attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   577                     attribs[iattr++] = _this->gl_config.profile_mask;
   578                 }
   579 
   580                 /* SDL flags match GLX flags */
   581                 if( _this->gl_config.flags != 0 ) {
   582                     attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   583                     attribs[iattr++] = _this->gl_config.flags;
   584                 }
   585 
   586                 attribs[iattr++] = 0;
   587 
   588                 /* Get a pointer to the context creation function for GL 3.0 */
   589                 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs =
   590                     (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   591                     glXGetProcAddress((GLubyte *)
   592                                       "glXCreateContextAttribsARB");
   593                 if (!glXCreateContextAttribs) {
   594                     SDL_SetError("GL 3.x is not supported");
   595                     context = temp_context;
   596                 } else {
   597                     int glxAttribs[64];
   598 
   599                     /* Create a GL 3.x context */
   600                     GLXFBConfig *framebuffer_config = NULL;
   601                     int fbcount = 0;
   602                     GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
   603                                                        int screen,
   604                                                        const int *attrib_list,
   605                                                        int *nelements);
   606 
   607                     glXChooseFBConfig =
   608                         (GLXFBConfig *
   609                          (*)(Display *, int, const int *,
   610                              int *)) _this->gl_data->
   611                         glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
   612 
   613                     X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
   614 
   615                     if (!glXChooseFBConfig
   616                         || !(framebuffer_config =
   617                              glXChooseFBConfig(display,
   618                                                DefaultScreen(display), glxAttribs,
   619                                                &fbcount))) {
   620                         SDL_SetError
   621                             ("No good framebuffers found. GL 3.x disabled");
   622                         context = temp_context;
   623                     } else {
   624                         context =
   625                             glXCreateContextAttribs(display,
   626                                                     framebuffer_config[0],
   627                                                     share_context, True, attribs);
   628                         _this->gl_data->glXDestroyContext(display,
   629                                                           temp_context);
   630                     }
   631                 }
   632             }
   633         }
   634         XFree(vinfo);
   635     }
   636     XSync(display, False);
   637     XSetErrorHandler(handler);
   638     
   639     if (!context) {
   640         SDL_SetError("Could not create GL context");
   641         return NULL;
   642     }
   643 
   644     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   645         X11_GL_DeleteContext(_this, context);
   646         return NULL;
   647     }
   648 
   649     return context;
   650 }
   651 
   652 int
   653 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   654 {
   655     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   656     Window drawable =
   657         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   658     GLXContext glx_context = (GLXContext) context;
   659     int status;
   660 
   661     if (!_this->gl_data) {
   662         SDL_SetError("OpenGL not initialized");
   663         return -1;
   664     }
   665 
   666     status = 0;
   667     if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
   668         SDL_SetError("Unable to make GL context current");
   669         status = -1;
   670     }
   671 
   672     return (status);
   673 }
   674 
   675 /* 
   676    0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
   677    will undo the effect of a previous call with a value that is greater
   678    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   679    argument to glxSwapIntervalSGI and it returns an error if you call it
   680    with 0 as an argument.
   681 */
   682 
   683 static int swapinterval = -1;
   684 int
   685 X11_GL_SetSwapInterval(_THIS, int interval)
   686 {
   687     int status = -1;
   688 
   689     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   690         SDL_SetError("Negative swap interval unsupported in this GL");
   691     } else if (_this->gl_data->glXSwapIntervalEXT) {
   692         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   693         const SDL_WindowData *windowdata = (SDL_WindowData *)
   694             _this->current_glwin->driverdata;
   695 
   696         Window drawable = windowdata->xwindow;
   697 
   698         /*
   699          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   700          * and will be fixed in a future release (probably 319.xx).
   701          *
   702          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   703          * it has the wrong value cached. To work around it, we just run a no-op
   704          * update to the current value.
   705          */
   706         int currentInterval = X11_GL_GetSwapInterval(_this);
   707         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   708         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   709 
   710         status = 0;
   711         swapinterval = interval;
   712     } else if (_this->gl_data->glXSwapIntervalMESA) {
   713         status = _this->gl_data->glXSwapIntervalMESA(interval);
   714         if (status != 0) {
   715             SDL_SetError("glxSwapIntervalMESA failed");
   716         } else {
   717             swapinterval = interval;
   718         }
   719     } else if (_this->gl_data->glXSwapIntervalSGI) {
   720         status = _this->gl_data->glXSwapIntervalSGI(interval);
   721         if (status != 0) {
   722             SDL_SetError("glxSwapIntervalSGI failed");
   723         } else {
   724             swapinterval = interval;
   725         }
   726     } else {
   727         SDL_Unsupported();
   728     }
   729     return status;
   730 }
   731 
   732 int
   733 X11_GL_GetSwapInterval(_THIS)
   734 {
   735     if (_this->gl_data->glXSwapIntervalEXT) {
   736         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   737         const SDL_WindowData *windowdata = (SDL_WindowData *)
   738             _this->current_glwin->driverdata;
   739         Window drawable = windowdata->xwindow;
   740         unsigned int allow_late_swap_tearing = 0;
   741         unsigned int interval = 0;
   742 
   743         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   744             _this->gl_data->glXQueryDrawable(display, drawable,
   745                                             GLX_LATE_SWAPS_TEAR_EXT,
   746                                             &allow_late_swap_tearing);
   747         }
   748 
   749         _this->gl_data->glXQueryDrawable(display, drawable,
   750                                          GLX_SWAP_INTERVAL_EXT, &interval);
   751 
   752         if ((allow_late_swap_tearing) && (interval > 0)) {
   753             return -((int) interval);
   754         }
   755 
   756         return (int) interval;
   757     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   758         return _this->gl_data->glXGetSwapIntervalMESA();
   759     } else {
   760         return swapinterval;
   761     }
   762 }
   763 
   764 void
   765 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   766 {
   767     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   768     Display *display = data->videodata->display;
   769 
   770     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   771 }
   772 
   773 void
   774 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   775 {
   776     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   777     GLXContext glx_context = (GLXContext) context;
   778 
   779     if (!_this->gl_data) {
   780         return;
   781     }
   782     _this->gl_data->glXDestroyContext(display, glx_context);
   783     XSync(display, False);
   784 }
   785 
   786 #endif /* SDL_VIDEO_OPENGL_GLX */
   787 
   788 #endif /* SDL_VIDEO_DRIVER_X11 */
   789 
   790 /* vi: set ts=4 sw=4 expandtab: */