src/video/x11/SDL_x11opengl.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 20 Oct 2013 21:18:05 -0400
changeset 7853 4861edda71d1
parent 7827 a03ec8de0426
child 8093 b43765095a6f
permissions -rw-r--r--
Added SDL_GL_FRAMEBUFFER_SRGB_CAPABLE (thanks, David!).

Fixes Bugzilla #1985.
     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_ARB_framebuffer_sRGB
   110 #define GLX_ARB_framebuffer_sRGB
   111 #ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB
   112 #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB                0x20B2
   113 #endif
   114 #endif
   115 
   116 #ifndef GLX_EXT_swap_control
   117 #define GLX_SWAP_INTERVAL_EXT              0x20F1
   118 #define GLX_MAX_SWAP_INTERVAL_EXT          0x20F2
   119 #endif
   120 
   121 #ifndef GLX_EXT_swap_control_tear
   122 #define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
   123 #endif
   124 
   125 #define OPENGL_REQUIRES_DLOPEN
   126 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   127 #include <dlfcn.h>
   128 #define GL_LoadObject(X)    dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
   129 #define GL_LoadFunction     dlsym
   130 #define GL_UnloadObject     dlclose
   131 #else
   132 #define GL_LoadObject   SDL_LoadObject
   133 #define GL_LoadFunction SDL_LoadFunction
   134 #define GL_UnloadObject SDL_UnloadObject
   135 #endif
   136 
   137 static void X11_GL_InitExtensions(_THIS);
   138 
   139 
   140 int
   141 X11_GL_LoadLibrary(_THIS, const char *path)
   142 {
   143     Display *display;
   144     void *handle;
   145 
   146     if (_this->gl_data) {
   147         return SDL_SetError("OpenGL context already created");
   148     }
   149 
   150     /* Load the OpenGL library */
   151     if (path == NULL) {
   152         path = SDL_getenv("SDL_OPENGL_LIBRARY");
   153     }
   154     if (path == NULL) {
   155         path = DEFAULT_OPENGL;
   156     }
   157     _this->gl_config.dll_handle = GL_LoadObject(path);
   158     if (!_this->gl_config.dll_handle) {
   159 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   160         SDL_SetError("Failed loading %s: %s", path, dlerror());
   161 #endif
   162         return -1;
   163     }
   164     SDL_strlcpy(_this->gl_config.driver_path, path,
   165                 SDL_arraysize(_this->gl_config.driver_path));
   166 
   167     /* Allocate OpenGL memory */
   168     _this->gl_data =
   169         (struct SDL_GLDriverData *) SDL_calloc(1,
   170                                                sizeof(struct
   171                                                       SDL_GLDriverData));
   172     if (!_this->gl_data) {
   173         return SDL_OutOfMemory();
   174     }
   175 
   176     /* Load function pointers */
   177     handle = _this->gl_config.dll_handle;
   178     _this->gl_data->glXQueryExtension =
   179         (Bool (*)(Display *, int *, int *))
   180             GL_LoadFunction(handle, "glXQueryExtension");
   181     _this->gl_data->glXGetProcAddress =
   182         (void *(*)(const GLubyte *))
   183             GL_LoadFunction(handle, "glXGetProcAddressARB");
   184     _this->gl_data->glXChooseVisual =
   185         (XVisualInfo * (*)(Display *, int, int *))
   186             X11_GL_GetProcAddress(_this, "glXChooseVisual");
   187     _this->gl_data->glXCreateContext =
   188         (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
   189             X11_GL_GetProcAddress(_this, "glXCreateContext");
   190     _this->gl_data->glXDestroyContext =
   191         (void (*)(Display *, GLXContext))
   192             X11_GL_GetProcAddress(_this, "glXDestroyContext");
   193     _this->gl_data->glXMakeCurrent =
   194         (int (*)(Display *, GLXDrawable, GLXContext))
   195             X11_GL_GetProcAddress(_this, "glXMakeCurrent");
   196     _this->gl_data->glXSwapBuffers =
   197         (void (*)(Display *, GLXDrawable))
   198             X11_GL_GetProcAddress(_this, "glXSwapBuffers");
   199     _this->gl_data->glXQueryDrawable =
   200         (void (*)(Display*,GLXDrawable,int,unsigned int*))
   201             X11_GL_GetProcAddress(_this, "glXQueryDrawable");
   202 
   203     if (!_this->gl_data->glXQueryExtension ||
   204         !_this->gl_data->glXChooseVisual ||
   205         !_this->gl_data->glXCreateContext ||
   206         !_this->gl_data->glXDestroyContext ||
   207         !_this->gl_data->glXMakeCurrent ||
   208         !_this->gl_data->glXSwapBuffers) {
   209         return SDL_SetError("Could not retrieve OpenGL functions");
   210     }
   211 
   212     display = ((SDL_VideoData *) _this->driverdata)->display;
   213     if (!_this->gl_data->glXQueryExtension(display, &_this->gl_data->errorBase, &_this->gl_data->eventBase)) {
   214         return SDL_SetError("GLX is not supported");
   215     }
   216 
   217     /* Initialize extensions */
   218     X11_GL_InitExtensions(_this);
   219     
   220     /* If we need a GL ES context and there's no  
   221      * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions  
   222      */
   223     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && 
   224         ! _this->gl_data->HAS_GLX_EXT_create_context_es2_profile ) {
   225 #if SDL_VIDEO_OPENGL_EGL
   226         X11_GL_UnloadLibrary(_this);
   227         /* Better avoid conflicts! */
   228         if (_this->gl_config.dll_handle != NULL ) {
   229             GL_UnloadObject(_this->gl_config.dll_handle);
   230             _this->gl_config.dll_handle = NULL;
   231         }
   232         _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
   233         _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
   234         _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
   235         _this->GL_CreateContext = X11_GLES_CreateContext;
   236         _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
   237         _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
   238         _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
   239         _this->GL_SwapWindow = X11_GLES_SwapWindow;
   240         _this->GL_DeleteContext = X11_GLES_DeleteContext;
   241         return X11_GLES_LoadLibrary(_this, NULL);
   242 #else
   243         return SDL_SetError("SDL not configured with EGL support");
   244 #endif
   245     }
   246 
   247     return 0;
   248 }
   249 
   250 void *
   251 X11_GL_GetProcAddress(_THIS, const char *proc)
   252 {
   253     if (_this->gl_data->glXGetProcAddress) {
   254         return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
   255     }
   256     return GL_LoadFunction(_this->gl_config.dll_handle, proc);
   257 }
   258 
   259 void
   260 X11_GL_UnloadLibrary(_THIS)
   261 {
   262     /* Don't actually unload the library, since it may have registered
   263      * X11 shutdown hooks, per the notes at:
   264      * http://dri.sourceforge.net/doc/DRIuserguide.html
   265      */
   266 #if 0
   267     GL_UnloadObject(_this->gl_config.dll_handle);
   268     _this->gl_config.dll_handle = NULL;
   269 #endif
   270 
   271     /* Free OpenGL memory */
   272     SDL_free(_this->gl_data);
   273     _this->gl_data = NULL;
   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         X11_XCreateColormap(display, RootWindow(display, screen), vinfo->visual,
   331                         AllocNone);
   332     w = X11_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     X11_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     X11_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.framebuffer_srgb_capable) {
   483         attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
   484         if( for_FBConfig ) {
   485             attribs[i++] = True;
   486         }
   487     }
   488 
   489     if (_this->gl_config.accelerated >= 0 &&
   490         _this->gl_data->HAS_GLX_EXT_visual_rating) {
   491         attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
   492         attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
   493                                                       GLX_SLOW_VISUAL_EXT;
   494     }
   495 
   496     /* If we're supposed to use DirectColor visuals, and we've got the
   497        EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
   498     if (X11_UseDirectColorVisuals() &&
   499         _this->gl_data->HAS_GLX_EXT_visual_info) {
   500         attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
   501         attribs[i++] = GLX_DIRECT_COLOR_EXT;
   502     }
   503 
   504     attribs[i++] = None;
   505 
   506     SDL_assert(i <= MAX_ATTRIBUTES);
   507 
   508     return i;
   509 }
   510 
   511 XVisualInfo *
   512 X11_GL_GetVisual(_THIS, Display * display, int screen)
   513 {
   514     XVisualInfo *vinfo;
   515 
   516     /* 64 seems nice. */
   517     int attribs[64];
   518     X11_GL_GetAttributes(_this,display,screen,attribs,64,SDL_FALSE);
   519 
   520     if (!_this->gl_data) {
   521         /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
   522         return NULL;
   523     }
   524 
   525     vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   526     if (!vinfo) {
   527         SDL_SetError("Couldn't find matching GLX visual");
   528     }
   529     return vinfo;
   530 }
   531 
   532 #ifndef GLXBadContext
   533 #define GLXBadContext 0
   534 #endif
   535 #ifndef GLXBadFBConfig
   536 #define GLXBadFBConfig 9
   537 #endif
   538 #ifndef GLXBadProfileARB
   539 #define GLXBadProfileARB 13
   540 #endif
   541 static int (*handler) (Display *, XErrorEvent *) = NULL;
   542 static int errorBase = 0;
   543 static int
   544 X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e)
   545 {
   546     switch (e->error_code) {
   547     case BadRequest:
   548     case BadMatch:
   549     case BadValue:
   550     case BadAlloc:
   551         return (0);
   552     default:
   553         if (errorBase && 
   554             (e->error_code == errorBase + GLXBadContext ||
   555              e->error_code == errorBase + GLXBadFBConfig ||
   556              e->error_code == errorBase + GLXBadProfileARB)) {
   557             return (0);
   558         }
   559         return (handler(d, e));
   560     }
   561 }
   562 
   563 SDL_GLContext
   564 X11_GL_CreateContext(_THIS, SDL_Window * window)
   565 {
   566     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   567     Display *display = data->videodata->display;
   568     int screen =
   569         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
   570     XWindowAttributes xattr;
   571     XVisualInfo v, *vinfo;
   572     int n;
   573     GLXContext context = NULL, share_context;
   574     PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = NULL;
   575 
   576     if (_this->gl_config.share_with_current_context) {
   577         share_context = (GLXContext)SDL_GL_GetCurrentContext();
   578     } else {
   579         share_context = NULL;
   580     }
   581 
   582     /* We do this to create a clean separation between X and GLX errors. */
   583     X11_XSync(display, False);
   584     errorBase = _this->gl_data->errorBase;
   585     handler = X11_XSetErrorHandler(X11_GL_CreateContextErrorHandler);
   586     X11_XGetWindowAttributes(display, data->xwindow, &xattr);
   587     v.screen = screen;
   588     v.visualid = X11_XVisualIDFromVisual(xattr.visual);
   589     vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   590     if (vinfo) {
   591         if (_this->gl_config.major_version < 3 &&
   592             _this->gl_config.profile_mask == 0 &&
   593             _this->gl_config.flags == 0) {
   594             /* Create legacy context */
   595             context =
   596                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   597         } else {
   598             /* If we want a GL 3.0 context or later we need to get a temporary
   599                context to grab the new context creation function */
   600             GLXContext temp_context =
   601                 _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   602             if (temp_context) {
   603                 /* max 8 attributes plus terminator */
   604                 int attribs[9] = {
   605                     GLX_CONTEXT_MAJOR_VERSION_ARB,
   606                     _this->gl_config.major_version,
   607                     GLX_CONTEXT_MINOR_VERSION_ARB,
   608                     _this->gl_config.minor_version,
   609                     0
   610                 };
   611                 int iattr = 4;
   612 
   613                 /* SDL profile bits match GLX profile bits */
   614                 if( _this->gl_config.profile_mask != 0 ) {
   615                     attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   616                     attribs[iattr++] = _this->gl_config.profile_mask;
   617                 }
   618 
   619                 /* SDL flags match GLX flags */
   620                 if( _this->gl_config.flags != 0 ) {
   621                     attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   622                     attribs[iattr++] = _this->gl_config.flags;
   623                 }
   624 
   625                 attribs[iattr++] = 0;
   626 
   627                 /* Get a pointer to the context creation function for GL 3.0 */
   628                 glXCreateContextAttribs =
   629                     (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   630                     glXGetProcAddress((GLubyte *)
   631                                       "glXCreateContextAttribsARB");
   632                 if (!glXCreateContextAttribs) {
   633                     SDL_SetError("GL 3.x is not supported");
   634                     context = temp_context;
   635                 } else {
   636                     int glxAttribs[64];
   637 
   638                     /* Create a GL 3.x context */
   639                     GLXFBConfig *framebuffer_config = NULL;
   640                     int fbcount = 0;
   641                     GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
   642                                                        int screen,
   643                                                        const int *attrib_list,
   644                                                        int *nelements);
   645 
   646                     glXChooseFBConfig =
   647                         (GLXFBConfig *
   648                          (*)(Display *, int, const int *,
   649                              int *)) _this->gl_data->
   650                         glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
   651 
   652                     X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
   653 
   654                     if (!glXChooseFBConfig
   655                         || !(framebuffer_config =
   656                              glXChooseFBConfig(display,
   657                                                DefaultScreen(display), glxAttribs,
   658                                                &fbcount))) {
   659                         SDL_SetError
   660                             ("No good framebuffers found. GL 3.x disabled");
   661                         context = temp_context;
   662                     } else {
   663                         context =
   664                             glXCreateContextAttribs(display,
   665                                                     framebuffer_config[0],
   666                                                     share_context, True, attribs);
   667                         _this->gl_data->glXDestroyContext(display,
   668                                                           temp_context);
   669                     }
   670                 }
   671             }
   672         }
   673         X11_XFree(vinfo);
   674     }
   675     X11_XSync(display, False);
   676     X11_XSetErrorHandler(handler);
   677 
   678     if (!context) {
   679         SDL_SetError("Could not create GL context");
   680         return NULL;
   681     }
   682 
   683     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   684         X11_GL_DeleteContext(_this, context);
   685         return NULL;
   686     }
   687 
   688     return context;
   689 }
   690 
   691 int
   692 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   693 {
   694     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   695     Window drawable =
   696         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   697     GLXContext glx_context = (GLXContext) context;
   698 
   699     if (!_this->gl_data) {
   700         return SDL_SetError("OpenGL not initialized");
   701     }
   702 
   703     if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
   704         return SDL_SetError("Unable to make GL context current");
   705     }
   706 
   707     return 0;
   708 }
   709 
   710 /*
   711    0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
   712    will undo the effect of a previous call with a value that is greater
   713    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   714    argument to glxSwapIntervalSGI and it returns an error if you call it
   715    with 0 as an argument.
   716 */
   717 
   718 static int swapinterval = -1;
   719 int
   720 X11_GL_SetSwapInterval(_THIS, int interval)
   721 {
   722     int status = -1;
   723 
   724     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   725         SDL_SetError("Negative swap interval unsupported in this GL");
   726     } else if (_this->gl_data->glXSwapIntervalEXT) {
   727         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   728         const SDL_WindowData *windowdata = (SDL_WindowData *)
   729             SDL_GL_GetCurrentWindow()->driverdata;
   730 
   731         Window drawable = windowdata->xwindow;
   732 
   733         /*
   734          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   735          * and will be fixed in a future release (probably 319.xx).
   736          *
   737          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   738          * it has the wrong value cached. To work around it, we just run a no-op
   739          * update to the current value.
   740          */
   741         int currentInterval = X11_GL_GetSwapInterval(_this);
   742         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   743         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   744 
   745         status = 0;
   746         swapinterval = interval;
   747     } else if (_this->gl_data->glXSwapIntervalMESA) {
   748         status = _this->gl_data->glXSwapIntervalMESA(interval);
   749         if (status != 0) {
   750             SDL_SetError("glxSwapIntervalMESA failed");
   751         } else {
   752             swapinterval = interval;
   753         }
   754     } else if (_this->gl_data->glXSwapIntervalSGI) {
   755         status = _this->gl_data->glXSwapIntervalSGI(interval);
   756         if (status != 0) {
   757             SDL_SetError("glxSwapIntervalSGI failed");
   758         } else {
   759             swapinterval = interval;
   760         }
   761     } else {
   762         SDL_Unsupported();
   763     }
   764     return status;
   765 }
   766 
   767 int
   768 X11_GL_GetSwapInterval(_THIS)
   769 {
   770     if (_this->gl_data->glXSwapIntervalEXT) {
   771         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   772         const SDL_WindowData *windowdata = (SDL_WindowData *)
   773             SDL_GL_GetCurrentWindow()->driverdata;
   774         Window drawable = windowdata->xwindow;
   775         unsigned int allow_late_swap_tearing = 0;
   776         unsigned int interval = 0;
   777 
   778         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   779             _this->gl_data->glXQueryDrawable(display, drawable,
   780                                             GLX_LATE_SWAPS_TEAR_EXT,
   781                                             &allow_late_swap_tearing);
   782         }
   783 
   784         _this->gl_data->glXQueryDrawable(display, drawable,
   785                                          GLX_SWAP_INTERVAL_EXT, &interval);
   786 
   787         if ((allow_late_swap_tearing) && (interval > 0)) {
   788             return -((int) interval);
   789         }
   790 
   791         return (int) interval;
   792     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   793         return _this->gl_data->glXGetSwapIntervalMESA();
   794     } else {
   795         return swapinterval;
   796     }
   797 }
   798 
   799 void
   800 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   801 {
   802     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   803     Display *display = data->videodata->display;
   804 
   805     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   806 }
   807 
   808 void
   809 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   810 {
   811     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   812     GLXContext glx_context = (GLXContext) context;
   813 
   814     if (!_this->gl_data) {
   815         return;
   816     }
   817     _this->gl_data->glXDestroyContext(display, glx_context);
   818     X11_XSync(display, False);
   819 }
   820 
   821 #endif /* SDL_VIDEO_OPENGL_GLX */
   822 
   823 #endif /* SDL_VIDEO_DRIVER_X11 */
   824 
   825 /* vi: set ts=4 sw=4 expandtab: */