24 TypeHandle glxGraphicsStateGuardian::_type_handle;
29 glxGraphicsStateGuardian::
34 _share_context=
nullptr;
41 _context_has_pbuffer =
false;
42 _context_has_pixmap =
false;
45 _supports_swap_control =
false;
46 _supports_fbconfig =
false;
47 _supports_pbuffer =
false;
48 _uses_sgix_pbuffer =
false;
50 if (share_with !=
nullptr) {
51 _prepared_objects = share_with->get_prepared_objects();
52 _share_context = share_with->_context;
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;
65 glxGraphicsStateGuardian::
66 ~glxGraphicsStateGuardian() {
70 destroy_temp_xwindow();
71 if (_visuals !=
nullptr) {
74 if (_context != (GLXContext)
nullptr) {
75 glXDestroyContext(_display, _context);
76 _context = (GLXContext)
nullptr;
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;
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);
116 properties.set_back_buffers(1);
119 properties.set_stereo(1);
122 properties.set_rgb_color(1);
124 properties.set_indexed_color(1);
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);
133 properties.set_force_software(1);
134 properties.set_force_hardware(1);
142 bool &context_has_pbuffer,
bool &context_has_pixmap,
143 bool &slow, GLXFBConfig config) {
146 if (_supports_fbconfig) {
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;
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);
170 context_has_pbuffer =
false;
171 if ((drawable_type & GLX_PBUFFER_BIT)!=0) {
172 context_has_pbuffer =
true;
175 context_has_pixmap =
false;
176 if ((drawable_type & GLX_PIXMAP_BIT)!=0) {
177 context_has_pixmap =
true;
181 if (caveat == GLX_SLOW_CONFIG) {
185 if ((drawable_type & GLX_WINDOW_BIT)==0) {
191 properties.set_back_buffers(1);
195 properties.set_stereo(
true);
199 properties.set_srgb_color(
true);
202 if ((render_type & GLX_RGBA_BIT)!=0) {
203 properties.set_rgb_color(
true);
205 if ((render_type & GLX_COLOR_INDEX_BIT)!=0) {
206 properties.set_indexed_color(
true);
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);
216 properties.set_force_software(1);
217 properties.set_force_hardware(1);
227 X11_Display *display,
228 int screen,
bool need_pbuffer,
bool need_pixmap) {
236 if (_visuals !=
nullptr) {
246 destroy_temp_xwindow();
247 choose_temp_visual(properties);
248 if (_temp_context ==
nullptr) {
258 if (!_supports_fbconfig) {
261 glxdisplay_cat.debug()
262 <<
" No FBConfig supported; using XVisual only.\n"
265 _context = _temp_context;
266 _temp_context = (GLXContext)
nullptr;
270 _context_has_pixmap = !glXIsDirect(_display, _context);
273 _context_has_pbuffer =
false;
282 int best_quality = 0;
286 int render_type = GLX_RGBA_TYPE;
287 if (properties.get_indexed_color()) {
288 render_type = GLX_COLOR_INDEX_TYPE;
291 static const int max_attrib_list = 32;
292 int attrib_list[max_attrib_list];
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;
303 GLXFBConfig *configs =
304 _glXChooseFBConfig(_display, _screen, attrib_list, &num_configs);
306 if (configs !=
nullptr) {
307 bool context_has_pbuffer, context_has_pixmap, slow;
309 for (i = 0; i < num_configs; ++i) {
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";
323 if (need_pbuffer && !context_has_pbuffer) {
326 if (need_pixmap && !context_has_pixmap) {
330 if (quality > best_quality) {
331 best_quality = quality;
333 best_props = fbprops;
338 if (best_quality > 0) {
339 _fbconfig = configs[best_result];
341 if (_glXCreateContextAttribs !=
nullptr) {
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];
357 flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
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";
367 attrib_list[n++] = GLX_CONTEXT_FLAGS_ARB;
368 attrib_list[n++] = flags;
370 attrib_list[n] = None;
371 _context = _glXCreateContextAttribs(_display, _fbconfig, _share_context,
372 GL_TRUE, attrib_list);
375 _glXCreateNewContext(_display, _fbconfig, render_type, _share_context,
382 if (_visuals !=
nullptr) {
386 _visuals = _glXGetVisualFromFBConfig(_display, _fbconfig);
393 if (!properties.get_srgb_color()) {
394 _fbprops.set_srgb_color(
false);
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";
409 glxdisplay_cat.error()
410 <<
"Could not create FBConfig context!\n";
417 glxdisplay_cat.warning()
418 <<
"No suitable FBConfig contexts available; using XVisual only.\n"
421 _context = _temp_context;
422 _temp_context = (GLXContext)
nullptr;
426 _context_has_pixmap = !glXIsDirect(_display, _context);
429 _context_has_pbuffer =
false;
438 if (_glx_version_major < major_version) {
441 if (_glx_version_major > major_version) {
444 if (_glx_version_minor < minor_version) {
453 void glxGraphicsStateGuardian::
457 PosixGraphicsStateGuardian::gl_flush();
463 GLenum glxGraphicsStateGuardian::
464 gl_get_error()
const {
467 return PosixGraphicsStateGuardian::gl_get_error();
473 void glxGraphicsStateGuardian::
476 PosixGraphicsStateGuardian::query_gl_version();
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);
483 glXQueryVersion(_display, &_glx_version_major, &_glx_version_minor);
488 if (glgsg_cat.is_debug()) {
490 <<
"GLX_VERSION = " << _glx_version_major <<
"." << _glx_version_minor
500 void glxGraphicsStateGuardian::
501 get_extra_extensions() {
503 save_extensions(glXQueryExtensionsString(_display, _screen));
512 void *glxGraphicsStateGuardian::
513 do_get_extension_func(
const char *name) {
514 nassertr(name !=
nullptr,
nullptr);
516 if (glx_get_proc_address) {
522 #if defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESS)
527 return (
void *)glXGetProcAddress((
const GLubyte *)name);
529 #elif defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESSARB)
532 return (
void *)glXGetProcAddressARB((
const GLubyte *)name);
537 if (!_checked_get_proc_address) {
538 const char *funcName =
nullptr;
541 funcName =
"glXGetProcAddress";
543 }
else if (has_extension(
"GLX_ARB_get_proc_address")) {
544 funcName =
"glXGetProcAddressARB";
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";
556 _checked_get_proc_address =
true;
560 if (_glXGetProcAddress !=
nullptr) {
561 return (
void *)_glXGetProcAddress((
const GLubyte *)name);
563 #endif // HAVE_GLXGETPROCADDRESS
567 return PosixGraphicsStateGuardian::do_get_extension_func(name);
573 void glxGraphicsStateGuardian::
574 query_glx_extensions() {
575 _supports_swap_control = has_extension(
"GLX_SGI_swap_control");
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;
587 if (_supports_swap_control) {
590 _glXSwapIntervalSGI(sync_video ? 1 : 0);
593 if (glx_support_fbconfig) {
596 _supports_fbconfig =
true;
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");
607 (PFNGLXCREATEPIXMAPPROC)get_extension_func(
"glXCreatePixmap");
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;
618 }
else if (has_extension(
"GLX_SGIX_fbconfig")) {
622 _supports_fbconfig =
true;
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");
633 (PFNGLXCREATEPIXMAPPROC)get_extension_func(
"glXCreateGLXPixmapWithConfigSGIX");
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;
648 _supports_pbuffer =
true;
649 _uses_sgix_pbuffer =
false;
652 (PFNGLXCREATEPBUFFERPROC)get_extension_func(
"glXCreatePbuffer");
653 _glXCreateGLXPbufferSGIX =
nullptr;
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;
663 }
else if (has_extension(
"GLX_SGIX_pbuffer")) {
665 _uses_sgix_pbuffer =
true;
670 _glXCreatePbuffer =
nullptr;
671 _glXCreateGLXPbufferSGIX =
672 (PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func(
"glXCreateGLXPbufferSGIX");
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;
683 if (has_extension(
"GLX_ARB_create_context")) {
684 _glXCreateContextAttribs =
685 (PFNGLXCREATECONTEXTATTRIBSARBPROC)get_extension_func(
"glXCreateContextAttribsARB");
687 _glXCreateContextAttribs =
nullptr;
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";
703 if (_gl_renderer.find(
"Mesa") != string::npos &&
704 _gl_renderer.find(
"Mesa DRI") == string::npos) {
706 _fbprops.set_force_software(1);
707 _fbprops.set_force_hardware(0);
709 _fbprops.set_force_hardware(1);
710 _fbprops.set_force_software(0);
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) {
723 <<
"Unable to query " << name <<
" (client)\n";
726 << name <<
" (client) = " << (
const char *)text <<
"\n";
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) {
740 <<
"Unable to query " << name <<
" (server)\n";
743 << name <<
" (server) = " << (
const char *)text <<
"\n";
754 void glxGraphicsStateGuardian::
756 nassertv(_temp_context == (GLXContext)
nullptr);
758 int best_quality = 0;
763 if (_visuals !=
nullptr) {
768 _visuals = XGetVisualInfo(_display, 0,
nullptr, &nvisuals);
769 if (_visuals !=
nullptr) {
770 for (
int i = 0; i < nvisuals; i++) {
774 if (quality > best_quality) {
775 best_quality = quality;
777 best_props = fbprops;
782 if (best_quality > 0) {
783 _visual = _visuals + best_result;
784 _temp_context = glXCreateContext(_display, _visual, None, GL_TRUE);
786 _fbprops = best_props;
791 glxdisplay_cat.error()
792 <<
"Could not find a usable pixel format.\n";
799 void glxGraphicsStateGuardian::
800 init_temp_context() {
802 DCAST_INTO_V(x11_pipe, get_pipe());
803 X11_Window root_window = x11_pipe->
get_root();
806 Visual *visual = _visual->visual;
807 nassertv(visual->c_class == DirectColor || visual->c_class == TrueColor);
808 _temp_colormap = XCreateColormap(_display, root_window,
810 XSetWindowAttributes wa;
811 wa.colormap = _temp_colormap;
812 unsigned long attrib_mask = CWColormap;
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";
825 glXMakeCurrent(_display, _temp_xwindow, _temp_context);
827 get_extra_extensions();
828 query_glx_extensions();
834 void glxGraphicsStateGuardian::
835 destroy_temp_xwindow() {
836 glXMakeCurrent(_display, None,
nullptr);
838 if (_temp_colormap != (Colormap)
nullptr) {
839 XFreeColormap(_display, _temp_colormap);
840 _temp_colormap = (Colormap)
nullptr;
842 if (_temp_xwindow != (X11_Window)
nullptr) {
843 XDestroyWindow(_display, _temp_xwindow);
844 _temp_xwindow = (X11_Window)
nullptr;
847 if (_temp_context != (GLXContext)
nullptr) {
848 glXDestroyContext(_display, _temp_context);
849 _temp_context = (GLXContext)
nullptr;