src/video/x11/SDL_x11opengl.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 01 Sep 2017 14:08:09 -0400
changeset 11441 f9cf3fb0b2f7
parent 11440 71be1b793327
child 11645 2088cd828335
permissions -rw-r--r--
x11: Correctly restore previous GL context after sacrificial context is done.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 #include "SDL_hints.h"
    28 
    29 /* GLX implementation of SDL OpenGL support */
    30 
    31 #if SDL_VIDEO_OPENGL_GLX
    32 #include "SDL_loadso.h"
    33 #include "SDL_x11opengles.h"
    34 
    35 #if defined(__IRIX__)
    36 /* IRIX doesn't have a GL library versioning system */
    37 #define DEFAULT_OPENGL  "libGL.so"
    38 #elif defined(__MACOSX__)
    39 #define DEFAULT_OPENGL  "/usr/X11R6/lib/libGL.1.dylib"
    40 #elif defined(__QNXNTO__)
    41 #define DEFAULT_OPENGL  "libGL.so.3"
    42 #else
    43 #define DEFAULT_OPENGL  "libGL.so.1"
    44 #endif
    45 
    46 #ifndef GLX_NONE_EXT
    47 #define GLX_NONE_EXT                       0x8000
    48 #endif
    49 
    50 #ifndef GLX_ARB_multisample
    51 #define GLX_ARB_multisample
    52 #define GLX_SAMPLE_BUFFERS_ARB             100000
    53 #define GLX_SAMPLES_ARB                    100001
    54 #endif
    55 
    56 #ifndef GLX_EXT_visual_rating
    57 #define GLX_EXT_visual_rating
    58 #define GLX_VISUAL_CAVEAT_EXT              0x20
    59 #define GLX_NONE_EXT                       0x8000
    60 #define GLX_SLOW_VISUAL_EXT                0x8001
    61 #define GLX_NON_CONFORMANT_VISUAL_EXT      0x800D
    62 #endif
    63 
    64 #ifndef GLX_EXT_visual_info
    65 #define GLX_EXT_visual_info
    66 #define GLX_X_VISUAL_TYPE_EXT              0x22
    67 #define GLX_DIRECT_COLOR_EXT               0x8003
    68 #endif
    69 
    70 #ifndef GLX_ARB_create_context
    71 #define GLX_ARB_create_context
    72 #define GLX_CONTEXT_MAJOR_VERSION_ARB      0x2091
    73 #define GLX_CONTEXT_MINOR_VERSION_ARB      0x2092
    74 #define GLX_CONTEXT_FLAGS_ARB              0x2094
    75 #define GLX_CONTEXT_DEBUG_BIT_ARB          0x0001
    76 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
    77 
    78 /* Typedef for the GL 3.0 context creation function */
    79 typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
    80                                                         GLXFBConfig config,
    81                                                         GLXContext
    82                                                         share_context,
    83                                                         Bool direct,
    84                                                         const int
    85                                                         *attrib_list);
    86 #endif
    87 
    88 #ifndef GLX_ARB_create_context_profile
    89 #define GLX_ARB_create_context_profile
    90 #define GLX_CONTEXT_PROFILE_MASK_ARB       0x9126
    91 #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB   0x00000001
    92 #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
    93 #endif
    94 
    95 #ifndef GLX_ARB_create_context_robustness
    96 #define GLX_ARB_create_context_robustness
    97 #define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB  0x00000004
    98 #define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB     0x8256
    99 #define GLX_NO_RESET_NOTIFICATION_ARB                   0x8261
   100 #define GLX_LOSE_CONTEXT_ON_RESET_ARB                   0x8252
   101 #endif
   102 
   103 #ifndef GLX_EXT_create_context_es2_profile
   104 #define GLX_EXT_create_context_es2_profile
   105 #ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
   106 #define GLX_CONTEXT_ES2_PROFILE_BIT_EXT    0x00000002
   107 #endif
   108 #endif
   109 
   110 #ifndef GLX_ARB_framebuffer_sRGB
   111 #define GLX_ARB_framebuffer_sRGB
   112 #ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB
   113 #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB                0x20B2
   114 #endif
   115 #endif
   116 
   117 #ifndef GLX_ARB_create_context_no_error
   118 #define GLX_ARB_create_context_no_error
   119 #ifndef GLX_CONTEXT_OPENGL_NO_ERROR_ARB
   120 #define GLX_CONTEXT_OPENGL_NO_ERROR_ARB                 0x31B3
   121 #endif
   122 #endif
   123 
   124 #ifndef GLX_EXT_swap_control
   125 #define GLX_SWAP_INTERVAL_EXT              0x20F1
   126 #define GLX_MAX_SWAP_INTERVAL_EXT          0x20F2
   127 #endif
   128 
   129 #ifndef GLX_EXT_swap_control_tear
   130 #define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
   131 #endif
   132 
   133 #ifndef GLX_ARB_context_flush_control
   134 #define GLX_ARB_context_flush_control
   135 #define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB   0x2097
   136 #define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB           0x0000
   137 #define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB          0x2098
   138 #endif
   139 
   140 #define OPENGL_REQUIRES_DLOPEN
   141 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   142 #include <dlfcn.h>
   143 #define GL_LoadObject(X)    dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
   144 #define GL_LoadFunction     dlsym
   145 #define GL_UnloadObject     dlclose
   146 #else
   147 #define GL_LoadObject   SDL_LoadObject
   148 #define GL_LoadFunction SDL_LoadFunction
   149 #define GL_UnloadObject SDL_UnloadObject
   150 #endif
   151 
   152 static void X11_GL_InitExtensions(_THIS);
   153 
   154 int
   155 X11_GL_LoadLibrary(_THIS, const char *path)
   156 {
   157     Display *display;
   158     void *handle;
   159 
   160     if (_this->gl_data) {
   161         return SDL_SetError("OpenGL context already created");
   162     }
   163 
   164     /* Load the OpenGL library */
   165     if (path == NULL) {
   166         path = SDL_getenv("SDL_OPENGL_LIBRARY");
   167     }
   168     if (path == NULL) {
   169         path = DEFAULT_OPENGL;
   170     }
   171     _this->gl_config.dll_handle = GL_LoadObject(path);
   172     if (!_this->gl_config.dll_handle) {
   173 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   174         SDL_SetError("Failed loading %s: %s", path, dlerror());
   175 #endif
   176         return -1;
   177     }
   178     SDL_strlcpy(_this->gl_config.driver_path, path,
   179                 SDL_arraysize(_this->gl_config.driver_path));
   180 
   181     /* Allocate OpenGL memory */
   182     _this->gl_data =
   183         (struct SDL_GLDriverData *) SDL_calloc(1,
   184                                                sizeof(struct
   185                                                       SDL_GLDriverData));
   186     if (!_this->gl_data) {
   187         return SDL_OutOfMemory();
   188     }
   189 
   190     /* Load function pointers */
   191     handle = _this->gl_config.dll_handle;
   192     _this->gl_data->glXQueryExtension =
   193         (Bool (*)(Display *, int *, int *))
   194             GL_LoadFunction(handle, "glXQueryExtension");
   195     _this->gl_data->glXGetProcAddress =
   196         (void *(*)(const GLubyte *))
   197             GL_LoadFunction(handle, "glXGetProcAddressARB");
   198     _this->gl_data->glXChooseVisual =
   199         (XVisualInfo * (*)(Display *, int, int *))
   200             X11_GL_GetProcAddress(_this, "glXChooseVisual");
   201     _this->gl_data->glXCreateContext =
   202         (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
   203             X11_GL_GetProcAddress(_this, "glXCreateContext");
   204     _this->gl_data->glXDestroyContext =
   205         (void (*)(Display *, GLXContext))
   206             X11_GL_GetProcAddress(_this, "glXDestroyContext");
   207     _this->gl_data->glXMakeCurrent =
   208         (int (*)(Display *, GLXDrawable, GLXContext))
   209             X11_GL_GetProcAddress(_this, "glXMakeCurrent");
   210     _this->gl_data->glXSwapBuffers =
   211         (void (*)(Display *, GLXDrawable))
   212             X11_GL_GetProcAddress(_this, "glXSwapBuffers");
   213     _this->gl_data->glXQueryDrawable =
   214         (void (*)(Display*,GLXDrawable,int,unsigned int*))
   215             X11_GL_GetProcAddress(_this, "glXQueryDrawable");
   216 
   217     if (!_this->gl_data->glXQueryExtension ||
   218         !_this->gl_data->glXChooseVisual ||
   219         !_this->gl_data->glXCreateContext ||
   220         !_this->gl_data->glXDestroyContext ||
   221         !_this->gl_data->glXMakeCurrent ||
   222         !_this->gl_data->glXSwapBuffers) {
   223         return SDL_SetError("Could not retrieve OpenGL functions");
   224     }
   225 
   226     display = ((SDL_VideoData *) _this->driverdata)->display;
   227     if (!_this->gl_data->glXQueryExtension(display, &_this->gl_data->errorBase, &_this->gl_data->eventBase)) {
   228         return SDL_SetError("GLX is not supported");
   229     }
   230 
   231     /* Initialize extensions */
   232     /* See lengthy comment about the inc/dec in 
   233        ../windows/SDL_windowsopengl.c. */
   234     ++_this->gl_config.driver_loaded;
   235     X11_GL_InitExtensions(_this);
   236     --_this->gl_config.driver_loaded;
   237     
   238     /* If we need a GL ES context and there's no  
   239      * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions  
   240      */
   241     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && 
   242         X11_GL_UseEGL(_this) ) {
   243 #if SDL_VIDEO_OPENGL_EGL
   244         X11_GL_UnloadLibrary(_this);
   245         /* Better avoid conflicts! */
   246         if (_this->gl_config.dll_handle != NULL ) {
   247             GL_UnloadObject(_this->gl_config.dll_handle);
   248             _this->gl_config.dll_handle = NULL;
   249         }
   250         _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
   251         _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
   252         _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
   253         _this->GL_CreateContext = X11_GLES_CreateContext;
   254         _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
   255         _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
   256         _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
   257         _this->GL_SwapWindow = X11_GLES_SwapWindow;
   258         _this->GL_DeleteContext = X11_GLES_DeleteContext;
   259         return X11_GLES_LoadLibrary(_this, NULL);
   260 #else
   261         return SDL_SetError("SDL not configured with EGL support");
   262 #endif
   263     }
   264 
   265     return 0;
   266 }
   267 
   268 void *
   269 X11_GL_GetProcAddress(_THIS, const char *proc)
   270 {
   271     if (_this->gl_data->glXGetProcAddress) {
   272         return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
   273     }
   274     return GL_LoadFunction(_this->gl_config.dll_handle, proc);
   275 }
   276 
   277 void
   278 X11_GL_UnloadLibrary(_THIS)
   279 {
   280     /* Don't actually unload the library, since it may have registered
   281      * X11 shutdown hooks, per the notes at:
   282      * http://dri.sourceforge.net/doc/DRIuserguide.html
   283      */
   284 #if 0
   285     GL_UnloadObject(_this->gl_config.dll_handle);
   286     _this->gl_config.dll_handle = NULL;
   287 #endif
   288 
   289     /* Free OpenGL memory */
   290     SDL_free(_this->gl_data);
   291     _this->gl_data = NULL;
   292 }
   293 
   294 static SDL_bool
   295 HasExtension(const char *extension, const char *extensions)
   296 {
   297     const char *start;
   298     const char *where, *terminator;
   299 
   300     if (!extensions)
   301         return SDL_FALSE;
   302 
   303     /* Extension names should not have spaces. */
   304     where = SDL_strchr(extension, ' ');
   305     if (where || *extension == '\0')
   306         return SDL_FALSE;
   307 
   308     /* It takes a bit of care to be fool-proof about parsing the
   309      * OpenGL extensions string. Don't be fooled by sub-strings,
   310      * etc. */
   311 
   312     start = extensions;
   313 
   314     for (;;) {
   315         where = SDL_strstr(start, extension);
   316         if (!where)
   317             break;
   318 
   319         terminator = where + SDL_strlen(extension);
   320         if (where == start || *(where - 1) == ' ')
   321             if (*terminator == ' ' || *terminator == '\0')
   322                 return SDL_TRUE;
   323 
   324         start = terminator;
   325     }
   326     return SDL_FALSE;
   327 }
   328 
   329 static void
   330 X11_GL_InitExtensions(_THIS)
   331 {
   332     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   333     const int screen = DefaultScreen(display);
   334     XVisualInfo *vinfo = NULL;
   335     Window w = 0;
   336     GLXContext prev_ctx = 0;
   337     GLXDrawable prev_drawable = 0;
   338     GLXContext context = 0;
   339     const char *(*glXQueryExtensionsStringFunc) (Display *, int);
   340     const char *extensions;
   341 
   342     vinfo = X11_GL_GetVisual(_this, display, screen);
   343     if (vinfo) {
   344         GLXContext (*glXGetCurrentContextFunc) (void) =
   345             (GLXContext(*)(void))
   346                 X11_GL_GetProcAddress(_this, "glXGetCurrentContext");
   347 
   348         GLXDrawable (*glXGetCurrentDrawableFunc) (void) =
   349             (GLXDrawable(*)(void))
   350                 X11_GL_GetProcAddress(_this, "glXGetCurrentDrawable");
   351 
   352         if (glXGetCurrentContextFunc && glXGetCurrentDrawableFunc) {
   353             XSetWindowAttributes xattr;
   354             prev_ctx = glXGetCurrentContextFunc();
   355             prev_drawable = glXGetCurrentDrawableFunc();
   356 
   357             xattr.background_pixel = 0;
   358             xattr.border_pixel = 0;
   359             xattr.colormap =
   360                 X11_XCreateColormap(display, RootWindow(display, screen),
   361                                     vinfo->visual, AllocNone);
   362             w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0,
   363                         32, 32, 0, vinfo->depth, InputOutput, vinfo->visual,
   364                         (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
   365 
   366             context = _this->gl_data->glXCreateContext(display, vinfo,
   367                                                         NULL, True);
   368             if (context) {
   369                 _this->gl_data->glXMakeCurrent(display, w, context);
   370             }
   371         }
   372 
   373         X11_XFree(vinfo);
   374     }
   375 
   376     glXQueryExtensionsStringFunc =
   377         (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
   378                                                                 "glXQueryExtensionsString");
   379     if (glXQueryExtensionsStringFunc) {
   380         extensions = glXQueryExtensionsStringFunc(display, screen);
   381     } else {
   382         extensions = NULL;
   383     }
   384 
   385     /* Check for GLX_EXT_swap_control(_tear) */
   386     _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
   387     if (HasExtension("GLX_EXT_swap_control", extensions)) {
   388         _this->gl_data->glXSwapIntervalEXT =
   389             (void (*)(Display*,GLXDrawable,int))
   390                 X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
   391         if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
   392             _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
   393         }
   394     }
   395 
   396     /* Check for GLX_MESA_swap_control */
   397     if (HasExtension("GLX_MESA_swap_control", extensions)) {
   398         _this->gl_data->glXSwapIntervalMESA =
   399             (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
   400         _this->gl_data->glXGetSwapIntervalMESA =
   401             (int(*)(void)) X11_GL_GetProcAddress(_this,
   402                                                    "glXGetSwapIntervalMESA");
   403     }
   404 
   405     /* Check for GLX_SGI_swap_control */
   406     if (HasExtension("GLX_SGI_swap_control", extensions)) {
   407         _this->gl_data->glXSwapIntervalSGI =
   408             (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
   409     }
   410 
   411     /* Check for GLX_ARB_create_context */
   412     if (HasExtension("GLX_ARB_create_context", extensions)) {
   413         _this->gl_data->glXCreateContextAttribsARB =
   414             (GLXContext (*)(Display*,GLXFBConfig,GLXContext,Bool,const int *))
   415                 X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB");
   416         _this->gl_data->glXChooseFBConfig =
   417             (GLXFBConfig *(*)(Display *, int, const int *, int *))
   418                 X11_GL_GetProcAddress(_this, "glXChooseFBConfig");
   419     }
   420 
   421     /* Check for GLX_EXT_visual_rating */
   422     if (HasExtension("GLX_EXT_visual_rating", extensions)) {
   423         _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
   424     }
   425 
   426     /* Check for GLX_EXT_visual_info */
   427     if (HasExtension("GLX_EXT_visual_info", extensions)) {
   428         _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
   429     }
   430     
   431     /* Check for GLX_EXT_create_context_es2_profile */
   432     if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) {
   433         /* this wants to call glGetString(), so it needs a context. */
   434         /* !!! FIXME: it would be nice not to make a context here though! */
   435         if (context) {
   436             SDL_GL_DeduceMaxSupportedESProfile(
   437                 &_this->gl_data->es_profile_max_supported_version.major,
   438                 &_this->gl_data->es_profile_max_supported_version.minor
   439             );
   440         }
   441     }
   442 
   443     /* Check for GLX_ARB_context_flush_control */
   444     if (HasExtension("GLX_ARB_context_flush_control", extensions)) {
   445         _this->gl_data->HAS_GLX_ARB_context_flush_control = SDL_TRUE;
   446     }
   447 
   448     /* Check for GLX_ARB_create_context_robustness */
   449     if (HasExtension("GLX_ARB_create_context_robustness", extensions)) {
   450         _this->gl_data->HAS_GLX_ARB_create_context_robustness = SDL_TRUE;
   451     }
   452 
   453     /* Check for GLX_ARB_create_context_no_error */
   454     if (HasExtension("GLX_ARB_create_context_no_error", extensions)) {
   455         _this->gl_data->HAS_GLX_ARB_create_context_no_error = SDL_TRUE;
   456     }
   457 
   458     if (context) {
   459         _this->gl_data->glXMakeCurrent(display, None, NULL);
   460         _this->gl_data->glXDestroyContext(display, context);
   461         if (prev_ctx && prev_drawable) {
   462             _this->gl_data->glXMakeCurrent(display, prev_drawable, prev_ctx);
   463         }
   464     }
   465 
   466     X11_XDestroyWindow(display, w);
   467     X11_PumpEvents(_this);
   468 }
   469 
   470 /* glXChooseVisual and glXChooseFBConfig have some small differences in
   471  * the attribute encoding, it can be chosen with the for_FBConfig parameter.
   472  * Some targets fail if you use GLX_X_VISUAL_TYPE_EXT/GLX_DIRECT_COLOR_EXT,
   473  *  so it gets specified last if used and is pointed to by *_pvistypeattr.
   474  *  In case of failure, if that pointer is not NULL, set that pointer to None
   475  *  and try again.
   476  */
   477 static int
   478 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig, int **_pvistypeattr)
   479 {
   480     int i = 0;
   481     const int MAX_ATTRIBUTES = 64;
   482     int *pvistypeattr = NULL;
   483 
   484     /* assert buffer is large enough to hold all SDL attributes. */
   485     SDL_assert(size >= MAX_ATTRIBUTES);
   486 
   487     /* Setup our GLX attributes according to the gl_config. */
   488     if( for_FBConfig ) {
   489         attribs[i++] = GLX_RENDER_TYPE;
   490         attribs[i++] = GLX_RGBA_BIT;
   491     } else {
   492         attribs[i++] = GLX_RGBA;
   493     }
   494     attribs[i++] = GLX_RED_SIZE;
   495     attribs[i++] = _this->gl_config.red_size;
   496     attribs[i++] = GLX_GREEN_SIZE;
   497     attribs[i++] = _this->gl_config.green_size;
   498     attribs[i++] = GLX_BLUE_SIZE;
   499     attribs[i++] = _this->gl_config.blue_size;
   500 
   501     if (_this->gl_config.alpha_size) {
   502         attribs[i++] = GLX_ALPHA_SIZE;
   503         attribs[i++] = _this->gl_config.alpha_size;
   504     }
   505 
   506     if (_this->gl_config.double_buffer) {
   507         attribs[i++] = GLX_DOUBLEBUFFER;
   508         if( for_FBConfig ) {
   509             attribs[i++] = True;
   510         }
   511     }
   512 
   513     attribs[i++] = GLX_DEPTH_SIZE;
   514     attribs[i++] = _this->gl_config.depth_size;
   515 
   516     if (_this->gl_config.stencil_size) {
   517         attribs[i++] = GLX_STENCIL_SIZE;
   518         attribs[i++] = _this->gl_config.stencil_size;
   519     }
   520 
   521     if (_this->gl_config.accum_red_size) {
   522         attribs[i++] = GLX_ACCUM_RED_SIZE;
   523         attribs[i++] = _this->gl_config.accum_red_size;
   524     }
   525 
   526     if (_this->gl_config.accum_green_size) {
   527         attribs[i++] = GLX_ACCUM_GREEN_SIZE;
   528         attribs[i++] = _this->gl_config.accum_green_size;
   529     }
   530 
   531     if (_this->gl_config.accum_blue_size) {
   532         attribs[i++] = GLX_ACCUM_BLUE_SIZE;
   533         attribs[i++] = _this->gl_config.accum_blue_size;
   534     }
   535 
   536     if (_this->gl_config.accum_alpha_size) {
   537         attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
   538         attribs[i++] = _this->gl_config.accum_alpha_size;
   539     }
   540 
   541     if (_this->gl_config.stereo) {
   542         attribs[i++] = GLX_STEREO;
   543         if( for_FBConfig ) {
   544             attribs[i++] = True;
   545         }
   546     }
   547 
   548     if (_this->gl_config.multisamplebuffers) {
   549         attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
   550         attribs[i++] = _this->gl_config.multisamplebuffers;
   551     }
   552 
   553     if (_this->gl_config.multisamplesamples) {
   554         attribs[i++] = GLX_SAMPLES_ARB;
   555         attribs[i++] = _this->gl_config.multisamplesamples;
   556     }
   557 
   558     if (_this->gl_config.framebuffer_srgb_capable) {
   559         attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
   560         attribs[i++] = True;  /* always needed, for_FBConfig or not! */
   561     }
   562 
   563     if (_this->gl_config.accelerated >= 0 &&
   564         _this->gl_data->HAS_GLX_EXT_visual_rating) {
   565         attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
   566         attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
   567                                                       GLX_SLOW_VISUAL_EXT;
   568     }
   569 
   570     /* If we're supposed to use DirectColor visuals, and we've got the
   571        EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
   572     if (X11_UseDirectColorVisuals() &&
   573         _this->gl_data->HAS_GLX_EXT_visual_info) {
   574         pvistypeattr = &attribs[i];
   575         attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
   576         attribs[i++] = GLX_DIRECT_COLOR_EXT;
   577     }
   578 
   579     attribs[i++] = None;
   580 
   581     SDL_assert(i <= MAX_ATTRIBUTES);
   582 
   583     if (_pvistypeattr) {
   584         *_pvistypeattr = pvistypeattr;
   585     }
   586 
   587     return i;
   588 }
   589 
   590 XVisualInfo *
   591 X11_GL_GetVisual(_THIS, Display * display, int screen)
   592 {
   593     /* 64 seems nice. */
   594     int attribs[64];
   595     XVisualInfo *vinfo;
   596     int *pvistypeattr = NULL;
   597 
   598     if (!_this->gl_data) {
   599         /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
   600         return NULL;
   601     }
   602 
   603     X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr);
   604     vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   605 
   606     if (!vinfo && (pvistypeattr != NULL)) {
   607         *pvistypeattr = None;
   608         vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   609     }
   610 
   611     if (!vinfo) {
   612         SDL_SetError("Couldn't find matching GLX visual");
   613     }
   614     return vinfo;
   615 }
   616 
   617 static int (*handler) (Display *, XErrorEvent *) = NULL;
   618 static const char *errorHandlerOperation = NULL;
   619 static int errorBase = 0;
   620 static int errorCode = 0;
   621 static int
   622 X11_GL_ErrorHandler(Display * d, XErrorEvent * e)
   623 {
   624     char *x11_error = NULL;
   625     char x11_error_locale[256];
   626 
   627     errorCode = e->error_code;
   628     if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
   629     {
   630         x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
   631     }
   632 
   633     if (x11_error)
   634     {
   635         SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error);
   636         SDL_free(x11_error);
   637     }
   638     else
   639     {
   640         SDL_SetError("Could not %s: %i (Base %i)", errorHandlerOperation, errorCode, errorBase);
   641     }
   642 
   643     return (0);
   644 }
   645 
   646 SDL_bool
   647 X11_GL_UseEGL(_THIS)
   648 {
   649     SDL_assert(_this->gl_data != NULL);
   650     SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
   651 
   652     return (SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, SDL_FALSE)
   653             || _this->gl_config.major_version == 1 /* No GLX extension for OpenGL ES 1.x profiles. */
   654             || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major
   655             || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major
   656                 && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor));
   657 }
   658 
   659 SDL_GLContext
   660 X11_GL_CreateContext(_THIS, SDL_Window * window)
   661 {
   662     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   663     Display *display = data->videodata->display;
   664     int screen =
   665         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
   666     XWindowAttributes xattr;
   667     XVisualInfo v, *vinfo;
   668     int n;
   669     GLXContext context = NULL, share_context;
   670 
   671     if (_this->gl_config.share_with_current_context) {
   672         share_context = (GLXContext)SDL_GL_GetCurrentContext();
   673     } else {
   674         share_context = NULL;
   675     }
   676 
   677     /* We do this to create a clean separation between X and GLX errors. */
   678     X11_XSync(display, False);
   679     errorHandlerOperation = "create GL context";
   680     errorBase = _this->gl_data->errorBase;
   681     errorCode = Success;
   682     handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
   683     X11_XGetWindowAttributes(display, data->xwindow, &xattr);
   684     v.screen = screen;
   685     v.visualid = X11_XVisualIDFromVisual(xattr.visual);
   686     vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   687     if (vinfo) {
   688         if (_this->gl_config.major_version < 3 &&
   689             _this->gl_config.profile_mask == 0 &&
   690             _this->gl_config.flags == 0) {
   691             /* Create legacy context */
   692             context =
   693                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   694         } else {
   695             /* max 14 attributes plus terminator */
   696             int attribs[15] = {
   697                 GLX_CONTEXT_MAJOR_VERSION_ARB,
   698                 _this->gl_config.major_version,
   699                 GLX_CONTEXT_MINOR_VERSION_ARB,
   700                 _this->gl_config.minor_version,
   701                 0
   702             };
   703             int iattr = 4;
   704 
   705             /* SDL profile bits match GLX profile bits */
   706             if( _this->gl_config.profile_mask != 0 ) {
   707                 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   708                 attribs[iattr++] = _this->gl_config.profile_mask;
   709             }
   710 
   711             /* SDL flags match GLX flags */
   712             if( _this->gl_config.flags != 0 ) {
   713                 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   714                 attribs[iattr++] = _this->gl_config.flags;
   715             }
   716 
   717             /* only set if glx extension is available */
   718             if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) {
   719                 attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB;
   720                 attribs[iattr++] = 
   721                     _this->gl_config.release_behavior ? 
   722                     GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : 
   723                     GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
   724             }
   725 
   726             /* only set if glx extension is available */
   727             if( _this->gl_data->HAS_GLX_ARB_create_context_robustness ) {
   728                 attribs[iattr++] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
   729                 attribs[iattr++] =
   730                     _this->gl_config.reset_notification ?
   731                     GLX_LOSE_CONTEXT_ON_RESET_ARB :
   732                     GLX_NO_RESET_NOTIFICATION_ARB;
   733             }
   734 
   735             /* only set if glx extension is available */
   736             if( _this->gl_data->HAS_GLX_ARB_create_context_no_error ) {
   737                 attribs[iattr++] = GLX_CONTEXT_OPENGL_NO_ERROR_ARB;
   738                 attribs[iattr++] = _this->gl_config.no_error;
   739             }
   740 
   741             attribs[iattr++] = 0;
   742 
   743             /* Get a pointer to the context creation function for GL 3.0 */
   744             if (!_this->gl_data->glXCreateContextAttribsARB) {
   745                 SDL_SetError("OpenGL 3.0 and later are not supported by this system");
   746             } else {
   747                 int glxAttribs[64];
   748 
   749                 /* Create a GL 3.x context */
   750                 GLXFBConfig *framebuffer_config = NULL;
   751                 int fbcount = 0;
   752                 int *pvistypeattr = NULL;
   753 
   754                 X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE,&pvistypeattr);
   755 
   756                 if (_this->gl_data->glXChooseFBConfig) {
   757                     framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
   758                                           DefaultScreen(display), glxAttribs,
   759                                           &fbcount);
   760 
   761                     if (!framebuffer_config && (pvistypeattr != NULL)) {
   762                         *pvistypeattr = None;
   763                         framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
   764                                           DefaultScreen(display), glxAttribs,
   765                                           &fbcount);
   766                     }
   767             
   768                     if (framebuffer_config) {
   769                         context = _this->gl_data->glXCreateContextAttribsARB(display,
   770                                                         framebuffer_config[0],
   771                                                         share_context, True, attribs);
   772                         X11_XFree(framebuffer_config);
   773                     }
   774                 }
   775             }
   776         }
   777         X11_XFree(vinfo);
   778     }
   779     X11_XSync(display, False);
   780     X11_XSetErrorHandler(handler);
   781 
   782     if (!context) {
   783         if (errorCode == Success) {
   784             SDL_SetError("Could not create GL context");
   785         }
   786         return NULL;
   787     }
   788 
   789     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   790         X11_GL_DeleteContext(_this, context);
   791         return NULL;
   792     }
   793 
   794     return context;
   795 }
   796 
   797 int
   798 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   799 {
   800     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   801     Window drawable =
   802         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   803     GLXContext glx_context = (GLXContext) context;
   804     int rc;
   805 
   806     if (!_this->gl_data) {
   807         return SDL_SetError("OpenGL not initialized");
   808     }
   809 
   810     /* We do this to create a clean separation between X and GLX errors. */
   811     X11_XSync(display, False);
   812     errorHandlerOperation = "make GL context current";
   813     errorBase = _this->gl_data->errorBase;
   814     errorCode = Success;
   815     handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
   816     rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context);
   817     X11_XSetErrorHandler(handler);
   818 
   819     if (errorCode != Success) {   /* uhoh, an X error was thrown! */
   820         return -1;  /* the error handler called SDL_SetError() already. */
   821     } else if (!rc) {  /* glXMakeCurrent() failed without throwing an X error */
   822         return SDL_SetError("Unable to make GL context current");
   823     }
   824 
   825     return 0;
   826 }
   827 
   828 /*
   829    0 is a valid argument to glXSwapInterval(MESA|EXT) and setting it to 0
   830    will undo the effect of a previous call with a value that is greater
   831    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   832    argument to glXSwapIntervalSGI and it returns an error if you call it
   833    with 0 as an argument.
   834 */
   835 
   836 static int swapinterval = 0;
   837 int
   838 X11_GL_SetSwapInterval(_THIS, int interval)
   839 {
   840     int status = -1;
   841 
   842     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   843         SDL_SetError("Negative swap interval unsupported in this GL");
   844     } else if (_this->gl_data->glXSwapIntervalEXT) {
   845         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   846         const SDL_WindowData *windowdata = (SDL_WindowData *)
   847             SDL_GL_GetCurrentWindow()->driverdata;
   848 
   849         Window drawable = windowdata->xwindow;
   850 
   851         /*
   852          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   853          * and will be fixed in a future release (probably 319.xx).
   854          *
   855          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   856          * it has the wrong value cached. To work around it, we just run a no-op
   857          * update to the current value.
   858          */
   859         int currentInterval = X11_GL_GetSwapInterval(_this);
   860         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   861         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   862 
   863         status = 0;
   864         swapinterval = interval;
   865     } else if (_this->gl_data->glXSwapIntervalMESA) {
   866         status = _this->gl_data->glXSwapIntervalMESA(interval);
   867         if (status != 0) {
   868             SDL_SetError("glXSwapIntervalMESA failed");
   869         } else {
   870             swapinterval = interval;
   871         }
   872     } else if (_this->gl_data->glXSwapIntervalSGI) {
   873         status = _this->gl_data->glXSwapIntervalSGI(interval);
   874         if (status != 0) {
   875             SDL_SetError("glXSwapIntervalSGI failed");
   876         } else {
   877             swapinterval = interval;
   878         }
   879     } else {
   880         SDL_Unsupported();
   881     }
   882     return status;
   883 }
   884 
   885 int
   886 X11_GL_GetSwapInterval(_THIS)
   887 {
   888     if (_this->gl_data->glXSwapIntervalEXT) {
   889         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   890         const SDL_WindowData *windowdata = (SDL_WindowData *)
   891             SDL_GL_GetCurrentWindow()->driverdata;
   892         Window drawable = windowdata->xwindow;
   893         unsigned int allow_late_swap_tearing = 0;
   894         unsigned int interval = 0;
   895 
   896         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   897             _this->gl_data->glXQueryDrawable(display, drawable,
   898                                             GLX_LATE_SWAPS_TEAR_EXT,
   899                                             &allow_late_swap_tearing);
   900         }
   901 
   902         _this->gl_data->glXQueryDrawable(display, drawable,
   903                                          GLX_SWAP_INTERVAL_EXT, &interval);
   904 
   905         if ((allow_late_swap_tearing) && (interval > 0)) {
   906             return -((int) interval);
   907         }
   908 
   909         return (int) interval;
   910     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   911         return _this->gl_data->glXGetSwapIntervalMESA();
   912     } else {
   913         return swapinterval;
   914     }
   915 }
   916 
   917 int
   918 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   919 {
   920     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   921     Display *display = data->videodata->display;
   922 
   923     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   924     return 0;
   925 }
   926 
   927 void
   928 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   929 {
   930     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   931     GLXContext glx_context = (GLXContext) context;
   932 
   933     if (!_this->gl_data) {
   934         return;
   935     }
   936     _this->gl_data->glXDestroyContext(display, glx_context);
   937     X11_XSync(display, False);
   938 }
   939 
   940 #endif /* SDL_VIDEO_OPENGL_GLX */
   941 
   942 #endif /* SDL_VIDEO_DRIVER_X11 */
   943 
   944 /* vi: set ts=4 sw=4 expandtab: */