diff --git a/include/ACGL/OpenGL/Objects.hh b/include/ACGL/OpenGL/Objects.hh index 6c73332807e6db8a92c3c23c48331c19211027c7..3da8f33bcc100881a3becfaaf076e467d4ce749f 100644 --- a/include/ACGL/OpenGL/Objects.hh +++ b/include/ACGL/OpenGL/Objects.hh @@ -16,6 +16,7 @@ #include <ACGL/OpenGL/Objects/ElementArrayBuffer.hh> #include <ACGL/OpenGL/Objects/FrameBufferObject.hh> #include <ACGL/OpenGL/Objects/RenderBuffer.hh> +#include <ACGL/OpenGL/Objects/UniformBuffer.hh> #include <ACGL/OpenGL/Objects/RenderObject.hh> #include <ACGL/OpenGL/Objects/Shader.hh> #include <ACGL/OpenGL/Objects/ShaderProgram.hh> diff --git a/include/ACGL/OpenGL/Objects/Buffer.hh b/include/ACGL/OpenGL/Objects/Buffer.hh index a333bab6e0c8a8e561937379b2d602f7506ede83..08ff352caa3b36006b8637b3acc44ed032d747b7 100644 --- a/include/ACGL/OpenGL/Objects/Buffer.hh +++ b/include/ACGL/OpenGL/Objects/Buffer.hh @@ -150,6 +150,7 @@ public: inline GLint getAccessFlags() { return (GLint) getParameter ( GL_BUFFER_ACCESS_FLAGS ); } inline GLboolean isMapped() { return (GLboolean) getParameter ( GL_BUFFER_MAPPED ); } + //! the size is in bytes inline GLint64 getSize() { return mSize; } //! Bind this buffer @@ -233,8 +234,29 @@ public: flushMappedRange( mTarget, _offset, _length ); } - // TODO: bindBufferRange - // TODO: bindBufferBase + //! valid targets are only GL_TRANSFORM_FEEDBACK_BUFFER and GL_UNIFORM_BUFFER + inline void bindBufferRange( GLenum _target, GLuint _index, GLintptr _offset, GLsizeiptr _size ) { + glBindBufferRange( _target, _index, mBuffer->mObjectName, _offset, _size ); + } + + //! maps a subset of the buffer defined by _offset and _size + //! valid targets are only GL_TRANSFORM_FEEDBACK_BUFFER and GL_UNIFORM_BUFFER + inline void bindBufferRange( GLuint _index, GLintptr _offset, GLsizeiptr _size ) { + glBindBufferRange( mTarget, _index, mBuffer->mObjectName, _offset, _size ); + } + + //! maps the full buffer to the given index (binding point) + //! valid targets are only GL_TRANSFORM_FEEDBACK_BUFFER and GL_UNIFORM_BUFFER + inline void bindBufferBase( GLenum _target, GLuint _index ) { + glBindBufferBase( _target, _index, mBuffer->mObjectName ); + } + + //! maps the full buffer to the given index (binding point) + //! valid targets are only GL_TRANSFORM_FEEDBACK_BUFFER and GL_UNIFORM_BUFFER + inline void bindBufferBase( GLuint _index ) { + glBindBufferBase( mTarget, _index, mBuffer->mObjectName ); + } + #endif // OpenGL >= 3.0 //! Maps the whole buffer, if using GL 3+, better use mapRange! diff --git a/include/ACGL/OpenGL/Objects/ShaderProgram.hh b/include/ACGL/OpenGL/Objects/ShaderProgram.hh index 0e928e90a0dd6506a6262f03ba0aca0a86ec1ddb..a3dcb3b45c8242449c2d9b71cbdc3ce05833cb5e 100644 --- a/include/ACGL/OpenGL/Objects/ShaderProgram.hh +++ b/include/ACGL/OpenGL/Objects/ShaderProgram.hh @@ -110,12 +110,29 @@ public: // =========================================================================================== LOCATIONS \/ // ===================================================================================================== \/ - //////////// uniform locations: - inline GLint getUniformLocation (const std::string& _nameInShader) const { return glGetUniformLocation (mObjectName, _nameInShader.c_str()); } + //////////// uniform (block) locations: + inline GLint getUniformLocation (const std::string& _nameInShader) const { return glGetUniformLocation (mObjectName, _nameInShader.c_str()); } + +#if (ACGL_OPENGL_VERSION >= 31) + //! if the block name does not exist, GL_INVALID_INDEX will get returned + inline GLuint getUniformBlockIndex (const std::string& _nameInShader) { return glGetUniformBlockIndex(mObjectName, _nameInShader.c_str()); } + + inline void setUniformBlockBinding( GLuint _blockIndex, GLuint _bindingPoint ) { glUniformBlockBinding( mObjectName, _blockIndex, _bindingPoint ); } + inline void setUniformBlockBinding( const std::string& _blockName, GLuint _bindingPoint ) { glUniformBlockBinding( mObjectName, getUniformBlockIndex(_blockName), _bindingPoint ); } + + //! returns a mapping from the uniforms in a given block to the offset within the block + SharedLocationMappings getUniformOffsetsOfBlock( const std::string &_blockName ) { return getUniformOffsetsOfBlock(getUniformBlockIndex(_blockName)); } + SharedLocationMappings getUniformOffsetsOfBlock( GLuint _blockIndex ); + + //! returns the size in bytes of the uniform block, can be used to allocate the right amount of memory + GLsizeiptr getUniformBlockSize( const std::string &_blockName ) { return getUniformBlockSize(getUniformBlockIndex(_blockName)); } + GLsizeiptr getUniformBlockSize( GLuint _blockIndex ); + +#endif // OpenGL >= 3.1 //////////// attribute locations: - inline GLint getAttributeLocation (const std::string& _nameInShader) const { return glGetAttribLocation (mObjectName, _nameInShader.c_str()); } - inline void bindAttributeLocation (const std::string& _nameInShader, GLuint _location) const { glBindAttribLocation (mObjectName, _location, _nameInShader.c_str()); } + inline GLint getAttributeLocation (const std::string& _nameInShader) const { return glGetAttribLocation (mObjectName, _nameInShader.c_str()); } + inline void bindAttributeLocation (const std::string& _nameInShader, GLuint _location) const { glBindAttribLocation (mObjectName, _location, _nameInShader.c_str()); } //! Sets the attribute locations of this ShaderProgram according to the mappings specified in void setAttributeLocations( ConstSharedLocationMappings _locationMappings ); @@ -124,6 +141,7 @@ public: //////////// fragdata locations: #if (ACGL_OPENGL_VERSION >= 30) + //! if the location does not exist, -1 will get returned inline GLint getFragmentDataLocation (const std::string& _nameInShader) const { return glGetFragDataLocation(mObjectName, _nameInShader.c_str()); } inline void bindFragmentDataLocation (const std::string& _nameInShader, GLuint _location) const { glBindFragDataLocation (mObjectName, _location, _nameInShader.c_str()); } diff --git a/include/ACGL/OpenGL/Objects/UniformBuffer.hh b/include/ACGL/OpenGL/Objects/UniformBuffer.hh new file mode 100644 index 0000000000000000000000000000000000000000..4a097f533787b143394c40f5e823f7bdd0333b2f --- /dev/null +++ b/include/ACGL/OpenGL/Objects/UniformBuffer.hh @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2012, Computer Graphics Group RWTH Aachen University // +// All rights reserved. // +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ACGL_OPENGL_OBJECTS_UNIFORM_BUFFER_HH +#define ACGL_OPENGL_OBJECTS_UNIFORM_BUFFER_HH + +#include <ACGL/ACGL.hh> + +#include <ACGL/Base/Macros.hh> +#include <ACGL/OpenGL/GL.hh> +#include <ACGL/OpenGL/Tools.hh> +#include <ACGL/OpenGL/Objects/Buffer.hh> + +#include <ACGL/OpenGL/Objects/LocationMappings.hh> +#include <ACGL/Math/Math.hh> + +namespace ACGL{ +namespace OpenGL{ + +/** + * An OpenGL Uniform Buffer Object that can be used to share blocks of uniforms between multiple ShaderPrograms. + */ + +#if (ACGL_OPENGL_VERSION >= 31) + +class UniformBuffer : public Buffer +{ + // ========================================================================================================= \/ + // ============================================================================================ CONSTRUCTORS \/ + // ========================================================================================================= \/ +public: + UniformBuffer() + : Buffer(GL_UNIFORM_BUFFER) + {} + + UniformBuffer( SharedBufferObject _pBuffer ) + : Buffer(_pBuffer, GL_UNIFORM_BUFFER) + {} + + // ==================================================================================================== \/ + // ============================================================================================ GETTERS \/ + // ==================================================================================================== \/ +public: + GLint getUniformOffset (const std::string& _nameInShader) const { + if (!uniformNameToOffsetMap) return -1; + return uniformNameToOffsetMap->getLocation(_nameInShader); + } + void setUniformOffsets (SharedLocationMappings _uniformNameToOffsetMap) { uniformNameToOffsetMap = _uniformNameToOffsetMap; } + + // ==================================================================================================== \/ + // ============================================================================================ SETTERS \/ + // ==================================================================================================== \/ +public: + //! reserve a number of bytes on the GPU for uniforms + inline void reserveMemory(GLsizeiptr _size){ setData( _size, NULL, GL_STREAM_DRAW ); } + + // for scalar types: + inline void setUniform (const std::string &_nameInShader, GLfloat _v) { setUniformScalar<GLfloat> (_nameInShader, _v); } + inline void setUniform (const std::string &_nameInShader, GLint _v) { setUniformScalar<GLint> (_nameInShader, _v); } + inline void setUniform (const std::string &_nameInShader, GLuint _v) { setUniformScalar<GLuint> (_nameInShader, _v); } + inline void setUniform (const std::string &_nameInShader, GLboolean _v) { setUniformScalar<GLboolean>(_nameInShader, _v); } + inline void setUniform (const std::string &_nameInShader, GLdouble _v) { setUniformScalar<GLdouble> (_nameInShader, _v); } + + // for GLM types: + template <typename T> + void setUniform (const std::string &_nameInShader, T _v) { + GLint offset = getUniformOffset( _nameInShader ); + if (offset == -1) { + ACGL::Utils::error() << "UniformBuffer does not know uniform " << _nameInShader << std::endl; + return; + } + setSubData( offset, sizeof(T), glm::value_ptr(_v) ); + } + + // =================================================================================================== \/ + // ============================================================================================ FIELDS \/ + // =================================================================================================== \/ +private: + // for scalar types: + template <typename T> + void setUniformScalar (const std::string &_nameInShader, T _v) { + GLint offset = getUniformOffset( _nameInShader ); + if (offset == -1) { + ACGL::Utils::error() << "UniformBuffer does not know uniform " << _nameInShader << std::endl; + return; + } + setSubData( offset, sizeof(T), &_v ); + } + + SharedLocationMappings uniformNameToOffsetMap; +}; + +ACGL_SMARTPOINTER_TYPEDEFS(UniformBuffer) +#endif // OpenGL >= 3.1 + +} // OpenGL +} // ACGL + +#endif // ACGL_OPENGL_OBJECTS_UNIFORM_BUFFER_HH diff --git a/src/ACGL/OpenGL/Objects/ShaderProgram.cc b/src/ACGL/OpenGL/Objects/ShaderProgram.cc index b24b6740b1e22e94725bb73ea3e39433ac8561d7..f1aaef31e3edce9fd34814daf3f5cfff817e546b 100644 --- a/src/ACGL/OpenGL/Objects/ShaderProgram.cc +++ b/src/ACGL/OpenGL/Objects/ShaderProgram.cc @@ -133,14 +133,14 @@ SharedLocationMappings ShaderProgram::getAttributeLocations() GLint size; GLsizei length; glGetActiveAttrib( mObjectName, i, longestAttributeName, &length, &size, &type, name ); - name[ length+1 ] = 0; // null terminate + name[ length+1 ] = 0; // null terminate string GLint attribLocation = glGetAttribLocation( mObjectName, name ); locationMap->setLocation( std::string(name), (GLuint) attribLocation ); } - delete name; + delete[] name; return locationMap; } @@ -153,3 +153,53 @@ SharedLocationMappings ShaderProgram::getFragmentDataLocations() return locationMap; } +SharedLocationMappings ShaderProgram::getUniformOffsetsOfBlock( GLuint _blockIndex ) +{ + SharedLocationMappings locationMap = SharedLocationMappings( new LocationMappings() ); + + if (_blockIndex == GL_INVALID_INDEX) return locationMap; // block does not exist + + // query the number of _active_ uniforms: + GLint uniformCount; + glGetProgramiv( mObjectName, GL_ACTIVE_UNIFORMS, &uniformCount ); + if (uniformCount == 0) return locationMap; + + // reserve a string long enought for the longest name: + GLint longestUniformName; + glGetProgramiv( mObjectName, GL_ACTIVE_UNIFORM_MAX_LENGTH, &longestUniformName ); + char *name = new char[longestUniformName+1]; + + // get the name and location of each active attribute: + for (int i = 0; i < uniformCount; ++i) { + GLsizei length; + glGetActiveUniformName( mObjectName, i, longestUniformName, &length, name ); + + name[ length+1 ] = 0; // null terminate string + + GLuint idx = i; + GLint uniformBlockIndex; + glGetActiveUniformsiv( mObjectName, 1, &idx, GL_UNIFORM_BLOCK_INDEX, &uniformBlockIndex ); + + if (uniformBlockIndex != -1) { + if ((GLuint)uniformBlockIndex == _blockIndex) { + GLint offset; + glGetActiveUniformsiv( mObjectName, 1, &idx, GL_UNIFORM_OFFSET, &offset ); + //ACGL::Utils::message() << "uniform " << i << " is " << name << " block: " << uniformBlockIndex << " offset: " << offset << std::endl; + locationMap->setLocation( std::string(name), (GLuint) offset ); + } + } + } + + delete[] name; + return locationMap; +} + +GLsizeiptr ShaderProgram::getUniformBlockSize( GLuint _blockIndex ) +{ + if (_blockIndex == GL_INVALID_INDEX) return 0; // block does not exist + + GLint uniformBlockSize; + glGetActiveUniformBlockiv( mObjectName, _blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &uniformBlockSize); + + return (GLsizeiptr) uniformBlockSize; +} diff --git a/src/ACGL/OpenGL/Objects/UniformBuffer.cc b/src/ACGL/OpenGL/Objects/UniformBuffer.cc new file mode 100644 index 0000000000000000000000000000000000000000..f0115a08d176728debc40b47ef4d7b3c1fc23bec --- /dev/null +++ b/src/ACGL/OpenGL/Objects/UniformBuffer.cc @@ -0,0 +1,15 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University // +// All rights reserved. // +//////////////////////////////////////////////////////////////////////////////// + +#include <ACGL/OpenGL/Objects/UniformBuffer.hh> + +using namespace ACGL; +using namespace ACGL::OpenGL; + +#if (ACGL_OPENGL_VERSION >= 31) + + + +#endif // OpenGL 3.1