SDL  2.0
SDL_x11opengl.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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_hints.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__) || defined(__NetBSD__) || defined(__OpenBSD__)
35 /*
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.
39  */
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"
45 #else
46 #define DEFAULT_OPENGL "libGL.so.1"
47 #endif
48 
49 #ifndef GLX_NONE_EXT
50 #define GLX_NONE_EXT 0x8000
51 #endif
52 
53 #ifndef GLX_ARB_multisample
54 #define GLX_ARB_multisample
55 #define GLX_SAMPLE_BUFFERS_ARB 100000
56 #define GLX_SAMPLES_ARB 100001
57 #endif
58 
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
65 #endif
66 
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
71 #endif
72 
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
80 
81 /* Typedef for the GL 3.0 context creation function */
82 typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
83  GLXFBConfig config,
84  GLXContext
85  share_context,
86  Bool direct,
87  const int
88  *attrib_list);
89 #endif
90 
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
96 #endif
97 
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
104 #endif
105 
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
110 #endif
111 #endif
112 
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
117 #endif
118 #endif
119 
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
124 #endif
125 #endif
126 
127 #ifndef GLX_EXT_swap_control
128 #define GLX_SWAP_INTERVAL_EXT 0x20F1
129 #define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
130 #endif
131 
132 #ifndef GLX_EXT_swap_control_tear
133 #define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
134 #endif
135 
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
141 #endif
142 
143 #define OPENGL_REQUIRES_DLOPEN
144 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
145 #include <dlfcn.h>
146 #define GL_LoadObject(X) dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
147 #define GL_LoadFunction dlsym
148 #define GL_UnloadObject dlclose
149 #else
150 #define GL_LoadObject SDL_LoadObject
151 #define GL_LoadFunction SDL_LoadFunction
152 #define GL_UnloadObject SDL_UnloadObject
153 #endif
154 
155 static void X11_GL_InitExtensions(_THIS);
156 
157 int
158 X11_GL_LoadLibrary(_THIS, const char *path)
159 {
160  Display *display;
161  void *handle;
162 
163  if (_this->gl_data) {
164  return SDL_SetError("OpenGL context already created");
165  }
166 
167  /* Load the OpenGL library */
168  if (path == NULL) {
169  path = SDL_getenv("SDL_OPENGL_LIBRARY");
170  }
171  if (path == NULL) {
172  path = DEFAULT_OPENGL;
173  }
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());
178 #endif
179  return -1;
180  }
183 
184  /* Allocate OpenGL memory */
185  _this->gl_data =
186  (struct SDL_GLDriverData *) SDL_calloc(1,
187  sizeof(struct
189  if (!_this->gl_data) {
190  return SDL_OutOfMemory();
191  }
192 
193  /* Load function pointers */
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");
219 
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");
227  }
228 
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");
232  }
233 
234  /* Initialize extensions */
235  /* See lengthy comment about the inc/dec in
236  ../windows/SDL_windowsopengl.c. */
238  X11_GL_InitExtensions(_this);
240 
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
243  */
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);
253  }
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);
264 #else
265  return SDL_SetError("SDL not configured with EGL support");
266 #endif
267  }
268 
269  return 0;
270 }
271 
272 void *
273 X11_GL_GetProcAddress(_THIS, const char *proc)
274 {
275  if (_this->gl_data->glXGetProcAddress) {
276  return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
277  }
278  return GL_LoadFunction(_this->gl_config.dll_handle, proc);
279 }
280 
281 void
282 X11_GL_UnloadLibrary(_THIS)
283 {
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
287  */
288 #if 0
289  GL_UnloadObject(_this->gl_config.dll_handle);
291 #endif
292 
293  /* Free OpenGL memory */
295  _this->gl_data = NULL;
296 }
297 
298 static SDL_bool
299 HasExtension(const char *extension, const char *extensions)
300 {
301  const char *start;
302  const char *where, *terminator;
303 
304  if (!extensions)
305  return SDL_FALSE;
306 
307  /* Extension names should not have spaces. */
308  where = SDL_strchr(extension, ' ');
309  if (where || *extension == '\0')
310  return SDL_FALSE;
311 
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,
314  * etc. */
315 
316  start = extensions;
317 
318  for (;;) {
319  where = SDL_strstr(start, extension);
320  if (!where)
321  break;
322 
323  terminator = where + SDL_strlen(extension);
324  if (where == start || *(where - 1) == ' ')
325  if (*terminator == ' ' || *terminator == '\0')
326  return SDL_TRUE;
327 
328  start = terminator;
329  }
330  return SDL_FALSE;
331 }
332 
333 static void
334 X11_GL_InitExtensions(_THIS)
335 {
336  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
337  const int screen = DefaultScreen(display);
338  XVisualInfo *vinfo = NULL;
339  Window w = 0;
340  GLXContext prev_ctx = 0;
341  GLXDrawable prev_drawable = 0;
342  GLXContext context = 0;
343  const char *(*glXQueryExtensionsStringFunc) (Display *, int);
344  const char *extensions;
345 
346  vinfo = X11_GL_GetVisual(_this, display, screen);
347  if (vinfo) {
348  GLXContext (*glXGetCurrentContextFunc) (void) =
349  (GLXContext(*)(void))
350  X11_GL_GetProcAddress(_this, "glXGetCurrentContext");
351 
352  GLXDrawable (*glXGetCurrentDrawableFunc) (void) =
353  (GLXDrawable(*)(void))
354  X11_GL_GetProcAddress(_this, "glXGetCurrentDrawable");
355 
356  if (glXGetCurrentContextFunc && glXGetCurrentDrawableFunc) {
357  XSetWindowAttributes xattr;
358  prev_ctx = glXGetCurrentContextFunc();
359  prev_drawable = glXGetCurrentDrawableFunc();
360 
361  xattr.background_pixel = 0;
362  xattr.border_pixel = 0;
363  xattr.colormap =
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);
369 
370  context = _this->gl_data->glXCreateContext(display, vinfo,
371  NULL, True);
372  if (context) {
373  _this->gl_data->glXMakeCurrent(display, w, context);
374  }
375  }
376 
377  X11_XFree(vinfo);
378  }
379 
380  glXQueryExtensionsStringFunc =
381  (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
382  "glXQueryExtensionsString");
383  if (glXQueryExtensionsStringFunc) {
384  extensions = glXQueryExtensionsStringFunc(display, screen);
385  } else {
386  extensions = NULL;
387  }
388 
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;
397  }
398  }
399 
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");
407  }
408 
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");
413  }
414 
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");
423  }
424 
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;
428  }
429 
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;
433  }
434 
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! */
439  if (context) {
441  &_this->gl_data->es_profile_max_supported_version.major,
442  &_this->gl_data->es_profile_max_supported_version.minor
443  );
444  }
445  }
446 
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;
450  }
451 
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;
455  }
456 
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;
460  }
461 
462  if (context) {
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);
467  }
468  }
469 
470  if (w) {
471  X11_XDestroyWindow(display, w);
472  }
474 }
475 
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
481  * and try again.
482  */
483 static int
484 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig, int **_pvistypeattr)
485 {
486  int i = 0;
487  const int MAX_ATTRIBUTES = 64;
488  int *pvistypeattr = NULL;
489 
490  /* assert buffer is large enough to hold all SDL attributes. */
491  SDL_assert(size >= MAX_ATTRIBUTES);
492 
493  /* Setup our GLX attributes according to the gl_config. */
494  if( for_FBConfig ) {
495  attribs[i++] = GLX_RENDER_TYPE;
496  attribs[i++] = GLX_RGBA_BIT;
497  } else {
498  attribs[i++] = GLX_RGBA;
499  }
500  attribs[i++] = GLX_RED_SIZE;
502  attribs[i++] = GLX_GREEN_SIZE;
504  attribs[i++] = GLX_BLUE_SIZE;
506 
507  if (_this->gl_config.alpha_size) {
508  attribs[i++] = GLX_ALPHA_SIZE;
510  }
511 
513  attribs[i++] = GLX_DOUBLEBUFFER;
514  if( for_FBConfig ) {
515  attribs[i++] = True;
516  }
517  }
518 
519  attribs[i++] = GLX_DEPTH_SIZE;
521 
523  attribs[i++] = GLX_STENCIL_SIZE;
525  }
526 
528  attribs[i++] = GLX_ACCUM_RED_SIZE;
530  }
531 
533  attribs[i++] = GLX_ACCUM_GREEN_SIZE;
535  }
536 
538  attribs[i++] = GLX_ACCUM_BLUE_SIZE;
540  }
541 
543  attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
545  }
546 
547  if (_this->gl_config.stereo) {
548  attribs[i++] = GLX_STEREO;
549  if( for_FBConfig ) {
550  attribs[i++] = True;
551  }
552  }
553 
555  attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
557  }
558 
560  attribs[i++] = GLX_SAMPLES_ARB;
562  }
563 
565  attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
566  attribs[i++] = True; /* always needed, for_FBConfig or not! */
567  }
568 
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 :
573  GLX_SLOW_VISUAL_EXT;
574  }
575 
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. */
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;
583  }
584 
585  attribs[i++] = None;
586 
587  SDL_assert(i <= MAX_ATTRIBUTES);
588 
589  if (_pvistypeattr) {
590  *_pvistypeattr = pvistypeattr;
591  }
592 
593  return i;
594 }
595 
596 XVisualInfo *
597 X11_GL_GetVisual(_THIS, Display * display, int screen)
598 {
599  /* 64 seems nice. */
600  int attribs[64];
601  XVisualInfo *vinfo;
602  int *pvistypeattr = NULL;
603 
604  if (!_this->gl_data) {
605  /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
606  return NULL;
607  }
608 
609  X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr);
610  vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
611 
612  if (!vinfo && (pvistypeattr != NULL)) {
613  *pvistypeattr = None;
614  vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
615  }
616 
617  if (!vinfo) {
618  SDL_SetError("Couldn't find matching GLX visual");
619  }
620  return vinfo;
621 }
622 
623 static int (*handler) (Display *, XErrorEvent *) = NULL;
624 static const char *errorHandlerOperation = NULL;
625 static int errorBase = 0;
626 static int errorCode = 0;
627 static int
628 X11_GL_ErrorHandler(Display * d, XErrorEvent * e)
629 {
630  char *x11_error = NULL;
631  char x11_error_locale[256];
632 
633  errorCode = e->error_code;
634  if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
635  {
636  x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
637  }
638 
639  if (x11_error)
640  {
641  SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error);
642  SDL_free(x11_error);
643  }
644  else
645  {
646  SDL_SetError("Could not %s: %i (Base %i)", errorHandlerOperation, errorCode, errorBase);
647  }
648 
649  return (0);
650 }
651 
652 SDL_bool
653 X11_GL_UseEGL(_THIS)
654 {
657  {
658  /* use of EGL has been requested, even for desktop GL */
659  return SDL_TRUE;
660  }
661 
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));
668 }
669 
671 X11_GL_CreateContext(_THIS, SDL_Window * window)
672 {
673  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
674  Display *display = data->videodata->display;
675  int screen =
677  XWindowAttributes xattr;
678  XVisualInfo v, *vinfo;
679  int n;
680  GLXContext context = NULL, share_context;
681 
683  share_context = (GLXContext)SDL_GL_GetCurrentContext();
684  } else {
685  share_context = NULL;
686  }
687 
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;
692  errorCode = Success;
693  handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
694  X11_XGetWindowAttributes(display, data->xwindow, &xattr);
695  v.screen = screen;
696  v.visualid = X11_XVisualIDFromVisual(xattr.visual);
697  vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
698  if (vinfo) {
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 */
703  context =
704  _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
705  } else {
706  /* max 14 attributes plus terminator */
707  int attribs[15] = {
708  GLX_CONTEXT_MAJOR_VERSION_ARB,
710  GLX_CONTEXT_MINOR_VERSION_ARB,
712  0
713  };
714  int iattr = 4;
715 
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;
720  }
721 
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;
726  }
727 
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;
731  attribs[iattr++] =
733  GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :
734  GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
735  }
736 
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;
740  attribs[iattr++] =
742  GLX_LOSE_CONTEXT_ON_RESET_ARB :
743  GLX_NO_RESET_NOTIFICATION_ARB;
744  }
745 
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;
750  }
751 
752  attribs[iattr++] = 0;
753 
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");
757  } else {
758  int glxAttribs[64];
759 
760  /* Create a GL 3.x context */
761  GLXFBConfig *framebuffer_config = NULL;
762  int fbcount = 0;
763  int *pvistypeattr = NULL;
764 
765  X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE,&pvistypeattr);
766 
767  if (_this->gl_data->glXChooseFBConfig) {
768  framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
769  DefaultScreen(display), glxAttribs,
770  &fbcount);
771 
772  if (!framebuffer_config && (pvistypeattr != NULL)) {
773  *pvistypeattr = None;
774  framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
775  DefaultScreen(display), glxAttribs,
776  &fbcount);
777  }
778 
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);
784  }
785  }
786  }
787  }
788  X11_XFree(vinfo);
789  }
790  X11_XSync(display, False);
791  X11_XSetErrorHandler(handler);
792 
793  if (!context) {
794  if (errorCode == Success) {
795  SDL_SetError("Could not create GL context");
796  }
797  return NULL;
798  }
799 
800  if (X11_GL_MakeCurrent(_this, window, context) < 0) {
801  X11_GL_DeleteContext(_this, context);
802  return NULL;
803  }
804 
805  return context;
806 }
807 
808 int
809 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
810 {
811  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
812  Window drawable =
813  (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
814  GLXContext glx_context = (GLXContext) context;
815  int rc;
816 
817  if (!_this->gl_data) {
818  return SDL_SetError("OpenGL not initialized");
819  }
820 
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;
825  errorCode = Success;
826  handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
827  rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context);
828  X11_XSetErrorHandler(handler);
829 
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");
834  }
835 
836  return 0;
837 }
838 
839 /*
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.
845 */
846 
847 static int swapinterval = 0;
848 int
849 X11_GL_SetSwapInterval(_THIS, int interval)
850 {
851  int status = -1;
852 
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;
859 
860  Window drawable = windowdata->xwindow;
861 
862  /*
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).
865  *
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.
869  */
870  int currentInterval = X11_GL_GetSwapInterval(_this);
871  _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
872  _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
873 
874  status = 0;
875  swapinterval = interval;
876  } else if (_this->gl_data->glXSwapIntervalMESA) {
877  status = _this->gl_data->glXSwapIntervalMESA(interval);
878  if (status != 0) {
879  SDL_SetError("glXSwapIntervalMESA failed");
880  } else {
881  swapinterval = interval;
882  }
883  } else if (_this->gl_data->glXSwapIntervalSGI) {
884  status = _this->gl_data->glXSwapIntervalSGI(interval);
885  if (status != 0) {
886  SDL_SetError("glXSwapIntervalSGI failed");
887  } else {
888  swapinterval = interval;
889  }
890  } else {
891  SDL_Unsupported();
892  }
893  return status;
894 }
895 
896 int
897 X11_GL_GetSwapInterval(_THIS)
898 {
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;
906 
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);
911  }
912 
913  _this->gl_data->glXQueryDrawable(display, drawable,
914  GLX_SWAP_INTERVAL_EXT, &interval);
915 
916  if ((allow_late_swap_tearing) && (interval > 0)) {
917  return -((int) interval);
918  }
919 
920  return (int) interval;
921  } else if (_this->gl_data->glXGetSwapIntervalMESA) {
922  return _this->gl_data->glXGetSwapIntervalMESA();
923  } else {
924  return swapinterval;
925  }
926 }
927 
928 int
929 X11_GL_SwapWindow(_THIS, SDL_Window * window)
930 {
931  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
932  Display *display = data->videodata->display;
933 
934  _this->gl_data->glXSwapBuffers(display, data->xwindow);
935  return 0;
936 }
937 
938 void
939 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
940 {
941  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
942  GLXContext glx_context = (GLXContext) context;
943 
944  if (!_this->gl_data) {
945  return;
946  }
947  _this->gl_data->glXDestroyContext(display, glx_context);
948  X11_XSync(display, False);
949 }
950 
951 #endif /* SDL_VIDEO_OPENGL_GLX */
952 
953 #endif /* SDL_VIDEO_DRIVER_X11 */
954 
955 /* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define SDL_assert(condition)
Definition: SDL_assert.h:171
#define SDL_SetError
#define SDL_strchr
#define SDL_GL_GetCurrentWindow
#define SDL_getenv
#define SDL_strlen
#define SDL_strlcpy
#define SDL_free
#define SDL_iconv_string
#define SDL_strstr
#define SDL_GetHintBoolean
#define SDL_calloc
#define SDL_GL_GetCurrentContext
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 Uint32 * e
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_Unsupported()
Definition: SDL_error.h:89
#define SDL_HINT_VIDEO_X11_FORCE_EGL
A variable controlling whether X11 should use GLX or EGL by default.
Definition: SDL_hints.h:256
#define SDL_HINT_OPENGL_ES_DRIVER
A variable controlling what driver to use for OpenGL ES contexts.
Definition: SDL_hints.h:1239
unsigned char GLubyte
Definition: SDL_opengl.h:183
const GLdouble * v
Definition: SDL_opengl.h:2064
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLuint start
Definition: SDL_opengl.h:1571
GLsizeiptr size
GLsizei const GLchar *const * path
GLdouble n
const GLint * attribs
GLubyte GLubyte GLubyte GLubyte w
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:121
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1130
void SDL_GL_DeduceMaxSupportedESProfile(int *major, int *minor)
Definition: SDL_video.c:3162
static SDL_VideoDevice * _this
Definition: SDL_video.c:126
void * SDL_GLContext
An opaque handle to an OpenGL context.
Definition: SDL_video.h:195
@ SDL_GL_CONTEXT_PROFILE_ES
Definition: SDL_video.h:235
void X11_PumpEvents(_THIS)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display dpy)
Definition: SDL_x11sym.h:44
SDL_bool X11_UseDirectColorVisuals(void)
#define NULL
Definition: begin_code.h:163
EGLConfig config
Definition: eglext.h:433
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
EGLenum const EGLAttribKHR * attrib_list
Definition: eglext.h:63
uint32_t swapinterval
Definition: SDL_pspgl_c.h:36
EGLDisplay display
Definition: SDL_pspgl_c.h:33
int framebuffer_srgb_capable
Definition: SDL_sysvideo.h:360
char driver_path[256]
Definition: SDL_sysvideo.h:364
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:265
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:260
struct SDL_VideoDevice::@440 gl_config
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:259
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:262
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:258
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:257
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:263
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:256
int(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:264
struct SDL_GLDriverData * gl_data
Definition: SDL_sysvideo.h:397
int share_with_current_context
Definition: SDL_sysvideo.h:357
The type used to identify a window.
Definition: SDL_sysvideo.h:75
SDL_Renderer * screen
static screen_context_t context
Definition: video.c:25
typedef int(__stdcall *FARPROC)()