src/video/x11/SDL_x11opengl.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 26 May 2015 06:27:46 -0700
changeset 9619 b94b6d0bff0f
parent 9459 f5b468964b0b
child 9812 9b4dd9efb04e
permissions -rw-r--r--
Updated the copyright year to 2015
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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         attribs[i++] = True;  /* always needed, for_FBConfig or not! */
   478     }
   479 
   480     if (_this->gl_config.accelerated >= 0 &&
   481         _this->gl_data->HAS_GLX_EXT_visual_rating) {
   482         attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
   483         attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
   484                                                       GLX_SLOW_VISUAL_EXT;
   485     }
   486 
   487     /* If we're supposed to use DirectColor visuals, and we've got the
   488        EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
   489     if (X11_UseDirectColorVisuals() &&
   490         _this->gl_data->HAS_GLX_EXT_visual_info) {
   491         attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
   492         attribs[i++] = GLX_DIRECT_COLOR_EXT;
   493     }
   494 
   495     attribs[i++] = None;
   496 
   497     SDL_assert(i <= MAX_ATTRIBUTES);
   498 
   499     return i;
   500 }
   501 
   502 XVisualInfo *
   503 X11_GL_GetVisual(_THIS, Display * display, int screen)
   504 {
   505     /* 64 seems nice. */
   506     int attribs[64];
   507     XVisualInfo *vinfo;
   508 
   509     if (!_this->gl_data) {
   510         /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
   511         return NULL;
   512     }
   513 
   514     X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE);
   515     vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   516     if (!vinfo) {
   517         SDL_SetError("Couldn't find matching GLX visual");
   518     }
   519     return vinfo;
   520 }
   521 
   522 #ifndef GLXBadContext
   523 #define GLXBadContext 0
   524 #endif
   525 #ifndef GLXBadFBConfig
   526 #define GLXBadFBConfig 9
   527 #endif
   528 #ifndef GLXBadProfileARB
   529 #define GLXBadProfileARB 13
   530 #endif
   531 static int (*handler) (Display *, XErrorEvent *) = NULL;
   532 static int errorBase = 0;
   533 static int errorCode = 0;
   534 static int
   535 X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e)
   536 {
   537     char *x11_error = NULL;
   538     char x11_error_locale[256];
   539 
   540     errorCode = e->error_code;
   541     if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
   542     {
   543         x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
   544     }
   545 
   546     if (x11_error)
   547     {
   548         SDL_SetError("Could not create GL context: %s", x11_error);
   549         SDL_free(x11_error);
   550     }
   551     else
   552     {
   553         SDL_SetError("Could not create GL context: %i (Base %i)\n", errorCode, errorBase);
   554     }
   555 
   556     return (0);
   557 }
   558 
   559 SDL_GLContext
   560 X11_GL_CreateContext(_THIS, SDL_Window * window)
   561 {
   562     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   563     Display *display = data->videodata->display;
   564     int screen =
   565         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
   566     XWindowAttributes xattr;
   567     XVisualInfo v, *vinfo;
   568     int n;
   569     GLXContext context = NULL, share_context;
   570 
   571     if (_this->gl_config.share_with_current_context) {
   572         share_context = (GLXContext)SDL_GL_GetCurrentContext();
   573     } else {
   574         share_context = NULL;
   575     }
   576 
   577     /* We do this to create a clean separation between X and GLX errors. */
   578     X11_XSync(display, False);
   579     errorBase = _this->gl_data->errorBase;
   580     errorCode = Success;
   581     handler = X11_XSetErrorHandler(X11_GL_CreateContextErrorHandler);
   582     X11_XGetWindowAttributes(display, data->xwindow, &xattr);
   583     v.screen = screen;
   584     v.visualid = X11_XVisualIDFromVisual(xattr.visual);
   585     vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   586     if (vinfo) {
   587         if (_this->gl_config.major_version < 3 &&
   588             _this->gl_config.profile_mask == 0 &&
   589             _this->gl_config.flags == 0) {
   590             /* Create legacy context */
   591             context =
   592                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   593         } else {
   594             /* max 10 attributes plus terminator */
   595             int attribs[11] = {
   596                 GLX_CONTEXT_MAJOR_VERSION_ARB,
   597                 _this->gl_config.major_version,
   598                 GLX_CONTEXT_MINOR_VERSION_ARB,
   599                 _this->gl_config.minor_version,
   600                 0
   601             };
   602             int iattr = 4;
   603 
   604             /* SDL profile bits match GLX profile bits */
   605             if( _this->gl_config.profile_mask != 0 ) {
   606                 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   607                 attribs[iattr++] = _this->gl_config.profile_mask;
   608             }
   609 
   610             /* SDL flags match GLX flags */
   611             if( _this->gl_config.flags != 0 ) {
   612                 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   613                 attribs[iattr++] = _this->gl_config.flags;
   614             }
   615 
   616             /* only set if glx extension is available */
   617             if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) {
   618                 attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB;
   619                 attribs[iattr++] = 
   620                     _this->gl_config.release_behavior ? 
   621                     GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : 
   622                     GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
   623             }
   624 
   625             attribs[iattr++] = 0;
   626 
   627             /* Get a pointer to the context creation function for GL 3.0 */
   628             if (!_this->gl_data->glXCreateContextAttribsARB) {
   629                 SDL_SetError("OpenGL 3.0 and later are not supported by this system");
   630             } else {
   631                 int glxAttribs[64];
   632 
   633                 /* Create a GL 3.x context */
   634                 GLXFBConfig *framebuffer_config = NULL;
   635                 int fbcount = 0;
   636 
   637                 X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
   638 
   639                 if (!_this->gl_data->glXChooseFBConfig
   640                     || !(framebuffer_config =
   641                         _this->gl_data->glXChooseFBConfig(display,
   642                                           DefaultScreen(display), glxAttribs,
   643                                           &fbcount))) {
   644                     SDL_SetError("No good framebuffers found. OpenGL 3.0 and later unavailable");
   645                 } else {
   646                     context = _this->gl_data->glXCreateContextAttribsARB(display,
   647                                                     framebuffer_config[0],
   648                                                     share_context, True, attribs);
   649                 }
   650             }
   651         }
   652         X11_XFree(vinfo);
   653     }
   654     X11_XSync(display, False);
   655     X11_XSetErrorHandler(handler);
   656 
   657     if (!context) {
   658         if (errorCode == Success) {
   659             SDL_SetError("Could not create GL context");
   660         }
   661         return NULL;
   662     }
   663 
   664     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   665         X11_GL_DeleteContext(_this, context);
   666         return NULL;
   667     }
   668 
   669     return context;
   670 }
   671 
   672 int
   673 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   674 {
   675     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   676     Window drawable =
   677         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   678     GLXContext glx_context = (GLXContext) context;
   679 
   680     if (!_this->gl_data) {
   681         return SDL_SetError("OpenGL not initialized");
   682     }
   683 
   684     if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
   685         return SDL_SetError("Unable to make GL context current");
   686     }
   687 
   688     return 0;
   689 }
   690 
   691 /*
   692    0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
   693    will undo the effect of a previous call with a value that is greater
   694    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   695    argument to glxSwapIntervalSGI and it returns an error if you call it
   696    with 0 as an argument.
   697 */
   698 
   699 static int swapinterval = -1;
   700 int
   701 X11_GL_SetSwapInterval(_THIS, int interval)
   702 {
   703     int status = -1;
   704 
   705     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   706         SDL_SetError("Negative swap interval unsupported in this GL");
   707     } else if (_this->gl_data->glXSwapIntervalEXT) {
   708         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   709         const SDL_WindowData *windowdata = (SDL_WindowData *)
   710             SDL_GL_GetCurrentWindow()->driverdata;
   711 
   712         Window drawable = windowdata->xwindow;
   713 
   714         /*
   715          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   716          * and will be fixed in a future release (probably 319.xx).
   717          *
   718          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   719          * it has the wrong value cached. To work around it, we just run a no-op
   720          * update to the current value.
   721          */
   722         int currentInterval = X11_GL_GetSwapInterval(_this);
   723         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   724         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   725 
   726         status = 0;
   727         swapinterval = interval;
   728     } else if (_this->gl_data->glXSwapIntervalMESA) {
   729         status = _this->gl_data->glXSwapIntervalMESA(interval);
   730         if (status != 0) {
   731             SDL_SetError("glxSwapIntervalMESA failed");
   732         } else {
   733             swapinterval = interval;
   734         }
   735     } else if (_this->gl_data->glXSwapIntervalSGI) {
   736         status = _this->gl_data->glXSwapIntervalSGI(interval);
   737         if (status != 0) {
   738             SDL_SetError("glxSwapIntervalSGI failed");
   739         } else {
   740             swapinterval = interval;
   741         }
   742     } else {
   743         SDL_Unsupported();
   744     }
   745     return status;
   746 }
   747 
   748 int
   749 X11_GL_GetSwapInterval(_THIS)
   750 {
   751     if (_this->gl_data->glXSwapIntervalEXT) {
   752         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   753         const SDL_WindowData *windowdata = (SDL_WindowData *)
   754             SDL_GL_GetCurrentWindow()->driverdata;
   755         Window drawable = windowdata->xwindow;
   756         unsigned int allow_late_swap_tearing = 0;
   757         unsigned int interval = 0;
   758 
   759         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   760             _this->gl_data->glXQueryDrawable(display, drawable,
   761                                             GLX_LATE_SWAPS_TEAR_EXT,
   762                                             &allow_late_swap_tearing);
   763         }
   764 
   765         _this->gl_data->glXQueryDrawable(display, drawable,
   766                                          GLX_SWAP_INTERVAL_EXT, &interval);
   767 
   768         if ((allow_late_swap_tearing) && (interval > 0)) {
   769             return -((int) interval);
   770         }
   771 
   772         return (int) interval;
   773     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   774         return _this->gl_data->glXGetSwapIntervalMESA();
   775     } else {
   776         return swapinterval;
   777     }
   778 }
   779 
   780 void
   781 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   782 {
   783     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   784     Display *display = data->videodata->display;
   785 
   786     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   787 }
   788 
   789 void
   790 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   791 {
   792     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   793     GLXContext glx_context = (GLXContext) context;
   794 
   795     if (!_this->gl_data) {
   796         return;
   797     }
   798     _this->gl_data->glXDestroyContext(display, glx_context);
   799     X11_XSync(display, False);
   800 }
   801 
   802 #endif /* SDL_VIDEO_OPENGL_GLX */
   803 
   804 #endif /* SDL_VIDEO_DRIVER_X11 */
   805 
   806 /* vi: set ts=4 sw=4 expandtab: */