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