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