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
14 #include "glxGraphicsStateGuardian.h"
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 */
83 void glxGraphicsStateGuardian::
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 */
140 void glxGraphicsStateGuardian::
141 get_properties_advanced(FrameBufferProperties &properties,
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 */
225 void glxGraphicsStateGuardian::
226 choose_pixel_format(const FrameBufferProperties &properties,
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 */
436 bool glxGraphicsStateGuardian::
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 }
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
FrameBufferProperties::clear
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
Definition: frameBufferProperties.cxx:185
FrameBufferProperties::get_quality
int get_quality(const FrameBufferProperties &reqs) const
Assumes that these properties are a description of a window.
Definition: frameBufferProperties.cxx:438
GraphicsEngine
This class is the main interface to controlling the render process.
Definition: graphicsEngine.h:53
GraphicsPipe
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
PosixGraphicsStateGuardian
This GSG is used only for CallbackGraphicsWindow (which might not be using the glx interfaces),...
Definition: posixGraphicsStateGuardian.h:26
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
glxGraphicsStateGuardian
A tiny specialization on GLGraphicsStateGuardian to add some glx-specific information.
Definition: glxGraphicsStateGuardian.h:74
glxGraphicsStateGuardian::get_properties
void get_properties(FrameBufferProperties &properties, XVisualInfo *visual)
Gets the FrameBufferProperties to match the indicated visual.
Definition: glxGraphicsStateGuardian.cxx:84
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::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
x11GraphicsPipe
This graphics pipe represents the interface for creating graphics windows on an X-based client.
Definition: x11GraphicsPipe.h:96
x11GraphicsPipe::get_root
X11_Window get_root() const
Returns the handle to the root window on the pipe's display.
Definition: x11GraphicsPipe.I:35
config_glgsg.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_glxdisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glxGraphicsStateGuardian.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
lightReMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.