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_assert.h"
27 #include "SDL_hints.h"
28 
29 /* GLX implementation of SDL OpenGL support */
30 
31 #if SDL_VIDEO_OPENGL_GLX
32 #include "SDL_loadso.h"
33 #include "SDL_x11opengles.h"
34 
35 #if defined(__IRIX__)
36 /* IRIX doesn't have a GL library versioning system */
37 #define DEFAULT_OPENGL "libGL.so"
38 #elif defined(__MACOSX__)
39 #define DEFAULT_OPENGL "/opt/X11/lib/libGL.1.dylib"
40 #elif defined(__QNXNTO__)
41 #define DEFAULT_OPENGL "libGL.so.3"
42 #else
43 #define DEFAULT_OPENGL "libGL.so.1"
44 #endif
45 
46 #ifndef GLX_NONE_EXT
47 #define GLX_NONE_EXT 0x8000
48 #endif
49 
50 #ifndef GLX_ARB_multisample
51 #define GLX_ARB_multisample
52 #define GLX_SAMPLE_BUFFERS_ARB 100000
53 #define GLX_SAMPLES_ARB 100001
54 #endif
55 
56 #ifndef GLX_EXT_visual_rating
57 #define GLX_EXT_visual_rating
58 #define GLX_VISUAL_CAVEAT_EXT 0x20
59 #define GLX_NONE_EXT 0x8000
60 #define GLX_SLOW_VISUAL_EXT 0x8001
61 #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
62 #endif
63 
64 #ifndef GLX_EXT_visual_info
65 #define GLX_EXT_visual_info
66 #define GLX_X_VISUAL_TYPE_EXT 0x22
67 #define GLX_DIRECT_COLOR_EXT 0x8003
68 #endif
69 
70 #ifndef GLX_ARB_create_context
71 #define GLX_ARB_create_context
72 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
73 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
74 #define GLX_CONTEXT_FLAGS_ARB 0x2094
75 #define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001
76 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
77 
78 /* Typedef for the GL 3.0 context creation function */
79 typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy,
80  GLXFBConfig config,
81  GLXContext
82  share_context,
83  Bool direct,
84  const int
85  *attrib_list);
86 #endif
87 
88 #ifndef GLX_ARB_create_context_profile
89 #define GLX_ARB_create_context_profile
90 #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
91 #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
92 #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
93 #endif
94 
95 #ifndef GLX_ARB_create_context_robustness
96 #define GLX_ARB_create_context_robustness
97 #define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
98 #define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
99 #define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
100 #define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
101 #endif
102 
103 #ifndef GLX_EXT_create_context_es2_profile
104 #define GLX_EXT_create_context_es2_profile
105 #ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
106 #define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000002
107 #endif
108 #endif
109 
110 #ifndef GLX_ARB_framebuffer_sRGB
111 #define GLX_ARB_framebuffer_sRGB
112 #ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB
113 #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
114 #endif
115 #endif
116 
117 #ifndef GLX_ARB_create_context_no_error
118 #define GLX_ARB_create_context_no_error
119 #ifndef GLX_CONTEXT_OPENGL_NO_ERROR_ARB
120 #define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3
121 #endif
122 #endif
123 
124 #ifndef GLX_EXT_swap_control
125 #define GLX_SWAP_INTERVAL_EXT 0x20F1
126 #define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
127 #endif
128 
129 #ifndef GLX_EXT_swap_control_tear
130 #define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
131 #endif
132 
133 #ifndef GLX_ARB_context_flush_control
134 #define GLX_ARB_context_flush_control
135 #define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
136 #define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000
137 #define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
138 #endif
139 
140 #define OPENGL_REQUIRES_DLOPEN
141 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
142 #include <dlfcn.h>
143 #define GL_LoadObject(X) dlopen(X, (RTLD_NOW|RTLD_GLOBAL))
144 #define GL_LoadFunction dlsym
145 #define GL_UnloadObject dlclose
146 #else
147 #define GL_LoadObject SDL_LoadObject
148 #define GL_LoadFunction SDL_LoadFunction
149 #define GL_UnloadObject SDL_UnloadObject
150 #endif
151 
152 static void X11_GL_InitExtensions(_THIS);
153 
154 int
155 X11_GL_LoadLibrary(_THIS, const char *path)
156 {
157  Display *display;
158  void *handle;
159 
160  if (_this->gl_data) {
161  return SDL_SetError("OpenGL context already created");
162  }
163 
164  /* Load the OpenGL library */
165  if (path == NULL) {
166  path = SDL_getenv("SDL_OPENGL_LIBRARY");
167  }
168  if (path == NULL) {
169  path = DEFAULT_OPENGL;
170  }
171  _this->gl_config.dll_handle = GL_LoadObject(path);
172  if (!_this->gl_config.dll_handle) {
173 #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN)
174  SDL_SetError("Failed loading %s: %s", path, dlerror());
175 #endif
176  return -1;
177  }
180 
181  /* Allocate OpenGL memory */
182  _this->gl_data =
183  (struct SDL_GLDriverData *) SDL_calloc(1,
184  sizeof(struct
186  if (!_this->gl_data) {
187  return SDL_OutOfMemory();
188  }
189 
190  /* Load function pointers */
192  _this->gl_data->glXQueryExtension =
193  (Bool (*)(Display *, int *, int *))
194  GL_LoadFunction(handle, "glXQueryExtension");
195  _this->gl_data->glXGetProcAddress =
196  (void *(*)(const GLubyte *))
197  GL_LoadFunction(handle, "glXGetProcAddressARB");
198  _this->gl_data->glXChooseVisual =
199  (XVisualInfo * (*)(Display *, int, int *))
200  X11_GL_GetProcAddress(_this, "glXChooseVisual");
201  _this->gl_data->glXCreateContext =
202  (GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
203  X11_GL_GetProcAddress(_this, "glXCreateContext");
204  _this->gl_data->glXDestroyContext =
205  (void (*)(Display *, GLXContext))
206  X11_GL_GetProcAddress(_this, "glXDestroyContext");
207  _this->gl_data->glXMakeCurrent =
208  (int (*)(Display *, GLXDrawable, GLXContext))
209  X11_GL_GetProcAddress(_this, "glXMakeCurrent");
210  _this->gl_data->glXSwapBuffers =
211  (void (*)(Display *, GLXDrawable))
212  X11_GL_GetProcAddress(_this, "glXSwapBuffers");
213  _this->gl_data->glXQueryDrawable =
214  (void (*)(Display*,GLXDrawable,int,unsigned int*))
215  X11_GL_GetProcAddress(_this, "glXQueryDrawable");
216 
217  if (!_this->gl_data->glXQueryExtension ||
218  !_this->gl_data->glXChooseVisual ||
219  !_this->gl_data->glXCreateContext ||
220  !_this->gl_data->glXDestroyContext ||
221  !_this->gl_data->glXMakeCurrent ||
222  !_this->gl_data->glXSwapBuffers) {
223  return SDL_SetError("Could not retrieve OpenGL functions");
224  }
225 
226  display = ((SDL_VideoData *) _this->driverdata)->display;
227  if (!_this->gl_data->glXQueryExtension(display, &_this->gl_data->errorBase, &_this->gl_data->eventBase)) {
228  return SDL_SetError("GLX is not supported");
229  }
230 
231  /* Initialize extensions */
232  /* See lengthy comment about the inc/dec in
233  ../windows/SDL_windowsopengl.c. */
235  X11_GL_InitExtensions(_this);
237 
238  /* If we need a GL ES context and there's no
239  * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions
240  */
243  X11_GL_UseEGL(_this) ) {
244 #if SDL_VIDEO_OPENGL_EGL
245  X11_GL_UnloadLibrary(_this);
246  /* Better avoid conflicts! */
247  if (_this->gl_config.dll_handle != NULL ) {
248  GL_UnloadObject(_this->gl_config.dll_handle);
250  }
251  _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
252  _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
253  _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
254  _this->GL_CreateContext = X11_GLES_CreateContext;
255  _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
256  _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
257  _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
258  _this->GL_SwapWindow = X11_GLES_SwapWindow;
259  _this->GL_DeleteContext = X11_GLES_DeleteContext;
260  return X11_GLES_LoadLibrary(_this, NULL);
261 #else
262  return SDL_SetError("SDL not configured with EGL support");
263 #endif
264  }
265 
266  return 0;
267 }
268 
269 void *
270 X11_GL_GetProcAddress(_THIS, const char *proc)
271 {
272  if (_this->gl_data->glXGetProcAddress) {
273  return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
274  }
275  return GL_LoadFunction(_this->gl_config.dll_handle, proc);
276 }
277 
278 void
279 X11_GL_UnloadLibrary(_THIS)
280 {
281  /* Don't actually unload the library, since it may have registered
282  * X11 shutdown hooks, per the notes at:
283  * http://dri.sourceforge.net/doc/DRIuserguide.html
284  */
285 #if 0
286  GL_UnloadObject(_this->gl_config.dll_handle);
288 #endif
289 
290  /* Free OpenGL memory */
292  _this->gl_data = NULL;
293 }
294 
295 static SDL_bool
296 HasExtension(const char *extension, const char *extensions)
297 {
298  const char *start;
299  const char *where, *terminator;
300 
301  if (!extensions)
302  return SDL_FALSE;
303 
304  /* Extension names should not have spaces. */
305  where = SDL_strchr(extension, ' ');
306  if (where || *extension == '\0')
307  return SDL_FALSE;
308 
309  /* It takes a bit of care to be fool-proof about parsing the
310  * OpenGL extensions string. Don't be fooled by sub-strings,
311  * etc. */
312 
313  start = extensions;
314 
315  for (;;) {
316  where = SDL_strstr(start, extension);
317  if (!where)
318  break;
319 
320  terminator = where + SDL_strlen(extension);
321  if (where == start || *(where - 1) == ' ')
322  if (*terminator == ' ' || *terminator == '\0')
323  return SDL_TRUE;
324 
325  start = terminator;
326  }
327  return SDL_FALSE;
328 }
329 
330 static void
331 X11_GL_InitExtensions(_THIS)
332 {
333  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
334  const int screen = DefaultScreen(display);
335  XVisualInfo *vinfo = NULL;
336  Window w = 0;
337  GLXContext prev_ctx = 0;
338  GLXDrawable prev_drawable = 0;
339  GLXContext context = 0;
340  const char *(*glXQueryExtensionsStringFunc) (Display *, int);
341  const char *extensions;
342 
343  vinfo = X11_GL_GetVisual(_this, display, screen);
344  if (vinfo) {
345  GLXContext (*glXGetCurrentContextFunc) (void) =
346  (GLXContext(*)(void))
347  X11_GL_GetProcAddress(_this, "glXGetCurrentContext");
348 
349  GLXDrawable (*glXGetCurrentDrawableFunc) (void) =
350  (GLXDrawable(*)(void))
351  X11_GL_GetProcAddress(_this, "glXGetCurrentDrawable");
352 
353  if (glXGetCurrentContextFunc && glXGetCurrentDrawableFunc) {
354  XSetWindowAttributes xattr;
355  prev_ctx = glXGetCurrentContextFunc();
356  prev_drawable = glXGetCurrentDrawableFunc();
357 
358  xattr.background_pixel = 0;
359  xattr.border_pixel = 0;
360  xattr.colormap =
361  X11_XCreateColormap(display, RootWindow(display, screen),
362  vinfo->visual, AllocNone);
363  w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0,
364  32, 32, 0, vinfo->depth, InputOutput, vinfo->visual,
365  (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
366 
367  context = _this->gl_data->glXCreateContext(display, vinfo,
368  NULL, True);
369  if (context) {
370  _this->gl_data->glXMakeCurrent(display, w, context);
371  }
372  }
373 
374  X11_XFree(vinfo);
375  }
376 
377  glXQueryExtensionsStringFunc =
378  (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
379  "glXQueryExtensionsString");
380  if (glXQueryExtensionsStringFunc) {
381  extensions = glXQueryExtensionsStringFunc(display, screen);
382  } else {
383  extensions = NULL;
384  }
385 
386  /* Check for GLX_EXT_swap_control(_tear) */
387  _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
388  if (HasExtension("GLX_EXT_swap_control", extensions)) {
389  _this->gl_data->glXSwapIntervalEXT =
390  (void (*)(Display*,GLXDrawable,int))
391  X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
392  if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
393  _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
394  }
395  }
396 
397  /* Check for GLX_MESA_swap_control */
398  if (HasExtension("GLX_MESA_swap_control", extensions)) {
399  _this->gl_data->glXSwapIntervalMESA =
400  (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
401  _this->gl_data->glXGetSwapIntervalMESA =
402  (int(*)(void)) X11_GL_GetProcAddress(_this,
403  "glXGetSwapIntervalMESA");
404  }
405 
406  /* Check for GLX_SGI_swap_control */
407  if (HasExtension("GLX_SGI_swap_control", extensions)) {
408  _this->gl_data->glXSwapIntervalSGI =
409  (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
410  }
411 
412  /* Check for GLX_ARB_create_context */
413  if (HasExtension("GLX_ARB_create_context", extensions)) {
414  _this->gl_data->glXCreateContextAttribsARB =
415  (GLXContext (*)(Display*,GLXFBConfig,GLXContext,Bool,const int *))
416  X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB");
417  _this->gl_data->glXChooseFBConfig =
418  (GLXFBConfig *(*)(Display *, int, const int *, int *))
419  X11_GL_GetProcAddress(_this, "glXChooseFBConfig");
420  }
421 
422  /* Check for GLX_EXT_visual_rating */
423  if (HasExtension("GLX_EXT_visual_rating", extensions)) {
424  _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
425  }
426 
427  /* Check for GLX_EXT_visual_info */
428  if (HasExtension("GLX_EXT_visual_info", extensions)) {
429  _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
430  }
431 
432  /* Check for GLX_EXT_create_context_es2_profile */
433  if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) {
434  /* this wants to call glGetString(), so it needs a context. */
435  /* !!! FIXME: it would be nice not to make a context here though! */
436  if (context) {
438  &_this->gl_data->es_profile_max_supported_version.major,
439  &_this->gl_data->es_profile_max_supported_version.minor
440  );
441  }
442  }
443 
444  /* Check for GLX_ARB_context_flush_control */
445  if (HasExtension("GLX_ARB_context_flush_control", extensions)) {
446  _this->gl_data->HAS_GLX_ARB_context_flush_control = SDL_TRUE;
447  }
448 
449  /* Check for GLX_ARB_create_context_robustness */
450  if (HasExtension("GLX_ARB_create_context_robustness", extensions)) {
451  _this->gl_data->HAS_GLX_ARB_create_context_robustness = SDL_TRUE;
452  }
453 
454  /* Check for GLX_ARB_create_context_no_error */
455  if (HasExtension("GLX_ARB_create_context_no_error", extensions)) {
456  _this->gl_data->HAS_GLX_ARB_create_context_no_error = SDL_TRUE;
457  }
458 
459  if (context) {
460  _this->gl_data->glXMakeCurrent(display, None, NULL);
461  _this->gl_data->glXDestroyContext(display, context);
462  if (prev_ctx && prev_drawable) {
463  _this->gl_data->glXMakeCurrent(display, prev_drawable, prev_ctx);
464  }
465  }
466 
467  if (w) {
468  X11_XDestroyWindow(display, w);
469  }
471 }
472 
473 /* glXChooseVisual and glXChooseFBConfig have some small differences in
474  * the attribute encoding, it can be chosen with the for_FBConfig parameter.
475  * Some targets fail if you use GLX_X_VISUAL_TYPE_EXT/GLX_DIRECT_COLOR_EXT,
476  * so it gets specified last if used and is pointed to by *_pvistypeattr.
477  * In case of failure, if that pointer is not NULL, set that pointer to None
478  * and try again.
479  */
480 static int
481 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig, int **_pvistypeattr)
482 {
483  int i = 0;
484  const int MAX_ATTRIBUTES = 64;
485  int *pvistypeattr = NULL;
486 
487  /* assert buffer is large enough to hold all SDL attributes. */
488  SDL_assert(size >= MAX_ATTRIBUTES);
489 
490  /* Setup our GLX attributes according to the gl_config. */
491  if( for_FBConfig ) {
492  attribs[i++] = GLX_RENDER_TYPE;
493  attribs[i++] = GLX_RGBA_BIT;
494  } else {
495  attribs[i++] = GLX_RGBA;
496  }
497  attribs[i++] = GLX_RED_SIZE;
499  attribs[i++] = GLX_GREEN_SIZE;
501  attribs[i++] = GLX_BLUE_SIZE;
503 
504  if (_this->gl_config.alpha_size) {
505  attribs[i++] = GLX_ALPHA_SIZE;
507  }
508 
510  attribs[i++] = GLX_DOUBLEBUFFER;
511  if( for_FBConfig ) {
512  attribs[i++] = True;
513  }
514  }
515 
516  attribs[i++] = GLX_DEPTH_SIZE;
518 
520  attribs[i++] = GLX_STENCIL_SIZE;
522  }
523 
525  attribs[i++] = GLX_ACCUM_RED_SIZE;
527  }
528 
530  attribs[i++] = GLX_ACCUM_GREEN_SIZE;
532  }
533 
535  attribs[i++] = GLX_ACCUM_BLUE_SIZE;
537  }
538 
540  attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
542  }
543 
544  if (_this->gl_config.stereo) {
545  attribs[i++] = GLX_STEREO;
546  if( for_FBConfig ) {
547  attribs[i++] = True;
548  }
549  }
550 
552  attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
554  }
555 
557  attribs[i++] = GLX_SAMPLES_ARB;
559  }
560 
562  attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
563  attribs[i++] = True; /* always needed, for_FBConfig or not! */
564  }
565 
566  if (_this->gl_config.accelerated >= 0 &&
567  _this->gl_data->HAS_GLX_EXT_visual_rating) {
568  attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
569  attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
570  GLX_SLOW_VISUAL_EXT;
571  }
572 
573  /* If we're supposed to use DirectColor visuals, and we've got the
574  EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
576  _this->gl_data->HAS_GLX_EXT_visual_info) {
577  pvistypeattr = &attribs[i];
578  attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
579  attribs[i++] = GLX_DIRECT_COLOR_EXT;
580  }
581 
582  attribs[i++] = None;
583 
584  SDL_assert(i <= MAX_ATTRIBUTES);
585 
586  if (_pvistypeattr) {
587  *_pvistypeattr = pvistypeattr;
588  }
589 
590  return i;
591 }
592 
593 XVisualInfo *
594 X11_GL_GetVisual(_THIS, Display * display, int screen)
595 {
596  /* 64 seems nice. */
597  int attribs[64];
598  XVisualInfo *vinfo;
599  int *pvistypeattr = NULL;
600 
601  if (!_this->gl_data) {
602  /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
603  return NULL;
604  }
605 
606  X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr);
607  vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
608 
609  if (!vinfo && (pvistypeattr != NULL)) {
610  *pvistypeattr = None;
611  vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
612  }
613 
614  if (!vinfo) {
615  SDL_SetError("Couldn't find matching GLX visual");
616  }
617  return vinfo;
618 }
619 
620 static int (*handler) (Display *, XErrorEvent *) = NULL;
621 static const char *errorHandlerOperation = NULL;
622 static int errorBase = 0;
623 static int errorCode = 0;
624 static int
625 X11_GL_ErrorHandler(Display * d, XErrorEvent * e)
626 {
627  char *x11_error = NULL;
628  char x11_error_locale[256];
629 
630  errorCode = e->error_code;
631  if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
632  {
633  x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
634  }
635 
636  if (x11_error)
637  {
638  SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error);
639  SDL_free(x11_error);
640  }
641  else
642  {
643  SDL_SetError("Could not %s: %i (Base %i)", errorHandlerOperation, errorCode, errorBase);
644  }
645 
646  return (0);
647 }
648 
649 SDL_bool
650 X11_GL_UseEGL(_THIS)
651 {
654  {
655  /* use of EGL has been requested, even for desktop GL */
656  return SDL_TRUE;
657  }
658 
661  || _this->gl_config.major_version == 1 /* No GLX extension for OpenGL ES 1.x profiles. */
662  || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major
663  || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major
664  && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor));
665 }
666 
668 X11_GL_CreateContext(_THIS, SDL_Window * window)
669 {
670  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
671  Display *display = data->videodata->display;
672  int screen =
674  XWindowAttributes xattr;
675  XVisualInfo v, *vinfo;
676  int n;
677  GLXContext context = NULL, share_context;
678 
680  share_context = (GLXContext)SDL_GL_GetCurrentContext();
681  } else {
682  share_context = NULL;
683  }
684 
685  /* We do this to create a clean separation between X and GLX errors. */
686  X11_XSync(display, False);
687  errorHandlerOperation = "create GL context";
688  errorBase = _this->gl_data->errorBase;
689  errorCode = Success;
690  handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
691  X11_XGetWindowAttributes(display, data->xwindow, &xattr);
692  v.screen = screen;
693  v.visualid = X11_XVisualIDFromVisual(xattr.visual);
694  vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
695  if (vinfo) {
696  if (_this->gl_config.major_version < 3 &&
697  _this->gl_config.profile_mask == 0 &&
698  _this->gl_config.flags == 0) {
699  /* Create legacy context */
700  context =
701  _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
702  } else {
703  /* max 14 attributes plus terminator */
704  int attribs[15] = {
705  GLX_CONTEXT_MAJOR_VERSION_ARB,
707  GLX_CONTEXT_MINOR_VERSION_ARB,
709  0
710  };
711  int iattr = 4;
712 
713  /* SDL profile bits match GLX profile bits */
714  if( _this->gl_config.profile_mask != 0 ) {
715  attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
716  attribs[iattr++] = _this->gl_config.profile_mask;
717  }
718 
719  /* SDL flags match GLX flags */
720  if( _this->gl_config.flags != 0 ) {
721  attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
722  attribs[iattr++] = _this->gl_config.flags;
723  }
724 
725  /* only set if glx extension is available */
726  if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) {
727  attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB;
728  attribs[iattr++] =
730  GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :
731  GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
732  }
733 
734  /* only set if glx extension is available */
735  if( _this->gl_data->HAS_GLX_ARB_create_context_robustness ) {
736  attribs[iattr++] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
737  attribs[iattr++] =
739  GLX_LOSE_CONTEXT_ON_RESET_ARB :
740  GLX_NO_RESET_NOTIFICATION_ARB;
741  }
742 
743  /* only set if glx extension is available */
744  if( _this->gl_data->HAS_GLX_ARB_create_context_no_error ) {
745  attribs[iattr++] = GLX_CONTEXT_OPENGL_NO_ERROR_ARB;
746  attribs[iattr++] = _this->gl_config.no_error;
747  }
748 
749  attribs[iattr++] = 0;
750 
751  /* Get a pointer to the context creation function for GL 3.0 */
752  if (!_this->gl_data->glXCreateContextAttribsARB) {
753  SDL_SetError("OpenGL 3.0 and later are not supported by this system");
754  } else {
755  int glxAttribs[64];
756 
757  /* Create a GL 3.x context */
758  GLXFBConfig *framebuffer_config = NULL;
759  int fbcount = 0;
760  int *pvistypeattr = NULL;
761 
762  X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE,&pvistypeattr);
763 
764  if (_this->gl_data->glXChooseFBConfig) {
765  framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
766  DefaultScreen(display), glxAttribs,
767  &fbcount);
768 
769  if (!framebuffer_config && (pvistypeattr != NULL)) {
770  *pvistypeattr = None;
771  framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
772  DefaultScreen(display), glxAttribs,
773  &fbcount);
774  }
775 
776  if (framebuffer_config) {
777  context = _this->gl_data->glXCreateContextAttribsARB(display,
778  framebuffer_config[0],
779  share_context, True, attribs);
780  X11_XFree(framebuffer_config);
781  }
782  }
783  }
784  }
785  X11_XFree(vinfo);
786  }
787  X11_XSync(display, False);
788  X11_XSetErrorHandler(handler);
789 
790  if (!context) {
791  if (errorCode == Success) {
792  SDL_SetError("Could not create GL context");
793  }
794  return NULL;
795  }
796 
797  if (X11_GL_MakeCurrent(_this, window, context) < 0) {
798  X11_GL_DeleteContext(_this, context);
799  return NULL;
800  }
801 
802  return context;
803 }
804 
805 int
806 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
807 {
808  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
809  Window drawable =
810  (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
811  GLXContext glx_context = (GLXContext) context;
812  int rc;
813 
814  if (!_this->gl_data) {
815  return SDL_SetError("OpenGL not initialized");
816  }
817 
818  /* We do this to create a clean separation between X and GLX errors. */
819  X11_XSync(display, False);
820  errorHandlerOperation = "make GL context current";
821  errorBase = _this->gl_data->errorBase;
822  errorCode = Success;
823  handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
824  rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context);
825  X11_XSetErrorHandler(handler);
826 
827  if (errorCode != Success) { /* uhoh, an X error was thrown! */
828  return -1; /* the error handler called SDL_SetError() already. */
829  } else if (!rc) { /* glXMakeCurrent() failed without throwing an X error */
830  return SDL_SetError("Unable to make GL context current");
831  }
832 
833  return 0;
834 }
835 
836 /*
837  0 is a valid argument to glXSwapInterval(MESA|EXT) and setting it to 0
838  will undo the effect of a previous call with a value that is greater
839  than zero (or at least that is what the docs say). OTOH, 0 is an invalid
840  argument to glXSwapIntervalSGI and it returns an error if you call it
841  with 0 as an argument.
842 */
843 
844 static int swapinterval = 0;
845 int
846 X11_GL_SetSwapInterval(_THIS, int interval)
847 {
848  int status = -1;
849 
850  if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
851  SDL_SetError("Negative swap interval unsupported in this GL");
852  } else if (_this->gl_data->glXSwapIntervalEXT) {
853  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
854  const SDL_WindowData *windowdata = (SDL_WindowData *)
855  SDL_GL_GetCurrentWindow()->driverdata;
856 
857  Window drawable = windowdata->xwindow;
858 
859  /*
860  * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
861  * and will be fixed in a future release (probably 319.xx).
862  *
863  * There's a bug where glXSetSwapIntervalEXT ignores updates because
864  * it has the wrong value cached. To work around it, we just run a no-op
865  * update to the current value.
866  */
867  int currentInterval = X11_GL_GetSwapInterval(_this);
868  _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
869  _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
870 
871  status = 0;
872  swapinterval = interval;
873  } else if (_this->gl_data->glXSwapIntervalMESA) {
874  status = _this->gl_data->glXSwapIntervalMESA(interval);
875  if (status != 0) {
876  SDL_SetError("glXSwapIntervalMESA failed");
877  } else {
878  swapinterval = interval;
879  }
880  } else if (_this->gl_data->glXSwapIntervalSGI) {
881  status = _this->gl_data->glXSwapIntervalSGI(interval);
882  if (status != 0) {
883  SDL_SetError("glXSwapIntervalSGI failed");
884  } else {
885  swapinterval = interval;
886  }
887  } else {
888  SDL_Unsupported();
889  }
890  return status;
891 }
892 
893 int
894 X11_GL_GetSwapInterval(_THIS)
895 {
896  if (_this->gl_data->glXSwapIntervalEXT) {
897  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
898  const SDL_WindowData *windowdata = (SDL_WindowData *)
899  SDL_GL_GetCurrentWindow()->driverdata;
900  Window drawable = windowdata->xwindow;
901  unsigned int allow_late_swap_tearing = 0;
902  unsigned int interval = 0;
903 
904  if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
905  _this->gl_data->glXQueryDrawable(display, drawable,
906  GLX_LATE_SWAPS_TEAR_EXT,
907  &allow_late_swap_tearing);
908  }
909 
910  _this->gl_data->glXQueryDrawable(display, drawable,
911  GLX_SWAP_INTERVAL_EXT, &interval);
912 
913  if ((allow_late_swap_tearing) && (interval > 0)) {
914  return -((int) interval);
915  }
916 
917  return (int) interval;
918  } else if (_this->gl_data->glXGetSwapIntervalMESA) {
919  return _this->gl_data->glXGetSwapIntervalMESA();
920  } else {
921  return swapinterval;
922  }
923 }
924 
925 int
926 X11_GL_SwapWindow(_THIS, SDL_Window * window)
927 {
928  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
929  Display *display = data->videodata->display;
930 
931  _this->gl_data->glXSwapBuffers(display, data->xwindow);
932  return 0;
933 }
934 
935 void
936 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
937 {
938  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
939  GLXContext glx_context = (GLXContext) context;
940 
941  if (!_this->gl_data) {
942  return;
943  }
944  _this->gl_data->glXDestroyContext(display, glx_context);
945  X11_XSync(display, False);
946 }
947 
948 #endif /* SDL_VIDEO_OPENGL_GLX */
949 
950 #endif /* SDL_VIDEO_DRIVER_X11 */
951 
952 /* vi: set ts=4 sw=4 expandtab: */
X11_UseDirectColorVisuals
SDL_bool X11_UseDirectColorVisuals(void)
screen
SDL_Renderer * screen
Definition: testgamecontroller.c:64
SDL_strlcpy
#define SDL_strlcpy
Definition: SDL_dynapi_overrides.h:394
SDL_VideoDevice::driverdata
void * driverdata
Definition: SDL_sysvideo.h:389
SDL_x11video.h
NULL
#define NULL
Definition: begin_code.h:167
handle
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
attribs
const GLint * attribs
Definition: SDL_opengl_glext.h:9691
SDL_VideoDevice::multisamplesamples
int multisamplesamples
Definition: SDL_sysvideo.h:349
SDL_VideoDevice::blue_size
int blue_size
Definition: SDL_sysvideo.h:337
dpy
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_VideoDevice::accum_alpha_size
int accum_alpha_size
Definition: SDL_sysvideo.h:346
SDL_VideoDevice::accum_green_size
int accum_green_size
Definition: SDL_sysvideo.h:344
SDL_WindowData
Definition: SDL_androidwindow.h:39
SDL_GetDisplayForWindow
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1110
SDL_VideoDevice::driver_path
char driver_path[256]
Definition: SDL_sysvideo.h:362
SDL_VideoDevice::major_version
int major_version
Definition: SDL_sysvideo.h:351
SDL_VideoDevice::gl_data
struct SDL_GLDriverData * gl_data
Definition: SDL_sysvideo.h:390
SDL_VideoDevice::accum_blue_size
int accum_blue_size
Definition: SDL_sysvideo.h:345
SDL_VideoDevice::profile_mask
int profile_mask
Definition: SDL_sysvideo.h:354
path
GLsizei const GLchar *const * path
Definition: SDL_opengl_glext.h:3733
SDL_VideoDevice::depth_size
int depth_size
Definition: SDL_sysvideo.h:339
v
const GLdouble * v
Definition: SDL_opengl.h:2064
GLubyte
unsigned char GLubyte
Definition: SDL_opengl.h:183
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_VideoDevice::red_size
int red_size
Definition: SDL_sysvideo.h:335
SDL_Window
The type used to identify a window.
Definition: SDL_sysvideo.h:75
n
GLdouble n
Definition: SDL_opengl_glext.h:1955
SDL_VideoDevice::accum_red_size
int accum_red_size
Definition: SDL_sysvideo.h:343
SDL_GLContext
void * SDL_GLContext
An opaque handle to an OpenGL context.
Definition: SDL_video.h:192
SDL_VideoDevice::gl_config
struct SDL_VideoDevice::@255 gl_config
SDL_GetHintBoolean
#define SDL_GetHintBoolean
Definition: SDL_dynapi_overrides.h:608
SDL_WindowData::xwindow
Window xwindow
Definition: SDL_x11window.h:46
context
static screen_context_t context
Definition: video.c:25
SDL_strchr
#define SDL_strchr
Definition: SDL_dynapi_overrides.h:401
_this
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
SDL_HINT_OPENGL_ES_DRIVER
#define SDL_HINT_OPENGL_ES_DRIVER
A variable controlling what driver to use for OpenGL ES contexts.
Definition: SDL_hints.h:1108
window
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
config
EGLConfig config
Definition: eglext.h:433
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_GL_DeduceMaxSupportedESProfile
void SDL_GL_DeduceMaxSupportedESProfile(int *major, int *minor)
Definition: SDL_video.c:3065
SDL_VideoDevice::driver_loaded
int driver_loaded
Definition: SDL_sysvideo.h:361
SDL_VideoDevice::multisamplebuffers
int multisamplebuffers
Definition: SDL_sysvideo.h:348
SDL_GL_CONTEXT_PROFILE_ES
@ SDL_GL_CONTEXT_PROFILE_ES
Definition: SDL_video.h:232
SDL_VideoDevice::share_with_current_context
int share_with_current_context
Definition: SDL_sysvideo.h:355
SDL_VideoDevice::green_size
int green_size
Definition: SDL_sysvideo.h:336
SDL_assert.h
SDL_GLDriverData
Definition: SDL_pspgl_c.h:32
SDL_GLDriverData::swapinterval
uint32_t swapinterval
Definition: SDL_pspgl_c.h:36
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
SDL_VideoDevice::no_error
int no_error
Definition: SDL_sysvideo.h:359
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_VideoDevice::dll_handle
void * dll_handle
Definition: SDL_sysvideo.h:363
SDL_GL_GetCurrentContext
#define SDL_GL_GetCurrentContext
Definition: SDL_dynapi_overrides.h:562
SDL_VideoDisplay::driverdata
void * driverdata
Definition: SDL_sysvideo.h:140
start
GLuint start
Definition: SDL_opengl.h:1571
SDL_VideoDevice::double_buffer
int double_buffer
Definition: SDL_sysvideo.h:342
SDL_DisplayData
Definition: SDL_cocoamodes.h:27
SDL_x11opengles.h
SDL_VideoDevice::release_behavior
int release_behavior
Definition: SDL_sysvideo.h:356
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_VideoDevice::flags
int flags
Definition: SDL_sysvideo.h:353
size
GLsizeiptr size
Definition: SDL_opengl_glext.h:540
SDL_HINT_VIDEO_X11_FORCE_EGL
#define SDL_HINT_VIDEO_X11_FORCE_EGL
A variable controlling whether X11 should use GLX or EGL by default.
Definition: SDL_hints.h:256
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_VideoDevice::GL_SetSwapInterval
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:262
SDL_VideoDevice::reset_notification
int reset_notification
Definition: SDL_sysvideo.h:357
SDL_VideoDevice::stereo
int stereo
Definition: SDL_sysvideo.h:347
SDL_getenv
#define SDL_getenv
Definition: SDL_dynapi_overrides.h:378
attrib_list
EGLenum const EGLAttribKHR * attrib_list
Definition: eglext.h:63
SDL_iconv_string
#define SDL_iconv_string
Definition: SDL_dynapi_overrides.h:441
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_VideoDevice::GL_MakeCurrent
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:260
SDL_VideoDevice::GL_LoadLibrary
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:256
SDL_GL_GetCurrentWindow
#define SDL_GL_GetCurrentWindow
Definition: SDL_dynapi_overrides.h:561
SDL_VideoDevice::GL_UnloadLibrary
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:258
SDL_VideoDevice::GL_CreateContext
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:259
SDL_hints.h
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 Uint32 * e
Definition: SDL_dynapi_procs.h:117
SDL_VideoDevice::framebuffer_srgb_capable
int framebuffer_srgb_capable
Definition: SDL_sysvideo.h:358
SDL_VideoDevice::GL_GetSwapInterval
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:263
SDL_VideoDevice::alpha_size
int alpha_size
Definition: SDL_sysvideo.h:338
SDL_strlen
#define SDL_strlen
Definition: SDL_dynapi_overrides.h:393
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_VideoDevice::GL_SwapWindow
int(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:264
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_Unsupported
#define SDL_Unsupported()
Definition: SDL_error.h:53
SDL_VideoDevice::accelerated
int accelerated
Definition: SDL_sysvideo.h:350
SDL_VideoDevice::GL_GetProcAddress
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:257
SDL_VideoDevice::stencil_size
int stencil_size
Definition: SDL_sysvideo.h:341
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 void
Definition: SDL_dynapi_procs.h:89
SDL_strstr
#define SDL_strstr
Definition: SDL_dynapi_overrides.h:403
SDL_VideoDevice::minor_version
int minor_version
Definition: SDL_sysvideo.h:352
X11_PumpEvents
void X11_PumpEvents(_THIS)
SDL_VideoDevice::GL_DeleteContext
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:265
SDL_loadso.h
i
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
SDL_VideoData
Definition: SDL_androidvideo.h:37
d
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
Definition: SDL_dynapi_procs.h:117
w
GLubyte GLubyte GLubyte GLubyte w
Definition: SDL_opengl_glext.h:734
SDL_GLDriverData::display
EGLDisplay display
Definition: SDL_pspgl_c.h:33