diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 129d910eae..7af3fb5c5b 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -408,8 +408,8 @@ make_output(GraphicsPipe *pipe, << " got: " << window->get_fb_properties() << "\n"; } } else { - display_cat.error() - << "Window wouldn't open; abandoning window.\n"; + display_cat.info() + << window->get_type() << " wouldn't open; abandoning.\n"; } // No good; delete the window and keep trying. diff --git a/panda/src/glxdisplay/Sources.pp b/panda/src/glxdisplay/Sources.pp index dd9359fe48..8a606e8861 100644 --- a/panda/src/glxdisplay/Sources.pp +++ b/panda/src/glxdisplay/Sources.pp @@ -20,7 +20,7 @@ glxGraphicsWindow.h glxGraphicsWindow.cxx \ glxGraphicsStateGuardian.h glxGraphicsStateGuardian.I \ glxGraphicsStateGuardian.cxx \ - glxext.h + panda_glxext.h #define INSTALL_HEADERS \ glxGraphicsBuffer.I glxGraphicsBuffer.h \ diff --git a/panda/src/glxdisplay/config_glxdisplay.cxx b/panda/src/glxdisplay/config_glxdisplay.cxx index ffc44a5889..fc99763ab4 100644 --- a/panda/src/glxdisplay/config_glxdisplay.cxx +++ b/panda/src/glxdisplay/config_glxdisplay.cxx @@ -16,6 +16,7 @@ #include "glxGraphicsBuffer.h" #include "glxGraphicsPipe.h" #include "glxGraphicsPixmap.h" +#include "glxGraphicsBuffer.h" #include "glxGraphicsWindow.h" #include "glxGraphicsStateGuardian.h" #include "graphicsPipeSelection.h" @@ -43,6 +44,19 @@ ConfigVariableBool glx_get_os_address "addresses of extension functions. This will be done only " "if glxGetProcAddress() cannot be used for some reason.")); +ConfigVariableBool gl_support_fbo +("gl-support-fbo", true, + PRC_DESC("Configure this false if your GL's implementation of " + "EXT_framebuffer_object is broken. The system might still be " + "able to create buffers using pbuffers or the like.")); + +ConfigVariableBool glx_support_fbconfig +("glx-support-fbconfig", true, + PRC_DESC("Set this true to enable the use of the advanced FBConfig " + "interface (as opposed to the older XVisual interface) " + "if it is available, to select a graphics visual and " + "create an OpenGL context.")); + ConfigVariableBool glx_support_pbuffer ("glx-support-pbuffer", true, PRC_DESC("Set this true to enable the use of X pbuffer-based offscreen " @@ -53,9 +67,7 @@ ConfigVariableBool glx_support_pixmap ("glx-support-pixmap", false, PRC_DESC("Set this true to enable the use of X pixmap-based offscreen " "buffers. This is false by default because pixmap-based buffers " - "are usually slower than pbuffer-based buffers, and because at " - "least one driver is known to crash (crash!) when it attempts " - "to create a pixmap-based buffer.")); + "are usually slower than pbuffer-based buffers.")); //////////////////////////////////////////////////////////////////// @@ -79,6 +91,7 @@ init_libglxdisplay() { #endif // HAVE_GLXFBCONFIG glxGraphicsPipe::init_type(); glxGraphicsPixmap::init_type(); + glxGraphicsBuffer::init_type(); glxGraphicsWindow::init_type(); glxGraphicsStateGuardian::init_type(); diff --git a/panda/src/glxdisplay/config_glxdisplay.h b/panda/src/glxdisplay/config_glxdisplay.h index 7bd64e31b0..7f55210381 100644 --- a/panda/src/glxdisplay/config_glxdisplay.h +++ b/panda/src/glxdisplay/config_glxdisplay.h @@ -28,6 +28,8 @@ extern EXPCL_PANDAGL void init_libglxdisplay(); extern ConfigVariableBool glx_get_proc_address; extern ConfigVariableBool glx_get_os_address; +extern ConfigVariableBool gl_support_fbo; +extern ConfigVariableBool glx_support_fbconfig; extern ConfigVariableBool glx_support_pbuffer; extern ConfigVariableBool glx_support_pixmap; diff --git a/panda/src/glxdisplay/glxGraphicsBuffer.cxx b/panda/src/glxdisplay/glxGraphicsBuffer.cxx index 62f72d015e..fb7ae5de2e 100644 --- a/panda/src/glxdisplay/glxGraphicsBuffer.cxx +++ b/panda/src/glxdisplay/glxGraphicsBuffer.cxx @@ -21,10 +21,6 @@ #include "glgsg.h" #include "pStatTimer.h" -#ifdef HAVE_GLXFBCONFIG -// This whole class doesn't make sense unless we have the GLXFBConfig -// and associated GLXPbuffer interfaces available. - TypeHandle glxGraphicsBuffer::_type_handle; //////////////////////////////////////////////////////////////////// @@ -76,7 +72,8 @@ begin_frame(FrameMode mode, Thread *current_thread) { PStatTimer timer(_make_current_pcollector, current_thread); begin_frame_spam(mode); - if (_gsg == (GraphicsStateGuardian *)NULL) { + if (_gsg == (GraphicsStateGuardian *)NULL || + _pbuffer == None) { return false; } @@ -140,15 +137,19 @@ void glxGraphicsBuffer:: close_buffer() { if (_gsg != (GraphicsStateGuardian *)NULL) { glXMakeCurrent(_display, None, NULL); + + if (_pbuffer != None) { + glxGraphicsStateGuardian *glxgsg; + DCAST_INTO_V(glxgsg, _gsg); + glxgsg->_glXDestroyPbuffer(_display, _pbuffer); + _pbuffer = None; + } + _gsg.clear(); _active = false; } - if (_pbuffer != None) { - glXDestroyPbuffer(_display, _pbuffer); - _pbuffer = None; - } - + _pbuffer = None; _is_valid = false; } @@ -175,43 +176,47 @@ open_buffer() { // If the old gsg has the wrong pixel format, create a // new one that shares with the old gsg. DCAST_INTO_R(glxgsg, _gsg, false); - if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) { + + if (!glxgsg->_context_has_pbuffer || + !glxgsg->get_fb_properties().subsumes(_fb_properties)) { + // We need a new pixel format, and hence a new GSG. glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg); glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true, false); _gsg = glxgsg; } } - if (glxgsg->_fbconfig == None) { - // If we didn't use an fbconfig to create the GSG, we can't create - // a PBuffer. + if (glxgsg->_fbconfig == None || glxgsg->_context_has_pbuffer) { + // If we didn't use an fbconfig to create the GSG, or it doesn't + // support buffers, we can't create a PBuffer. return false; } + nassertr(glxgsg->_supports_pbuffer, false); + static const int max_attrib_list = 32; int attrib_list[max_attrib_list]; - int n=0; + int n = 0; -#ifdef HAVE_OFFICIAL_GLXFBCONFIG - // The official GLX 1.3 version passes in the size in the attrib - // list. - attrib_list[n++] = GLX_PBUFFER_WIDTH; - attrib_list[n++] = _x_size; - attrib_list[n++] = GLX_PBUFFER_HEIGHT; - attrib_list[n++] = _y_size; - - nassertr(n < max_attrib_list, false); - attrib_list[n] = (int)None; - _pbuffer = glXCreatePbuffer(glxgsg->_display, glxgsg->_fbconfig, - attrib_list); - -#else - // The SGI version passed in the size in the parameter list. - nassertr(n < max_attrib_list, false); - attrib_list[n] = (int)None; - _pbuffer = glXCreateGLXPbufferSGIX(glxgsg->_display, glxgsg->_fbconfig, - _x_size, _y_size, attrib_list); -#endif + if (glxgsg->_uses_sgix_pbuffer) { + // The SGI version passed in the size in the parameter list. + nassertr(n < max_attrib_list, false); + attrib_list[n] = (int)None; + _pbuffer = glxgsg->_glXCreateGLXPbufferSGIX(glxgsg->_display, glxgsg->_fbconfig, + _x_size, _y_size, attrib_list); + } else { + // The official GLX 1.3 version passes in the size in the attrib + // list. + attrib_list[n++] = GLX_PBUFFER_WIDTH; + attrib_list[n++] = _x_size; + attrib_list[n++] = GLX_PBUFFER_HEIGHT; + attrib_list[n++] = _y_size; + + nassertr(n < max_attrib_list, false); + attrib_list[n] = (int)None; + _pbuffer = glxgsg->_glXCreatePbuffer(glxgsg->_display, glxgsg->_fbconfig, + attrib_list); + } if (_pbuffer == None) { glxdisplay_cat.error() @@ -235,6 +240,3 @@ open_buffer() { _is_valid = true; return true; } - - -#endif // HAVE_GLXFBCONFIG diff --git a/panda/src/glxdisplay/glxGraphicsBuffer.h b/panda/src/glxdisplay/glxGraphicsBuffer.h index a5545e4f5d..6e17626325 100644 --- a/panda/src/glxdisplay/glxGraphicsBuffer.h +++ b/panda/src/glxdisplay/glxGraphicsBuffer.h @@ -20,10 +20,6 @@ #include "glxGraphicsPipe.h" #include "graphicsBuffer.h" -#ifdef HAVE_GLXFBCONFIG -// This whole class doesn't make sense unless we have the GLXFBConfig -// and associated GLXPbuffer interfaces available. - //////////////////////////////////////////////////////////////////// // Class : glxGraphicsBuffer // Description : An offscreen buffer in the GLX environment. This @@ -71,6 +67,4 @@ private: #include "glxGraphicsBuffer.I" -#endif // HAVE_GLXFBCONFIG - #endif diff --git a/panda/src/glxdisplay/glxGraphicsPipe.cxx b/panda/src/glxdisplay/glxGraphicsPipe.cxx index 9b4ab9351d..a5a290113c 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.cxx +++ b/panda/src/glxdisplay/glxGraphicsPipe.cxx @@ -119,7 +119,7 @@ make_output(const string &name, if (retry == 1) { if ((host==0)|| - // (!gl_support_fbo)|| + (!gl_support_fbo)|| ((flags&BF_require_parasite)!=0)|| ((flags&BF_require_window)!=0)) { return NULL; @@ -152,34 +152,33 @@ make_output(const string &name, flags, gsg, host); } -#ifdef HAVE_GLXFBCONFIG // Third thing to try: a glxGraphicsBuffer - - if (retry == 2) { - if (!glx_support_pbuffer) { - return NULL; - } - - if (((flags&BF_require_parasite)!=0)|| - ((flags&BF_require_window)!=0)|| - ((flags&BF_resizeable)!=0)|| - ((flags&BF_size_track_host)!=0)) { - return NULL; - } - - if (!support_rtt) { - if (((flags&BF_rtt_cumulative)!=0)|| - ((flags&BF_can_bind_every)!=0)) { - // If we require Render-to-Texture, but can't be sure we - // support it, bail. + if (glxgsg == NULL || glxgsg->_supports_fbconfig) { + if (retry == 2) { + if (!glx_support_pbuffer) { return NULL; } + + if (((flags&BF_require_parasite)!=0)|| + ((flags&BF_require_window)!=0)|| + ((flags&BF_resizeable)!=0)|| + ((flags&BF_size_track_host)!=0)) { + return NULL; + } + + if (!support_rtt) { + if (((flags&BF_rtt_cumulative)!=0)|| + ((flags&BF_can_bind_every)!=0)) { + // If we require Render-to-Texture, but can't be sure we + // support it, bail. + return NULL; + } + } + + return new glxGraphicsBuffer(engine, this, name, fb_prop, win_prop, + flags, gsg, host); } - - return new glxGraphicsBuffer(engine, this, name, fb_prop, win_prop, - flags, gsg, host); } -#endif // HAVE_GLXFBCONFIG // Third thing to try: a glxGraphicsPixmap. if (retry == 3) { diff --git a/panda/src/glxdisplay/glxGraphicsPipe.h b/panda/src/glxdisplay/glxGraphicsPipe.h index 6b49be04fa..c571da7422 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.h +++ b/panda/src/glxdisplay/glxGraphicsPipe.h @@ -27,20 +27,25 @@ class FrameBufferProperties; #ifndef CPPPARSER +// Don't pick up the system glxext.h; use our own, which is better. +#define __glxext_h_ + #include +/* #if defined(GLX_VERSION_1_3) // If the system glx version is at least 1.3, then we know we have // GLXFBConfig and GLXPbuffer. #define HAVE_GLXFBCONFIG #define HAVE_OFFICIAL_GLXFBCONFIG #endif +*/ // This must be included after we have included glgsg.h (which // includes gl.h), and after we have checked GLX_VERSION_1_3. But we // must also include it before we redefine the GLXFBConfig types, // below. -#include "glxext.h" +#include "panda_glxext.h" // drose: the version of GL/glx.h that ships with Fedora Core 2 seems // to define GLX_VERSION_1_4, but for some reason does not define @@ -54,6 +59,7 @@ class FrameBufferProperties; #endif +/* #if !defined(HAVE_GLXFBCONFIG) && defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) // If the system glx version isn't 1.3, but these were defined as // extensions, we can work with that. @@ -68,6 +74,7 @@ class FrameBufferProperties; #define HAVE_GLXFBCONFIG #define HAVE_SGI_GLXFBCONFIG #endif +*/ #endif // CPPPARSER diff --git a/panda/src/glxdisplay/glxGraphicsPixmap.cxx b/panda/src/glxdisplay/glxGraphicsPixmap.cxx index b5be854c3e..38a286f1c7 100644 --- a/panda/src/glxdisplay/glxGraphicsPixmap.cxx +++ b/panda/src/glxdisplay/glxGraphicsPixmap.cxx @@ -75,7 +75,8 @@ begin_frame(FrameMode mode, Thread *current_thread) { PStatTimer timer(_make_current_pcollector, current_thread); begin_frame_spam(mode); - if (_gsg == (GraphicsStateGuardian *)NULL) { + if (_gsg == (GraphicsStateGuardian *)NULL || + _glx_pixmap == None) { return false; } @@ -179,13 +180,19 @@ open_buffer() { // If the old gsg has the wrong pixel format, create a // new one that shares with the old gsg. DCAST_INTO_R(glxgsg, _gsg, false); - if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) { + if (!glxgsg->_context_has_pixmap || + !glxgsg->get_fb_properties().subsumes(_fb_properties)) { glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg); glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true); _gsg = glxgsg; } } + if (!glxgsg->_context_has_pixmap) { + // Hmm, the GSG we created won't work. + return false; + } + XVisualInfo *visual_info = glxgsg->_visual; if (visual_info == NULL) { // No X visual for this fbconfig; how can we create the pixmap? @@ -214,16 +221,13 @@ open_buffer() { return false; } -#ifdef HAVE_GLXFBCONFIG if (glxgsg->_fbconfig) { // Use the FBConfig to create the pixmap. - _glx_pixmap = glXCreatePixmap(_display, glxgsg->_fbconfig, _x_pixmap, NULL); - } else -#endif // HAVE_GLXFBCONFIG - { - // Use the XVisual to create the pixmap. - _glx_pixmap = glXCreateGLXPixmap(_display, visual_info, _x_pixmap); - } + _glx_pixmap = glxgsg->_glXCreatePixmap(_display, glxgsg->_fbconfig, _x_pixmap, NULL); + } else { + // Use the XVisual to create the pixmap. + _glx_pixmap = glXCreateGLXPixmap(_display, visual_info, _x_pixmap); + } if (_glx_pixmap == None) { glxdisplay_cat.error() diff --git a/panda/src/glxdisplay/glxGraphicsStateGuardian.cxx b/panda/src/glxdisplay/glxGraphicsStateGuardian.cxx index 16f74f7b63..388593de4f 100644 --- a/panda/src/glxdisplay/glxGraphicsStateGuardian.cxx +++ b/panda/src/glxdisplay/glxGraphicsStateGuardian.cxx @@ -39,6 +39,14 @@ glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe, _visual=0; _visuals=0; _fbconfig=0; + _context_has_pbuffer = false; + _context_has_pixmap = false; + _slow = false; + + _supports_swap_control = false; + _supports_fbconfig = false; + _supports_pbuffer = false; + _uses_sgix_pbuffer = false; if (share_with != (glxGraphicsStateGuardian *)NULL) { _prepared_objects = share_with->get_prepared_objects(); @@ -48,6 +56,7 @@ glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe, _libgl_handle = NULL; _checked_get_proc_address = false; _glXGetProcAddress = NULL; + _temp_xwindow = (Window)NULL; } //////////////////////////////////////////////////////////////////// @@ -57,6 +66,7 @@ glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe, //////////////////////////////////////////////////////////////////// glxGraphicsStateGuardian:: ~glxGraphicsStateGuardian() { + destroy_temp_xwindow(); if (_visuals != (XVisualInfo *)NULL) { XFree(_visuals); } @@ -71,7 +81,7 @@ glxGraphicsStateGuardian:: //////////////////////////////////////////////////////////////////// // Function: glxGraphicsStateGuardian::get_properties -// Access: Private +// Access: Public // Description: Gets the FrameBufferProperties to match the // indicated visual. //////////////////////////////////////////////////////////////////// @@ -131,87 +141,86 @@ get_properties(FrameBufferProperties &properties, XVisualInfo *visual) { //////////////////////////////////////////////////////////////////// // Function: glxGraphicsStateGuardian::get_properties_advanced -// Access: Private +// Access: Public // Description: Gets the FrameBufferProperties to match the // indicated GLXFBConfig //////////////////////////////////////////////////////////////////// void glxGraphicsStateGuardian:: get_properties_advanced(FrameBufferProperties &properties, - bool &pbuffer_supported, bool &pixmap_supported, - bool &slow, fbconfig config) { - + bool &context_has_pbuffer, bool &context_has_pixmap, + bool &slow, GLXFBConfig config) { properties.clear(); -#ifdef HAVE_GLXFBCONFIG - // Now update our framebuffer_mode and bit depth appropriately. - int render_mode, double_buffer, stereo, red_size, green_size, blue_size, - alpha_size, ared_size, agreen_size, ablue_size, aalpha_size, - depth_size, stencil_size, samples, drawable_type, caveat; - - glXGetFBConfigAttrib(_display, config, GLX_RGBA, &render_mode); - glXGetFBConfigAttrib(_display, config, GLX_DOUBLEBUFFER, &double_buffer); - glXGetFBConfigAttrib(_display, config, GLX_STEREO, &stereo); - glXGetFBConfigAttrib(_display, config, GLX_RED_SIZE, &red_size); - glXGetFBConfigAttrib(_display, config, GLX_GREEN_SIZE, &green_size); - glXGetFBConfigAttrib(_display, config, GLX_BLUE_SIZE, &blue_size); - glXGetFBConfigAttrib(_display, config, GLX_ALPHA_SIZE, &alpha_size); - glXGetFBConfigAttrib(_display, config, GLX_ACCUM_RED_SIZE, &ared_size); - glXGetFBConfigAttrib(_display, config, GLX_ACCUM_GREEN_SIZE, &agreen_size); - glXGetFBConfigAttrib(_display, config, GLX_ACCUM_BLUE_SIZE, &ablue_size); - glXGetFBConfigAttrib(_display, config, GLX_ACCUM_ALPHA_SIZE, &aalpha_size); - glXGetFBConfigAttrib(_display, config, GLX_DEPTH_SIZE, &depth_size); - glXGetFBConfigAttrib(_display, config, GLX_STENCIL_SIZE, &stencil_size); - glXGetFBConfigAttrib(_display, config, GLX_SAMPLES, &samples); - glXGetFBConfigAttrib(_display, config, GLX_DRAWABLE_TYPE, &drawable_type); - glXGetFBConfigAttrib(_display, config, GLX_CONFIG_CAVEAT, &caveat); - - pbuffer_supported = false; - if ((drawable_type & GLX_PBUFFER_BIT)!=0) { - pbuffer_supported = true; + if (_supports_fbconfig) { + // Now update our framebuffer_mode and bit depth appropriately. + int render_mode, double_buffer, stereo, red_size, green_size, blue_size, + alpha_size, ared_size, agreen_size, ablue_size, aalpha_size, + depth_size, stencil_size, samples, drawable_type, caveat; + + _glXGetFBConfigAttrib(_display, config, GLX_RGBA, &render_mode); + _glXGetFBConfigAttrib(_display, config, GLX_DOUBLEBUFFER, &double_buffer); + _glXGetFBConfigAttrib(_display, config, GLX_STEREO, &stereo); + _glXGetFBConfigAttrib(_display, config, GLX_RED_SIZE, &red_size); + _glXGetFBConfigAttrib(_display, config, GLX_GREEN_SIZE, &green_size); + _glXGetFBConfigAttrib(_display, config, GLX_BLUE_SIZE, &blue_size); + _glXGetFBConfigAttrib(_display, config, GLX_ALPHA_SIZE, &alpha_size); + _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_RED_SIZE, &ared_size); + _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_GREEN_SIZE, &agreen_size); + _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_BLUE_SIZE, &ablue_size); + _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_ALPHA_SIZE, &aalpha_size); + _glXGetFBConfigAttrib(_display, config, GLX_DEPTH_SIZE, &depth_size); + _glXGetFBConfigAttrib(_display, config, GLX_STENCIL_SIZE, &stencil_size); + _glXGetFBConfigAttrib(_display, config, GLX_SAMPLES, &samples); + _glXGetFBConfigAttrib(_display, config, GLX_DRAWABLE_TYPE, &drawable_type); + _glXGetFBConfigAttrib(_display, config, GLX_CONFIG_CAVEAT, &caveat); + + context_has_pbuffer = false; + if ((drawable_type & GLX_PBUFFER_BIT)!=0) { + context_has_pbuffer = true; + } + + context_has_pixmap = false; + if ((drawable_type & GLX_PIXMAP_BIT)!=0) { + context_has_pixmap = true; + } + + slow = false; + if (caveat == GLX_SLOW_CONFIG) { + slow = true; + } + + if ((drawable_type & GLX_WINDOW_BIT)==0) { + // We insist on having a context that will support an onscreen window. + return; + } + + if (double_buffer) { + properties.set_back_buffers(1); + } + if (stereo) { + properties.set_stereo(1); + } + if (render_mode) { + properties.set_rgb_color(1); + } else { + properties.set_indexed_color(1); + } + properties.set_color_bits(red_size+green_size+blue_size); + properties.set_stencil_bits(stencil_size); + properties.set_depth_bits(depth_size); + properties.set_alpha_bits(alpha_size); + properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size); + properties.set_multisamples(samples); + + // Set both hardware and software bits, indicating not-yet-known. + properties.set_force_software(1); + properties.set_force_hardware(1); } - - pixmap_supported = false; - if ((drawable_type & GLX_PIXMAP_BIT)!=0) { - pixmap_supported = true; - } - - slow = false; - if (caveat == GLX_SLOW_CONFIG) { - slow = true; - } - - if ((drawable_type & GLX_WINDOW_BIT)==0) { - // We insist on having a context that will support an onscreen window. - return; - } - - if (double_buffer) { - properties.set_back_buffers(1); - } - if (stereo) { - properties.set_stereo(1); - } - if (render_mode) { - properties.set_rgb_color(1); - } else { - properties.set_indexed_color(1); - } - properties.set_color_bits(red_size+green_size+blue_size); - properties.set_stencil_bits(stencil_size); - properties.set_depth_bits(depth_size); - properties.set_alpha_bits(alpha_size); - properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size); - properties.set_multisamples(samples); - - // Set both hardware and software bits, indicating not-yet-known. - properties.set_force_software(1); - properties.set_force_hardware(1); -#endif // HAVE_GLXFBCONFIG } //////////////////////////////////////////////////////////////////// // Function: glxGraphicsStateGuardian::choose_pixel_format -// Access: Private +// Access: Public // Description: Selects a visual or fbconfig for all the windows // and buffers that use this gsg. Also creates the GL // context and obtains the visual. @@ -229,8 +238,51 @@ choose_pixel_format(const FrameBufferProperties &properties, _visuals = 0; _fbprops.clear(); -#ifdef HAVE_GLXFBCONFIG - //// Choose best format available using GLXFBConfig + // First, attempt to create a context using the XVisual interface. + // We need this before we can query the FBConfig interface, because + // we need an OpenGL context to get the required extension function + // pointers. + choose_visual(properties); + if (_context == NULL) { + // No good. + return; + } + + // Now we have to initialize the context so we can query its + // capabilities and extensions. This also means creating a + // temporary window, so we have something to bind the context to and + // make it current. + init_temp_context(); + + if (!_supports_fbconfig) { + // We have a good OpenGL context, but it doesn't support the + // FBConfig interface, so we'll stop there. + if (glxdisplay_cat.is_debug()) { + glxdisplay_cat.debug() + <<" No FBConfig supported; using XVisual only.\n"; + + glxdisplay_cat.debug() + << _fbprops << "\n"; + + // By convention, every indirect XVisual that can render to a + // window can also render to a GLXPixmap. Direct visuals we're + // not as sure about. + _context_has_pixmap = !glXIsDirect(_display, _context); + + // Pbuffers aren't supported at all with the XVisual interface. + _context_has_pbuffer = false; + } + return; + } + + // The OpenGL context supports the FBConfig interface, so we can use + // that more advanced interface to choose the actual window format + // we'll use. FBConfig provides for more options than the older + // XVisual interface, so we'd much rather use it if it's available. + + int best_quality = 0; + int best_result = 0; + FrameBufferProperties best_props; static const int max_attrib_list = 32; int attrib_list[max_attrib_list]; @@ -242,35 +294,38 @@ choose_pixel_format(const FrameBufferProperties &properties, attrib_list[n++] = GLX_DRAWABLE_TYPE; attrib_list[n++] = GLX_DONT_CARE; attrib_list[n] = (int)None; - + int num_configs = 0; GLXFBConfig *configs = - glXChooseFBConfig(_display, _screen, attrib_list, &num_configs); + _glXChooseFBConfig(_display, _screen, attrib_list, &num_configs); - int best_quality = 0; - int best_result = 0; - FrameBufferProperties best_props; + // Now that we're done querying the first context, we don't need it + // anymore. Clear it so we can create our actual OpenGL context. + glXDestroyContext(_display, _context); + _context = (GLXContext)NULL; + destroy_temp_xwindow(); if (configs != 0) { for (int i = 0; i < num_configs; ++i) { FrameBufferProperties fbprops; - bool pbuffer_supported, pixmap_supported, slow; - get_properties_advanced(fbprops, pbuffer_supported, pixmap_supported, + bool context_has_pbuffer, context_has_pixmap, slow; + get_properties_advanced(fbprops, context_has_pbuffer, context_has_pixmap, slow, configs[i]); - // We're not protecting this code by an is_debug() check, because if we do, - // some weird compiler bug appears and somehow makes the quality always 0. - const char *pbuffertext = pbuffer_supported ? " (pbuffer)" : ""; - const char *pixmaptext = pixmap_supported ? " (pixmap)" : ""; + // We're not protecting this code by an is_debug() check, + // because if we do, some weird compiler bug appears and somehow + // makes the quality always 0. + const char *pbuffertext = context_has_pbuffer ? " (pbuffer)" : ""; + const char *pixmaptext = context_has_pixmap ? " (pixmap)" : ""; const char *slowtext = slow ? " (slow)" : ""; glxdisplay_cat.debug() << i << ": " << fbprops << pbuffertext << pixmaptext << slowtext << "\n"; int quality = fbprops.get_quality(properties); if ((quality > 0)&&(slow)) quality -= 10000000; - - if (need_pbuffer && !pbuffer_supported) { + + if (need_pbuffer && !context_has_pbuffer) { continue; } - if (need_pixmap && !pixmap_supported) { + if (need_pixmap && !context_has_pixmap) { continue; } @@ -281,17 +336,31 @@ choose_pixel_format(const FrameBufferProperties &properties, } } } - + if (best_quality > 0) { _fbconfig = configs[best_result]; _context = - glXCreateNewContext(_display, _fbconfig, GLX_RGBA_TYPE, _share_context, - GL_TRUE); + _glXCreateNewContext(_display, _fbconfig, GLX_RGBA_TYPE, _share_context, + GL_TRUE); if (_context) { - _visuals = glXGetVisualFromFBConfig(_display, _fbconfig); + _visuals = _glXGetVisualFromFBConfig(_display, _fbconfig); _visual = _visuals; + if (_visual) { - _fbprops = best_props; + get_properties_advanced(_fbprops, _context_has_pbuffer, _context_has_pixmap, + _slow, _fbconfig); + + // hack? + //init_temp_context(); + + if (glxdisplay_cat.is_debug()) { + glxdisplay_cat.debug() + << "Selected context " << best_result << "\n"; + glxdisplay_cat.debug() + << "context_has_pbuffer = " << _context_has_pbuffer + << ", context_has_pixmap = " << _context_has_pixmap << "\n"; + } + return; } } @@ -303,40 +372,9 @@ choose_pixel_format(const FrameBufferProperties &properties, _visual = 0; _visuals = 0; } -#endif // HAVE_GLXFBCONFIG - - if (need_pbuffer) { - // The xvisual interface cannot create pbuffers. - return; - } - // Scan available visuals. - int nvisuals=0; - _visuals = XGetVisualInfo(_display, 0, 0, &nvisuals); - if (_visuals != 0) { - for (int i=0; i best_quality) { - best_quality = quality; - best_result = i; - best_props = fbprops; - } - } - } - - if (best_quality > 0) { - _visual = _visuals+best_result; - _context = glXCreateContext(_display, _visual, None, GL_TRUE); - if (_context) { - _fbprops = best_props; - return; - } - } - - glxdisplay_cat.error() << - "Could not find a usable pixel format.\n"; + glxdisplay_cat.info() + << "No suitable FBConfig contexts available.\n"; } //////////////////////////////////////////////////////////////////// @@ -367,6 +405,108 @@ reset() { _glXSwapIntervalSGI(sync_video ? 1 : 0); } + if (glx_support_fbconfig) { + if (glx_is_at_least_version(1, 3)) { + // If we have glx 1.3 or better, we have the FBConfig interface. + _supports_fbconfig = true; + + _glXChooseFBConfig = + (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfig"); + _glXCreateNewContext = + (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateNewContext"); + _glXGetVisualFromFBConfig = + (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfig"); + _glXGetFBConfigAttrib = + (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttrib"); + _glXCreatePixmap = + (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreatePixmap"); + + if (_glXChooseFBConfig == NULL || + _glXCreateNewContext == NULL || + _glXGetVisualFromFBConfig == NULL || + _glXGetFBConfigAttrib == NULL || + _glXCreatePixmap == NULL) { + glxdisplay_cat.error() + << "Driver claims to support GLX_fbconfig extension, but does not define all functions.\n"; + _supports_fbconfig = false; + } + } else if (has_extension("GLX_SGIX_fbconfig")) { + // Or maybe we have the old SGIX extension for FBConfig. This is + // the same, but the function names are different--we just remap + // them to the same function pointers. + _supports_fbconfig = true; + + _glXChooseFBConfig = + (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfigSGIX"); + _glXCreateNewContext = + (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateContextWithConfigSGIX"); + _glXGetVisualFromFBConfig = + (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfigSGIX"); + _glXGetFBConfigAttrib = + (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttribSGIX"); + _glXCreatePixmap = + (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreateGLXPixmapWithConfigSGIX"); + + if (_glXChooseFBConfig == NULL || + _glXCreateNewContext == NULL || + _glXGetVisualFromFBConfig == NULL || + _glXGetFBConfigAttrib == NULL || + _glXCreatePixmap == NULL) { + glxdisplay_cat.error() + << "Driver claims to support GLX_SGIX_fbconfig extension, but does not define all functions.\n"; + _supports_fbconfig = false; + } + } + + if (glx_is_at_least_version(1, 3)) { + // If we have glx 1.3 or better, we have the PBuffer interface. + _supports_pbuffer = true; + _uses_sgix_pbuffer = false; + + _glXCreatePbuffer = + (PFNGLXCREATEPBUFFERPROC)get_extension_func("glX", "CreatePbuffer"); + _glXCreateGLXPbufferSGIX = NULL; + _glXDestroyPbuffer = + (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyPbuffer"); + if (_glXCreatePbuffer == NULL || + _glXDestroyPbuffer == NULL) { + glxdisplay_cat.error() + << "Driver claims to support GLX_pbuffer extension, but does not define all functions.\n"; + _supports_pbuffer = false; + } + + } else if (has_extension("GLX_SGIX_pbuffer")) { + // Or maybe we have the old SGIX extension for PBuffers. + _uses_sgix_pbuffer = true; + + // CreatePbuffer has a different form between SGIX and 1.3, + // however, so we must treat it specially. But we can use the + // same function pointer for DestroyPbuffer. + _glXCreatePbuffer = NULL; + _glXCreateGLXPbufferSGIX = + (PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func("glX", "CreateGLXPbufferSGIX"); + _glXDestroyPbuffer = + (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyGLXPbufferSGIX"); + if (_glXCreateGLXPbufferSGIX == NULL || + _glXDestroyPbuffer == NULL) { + glxdisplay_cat.error() + << "Driver claims to support GLX_SGIX_pbuffer extension, but does not define all functions.\n"; + _supports_pbuffer = false; + } + } + } + + + if (glxdisplay_cat.is_debug()) { + glxdisplay_cat.debug() + << "supports_swap_control = " << _supports_swap_control << "\n"; + glxdisplay_cat.debug() + << "supports_fbconfig = " << _supports_fbconfig << "\n"; + glxdisplay_cat.debug() + << "supports_pbuffer = " << _supports_pbuffer + << " sgix = " << _uses_sgix_pbuffer << "\n"; + } + // If "Mesa" is present, assume software. However, if "Mesa DRI" is // found, it's actually a Mesa-based OpenGL layer running over a // hardware driver. @@ -604,3 +744,90 @@ show_glx_server_string(const string &name, int id) { } } } + +//////////////////////////////////////////////////////////////////// +// Function: glxGraphicsStateGuardian::choose_visual +// Access: Private +// Description: Selects a visual for this gsg. This may be called +// initially, to create the first context needed in +// order to create the fbconfig. On successful return, +// _visual and _context will be filled in with a +// non-NULL value. +//////////////////////////////////////////////////////////////////// +void glxGraphicsStateGuardian:: +choose_visual(const FrameBufferProperties &properties) { + int best_quality = 0; + int best_result = 0; + FrameBufferProperties best_props; + + // Scan available visuals. + int nvisuals = 0; + _visuals = XGetVisualInfo(_display, 0, 0, &nvisuals); + if (_visuals != 0) { + for (int i = 0; i < nvisuals; i++) { + FrameBufferProperties fbprops; + get_properties(fbprops, _visuals + i); + int quality = fbprops.get_quality(properties); + if (quality > best_quality) { + best_quality = quality; + best_result = i; + best_props = fbprops; + } + } + } + + if (best_quality > 0) { + _visual = _visuals + best_result; + _context = glXCreateContext(_display, _visual, None, GL_TRUE); + if (_context) { + _fbprops = best_props; + return; + } + } + + glxdisplay_cat.error() + << "Could not find a usable pixel format.\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: glxGraphicsStateGuardian::init_temp_context +// Access: Private +// Description: Initializes the context created in choose_visual() by +// creating a temporary window and binding the context +// to that window. +//////////////////////////////////////////////////////////////////// +void glxGraphicsStateGuardian:: +init_temp_context() { + x11GraphicsPipe *x11_pipe; + DCAST_INTO_V(x11_pipe, get_pipe()); + Window root_window = x11_pipe->get_root(); + + destroy_temp_xwindow(); + + _temp_xwindow = XCreateWindow + (_display, root_window, 0, 0, 1, 1, + 0, _visual->depth, InputOutput, + _visual->visual, 0, NULL); + if (_temp_xwindow == (Window)NULL) { + glxdisplay_cat.error() + << "Could not create temporary window for context\n"; + return; + } + + glXMakeCurrent(_display, _temp_xwindow, _context); + reset(); +} + +//////////////////////////////////////////////////////////////////// +// Function: glxGraphicsStateGuardian::destroy_temp_xwindow +// Access: Private +// Description: Destroys the temporary unmapped window created by +// init_temp_context(). +//////////////////////////////////////////////////////////////////// +void glxGraphicsStateGuardian:: +destroy_temp_xwindow() { + if (_temp_xwindow != (Window)NULL) { + XDestroyWindow(_display, _temp_xwindow); + _temp_xwindow = (Window)NULL; + } +} diff --git a/panda/src/glxdisplay/glxGraphicsStateGuardian.h b/panda/src/glxdisplay/glxGraphicsStateGuardian.h index 2224966672..831a5f574f 100644 --- a/panda/src/glxdisplay/glxGraphicsStateGuardian.h +++ b/panda/src/glxdisplay/glxGraphicsStateGuardian.h @@ -20,6 +20,9 @@ #include "glgsg.h" #include "glxGraphicsPipe.h" +// Don't pick up the system glxext.h; use our own, which is better. +#define __glxext_h_ + #include #if defined(GLX_VERSION_1_4) @@ -39,7 +42,7 @@ extern "C" void (*glXGetProcAddressARB(const GLubyte *procName))( void ); // This must be included after we have included glgsg.h (which // includes gl.h). -#include "glxext.h" +#include "panda_glxext.h" // drose: the version of GL/glx.h that ships with Fedora Core 2 seems // to define GLX_VERSION_1_4, but for some reason does not define @@ -69,17 +72,11 @@ typedef int (* PFNGLXSWAPINTERVALSGIPROC) (int interval); //////////////////////////////////////////////////////////////////// class glxGraphicsStateGuardian : public GLGraphicsStateGuardian { public: -#ifdef HAVE_GLXFBCONFIG - typedef GLXFBConfig fbconfig; -#else - typedef int fbconfig; -#endif - INLINE const FrameBufferProperties &get_fb_properties() const; void get_properties(FrameBufferProperties &properties, XVisualInfo *visual); void get_properties_advanced(FrameBufferProperties &properties, - bool &pbuffer_supported, bool &pixmap_supported, - bool &slow, fbconfig config); + bool &context_has_pbuffer, bool &pixmap_supported, + bool &slow, GLXFBConfig config); void choose_pixel_format(const FrameBufferProperties &properties, Display *_display, int _screen, @@ -100,13 +97,30 @@ public: int _screen; XVisualInfo *_visual; XVisualInfo *_visuals; - fbconfig _fbconfig; + + GLXFBConfig _fbconfig; FrameBufferProperties _fbprops; + bool _context_has_pbuffer; // true if the particular fbconfig supports pbuffers + bool _context_has_pixmap; + bool _slow; public: bool _supports_swap_control; PFNGLXSWAPINTERVALSGIPROC _glXSwapIntervalSGI; + bool _supports_fbconfig; + PFNGLXCHOOSEFBCONFIGPROC _glXChooseFBConfig; + PFNGLXCREATENEWCONTEXTPROC _glXCreateNewContext; + PFNGLXGETVISUALFROMFBCONFIGPROC _glXGetVisualFromFBConfig; + PFNGLXGETFBCONFIGATTRIBPROC _glXGetFBConfigAttrib; + PFNGLXCREATEPIXMAPPROC _glXCreatePixmap; + + bool _supports_pbuffer; // true if the interface is available. + bool _uses_sgix_pbuffer; + PFNGLXCREATEPBUFFERPROC _glXCreatePbuffer; + PFNGLXCREATEGLXPBUFFERSGIXPROC _glXCreateGLXPbufferSGIX; + PFNGLXDESTROYPBUFFERPROC _glXDestroyPbuffer; + protected: virtual void gl_flush() const; virtual GLenum gl_get_error() const; @@ -119,13 +133,16 @@ private: void *get_system_func(const char *name); void show_glx_client_string(const string &name, int id); void show_glx_server_string(const string &name, int id); - + void choose_visual(const FrameBufferProperties &properties); + void init_temp_context(); + void destroy_temp_xwindow(); int _glx_version_major, _glx_version_minor; void *_libgl_handle; bool _checked_get_proc_address; PFNGLXGETPROCADDRESSPROC _glXGetProcAddress; + Window _temp_xwindow; public: static TypeHandle get_class_type() { diff --git a/panda/src/glxdisplay/glxGraphicsWindow.cxx b/panda/src/glxdisplay/glxGraphicsWindow.cxx index adade59536..79c7e48e8d 100644 --- a/panda/src/glxdisplay/glxGraphicsWindow.cxx +++ b/panda/src/glxdisplay/glxGraphicsWindow.cxx @@ -188,15 +188,11 @@ open_window() { } Visual *visual = _visual_info->visual; -#ifdef HAVE_GLXFBCONFIG if (glxgsg->_fbconfig != None) { setup_colormap(glxgsg->_fbconfig); } else { setup_colormap(_visual_info); } -#else - setup_colormap(_visual_info); -#endif // HAVE_GLXFBCONFIG if (!x11GraphicsWindow::open_window()) { return false; @@ -218,7 +214,6 @@ open_window() { return true; } -#ifdef HAVE_GLXFBCONFIG //////////////////////////////////////////////////////////////////// // Function: glxGraphicsWindow::setup_colormap // Access: Private @@ -227,7 +222,11 @@ open_window() { //////////////////////////////////////////////////////////////////// void glxGraphicsWindow:: setup_colormap(GLXFBConfig fbconfig) { - XVisualInfo *visual_info = glXGetVisualFromFBConfig(_display, fbconfig); + glxGraphicsStateGuardian *glxgsg; + DCAST_INTO_V(glxgsg, _gsg); + nassertv(glxgsg->_supports_fbconfig); + + XVisualInfo *visual_info = glxgsg->_glXGetVisualFromFBConfig(_display, fbconfig); if (visual_info == NULL) { // No X visual; no need to set up a colormap. return; @@ -244,7 +243,7 @@ setup_colormap(GLXFBConfig fbconfig) { switch (visual_class) { case PseudoColor: - rc = glXGetFBConfigAttrib(_display, fbconfig, GLX_RGBA, &is_rgb); + rc = glxgsg->_glXGetFBConfigAttrib(_display, fbconfig, GLX_RGBA, &is_rgb); if (rc == 0 && is_rgb) { glxdisplay_cat.warning() << "mesa pseudocolor not supported.\n"; @@ -274,7 +273,6 @@ setup_colormap(GLXFBConfig fbconfig) { break; } } -#endif // HAVE_GLXFBCONFIG //////////////////////////////////////////////////////////////////// // Function: glxGraphicsWindow::setup_colormap diff --git a/panda/src/glxdisplay/glxGraphicsWindow.h b/panda/src/glxdisplay/glxGraphicsWindow.h index 9686455c06..e2406c534e 100644 --- a/panda/src/glxdisplay/glxGraphicsWindow.h +++ b/panda/src/glxdisplay/glxGraphicsWindow.h @@ -46,10 +46,7 @@ protected: virtual bool open_window(); private: - -#ifdef HAVE_GLXFBCONFIG virtual void setup_colormap(GLXFBConfig fbconfig); -#endif // HAVE_GLXFBCONFIG virtual void setup_colormap(XVisualInfo *visual); public: diff --git a/panda/src/glxdisplay/glxext.h b/panda/src/glxdisplay/panda_glxext.h similarity index 99% rename from panda/src/glxdisplay/glxext.h rename to panda/src/glxdisplay/panda_glxext.h index 5fba57a2f4..fad3574052 100644 --- a/panda/src/glxdisplay/glxext.h +++ b/panda/src/glxdisplay/panda_glxext.h @@ -1,5 +1,5 @@ -#ifndef __glxext_h_ -#define __glxext_h_ +#ifndef panda__glxext_h_ +#define panda__glxext_h_ #ifdef __cplusplus extern "C" {