src/video/x11/SDL_x11opengl.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 02 Mar 2013 20:44:16 -0800
changeset 6950 1ddb72193079
parent 6948 84a71440360d
child 6988 2aed1beaf5bc
permissions -rw-r--r--
Added a mouse ID to the mouse events, which set to the special value SDL_TOUCH_MOUSEID for mouse events simulated by touch input.
     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 SDL_GLContext
   500 X11_GL_CreateContext(_THIS, SDL_Window * window)
   501 {
   502     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   503     Display *display = data->videodata->display;
   504     int screen =
   505         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
   506     XWindowAttributes xattr;
   507     XVisualInfo v, *vinfo;
   508     int n;
   509     GLXContext context = NULL, share_context;
   510 
   511     if (_this->gl_config.share_with_current_context) {
   512         share_context = (GLXContext)(_this->current_glctx);
   513     } else {
   514         share_context = NULL;
   515     }
   516 
   517     /* We do this to create a clean separation between X and GLX errors. */
   518     XSync(display, False);
   519     XGetWindowAttributes(display, data->xwindow, &xattr);
   520     v.screen = screen;
   521     v.visualid = XVisualIDFromVisual(xattr.visual);
   522     vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   523     if (vinfo) {
   524         if (_this->gl_config.major_version < 3 &&
   525             _this->gl_config.profile_mask == 0 &&
   526             _this->gl_config.flags == 0) {
   527             /* Create legacy context */
   528             context =
   529                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   530         } else {
   531             /* If we want a GL 3.0 context or later we need to get a temporary
   532                context to grab the new context creation function */
   533             GLXContext temp_context =
   534                 _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   535             if (!temp_context) {
   536                 SDL_SetError("Could not create GL context");
   537                 return NULL;
   538             } else {
   539                 /* max 8 attributes plus terminator */
   540                 int attribs[9] = {
   541                     GLX_CONTEXT_MAJOR_VERSION_ARB,
   542                     _this->gl_config.major_version,
   543                     GLX_CONTEXT_MINOR_VERSION_ARB,
   544                     _this->gl_config.minor_version,
   545                     0
   546                 };
   547                 int iattr = 4;
   548 
   549                 /* SDL profile bits match GLX profile bits */
   550                 if( _this->gl_config.profile_mask != 0 ) {
   551                     attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   552                     attribs[iattr++] = _this->gl_config.profile_mask;
   553                 }
   554 
   555                 /* SDL flags match GLX flags */
   556                 if( _this->gl_config.flags != 0 ) {
   557                     attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   558                     attribs[iattr++] = _this->gl_config.flags;
   559                 }
   560 
   561                 attribs[iattr++] = 0;
   562 
   563                 /* Get a pointer to the context creation function for GL 3.0 */
   564                 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs =
   565                     (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   566                     glXGetProcAddress((GLubyte *)
   567                                       "glXCreateContextAttribsARB");
   568                 if (!glXCreateContextAttribs) {
   569                     SDL_SetError("GL 3.x is not supported");
   570                     context = temp_context;
   571                 } else {
   572                     int glxAttribs[64];
   573 
   574                     /* Create a GL 3.x context */
   575                     GLXFBConfig *framebuffer_config = NULL;
   576                     int fbcount = 0;
   577                     GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
   578                                                        int screen,
   579                                                        const int *attrib_list,
   580                                                        int *nelements);
   581 
   582                     glXChooseFBConfig =
   583                         (GLXFBConfig *
   584                          (*)(Display *, int, const int *,
   585                              int *)) _this->gl_data->
   586                         glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
   587 
   588                     X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
   589 
   590                     if (!glXChooseFBConfig
   591                         || !(framebuffer_config =
   592                              glXChooseFBConfig(display,
   593                                                DefaultScreen(display), glxAttribs,
   594                                                &fbcount))) {
   595                         SDL_SetError
   596                             ("No good framebuffers found. GL 3.x disabled");
   597                         context = temp_context;
   598                     } else {
   599                         context =
   600                             glXCreateContextAttribs(display,
   601                                                     framebuffer_config[0],
   602                                                     share_context, True, attribs);
   603                         _this->gl_data->glXDestroyContext(display,
   604                                                           temp_context);
   605                     }
   606                 }
   607             }
   608         }
   609         XFree(vinfo);
   610     }
   611     XSync(display, False);
   612 
   613     if (!context) {
   614         SDL_SetError("Could not create GL context");
   615         return NULL;
   616     }
   617 
   618     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   619         X11_GL_DeleteContext(_this, context);
   620         return NULL;
   621     }
   622 
   623     return context;
   624 }
   625 
   626 int
   627 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   628 {
   629     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   630     Window drawable =
   631         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   632     GLXContext glx_context = (GLXContext) context;
   633     int status;
   634 
   635     if (!_this->gl_data) {
   636         SDL_SetError("OpenGL not initialized");
   637         return -1;
   638     }
   639 
   640     status = 0;
   641     if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
   642         SDL_SetError("Unable to make GL context current");
   643         status = -1;
   644     }
   645 
   646     return (status);
   647 }
   648 
   649 /* 
   650    0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
   651    will undo the effect of a previous call with a value that is greater
   652    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   653    argument to glxSwapIntervalSGI and it returns an error if you call it
   654    with 0 as an argument.
   655 */
   656 
   657 static int swapinterval = -1;
   658 int
   659 X11_GL_SetSwapInterval(_THIS, int interval)
   660 {
   661     int status = -1;
   662 
   663     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   664         SDL_SetError("Negative swap interval unsupported in this GL");
   665     } else if (_this->gl_data->glXSwapIntervalEXT) {
   666         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   667         const SDL_WindowData *windowdata = (SDL_WindowData *)
   668             _this->current_glwin->driverdata;
   669 
   670         Window drawable = windowdata->xwindow;
   671 
   672         /*
   673          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   674          * and will be fixed in a future release (probably 319.xx).
   675          *
   676          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   677          * it has the wrong value cached. To work around it, we just run a no-op
   678          * update to the current value.
   679          */
   680         int currentInterval = X11_GL_GetSwapInterval(_this);
   681         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   682         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   683 
   684         status = 0;
   685         swapinterval = interval;
   686     } else if (_this->gl_data->glXSwapIntervalMESA) {
   687         status = _this->gl_data->glXSwapIntervalMESA(interval);
   688         if (status != 0) {
   689             SDL_SetError("glxSwapIntervalMESA failed");
   690         } else {
   691             swapinterval = interval;
   692         }
   693     } else if (_this->gl_data->glXSwapIntervalSGI) {
   694         status = _this->gl_data->glXSwapIntervalSGI(interval);
   695         if (status != 0) {
   696             SDL_SetError("glxSwapIntervalSGI failed");
   697         } else {
   698             swapinterval = interval;
   699         }
   700     } else {
   701         SDL_Unsupported();
   702     }
   703     return status;
   704 }
   705 
   706 int
   707 X11_GL_GetSwapInterval(_THIS)
   708 {
   709     if (_this->gl_data->glXSwapIntervalEXT) {
   710         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   711         const SDL_WindowData *windowdata = (SDL_WindowData *)
   712             _this->current_glwin->driverdata;
   713         Window drawable = windowdata->xwindow;
   714         unsigned int allow_late_swap_tearing = 0;
   715         unsigned int interval = 0;
   716 
   717         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   718             _this->gl_data->glXQueryDrawable(display, drawable,
   719                                             GLX_LATE_SWAPS_TEAR_EXT,
   720                                             &allow_late_swap_tearing);
   721         }
   722 
   723         _this->gl_data->glXQueryDrawable(display, drawable,
   724                                          GLX_SWAP_INTERVAL_EXT, &interval);
   725 
   726         if ((allow_late_swap_tearing) && (interval > 0)) {
   727             return -((int) interval);
   728         }
   729 
   730         return (int) interval;
   731     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   732         return _this->gl_data->glXGetSwapIntervalMESA();
   733     } else {
   734         return swapinterval;
   735     }
   736 }
   737 
   738 void
   739 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   740 {
   741     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   742     Display *display = data->videodata->display;
   743 
   744     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   745 }
   746 
   747 void
   748 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   749 {
   750     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   751     GLXContext glx_context = (GLXContext) context;
   752 
   753     if (!_this->gl_data) {
   754         return;
   755     }
   756     _this->gl_data->glXDestroyContext(display, glx_context);
   757     XSync(display, False);
   758 }
   759 
   760 #endif /* SDL_VIDEO_OPENGL_GLX */
   761 
   762 #endif /* SDL_VIDEO_DRIVER_X11 */
   763 
   764 /* vi: set ts=4 sw=4 expandtab: */