src/video/x11/SDL_x11opengl.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 12 Dec 2019 19:07:26 -0800
changeset 13347 99ecd178999f
parent 13130 502bb7d04f0a
permissions -rw-r--r--
Fixed binding D-pad on NES30 controller
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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  "/opt/X11/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     if (w) {
   467         X11_XDestroyWindow(display, w);
   468     }
   469     X11_PumpEvents(_this);
   470 }
   471 
   472 /* glXChooseVisual and glXChooseFBConfig have some small differences in
   473  * the attribute encoding, it can be chosen with the for_FBConfig parameter.
   474  * Some targets fail if you use GLX_X_VISUAL_TYPE_EXT/GLX_DIRECT_COLOR_EXT,
   475  *  so it gets specified last if used and is pointed to by *_pvistypeattr.
   476  *  In case of failure, if that pointer is not NULL, set that pointer to None
   477  *  and try again.
   478  */
   479 static int
   480 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig, int **_pvistypeattr)
   481 {
   482     int i = 0;
   483     const int MAX_ATTRIBUTES = 64;
   484     int *pvistypeattr = NULL;
   485 
   486     /* assert buffer is large enough to hold all SDL attributes. */
   487     SDL_assert(size >= MAX_ATTRIBUTES);
   488 
   489     /* Setup our GLX attributes according to the gl_config. */
   490     if( for_FBConfig ) {
   491         attribs[i++] = GLX_RENDER_TYPE;
   492         attribs[i++] = GLX_RGBA_BIT;
   493     } else {
   494         attribs[i++] = GLX_RGBA;
   495     }
   496     attribs[i++] = GLX_RED_SIZE;
   497     attribs[i++] = _this->gl_config.red_size;
   498     attribs[i++] = GLX_GREEN_SIZE;
   499     attribs[i++] = _this->gl_config.green_size;
   500     attribs[i++] = GLX_BLUE_SIZE;
   501     attribs[i++] = _this->gl_config.blue_size;
   502 
   503     if (_this->gl_config.alpha_size) {
   504         attribs[i++] = GLX_ALPHA_SIZE;
   505         attribs[i++] = _this->gl_config.alpha_size;
   506     }
   507 
   508     if (_this->gl_config.double_buffer) {
   509         attribs[i++] = GLX_DOUBLEBUFFER;
   510         if( for_FBConfig ) {
   511             attribs[i++] = True;
   512         }
   513     }
   514 
   515     attribs[i++] = GLX_DEPTH_SIZE;
   516     attribs[i++] = _this->gl_config.depth_size;
   517 
   518     if (_this->gl_config.stencil_size) {
   519         attribs[i++] = GLX_STENCIL_SIZE;
   520         attribs[i++] = _this->gl_config.stencil_size;
   521     }
   522 
   523     if (_this->gl_config.accum_red_size) {
   524         attribs[i++] = GLX_ACCUM_RED_SIZE;
   525         attribs[i++] = _this->gl_config.accum_red_size;
   526     }
   527 
   528     if (_this->gl_config.accum_green_size) {
   529         attribs[i++] = GLX_ACCUM_GREEN_SIZE;
   530         attribs[i++] = _this->gl_config.accum_green_size;
   531     }
   532 
   533     if (_this->gl_config.accum_blue_size) {
   534         attribs[i++] = GLX_ACCUM_BLUE_SIZE;
   535         attribs[i++] = _this->gl_config.accum_blue_size;
   536     }
   537 
   538     if (_this->gl_config.accum_alpha_size) {
   539         attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
   540         attribs[i++] = _this->gl_config.accum_alpha_size;
   541     }
   542 
   543     if (_this->gl_config.stereo) {
   544         attribs[i++] = GLX_STEREO;
   545         if( for_FBConfig ) {
   546             attribs[i++] = True;
   547         }
   548     }
   549 
   550     if (_this->gl_config.multisamplebuffers) {
   551         attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
   552         attribs[i++] = _this->gl_config.multisamplebuffers;
   553     }
   554 
   555     if (_this->gl_config.multisamplesamples) {
   556         attribs[i++] = GLX_SAMPLES_ARB;
   557         attribs[i++] = _this->gl_config.multisamplesamples;
   558     }
   559 
   560     if (_this->gl_config.framebuffer_srgb_capable) {
   561         attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
   562         attribs[i++] = True;  /* always needed, for_FBConfig or not! */
   563     }
   564 
   565     if (_this->gl_config.accelerated >= 0 &&
   566         _this->gl_data->HAS_GLX_EXT_visual_rating) {
   567         attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
   568         attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
   569                                                       GLX_SLOW_VISUAL_EXT;
   570     }
   571 
   572     /* If we're supposed to use DirectColor visuals, and we've got the
   573        EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
   574     if (X11_UseDirectColorVisuals() &&
   575         _this->gl_data->HAS_GLX_EXT_visual_info) {
   576         pvistypeattr = &attribs[i];
   577         attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
   578         attribs[i++] = GLX_DIRECT_COLOR_EXT;
   579     }
   580 
   581     attribs[i++] = None;
   582 
   583     SDL_assert(i <= MAX_ATTRIBUTES);
   584 
   585     if (_pvistypeattr) {
   586         *_pvistypeattr = pvistypeattr;
   587     }
   588 
   589     return i;
   590 }
   591 
   592 XVisualInfo *
   593 X11_GL_GetVisual(_THIS, Display * display, int screen)
   594 {
   595     /* 64 seems nice. */
   596     int attribs[64];
   597     XVisualInfo *vinfo;
   598     int *pvistypeattr = NULL;
   599 
   600     if (!_this->gl_data) {
   601         /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
   602         return NULL;
   603     }
   604 
   605     X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr);
   606     vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   607 
   608     if (!vinfo && (pvistypeattr != NULL)) {
   609         *pvistypeattr = None;
   610         vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   611     }
   612 
   613     if (!vinfo) {
   614         SDL_SetError("Couldn't find matching GLX visual");
   615     }
   616     return vinfo;
   617 }
   618 
   619 static int (*handler) (Display *, XErrorEvent *) = NULL;
   620 static const char *errorHandlerOperation = NULL;
   621 static int errorBase = 0;
   622 static int errorCode = 0;
   623 static int
   624 X11_GL_ErrorHandler(Display * d, XErrorEvent * e)
   625 {
   626     char *x11_error = NULL;
   627     char x11_error_locale[256];
   628 
   629     errorCode = e->error_code;
   630     if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
   631     {
   632         x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
   633     }
   634 
   635     if (x11_error)
   636     {
   637         SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error);
   638         SDL_free(x11_error);
   639     }
   640     else
   641     {
   642         SDL_SetError("Could not %s: %i (Base %i)", errorHandlerOperation, errorCode, errorBase);
   643     }
   644 
   645     return (0);
   646 }
   647 
   648 SDL_bool
   649 X11_GL_UseEGL(_THIS)
   650 {
   651     SDL_assert(_this->gl_data != NULL);
   652     SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
   653 
   654     return (SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, SDL_FALSE)
   655             || _this->gl_config.major_version == 1 /* No GLX extension for OpenGL ES 1.x profiles. */
   656             || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major
   657             || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major
   658                 && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor));
   659 }
   660 
   661 SDL_GLContext
   662 X11_GL_CreateContext(_THIS, SDL_Window * window)
   663 {
   664     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   665     Display *display = data->videodata->display;
   666     int screen =
   667         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
   668     XWindowAttributes xattr;
   669     XVisualInfo v, *vinfo;
   670     int n;
   671     GLXContext context = NULL, share_context;
   672 
   673     if (_this->gl_config.share_with_current_context) {
   674         share_context = (GLXContext)SDL_GL_GetCurrentContext();
   675     } else {
   676         share_context = NULL;
   677     }
   678 
   679     /* We do this to create a clean separation between X and GLX errors. */
   680     X11_XSync(display, False);
   681     errorHandlerOperation = "create GL context";
   682     errorBase = _this->gl_data->errorBase;
   683     errorCode = Success;
   684     handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
   685     X11_XGetWindowAttributes(display, data->xwindow, &xattr);
   686     v.screen = screen;
   687     v.visualid = X11_XVisualIDFromVisual(xattr.visual);
   688     vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   689     if (vinfo) {
   690         if (_this->gl_config.major_version < 3 &&
   691             _this->gl_config.profile_mask == 0 &&
   692             _this->gl_config.flags == 0) {
   693             /* Create legacy context */
   694             context =
   695                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   696         } else {
   697             /* max 14 attributes plus terminator */
   698             int attribs[15] = {
   699                 GLX_CONTEXT_MAJOR_VERSION_ARB,
   700                 _this->gl_config.major_version,
   701                 GLX_CONTEXT_MINOR_VERSION_ARB,
   702                 _this->gl_config.minor_version,
   703                 0
   704             };
   705             int iattr = 4;
   706 
   707             /* SDL profile bits match GLX profile bits */
   708             if( _this->gl_config.profile_mask != 0 ) {
   709                 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   710                 attribs[iattr++] = _this->gl_config.profile_mask;
   711             }
   712 
   713             /* SDL flags match GLX flags */
   714             if( _this->gl_config.flags != 0 ) {
   715                 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   716                 attribs[iattr++] = _this->gl_config.flags;
   717             }
   718 
   719             /* only set if glx extension is available */
   720             if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) {
   721                 attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB;
   722                 attribs[iattr++] = 
   723                     _this->gl_config.release_behavior ? 
   724                     GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : 
   725                     GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
   726             }
   727 
   728             /* only set if glx extension is available */
   729             if( _this->gl_data->HAS_GLX_ARB_create_context_robustness ) {
   730                 attribs[iattr++] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
   731                 attribs[iattr++] =
   732                     _this->gl_config.reset_notification ?
   733                     GLX_LOSE_CONTEXT_ON_RESET_ARB :
   734                     GLX_NO_RESET_NOTIFICATION_ARB;
   735             }
   736 
   737             /* only set if glx extension is available */
   738             if( _this->gl_data->HAS_GLX_ARB_create_context_no_error ) {
   739                 attribs[iattr++] = GLX_CONTEXT_OPENGL_NO_ERROR_ARB;
   740                 attribs[iattr++] = _this->gl_config.no_error;
   741             }
   742 
   743             attribs[iattr++] = 0;
   744 
   745             /* Get a pointer to the context creation function for GL 3.0 */
   746             if (!_this->gl_data->glXCreateContextAttribsARB) {
   747                 SDL_SetError("OpenGL 3.0 and later are not supported by this system");
   748             } else {
   749                 int glxAttribs[64];
   750 
   751                 /* Create a GL 3.x context */
   752                 GLXFBConfig *framebuffer_config = NULL;
   753                 int fbcount = 0;
   754                 int *pvistypeattr = NULL;
   755 
   756                 X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE,&pvistypeattr);
   757 
   758                 if (_this->gl_data->glXChooseFBConfig) {
   759                     framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
   760                                           DefaultScreen(display), glxAttribs,
   761                                           &fbcount);
   762 
   763                     if (!framebuffer_config && (pvistypeattr != NULL)) {
   764                         *pvistypeattr = None;
   765                         framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
   766                                           DefaultScreen(display), glxAttribs,
   767                                           &fbcount);
   768                     }
   769             
   770                     if (framebuffer_config) {
   771                         context = _this->gl_data->glXCreateContextAttribsARB(display,
   772                                                         framebuffer_config[0],
   773                                                         share_context, True, attribs);
   774                         X11_XFree(framebuffer_config);
   775                     }
   776                 }
   777             }
   778         }
   779         X11_XFree(vinfo);
   780     }
   781     X11_XSync(display, False);
   782     X11_XSetErrorHandler(handler);
   783 
   784     if (!context) {
   785         if (errorCode == Success) {
   786             SDL_SetError("Could not create GL context");
   787         }
   788         return NULL;
   789     }
   790 
   791     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   792         X11_GL_DeleteContext(_this, context);
   793         return NULL;
   794     }
   795 
   796     return context;
   797 }
   798 
   799 int
   800 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   801 {
   802     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   803     Window drawable =
   804         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   805     GLXContext glx_context = (GLXContext) context;
   806     int rc;
   807 
   808     if (!_this->gl_data) {
   809         return SDL_SetError("OpenGL not initialized");
   810     }
   811 
   812     /* We do this to create a clean separation between X and GLX errors. */
   813     X11_XSync(display, False);
   814     errorHandlerOperation = "make GL context current";
   815     errorBase = _this->gl_data->errorBase;
   816     errorCode = Success;
   817     handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
   818     rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context);
   819     X11_XSetErrorHandler(handler);
   820 
   821     if (errorCode != Success) {   /* uhoh, an X error was thrown! */
   822         return -1;  /* the error handler called SDL_SetError() already. */
   823     } else if (!rc) {  /* glXMakeCurrent() failed without throwing an X error */
   824         return SDL_SetError("Unable to make GL context current");
   825     }
   826 
   827     return 0;
   828 }
   829 
   830 /*
   831    0 is a valid argument to glXSwapInterval(MESA|EXT) and setting it to 0
   832    will undo the effect of a previous call with a value that is greater
   833    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   834    argument to glXSwapIntervalSGI and it returns an error if you call it
   835    with 0 as an argument.
   836 */
   837 
   838 static int swapinterval = 0;
   839 int
   840 X11_GL_SetSwapInterval(_THIS, int interval)
   841 {
   842     int status = -1;
   843 
   844     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   845         SDL_SetError("Negative swap interval unsupported in this GL");
   846     } else if (_this->gl_data->glXSwapIntervalEXT) {
   847         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   848         const SDL_WindowData *windowdata = (SDL_WindowData *)
   849             SDL_GL_GetCurrentWindow()->driverdata;
   850 
   851         Window drawable = windowdata->xwindow;
   852 
   853         /*
   854          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   855          * and will be fixed in a future release (probably 319.xx).
   856          *
   857          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   858          * it has the wrong value cached. To work around it, we just run a no-op
   859          * update to the current value.
   860          */
   861         int currentInterval = X11_GL_GetSwapInterval(_this);
   862         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   863         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   864 
   865         status = 0;
   866         swapinterval = interval;
   867     } else if (_this->gl_data->glXSwapIntervalMESA) {
   868         status = _this->gl_data->glXSwapIntervalMESA(interval);
   869         if (status != 0) {
   870             SDL_SetError("glXSwapIntervalMESA failed");
   871         } else {
   872             swapinterval = interval;
   873         }
   874     } else if (_this->gl_data->glXSwapIntervalSGI) {
   875         status = _this->gl_data->glXSwapIntervalSGI(interval);
   876         if (status != 0) {
   877             SDL_SetError("glXSwapIntervalSGI failed");
   878         } else {
   879             swapinterval = interval;
   880         }
   881     } else {
   882         SDL_Unsupported();
   883     }
   884     return status;
   885 }
   886 
   887 int
   888 X11_GL_GetSwapInterval(_THIS)
   889 {
   890     if (_this->gl_data->glXSwapIntervalEXT) {
   891         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   892         const SDL_WindowData *windowdata = (SDL_WindowData *)
   893             SDL_GL_GetCurrentWindow()->driverdata;
   894         Window drawable = windowdata->xwindow;
   895         unsigned int allow_late_swap_tearing = 0;
   896         unsigned int interval = 0;
   897 
   898         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   899             _this->gl_data->glXQueryDrawable(display, drawable,
   900                                             GLX_LATE_SWAPS_TEAR_EXT,
   901                                             &allow_late_swap_tearing);
   902         }
   903 
   904         _this->gl_data->glXQueryDrawable(display, drawable,
   905                                          GLX_SWAP_INTERVAL_EXT, &interval);
   906 
   907         if ((allow_late_swap_tearing) && (interval > 0)) {
   908             return -((int) interval);
   909         }
   910 
   911         return (int) interval;
   912     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   913         return _this->gl_data->glXGetSwapIntervalMESA();
   914     } else {
   915         return swapinterval;
   916     }
   917 }
   918 
   919 int
   920 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   921 {
   922     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   923     Display *display = data->videodata->display;
   924 
   925     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   926     return 0;
   927 }
   928 
   929 void
   930 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   931 {
   932     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   933     GLXContext glx_context = (GLXContext) context;
   934 
   935     if (!_this->gl_data) {
   936         return;
   937     }
   938     _this->gl_data->glXDestroyContext(display, glx_context);
   939     X11_XSync(display, False);
   940 }
   941 
   942 #endif /* SDL_VIDEO_OPENGL_GLX */
   943 
   944 #endif /* SDL_VIDEO_DRIVER_X11 */
   945 
   946 /* vi: set ts=4 sw=4 expandtab: */