change SDL 1.2 to SDL 2.0
[platform/upstream/SDL.git] / src / video / x11 / SDL_x11opengl.c
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 #ifndef GLXBadContext
523 #define GLXBadContext 0
524 #endif
525 #ifndef GLXBadFBConfig
526 #define GLXBadFBConfig 9
527 #endif
528 #ifndef GLXBadProfileARB
529 #define GLXBadProfileARB 13
530 #endif
531 static int (*handler) (Display *, XErrorEvent *) = NULL;
532 static const char *errorHandlerOperation = NULL;
533 static int errorBase = 0;
534 static int errorCode = 0;
535 static int
536 X11_GL_ErrorHandler(Display * d, XErrorEvent * e)
537 {
538     char *x11_error = NULL;
539     char x11_error_locale[256];
540
541     errorCode = e->error_code;
542     if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
543     {
544         x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
545     }
546
547     if (x11_error)
548     {
549         SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error);
550         SDL_free(x11_error);
551     }
552     else
553     {
554         SDL_SetError("Could not %s: %i (Base %i)\n", errorHandlerOperation, errorCode, errorBase);
555     }
556
557     return (0);
558 }
559
560 SDL_GLContext
561 X11_GL_CreateContext(_THIS, SDL_Window * window)
562 {
563     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
564     Display *display = data->videodata->display;
565     int screen =
566         ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
567     XWindowAttributes xattr;
568     XVisualInfo v, *vinfo;
569     int n;
570     GLXContext context = NULL, share_context;
571
572     if (_this->gl_config.share_with_current_context) {
573         share_context = (GLXContext)SDL_GL_GetCurrentContext();
574     } else {
575         share_context = NULL;
576     }
577
578     /* We do this to create a clean separation between X and GLX errors. */
579     X11_XSync(display, False);
580     errorHandlerOperation = "create GL context";
581     errorBase = _this->gl_data->errorBase;
582     errorCode = Success;
583     handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
584     X11_XGetWindowAttributes(display, data->xwindow, &xattr);
585     v.screen = screen;
586     v.visualid = X11_XVisualIDFromVisual(xattr.visual);
587     vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
588     if (vinfo) {
589         if (_this->gl_config.major_version < 3 &&
590             _this->gl_config.profile_mask == 0 &&
591             _this->gl_config.flags == 0) {
592             /* Create legacy context */
593             context =
594                 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
595         } else {
596             /* max 10 attributes plus terminator */
597             int attribs[11] = {
598                 GLX_CONTEXT_MAJOR_VERSION_ARB,
599                 _this->gl_config.major_version,
600                 GLX_CONTEXT_MINOR_VERSION_ARB,
601                 _this->gl_config.minor_version,
602                 0
603             };
604             int iattr = 4;
605
606             /* SDL profile bits match GLX profile bits */
607             if( _this->gl_config.profile_mask != 0 ) {
608                 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
609                 attribs[iattr++] = _this->gl_config.profile_mask;
610             }
611
612             /* SDL flags match GLX flags */
613             if( _this->gl_config.flags != 0 ) {
614                 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
615                 attribs[iattr++] = _this->gl_config.flags;
616             }
617
618             /* only set if glx extension is available */
619             if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) {
620                 attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB;
621                 attribs[iattr++] = 
622                     _this->gl_config.release_behavior ? 
623                     GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : 
624                     GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
625             }
626
627             attribs[iattr++] = 0;
628
629             /* Get a pointer to the context creation function for GL 3.0 */
630             if (!_this->gl_data->glXCreateContextAttribsARB) {
631                 SDL_SetError("OpenGL 3.0 and later are not supported by this system");
632             } else {
633                 int glxAttribs[64];
634
635                 /* Create a GL 3.x context */
636                 GLXFBConfig *framebuffer_config = NULL;
637                 int fbcount = 0;
638
639                 X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
640
641                 if (!_this->gl_data->glXChooseFBConfig
642                     || !(framebuffer_config =
643                         _this->gl_data->glXChooseFBConfig(display,
644                                           DefaultScreen(display), glxAttribs,
645                                           &fbcount))) {
646                     SDL_SetError("No good framebuffers found. OpenGL 3.0 and later unavailable");
647                 } else {
648                     context = _this->gl_data->glXCreateContextAttribsARB(display,
649                                                     framebuffer_config[0],
650                                                     share_context, True, attribs);
651                 }
652             }
653         }
654         X11_XFree(vinfo);
655     }
656     X11_XSync(display, False);
657     X11_XSetErrorHandler(handler);
658
659     if (!context) {
660         if (errorCode == Success) {
661             SDL_SetError("Could not create GL context");
662         }
663         return NULL;
664     }
665
666     if (X11_GL_MakeCurrent(_this, window, context) < 0) {
667         X11_GL_DeleteContext(_this, context);
668         return NULL;
669     }
670
671     return context;
672 }
673
674 int
675 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
676 {
677     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
678     Window drawable =
679         (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
680     GLXContext glx_context = (GLXContext) context;
681     int rc;
682
683     if (!_this->gl_data) {
684         return SDL_SetError("OpenGL not initialized");
685     }
686
687     /* We do this to create a clean separation between X and GLX errors. */
688     X11_XSync(display, False);
689     errorHandlerOperation = "make GL context current";
690     errorBase = _this->gl_data->errorBase;
691     errorCode = Success;
692     handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
693     rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context);
694     X11_XSetErrorHandler(handler);
695
696     if (errorCode != Success) {   /* uhoh, an X error was thrown! */
697         return -1;  /* the error handler called SDL_SetError() already. */
698     } else if (!rc) {  /* glxMakeCurrent() failed without throwing an X error */
699         return SDL_SetError("Unable to make GL context current");
700     }
701
702     return 0;
703 }
704
705 /*
706    0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
707    will undo the effect of a previous call with a value that is greater
708    than zero (or at least that is what the docs say). OTOH, 0 is an invalid
709    argument to glxSwapIntervalSGI and it returns an error if you call it
710    with 0 as an argument.
711 */
712
713 static int swapinterval = -1;
714 int
715 X11_GL_SetSwapInterval(_THIS, int interval)
716 {
717     int status = -1;
718
719     if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
720         SDL_SetError("Negative swap interval unsupported in this GL");
721     } else if (_this->gl_data->glXSwapIntervalEXT) {
722         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
723         const SDL_WindowData *windowdata = (SDL_WindowData *)
724             SDL_GL_GetCurrentWindow()->driverdata;
725
726         Window drawable = windowdata->xwindow;
727
728         /*
729          * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
730          * and will be fixed in a future release (probably 319.xx).
731          *
732          * There's a bug where glXSetSwapIntervalEXT ignores updates because
733          * it has the wrong value cached. To work around it, we just run a no-op
734          * update to the current value.
735          */
736         int currentInterval = X11_GL_GetSwapInterval(_this);
737         _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
738         _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
739
740         status = 0;
741         swapinterval = interval;
742     } else if (_this->gl_data->glXSwapIntervalMESA) {
743         status = _this->gl_data->glXSwapIntervalMESA(interval);
744         if (status != 0) {
745             SDL_SetError("glxSwapIntervalMESA failed");
746         } else {
747             swapinterval = interval;
748         }
749     } else if (_this->gl_data->glXSwapIntervalSGI) {
750         status = _this->gl_data->glXSwapIntervalSGI(interval);
751         if (status != 0) {
752             SDL_SetError("glxSwapIntervalSGI failed");
753         } else {
754             swapinterval = interval;
755         }
756     } else {
757         SDL_Unsupported();
758     }
759     return status;
760 }
761
762 int
763 X11_GL_GetSwapInterval(_THIS)
764 {
765     if (_this->gl_data->glXSwapIntervalEXT) {
766         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
767         const SDL_WindowData *windowdata = (SDL_WindowData *)
768             SDL_GL_GetCurrentWindow()->driverdata;
769         Window drawable = windowdata->xwindow;
770         unsigned int allow_late_swap_tearing = 0;
771         unsigned int interval = 0;
772
773         if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
774             _this->gl_data->glXQueryDrawable(display, drawable,
775                                             GLX_LATE_SWAPS_TEAR_EXT,
776                                             &allow_late_swap_tearing);
777         }
778
779         _this->gl_data->glXQueryDrawable(display, drawable,
780                                          GLX_SWAP_INTERVAL_EXT, &interval);
781
782         if ((allow_late_swap_tearing) && (interval > 0)) {
783             return -((int) interval);
784         }
785
786         return (int) interval;
787     } else if (_this->gl_data->glXGetSwapIntervalMESA) {
788         return _this->gl_data->glXGetSwapIntervalMESA();
789     } else {
790         return swapinterval;
791     }
792 }
793
794 void
795 X11_GL_SwapWindow(_THIS, SDL_Window * window)
796 {
797     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
798     Display *display = data->videodata->display;
799
800     _this->gl_data->glXSwapBuffers(display, data->xwindow);
801 }
802
803 void
804 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
805 {
806     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
807     GLXContext glx_context = (GLXContext) context;
808
809     if (!_this->gl_data) {
810         return;
811     }
812     _this->gl_data->glXDestroyContext(display, glx_context);
813     X11_XSync(display, False);
814 }
815
816 #endif /* SDL_VIDEO_OPENGL_GLX */
817
818 #endif /* SDL_VIDEO_DRIVER_X11 */
819
820 /* vi: set ts=4 sw=4 expandtab: */