src/video/x11/SDL_x11opengl.c
author Gabriel Jacobo <gabomdq@gmail.com>
Thu, 29 Aug 2013 15:02:32 -0300
changeset 7723 aea98cc3e696
parent 7719 31b5f9ff36ca
child 7827 a03ec8de0426
permissions -rw-r--r--
Fixes bug #2040, prepare SDL_GL_CONTEXT_EGL for deprecation on v2.1

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