2 Simple DirectMedia Layer
3 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../../SDL_internal.h"
23 #if SDL_VIDEO_DRIVER_X11
25 #include "SDL_x11video.h"
26 #include "SDL_assert.h"
28 /* GLX implementation of SDL OpenGL support */
30 #if SDL_VIDEO_OPENGL_GLX
31 #include "SDL_loadso.h"
32 #include "SDL_x11opengles.h"
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"
42 #define DEFAULT_OPENGL "libGL.so.1"
46 #define GLX_NONE_EXT 0x8000
49 #ifndef GLX_ARB_multisample
50 #define GLX_ARB_multisample
51 #define GLX_SAMPLE_BUFFERS_ARB 100000
52 #define GLX_SAMPLES_ARB 100001
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
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
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
77 /* Typedef for the GL 3.0 context creation function */
78 typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
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
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
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
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
116 #ifndef GLX_EXT_swap_control
117 #define GLX_SWAP_INTERVAL_EXT 0x20F1
118 #define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
121 #ifndef GLX_EXT_swap_control_tear
122 #define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
125 #define OPENGL_REQUIRES_DLOPEN
126 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
128 #define GL_LoadObject(X) dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
129 #define GL_LoadFunction dlsym
130 #define GL_UnloadObject dlclose
132 #define GL_LoadObject SDL_LoadObject
133 #define GL_LoadFunction SDL_LoadFunction
134 #define GL_UnloadObject SDL_UnloadObject
137 static void X11_GL_InitExtensions(_THIS);
141 X11_GL_LoadLibrary(_THIS, const char *path)
146 if (_this->gl_data) {
147 return SDL_SetError("OpenGL context already created");
150 /* Load the OpenGL library */
152 path = SDL_getenv("SDL_OPENGL_LIBRARY");
155 path = DEFAULT_OPENGL;
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());
164 SDL_strlcpy(_this->gl_config.driver_path, path,
165 SDL_arraysize(_this->gl_config.driver_path));
167 /* Allocate OpenGL memory */
169 (struct SDL_GLDriverData *) SDL_calloc(1,
172 if (!_this->gl_data) {
173 return SDL_OutOfMemory();
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");
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");
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");
217 /* Initialize extensions */
218 X11_GL_InitExtensions(_this);
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
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;
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);
243 return SDL_SetError("SDL not configured with EGL support");
251 X11_GL_GetProcAddress(_THIS, const char *proc)
253 if (_this->gl_data->glXGetProcAddress) {
254 return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
256 return GL_LoadFunction(_this->gl_config.dll_handle, proc);
260 X11_GL_UnloadLibrary(_THIS)
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
267 GL_UnloadObject(_this->gl_config.dll_handle);
268 _this->gl_config.dll_handle = NULL;
271 /* Free OpenGL memory */
272 SDL_free(_this->gl_data);
273 _this->gl_data = NULL;
277 HasExtension(const char *extension, const char *extensions)
280 const char *where, *terminator;
282 /* Extension names should not have spaces. */
283 where = SDL_strchr(extension, ' ');
284 if (where || *extension == '\0')
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,
297 where = SDL_strstr(start, extension);
301 terminator = where + SDL_strlen(extension);
302 if (where == start || *(where - 1) == ' ')
303 if (*terminator == ' ' || *terminator == '\0')
312 X11_GL_InitExtensions(_THIS)
314 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
315 int screen = DefaultScreen(display);
317 XSetWindowAttributes xattr;
320 const char *(*glXQueryExtensionsStringFunc) (Display *, int);
321 const char *extensions;
323 vinfo = X11_GL_GetVisual(_this, display, screen);
327 xattr.background_pixel = 0;
328 xattr.border_pixel = 0;
330 X11_XCreateColormap(display, RootWindow(display, screen), vinfo->visual,
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);
337 _this->gl_data->glXMakeCurrent(display, w, context);
341 glXQueryExtensionsStringFunc =
342 (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
343 "glXQueryExtensionsString");
344 if (glXQueryExtensionsStringFunc) {
345 extensions = glXQueryExtensionsStringFunc(display, screen);
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;
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");
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");
376 /* Check for GLX_EXT_visual_rating */
377 if (HasExtension("GLX_EXT_visual_rating", extensions)) {
378 _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
381 /* Check for GLX_EXT_visual_info */
382 if (HasExtension("GLX_EXT_visual_info", extensions)) {
383 _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
386 /* Check for GLX_EXT_create_context_es2_profile */
387 if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) {
388 _this->gl_data->HAS_GLX_EXT_create_context_es2_profile = SDL_TRUE;
392 _this->gl_data->glXMakeCurrent(display, None, NULL);
393 _this->gl_data->glXDestroyContext(display, context);
395 X11_XDestroyWindow(display, w);
396 X11_PumpEvents(_this);
399 /* glXChooseVisual and glXChooseFBConfig have some small differences in
400 * the attribute encoding, it can be chosen with the for_FBConfig parameter.
403 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig)
406 const int MAX_ATTRIBUTES = 64;
408 /* assert buffer is large enough to hold all SDL attributes. */
409 SDL_assert(size >= MAX_ATTRIBUTES);
411 /* Setup our GLX attributes according to the gl_config. */
413 attribs[i++] = GLX_RENDER_TYPE;
414 attribs[i++] = GLX_RGBA_BIT;
416 attribs[i++] = GLX_RGBA;
418 attribs[i++] = GLX_RED_SIZE;
419 attribs[i++] = _this->gl_config.red_size;
420 attribs[i++] = GLX_GREEN_SIZE;
421 attribs[i++] = _this->gl_config.green_size;
422 attribs[i++] = GLX_BLUE_SIZE;
423 attribs[i++] = _this->gl_config.blue_size;
425 if (_this->gl_config.alpha_size) {
426 attribs[i++] = GLX_ALPHA_SIZE;
427 attribs[i++] = _this->gl_config.alpha_size;
430 if (_this->gl_config.double_buffer) {
431 attribs[i++] = GLX_DOUBLEBUFFER;
437 attribs[i++] = GLX_DEPTH_SIZE;
438 attribs[i++] = _this->gl_config.depth_size;
440 if (_this->gl_config.stencil_size) {
441 attribs[i++] = GLX_STENCIL_SIZE;
442 attribs[i++] = _this->gl_config.stencil_size;
445 if (_this->gl_config.accum_red_size) {
446 attribs[i++] = GLX_ACCUM_RED_SIZE;
447 attribs[i++] = _this->gl_config.accum_red_size;
450 if (_this->gl_config.accum_green_size) {
451 attribs[i++] = GLX_ACCUM_GREEN_SIZE;
452 attribs[i++] = _this->gl_config.accum_green_size;
455 if (_this->gl_config.accum_blue_size) {
456 attribs[i++] = GLX_ACCUM_BLUE_SIZE;
457 attribs[i++] = _this->gl_config.accum_blue_size;
460 if (_this->gl_config.accum_alpha_size) {
461 attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
462 attribs[i++] = _this->gl_config.accum_alpha_size;
465 if (_this->gl_config.stereo) {
466 attribs[i++] = GLX_STEREO;
472 if (_this->gl_config.multisamplebuffers) {
473 attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
474 attribs[i++] = _this->gl_config.multisamplebuffers;
477 if (_this->gl_config.multisamplesamples) {
478 attribs[i++] = GLX_SAMPLES_ARB;
479 attribs[i++] = _this->gl_config.multisamplesamples;
482 if (_this->gl_config.framebuffer_srgb_capable) {
483 attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
489 if (_this->gl_config.accelerated >= 0 &&
490 _this->gl_data->HAS_GLX_EXT_visual_rating) {
491 attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
492 attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
496 /* If we're supposed to use DirectColor visuals, and we've got the
497 EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
498 if (X11_UseDirectColorVisuals() &&
499 _this->gl_data->HAS_GLX_EXT_visual_info) {
500 attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
501 attribs[i++] = GLX_DIRECT_COLOR_EXT;
506 SDL_assert(i <= MAX_ATTRIBUTES);
512 X11_GL_GetVisual(_THIS, Display * display, int screen)
518 X11_GL_GetAttributes(_this,display,screen,attribs,64,SDL_FALSE);
520 if (!_this->gl_data) {
521 /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
525 vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
527 SDL_SetError("Couldn't find matching GLX visual");
532 #ifndef GLXBadContext
533 #define GLXBadContext 0
535 #ifndef GLXBadFBConfig
536 #define GLXBadFBConfig 9
538 #ifndef GLXBadProfileARB
539 #define GLXBadProfileARB 13
541 static int (*handler) (Display *, XErrorEvent *) = NULL;
542 static int errorBase = 0;
544 X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e)
546 switch (e->error_code) {
554 (e->error_code == errorBase + GLXBadContext ||
555 e->error_code == errorBase + GLXBadFBConfig ||
556 e->error_code == errorBase + GLXBadProfileARB)) {
559 return (handler(d, e));
564 X11_GL_CreateContext(_THIS, SDL_Window * window)
566 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
567 Display *display = data->videodata->display;
569 ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
570 XWindowAttributes xattr;
571 XVisualInfo v, *vinfo;
573 GLXContext context = NULL, share_context;
574 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = NULL;
576 if (_this->gl_config.share_with_current_context) {
577 share_context = (GLXContext)SDL_GL_GetCurrentContext();
579 share_context = NULL;
582 /* We do this to create a clean separation between X and GLX errors. */
583 X11_XSync(display, False);
584 errorBase = _this->gl_data->errorBase;
585 handler = X11_XSetErrorHandler(X11_GL_CreateContextErrorHandler);
586 X11_XGetWindowAttributes(display, data->xwindow, &xattr);
588 v.visualid = X11_XVisualIDFromVisual(xattr.visual);
589 vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
591 if (_this->gl_config.major_version < 3 &&
592 _this->gl_config.profile_mask == 0 &&
593 _this->gl_config.flags == 0) {
594 /* Create legacy context */
596 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
598 /* If we want a GL 3.0 context or later we need to get a temporary
599 context to grab the new context creation function */
600 GLXContext temp_context =
601 _this->gl_data->glXCreateContext(display, vinfo, NULL, True);
603 /* max 8 attributes plus terminator */
605 GLX_CONTEXT_MAJOR_VERSION_ARB,
606 _this->gl_config.major_version,
607 GLX_CONTEXT_MINOR_VERSION_ARB,
608 _this->gl_config.minor_version,
613 /* SDL profile bits match GLX profile bits */
614 if( _this->gl_config.profile_mask != 0 ) {
615 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
616 attribs[iattr++] = _this->gl_config.profile_mask;
619 /* SDL flags match GLX flags */
620 if( _this->gl_config.flags != 0 ) {
621 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
622 attribs[iattr++] = _this->gl_config.flags;
625 attribs[iattr++] = 0;
627 /* Get a pointer to the context creation function for GL 3.0 */
628 glXCreateContextAttribs =
629 (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
630 glXGetProcAddress((GLubyte *)
631 "glXCreateContextAttribsARB");
632 if (!glXCreateContextAttribs) {
633 SDL_SetError("GL 3.x is not supported");
634 context = temp_context;
638 /* Create a GL 3.x context */
639 GLXFBConfig *framebuffer_config = NULL;
641 GLXFBConfig *(*glXChooseFBConfig) (Display * disp,
643 const int *attrib_list,
648 (*)(Display *, int, const int *,
649 int *)) _this->gl_data->
650 glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
652 X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
654 if (!glXChooseFBConfig
655 || !(framebuffer_config =
656 glXChooseFBConfig(display,
657 DefaultScreen(display), glxAttribs,
660 ("No good framebuffers found. GL 3.x disabled");
661 context = temp_context;
664 glXCreateContextAttribs(display,
665 framebuffer_config[0],
666 share_context, True, attribs);
667 _this->gl_data->glXDestroyContext(display,
675 X11_XSync(display, False);
676 X11_XSetErrorHandler(handler);
679 SDL_SetError("Could not create GL context");
683 if (X11_GL_MakeCurrent(_this, window, context) < 0) {
684 X11_GL_DeleteContext(_this, context);
692 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
694 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
696 (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
697 GLXContext glx_context = (GLXContext) context;
699 if (!_this->gl_data) {
700 return SDL_SetError("OpenGL not initialized");
703 if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) {
704 return SDL_SetError("Unable to make GL context current");
711 0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0
712 will undo the effect of a previous call with a value that is greater
713 than zero (or at least that is what the docs say). OTOH, 0 is an invalid
714 argument to glxSwapIntervalSGI and it returns an error if you call it
715 with 0 as an argument.
718 static int swapinterval = -1;
720 X11_GL_SetSwapInterval(_THIS, int interval)
724 if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
725 SDL_SetError("Negative swap interval unsupported in this GL");
726 } else if (_this->gl_data->glXSwapIntervalEXT) {
727 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
728 const SDL_WindowData *windowdata = (SDL_WindowData *)
729 SDL_GL_GetCurrentWindow()->driverdata;
731 Window drawable = windowdata->xwindow;
734 * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
735 * and will be fixed in a future release (probably 319.xx).
737 * There's a bug where glXSetSwapIntervalEXT ignores updates because
738 * it has the wrong value cached. To work around it, we just run a no-op
739 * update to the current value.
741 int currentInterval = X11_GL_GetSwapInterval(_this);
742 _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
743 _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
746 swapinterval = interval;
747 } else if (_this->gl_data->glXSwapIntervalMESA) {
748 status = _this->gl_data->glXSwapIntervalMESA(interval);
750 SDL_SetError("glxSwapIntervalMESA failed");
752 swapinterval = interval;
754 } else if (_this->gl_data->glXSwapIntervalSGI) {
755 status = _this->gl_data->glXSwapIntervalSGI(interval);
757 SDL_SetError("glxSwapIntervalSGI failed");
759 swapinterval = interval;
768 X11_GL_GetSwapInterval(_THIS)
770 if (_this->gl_data->glXSwapIntervalEXT) {
771 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
772 const SDL_WindowData *windowdata = (SDL_WindowData *)
773 SDL_GL_GetCurrentWindow()->driverdata;
774 Window drawable = windowdata->xwindow;
775 unsigned int allow_late_swap_tearing = 0;
776 unsigned int interval = 0;
778 if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
779 _this->gl_data->glXQueryDrawable(display, drawable,
780 GLX_LATE_SWAPS_TEAR_EXT,
781 &allow_late_swap_tearing);
784 _this->gl_data->glXQueryDrawable(display, drawable,
785 GLX_SWAP_INTERVAL_EXT, &interval);
787 if ((allow_late_swap_tearing) && (interval > 0)) {
788 return -((int) interval);
791 return (int) interval;
792 } else if (_this->gl_data->glXGetSwapIntervalMESA) {
793 return _this->gl_data->glXGetSwapIntervalMESA();
800 X11_GL_SwapWindow(_THIS, SDL_Window * window)
802 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
803 Display *display = data->videodata->display;
805 _this->gl_data->glXSwapBuffers(display, data->xwindow);
809 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
811 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
812 GLXContext glx_context = (GLXContext) context;
814 if (!_this->gl_data) {
817 _this->gl_data->glXDestroyContext(display, glx_context);
818 X11_XSync(display, False);
821 #endif /* SDL_VIDEO_OPENGL_GLX */
823 #endif /* SDL_VIDEO_DRIVER_X11 */
825 /* vi: set ts=4 sw=4 expandtab: */