src/video/x11/SDL_x11opengl.c
author Sam Lantinga
Mon, 25 Jan 2021 20:51:47 -0800
changeset 14801 c6cc98d3fed8
parent 14640 b2b3343a310d
permissions -rw-r--r--
Fixed bug 5497 - SDL_COMPOSE_ERROR is wrong

UMU

#define SDL_COMPOSE_ERROR(str) SDL_STRINGIFY_ARG(__FUNCTION__) ", " str

I think SDL_STRINGIFY_ARG should be removed.

#define SDL_COMPOSE_ERROR(str) __FUNCTION__ ", " str

(verified with Visual Studio 2019)
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2021 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: */