From 1284a0dd40051738f7073afdd41667d960631f8b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 22 May 2013 12:49:46 +0000 Subject: [PATCH] From Pawel Ksiezopolski, first email: "This submission adds texture buffer object ( defined in GL_ARB_texture_buffer_object extension ) to the osg::Texture* family. TextureBuffer objects may use osg::Texture::bindToImageUnit(), so GLSL shaders are able to use not only texelFetch() function , but also functions defined in GL_ARB_shader_image_load_store extension : imageLoad(), imageStore(), imageAtomicAdd() etc." second email: "After a while I found that osg::Texture::applyTexParameters() used with TextureBuffer may cause some OpenGL errors ( applying texture filters and wraps to TextureBuffer makes no sense ) so I fixed it." --- include/osg/BufferObject | 5 + include/osg/TextureBuffer | 146 ++++++++++++++++++++++++++ src/osg/BufferObject.cpp | 14 ++- src/osg/CMakeLists.txt | 2 + src/osg/TextureBuffer.cpp | 212 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 include/osg/TextureBuffer create mode 100644 src/osg/TextureBuffer.cpp diff --git a/include/osg/BufferObject b/include/osg/BufferObject index 9cc17eaac..f5c98cbae 100644 --- a/include/osg/BufferObject +++ b/include/osg/BufferObject @@ -271,6 +271,7 @@ class OSG_EXPORT GLBufferObject : public Referenced bool isBufferObjectSupported() const { return _glGenBuffers!=0; } bool isPBOSupported() const { return _isPBOSupported; } bool isUniformBufferObjectSupported() const { return _isUniformBufferObjectSupported; } + bool isTBOSupported() const { return _isTBOSupported; } void glGenBuffers (GLsizei n, GLuint *buffers) const; void glBindBuffer (GLenum target, GLuint buffer) const; @@ -285,6 +286,7 @@ class OSG_EXPORT GLBufferObject : public Referenced void glGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params) const; void glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); void glBindBufferBase (GLenum target, GLuint index, GLuint buffer); + void glTexBuffer( GLenum target, GLenum internalFormat, GLuint buffer ) const; protected: @@ -301,6 +303,7 @@ class OSG_EXPORT GLBufferObject : public Referenced typedef void (GL_APIENTRY * GetBufferPointervProc) (GLenum target, GLenum pname, GLvoid* *params); typedef void (GL_APIENTRY * BindBufferRangeProc) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (GL_APIENTRY * BindBufferBaseProc) (GLenum target, GLuint index, GLuint buffer); + typedef void (GL_APIENTRY *TexBufferProc ) ( GLenum target, GLenum internalFormat, GLuint buffer ); GenBuffersProc _glGenBuffers; @@ -316,9 +319,11 @@ class OSG_EXPORT GLBufferObject : public Referenced GetBufferPointervProc _glGetBufferPointerv; BindBufferRangeProc _glBindBufferRange; BindBufferBaseProc _glBindBufferBase; + TexBufferProc _glTexBuffer; bool _isPBOSupported; bool _isUniformBufferObjectSupported; + bool _isTBOSupported; }; /** Function to call to get the extension of a specified context. diff --git a/include/osg/TextureBuffer b/include/osg/TextureBuffer new file mode 100644 index 000000000..c9ef66dbc --- /dev/null +++ b/include/osg/TextureBuffer @@ -0,0 +1,146 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// -*-c++-*- + +#ifndef OSG_TEXTUREBUFFEROBJECT +#define OSG_TEXTUREBUFFEROBJECT 1 + +#include +#include + +#ifndef GL_ARB_texture_buffer_object + #define GL_TEXTURE_BUFFER_ARB 0x8C2A + #define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B + #define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C + #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D + #define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E +#endif + +namespace osg { + +/** Encapsulates OpenGL texture buffer functionality. +*/ +class OSG_EXPORT TextureBuffer : public Texture +{ + + public : + + TextureBuffer(); + + TextureBuffer(Image* image); + + /** Copy constructor using CopyOp to manage deep vs shallow copy. */ + TextureBuffer(const TextureBuffer& text,const CopyOp& copyop=CopyOp::SHALLOW_COPY); + + META_StateAttribute(osg, TextureBuffer, TEXTURE); + + /** Return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */ + virtual int compare(const StateAttribute& rhs) const; + + virtual GLenum getTextureTarget() const { return GL_TEXTURE_BUFFER_ARB; } + + /** Sets the texture image. */ + void setImage(Image* image); + + /** Gets the texture image. */ + Image* getImage() { return _image.get(); } + + /** Gets the const texture image. */ + inline const Image* getImage() const { return _image.get(); } + + inline unsigned int& getModifiedCount(unsigned int contextID) const + { + // get the modified count for the current contextID. + return _modifiedCount[contextID]; + } + + + /** Sets the texture image, ignoring face. */ + virtual void setImage(unsigned int, Image* image) { setImage(image); } + + /** Gets the texture image, ignoring face. */ + virtual Image* getImage(unsigned int) { return _image.get(); } + + /** Gets the const texture image, ignoring face. */ + virtual const Image* getImage(unsigned int) const { return _image.get(); } + + /** Gets the number of images that can be assigned to the Texture. */ + virtual unsigned int getNumImages() const { return 1; } + + + /** Sets the texture width. If width is zero, calculate the value + * from the source image width. */ + inline void setTextureWidth(int width) { _textureWidth = width; } + + /** Gets the texture width. */ + virtual int getTextureWidth() const { return _textureWidth; } + virtual int getTextureHeight() const { return 1; } + virtual int getTextureDepth() const { return 1; } + + inline void setUsageHint( GLenum usageHint ) { _usageHint=usageHint; } + inline GLenum getUsageHint() const { return _usageHint; } + + virtual void allocateMipmap(State& state) const {}; + + /** Bind the texture buffer.*/ + virtual void apply(State& state) const; + + /** Bind buffer to different target. */ + void bindBufferAs(unsigned int contextID, GLenum target); + void unbindBufferAs(unsigned int contextID, GLenum target); + + protected : + + virtual ~TextureBuffer(); + + virtual void computeInternalFormat() const; + + ref_ptr _image; + + mutable GLsizei _textureWidth; + GLenum _usageHint; + + typedef buffered_value ImageModifiedCount; + mutable ImageModifiedCount _modifiedCount; + + class TextureBufferObject : public osg::Referenced + { + public: + TextureBufferObject(unsigned int contextID, GLenum usageHint) : + _id(0), + _usageHint(usageHint) + { + _extensions = osg::GLBufferObject::getExtensions(contextID, true); + } + + void bindBuffer(GLenum target); + void unbindBuffer(GLenum target); + + void texBuffer(GLenum internalFormat); + void bufferData( osg::Image* image ); + void bufferSubData( osg::Image* image ); + + public: + GLuint _id; + GLenum _usageHint; + osg::GLBufferObject::Extensions* _extensions; + }; + + typedef osg::buffered_object > TextureBufferObjectList; + mutable TextureBufferObjectList _textureBufferObjects; +}; + +} + +#endif diff --git a/src/osg/BufferObject.cpp b/src/osg/BufferObject.cpp index 85772b299..2ef8d2c3e 100644 --- a/src/osg/BufferObject.cpp +++ b/src/osg/BufferObject.cpp @@ -278,6 +278,7 @@ GLBufferObject::Extensions::Extensions(const Extensions& rhs): _glGetBufferPointerv = rhs._glGetBufferPointerv; _glBindBufferRange = rhs._glBindBufferRange; _glBindBufferBase = rhs._glBindBufferBase; + _glTexBuffer = rhs._glTexBuffer; } @@ -297,9 +298,11 @@ void GLBufferObject::Extensions::lowestCommonDenominator(const Extensions& rhs) if (!rhs._glGetBufferParameteriv) _glGetBufferPointerv = rhs._glGetBufferPointerv; if (!rhs._glBindBufferRange) _glBindBufferRange = rhs._glBindBufferRange; if (!rhs._glBindBufferBase) _glBindBufferBase = rhs._glBindBufferBase; + if (!rhs._glTexBuffer) _glTexBuffer = rhs._glTexBuffer; _isPBOSupported = rhs._isPBOSupported; _isUniformBufferObjectSupported = rhs._isUniformBufferObjectSupported; + _isTBOSupported = rhs._isTBOSupported; } void GLBufferObject::Extensions::setupGLExtensions(unsigned int contextID) @@ -317,9 +320,11 @@ void GLBufferObject::Extensions::setupGLExtensions(unsigned int contextID) setGLExtensionFuncPtr(_glGetBufferPointerv, "glGetBufferPointerv","glGetBufferPointervARB"); setGLExtensionFuncPtr(_glBindBufferRange, "glBindBufferRange"); setGLExtensionFuncPtr(_glBindBufferBase, "glBindBufferBase"); - + setGLExtensionFuncPtr(_glTexBuffer, "glTexBuffer","glTexBufferARB" ); + _isPBOSupported = OSG_GL3_FEATURES || osg::isGLExtensionSupported(contextID,"GL_ARB_pixel_buffer_object"); _isUniformBufferObjectSupported = osg::isGLExtensionSupported(contextID, "GL_ARB_uniform_buffer_object"); + _isTBOSupported = osg::isGLExtensionSupported(contextID,"GL_ARB_texture_buffer_object"); } void GLBufferObject::Extensions::glGenBuffers(GLsizei n, GLuint *buffers) const @@ -411,6 +416,13 @@ void GLBufferObject::Extensions::glBindBufferBase (GLenum target, GLuint index, if (_glBindBufferBase) _glBindBufferBase(target, index, buffer); else OSG_WARN<<"Error: glBindBufferBase not supported by OpenGL driver\n"; } + +void GLBufferObject::Extensions::glTexBuffer( GLenum target, GLenum internalFormat, GLuint buffer ) const +{ + if ( _glTexBuffer ) _glTexBuffer( target, internalFormat, buffer ); + else OSG_WARN<<"Error: glTexBuffer not supported by OpenGL driver\n"; +} + ////////////////////////////////////////////////////////////////////////////////////////////////////// // // GLBufferObjectSet diff --git a/src/osg/CMakeLists.txt b/src/osg/CMakeLists.txt index 944e67ccb..be2324cdb 100644 --- a/src/osg/CMakeLists.txt +++ b/src/osg/CMakeLists.txt @@ -165,6 +165,7 @@ SET(TARGET_H ${HEADER_PATH}/Texture2DMultisample ${HEADER_PATH}/Texture2DArray ${HEADER_PATH}/Texture3D + ${HEADER_PATH}/TextureBuffer ${HEADER_PATH}/TextureCubeMap ${HEADER_PATH}/TextureRectangle ${HEADER_PATH}/Timer @@ -335,6 +336,7 @@ SET(TARGET_SRC Texture2DMultisample.cpp Texture3D.cpp Texture.cpp + TextureBuffer.cpp TextureCubeMap.cpp TextureRectangle.cpp Timer.cpp diff --git a/src/osg/TextureBuffer.cpp b/src/osg/TextureBuffer.cpp new file mode 100644 index 000000000..6af11bd19 --- /dev/null +++ b/src/osg/TextureBuffer.cpp @@ -0,0 +1,212 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ +#include +#include + +using namespace osg; + +TextureBuffer::TextureBuffer(): + _textureWidth(0), _usageHint(GL_STREAM_DRAW) +{ +} + +TextureBuffer::TextureBuffer(osg::Image* image): + _textureWidth(0), _usageHint(GL_STREAM_DRAW) +{ + setImage(image); +} + +TextureBuffer::TextureBuffer(const TextureBuffer& text,const CopyOp& copyop): + Texture(text,copyop), + _image(copyop(text._image.get())), + _textureWidth(text._textureWidth), + _usageHint(text._usageHint) +{ +} + +TextureBuffer::~TextureBuffer() +{ +} + +int TextureBuffer::compare(const StateAttribute& sa) const +{ + // check the types are equal and then create the rhs variable + // used by the COMPARE_StateAttribute_Parameter macros below. + COMPARE_StateAttribute_Types(TextureBuffer,sa) + + if (_image!=rhs._image) // smart pointer comparison. + { + if (_image.valid()) + { + if (rhs._image.valid()) + { + int result = _image->compare(*rhs._image); + if (result!=0) return result; + } + else + { + return 1; // valid lhs._image is greater than null. + } + } + else if (rhs._image.valid()) + { + return -1; // valid rhs._image is greater than null. + } + } + + if (!_image && !rhs._image) + { + int result = compareTextureObjects(rhs); + if (result!=0) return result; + } + + int result = compareTexture(rhs); + if (result!=0) return result; + + // compare each parameter in turn against the rhs. + COMPARE_StateAttribute_Parameter(_textureWidth) + COMPARE_StateAttribute_Parameter(_usageHint) + + return 0; +} + +void TextureBuffer::setImage(Image* image) +{ + if (_image == image) return; + + _image = image; + _modifiedCount.setAllElementsTo(0); +} + + +void TextureBuffer::apply(State& state) const +{ +#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) + const unsigned int contextID = state.getContextID(); + + TextureObject* textureObject = getTextureObject(contextID); + TextureBufferObject* textureBufferObject = _textureBufferObjects[contextID].get(); + + + if (textureObject) + { + if (_image.valid() && getModifiedCount(contextID) != _image->getModifiedCount()) + { + computeInternalFormat(); + textureBufferObject->bindBuffer(GL_TEXTURE_BUFFER_ARB); + textureBufferObject->bufferSubData(_image.get() ); + textureBufferObject->unbindBuffer(GL_TEXTURE_BUFFER_ARB); + _modifiedCount[contextID] = _image->getModifiedCount(); + } + textureObject->bind(); + + if( getTextureParameterDirty(contextID) ) + { + const Extensions* extensions = Texture::getExtensions(contextID,true); + if (extensions->isBindImageTextureSupported() && _imageAttachment.access!=0) + { + extensions->glBindImageTexture( + _imageAttachment.unit, textureObject->id(), _imageAttachment.level, + _imageAttachment.layered, _imageAttachment.layer, _imageAttachment.access, + _imageAttachment.format!=0 ? _imageAttachment.format : _internalFormat); + } + getTextureParameterDirty(state.getContextID()) = false; + } + } + else if (_image.valid() && _image->data()) + { + textureObject = generateTextureObject(this, contextID,GL_TEXTURE_BUFFER_ARB); + _textureObjectBuffer[contextID] = textureObject; + textureObject->bind(); + + textureBufferObject = new TextureBufferObject(contextID,_usageHint); + _textureBufferObjects[contextID] = textureBufferObject; + + const Extensions* extensions = Texture::getExtensions(contextID,true); + if (extensions->isBindImageTextureSupported() && _imageAttachment.access!=0) + { + extensions->glBindImageTexture( + _imageAttachment.unit, textureObject->id(), _imageAttachment.level, + _imageAttachment.layered, _imageAttachment.layer, _imageAttachment.access, + _imageAttachment.format!=0 ? _imageAttachment.format : _internalFormat); + } + getTextureParameterDirty(state.getContextID()) = false; + + computeInternalFormat(); + _textureWidth = _image->s(); + textureBufferObject->bindBuffer(GL_TEXTURE_BUFFER_ARB); + textureBufferObject->bufferData( _image.get() ); + textureObject->setAllocated(true); + textureBufferObject->unbindBuffer(GL_TEXTURE_BUFFER_ARB); + + textureObject->bind(); + textureBufferObject->texBuffer(_internalFormat); + + _modifiedCount[contextID] = _image->getModifiedCount(); + } + else + { + glBindTexture(GL_TEXTURE_BUFFER_ARB, 0); + } + +#else + OSG_NOTICE<<"Warning: TextureBuffer::apply(State& state) not supported."<bindBuffer(target); + +} + +void TextureBuffer::unbindBufferAs( unsigned int contextID, GLuint target ) +{ + TextureBufferObject* textureBufferObject = _textureBufferObjects[contextID].get(); + textureBufferObject->unbindBuffer(target); +} + + +void TextureBuffer::computeInternalFormat() const +{ + if (_image.valid()) computeInternalFormatWithImage(*_image); + else computeInternalFormatType(); +} + +void TextureBuffer::TextureBufferObject::bindBuffer(GLenum target) +{ + if (_id == 0) + _extensions->glGenBuffers(1, &_id); + _extensions->glBindBuffer(target, _id); +} + +void TextureBuffer::TextureBufferObject::unbindBuffer(GLenum target) +{ + _extensions->glBindBuffer(target, 0); +} + +void TextureBuffer::TextureBufferObject::texBuffer(GLenum internalFormat) +{ + _extensions->glTexBuffer(GL_TEXTURE_BUFFER_ARB, internalFormat, _id); +} + +void TextureBuffer::TextureBufferObject::bufferData( osg::Image* image ) +{ + _extensions->glBufferData(GL_TEXTURE_BUFFER_ARB, image->getTotalDataSize(), image->data(), _usageHint); +} + +void TextureBuffer::TextureBufferObject::bufferSubData( osg::Image* image ) +{ + _extensions->glBufferSubData(GL_TEXTURE_BUFFER_ARB, 0, image->getTotalDataSize(), image->data()); +}