Panda3D
glxGraphicsStateGuardian.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file glxGraphicsStateGuardian.cxx
10  * @author drose
11  * @date 2003-01-27
12  */
13 
15 #include "config_glxdisplay.h"
16 #include "config_glgsg.h"
17 #include "lightReMutexHolder.h"
18 
19 #include <dlfcn.h>
20 
21 using std::string;
22 
23 
24 TypeHandle glxGraphicsStateGuardian::_type_handle;
25 
26 /**
27  *
28  */
29 glxGraphicsStateGuardian::
30 glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
31  glxGraphicsStateGuardian *share_with) :
32  PosixGraphicsStateGuardian(engine, pipe)
33 {
34  _share_context=nullptr;
35  _context=nullptr;
36  _display=nullptr;
37  _screen=0;
38  _visual=nullptr;
39  _visuals=nullptr;
40  _fbconfig=nullptr;
41  _context_has_pbuffer = false;
42  _context_has_pixmap = false;
43  _slow = false;
44 
45  _supports_swap_control = false;
46  _supports_fbconfig = false;
47  _supports_pbuffer = false;
48  _uses_sgix_pbuffer = false;
49 
50  if (share_with != nullptr) {
51  _prepared_objects = share_with->get_prepared_objects();
52  _share_context = share_with->_context;
53  }
54 
55  _checked_get_proc_address = false;
56  _glXGetProcAddress = nullptr;
57  _temp_context = (GLXContext)nullptr;
58  _temp_xwindow = (X11_Window)nullptr;
59  _temp_colormap = (Colormap)nullptr;
60 }
61 
62 /**
63  *
64  */
65 glxGraphicsStateGuardian::
66 ~glxGraphicsStateGuardian() {
67  // Actually, the lock might have already destructed, so we can't reliably
68  // grab the X11 lock here.
69  //LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
70  destroy_temp_xwindow();
71  if (_visuals != nullptr) {
72  XFree(_visuals);
73  }
74  if (_context != (GLXContext)nullptr) {
75  glXDestroyContext(_display, _context);
76  _context = (GLXContext)nullptr;
77  }
78 }
79 
80 /**
81  * Gets the FrameBufferProperties to match the indicated visual.
82  */
84 get_properties(FrameBufferProperties &properties, XVisualInfo *visual) {
85 
86  int use_gl, render_mode, double_buffer, stereo,
87  red_size, green_size, blue_size,
88  alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
89  depth_size, stencil_size;
90 
91  glXGetConfig(_display, visual, GLX_USE_GL, &use_gl);
92  glXGetConfig(_display, visual, GLX_RGBA, &render_mode);
93  glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &double_buffer);
94  glXGetConfig(_display, visual, GLX_STEREO, &stereo);
95  glXGetConfig(_display, visual, GLX_RED_SIZE, &red_size);
96  glXGetConfig(_display, visual, GLX_GREEN_SIZE, &green_size);
97  glXGetConfig(_display, visual, GLX_BLUE_SIZE, &blue_size);
98  glXGetConfig(_display, visual, GLX_ALPHA_SIZE, &alpha_size);
99  glXGetConfig(_display, visual, GLX_ACCUM_RED_SIZE, &ared_size);
100  glXGetConfig(_display, visual, GLX_ACCUM_GREEN_SIZE, &agreen_size);
101  glXGetConfig(_display, visual, GLX_ACCUM_BLUE_SIZE, &ablue_size);
102  glXGetConfig(_display, visual, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
103  glXGetConfig(_display, visual, GLX_DEPTH_SIZE, &depth_size);
104  glXGetConfig(_display, visual, GLX_STENCIL_SIZE, &stencil_size);
105 
106  properties.clear();
107 
108  if (use_gl == 0) {
109  // If we return a set of properties without setting either rgb_color or
110  // indexed_color, then this indicates a visual that's no good for any kind
111  // of rendering.
112  return;
113  }
114 
115  if (double_buffer) {
116  properties.set_back_buffers(1);
117  }
118  if (stereo) {
119  properties.set_stereo(1);
120  }
121  if (render_mode) {
122  properties.set_rgb_color(1);
123  } else {
124  properties.set_indexed_color(1);
125  }
126 
127  properties.set_rgba_bits(red_size, green_size, blue_size, alpha_size);
128  properties.set_stencil_bits(stencil_size);
129  properties.set_depth_bits(depth_size);
130  properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size);
131 
132  // Set both hardware and software bits, indicating not-yet-known.
133  properties.set_force_software(1);
134  properties.set_force_hardware(1);
135 }
136 
137 /**
138  * Gets the FrameBufferProperties to match the indicated GLXFBConfig
139  */
142  bool &context_has_pbuffer, bool &context_has_pixmap,
143  bool &slow, GLXFBConfig config) {
144  properties.clear();
145 
146  if (_supports_fbconfig) {
147  // Now update our framebuffer_mode and bit depth appropriately.
148  int render_type, double_buffer, stereo, red_size, green_size, blue_size,
149  alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
150  depth_size, stencil_size, samples, drawable_type, caveat, srgb_capable;
151 
152  _glXGetFBConfigAttrib(_display, config, GLX_RENDER_TYPE, &render_type);
153  _glXGetFBConfigAttrib(_display, config, GLX_DOUBLEBUFFER, &double_buffer);
154  _glXGetFBConfigAttrib(_display, config, GLX_STEREO, &stereo);
155  _glXGetFBConfigAttrib(_display, config, GLX_RED_SIZE, &red_size);
156  _glXGetFBConfigAttrib(_display, config, GLX_GREEN_SIZE, &green_size);
157  _glXGetFBConfigAttrib(_display, config, GLX_BLUE_SIZE, &blue_size);
158  _glXGetFBConfigAttrib(_display, config, GLX_ALPHA_SIZE, &alpha_size);
159  _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_RED_SIZE, &ared_size);
160  _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_GREEN_SIZE, &agreen_size);
161  _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_BLUE_SIZE, &ablue_size);
162  _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
163  _glXGetFBConfigAttrib(_display, config, GLX_DEPTH_SIZE, &depth_size);
164  _glXGetFBConfigAttrib(_display, config, GLX_STENCIL_SIZE, &stencil_size);
165  _glXGetFBConfigAttrib(_display, config, GLX_SAMPLES, &samples);
166  _glXGetFBConfigAttrib(_display, config, GLX_DRAWABLE_TYPE, &drawable_type);
167  _glXGetFBConfigAttrib(_display, config, GLX_CONFIG_CAVEAT, &caveat);
168  _glXGetFBConfigAttrib(_display, config, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgb_capable);
169 
170  context_has_pbuffer = false;
171  if ((drawable_type & GLX_PBUFFER_BIT)!=0) {
172  context_has_pbuffer = true;
173  }
174 
175  context_has_pixmap = false;
176  if ((drawable_type & GLX_PIXMAP_BIT)!=0) {
177  context_has_pixmap = true;
178  }
179 
180  slow = false;
181  if (caveat == GLX_SLOW_CONFIG) {
182  slow = true;
183  }
184 
185  if ((drawable_type & GLX_WINDOW_BIT)==0) {
186  // We insist on having a context that will support an onscreen window.
187  return;
188  }
189 
190  if (double_buffer) {
191  properties.set_back_buffers(1);
192  }
193 
194  if (stereo) {
195  properties.set_stereo(true);
196  }
197 
198  if (srgb_capable) {
199  properties.set_srgb_color(true);
200  }
201 
202  if ((render_type & GLX_RGBA_BIT)!=0) {
203  properties.set_rgb_color(true);
204  }
205  if ((render_type & GLX_COLOR_INDEX_BIT)!=0) {
206  properties.set_indexed_color(true);
207  }
208 
209  properties.set_rgba_bits(red_size, green_size, blue_size, alpha_size);
210  properties.set_stencil_bits(stencil_size);
211  properties.set_depth_bits(depth_size);
212  properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size);
213  properties.set_multisamples(samples);
214 
215  // Set both hardware and software bits, indicating not-yet-known.
216  properties.set_force_software(1);
217  properties.set_force_hardware(1);
218  }
219 }
220 
221 /**
222  * Selects a visual or fbconfig for all the windows and buffers that use this
223  * gsg. Also creates the GL context and obtains the visual.
224  */
227  X11_Display *display,
228  int screen, bool need_pbuffer, bool need_pixmap) {
229 
230  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
231  _display = display;
232  _screen = screen;
233  _context = nullptr;
234  _fbconfig = nullptr;
235  _visual = nullptr;
236  if (_visuals != nullptr) {
237  XFree(_visuals);
238  _visuals = nullptr;
239  }
240 
241  _fbprops.clear();
242 
243  // First, attempt to create a context using the XVisual interface. We need
244  // this before we can query the FBConfig interface, because we need an
245  // OpenGL context to get the required extension function pointers.
246  destroy_temp_xwindow();
247  choose_temp_visual(properties);
248  if (_temp_context == nullptr) {
249  // No good.
250  return;
251  }
252 
253  // Now we have to initialize the context so we can query its capabilities
254  // and extensions. This also means creating a temporary window, so we have
255  // something to bind the context to and make it current.
256  init_temp_context();
257 
258  if (!_supports_fbconfig) {
259  // We have a good OpenGL context, but it doesn't support the FBConfig
260  // interface, so we'll stop there.
261  glxdisplay_cat.debug()
262  <<" No FBConfig supported; using XVisual only.\n"
263  << _fbprops << "\n";
264 
265  _context = _temp_context;
266  _temp_context = (GLXContext)nullptr;
267 
268  // By convention, every indirect XVisual that can render to a window can
269  // also render to a GLXPixmap. Direct visuals we're not as sure about.
270  _context_has_pixmap = !glXIsDirect(_display, _context);
271 
272  // Pbuffers aren't supported at all with the XVisual interface.
273  _context_has_pbuffer = false;
274  return;
275  }
276 
277  // The OpenGL context supports the FBConfig interface, so we can use that
278  // more advanced interface to choose the actual window format we'll use.
279  // FBConfig provides for more options than the older XVisual interface, so
280  // we'd much rather use it if it's available.
281 
282  int best_quality = 0;
283  int best_result = 0;
284  FrameBufferProperties best_props;
285 
286  int render_type = GLX_RGBA_TYPE;
287  if (properties.get_indexed_color()) {
288  render_type = GLX_COLOR_INDEX_TYPE;
289  }
290 
291  static const int max_attrib_list = 32;
292  int attrib_list[max_attrib_list];
293  int n = 0;
294  attrib_list[n++] = GLX_STEREO;
295  attrib_list[n++] = GLX_DONT_CARE;
296  attrib_list[n++] = GLX_RENDER_TYPE;
297  attrib_list[n++] = GLX_DONT_CARE;
298  attrib_list[n++] = GLX_DRAWABLE_TYPE;
299  attrib_list[n++] = GLX_DONT_CARE;
300  attrib_list[n] = (int)None;
301 
302  int num_configs = 0;
303  GLXFBConfig *configs =
304  _glXChooseFBConfig(_display, _screen, attrib_list, &num_configs);
305 
306  if (configs != nullptr) {
307  bool context_has_pbuffer, context_has_pixmap, slow;
308  int quality, i;
309  for (i = 0; i < num_configs; ++i) {
310  FrameBufferProperties fbprops;
311  get_properties_advanced(fbprops, context_has_pbuffer, context_has_pixmap,
312  slow, configs[i]);
313  quality = fbprops.get_quality(properties);
314  if ((quality > 0)&&(slow)) quality -= 10000000;
315  if (glxdisplay_cat.is_debug()) {
316  const char *pbuffertext = context_has_pbuffer ? " (pbuffer)" : "";
317  const char *pixmaptext = context_has_pixmap ? " (pixmap)" : "";
318  const char *slowtext = slow ? " (slow)" : "";
319  glxdisplay_cat.debug()
320  << i << ": " << fbprops << " quality=" << quality << pbuffertext
321  << pixmaptext << slowtext << "\n";
322  }
323  if (need_pbuffer && !context_has_pbuffer) {
324  continue;
325  }
326  if (need_pixmap && !context_has_pixmap) {
327  continue;
328  }
329 
330  if (quality > best_quality) {
331  best_quality = quality;
332  best_result = i;
333  best_props = fbprops;
334  }
335  }
336  }
337 
338  if (best_quality > 0) {
339  _fbconfig = configs[best_result];
340 
341  if (_glXCreateContextAttribs != nullptr) {
342  // NB. This is a wholly different type of attrib list than below, the
343  // same values are not used!
344  n = 0;
345  attrib_list[n++] = GLX_RENDER_TYPE;
346  attrib_list[n++] = render_type;
347  if (gl_version.get_num_words() > 0) {
348  attrib_list[n++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
349  attrib_list[n++] = gl_version[0];
350  if (gl_version.get_num_words() > 1) {
351  attrib_list[n++] = GLX_CONTEXT_MINOR_VERSION_ARB;
352  attrib_list[n++] = gl_version[1];
353  }
354  }
355  int flags = 0;
356  if (gl_debug) {
357  flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
358  }
359  if (gl_forward_compatible) {
360  flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
361  if (gl_version.get_num_words() == 0 || gl_version[0] < 2) {
362  glxdisplay_cat.error()
363  << "gl-forward-compatible requires gl-version >= 3 0\n";
364  }
365  }
366  if (flags != 0) {
367  attrib_list[n++] = GLX_CONTEXT_FLAGS_ARB;
368  attrib_list[n++] = flags;
369  }
370  attrib_list[n] = None;
371  _context = _glXCreateContextAttribs(_display, _fbconfig, _share_context,
372  GL_TRUE, attrib_list);
373  } else {
374  _context =
375  _glXCreateNewContext(_display, _fbconfig, render_type, _share_context,
376  GL_TRUE);
377  }
378 
379  if (_context) {
380  mark_new();
381 
382  if (_visuals != nullptr) {
383  XFree(_visuals);
384  _visuals = nullptr;
385  }
386  _visuals = _glXGetVisualFromFBConfig(_display, _fbconfig);
387  _visual = _visuals;
388 
389  if (_visual) {
390  get_properties_advanced(_fbprops, _context_has_pbuffer, _context_has_pixmap,
391  _slow, _fbconfig);
392 
393  if (!properties.get_srgb_color()) {
394  _fbprops.set_srgb_color(false);
395  }
396 
397  if (glxdisplay_cat.is_debug()) {
398  glxdisplay_cat.debug()
399  << "Selected context " << best_result << ": " << _fbprops << "\n";
400  glxdisplay_cat.debug()
401  << "context_has_pbuffer = " << _context_has_pbuffer
402  << ", context_has_pixmap = " << _context_has_pixmap << "\n";
403  }
404 
405  return;
406  }
407  }
408  // This really shouldn't happen, so I'm not too careful about cleanup.
409  glxdisplay_cat.error()
410  << "Could not create FBConfig context!\n";
411  _fbconfig = nullptr;
412  _context = nullptr;
413  _visual = nullptr;
414  _visuals = nullptr;
415  }
416 
417  glxdisplay_cat.warning()
418  << "No suitable FBConfig contexts available; using XVisual only.\n"
419  << _fbprops << "\n";
420 
421  _context = _temp_context;
422  _temp_context = (GLXContext)nullptr;
423 
424  // By convention, every indirect XVisual that can render to a window can
425  // also render to a GLXPixmap. Direct visuals we're not as sure about.
426  _context_has_pixmap = !glXIsDirect(_display, _context);
427 
428  // Pbuffers aren't supported at all with the XVisual interface.
429  _context_has_pbuffer = false;
430 }
431 
432 /**
433  * Returns true if the runtime GLX version number is at least the indicated
434  * value, false otherwise.
435  */
437 glx_is_at_least_version(int major_version, int minor_version) const {
438  if (_glx_version_major < major_version) {
439  return false;
440  }
441  if (_glx_version_major > major_version) {
442  return true;
443  }
444  if (_glx_version_minor < minor_version) {
445  return false;
446  }
447  return true;
448 }
449 
450 /**
451  * Calls glFlush().
452  */
453 void glxGraphicsStateGuardian::
454 gl_flush() const {
455  // This call requires synchronization with X.
456  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
457  PosixGraphicsStateGuardian::gl_flush();
458 }
459 
460 /**
461  * Returns the result of glGetError().
462  */
463 GLenum glxGraphicsStateGuardian::
464 gl_get_error() const {
465  // This call requires synchronization with X.
466  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
467  return PosixGraphicsStateGuardian::gl_get_error();
468 }
469 
470 /**
471  * Queries the runtime version of OpenGL in use.
472  */
473 void glxGraphicsStateGuardian::
474 query_gl_version() {
475  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
476  PosixGraphicsStateGuardian::query_gl_version();
477 
478  show_glx_client_string("GLX_VENDOR", GLX_VENDOR);
479  show_glx_client_string("GLX_VERSION", GLX_VERSION);
480  show_glx_server_string("GLX_VENDOR", GLX_VENDOR);
481  show_glx_server_string("GLX_VERSION", GLX_VERSION);
482 
483  glXQueryVersion(_display, &_glx_version_major, &_glx_version_minor);
484 
485  // We output to glgsg_cat instead of glxdisplay_cat, since this is where the
486  // GL version has been output, and it's nice to see the two of these
487  // together.
488  if (glgsg_cat.is_debug()) {
489  glgsg_cat.debug()
490  << "GLX_VERSION = " << _glx_version_major << "." << _glx_version_minor
491  << "\n";
492  }
493 }
494 
495 /**
496  * This may be redefined by a derived class (e.g. glx or wgl) to get whatever
497  * further extensions strings may be appropriate to that interface, in
498  * addition to the GL extension strings return by glGetString().
499  */
500 void glxGraphicsStateGuardian::
501 get_extra_extensions() {
502  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
503  save_extensions(glXQueryExtensionsString(_display, _screen));
504 }
505 
506 /**
507  * Returns the pointer to the GL extension function with the indicated name.
508  * It is the responsibility of the caller to ensure that the required
509  * extension is defined in the OpenGL runtime prior to calling this; it is an
510  * error to call this for a function that is not defined.
511  */
512 void *glxGraphicsStateGuardian::
513 do_get_extension_func(const char *name) {
514  nassertr(name != nullptr, nullptr);
515 
516  if (glx_get_proc_address) {
517  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
518 
519  // First, check if we have glXGetProcAddress available. This will be
520  // superior if we can get it.
521 
522 #if defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESS)
523  // If we are confident the system headers defined it, we can call it
524  // directly. This is more reliable than trying to determine its address
525  // dynamically, but it may make libpandagl.so fail to load if the symbol
526  // isn't in the runtime library.
527  return (void *)glXGetProcAddress((const GLubyte *)name);
528 
529 #elif defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESSARB)
530  // The ARB extension version is OK too. Sometimes the prototype isn't
531  // supplied for some reason.
532  return (void *)glXGetProcAddressARB((const GLubyte *)name);
533 
534 #else
535  // Otherwise, we have to fiddle around with the dynamic runtime.
536 
537  if (!_checked_get_proc_address) {
538  const char *funcName = nullptr;
539 
540  if (glx_is_at_least_version(1, 4)) {
541  funcName = "glXGetProcAddress";
542 
543  } else if (has_extension("GLX_ARB_get_proc_address")) {
544  funcName = "glXGetProcAddressARB";
545  }
546 
547  if (funcName != nullptr) {
548  _glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)get_system_func(funcName);
549  if (_glXGetProcAddress == nullptr) {
550  glxdisplay_cat.warning()
551  << "Couldn't load function " << funcName
552  << ", GL extensions may be unavailable.\n";
553  }
554  }
555 
556  _checked_get_proc_address = true;
557  }
558 
559  // Use glxGetProcAddress() if we've got it; it should be more robust.
560  if (_glXGetProcAddress != nullptr) {
561  return (void *)_glXGetProcAddress((const GLubyte *)name);
562  }
563 #endif // HAVE_GLXGETPROCADDRESS
564  }
565 
566  // Otherwise, fall back to the OS-provided calls.
567  return PosixGraphicsStateGuardian::do_get_extension_func(name);
568 }
569 
570 /**
571  * Queries the GLX extension pointers.
572  */
573 void glxGraphicsStateGuardian::
574 query_glx_extensions() {
575  _supports_swap_control = has_extension("GLX_SGI_swap_control");
576 
577  if (_supports_swap_control) {
578  _glXSwapIntervalSGI =
579  (PFNGLXSWAPINTERVALSGIPROC)get_extension_func("glXSwapIntervalSGI");
580  if (_glXSwapIntervalSGI == nullptr) {
581  glxdisplay_cat.error()
582  << "Driver claims to support GLX_SGI_swap_control extension, but does not define all functions.\n";
583  _supports_swap_control = false;
584  }
585  }
586 
587  if (_supports_swap_control) {
588  // Set the video-sync setting up front, if we have the extension that
589  // supports it.
590  _glXSwapIntervalSGI(sync_video ? 1 : 0);
591  }
592 
593  if (glx_support_fbconfig) {
594  if (glx_is_at_least_version(1, 3)) {
595  // If we have glx 1.3 or better, we have the FBConfig interface.
596  _supports_fbconfig = true;
597 
598  _glXChooseFBConfig =
599  (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glXChooseFBConfig");
600  _glXCreateNewContext =
601  (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glXCreateNewContext");
602  _glXGetVisualFromFBConfig =
603  (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glXGetVisualFromFBConfig");
604  _glXGetFBConfigAttrib =
605  (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glXGetFBConfigAttrib");
606  _glXCreatePixmap =
607  (PFNGLXCREATEPIXMAPPROC)get_extension_func("glXCreatePixmap");
608 
609  if (_glXChooseFBConfig == nullptr ||
610  _glXCreateNewContext == nullptr ||
611  _glXGetVisualFromFBConfig == nullptr ||
612  _glXGetFBConfigAttrib == nullptr ||
613  _glXCreatePixmap == nullptr) {
614  glxdisplay_cat.error()
615  << "Driver claims to support GLX_fbconfig extension, but does not define all functions.\n";
616  _supports_fbconfig = false;
617  }
618  } else if (has_extension("GLX_SGIX_fbconfig")) {
619  // Or maybe we have the old SGIX extension for FBConfig. This is the
620  // same, but the function names are different--we just remap them to the
621  // same function pointers.
622  _supports_fbconfig = true;
623 
624  _glXChooseFBConfig =
625  (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glXChooseFBConfigSGIX");
626  _glXCreateNewContext =
627  (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glXCreateContextWithConfigSGIX");
628  _glXGetVisualFromFBConfig =
629  (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glXGetVisualFromFBConfigSGIX");
630  _glXGetFBConfigAttrib =
631  (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glXGetFBConfigAttribSGIX");
632  _glXCreatePixmap =
633  (PFNGLXCREATEPIXMAPPROC)get_extension_func("glXCreateGLXPixmapWithConfigSGIX");
634 
635  if (_glXChooseFBConfig == nullptr ||
636  _glXCreateNewContext == nullptr ||
637  _glXGetVisualFromFBConfig == nullptr ||
638  _glXGetFBConfigAttrib == nullptr ||
639  _glXCreatePixmap == nullptr) {
640  glxdisplay_cat.error()
641  << "Driver claims to support GLX_SGIX_fbconfig extension, but does not define all functions.\n";
642  _supports_fbconfig = false;
643  }
644  }
645 
646  if (glx_is_at_least_version(1, 3)) {
647  // If we have glx 1.3 or better, we have the PBuffer interface.
648  _supports_pbuffer = true;
649  _uses_sgix_pbuffer = false;
650 
651  _glXCreatePbuffer =
652  (PFNGLXCREATEPBUFFERPROC)get_extension_func("glXCreatePbuffer");
653  _glXCreateGLXPbufferSGIX = nullptr;
654  _glXDestroyPbuffer =
655  (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glXDestroyPbuffer");
656  if (_glXCreatePbuffer == nullptr ||
657  _glXDestroyPbuffer == nullptr) {
658  glxdisplay_cat.error()
659  << "Driver claims to support GLX_pbuffer extension, but does not define all functions.\n";
660  _supports_pbuffer = false;
661  }
662 
663  } else if (has_extension("GLX_SGIX_pbuffer")) {
664  // Or maybe we have the old SGIX extension for PBuffers.
665  _uses_sgix_pbuffer = true;
666 
667  // CreatePbuffer has a different form between SGIX and 1.3, however, so
668  // we must treat it specially. But we can use the same function pointer
669  // for DestroyPbuffer.
670  _glXCreatePbuffer = nullptr;
671  _glXCreateGLXPbufferSGIX =
672  (PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func("glXCreateGLXPbufferSGIX");
673  _glXDestroyPbuffer =
674  (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glXDestroyGLXPbufferSGIX");
675  if (_glXCreateGLXPbufferSGIX == nullptr ||
676  _glXDestroyPbuffer == nullptr) {
677  glxdisplay_cat.error()
678  << "Driver claims to support GLX_SGIX_pbuffer extension, but does not define all functions.\n";
679  _supports_pbuffer = false;
680  }
681  }
682 
683  if (has_extension("GLX_ARB_create_context")) {
684  _glXCreateContextAttribs =
685  (PFNGLXCREATECONTEXTATTRIBSARBPROC)get_extension_func("glXCreateContextAttribsARB");
686  } else {
687  _glXCreateContextAttribs = nullptr;
688  }
689  }
690 
691  if (glxdisplay_cat.is_debug()) {
692  glxdisplay_cat.debug()
693  << "supports_swap_control = " << _supports_swap_control << "\n";
694  glxdisplay_cat.debug()
695  << "supports_fbconfig = " << _supports_fbconfig << "\n";
696  glxdisplay_cat.debug()
697  << "supports_pbuffer = " << _supports_pbuffer
698  << " sgix = " << _uses_sgix_pbuffer << "\n";
699  }
700 
701  // If "Mesa" is present, assume software. However, if "Mesa DRI" is found,
702  // it's actually a Mesa-based OpenGL layer running over a hardware driver.
703  if (_gl_renderer.find("Mesa") != string::npos &&
704  _gl_renderer.find("Mesa DRI") == string::npos) {
705  // It's Mesa, therefore probably a software context.
706  _fbprops.set_force_software(1);
707  _fbprops.set_force_hardware(0);
708  } else {
709  _fbprops.set_force_hardware(1);
710  _fbprops.set_force_software(0);
711  }
712 }
713 
714 /**
715  * Outputs the result of glxGetClientString() on the indicated tag.
716  */
717 void glxGraphicsStateGuardian::
718 show_glx_client_string(const string &name, int id) {
719  if (glgsg_cat.is_debug()) {
720  const char *text = glXGetClientString(_display, id);
721  if (text == nullptr) {
722  glgsg_cat.debug()
723  << "Unable to query " << name << " (client)\n";
724  } else {
725  glgsg_cat.debug()
726  << name << " (client) = " << (const char *)text << "\n";
727  }
728  }
729 }
730 
731 /**
732  * Outputs the result of glxQueryServerString() on the indicated tag.
733  */
734 void glxGraphicsStateGuardian::
735 show_glx_server_string(const string &name, int id) {
736  if (glgsg_cat.is_debug()) {
737  const char *text = glXQueryServerString(_display, _screen, id);
738  if (text == nullptr) {
739  glgsg_cat.debug()
740  << "Unable to query " << name << " (server)\n";
741  } else {
742  glgsg_cat.debug()
743  << name << " (server) = " << (const char *)text << "\n";
744  }
745  }
746 }
747 
748 /**
749  * Selects an XVisual for an initial OpenGL context. This may be called
750  * initially, to create the first context needed in order to create the
751  * fbconfig. On successful return, _visual and _temp_context will be filled
752  * in with a non-NULL value.
753  */
754 void glxGraphicsStateGuardian::
755 choose_temp_visual(const FrameBufferProperties &properties) {
756  nassertv(_temp_context == (GLXContext)nullptr);
757 
758  int best_quality = 0;
759  int best_result = 0;
760  FrameBufferProperties best_props;
761 
762  // Scan available visuals.
763  if (_visuals != nullptr) {
764  XFree(_visuals);
765  _visuals = nullptr;
766  }
767  int nvisuals = 0;
768  _visuals = XGetVisualInfo(_display, 0, nullptr, &nvisuals);
769  if (_visuals != nullptr) {
770  for (int i = 0; i < nvisuals; i++) {
771  FrameBufferProperties fbprops;
772  get_properties(fbprops, _visuals + i);
773  int quality = fbprops.get_quality(properties);
774  if (quality > best_quality) {
775  best_quality = quality;
776  best_result = i;
777  best_props = fbprops;
778  }
779  }
780  }
781 
782  if (best_quality > 0) {
783  _visual = _visuals + best_result;
784  _temp_context = glXCreateContext(_display, _visual, None, GL_TRUE);
785  if (_temp_context) {
786  _fbprops = best_props;
787  return;
788  }
789  }
790 
791  glxdisplay_cat.error()
792  << "Could not find a usable pixel format.\n";
793 }
794 
795 /**
796  * Initializes the context created in choose_temp_visual() by creating a
797  * temporary window and binding the context to that window.
798  */
799 void glxGraphicsStateGuardian::
800 init_temp_context() {
801  x11GraphicsPipe *x11_pipe;
802  DCAST_INTO_V(x11_pipe, get_pipe());
803  X11_Window root_window = x11_pipe->get_root();
804 
805  // Assume everyone uses TrueColor or DirectColor these days.
806  Visual *visual = _visual->visual;
807  nassertv(visual->c_class == DirectColor || visual->c_class == TrueColor);
808  _temp_colormap = XCreateColormap(_display, root_window,
809  visual, AllocNone);
810  XSetWindowAttributes wa;
811  wa.colormap = _temp_colormap;
812  unsigned long attrib_mask = CWColormap;
813 
814  _temp_xwindow = XCreateWindow
815  (_display, root_window, 0, 0, 100, 100,
816  0, _visual->depth, InputOutput,
817  visual, attrib_mask, &wa);
818  if (_temp_xwindow == (X11_Window)nullptr) {
819  glxdisplay_cat.error()
820  << "Could not create temporary window for context\n";
821  return;
822  }
823 
824  // Now use it to query the available GLX features.
825  glXMakeCurrent(_display, _temp_xwindow, _temp_context);
826  query_gl_version();
827  get_extra_extensions();
828  query_glx_extensions();
829 }
830 
831 /**
832  * Destroys the temporary unmapped window created by init_temp_context().
833  */
834 void glxGraphicsStateGuardian::
835 destroy_temp_xwindow() {
836  glXMakeCurrent(_display, None, nullptr);
837 
838  if (_temp_colormap != (Colormap)nullptr) {
839  XFreeColormap(_display, _temp_colormap);
840  _temp_colormap = (Colormap)nullptr;
841  }
842  if (_temp_xwindow != (X11_Window)nullptr) {
843  XDestroyWindow(_display, _temp_xwindow);
844  _temp_xwindow = (X11_Window)nullptr;
845  }
846 
847  if (_temp_context != (GLXContext)nullptr) {
848  glXDestroyContext(_display, _temp_context);
849  _temp_context = (GLXContext)nullptr;
850  }
851 }
PosixGraphicsStateGuardian
This GSG is used only for CallbackGraphicsWindow (which might not be using the glx interfaces),...
Definition: posixGraphicsStateGuardian.h:26
FrameBufferProperties
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
Definition: frameBufferProperties.h:26
FrameBufferProperties::set_rgba_bits
void set_rgba_bits(int r, int g, int b, int a)
Convenience method for setting the red, green, blue and alpha bits in one go.
Definition: frameBufferProperties.I:255
config_glxdisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
x11GraphicsPipe::get_root
X11_Window get_root() const
Returns the handle to the root window on the pipe's display.
Definition: x11GraphicsPipe.I:35
FrameBufferProperties::clear
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
Definition: frameBufferProperties.cxx:185
GraphicsEngine
This class is the main interface to controlling the render process.
Definition: graphicsEngine.h:53
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
GraphicsPipe
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
FrameBufferProperties::get_quality
int get_quality(const FrameBufferProperties &reqs) const
Assumes that these properties are a description of a window.
Definition: frameBufferProperties.cxx:438
glxGraphicsStateGuardian::glx_is_at_least_version
bool glx_is_at_least_version(int major_version, int minor_version) const
Returns true if the runtime GLX version number is at least the indicated value, false otherwise.
Definition: glxGraphicsStateGuardian.cxx:437
glxGraphicsStateGuardian::choose_pixel_format
void choose_pixel_format(const FrameBufferProperties &properties, X11_Display *_display, int _screen, bool need_pbuffer, bool need_pixmap)
Selects a visual or fbconfig for all the windows and buffers that use this gsg.
Definition: glxGraphicsStateGuardian.cxx:226
glxGraphicsStateGuardian::get_properties
void get_properties(FrameBufferProperties &properties, XVisualInfo *visual)
Gets the FrameBufferProperties to match the indicated visual.
Definition: glxGraphicsStateGuardian.cxx:84
x11GraphicsPipe
This graphics pipe represents the interface for creating graphics windows on an X-based client.
Definition: x11GraphicsPipe.h:96
config_glgsg.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glxGraphicsStateGuardian::get_properties_advanced
void get_properties_advanced(FrameBufferProperties &properties, bool &context_has_pbuffer, bool &pixmap_supported, bool &slow, GLXFBConfig config)
Gets the FrameBufferProperties to match the indicated GLXFBConfig.
Definition: glxGraphicsStateGuardian.cxx:141
glxGraphicsStateGuardian
A tiny specialization on GLGraphicsStateGuardian to add some glx-specific information.
Definition: glxGraphicsStateGuardian.h:74
lightReMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glxGraphicsStateGuardian.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.