SDL  2.0
SDL_x11opengl.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 "/usr/X11R6/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 */
191  handle = _this->gl_config.dll_handle;
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  */
242  X11_GL_UseEGL(_this) ) {
243 #if SDL_VIDEO_OPENGL_EGL
244  X11_GL_UnloadLibrary(_this);
245  /* Better avoid conflicts! */
246  if (_this->gl_config.dll_handle != NULL ) {
247  GL_UnloadObject(_this->gl_config.dll_handle);
249  }
250  _this->GL_LoadLibrary = X11_GLES_LoadLibrary;
251  _this->GL_GetProcAddress = X11_GLES_GetProcAddress;
252  _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
253  _this->GL_CreateContext = X11_GLES_CreateContext;
254  _this->GL_MakeCurrent = X11_GLES_MakeCurrent;
255  _this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
256  _this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
257  _this->GL_SwapWindow = X11_GLES_SwapWindow;
258  _this->GL_DeleteContext = X11_GLES_DeleteContext;
259  return X11_GLES_LoadLibrary(_this, NULL);
260 #else
261  return SDL_SetError("SDL not configured with EGL support");
262 #endif
263  }
264 
265  return 0;
266 }
267 
268 void *
269 X11_GL_GetProcAddress(_THIS, const char *proc)
270 {
271  if (_this->gl_data->glXGetProcAddress) {
272  return _this->gl_data->glXGetProcAddress((const GLubyte *) proc);
273  }
274  return GL_LoadFunction(_this->gl_config.dll_handle, proc);
275 }
276 
277 void
278 X11_GL_UnloadLibrary(_THIS)
279 {
280  /* Don't actually unload the library, since it may have registered
281  * X11 shutdown hooks, per the notes at:
282  * http://dri.sourceforge.net/doc/DRIuserguide.html
283  */
284 #if 0
285  GL_UnloadObject(_this->gl_config.dll_handle);
287 #endif
288 
289  /* Free OpenGL memory */
291  _this->gl_data = NULL;
292 }
293 
294 static SDL_bool
295 HasExtension(const char *extension, const char *extensions)
296 {
297  const char *start;
298  const char *where, *terminator;
299 
300  if (!extensions)
301  return SDL_FALSE;
302 
303  /* Extension names should not have spaces. */
304  where = SDL_strchr(extension, ' ');
305  if (where || *extension == '\0')
306  return SDL_FALSE;
307 
308  /* It takes a bit of care to be fool-proof about parsing the
309  * OpenGL extensions string. Don't be fooled by sub-strings,
310  * etc. */
311 
312  start = extensions;
313 
314  for (;;) {
315  where = SDL_strstr(start, extension);
316  if (!where)
317  break;
318 
319  terminator = where + SDL_strlen(extension);
320  if (where == start || *(where - 1) == ' ')
321  if (*terminator == ' ' || *terminator == '\0')
322  return SDL_TRUE;
323 
324  start = terminator;
325  }
326  return SDL_FALSE;
327 }
328 
329 static void
330 X11_GL_InitExtensions(_THIS)
331 {
332  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
333  const int screen = DefaultScreen(display);
334  XVisualInfo *vinfo = NULL;
335  Window w = 0;
336  GLXContext prev_ctx = 0;
337  GLXDrawable prev_drawable = 0;
338  GLXContext context = 0;
339  const char *(*glXQueryExtensionsStringFunc) (Display *, int);
340  const char *extensions;
341 
342  vinfo = X11_GL_GetVisual(_this, display, screen);
343  if (vinfo) {
344  GLXContext (*glXGetCurrentContextFunc) (void) =
345  (GLXContext(*)(void))
346  X11_GL_GetProcAddress(_this, "glXGetCurrentContext");
347 
348  GLXDrawable (*glXGetCurrentDrawableFunc) (void) =
349  (GLXDrawable(*)(void))
350  X11_GL_GetProcAddress(_this, "glXGetCurrentDrawable");
351 
352  if (glXGetCurrentContextFunc && glXGetCurrentDrawableFunc) {
353  XSetWindowAttributes xattr;
354  prev_ctx = glXGetCurrentContextFunc();
355  prev_drawable = glXGetCurrentDrawableFunc();
356 
357  xattr.background_pixel = 0;
358  xattr.border_pixel = 0;
359  xattr.colormap =
360  X11_XCreateColormap(display, RootWindow(display, screen),
361  vinfo->visual, AllocNone);
362  w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0,
363  32, 32, 0, vinfo->depth, InputOutput, vinfo->visual,
364  (CWBackPixel | CWBorderPixel | CWColormap), &xattr);
365 
366  context = _this->gl_data->glXCreateContext(display, vinfo,
367  NULL, True);
368  if (context) {
369  _this->gl_data->glXMakeCurrent(display, w, context);
370  }
371  }
372 
373  X11_XFree(vinfo);
374  }
375 
376  glXQueryExtensionsStringFunc =
377  (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this,
378  "glXQueryExtensionsString");
379  if (glXQueryExtensionsStringFunc) {
380  extensions = glXQueryExtensionsStringFunc(display, screen);
381  } else {
382  extensions = NULL;
383  }
384 
385  /* Check for GLX_EXT_swap_control(_tear) */
386  _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
387  if (HasExtension("GLX_EXT_swap_control", extensions)) {
388  _this->gl_data->glXSwapIntervalEXT =
389  (void (*)(Display*,GLXDrawable,int))
390  X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
391  if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
392  _this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
393  }
394  }
395 
396  /* Check for GLX_MESA_swap_control */
397  if (HasExtension("GLX_MESA_swap_control", extensions)) {
398  _this->gl_data->glXSwapIntervalMESA =
399  (int(*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
400  _this->gl_data->glXGetSwapIntervalMESA =
401  (int(*)(void)) X11_GL_GetProcAddress(_this,
402  "glXGetSwapIntervalMESA");
403  }
404 
405  /* Check for GLX_SGI_swap_control */
406  if (HasExtension("GLX_SGI_swap_control", extensions)) {
407  _this->gl_data->glXSwapIntervalSGI =
408  (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
409  }
410 
411  /* Check for GLX_ARB_create_context */
412  if (HasExtension("GLX_ARB_create_context", extensions)) {
413  _this->gl_data->glXCreateContextAttribsARB =
414  (GLXContext (*)(Display*,GLXFBConfig,GLXContext,Bool,const int *))
415  X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB");
416  _this->gl_data->glXChooseFBConfig =
417  (GLXFBConfig *(*)(Display *, int, const int *, int *))
418  X11_GL_GetProcAddress(_this, "glXChooseFBConfig");
419  }
420 
421  /* Check for GLX_EXT_visual_rating */
422  if (HasExtension("GLX_EXT_visual_rating", extensions)) {
423  _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
424  }
425 
426  /* Check for GLX_EXT_visual_info */
427  if (HasExtension("GLX_EXT_visual_info", extensions)) {
428  _this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
429  }
430 
431  /* Check for GLX_EXT_create_context_es2_profile */
432  if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) {
433  /* this wants to call glGetString(), so it needs a context. */
434  /* !!! FIXME: it would be nice not to make a context here though! */
435  if (context) {
437  &_this->gl_data->es_profile_max_supported_version.major,
438  &_this->gl_data->es_profile_max_supported_version.minor
439  );
440  }
441  }
442 
443  /* Check for GLX_ARB_context_flush_control */
444  if (HasExtension("GLX_ARB_context_flush_control", extensions)) {
445  _this->gl_data->HAS_GLX_ARB_context_flush_control = SDL_TRUE;
446  }
447 
448  /* Check for GLX_ARB_create_context_robustness */
449  if (HasExtension("GLX_ARB_create_context_robustness", extensions)) {
450  _this->gl_data->HAS_GLX_ARB_create_context_robustness = SDL_TRUE;
451  }
452 
453  /* Check for GLX_ARB_create_context_no_error */
454  if (HasExtension("GLX_ARB_create_context_no_error", extensions)) {
455  _this->gl_data->HAS_GLX_ARB_create_context_no_error = SDL_TRUE;
456  }
457 
458  if (context) {
459  _this->gl_data->glXMakeCurrent(display, None, NULL);
460  _this->gl_data->glXDestroyContext(display, context);
461  if (prev_ctx && prev_drawable) {
462  _this->gl_data->glXMakeCurrent(display, prev_drawable, prev_ctx);
463  }
464  }
465 
466  if (w) {
467  X11_XDestroyWindow(display, w);
468  }
470 }
471 
472 /* glXChooseVisual and glXChooseFBConfig have some small differences in
473  * the attribute encoding, it can be chosen with the for_FBConfig parameter.
474  * Some targets fail if you use GLX_X_VISUAL_TYPE_EXT/GLX_DIRECT_COLOR_EXT,
475  * so it gets specified last if used and is pointed to by *_pvistypeattr.
476  * In case of failure, if that pointer is not NULL, set that pointer to None
477  * and try again.
478  */
479 static int
480 X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig, int **_pvistypeattr)
481 {
482  int i = 0;
483  const int MAX_ATTRIBUTES = 64;
484  int *pvistypeattr = NULL;
485 
486  /* assert buffer is large enough to hold all SDL attributes. */
487  SDL_assert(size >= MAX_ATTRIBUTES);
488 
489  /* Setup our GLX attributes according to the gl_config. */
490  if( for_FBConfig ) {
491  attribs[i++] = GLX_RENDER_TYPE;
492  attribs[i++] = GLX_RGBA_BIT;
493  } else {
494  attribs[i++] = GLX_RGBA;
495  }
496  attribs[i++] = GLX_RED_SIZE;
497  attribs[i++] = _this->gl_config.red_size;
498  attribs[i++] = GLX_GREEN_SIZE;
499  attribs[i++] = _this->gl_config.green_size;
500  attribs[i++] = GLX_BLUE_SIZE;
501  attribs[i++] = _this->gl_config.blue_size;
502 
503  if (_this->gl_config.alpha_size) {
504  attribs[i++] = GLX_ALPHA_SIZE;
505  attribs[i++] = _this->gl_config.alpha_size;
506  }
507 
509  attribs[i++] = GLX_DOUBLEBUFFER;
510  if( for_FBConfig ) {
511  attribs[i++] = True;
512  }
513  }
514 
515  attribs[i++] = GLX_DEPTH_SIZE;
516  attribs[i++] = _this->gl_config.depth_size;
517 
519  attribs[i++] = GLX_STENCIL_SIZE;
520  attribs[i++] = _this->gl_config.stencil_size;
521  }
522 
524  attribs[i++] = GLX_ACCUM_RED_SIZE;
525  attribs[i++] = _this->gl_config.accum_red_size;
526  }
527 
529  attribs[i++] = GLX_ACCUM_GREEN_SIZE;
530  attribs[i++] = _this->gl_config.accum_green_size;
531  }
532 
534  attribs[i++] = GLX_ACCUM_BLUE_SIZE;
535  attribs[i++] = _this->gl_config.accum_blue_size;
536  }
537 
539  attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
540  attribs[i++] = _this->gl_config.accum_alpha_size;
541  }
542 
543  if (_this->gl_config.stereo) {
544  attribs[i++] = GLX_STEREO;
545  if( for_FBConfig ) {
546  attribs[i++] = True;
547  }
548  }
549 
551  attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
552  attribs[i++] = _this->gl_config.multisamplebuffers;
553  }
554 
556  attribs[i++] = GLX_SAMPLES_ARB;
557  attribs[i++] = _this->gl_config.multisamplesamples;
558  }
559 
561  attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
562  attribs[i++] = True; /* always needed, for_FBConfig or not! */
563  }
564 
565  if (_this->gl_config.accelerated >= 0 &&
566  _this->gl_data->HAS_GLX_EXT_visual_rating) {
567  attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
568  attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT :
569  GLX_SLOW_VISUAL_EXT;
570  }
571 
572  /* If we're supposed to use DirectColor visuals, and we've got the
573  EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
575  _this->gl_data->HAS_GLX_EXT_visual_info) {
576  pvistypeattr = &attribs[i];
577  attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
578  attribs[i++] = GLX_DIRECT_COLOR_EXT;
579  }
580 
581  attribs[i++] = None;
582 
583  SDL_assert(i <= MAX_ATTRIBUTES);
584 
585  if (_pvistypeattr) {
586  *_pvistypeattr = pvistypeattr;
587  }
588 
589  return i;
590 }
591 
592 XVisualInfo *
593 X11_GL_GetVisual(_THIS, Display * display, int screen)
594 {
595  /* 64 seems nice. */
596  int attribs[64];
597  XVisualInfo *vinfo;
598  int *pvistypeattr = NULL;
599 
600  if (!_this->gl_data) {
601  /* The OpenGL library wasn't loaded, SDL_GetError() should have info */
602  return NULL;
603  }
604 
605  X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr);
606  vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
607 
608  if (!vinfo && (pvistypeattr != NULL)) {
609  *pvistypeattr = None;
610  vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
611  }
612 
613  if (!vinfo) {
614  SDL_SetError("Couldn't find matching GLX visual");
615  }
616  return vinfo;
617 }
618 
619 static int (*handler) (Display *, XErrorEvent *) = NULL;
620 static const char *errorHandlerOperation = NULL;
621 static int errorBase = 0;
622 static int errorCode = 0;
623 static int
624 X11_GL_ErrorHandler(Display * d, XErrorEvent * e)
625 {
626  char *x11_error = NULL;
627  char x11_error_locale[256];
628 
629  errorCode = e->error_code;
630  if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success)
631  {
632  x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1);
633  }
634 
635  if (x11_error)
636  {
637  SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error);
638  SDL_free(x11_error);
639  }
640  else
641  {
642  SDL_SetError("Could not %s: %i (Base %i)", errorHandlerOperation, errorCode, errorBase);
643  }
644 
645  return (0);
646 }
647 
648 SDL_bool
649 X11_GL_UseEGL(_THIS)
650 {
653 
655  || _this->gl_config.major_version == 1 /* No GLX extension for OpenGL ES 1.x profiles. */
656  || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major
657  || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major
658  && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor));
659 }
660 
662 X11_GL_CreateContext(_THIS, SDL_Window * window)
663 {
665  Display *display = data->videodata->display;
666  int screen =
667  ((SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata)->screen;
668  XWindowAttributes xattr;
669  XVisualInfo v, *vinfo;
670  int n;
671  GLXContext context = NULL, share_context;
672 
674  share_context = (GLXContext)SDL_GL_GetCurrentContext();
675  } else {
676  share_context = NULL;
677  }
678 
679  /* We do this to create a clean separation between X and GLX errors. */
680  X11_XSync(display, False);
681  errorHandlerOperation = "create GL context";
682  errorBase = _this->gl_data->errorBase;
683  errorCode = Success;
684  handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
685  X11_XGetWindowAttributes(display, data->xwindow, &xattr);
686  v.screen = screen;
687  v.visualid = X11_XVisualIDFromVisual(xattr.visual);
688  vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
689  if (vinfo) {
690  if (_this->gl_config.major_version < 3 &&
691  _this->gl_config.profile_mask == 0 &&
692  _this->gl_config.flags == 0) {
693  /* Create legacy context */
694  context =
695  _this->gl_data->glXCreateContext(display, vinfo, share_context, True);
696  } else {
697  /* max 14 attributes plus terminator */
698  int attribs[15] = {
699  GLX_CONTEXT_MAJOR_VERSION_ARB,
701  GLX_CONTEXT_MINOR_VERSION_ARB,
703  0
704  };
705  int iattr = 4;
706 
707  /* SDL profile bits match GLX profile bits */
708  if( _this->gl_config.profile_mask != 0 ) {
709  attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
710  attribs[iattr++] = _this->gl_config.profile_mask;
711  }
712 
713  /* SDL flags match GLX flags */
714  if( _this->gl_config.flags != 0 ) {
715  attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
716  attribs[iattr++] = _this->gl_config.flags;
717  }
718 
719  /* only set if glx extension is available */
720  if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) {
721  attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB;
722  attribs[iattr++] =
724  GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :
725  GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
726  }
727 
728  /* only set if glx extension is available */
729  if( _this->gl_data->HAS_GLX_ARB_create_context_robustness ) {
730  attribs[iattr++] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
731  attribs[iattr++] =
733  GLX_LOSE_CONTEXT_ON_RESET_ARB :
734  GLX_NO_RESET_NOTIFICATION_ARB;
735  }
736 
737  /* only set if glx extension is available */
738  if( _this->gl_data->HAS_GLX_ARB_create_context_no_error ) {
739  attribs[iattr++] = GLX_CONTEXT_OPENGL_NO_ERROR_ARB;
740  attribs[iattr++] = _this->gl_config.no_error;
741  }
742 
743  attribs[iattr++] = 0;
744 
745  /* Get a pointer to the context creation function for GL 3.0 */
746  if (!_this->gl_data->glXCreateContextAttribsARB) {
747  SDL_SetError("OpenGL 3.0 and later are not supported by this system");
748  } else {
749  int glxAttribs[64];
750 
751  /* Create a GL 3.x context */
752  GLXFBConfig *framebuffer_config = NULL;
753  int fbcount = 0;
754  int *pvistypeattr = NULL;
755 
756  X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE,&pvistypeattr);
757 
758  if (_this->gl_data->glXChooseFBConfig) {
759  framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
760  DefaultScreen(display), glxAttribs,
761  &fbcount);
762 
763  if (!framebuffer_config && (pvistypeattr != NULL)) {
764  *pvistypeattr = None;
765  framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
766  DefaultScreen(display), glxAttribs,
767  &fbcount);
768  }
769 
770  if (framebuffer_config) {
771  context = _this->gl_data->glXCreateContextAttribsARB(display,
772  framebuffer_config[0],
773  share_context, True, attribs);
774  X11_XFree(framebuffer_config);
775  }
776  }
777  }
778  }
779  X11_XFree(vinfo);
780  }
781  X11_XSync(display, False);
782  X11_XSetErrorHandler(handler);
783 
784  if (!context) {
785  if (errorCode == Success) {
786  SDL_SetError("Could not create GL context");
787  }
788  return NULL;
789  }
790 
791  if (X11_GL_MakeCurrent(_this, window, context) < 0) {
792  X11_GL_DeleteContext(_this, context);
793  return NULL;
794  }
795 
796  return context;
797 }
798 
799 int
800 X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
801 {
802  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
803  Window drawable =
804  (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None);
805  GLXContext glx_context = (GLXContext) context;
806  int rc;
807 
808  if (!_this->gl_data) {
809  return SDL_SetError("OpenGL not initialized");
810  }
811 
812  /* We do this to create a clean separation between X and GLX errors. */
813  X11_XSync(display, False);
814  errorHandlerOperation = "make GL context current";
815  errorBase = _this->gl_data->errorBase;
816  errorCode = Success;
817  handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
818  rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context);
819  X11_XSetErrorHandler(handler);
820 
821  if (errorCode != Success) { /* uhoh, an X error was thrown! */
822  return -1; /* the error handler called SDL_SetError() already. */
823  } else if (!rc) { /* glXMakeCurrent() failed without throwing an X error */
824  return SDL_SetError("Unable to make GL context current");
825  }
826 
827  return 0;
828 }
829 
830 /*
831  0 is a valid argument to glXSwapInterval(MESA|EXT) and setting it to 0
832  will undo the effect of a previous call with a value that is greater
833  than zero (or at least that is what the docs say). OTOH, 0 is an invalid
834  argument to glXSwapIntervalSGI and it returns an error if you call it
835  with 0 as an argument.
836 */
837 
838 static int swapinterval = 0;
839 int
840 X11_GL_SetSwapInterval(_THIS, int interval)
841 {
842  int status = -1;
843 
844  if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
845  SDL_SetError("Negative swap interval unsupported in this GL");
846  } else if (_this->gl_data->glXSwapIntervalEXT) {
847  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
848  const SDL_WindowData *windowdata = (SDL_WindowData *)
849  SDL_GL_GetCurrentWindow()->driverdata;
850 
851  Window drawable = windowdata->xwindow;
852 
853  /*
854  * This is a workaround for a bug in NVIDIA drivers. Bug has been reported
855  * and will be fixed in a future release (probably 319.xx).
856  *
857  * There's a bug where glXSetSwapIntervalEXT ignores updates because
858  * it has the wrong value cached. To work around it, we just run a no-op
859  * update to the current value.
860  */
861  int currentInterval = X11_GL_GetSwapInterval(_this);
862  _this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
863  _this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
864 
865  status = 0;
866  swapinterval = interval;
867  } else if (_this->gl_data->glXSwapIntervalMESA) {
868  status = _this->gl_data->glXSwapIntervalMESA(interval);
869  if (status != 0) {
870  SDL_SetError("glXSwapIntervalMESA failed");
871  } else {
872  swapinterval = interval;
873  }
874  } else if (_this->gl_data->glXSwapIntervalSGI) {
875  status = _this->gl_data->glXSwapIntervalSGI(interval);
876  if (status != 0) {
877  SDL_SetError("glXSwapIntervalSGI failed");
878  } else {
879  swapinterval = interval;
880  }
881  } else {
882  SDL_Unsupported();
883  }
884  return status;
885 }
886 
887 int
888 X11_GL_GetSwapInterval(_THIS)
889 {
890  if (_this->gl_data->glXSwapIntervalEXT) {
891  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
892  const SDL_WindowData *windowdata = (SDL_WindowData *)
893  SDL_GL_GetCurrentWindow()->driverdata;
894  Window drawable = windowdata->xwindow;
895  unsigned int allow_late_swap_tearing = 0;
896  unsigned int interval = 0;
897 
898  if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
899  _this->gl_data->glXQueryDrawable(display, drawable,
900  GLX_LATE_SWAPS_TEAR_EXT,
901  &allow_late_swap_tearing);
902  }
903 
904  _this->gl_data->glXQueryDrawable(display, drawable,
905  GLX_SWAP_INTERVAL_EXT, &interval);
906 
907  if ((allow_late_swap_tearing) && (interval > 0)) {
908  return -((int) interval);
909  }
910 
911  return (int) interval;
912  } else if (_this->gl_data->glXGetSwapIntervalMESA) {
913  return _this->gl_data->glXGetSwapIntervalMESA();
914  } else {
915  return swapinterval;
916  }
917 }
918 
919 int
920 X11_GL_SwapWindow(_THIS, SDL_Window * window)
921 {
922  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
923  Display *display = data->videodata->display;
924 
925  _this->gl_data->glXSwapBuffers(display, data->xwindow);
926  return 0;
927 }
928 
929 void
930 X11_GL_DeleteContext(_THIS, SDL_GLContext context)
931 {
932  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
933  GLXContext glx_context = (GLXContext) context;
934 
935  if (!_this->gl_data) {
936  return;
937  }
938  _this->gl_data->glXDestroyContext(display, glx_context);
939  X11_XSync(display, False);
940 }
941 
942 #endif /* SDL_VIDEO_OPENGL_GLX */
943 
944 #endif /* SDL_VIDEO_DRIVER_X11 */
945 
946 /* vi: set ts=4 sw=4 expandtab: */
void X11_PumpEvents(_THIS)
#define SDL_strlcpy
const GLint * attribs
uint32_t swapinterval
Definition: SDL_pspgl_c.h:36
EGLenum const EGLAttribKHR * attrib_list
Definition: eglext.h:63
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
const GLdouble * v
Definition: SDL_opengl.h:2064
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display dpy)
Definition: SDL_x11sym.h:44
struct wl_display * display
SDL_bool X11_UseDirectColorVisuals(void)
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:260
static screen_context_t context
Definition: video.c:25
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLuint start
Definition: SDL_opengl.h:1571
EGLDisplay display
Definition: SDL_pspgl_c.h:33
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:254
struct SDL_GLDriverData * gl_data
Definition: SDL_sysvideo.h:378
#define SDL_strchr
#define SDL_GetHintBoolean
#define SDL_HINT_OPENGL_ES_DRIVER
A variable controlling what driver to use for OpenGL ES contexts.
Definition: SDL_hints.h:892
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
void * SDL_GLContext
An opaque handle to an OpenGL context.
Definition: SDL_video.h:175
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:257
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
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 _THIS
struct SDL_VideoData * videodata
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:258
#define SDL_free
char driver_path[256]
Definition: SDL_sysvideo.h:350
void SDL_GL_DeduceMaxSupportedESProfile(int *major, int *minor)
Definition: SDL_video.c:2942
GLubyte GLubyte GLubyte GLubyte w
int framebuffer_srgb_capable
Definition: SDL_sysvideo.h:346
unsigned char GLubyte
Definition: SDL_opengl.h:183
GLsizeiptr size
#define SDL_getenv
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:256
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
int share_with_current_context
Definition: SDL_sysvideo.h:343
#define SDL_assert(condition)
Definition: SDL_assert.h:169
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
#define SDL_GL_GetCurrentContext
#define SDL_SetError
#define SDL_GL_GetCurrentWindow
#define SDL_calloc
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1073
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
int(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:262
#define SDL_strlen
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
The type used to identify a window.
Definition: SDL_sysvideo.h:73
EGLConfig config
Definition: eglext.h:433
#define SDL_iconv_string
GLdouble n
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
GLsizei const GLchar *const * path
struct SDL_VideoDevice::@34 gl_config
void * driverdata
Definition: SDL_sysvideo.h:111
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:263
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:261
SDL_Renderer * screen
#define SDL_Unsupported()
Definition: SDL_error.h:53
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:255
#define SDL_strstr