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
X11_GL_LoadLibrary(_THIS,const char * path)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 *
X11_GL_GetProcAddress(_THIS,const char * proc)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
X11_GL_UnloadLibrary(_THIS)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
HasExtension(const char * extension,const char * extensions)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
X11_GL_InitExtensions(_THIS)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
X11_GL_GetAttributes(_THIS,Display * display,int screen,int * attribs,int size,Bool for_FBConfig)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 *
X11_GL_GetVisual(_THIS,Display * display,int screen)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
X11_GL_ErrorHandler(Display * d,XErrorEvent * e)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
X11_GL_CreateContext(_THIS,SDL_Window * window)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
X11_GL_MakeCurrent(_THIS,SDL_Window * window,SDL_GLContext context)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 = 0;
714 int
X11_GL_SetSwapInterval(_THIS,int interval)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
X11_GL_GetSwapInterval(_THIS)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
X11_GL_SwapWindow(_THIS,SDL_Window * window)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
X11_GL_DeleteContext(_THIS,SDL_GLContext context)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: */
821