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