src/video/x11/SDL_x11opengl.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 17 Feb 2015 22:59:56 -0500
changeset 9354 5709598d628a
parent 9330 26eb20aad02f
child 9355 0d1e81f10b7e
permissions -rw-r--r--
glX HasExtension(): check for NULL ext string first.

It's slightly faster than failing later, after a strchr() call, since this
will get called multiple times with a NULL string if the system totally
fails elsewhere.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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 #define OPENGL_REQUIRES_DLOPEN
   126 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   127 #include <dlfcn.h>
   128 #define GL_LoadObject(X)    dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
   129 #define GL_LoadFunction     dlsym
   130 #define GL_UnloadObject     dlclose
   131 #else
   132 #define GL_LoadObject   SDL_LoadObject
   133 #define GL_LoadFunction SDL_LoadFunction
   134 #define GL_UnloadObject SDL_UnloadObject
   135 #endif
   136 
   137 static void X11_GL_InitExtensions(_THIS);
   138 
   139 
   140 int
   141 X11_GL_LoadLibrary(_THIS, const char *path)
   142 {
   143     Display *display;
   144     void *handle;
   145 
   146     if (_this->gl_data) {
   147         return SDL_SetError("OpenGL context already created");
   148     }
   149 
   150     /* Load the OpenGL library */
   151     if (path == NULL) {
   152         path = SDL_getenv("SDL_OPENGL_LIBRARY");
   153     }
   154     if (path == NULL) {
   155         path = DEFAULT_OPENGL;
   156     }
   157     _this->gl_config.dll_handle = GL_LoadObject(path);
   158     if (!_this->gl_config.dll_handle) {
   159 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
   160         SDL_SetError("Failed loading %s: %s", path, dlerror());
   161 #endif
   162         return -1;
   163     }
   164     SDL_strlcpy(_this->gl_config.driver_path, path,
   165                 SDL_arraysize(_this->gl_config.driver_path));
   166 
   167     /* Allocate OpenGL memory */
   168     _this->gl_data =
   169         (struct SDL_GLDriverData *) SDL_calloc(1,
   170                                                sizeof(struct
   171                                                       SDL_GLDriverData));
   172     if (!_this->gl_data) {
   173         return SDL_OutOfMemory();
   174     }
   175 
   176     /* Load function pointers */
   177     handle = _this->gl_config.dll_handle;
   178     _this->gl_data->glXQueryExtension =
   179         (Bool (*)(Display *, int *, int *))
   180             GL_LoadFunction(handle, "glXQueryExtension");
   181     _this->gl_data->glXGetProcAddress =
   182         (void *(*)(const GLubyte *))
   183             GL_LoadFunction(handle, "glXGetProcAddressARB");
   184     _this->gl_data->glXChooseVisual =
   185         (XVisualInfo * (*)(Display *, int, int *))
   186             X11_GL_GetProcAddress(_this, "glXChooseVisual");
   187     _this->gl_data->glXCreateContext =
   188         (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
   189             X11_GL_GetProcAddress(_this, "glXCreateContext");
   190     _this->gl_data->glXDestroyContext =
   191         (void (*)(Display *, GLXContext))
   192             X11_GL_GetProcAddress(_this, "glXDestroyContext");
   193     _this->gl_data->glXMakeCurrent =
   194         (int (*)(Display *, GLXDrawable, GLXContext))
   195             X11_GL_GetProcAddress(_this, "glXMakeCurrent");
   196     _this->gl_data->glXSwapBuffers =
   197         (void (*)(Display *, GLXDrawable))
   198             X11_GL_GetProcAddress(_this, "glXSwapBuffers");
   199     _this->gl_data->glXQueryDrawable =
   200         (void (*)(Display*,GLXDrawable,int,unsigned int*))
   201             X11_GL_GetProcAddress(_this, "glXQueryDrawable");
   202 
   203     if (!_this->gl_data->glXQueryExtension ||
   204         !_this->gl_data->glXChooseVisual ||
   205         !_this->gl_data->glXCreateContext ||
   206         !_this->gl_data->glXDestroyContext ||
   207         !_this->gl_data->glXMakeCurrent ||
   208         !_this->gl_data->glXSwapBuffers) {
   209         return SDL_SetError("Could not retrieve OpenGL functions");
   210     }
   211 
   212     display = ((SDL_VideoData *) _this->driverdata)->display;
   213     if (!_this->gl_data->glXQueryExtension(display, &_this->gl_data->errorBase, &_this->gl_data->eventBase)) {
   214         return SDL_SetError("GLX is not supported");
   215     }
   216 
   217     /* Initialize extensions */
   218     X11_GL_InitExtensions(_this);
   219     
   220     /* If we need a GL ES context and there's no  
   221      * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions  
   222      */
   223     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && 
   224         ! _this->gl_data->HAS_GLX_EXT_create_context_es2_profile ) {
   225 #if SDL_VIDEO_OPENGL_EGL
   226         X11_GL_UnloadLibrary(_this);
   227         /* Better avoid conflicts! */
   228         if (_this->gl_config.dll_handle != NULL ) {
   229             GL_UnloadObject(_this->gl_config.dll_handle);
   230             _this->gl_config.dll_handle = NULL;
   231         }
   232         _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
   233         _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
   234         _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
   235         _this->GL_CreateContext = X11_GLES_CreateContext;
   236         _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
   237         _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
   238         _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
   239         _this->GL_SwapWindow = X11_GLES_SwapWindow;
   240         _this->GL_DeleteContext = X11_GLES_DeleteContext;
   241         return X11_GLES_LoadLibrary(_this, NULL);
   242 #else
   243         return SDL_SetError("SDL not configured with EGL support");
   244 #endif
   245     }
   246 
   247     return 0;
   248 }
   249 
   250 void *
   251 X11_GL_GetProcAddress(_THIS, const char *proc)
   252 {
   253     if (_this->gl_data->glXGetProcAddress) {
   254         return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
   255     }
   256     return GL_LoadFunction(_this->gl_config.dll_handle, proc);
   257 }
   258 
   259 void
   260 X11_GL_UnloadLibrary(_THIS)
   261 {
   262     /* Don't actually unload the library, since it may have registered
   263      * X11 shutdown hooks, per the notes at:
   264      * http://dri.sourceforge.net/doc/DRIuserguide.html
   265      */
   266 #if 0
   267     GL_UnloadObject(_this->gl_config.dll_handle);
   268     _this->gl_config.dll_handle = NULL;
   269 #endif
   270 
   271     /* Free OpenGL memory */
   272     SDL_free(_this->gl_data);
   273     _this->gl_data = NULL;
   274 }
   275 
   276 static SDL_bool
   277 HasExtension(const char *extension, const char *extensions)
   278 {
   279     const char *start;
   280     const char *where, *terminator;
   281 
   282     if (!extensions)
   283         return SDL_FALSE;
   284 
   285     /* Extension names should not have spaces. */
   286     where = SDL_strchr(extension, ' ');
   287     if (where || *extension == '\0')
   288         return SDL_FALSE;
   289 
   290     /* It takes a bit of care to be fool-proof about parsing the
   291      * OpenGL extensions string. Don't be fooled by sub-strings,
   292      * etc. */
   293 
   294     start = extensions;
   295 
   296     for (;;) {
   297         where = SDL_strstr(start, extension);
   298         if (!where)
   299             break;
   300 
   301         terminator = where + SDL_strlen(extension);
   302         if (where == start || *(where - 1) == ' ')
   303             if (*terminator == ' ' || *terminator == '\0')
   304                 return SDL_TRUE;
   305 
   306         start = terminator;
   307     }
   308     return SDL_FALSE;
   309 }
   310 
   311 static void
   312 X11_GL_InitExtensions(_THIS)
   313 {
   314     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   315     int screen = DefaultScreen(display);
   316     XVisualInfo *vinfo;
   317     XSetWindowAttributes xattr;
   318     Window w;
   319     GLXContext context;
   320     const char *(*glXQueryExtensionsStringFunc) (Display *, int);
   321     const char *extensions;
   322 
   323     vinfo = X11_GL_GetVisual(_this, display, screen);
   324     if (!vinfo) {
   325         return;
   326     }
   327     xattr.background_pixel = 0;
   328     xattr.border_pixel = 0;
   329     xattr.colormap =
   330         X11_XCreateColormap(display, RootWindow(display, screen), vinfo->visual,
   331                         AllocNone);
   332     w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0,
   333                       vinfo->depth, InputOutput, vinfo->visual,
   334                       (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
   335     context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
   336     if (context) {
   337         _this->gl_data->glXMakeCurrent(display, w, context);
   338     }
   339     X11_XFree(vinfo);
   340 
   341     glXQueryExtensionsStringFunc =
   342         (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
   343                                                                 "glXQueryExtensionsString");
   344     if (glXQueryExtensionsStringFunc) {
   345         extensions = glXQueryExtensionsStringFunc(display, screen);
   346     } else {
   347         extensions = NULL;
   348     }
   349 
   350     /* Check for GLX_EXT_swap_control(_tear) */
   351     _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
   352     if (HasExtension("GLX_EXT_swap_control", extensions)) {
   353         _this->gl_data->glXSwapIntervalEXT =
   354             (void (*)(Display*,GLXDrawable,int))
   355                 X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
   356         if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
   357             _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
   358         }
   359     }
   360 
   361     /* Check for GLX_MESA_swap_control */
   362     if (HasExtension("GLX_MESA_swap_control", extensions)) {
   363         _this->gl_data->glXSwapIntervalMESA =
   364             (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
   365         _this->gl_data->glXGetSwapIntervalMESA =
   366             (int(*)(void)) X11_GL_GetProcAddress(_this,
   367                                                    "glXGetSwapIntervalMESA");
   368     }
   369 
   370     /* Check for GLX_SGI_swap_control */
   371     if (HasExtension("GLX_SGI_swap_control", extensions)) {
   372         _this->gl_data->glXSwapIntervalSGI =
   373             (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
   374     }
   375 
   376     /* Check for GLX_ARB_create_context */
   377     if (HasExtension("GLX_ARB_create_context", extensions)) {
   378         _this->gl_data->glXCreateContextAttribsARB =
   379             (GLXContext (*)(Display*,GLXFBConfig,GLXContext,Bool,const int *))
   380                 X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB");
   381         _this->gl_data->glXChooseFBConfig =
   382             (GLXFBConfig *(*)(Display *, int, const int *, int *))
   383                 X11_GL_GetProcAddress(_this, "glXChooseFBConfig");
   384     }
   385 
   386     /* Check for GLX_EXT_visual_rating */
   387     if (HasExtension("GLX_EXT_visual_rating", extensions)) {
   388         _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
   389     }
   390 
   391     /* Check for GLX_EXT_visual_info */
   392     if (HasExtension("GLX_EXT_visual_info", extensions)) {
   393         _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
   394     }
   395     
   396     /* Check for GLX_EXT_create_context_es2_profile */
   397     if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) {
   398         _this->gl_data->HAS_GLX_EXT_create_context_es2_profile = SDL_TRUE;
   399     }
   400 
   401     if (context) {
   402         _this->gl_data->glXMakeCurrent(display, None, NULL);
   403         _this->gl_data->glXDestroyContext(display, context);
   404     }
   405     X11_XDestroyWindow(display, w);
   406     X11_PumpEvents(_this);
   407 }
   408 
   409 /* glXChooseVisual and glXChooseFBConfig have some small differences in
   410  * the attribute encoding, it can be chosen with the for_FBConfig parameter.
   411  */
   412 int
   413 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig)
   414 {
   415     int i = 0;
   416     const int MAX_ATTRIBUTES = 64;
   417 
   418     /* assert buffer is large enough to hold all SDL attributes. */
   419     SDL_assert(size >= MAX_ATTRIBUTES);
   420 
   421     /* Setup our GLX attributes according to the gl_config. */
   422     if( for_FBConfig ) {
   423         attribs[i++] = GLX_RENDER_TYPE;
   424         attribs[i++] = GLX_RGBA_BIT;
   425     } else {
   426         attribs[i++] = GLX_RGBA;
   427     }
   428     attribs[i++] = GLX_RED_SIZE;
   429     attribs[i++] = _this->gl_config.red_size;
   430     attribs[i++] = GLX_GREEN_SIZE;
   431     attribs[i++] = _this->gl_config.green_size;
   432     attribs[i++] = GLX_BLUE_SIZE;
   433     attribs[i++] = _this->gl_config.blue_size;
   434 
   435     if (_this->gl_config.alpha_size) {
   436         attribs[i++] = GLX_ALPHA_SIZE;
   437         attribs[i++] = _this->gl_config.alpha_size;
   438     }
   439 
   440     if (_this->gl_config.double_buffer) {
   441         attribs[i++] = GLX_DOUBLEBUFFER;
   442         if( for_FBConfig ) {
   443             attribs[i++] = True;
   444         }
   445     }
   446 
   447     attribs[i++] = GLX_DEPTH_SIZE;
   448     attribs[i++] = _this->gl_config.depth_size;
   449 
   450     if (_this->gl_config.stencil_size) {
   451         attribs[i++] = GLX_STENCIL_SIZE;
   452         attribs[i++] = _this->gl_config.stencil_size;
   453     }
   454 
   455     if (_this->gl_config.accum_red_size) {
   456         attribs[i++] = GLX_ACCUM_RED_SIZE;
   457         attribs[i++] = _this->gl_config.accum_red_size;
   458     }
   459 
   460     if (_this->gl_config.accum_green_size) {
   461         attribs[i++] = GLX_ACCUM_GREEN_SIZE;
   462         attribs[i++] = _this->gl_config.accum_green_size;
   463     }
   464 
   465     if (_this->gl_config.accum_blue_size) {
   466         attribs[i++] = GLX_ACCUM_BLUE_SIZE;
   467         attribs[i++] = _this->gl_config.accum_blue_size;
   468     }
   469 
   470     if (_this->gl_config.accum_alpha_size) {
   471         attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
   472         attribs[i++] = _this->gl_config.accum_alpha_size;
   473     }
   474 
   475     if (_this->gl_config.stereo) {
   476         attribs[i++] = GLX_STEREO;
   477         if( for_FBConfig ) {
   478             attribs[i++] = True;
   479         }
   480     }
   481 
   482     if (_this->gl_config.multisamplebuffers) {
   483         attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
   484         attribs[i++] = _this->gl_config.multisamplebuffers;
   485     }
   486 
   487     if (_this->gl_config.multisamplesamples) {
   488         attribs[i++] = GLX_SAMPLES_ARB;
   489         attribs[i++] = _this->gl_config.multisamplesamples;
   490     }
   491 
   492     if (_this->gl_config.framebuffer_srgb_capable) {
   493         attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
   494         if( for_FBConfig ) {
   495             attribs[i++] = True;
   496         }
   497     }
   498 
   499     if (_this->gl_config.accelerated >= 0 &&
   500         _this->gl_data->HAS_GLX_EXT_visual_rating) {
   501         attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
   502         attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
   503                                                       GLX_SLOW_VISUAL_EXT;
   504     }
   505 
   506     /* If we're supposed to use DirectColor visuals, and we've got the
   507        EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
   508     if (X11_UseDirectColorVisuals() &&
   509         _this->gl_data->HAS_GLX_EXT_visual_info) {
   510         attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
   511         attribs[i++] = GLX_DIRECT_COLOR_EXT;
   512     }
   513 
   514     attribs[i++] = None;
   515 
   516     SDL_assert(i <= MAX_ATTRIBUTES);
   517 
   518     return i;
   519 }
   520 
   521 XVisualInfo *
   522 X11_GL_GetVisual(_THIS, Display * display, int screen)
   523 {
   524     /* 64 seems nice. */
   525     int attribs[64];
   526     XVisualInfo *vinfo;
   527 
   528     if (!_this->gl_data) {
   529         /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
   530         return NULL;
   531     }
   532 
   533     X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE);
   534     vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
   535     if (!vinfo) {
   536         SDL_SetError("Couldn't find matching GLX visual");
   537     }
   538     return vinfo;
   539 }
   540 
   541 #ifndef GLXBadContext
   542 #define GLXBadContext 0
   543 #endif
   544 #ifndef GLXBadFBConfig
   545 #define GLXBadFBConfig 9
   546 #endif
   547 #ifndef GLXBadProfileARB
   548 #define GLXBadProfileARB 13
   549 #endif
   550 static int (*handler) (Display *, XErrorEvent *) = NULL;
   551 static int errorBase = 0;
   552 static int errorCode = 0;
   553 static int
   554 X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e)
   555 {
   556     char *x11_error = NULL;
   557     char x11_error_locale[256];
   558 
   559     errorCode = e->error_code;
   560     if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
   561     {
   562         x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
   563     }
   564 
   565     if (x11_error)
   566     {
   567         SDL_SetError("Could not create GL context: %s", x11_error);
   568         SDL_free(x11_error);
   569     }
   570     else
   571     {
   572         SDL_SetError("Could not create GL context: %i (Base %i)\n", errorCode, errorBase);
   573     }
   574 
   575     return (0);
   576 }
   577 
   578 SDL_GLContext
   579 X11_GL_CreateContext(_THIS, SDL_Window * window)
   580 {
   581     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   582     Display *display = data->videodata->display;
   583     int screen =
   584         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
   585     XWindowAttributes xattr;
   586     XVisualInfo v, *vinfo;
   587     int n;
   588     GLXContext context = NULL, share_context;
   589 
   590     if (_this->gl_config.share_with_current_context) {
   591         share_context = (GLXContext)SDL_GL_GetCurrentContext();
   592     } else {
   593         share_context = NULL;
   594     }
   595 
   596     /* We do this to create a clean separation between X and GLX errors. */
   597     X11_XSync(display, False);
   598     errorBase = _this->gl_data->errorBase;
   599     errorCode = Success;
   600     handler = X11_XSetErrorHandler(X11_GL_CreateContextErrorHandler);
   601     X11_XGetWindowAttributes(display, data->xwindow, &xattr);
   602     v.screen = screen;
   603     v.visualid = X11_XVisualIDFromVisual(xattr.visual);
   604     vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
   605     if (vinfo) {
   606         if (_this->gl_config.major_version < 3 &&
   607             _this->gl_config.profile_mask == 0 &&
   608             _this->gl_config.flags == 0) {
   609             /* Create legacy context */
   610             context =
   611                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
   612         } else {
   613             /* max 8 attributes plus terminator */
   614             int attribs[9] = {
   615                 GLX_CONTEXT_MAJOR_VERSION_ARB,
   616                 _this->gl_config.major_version,
   617                 GLX_CONTEXT_MINOR_VERSION_ARB,
   618                 _this->gl_config.minor_version,
   619                 0
   620             };
   621             int iattr = 4;
   622 
   623             /* SDL profile bits match GLX profile bits */
   624             if( _this->gl_config.profile_mask != 0 ) {
   625                 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
   626                 attribs[iattr++] = _this->gl_config.profile_mask;
   627             }
   628 
   629             /* SDL flags match GLX flags */
   630             if( _this->gl_config.flags != 0 ) {
   631                 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
   632                 attribs[iattr++] = _this->gl_config.flags;
   633             }
   634 
   635             attribs[iattr++] = 0;
   636 
   637             /* Get a pointer to the context creation function for GL 3.0 */
   638             if (!_this->gl_data->glXCreateContextAttribsARB) {
   639                 SDL_SetError("OpenGL 3.0 and later are not supported by this system");
   640             } else {
   641                 int glxAttribs[64];
   642 
   643                 /* Create a GL 3.x context */
   644                 GLXFBConfig *framebuffer_config = NULL;
   645                 int fbcount = 0;
   646 
   647                 X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
   648 
   649                 if (!_this->gl_data->glXChooseFBConfig
   650                     || !(framebuffer_config =
   651                         _this->gl_data->glXChooseFBConfig(display,
   652                                           DefaultScreen(display), glxAttribs,
   653                                           &fbcount))) {
   654                     SDL_SetError("No good framebuffers found. OpenGL 3.0 and later unavailable");
   655                 } else {
   656                     context = _this->gl_data->glXCreateContextAttribsARB(display,
   657                                                     framebuffer_config[0],
   658                                                     share_context, True, attribs);
   659                 }
   660             }
   661         }
   662         X11_XFree(vinfo);
   663     }
   664     X11_XSync(display, False);
   665     X11_XSetErrorHandler(handler);
   666 
   667     if (!context) {
   668         if (errorCode == Success) {
   669             SDL_SetError("Could not create GL context");
   670         }
   671         return NULL;
   672     }
   673 
   674     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
   675         X11_GL_DeleteContext(_this, context);
   676         return NULL;
   677     }
   678 
   679     return context;
   680 }
   681 
   682 int
   683 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   684 {
   685     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   686     Window drawable =
   687         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
   688     GLXContext glx_context = (GLXContext) context;
   689 
   690     if (!_this->gl_data) {
   691         return SDL_SetError("OpenGL not initialized");
   692     }
   693 
   694     if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
   695         return SDL_SetError("Unable to make GL context current");
   696     }
   697 
   698     return 0;
   699 }
   700 
   701 /*
   702    0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
   703    will undo the effect of a previous call with a value that is greater
   704    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
   705    argument to glxSwapIntervalSGI and it returns an error if you call it
   706    with 0 as an argument.
   707 */
   708 
   709 static int swapinterval = -1;
   710 int
   711 X11_GL_SetSwapInterval(_THIS, int interval)
   712 {
   713     int status = -1;
   714 
   715     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
   716         SDL_SetError("Negative swap interval unsupported in this GL");
   717     } else if (_this->gl_data->glXSwapIntervalEXT) {
   718         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   719         const SDL_WindowData *windowdata = (SDL_WindowData *)
   720             SDL_GL_GetCurrentWindow()->driverdata;
   721 
   722         Window drawable = windowdata->xwindow;
   723 
   724         /*
   725          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
   726          * and will be fixed in a future release (probably 319.xx).
   727          *
   728          * There's a bug where glXSetSwapIntervalEXT ignores updates because
   729          * it has the wrong value cached. To work around it, we just run a no-op
   730          * update to the current value.
   731          */
   732         int currentInterval = X11_GL_GetSwapInterval(_this);
   733         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
   734         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
   735 
   736         status = 0;
   737         swapinterval = interval;
   738     } else if (_this->gl_data->glXSwapIntervalMESA) {
   739         status = _this->gl_data->glXSwapIntervalMESA(interval);
   740         if (status != 0) {
   741             SDL_SetError("glxSwapIntervalMESA failed");
   742         } else {
   743             swapinterval = interval;
   744         }
   745     } else if (_this->gl_data->glXSwapIntervalSGI) {
   746         status = _this->gl_data->glXSwapIntervalSGI(interval);
   747         if (status != 0) {
   748             SDL_SetError("glxSwapIntervalSGI failed");
   749         } else {
   750             swapinterval = interval;
   751         }
   752     } else {
   753         SDL_Unsupported();
   754     }
   755     return status;
   756 }
   757 
   758 int
   759 X11_GL_GetSwapInterval(_THIS)
   760 {
   761     if (_this->gl_data->glXSwapIntervalEXT) {
   762         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   763         const SDL_WindowData *windowdata = (SDL_WindowData *)
   764             SDL_GL_GetCurrentWindow()->driverdata;
   765         Window drawable = windowdata->xwindow;
   766         unsigned int allow_late_swap_tearing = 0;
   767         unsigned int interval = 0;
   768 
   769         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
   770             _this->gl_data->glXQueryDrawable(display, drawable,
   771                                             GLX_LATE_SWAPS_TEAR_EXT,
   772                                             &allow_late_swap_tearing);
   773         }
   774 
   775         _this->gl_data->glXQueryDrawable(display, drawable,
   776                                          GLX_SWAP_INTERVAL_EXT, &interval);
   777 
   778         if ((allow_late_swap_tearing) && (interval > 0)) {
   779             return -((int) interval);
   780         }
   781 
   782         return (int) interval;
   783     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
   784         return _this->gl_data->glXGetSwapIntervalMESA();
   785     } else {
   786         return swapinterval;
   787     }
   788 }
   789 
   790 void
   791 X11_GL_SwapWindow(_THIS, SDL_Window * window)
   792 {
   793     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   794     Display *display = data->videodata->display;
   795 
   796     _this->gl_data->glXSwapBuffers(display, data->xwindow);
   797 }
   798 
   799 void
   800 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
   801 {
   802     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   803     GLXContext glx_context = (GLXContext) context;
   804 
   805     if (!_this->gl_data) {
   806         return;
   807     }
   808     _this->gl_data->glXDestroyContext(display, glx_context);
   809     X11_XSync(display, False);
   810 }
   811 
   812 #endif /* SDL_VIDEO_OPENGL_GLX */
   813 
   814 #endif /* SDL_VIDEO_DRIVER_X11 */
   815 
   816 /* vi: set ts=4 sw=4 expandtab: */