2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 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_hints.h"
28 /* GLX implementation of SDL OpenGL support */
30 #if SDL_VIDEO_OPENGL_GLX
31 #include "SDL_loadso.h"
32 #include "SDL_x11opengles.h"
34 #if defined(__IRIX__) || defined(__NetBSD__) || defined(__OpenBSD__)
36 * IRIX doesn't have a GL library versioning system.
37 * NetBSD and OpenBSD have different GL library versions depending on how
38 * the library was installed.
40 #define DEFAULT_OPENGL "libGL.so"
41 #elif defined(__MACOSX__)
42 #define DEFAULT_OPENGL "/opt/X11/lib/libGL.1.dylib"
43 #elif defined(__QNXNTO__)
44 #define DEFAULT_OPENGL "libGL.so.3"
46 #define DEFAULT_OPENGL "libGL.so.1"
50 #define GLX_NONE_EXT 0x8000
53 #ifndef GLX_ARB_multisample
54 #define GLX_ARB_multisample
55 #define GLX_SAMPLE_BUFFERS_ARB 100000
56 #define GLX_SAMPLES_ARB 100001
59 #ifndef GLX_EXT_visual_rating
60 #define GLX_EXT_visual_rating
61 #define GLX_VISUAL_CAVEAT_EXT 0x20
62 #define GLX_NONE_EXT 0x8000
63 #define GLX_SLOW_VISUAL_EXT 0x8001
64 #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
67 #ifndef GLX_EXT_visual_info
68 #define GLX_EXT_visual_info
69 #define GLX_X_VISUAL_TYPE_EXT 0x22
70 #define GLX_DIRECT_COLOR_EXT 0x8003
73 #ifndef GLX_ARB_create_context
74 #define GLX_ARB_create_context
75 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
76 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
77 #define GLX_CONTEXT_FLAGS_ARB 0x2094
78 #define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001
79 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
81 /* Typedef for the GL 3.0 context creation function */
82 typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
91 #ifndef GLX_ARB_create_context_profile
92 #define GLX_ARB_create_context_profile
93 #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
94 #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
95 #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
98 #ifndef GLX_ARB_create_context_robustness
99 #define GLX_ARB_create_context_robustness
100 #define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
101 #define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
102 #define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
103 #define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
106 #ifndef GLX_EXT_create_context_es2_profile
107 #define GLX_EXT_create_context_es2_profile
108 #ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
109 #define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000002
113 #ifndef GLX_ARB_framebuffer_sRGB
114 #define GLX_ARB_framebuffer_sRGB
115 #ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB
116 #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
120 #ifndef GLX_ARB_create_context_no_error
121 #define GLX_ARB_create_context_no_error
122 #ifndef GLX_CONTEXT_OPENGL_NO_ERROR_ARB
123 #define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3
127 #ifndef GLX_EXT_swap_control
128 #define GLX_SWAP_INTERVAL_EXT 0x20F1
129 #define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
132 #ifndef GLX_EXT_swap_control_tear
133 #define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
136 #ifndef GLX_ARB_context_flush_control
137 #define GLX_ARB_context_flush_control
138 #define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
139 #define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000
140 #define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
143 #define OPENGL_REQUIRES_DLOPEN
144 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
146 #define GL_LoadObject(X) dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
147 #define GL_LoadFunction dlsym
148 #define GL_UnloadObject dlclose
150 #define GL_LoadObject SDL_LoadObject
151 #define GL_LoadFunction SDL_LoadFunction
152 #define GL_UnloadObject SDL_UnloadObject
155 static void X11_GL_InitExtensions(_THIS);
158 X11_GL_LoadLibrary(_THIS, const char *path)
163 if (_this->gl_data) {
164 return SDL_SetError("OpenGL context already created");
167 /* Load the OpenGL library */
169 path = SDL_getenv("SDL_OPENGL_LIBRARY");
172 path = DEFAULT_OPENGL;
174 _this->gl_config.dll_handle = GL_LoadObject(path);
175 if (!_this->gl_config.dll_handle) {
176 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
177 SDL_SetError("Failed loading %s: %s", path, dlerror());
181 SDL_strlcpy(_this->gl_config.driver_path, path,
182 SDL_arraysize(_this->gl_config.driver_path));
184 /* Allocate OpenGL memory */
186 (struct SDL_GLDriverData *) SDL_calloc(1,
189 if (!_this->gl_data) {
190 return SDL_OutOfMemory();
193 /* Load function pointers */
194 handle = _this->gl_config.dll_handle;
195 _this->gl_data->glXQueryExtension =
196 (Bool (*)(Display *, int *, int *))
197 GL_LoadFunction(handle, "glXQueryExtension");
198 _this->gl_data->glXGetProcAddress =
199 (void *(*)(const GLubyte *))
200 GL_LoadFunction(handle, "glXGetProcAddressARB");
201 _this->gl_data->glXChooseVisual =
202 (XVisualInfo * (*)(Display *, int, int *))
203 X11_GL_GetProcAddress(_this, "glXChooseVisual");
204 _this->gl_data->glXCreateContext =
205 (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
206 X11_GL_GetProcAddress(_this, "glXCreateContext");
207 _this->gl_data->glXDestroyContext =
208 (void (*)(Display *, GLXContext))
209 X11_GL_GetProcAddress(_this, "glXDestroyContext");
210 _this->gl_data->glXMakeCurrent =
211 (int (*)(Display *, GLXDrawable, GLXContext))
212 X11_GL_GetProcAddress(_this, "glXMakeCurrent");
213 _this->gl_data->glXSwapBuffers =
214 (void (*)(Display *, GLXDrawable))
215 X11_GL_GetProcAddress(_this, "glXSwapBuffers");
216 _this->gl_data->glXQueryDrawable =
217 (void (*)(Display*,GLXDrawable,int,unsigned int*))
218 X11_GL_GetProcAddress(_this, "glXQueryDrawable");
220 if (!_this->gl_data->glXQueryExtension ||
221 !_this->gl_data->glXChooseVisual ||
222 !_this->gl_data->glXCreateContext ||
223 !_this->gl_data->glXDestroyContext ||
224 !_this->gl_data->glXMakeCurrent ||
225 !_this->gl_data->glXSwapBuffers) {
226 return SDL_SetError("Could not retrieve OpenGL functions");
229 display = ((SDL_VideoData *) _this->driverdata)->display;
230 if (!_this->gl_data->glXQueryExtension(display, &_this->gl_data->errorBase, &_this->gl_data->eventBase)) {
231 return SDL_SetError("GLX is not supported");
234 /* Initialize extensions */
235 /* See lengthy comment about the inc/dec in
236 ../windows/SDL_windowsopengl.c. */
237 ++_this->gl_config.driver_loaded;
238 X11_GL_InitExtensions(_this);
239 --_this->gl_config.driver_loaded;
241 /* If we need a GL ES context and there's no
242 * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions
244 if (((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) ||
245 SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE)) &&
246 X11_GL_UseEGL(_this) ) {
247 #if SDL_VIDEO_OPENGL_EGL
248 X11_GL_UnloadLibrary(_this);
249 /* Better avoid conflicts! */
250 if (_this->gl_config.dll_handle != NULL ) {
251 GL_UnloadObject(_this->gl_config.dll_handle);
252 _this->gl_config.dll_handle = NULL;
254 _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
255 _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
256 _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
257 _this->GL_CreateContext = X11_GLES_CreateContext;
258 _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
259 _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
260 _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
261 _this->GL_SwapWindow = X11_GLES_SwapWindow;
262 _this->GL_DeleteContext = X11_GLES_DeleteContext;
263 return X11_GLES_LoadLibrary(_this, NULL);
265 return SDL_SetError("SDL not configured with EGL support");
273 X11_GL_GetProcAddress(_THIS, const char *proc)
275 if (_this->gl_data->glXGetProcAddress) {
276 return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
278 return GL_LoadFunction(_this->gl_config.dll_handle, proc);
282 X11_GL_UnloadLibrary(_THIS)
284 /* Don't actually unload the library, since it may have registered
285 * X11 shutdown hooks, per the notes at:
286 * http://dri.sourceforge.net/doc/DRIuserguide.html
289 GL_UnloadObject(_this->gl_config.dll_handle);
290 _this->gl_config.dll_handle = NULL;
293 /* Free OpenGL memory */
294 SDL_free(_this->gl_data);
295 _this->gl_data = NULL;
299 HasExtension(const char *extension, const char *extensions)
302 const char *where, *terminator;
307 /* Extension names should not have spaces. */
308 where = SDL_strchr(extension, ' ');
309 if (where || *extension == '\0')
312 /* It takes a bit of care to be fool-proof about parsing the
313 * OpenGL extensions string. Don't be fooled by sub-strings,
319 where = SDL_strstr(start, extension);
323 terminator = where + SDL_strlen(extension);
324 if (where == start || *(where - 1) == ' ')
325 if (*terminator == ' ' || *terminator == '\0')
334 X11_GL_InitExtensions(_THIS)
336 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
337 const int screen = DefaultScreen(display);
338 XVisualInfo *vinfo = NULL;
340 GLXContext prev_ctx = 0;
341 GLXDrawable prev_drawable = 0;
342 GLXContext context = 0;
343 const char *(*glXQueryExtensionsStringFunc) (Display *, int);
344 const char *extensions;
346 vinfo = X11_GL_GetVisual(_this, display, screen);
348 GLXContext (*glXGetCurrentContextFunc) (void) =
349 (GLXContext(*)(void))
350 X11_GL_GetProcAddress(_this, "glXGetCurrentContext");
352 GLXDrawable (*glXGetCurrentDrawableFunc) (void) =
353 (GLXDrawable(*)(void))
354 X11_GL_GetProcAddress(_this, "glXGetCurrentDrawable");
356 if (glXGetCurrentContextFunc && glXGetCurrentDrawableFunc) {
357 XSetWindowAttributes xattr;
358 prev_ctx = glXGetCurrentContextFunc();
359 prev_drawable = glXGetCurrentDrawableFunc();
361 xattr.background_pixel = 0;
362 xattr.border_pixel = 0;
364 X11_XCreateColormap(display, RootWindow(display, screen),
365 vinfo->visual, AllocNone);
366 w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0,
367 32, 32, 0, vinfo->depth, InputOutput, vinfo->visual,
368 (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
370 context = _this->gl_data->glXCreateContext(display, vinfo,
373 _this->gl_data->glXMakeCurrent(display, w, context);
380 glXQueryExtensionsStringFunc =
381 (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
382 "glXQueryExtensionsString");
383 if (glXQueryExtensionsStringFunc) {
384 extensions = glXQueryExtensionsStringFunc(display, screen);
389 /* Check for GLX_EXT_swap_control(_tear) */
390 _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
391 if (HasExtension("GLX_EXT_swap_control", extensions)) {
392 _this->gl_data->glXSwapIntervalEXT =
393 (void (*)(Display*,GLXDrawable,int))
394 X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
395 if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
396 _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
400 /* Check for GLX_MESA_swap_control */
401 if (HasExtension("GLX_MESA_swap_control", extensions)) {
402 _this->gl_data->glXSwapIntervalMESA =
403 (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
404 _this->gl_data->glXGetSwapIntervalMESA =
405 (int(*)(void)) X11_GL_GetProcAddress(_this,
406 "glXGetSwapIntervalMESA");
409 /* Check for GLX_SGI_swap_control */
410 if (HasExtension("GLX_SGI_swap_control", extensions)) {
411 _this->gl_data->glXSwapIntervalSGI =
412 (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
415 /* Check for GLX_ARB_create_context */
416 if (HasExtension("GLX_ARB_create_context", extensions)) {
417 _this->gl_data->glXCreateContextAttribsARB =
418 (GLXContext (*)(Display*,GLXFBConfig,GLXContext,Bool,const int *))
419 X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB");
420 _this->gl_data->glXChooseFBConfig =
421 (GLXFBConfig *(*)(Display *, int, const int *, int *))
422 X11_GL_GetProcAddress(_this, "glXChooseFBConfig");
425 /* Check for GLX_EXT_visual_rating */
426 if (HasExtension("GLX_EXT_visual_rating", extensions)) {
427 _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
430 /* Check for GLX_EXT_visual_info */
431 if (HasExtension("GLX_EXT_visual_info", extensions)) {
432 _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
435 /* Check for GLX_EXT_create_context_es2_profile */
436 if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) {
437 /* this wants to call glGetString(), so it needs a context. */
438 /* !!! FIXME: it would be nice not to make a context here though! */
440 SDL_GL_DeduceMaxSupportedESProfile(
441 &_this->gl_data->es_profile_max_supported_version.major,
442 &_this->gl_data->es_profile_max_supported_version.minor
447 /* Check for GLX_ARB_context_flush_control */
448 if (HasExtension("GLX_ARB_context_flush_control", extensions)) {
449 _this->gl_data->HAS_GLX_ARB_context_flush_control = SDL_TRUE;
452 /* Check for GLX_ARB_create_context_robustness */
453 if (HasExtension("GLX_ARB_create_context_robustness", extensions)) {
454 _this->gl_data->HAS_GLX_ARB_create_context_robustness = SDL_TRUE;
457 /* Check for GLX_ARB_create_context_no_error */
458 if (HasExtension("GLX_ARB_create_context_no_error", extensions)) {
459 _this->gl_data->HAS_GLX_ARB_create_context_no_error = SDL_TRUE;
463 _this->gl_data->glXMakeCurrent(display, None, NULL);
464 _this->gl_data->glXDestroyContext(display, context);
465 if (prev_ctx && prev_drawable) {
466 _this->gl_data->glXMakeCurrent(display, prev_drawable, prev_ctx);
471 X11_XDestroyWindow(display, w);
473 X11_PumpEvents(_this);
476 /* glXChooseVisual and glXChooseFBConfig have some small differences in
477 * the attribute encoding, it can be chosen with the for_FBConfig parameter.
478 * Some targets fail if you use GLX_X_VISUAL_TYPE_EXT/GLX_DIRECT_COLOR_EXT,
479 * so it gets specified last if used and is pointed to by *_pvistypeattr.
480 * In case of failure, if that pointer is not NULL, set that pointer to None
484 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig, int **_pvistypeattr)
487 const int MAX_ATTRIBUTES = 64;
488 int *pvistypeattr = NULL;
490 /* assert buffer is large enough to hold all SDL attributes. */
491 SDL_assert(size >= MAX_ATTRIBUTES);
493 /* Setup our GLX attributes according to the gl_config. */
495 attribs[i++] = GLX_RENDER_TYPE;
496 attribs[i++] = GLX_RGBA_BIT;
498 attribs[i++] = GLX_RGBA;
500 attribs[i++] = GLX_RED_SIZE;
501 attribs[i++] = _this->gl_config.red_size;
502 attribs[i++] = GLX_GREEN_SIZE;
503 attribs[i++] = _this->gl_config.green_size;
504 attribs[i++] = GLX_BLUE_SIZE;
505 attribs[i++] = _this->gl_config.blue_size;
507 if (_this->gl_config.alpha_size) {
508 attribs[i++] = GLX_ALPHA_SIZE;
509 attribs[i++] = _this->gl_config.alpha_size;
512 if (_this->gl_config.double_buffer) {
513 attribs[i++] = GLX_DOUBLEBUFFER;
519 attribs[i++] = GLX_DEPTH_SIZE;
520 attribs[i++] = _this->gl_config.depth_size;
522 if (_this->gl_config.stencil_size) {
523 attribs[i++] = GLX_STENCIL_SIZE;
524 attribs[i++] = _this->gl_config.stencil_size;
527 if (_this->gl_config.accum_red_size) {
528 attribs[i++] = GLX_ACCUM_RED_SIZE;
529 attribs[i++] = _this->gl_config.accum_red_size;
532 if (_this->gl_config.accum_green_size) {
533 attribs[i++] = GLX_ACCUM_GREEN_SIZE;
534 attribs[i++] = _this->gl_config.accum_green_size;
537 if (_this->gl_config.accum_blue_size) {
538 attribs[i++] = GLX_ACCUM_BLUE_SIZE;
539 attribs[i++] = _this->gl_config.accum_blue_size;
542 if (_this->gl_config.accum_alpha_size) {
543 attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
544 attribs[i++] = _this->gl_config.accum_alpha_size;
547 if (_this->gl_config.stereo) {
548 attribs[i++] = GLX_STEREO;
554 if (_this->gl_config.multisamplebuffers) {
555 attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
556 attribs[i++] = _this->gl_config.multisamplebuffers;
559 if (_this->gl_config.multisamplesamples) {
560 attribs[i++] = GLX_SAMPLES_ARB;
561 attribs[i++] = _this->gl_config.multisamplesamples;
564 if (_this->gl_config.framebuffer_srgb_capable) {
565 attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
566 attribs[i++] = True; /* always needed, for_FBConfig or not! */
569 if (_this->gl_config.accelerated >= 0 &&
570 _this->gl_data->HAS_GLX_EXT_visual_rating) {
571 attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
572 attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
576 /* If we're supposed to use DirectColor visuals, and we've got the
577 EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
578 if (X11_UseDirectColorVisuals() &&
579 _this->gl_data->HAS_GLX_EXT_visual_info) {
580 pvistypeattr = &attribs[i];
581 attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
582 attribs[i++] = GLX_DIRECT_COLOR_EXT;
587 SDL_assert(i <= MAX_ATTRIBUTES);
590 *_pvistypeattr = pvistypeattr;
597 X11_GL_GetVisual(_THIS, Display * display, int screen)
602 int *pvistypeattr = NULL;
604 if (!_this->gl_data) {
605 /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
609 X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr);
610 vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
612 if (!vinfo && (pvistypeattr != NULL)) {
613 *pvistypeattr = None;
614 vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
618 SDL_SetError("Couldn't find matching GLX visual");
623 static int (*handler) (Display *, XErrorEvent *) = NULL;
624 static const char *errorHandlerOperation = NULL;
625 static int errorBase = 0;
626 static int errorCode = 0;
628 X11_GL_ErrorHandler(Display * d, XErrorEvent * e)
630 char *x11_error = NULL;
631 char x11_error_locale[256];
633 errorCode = e->error_code;
634 if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
636 x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
641 SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error);
646 SDL_SetError("Could not %s: %i (Base %i)", errorHandlerOperation, errorCode, errorBase);
655 SDL_assert(_this->gl_data != NULL);
656 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE))
658 /* use of EGL has been requested, even for desktop GL */
662 SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
663 return (SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, SDL_FALSE)
664 || _this->gl_config.major_version == 1 /* No GLX extension for OpenGL ES 1.x profiles. */
665 || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major
666 || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major
667 && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor));
671 X11_GL_CreateContext(_THIS, SDL_Window * window)
673 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
674 Display *display = data->videodata->display;
676 ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
677 XWindowAttributes xattr;
678 XVisualInfo v, *vinfo;
680 GLXContext context = NULL, share_context;
682 if (_this->gl_config.share_with_current_context) {
683 share_context = (GLXContext)SDL_GL_GetCurrentContext();
685 share_context = NULL;
688 /* We do this to create a clean separation between X and GLX errors. */
689 X11_XSync(display, False);
690 errorHandlerOperation = "create GL context";
691 errorBase = _this->gl_data->errorBase;
693 handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
694 X11_XGetWindowAttributes(display, data->xwindow, &xattr);
696 v.visualid = X11_XVisualIDFromVisual(xattr.visual);
697 vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
699 if (_this->gl_config.major_version < 3 &&
700 _this->gl_config.profile_mask == 0 &&
701 _this->gl_config.flags == 0) {
702 /* Create legacy context */
704 _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
706 /* max 14 attributes plus terminator */
708 GLX_CONTEXT_MAJOR_VERSION_ARB,
709 _this->gl_config.major_version,
710 GLX_CONTEXT_MINOR_VERSION_ARB,
711 _this->gl_config.minor_version,
716 /* SDL profile bits match GLX profile bits */
717 if( _this->gl_config.profile_mask != 0 ) {
718 attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
719 attribs[iattr++] = _this->gl_config.profile_mask;
722 /* SDL flags match GLX flags */
723 if( _this->gl_config.flags != 0 ) {
724 attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
725 attribs[iattr++] = _this->gl_config.flags;
728 /* only set if glx extension is available */
729 if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) {
730 attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB;
732 _this->gl_config.release_behavior ?
733 GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :
734 GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
737 /* only set if glx extension is available */
738 if( _this->gl_data->HAS_GLX_ARB_create_context_robustness ) {
739 attribs[iattr++] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
741 _this->gl_config.reset_notification ?
742 GLX_LOSE_CONTEXT_ON_RESET_ARB :
743 GLX_NO_RESET_NOTIFICATION_ARB;
746 /* only set if glx extension is available */
747 if( _this->gl_data->HAS_GLX_ARB_create_context_no_error ) {
748 attribs[iattr++] = GLX_CONTEXT_OPENGL_NO_ERROR_ARB;
749 attribs[iattr++] = _this->gl_config.no_error;
752 attribs[iattr++] = 0;
754 /* Get a pointer to the context creation function for GL 3.0 */
755 if (!_this->gl_data->glXCreateContextAttribsARB) {
756 SDL_SetError("OpenGL 3.0 and later are not supported by this system");
760 /* Create a GL 3.x context */
761 GLXFBConfig *framebuffer_config = NULL;
763 int *pvistypeattr = NULL;
765 X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE,&pvistypeattr);
767 if (_this->gl_data->glXChooseFBConfig) {
768 framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
769 DefaultScreen(display), glxAttribs,
772 if (!framebuffer_config && (pvistypeattr != NULL)) {
773 *pvistypeattr = None;
774 framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
775 DefaultScreen(display), glxAttribs,
779 if (framebuffer_config) {
780 context = _this->gl_data->glXCreateContextAttribsARB(display,
781 framebuffer_config[0],
782 share_context, True, attribs);
783 X11_XFree(framebuffer_config);
790 X11_XSync(display, False);
791 X11_XSetErrorHandler(handler);
794 if (errorCode == Success) {
795 SDL_SetError("Could not create GL context");
800 if (X11_GL_MakeCurrent(_this, window, context) < 0) {
801 X11_GL_DeleteContext(_this, context);
809 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
811 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
813 (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
814 GLXContext glx_context = (GLXContext) context;
817 if (!_this->gl_data) {
818 return SDL_SetError("OpenGL not initialized");
821 /* We do this to create a clean separation between X and GLX errors. */
822 X11_XSync(display, False);
823 errorHandlerOperation = "make GL context current";
824 errorBase = _this->gl_data->errorBase;
826 handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
827 rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context);
828 X11_XSetErrorHandler(handler);
830 if (errorCode != Success) { /* uhoh, an X error was thrown! */
831 return -1; /* the error handler called SDL_SetError() already. */
832 } else if (!rc) { /* glXMakeCurrent() failed without throwing an X error */
833 return SDL_SetError("Unable to make GL context current");
840 0 is a valid argument to glXSwapInterval(MESA|EXT) and setting it to 0
841 will undo the effect of a previous call with a value that is greater
842 than zero (or at least that is what the docs say). OTOH, 0 is an invalid
843 argument to glXSwapIntervalSGI and it returns an error if you call it
844 with 0 as an argument.
847 static int swapinterval = 0;
849 X11_GL_SetSwapInterval(_THIS, int interval)
853 if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
854 SDL_SetError("Negative swap interval unsupported in this GL");
855 } else if (_this->gl_data->glXSwapIntervalEXT) {
856 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
857 const SDL_WindowData *windowdata = (SDL_WindowData *)
858 SDL_GL_GetCurrentWindow()->driverdata;
860 Window drawable = windowdata->xwindow;
863 * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
864 * and will be fixed in a future release (probably 319.xx).
866 * There's a bug where glXSetSwapIntervalEXT ignores updates because
867 * it has the wrong value cached. To work around it, we just run a no-op
868 * update to the current value.
870 int currentInterval = X11_GL_GetSwapInterval(_this);
871 _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
872 _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
875 swapinterval = interval;
876 } else if (_this->gl_data->glXSwapIntervalMESA) {
877 status = _this->gl_data->glXSwapIntervalMESA(interval);
879 SDL_SetError("glXSwapIntervalMESA failed");
881 swapinterval = interval;
883 } else if (_this->gl_data->glXSwapIntervalSGI) {
884 status = _this->gl_data->glXSwapIntervalSGI(interval);
886 SDL_SetError("glXSwapIntervalSGI failed");
888 swapinterval = interval;
897 X11_GL_GetSwapInterval(_THIS)
899 if (_this->gl_data->glXSwapIntervalEXT) {
900 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
901 const SDL_WindowData *windowdata = (SDL_WindowData *)
902 SDL_GL_GetCurrentWindow()->driverdata;
903 Window drawable = windowdata->xwindow;
904 unsigned int allow_late_swap_tearing = 0;
905 unsigned int interval = 0;
907 if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
908 _this->gl_data->glXQueryDrawable(display, drawable,
909 GLX_LATE_SWAPS_TEAR_EXT,
910 &allow_late_swap_tearing);
913 _this->gl_data->glXQueryDrawable(display, drawable,
914 GLX_SWAP_INTERVAL_EXT, &interval);
916 if ((allow_late_swap_tearing) && (interval > 0)) {
917 return -((int) interval);
920 return (int) interval;
921 } else if (_this->gl_data->glXGetSwapIntervalMESA) {
922 return _this->gl_data->glXGetSwapIntervalMESA();
929 X11_GL_SwapWindow(_THIS, SDL_Window * window)
931 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
932 Display *display = data->videodata->display;
934 _this->gl_data->glXSwapBuffers(display, data->xwindow);
939 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
941 Display *display = ((SDL_VideoData *) _this->driverdata)->display;
942 GLXContext glx_context = (GLXContext) context;
944 if (!_this->gl_data) {
947 _this->gl_data->glXDestroyContext(display, glx_context);
948 X11_XSync(display, False);
951 #endif /* SDL_VIDEO_OPENGL_GLX */
953 #endif /* SDL_VIDEO_DRIVER_X11 */
955 /* vi: set ts=4 sw=4 expandtab: */