src/video/x11/SDL_x11opengl.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 06 Apr 2015 00:10:54 -0400
changeset 9458 543298b36b28
parent 9412 8b1436ce1028
child 9459 f5b468964b0b
permissions -rw-r--r--
This function can be static.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.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 #ifndef GLX_ARB_context_flush_control
   126 #define GLX_ARB_context_flush_control
   127 #define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB   0x2097
   128 #define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB           0x0000
   129 #define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB          0x2098
   130 #endif
   131 
   132 #define OPENGL_REQUIRES_DLOPEN
   133 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   134 #include <dlfcn.h>
   135 #define GL_LoadObject(X)    dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
   136 #define GL_LoadFunction     dlsym
   137 #define GL_UnloadObject     dlclose
   138 #else
   139 #define GL_LoadObject   SDL_LoadObject
   140 #define GL_LoadFunction SDL_LoadFunction
   141 #define GL_UnloadObject SDL_UnloadObject
   142 #endif
   143 
   144 static void X11_GL_InitExtensions(_THIS);
   145 
   146 
   147 int
   148 X11_GL_LoadLibrary(_THIS, const char *path)
   149 {
   150     Display *display;
   151     void *handle;
   152 
   153     if (_this->gl_data) {
   154         return SDL_SetError("OpenGL context already created");
   155     }
   156 
   157     /* Load the OpenGL library */
   158     if (path == NULL) {
   159         path = SDL_getenv("SDL_OPENGL_LIBRARY");
   160     }
   161     if (path == NULL) {
   162         path = DEFAULT_OPENGL;
   163     }
   164     _this->gl_config.dll_handle = GL_LoadObject(path);
   165     if (!_this->gl_config.dll_handle) {
   166 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   167         SDL_SetError("Failed loading %s: %s", path, dlerror());
   168 #endif
   169         return -1;
   170     }
   171     SDL_strlcpy(_this->gl_config.driver_path, path,
   172                 SDL_arraysize(_this->gl_config.driver_path));
   173 
   174     /* Allocate OpenGL memory */
   175     _this->gl_data =
   176         (struct SDL_GLDriverData *) SDL_calloc(1,
   177                                                sizeof(struct
   178                                                       SDL_GLDriverData));
   179     if (!_this->gl_data) {
   180         return SDL_OutOfMemory();
   181     }
   182 
   183     /* Load function pointers */
   184     handle = _this->gl_config.dll_handle;
   185     _this->gl_data->glXQueryExtension =
   186         (Bool (*)(Display *, int *, int *))
   187             GL_LoadFunction(handle, "glXQueryExtension");
   188     _this->gl_data->glXGetProcAddress =
   189         (void *(*)(const GLubyte *))
   190             GL_LoadFunction(handle, "glXGetProcAddressARB");
   191     _this->gl_data->glXChooseVisual =
   192         (XVisualInfo * (*)(Display *, int, int *))
   193             X11_GL_GetProcAddress(_this, "glXChooseVisual");
   194     _this->gl_data->glXCreateContext =
   195         (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
   196             X11_GL_GetProcAddress(_this, "glXCreateContext");
   197     _this->gl_data->glXDestroyContext =
   198         (void (*)(Display *, GLXContext))
   199             X11_GL_GetProcAddress(_this, "glXDestroyContext");
   200     _this->gl_data->glXMakeCurrent =
   201         (int (*)(Display *, GLXDrawable, GLXContext))
   202             X11_GL_GetProcAddress(_this, "glXMakeCurrent");
   203     _this->gl_data->glXSwapBuffers =
   204         (void (*)(Display *, GLXDrawable))
   205             X11_GL_GetProcAddress(_this, "glXSwapBuffers");
   206     _this->gl_data->glXQueryDrawable =
   207         (void (*)(Display*,GLXDrawable,int,unsigned int*))
   208             X11_GL_GetProcAddress(_this, "glXQueryDrawable");
   209 
   210     if (!_this->gl_data->glXQueryExtension ||
   211         !_this->gl_data->glXChooseVisual ||
   212         !_this->gl_data->glXCreateContext ||
   213         !_this->gl_data->glXDestroyContext ||
   214         !_this->gl_data->glXMakeCurrent ||
   215         !_this->gl_data->glXSwapBuffers) {
   216         return SDL_SetError("Could not retrieve OpenGL functions");
   217     }
   218 
   219     display = ((SDL_VideoData *) _this->driverdata)->display;
   220     if (!_this->gl_data->glXQueryExtension(display, &_this->gl_data->errorBase, &_this->gl_data->eventBase)) {
   221         return SDL_SetError("GLX is not supported");
   222     }
   223 
   224     /* Initialize extensions */
   225     X11_GL_InitExtensions(_this);
   226     
   227     /* If we need a GL ES context and there's no  
   228      * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions  
   229      */
   230     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && 
   231         ! _this->gl_data->HAS_GLX_EXT_create_context_es2_profile ) {
   232 #if SDL_VIDEO_OPENGL_EGL
   233         X11_GL_UnloadLibrary(_this);
   234         /* Better avoid conflicts! */
   235         if (_this->gl_config.dll_handle != NULL ) {
   236             GL_UnloadObject(_this->gl_config.dll_handle);
   237             _this->gl_config.dll_handle = NULL;
   238         }
   239         _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
   240         _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
   241         _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
   242         _this->GL_CreateContext = X11_GLES_CreateContext;
   243         _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
   244         _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
   245         _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
   246         _this->GL_SwapWindow = X11_GLES_SwapWindow;
   247         _this->GL_DeleteContext = X11_GLES_DeleteContext;
   248         return X11_GLES_LoadLibrary(_this, NULL);
   249 #else
   250         return SDL_SetError("SDL not configured with EGL support");
   251 #endif
   252     }
   253 
   254     return 0;
   255 }
   256 
   257 void *
   258 X11_GL_GetProcAddress(_THIS, const char *proc)
   259 {
   260     if (_this->gl_data->glXGetProcAddress) {
   261         return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
   262     }
   263     return GL_LoadFunction(_this->gl_config.dll_handle, proc);
   264 }
   265 
   266 void
   267 X11_GL_UnloadLibrary(_THIS)
   268 {
   269     /* Don't actually unload the library, since it may have registered
   270      * X11 shutdown hooks, per the notes at:
   271      * http://dri.sourceforge.net/doc/DRIuserguide.html
   272      */
   273 #if 0
   274     GL_UnloadObject(_this->gl_config.dll_handle);
   275     _this->gl_config.dll_handle = NULL;
   276 #endif
   277 
   278     /* Free OpenGL memory */
   279     SDL_free(_this->gl_data);
   280     _this->gl_data = NULL;
   281 }
   282 
   283 static SDL_bool
   284 HasExtension(const char *extension, const char *extensions)
   285 {
   286     const char *start;
   287     const char *where, *terminator;
   288 
   289     if (!extensions)
   290         return SDL_FALSE;
   291 
   292     /* Extension names should not have spaces. */
   293     where = SDL_strchr(extension, ' ');
   294     if (where || *extension == '\0')
   295         return SDL_FALSE;
   296 
   297     /* It takes a bit of care to be fool-proof about parsing the
   298      * OpenGL extensions string. Don't be fooled by sub-strings,
   299      * etc. */
   300 
   301     start = extensions;
   302 
   303     for (;;) {
   304         where = SDL_strstr(start, extension);
   305         if (!where)
   306             break;
   307 
   308         terminator = where + SDL_strlen(extension);
   309         if (where == start || *(where - 1) == ' ')
   310             if (*terminator == ' ' || *terminator == '\0')
   311                 return SDL_TRUE;
   312 
   313         start = terminator;
   314     }
   315     return SDL_FALSE;
   316 }
   317 
   318 static void
   319 X11_GL_InitExtensions(_THIS)
   320 {
   321     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   322     const int screen = DefaultScreen(display);
   323     const char *(*glXQueryExtensionsStringFunc) (Display *, int);
   324     const char *extensions;
   325 
   326     glXQueryExtensionsStringFunc =
   327         (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
   328                                                                 "glXQueryExtensionsString");
   329     if (glXQueryExtensionsStringFunc) {
   330         extensions = glXQueryExtensionsStringFunc(display, screen);
   331     } else {
   332         extensions = NULL;
   333     }
   334 
   335     /* Check for GLX_EXT_swap_control(_tear) */
   336     _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
   337     if (HasExtension("GLX_EXT_swap_control", extensions)) {
   338         _this->gl_data->glXSwapIntervalEXT =
   339             (void (*)(Display*,GLXDrawable,int))
   340                 X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
   341         if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
   342             _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
   343         }
   344     }
   345 
   346     /* Check for GLX_MESA_swap_control */
   347     if (HasExtension("GLX_MESA_swap_control", extensions)) {
   348         _this->gl_data->glXSwapIntervalMESA =
   349             (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
   350         _this->gl_data->glXGetSwapIntervalMESA =
   351             (int(*)(void)) X11_GL_GetProcAddress(_this,
   352                                                    "glXGetSwapIntervalMESA");
   353     }
   354 
   355     /* Check for GLX_SGI_swap_control */
   356     if (HasExtension("GLX_SGI_swap_control", extensions)) {
   357         _this->gl_data->glXSwapIntervalSGI =
   358             (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
   359     }
   360 
   361     /* Check for GLX_ARB_create_context */
   362     if (HasExtension("GLX_ARB_create_context", extensions)) {
   363         _this->gl_data->glXCreateContextAttribsARB =
   364             (GLXContext (*)(Display*,GLXFBConfig,GLXContext,Bool,const int *))
   365                 X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB");
   366         _this->gl_data->glXChooseFBConfig =
   367             (GLXFBConfig *(*)(Display *, int, const int *, int *))
   368                 X11_GL_GetProcAddress(_this, "glXChooseFBConfig");
   369     }
   370 
   371     /* Check for GLX_EXT_visual_rating */
   372     if (HasExtension("GLX_EXT_visual_rating", extensions)) {
   373         _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
   374     }
   375 
   376     /* Check for GLX_EXT_visual_info */
   377     if (HasExtension("GLX_EXT_visual_info", extensions)) {
   378         _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
   379     }
   380     
   381     /* Check for GLX_EXT_create_context_es2_profile */
   382     if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) {
   383         _this->gl_data->HAS_GLX_EXT_create_context_es2_profile = SDL_TRUE;
   384     }
   385 
   386     /* Check for GLX_ARB_context_flush_control */
   387     if (HasExtension("GLX_ARB_context_flush_control", extensions)) {
   388         _this->gl_data->HAS_GLX_ARB_context_flush_control = SDL_TRUE;
   389     }
   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 static 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.framebuffer_srgb_capable) {
   476         attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
   477         if( for_FBConfig ) {
   478             attribs[i++] = True;
   479         }
   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     /* 64 seems nice. */
   508     int attribs[64];
   509     XVisualInfo *vinfo;
   510 
   511     if (!_this->gl_data) {
   512         /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
   513         return NULL;
   514     }
   515 
   516     X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE);
   517     vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   518     if (!vinfo) {
   519         SDL_SetError("Couldn't find matching GLX visual");
   520     }
   521     return vinfo;
   522 }
   523 
   524 #ifndef GLXBadContext
   525 #define GLXBadContext 0
   526 #endif
   527 #ifndef GLXBadFBConfig
   528 #define GLXBadFBConfig 9
   529 #endif
   530 #ifndef GLXBadProfileARB
   531 #define GLXBadProfileARB 13
   532 #endif
   533 static int (*handler) (Display *, XErrorEvent *) = NULL;
   534 static int errorBase = 0;
   535 static int errorCode = 0;
   536 static int
   537 X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e)
   538 {
   539     char *x11_error = NULL;
   540     char x11_error_locale[256];
   541 
   542     errorCode = e->error_code;
   543     if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
   544     {
   545         x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
   546     }
   547 
   548     if (x11_error)
   549     {
   550         SDL_SetError("Could not create GL context: %s", x11_error);
   551         SDL_free(x11_error);
   552     }
   553     else
   554     {
   555         SDL_SetError("Could not create GL context: %i (Base %i)\n", errorCode, errorBase);
   556     }
   557 
   558     return (0);
   559 }
   560 
   561 SDL_GLContext
   562 X11_GL_CreateContext(_THIS, SDL_Window * window)
   563 {
   564     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   565     Display *display = data->videodata->display;
   566     int screen =
   567         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
   568     XWindowAttributes xattr;
   569     XVisualInfo v, *vinfo;
   570     int n;
   571     GLXContext context = NULL, share_context;
   572 
   573     if (_this->gl_config.share_with_current_context) {
   574         share_context = (GLXContext)SDL_GL_GetCurrentContext();
   575     } else {
   576         share_context = NULL;
   577     }
   578 
   579     /* We do this to create a clean separation between X and GLX errors. */
   580     X11_XSync(display, False);
   581     errorBase = _this->gl_data->errorBase;
   582     errorCode = Success;
   583     handler = X11_XSetErrorHandler(X11_GL_CreateContextErrorHandler);
   584     X11_XGetWindowAttributes(display, data->xwindow, &xattr);
   585     v.screen = screen;
   586     v.visualid = X11_XVisualIDFromVisual(xattr.visual);
   587     vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   588     if (vinfo) {
   589         if (_this->gl_config.major_version < 3 &&
   590             _this->gl_config.profile_mask == 0 &&
   591             _this->gl_config.flags == 0) {
   592             /* Create legacy context */
   593             context =
   594                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   595         } else {
   596             /* max 10 attributes plus terminator */
   597             int attribs[11] = {
   598                 GLX_CONTEXT_MAJOR_VERSION_ARB,
   599                 _this->gl_config.major_version,
   600                 GLX_CONTEXT_MINOR_VERSION_ARB,
   601                 _this->gl_config.minor_version,
   602                 0
   603             };
   604             int iattr = 4;
   605 
   606             /* SDL profile bits match GLX profile bits */
   607             if( _this->gl_config.profile_mask != 0 ) {
   608                 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   609                 attribs[iattr++] = _this->gl_config.profile_mask;
   610             }
   611 
   612             /* SDL flags match GLX flags */
   613             if( _this->gl_config.flags != 0 ) {
   614                 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   615                 attribs[iattr++] = _this->gl_config.flags;
   616             }
   617 
   618             /* only set if glx extension is available */
   619             if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) {
   620                 attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB;
   621                 attribs[iattr++] = 
   622                     _this->gl_config.release_behavior ? 
   623                     GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : 
   624                     GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
   625             }
   626 
   627             attribs[iattr++] = 0;
   628 
   629             /* Get a pointer to the context creation function for GL 3.0 */
   630             if (!_this->gl_data->glXCreateContextAttribsARB) {
   631                 SDL_SetError("OpenGL 3.0 and later are not supported by this system");
   632             } else {
   633                 int glxAttribs[64];
   634 
   635                 /* Create a GL 3.x context */
   636                 GLXFBConfig *framebuffer_config = NULL;
   637                 int fbcount = 0;
   638 
   639                 X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
   640 
   641                 if (!_this->gl_data->glXChooseFBConfig
   642                     || !(framebuffer_config =
   643                         _this->gl_data->glXChooseFBConfig(display,
   644                                           DefaultScreen(display), glxAttribs,
   645                                           &fbcount))) {
   646                     SDL_SetError("No good framebuffers found. OpenGL 3.0 and later unavailable");
   647                 } else {
   648                     context = _this->gl_data->glXCreateContextAttribsARB(display,
   649                                                     framebuffer_config[0],
   650                                                     share_context, True, attribs);
   651                 }
   652             }
   653         }
   654         X11_XFree(vinfo);
   655     }
   656     X11_XSync(display, False);
   657     X11_XSetErrorHandler(handler);
   658 
   659     if (!context) {
   660         if (errorCode == Success) {
   661             SDL_SetError("Could not create GL context");
   662         }
   663         return NULL;
   664     }
   665 
   666     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   667         X11_GL_DeleteContext(_this, context);
   668         return NULL;
   669     }
   670 
   671     return context;
   672 }
   673 
   674 int
   675 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   676 {
   677     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   678     Window drawable =
   679         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   680     GLXContext glx_context = (GLXContext) context;
   681 
   682     if (!_this->gl_data) {
   683         return SDL_SetError("OpenGL not initialized");
   684     }
   685 
   686     if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
   687         return SDL_SetError("Unable to make GL context current");
   688     }
   689 
   690     return 0;
   691 }
   692 
   693 /*
   694    0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
   695    will undo the effect of a previous call with a value that is greater
   696    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   697    argument to glxSwapIntervalSGI and it returns an error if you call it
   698    with 0 as an argument.
   699 */
   700 
   701 static int swapinterval = -1;
   702 int
   703 X11_GL_SetSwapInterval(_THIS, int interval)
   704 {
   705     int status = -1;
   706 
   707     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   708         SDL_SetError("Negative swap interval unsupported in this GL");
   709     } else if (_this->gl_data->glXSwapIntervalEXT) {
   710         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   711         const SDL_WindowData *windowdata = (SDL_WindowData *)
   712             SDL_GL_GetCurrentWindow()->driverdata;
   713 
   714         Window drawable = windowdata->xwindow;
   715 
   716         /*
   717          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   718          * and will be fixed in a future release (probably 319.xx).
   719          *
   720          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   721          * it has the wrong value cached. To work around it, we just run a no-op
   722          * update to the current value.
   723          */
   724         int currentInterval = X11_GL_GetSwapInterval(_this);
   725         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   726         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   727 
   728         status = 0;
   729         swapinterval = interval;
   730     } else if (_this->gl_data->glXSwapIntervalMESA) {
   731         status = _this->gl_data->glXSwapIntervalMESA(interval);
   732         if (status != 0) {
   733             SDL_SetError("glxSwapIntervalMESA failed");
   734         } else {
   735             swapinterval = interval;
   736         }
   737     } else if (_this->gl_data->glXSwapIntervalSGI) {
   738         status = _this->gl_data->glXSwapIntervalSGI(interval);
   739         if (status != 0) {
   740             SDL_SetError("glxSwapIntervalSGI failed");
   741         } else {
   742             swapinterval = interval;
   743         }
   744     } else {
   745         SDL_Unsupported();
   746     }
   747     return status;
   748 }
   749 
   750 int
   751 X11_GL_GetSwapInterval(_THIS)
   752 {
   753     if (_this->gl_data->glXSwapIntervalEXT) {
   754         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   755         const SDL_WindowData *windowdata = (SDL_WindowData *)
   756             SDL_GL_GetCurrentWindow()->driverdata;
   757         Window drawable = windowdata->xwindow;
   758         unsigned int allow_late_swap_tearing = 0;
   759         unsigned int interval = 0;
   760 
   761         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   762             _this->gl_data->glXQueryDrawable(display, drawable,
   763                                             GLX_LATE_SWAPS_TEAR_EXT,
   764                                             &allow_late_swap_tearing);
   765         }
   766 
   767         _this->gl_data->glXQueryDrawable(display, drawable,
   768                                          GLX_SWAP_INTERVAL_EXT, &interval);
   769 
   770         if ((allow_late_swap_tearing) && (interval > 0)) {
   771             return -((int) interval);
   772         }
   773 
   774         return (int) interval;
   775     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   776         return _this->gl_data->glXGetSwapIntervalMESA();
   777     } else {
   778         return swapinterval;
   779     }
   780 }
   781 
   782 void
   783 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   784 {
   785     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   786     Display *display = data->videodata->display;
   787 
   788     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   789 }
   790 
   791 void
   792 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   793 {
   794     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   795     GLXContext glx_context = (GLXContext) context;
   796 
   797     if (!_this->gl_data) {
   798         return;
   799     }
   800     _this->gl_data->glXDestroyContext(display, glx_context);
   801     X11_XSync(display, False);
   802 }
   803 
   804 #endif /* SDL_VIDEO_OPENGL_GLX */
   805 
   806 #endif /* SDL_VIDEO_DRIVER_X11 */
   807 
   808 /* vi: set ts=4 sw=4 expandtab: */