diff --git a/include/osg/GLExtensions b/include/osg/GLExtensions index c80230d36..d5c546650 100644 --- a/include/osg/GLExtensions +++ b/include/osg/GLExtensions @@ -28,6 +28,10 @@ namespace osg { */ extern OSG_EXPORT float getGLVersionNumber(); +/** Return true if "extension" is contained in "extensionString". +*/ +extern OSG_EXPORT bool isExtensionInExtensionString(const char *extension, const char *extensionString); + /** Return true if OpenGL "extension" is supported. * Note: Must only be called within a valid OpenGL context, * undefined behavior may occur otherwise. diff --git a/include/osgViewer/api/X11/PixelBufferX11 b/include/osgViewer/api/X11/PixelBufferX11 index e015e9157..fa0f5c847 100644 --- a/include/osgViewer/api/X11/PixelBufferX11 +++ b/include/osgViewer/api/X11/PixelBufferX11 @@ -77,7 +77,6 @@ class OSGVIEWER_EXPORT PixelBufferX11 : public osg::GraphicsContext Display* getDisplay() const { return _display; } - Window& getParent() { return _parent; } GLXPbuffer& getPbuffer() { return _pbuffer; } GLXContext& getGLXContext() { return _glxContext; } @@ -91,13 +90,14 @@ class OSGVIEWER_EXPORT PixelBufferX11 : public osg::GraphicsContext bool _valid; Display* _display; - Window _parent; GLXPbuffer _pbuffer; XVisualInfo* _visualInfo; GLXContext _glxContext; bool _initialized; bool _realized; + + bool _useGLX1_3; }; } diff --git a/src/osg/GLExtensions.cpp b/src/osg/GLExtensions.cpp index 0cd8531c2..b969340c6 100644 --- a/src/osg/GLExtensions.cpp +++ b/src/osg/GLExtensions.cpp @@ -48,6 +48,22 @@ float osg::getGLVersionNumber() return( atof( vs.substr( 0, vs.find( " " ) ).c_str() ) ); } +bool osg::isExtensionInExtensionString(const char *extension, const char *extensionString) +{ + const char *startOfWord = extensionString; + const char *endOfWord; + while ((endOfWord = strchr(startOfWord,' ')) != 0) + { + if (strncmp(extension, startOfWord, endOfWord - startOfWord) == 0) + return true; + startOfWord = endOfWord+1; + } + if (*startOfWord && strcmp(extension, startOfWord) == 0) + return true; + + return false; +} + bool osg::isGLExtensionSupported(unsigned int contextID, const char *extension) { ExtensionSet& extensionSet = s_glExtensionSetList[contextID]; diff --git a/src/osgViewer/PixelBufferX11.cpp b/src/osgViewer/PixelBufferX11.cpp index 156d8dfcf..4ed82e916 100644 --- a/src/osgViewer/PixelBufferX11.cpp +++ b/src/osgViewer/PixelBufferX11.cpp @@ -18,6 +18,7 @@ #include #include +#include #include @@ -25,38 +26,15 @@ using namespace osgViewer; -#ifdef GLX_VERSION_1_3 -static GLXFBConfig getFBConfigFromVisual(::Display* dpy, XVisualInfo* visualInfo) -{ -#if defined(__APPLE__) || defined(_AIX) || defined(__hpux) - int screen = visualInfo->screen; - int nelements; - GLXFBConfig *configs = glXGetFBConfigs(dpy, screen, &nelements); - for( int i = 0; i < nelements; i++ ) - { - int visual_id; - if( glXGetFBConfigAttrib( dpy, configs[i], GLX_VISUAL_ID, &visual_id ) == 0 ) - { - if( (unsigned int)visual_id == visualInfo->visualid ) - return configs[i]; - } - } - return NULL; -#else - return glXGetFBConfigFromVisualSGIX( dpy, visualInfo ); -#endif -} -#endif - PixelBufferX11::PixelBufferX11(osg::GraphicsContext::Traits* traits) : _valid(false), _display(0), - _parent(0), _pbuffer(0), _visualInfo(0), _glxContext(0), _initialized(false), - _realized(false) + _realized(false), + _useGLX1_3(false) { _traits = traits; @@ -85,7 +63,7 @@ PixelBufferX11::~PixelBufferX11() close(true); } -#ifdef GLX_VERSION_1_3 +#if defined(GLX_VERSION_1_3) || defined(GLX_SGIX_pbuffer) bool PixelBufferX11::createVisualInfo() { typedef std::vector Attributes; @@ -153,7 +131,7 @@ void PixelBufferX11::init() return; } - // Query for GLX extension + // Query for GLX extension int errorBase, eventBase; if( glXQueryExtension( _display, &errorBase, &eventBase) == False ) { @@ -178,16 +156,46 @@ void PixelBufferX11::init() return; } - // We need to have at least GLX 1.3 to use getFBConfigFromVisual and glXCreatePbuffer - if (major < 1 || (major == 1 && minor < 3)) + // Just be paranoid, if we are older than 1.1, we cannot even call glxQueryExtensionString + if (1 < major || (1 == major && minor < 1)) { osg::notify(osg::NOTICE) << "Error: " << XDisplayName(_traits->displayName().c_str()) - << " GLX version " << major << "." << minor << " is too little." << std::endl; + << " GLX version " << major << "." << minor << " is too old." << std::endl; XCloseDisplay( _display ); _display = 0; _valid = false; return; } + + bool haveGLX1_3 = false; + bool haveSGIX_pbuffer = false; + + // We need to have at least GLX 1.3 to use getFBConfigFromVisual and glXCreatePbuffer + if (1 < major || (1 == major && 3 <= minor)) + { + haveGLX1_3 = true; + } + +#if defined(GLX_VERSION_1_1) + // We need at least GLX 1.1 for glXQueryExtensionsString + if (!haveGLX1_3 && 1 <= minor) + { + const char *extensions = glXQueryExtensionsString(_display, screen); + haveSGIX_pbuffer = osg::isExtensionInExtensionString("GLX_SGIX_pbuffer", extensions) + && osg::isExtensionInExtensionString("GLX_SGIX_fbconfig", extensions); + } +#endif + + if (!haveGLX1_3 && !haveSGIX_pbuffer) + { + osg::notify(osg::NOTICE) << "Error: " << XDisplayName(_traits->displayName().c_str()) + << " no Pbuffer support in GLX available." << std::endl; + XCloseDisplay( _display ); + _display = 0; + _valid = false; + return; + } + if (!createVisualInfo()) { @@ -237,43 +245,53 @@ void PixelBufferX11::init() return; } - _parent = RootWindow( _display, screen ); - - XWindowAttributes watt; - XGetWindowAttributes( _display, _parent, &watt ); - // unsigned int parentWindowHeight = watt.height; - - XSetWindowAttributes swatt; - swatt.colormap = XCreateColormap( _display, _parent, _visualInfo->visual, AllocNone); - //swatt.colormap = DefaultColormap( _dpy, 10 ); - swatt.background_pixel = 0; - swatt.border_pixel = 0; - swatt.event_mask = 0; - unsigned long mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap; - - bool overrideRedirect = false; - if (overrideRedirect) +#ifdef GLX_VERSION_1_3 + // First try the regular glx extension if we have a new enough version available. + if (haveGLX1_3) { - swatt.override_redirect = true; - mask |= CWOverrideRedirect; + int nelements; + GLXFBConfig *fbconfigs = glXGetFBConfigs( _display, screen, &nelements ); + for ( int i = 0; i < nelements; ++i ) + { + int visual_id; + if ( glXGetFBConfigAttrib( _display, fbconfigs[i], GLX_VISUAL_ID, &visual_id ) == 0 ) + { + if ( !_pbuffer && (unsigned int)visual_id == _visualInfo->visualid ) + { + typedef std::vector AttributeList; + + AttributeList attributes; + attributes.push_back( GLX_PBUFFER_WIDTH ); + attributes.push_back( _traits->width ); + attributes.push_back( GLX_PBUFFER_HEIGHT ); + attributes.push_back( _traits->height ); + attributes.push_back( 0L ); + + _pbuffer = glXCreatePbuffer(_display, fbconfigs[i], &attributes.front() ); + _useGLX1_3 = true; + } + } + } + + XFree( fbconfigs ); } +#endif - GLXFBConfig fbconfig = getFBConfigFromVisual( _display, _visualInfo ); +#ifdef GLX_SGIX_pbuffer + // If we still have no pbuffer but a capable display with the SGIX extension, try to use that + if (!_pbuffer && haveSGIX_pbuffer) + { + GLXFBConfigSGIX fbconfig = glXGetFBConfigFromVisualSGIX( _display, _visualInfo ); - typedef std::vector AttributeList; + _pbuffer = glXCreateGLXPbufferSGIX(_display, fbconfig, _traits->width, _traits->height, 0 ); - AttributeList attributes; - attributes.push_back( GLX_PBUFFER_WIDTH ); - attributes.push_back( _traits->width ); - attributes.push_back( GLX_PBUFFER_HEIGHT ); - attributes.push_back( _traits->height ); - attributes.push_back( 0L ); + XFree( fbconfig ); + } +#endif - _pbuffer = glXCreatePbuffer(_display, fbconfig, &attributes.front() ); - if (!_pbuffer) { - osg::notify(osg::NOTICE)<<"Error: Unable to create Window."<