sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_x11opengl.c (33311B)


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