From 91df37b5c8e408b57c448846b37ebc64c75e2c66 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 16 Sep 2002 20:58:05 +0000 Subject: [PATCH] Further work on multiple context extensions. --- include/osg/Image | 2 +- include/osg/Texture | 62 +++++++++++- include/osg/Texture3D | 1 + include/osg/TextureCubeMap | 39 ++++++++ src/osg/Image.cpp | 8 +- src/osg/Texture.cpp | 197 ++++++++++++++++++++++++------------- src/osg/Texture1D.cpp | 3 +- src/osg/Texture3D.cpp | 2 +- src/osg/TextureCubeMap.cpp | 47 +++++++-- 9 files changed, 272 insertions(+), 89 deletions(-) diff --git a/include/osg/Image b/include/osg/Image index 722713d17..26fd6c4df 100644 --- a/include/osg/Image +++ b/include/osg/Image @@ -153,7 +153,7 @@ class SG_EXPORT Image : public Object * Mip Mapped texture require the image dimensions to be * power of two and are within the maxiumum texture size for * the host machine.*/ - void ensureValidSizeForTexturing(); + void ensureValidSizeForTexturing(GLint maxTextureSize); /** Dirty the image, which increments the modified flag, to force osg::Texture to reload the image.*/ inline void dirty() { ++_modifiedTag; } diff --git a/include/osg/Texture b/include/osg/Texture index 211104ab3..fd1206053 100644 --- a/include/osg/Texture +++ b/include/osg/Texture @@ -247,17 +247,69 @@ class SG_EXPORT Texture : public osg::StateAttribute * in the OpenGL context related to contextID.*/ static void flushDeletedTextureObjects(uint contextID); - /** Get the maximum texture size supported, this is the - normally define by GL_MAX_TEXTURE_SIZE, but can be overridden - by the OSG_MAX_TEXTURE_SIZE environmental variable.*/ - static GLint getMaxTextureSize(); - /** Texture is pure virtual base class, apply must be overriden. */ virtual void apply(State& state) const = 0; /** Calls apply(state) to compile the texture. */ virtual void compile(State& state) const; + /** Extensions class which encapsulates the querring of extensions and + * associated function pointers, and provide convinience wrappers to + * check for the extensions or use the associated functions.*/ + class Extensions : public osg::Referenced + { + public: + Extensions(); + + Extensions(const Extensions& rhs); + + void lowestCommonDenominator(const Extensions& rhs); + + void setupGLExtenions(); + + bool isTextureFilterAnisotropicSupported() const { return _isTextureFilterAnisotropicSupported; } + bool isTextureCompressionARBSupported() const { return _isTextureCompressionARBSupported; } + bool isTextureCompressionS3TCSupported() const { return _isTextureCompressionS3TCSupported; } + bool isTextureMirroredRepeatSupported() const { return _isTextureMirroredRepeatSupported; } + bool isTextureEdgeClampSupported() const { return _isTextureEdgeClampSupported; } + bool isTextureBorderClampSupported() const { return _isTextureBorderClampSupported; } + + GLint maxTextureSize() const { return _maxTextureSize; } + + bool isCompressedTexImage2DSupported() const { return _glCompressedTexImage2D!=0; } + + void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const; + + protected: + + ~Extensions() {} + + bool _isTextureFilterAnisotropicSupported; + bool _isTextureCompressionARBSupported; + bool _isTextureCompressionS3TCSupported; + bool _isTextureMirroredRepeatSupported; + bool _isTextureEdgeClampSupported; + bool _isTextureBorderClampSupported; + + GLint _maxTextureSize; + + void* _glCompressedTexImage2D; + + }; + + /** Function to call to get the extension of a specified context. + * If the Exentsion object for that context has not yet been created then + * and the 'createIfNotInitalized' flag been set to false then returns NULL. + * If 'createIfNotInitalized' is true then the Extensions object is + * automatically created. However, in this case the extension object + * only be created with the graphics context associated with ContextID..*/ + static const Extensions* getExtensions(uint contextID,bool createIfNotInitalized); + + /** setExtensions allows users to override the extensions across graphics contexts. + * typically used when you have different extensions supported across graphics pipes + * but need to ensure that they all use the same low common denominator extensions.*/ + static void setExtensions(uint contextID,Extensions* extensions); + protected : virtual ~Texture(); diff --git a/include/osg/Texture3D b/include/osg/Texture3D index cdb301f64..f2f8183b2 100644 --- a/include/osg/Texture3D +++ b/include/osg/Texture3D @@ -108,6 +108,7 @@ class SG_EXPORT Texture3D : public Texture bool isTexture3DSupported() const { return _isTexture3DSupported; } bool isTexture3DFast() const { return _isTexture3DFast; } + GLint maxTexture3DSize() const { return _maxTexture3DSize; } void glTexImage3D( GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) const; diff --git a/include/osg/TextureCubeMap b/include/osg/TextureCubeMap index b2e2cb192..6f1de0b0b 100644 --- a/include/osg/TextureCubeMap +++ b/include/osg/TextureCubeMap @@ -89,6 +89,45 @@ class SG_EXPORT TextureCubeMap : public Texture * texture and bind it, subsequent apply will simple bind to texture.*/ virtual void apply(State& state) const; + + /** Extensions class which encapsulates the querring of extensions and + * associated function pointers, and provide convinience wrappers to + * check for the extensions or use the associated functions.*/ + class Extensions : public osg::Referenced + { + public: + Extensions(); + + Extensions(const Extensions& rhs); + + void lowestCommonDenominator(const Extensions& rhs); + + void setupGLExtenions(); + + bool isCubeMapSupported() const { return _isCubeMapSupported; } + + protected: + + ~Extensions() {} + + bool _isCubeMapSupported; + + }; + + /** Function to call to get the extension of a specified context. + * If the Exentsion object for that context has not yet been created then + * and the 'createIfNotInitalized' flag been set to false then returns NULL. + * If 'createIfNotInitalized' is true then the Extensions object is + * automatically created. However, in this case the extension object + * only be created with the graphics context associated with ContextID..*/ + static const Extensions* getExtensions(uint contextID,bool createIfNotInitalized); + + /** setExtensions allows users to override the extensions across graphics contexts. + * typically used when you have different extensions supported across graphics pipes + * but need to ensure that they all use the same low common denominator extensions.*/ + static void setExtensions(uint contextID,Extensions* extensions); + + protected : virtual ~TextureCubeMap(); diff --git a/src/osg/Image.cpp b/src/osg/Image.cpp index 5b23857c2..8ca5db3ae 100644 --- a/src/osg/Image.cpp +++ b/src/osg/Image.cpp @@ -453,15 +453,13 @@ void Image::flipVertical(int image) -void Image::ensureValidSizeForTexturing() +void Image::ensureValidSizeForTexturing(GLint maxTextureSize) { int new_s = computeNearestPowerOfTwo(_s); int new_t = computeNearestPowerOfTwo(_t); - static GLint max_size=Texture::getMaxTextureSize(); - - if (new_s>max_size) new_s = max_size; - if (new_t>max_size) new_t = max_size; + if (new_s>maxTextureSize) new_s = maxTextureSize; + if (new_t>maxTextureSize) new_t = maxTextureSize; if (new_s!=_s || new_t!=_t) { diff --git a/src/osg/Texture.cpp b/src/osg/Texture.cpp index 6d83b877f..dc4fa9952 100644 --- a/src/osg/Texture.cpp +++ b/src/osg/Texture.cpp @@ -5,8 +5,6 @@ #include #include -typedef void (APIENTRY * MyCompressedTexImage2DArbProc) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); - using namespace osg; @@ -142,8 +140,11 @@ void Texture::dirtyTextureParameters() void Texture::computeInternalFormatWithImage(osg::Image& image) const { - static bool s_ARB_Compression = isGLExtensionSupported("GL_ARB_texture_compression"); - static bool s_S3TC_Compression = isGLExtensionSupported("GL_EXT_texture_compression_s3tc"); + const uint contextID = 0; // state.getContextID(); // set to 0 right now, assume same paramters for each graphics context... + const Extensions* extensions = getExtensions(contextID,true); + +// static bool s_ARB_Compression = isGLExtensionSupported("GL_ARB_texture_compression"); +// static bool s_S3TC_Compression = isGLExtensionSupported("GL_EXT_texture_compression_s3tc"); GLint internalFormat = image.getInternalTextureFormat(); switch(_internalFormatMode) @@ -153,7 +154,7 @@ void Texture::computeInternalFormatWithImage(osg::Image& image) const break; case(USE_ARB_COMPRESSION): - if (s_ARB_Compression) + if (extensions->isTextureCompressionARBSupported()) { switch(image.getPixelFormat()) { @@ -173,7 +174,7 @@ void Texture::computeInternalFormatWithImage(osg::Image& image) const break; case(USE_S3TC_DXT1_COMPRESSION): - if (s_S3TC_Compression) + if (extensions->isTextureCompressionS3TCSupported()) { switch(image.getPixelFormat()) { @@ -188,7 +189,7 @@ void Texture::computeInternalFormatWithImage(osg::Image& image) const break; case(USE_S3TC_DXT3_COMPRESSION): - if (s_S3TC_Compression) + if (extensions->isTextureCompressionS3TCSupported()) { switch(image.getPixelFormat()) { @@ -203,7 +204,7 @@ void Texture::computeInternalFormatWithImage(osg::Image& image) const break; case(USE_S3TC_DXT5_COMPRESSION): - if (s_S3TC_Compression) + if (extensions->isTextureCompressionS3TCSupported()) { switch(image.getPixelFormat()) { @@ -248,11 +249,15 @@ bool Texture::isCompressedInternalFormat(GLint internalFormat) const void Texture::applyTexParameters(GLenum target, State& state) const { + // get the contextID (user defined ID of 0 upwards) for the + // current OpenGL context. + const uint contextID = state.getContextID(); + const Extensions* extensions = getExtensions(contextID,true); + WrapMode ws = _wrap_s, wt = _wrap_t; // GL_IBM_texture_mirrored_repeat, fall-back REPEAT - static bool s_mirroredSupported = isGLExtensionSupported("GL_IBM_texture_mirrored_repeat"); - if (!s_mirroredSupported) + if (!extensions->isTextureMirroredRepeatSupported()) { if (ws == MIRROR) ws = REPEAT; @@ -261,8 +266,7 @@ void Texture::applyTexParameters(GLenum target, State& state) const } // GL_EXT_texture_edge_clamp, fall-back CLAMP - static bool s_edgeClampSupported = isGLExtensionSupported("GL_EXT_texture_edge_clamp"); - if (!s_edgeClampSupported) + if (!extensions->isTextureEdgeClampSupported()) { if (ws == CLAMP_TO_EDGE) ws = CLAMP; @@ -270,8 +274,7 @@ void Texture::applyTexParameters(GLenum target, State& state) const wt = CLAMP; } - static bool s_borderClampSupported = isGLExtensionSupported("GL_ARB_texture_border_clamp"); - if(!s_borderClampSupported) + if(!extensions->isTextureBorderClampSupported()) { if(ws == CLAMP_TO_BORDER) ws = CLAMP; @@ -285,24 +288,14 @@ void Texture::applyTexParameters(GLenum target, State& state) const glTexParameteri( target, GL_TEXTURE_MIN_FILTER, _min_filter); glTexParameteri( target, GL_TEXTURE_MAG_FILTER, _mag_filter); - if (_maxAnisotropy>1.0f) + if (_maxAnisotropy>1.0f && extensions->isTextureFilterAnisotropicSupported()) { - // check for support for anisotropic filter, - // note since this is static varible it is intialised - // only on the first time entering this code block, - // is then never reevaluated on subsequent calls. - static bool s_anisotropicSupported = - isGLExtensionSupported("GL_EXT_texture_filter_anisotropic"); - - if (s_anisotropicSupported) - { - // note, GL_TEXTURE_MAX_ANISOTROPY_EXT will either be defined - // by gl.h (or via glext.h) or by include/osg/Texture. - glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, _maxAnisotropy); - } + // note, GL_TEXTURE_MAX_ANISOTROPY_EXT will either be defined + // by gl.h (or via glext.h) or by include/osg/Texture. + glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, _maxAnisotropy); } - if (s_borderClampSupported) + if (extensions->isTextureBorderClampSupported()) { glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, _borderColor.ptr()); } @@ -320,6 +313,7 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. const uint contextID = state.getContextID(); + const Extensions* extensions = getExtensions(contextID,true); // update the modified tag to show that it is upto date. getModifiedTag(contextID) = image->getModifiedTag(); @@ -331,13 +325,10 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei // select the internalFormat required for the texture. bool compressed = isCompressedInternalFormat(_internalFormat); - image->ensureValidSizeForTexturing(); + image->ensureValidSizeForTexturing(extensions->maxTextureSize()); glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking()); - static MyCompressedTexImage2DArbProc glCompressedTexImage2D_ptr = - (MyCompressedTexImage2DArbProc)getGLExtensionFuncPtr("glCompressedTexImage2DARB"); - if( _min_filter == LINEAR || _min_filter == NEAREST ) { if ( !compressed ) @@ -350,15 +341,15 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei image->data() ); } - else if(glCompressedTexImage2D_ptr) + else if (extensions->isCompressedTexImage2DSupported()) { numMimpmapLevels = 1; GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 ); GLint size = ((image->s()+3)/4)*((image->t()+3)/4)*blockSize; - glCompressedTexImage2D_ptr(target, 0, _internalFormat, - image->s(), image->t(),0, - size, - image->data()); + extensions->glCompressedTexImage2D(target, 0, _internalFormat, + image->s(), image->t(),0, + size, + image->data()); } @@ -403,7 +394,7 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei height >>= 1; } } - else if(glCompressedTexImage2D_ptr) + else if (extensions->isCompressedTexImage2DSupported()) { GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 ); GLint size = 0; @@ -415,8 +406,8 @@ void Texture::applyTexImage2D(GLenum target, Image* image, State& state, GLsizei height = 1; size = ((width+3)/4)*((height+3)/4)*blockSize; - glCompressedTexImage2D_ptr(target, k, _internalFormat, - width, height, 0, size, image->getMipmapData(k)); + extensions->glCompressedTexImage2D(target, k, _internalFormat, + width, height, 0, size, image->getMipmapData(k)); width >>= 1; height >>= 1; @@ -471,36 +462,102 @@ void Texture::flushDeletedTextureObjects(uint contextID) } } - -GLint Texture::getMaxTextureSize() -{ - static GLint s_maxTextureSize = 0; - if (s_maxTextureSize == 0) - { - - glGetIntegerv(GL_MAX_TEXTURE_SIZE,&s_maxTextureSize); - notify(INFO) << "GL_MAX_TEXTURE_SIZE "< > BufferedExtensions; +static BufferedExtensions s_extensions; + +const Texture::Extensions* Texture::getExtensions(uint contextID,bool createIfNotInitalized) +{ + if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions; + return s_extensions[contextID].get(); +} + +void Texture::setExtensions(uint contextID,Extensions* extensions) +{ + s_extensions[contextID] = extensions; +} + +Texture::Extensions::Extensions() +{ + setupGLExtenions(); +} + +Texture::Extensions::Extensions(const Extensions& rhs): + Referenced() +{ + _isTextureFilterAnisotropicSupported = rhs._isTextureFilterAnisotropicSupported; + _isTextureMirroredRepeatSupported = rhs._isTextureMirroredRepeatSupported; + _isTextureEdgeClampSupported = rhs._isTextureEdgeClampSupported; + _isTextureBorderClampSupported = rhs._isTextureBorderClampSupported; + + _isTextureCompressionARBSupported = rhs._isTextureCompressionARBSupported; + _isTextureCompressionS3TCSupported = rhs._isTextureCompressionS3TCSupported; + + _maxTextureSize = rhs._maxTextureSize; + + _glCompressedTexImage2D = rhs._glCompressedTexImage2D; +} + +void Texture::Extensions::lowestCommonDenominator(const Extensions& rhs) +{ + if (!rhs._isTextureFilterAnisotropicSupported) _isTextureFilterAnisotropicSupported = false; + if (!rhs._isTextureMirroredRepeatSupported) _isTextureMirroredRepeatSupported = false; + if (!rhs._isTextureEdgeClampSupported) _isTextureEdgeClampSupported = false; + if (!rhs._isTextureBorderClampSupported) _isTextureBorderClampSupported = false; + + if (!rhs._isTextureCompressionARBSupported) _isTextureCompressionARBSupported = false; + if (!rhs._isTextureCompressionS3TCSupported) _isTextureCompressionS3TCSupported = false; + + if (rhs._maxTextureSize<_maxTextureSize) _maxTextureSize = rhs._maxTextureSize; + + if (!rhs._glCompressedTexImage2D) _glCompressedTexImage2D = 0; +} + +void Texture::Extensions::setupGLExtenions() +{ + + _isTextureFilterAnisotropicSupported = isGLExtensionSupported("GL_EXT_texture_filter_anisotropic"); + _isTextureMirroredRepeatSupported = isGLExtensionSupported("GL_IBM_texture_mirrored_repeat"); + _isTextureEdgeClampSupported = isGLExtensionSupported("GL_EXT_texture_edge_clamp"); + _isTextureBorderClampSupported = isGLExtensionSupported("GL_ARB_texture_border_clamp"); + + _isTextureCompressionARBSupported = isGLExtensionSupported("GL_ARB_texture_compression"); + _isTextureCompressionS3TCSupported = isGLExtensionSupported("GL_EXT_texture_compression_s3tc"); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE,&_maxTextureSize); + + char *ptr; + if( (ptr = getenv("OSG_MAX_TEXTURE_SIZE")) != 0) + { + GLint osg_max_size = atoi(ptr); + + if (osg_max_size<_maxTextureSize) + { + + _maxTextureSize = osg_max_size; + } + + } + + _glCompressedTexImage2D = getGLExtensionFuncPtr("glCompressedTexImage2DARB");; + +} + +void Texture::Extensions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const +{ + if (_glCompressedTexImage2D) + { + typedef void (APIENTRY * CompressedTexImage2DArbProc) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); + (*((CompressedTexImage2DArbProc)_glCompressedTexImage2D))(target, level, internalformat, width, height, border, imageSize, data); + } + else + { + notify(WARN)<<"Error: glCompressedTexImage2D not supported by OpenGL driver"<getModifiedTag(); @@ -158,7 +159,7 @@ void Texture1D::applyTexImage1D(GLenum target, Image* image, State& state, GLsiz // select the internalFormat required for the texture. bool compressed = isCompressedInternalFormat(_internalFormat); - image->ensureValidSizeForTexturing(); + image->ensureValidSizeForTexturing(extensions->maxTextureSize()); glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking()); diff --git a/src/osg/Texture3D.cpp b/src/osg/Texture3D.cpp index 135a740dd..d8389cb08 100644 --- a/src/osg/Texture3D.cpp +++ b/src/osg/Texture3D.cpp @@ -183,7 +183,7 @@ void Texture3D::applyTexImage3D(GLenum target, Image* image, State& state, GLsiz return; } - image->ensureValidSizeForTexturing(); + image->ensureValidSizeForTexturing(extensions->maxTexture3DSize()); glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking()); diff --git a/src/osg/TextureCubeMap.cpp b/src/osg/TextureCubeMap.cpp index d2fd243a3..6cb403795 100644 --- a/src/osg/TextureCubeMap.cpp +++ b/src/osg/TextureCubeMap.cpp @@ -177,15 +177,13 @@ void TextureCubeMap::computeInternalFormat() const void TextureCubeMap::apply(State& state) const { - static bool s_CubeMapSupported = isGLExtensionSupported("GL_ARB_texture_cube_map") || - isGLExtensionSupported("GL_EXT_texture_cube_map"); - - if (!s_CubeMapSupported) - return; - // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. const uint contextID = state.getContextID(); + const Extensions* extensions = getExtensions(contextID,true); + + if (!extensions->isCubeMapSupported()) + return; // get the globj for the current contextID. GLuint& handle = getTextureObject(contextID); @@ -244,3 +242,40 @@ void TextureCubeMap::apply(State& state) const glBindTexture( GL_TEXTURE_CUBE_MAP, 0 ); } } + +typedef buffered_value< ref_ptr > BufferedExtensions; +static BufferedExtensions s_extensions; + +const TextureCubeMap::Extensions* TextureCubeMap::getExtensions(uint contextID,bool createIfNotInitalized) +{ + if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions; + return s_extensions[contextID].get(); +} + +void TextureCubeMap::setExtensions(uint contextID,Extensions* extensions) +{ + s_extensions[contextID] = extensions; +} + +TextureCubeMap::Extensions::Extensions() +{ + setupGLExtenions(); +} + +TextureCubeMap::Extensions::Extensions(const Extensions& rhs): + Referenced() +{ + _isCubeMapSupported = rhs._isCubeMapSupported; +} + +void TextureCubeMap::Extensions::lowestCommonDenominator(const Extensions& rhs) +{ + if (!rhs._isCubeMapSupported) _isCubeMapSupported = false; +} + +void TextureCubeMap::Extensions::setupGLExtenions() +{ + _isCubeMapSupported = isGLExtensionSupported("GL_ARB_texture_cube_map") || + isGLExtensionSupported("GL_EXT_texture_cube_map") || + strncmp((const char*)glGetString(GL_VERSION),"1.3",3)>=0;; +}