src/video/x11/SDL_x11opengl.c
author Gabriel Jacobo <gabomdq@gmail.com>
Mon, 19 Aug 2013 16:29:46 -0300
changeset 7659 ac4ce59c40e7
parent 7512 462839f2f408
child 7679 b1fe132bc6a4
permissions -rw-r--r--
Fixes bug #2037, common EGL code for Android and X11
     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 
   568     if (_this->gl_config.share_with_current_context) {
   569         share_context = (GLXContext)SDL_GL_GetCurrentContext();
   570     } else {
   571         share_context = NULL;
   572     }
   573 
   574     /* We do this to create a clean separation between X and GLX errors. */
   575     XSync(display, False);
   576     errorBase = _this->gl_data->errorBase;
   577     handler = XSetErrorHandler(X11_GL_CreateContextErrorHandler);
   578     XGetWindowAttributes(display, data->xwindow, &xattr);
   579     v.screen = screen;
   580     v.visualid = XVisualIDFromVisual(xattr.visual);
   581     vinfo = XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   582     if (vinfo) {
   583         if (_this->gl_config.major_version < 3 &&
   584             _this->gl_config.profile_mask == 0 &&
   585             _this->gl_config.flags == 0) {
   586             /* Create legacy context */
   587             context =
   588                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   589         } else {
   590             /* If we want a GL 3.0 context or later we need to get a temporary
   591                context to grab the new context creation function */
   592             GLXContext temp_context =
   593                 _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   594             if (temp_context) {
   595                 /* max 8 attributes plus terminator */
   596                 int attribs[9] = {
   597                     GLX_CONTEXT_MAJOR_VERSION_ARB,
   598                     _this->gl_config.major_version,
   599                     GLX_CONTEXT_MINOR_VERSION_ARB,
   600                     _this->gl_config.minor_version,
   601                     0
   602                 };
   603                 int iattr = 4;
   604 
   605                 /* SDL profile bits match GLX profile bits */
   606                 if( _this->gl_config.profile_mask != 0 ) {
   607                     attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   608                     attribs[iattr++] = _this->gl_config.profile_mask;
   609                 }
   610 
   611                 /* SDL flags match GLX flags */
   612                 if( _this->gl_config.flags != 0 ) {
   613                     attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   614                     attribs[iattr++] = _this->gl_config.flags;
   615                 }
   616 
   617                 attribs[iattr++] = 0;
   618 
   619                 /* Get a pointer to the context creation function for GL 3.0 */
   620                 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs =
   621                     (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   622                     glXGetProcAddress((GLubyte *)
   623                                       "glXCreateContextAttribsARB");
   624                 if (!glXCreateContextAttribs) {
   625                     SDL_SetError("GL 3.x is not supported");
   626                     context = temp_context;
   627                 } else {
   628                     int glxAttribs[64];
   629 
   630                     /* Create a GL 3.x context */
   631                     GLXFBConfig *framebuffer_config = NULL;
   632                     int fbcount = 0;
   633                     GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
   634                                                        int screen,
   635                                                        const int *attrib_list,
   636                                                        int *nelements);
   637 
   638                     glXChooseFBConfig =
   639                         (GLXFBConfig *
   640                          (*)(Display *, int, const int *,
   641                              int *)) _this->gl_data->
   642                         glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
   643 
   644                     X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
   645 
   646                     if (!glXChooseFBConfig
   647                         || !(framebuffer_config =
   648                              glXChooseFBConfig(display,
   649                                                DefaultScreen(display), glxAttribs,
   650                                                &fbcount))) {
   651                         SDL_SetError
   652                             ("No good framebuffers found. GL 3.x disabled");
   653                         context = temp_context;
   654                     } else {
   655                         context =
   656                             glXCreateContextAttribs(display,
   657                                                     framebuffer_config[0],
   658                                                     share_context, True, attribs);
   659                         _this->gl_data->glXDestroyContext(display,
   660                                                           temp_context);
   661                     }
   662                 }
   663             }
   664         }
   665         XFree(vinfo);
   666     }
   667     XSync(display, False);
   668     XSetErrorHandler(handler);
   669 
   670     if (!context) {
   671         SDL_SetError("Could not create GL context");
   672         return NULL;
   673     }
   674 
   675     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   676         X11_GL_DeleteContext(_this, context);
   677         return NULL;
   678     }
   679 
   680     return context;
   681 }
   682 
   683 int
   684 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   685 {
   686     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   687     Window drawable =
   688         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   689     GLXContext glx_context = (GLXContext) context;
   690 
   691     if (!_this->gl_data) {
   692         return SDL_SetError("OpenGL not initialized");
   693     }
   694 
   695     if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
   696         return SDL_SetError("Unable to make GL context current");
   697     }
   698 
   699     return 0;
   700 }
   701 
   702 /*
   703    0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
   704    will undo the effect of a previous call with a value that is greater
   705    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   706    argument to glxSwapIntervalSGI and it returns an error if you call it
   707    with 0 as an argument.
   708 */
   709 
   710 static int swapinterval = -1;
   711 int
   712 X11_GL_SetSwapInterval(_THIS, int interval)
   713 {
   714     int status = -1;
   715 
   716     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   717         SDL_SetError("Negative swap interval unsupported in this GL");
   718     } else if (_this->gl_data->glXSwapIntervalEXT) {
   719         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   720         const SDL_WindowData *windowdata = (SDL_WindowData *)
   721             SDL_GL_GetCurrentWindow()->driverdata;
   722 
   723         Window drawable = windowdata->xwindow;
   724 
   725         /*
   726          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   727          * and will be fixed in a future release (probably 319.xx).
   728          *
   729          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   730          * it has the wrong value cached. To work around it, we just run a no-op
   731          * update to the current value.
   732          */
   733         int currentInterval = X11_GL_GetSwapInterval(_this);
   734         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   735         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   736 
   737         status = 0;
   738         swapinterval = interval;
   739     } else if (_this->gl_data->glXSwapIntervalMESA) {
   740         status = _this->gl_data->glXSwapIntervalMESA(interval);
   741         if (status != 0) {
   742             SDL_SetError("glxSwapIntervalMESA failed");
   743         } else {
   744             swapinterval = interval;
   745         }
   746     } else if (_this->gl_data->glXSwapIntervalSGI) {
   747         status = _this->gl_data->glXSwapIntervalSGI(interval);
   748         if (status != 0) {
   749             SDL_SetError("glxSwapIntervalSGI failed");
   750         } else {
   751             swapinterval = interval;
   752         }
   753     } else {
   754         SDL_Unsupported();
   755     }
   756     return status;
   757 }
   758 
   759 int
   760 X11_GL_GetSwapInterval(_THIS)
   761 {
   762     if (_this->gl_data->glXSwapIntervalEXT) {
   763         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   764         const SDL_WindowData *windowdata = (SDL_WindowData *)
   765             SDL_GL_GetCurrentWindow()->driverdata;
   766         Window drawable = windowdata->xwindow;
   767         unsigned int allow_late_swap_tearing = 0;
   768         unsigned int interval = 0;
   769 
   770         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   771             _this->gl_data->glXQueryDrawable(display, drawable,
   772                                             GLX_LATE_SWAPS_TEAR_EXT,
   773                                             &allow_late_swap_tearing);
   774         }
   775 
   776         _this->gl_data->glXQueryDrawable(display, drawable,
   777                                          GLX_SWAP_INTERVAL_EXT, &interval);
   778 
   779         if ((allow_late_swap_tearing) && (interval > 0)) {
   780             return -((int) interval);
   781         }
   782 
   783         return (int) interval;
   784     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   785         return _this->gl_data->glXGetSwapIntervalMESA();
   786     } else {
   787         return swapinterval;
   788     }
   789 }
   790 
   791 void
   792 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   793 {
   794     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   795     Display *display = data->videodata->display;
   796 
   797     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   798 }
   799 
   800 void
   801 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   802 {
   803     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   804     GLXContext glx_context = (GLXContext) context;
   805 
   806     if (!_this->gl_data) {
   807         return;
   808     }
   809     _this->gl_data->glXDestroyContext(display, glx_context);
   810     XSync(display, False);
   811 }
   812 
   813 #endif /* SDL_VIDEO_OPENGL_GLX */
   814 
   815 #endif /* SDL_VIDEO_DRIVER_X11 */
   816 
   817 /* vi: set ts=4 sw=4 expandtab: */