diff --git a/src/engine/renderer/GLMemory.h b/src/engine/renderer/GLMemory.h index faba711ec7..69f56ac74d 100644 --- a/src/engine/renderer/GLMemory.h +++ b/src/engine/renderer/GLMemory.h @@ -36,7 +36,252 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef GLMEMORY_H #define GLMEMORY_H -#include "gl_shader.h" +#include "common/Common.h" +#include "GL/glew.h" +#include "tr_local.h" +#include "BufferBind.h" + +class GLBuffer { + public: + friend class GLVAO; + + std::string name; + const GLuint64 SYNC_TIMEOUT = 10000000000; // 10 seconds + + GLuint id; + + GLBuffer( const char* newName, const GLuint newBindingPoint, const GLbitfield newFlags, const GLbitfield newMapFlags ) : + name( newName ), + internalTarget( 0 ), + internalBindingPoint( newBindingPoint ), + flags( newFlags ), + mapFlags( newMapFlags ) { + } + + GLBuffer( const char* newName, const GLenum newTarget, const GLuint newBindingPoint, + const GLbitfield newFlags, const GLbitfield newMapFlags ) : + name( newName ), + internalTarget( newTarget ), + internalBindingPoint( newBindingPoint ), + flags( newFlags ), + mapFlags( newMapFlags ) { + } + + void BindBufferBase( GLenum target = 0, GLuint bindingPoint = 0 ) { + target = target ? target : internalTarget; + bindingPoint = bindingPoint ? bindingPoint : internalBindingPoint; + glBindBufferBase( target, bindingPoint, id ); + } + + void UnBindBufferBase( GLenum target = 0, GLuint bindingPoint = 0 ) { + target = target ? target : internalTarget; + bindingPoint = bindingPoint ? bindingPoint : internalBindingPoint; + glBindBufferBase( target, bindingPoint, 0 ); + } + + void BindBuffer( GLenum target = 0 ) { + target = target ? target : internalTarget; + glBindBuffer( target, id ); + } + + void UnBindBuffer( GLenum target = 0 ) { + target = target ? target : internalTarget; + glBindBuffer( target, 0 ); + } + + void BufferData( const GLsizeiptr size, const void* data, const GLenum usageFlags ) { + glNamedBufferData( id, size * sizeof( uint32_t ), data, usageFlags ); + } + + void BufferStorage( const GLsizeiptr newAreaSize, const GLsizeiptr areaCount, const void* data ) { + areaSize = newAreaSize; + maxAreas = areaCount; + glNamedBufferStorage( id, areaSize * areaCount * sizeof( uint32_t ), data, flags ); + syncs.resize( areaCount ); + + GL_CheckErrors(); + } + + void AreaIncr() { + syncs[area] = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); + area++; + if ( area >= maxAreas ) { + area = 0; + } + } + + void MapAll() { + if ( !mapped ) { + mapped = true; + data = ( uint32_t* ) glMapNamedBufferRange( id, 0, areaSize * maxAreas * sizeof( uint32_t ), flags | mapFlags ); + } + } + + uint32_t* GetCurrentAreaData() { + if ( syncs[area] != nullptr ) { + if ( glClientWaitSync( syncs[area], GL_SYNC_FLUSH_COMMANDS_BIT, SYNC_TIMEOUT ) == GL_TIMEOUT_EXPIRED ) { + Sys::Drop( "Failed buffer %s area %u sync", name, area ); + } + glDeleteSync( syncs[area] ); + } + + return data + area * areaSize; + } + + uint32_t* GetData() { + return data; + } + + void FlushCurrentArea() { + glFlushMappedNamedBufferRange( id, area * areaSize * sizeof( uint32_t ), areaSize * sizeof( uint32_t ) ); + } + + void FlushAll() { + glFlushMappedNamedBufferRange( id, 0, maxAreas * areaSize * sizeof( uint32_t ) ); + } + + void FlushRange( const GLsizeiptr offset, const GLsizeiptr size ) { + glFlushMappedNamedBufferRange( id, offset * sizeof( uint32_t ), size * sizeof( uint32_t ) ); + } + + uint32_t* MapBufferRange( const GLuint count ) { + return MapBufferRange( 0, count ); + } + + uint32_t* MapBufferRange( const GLuint offset, const GLuint count ) { + if ( !mapped ) { + mapped = true; + data = ( uint32_t* ) glMapNamedBufferRange( id, + offset * sizeof( uint32_t ), count * sizeof( uint32_t ), + flags | mapFlags ); + } + + return data; + } + + void UnmapBuffer() { + if ( mapped ) { + mapped = false; + glUnmapNamedBuffer( id ); + } + } + + void GenBuffer() { + glCreateBuffers( 1, &id ); + } + + void DelBuffer() { + glDeleteBuffers( 1, &id ); + mapped = false; + } + + private: + const GLenum internalTarget; + const GLuint internalBindingPoint; + + bool mapped = false; + const GLbitfield flags; + const GLbitfield mapFlags; + + std::vector syncs; + GLsizeiptr area = 0; + GLsizeiptr areaSize = 0; + GLsizeiptr maxAreas = 0; + uint32_t* data; +}; + +// Shorthands for buffers that are only bound to one specific target +class GLSSBO : public GLBuffer { + public: + GLSSBO( const char* name, const GLuint bindingPoint, const GLbitfield flags, const GLbitfield mapFlags ) : + GLBuffer( name, GL_SHADER_STORAGE_BUFFER, bindingPoint, flags, mapFlags ) { + } +}; + +class GLUBO : public GLBuffer { + public: + GLUBO( const char* name, const GLsizeiptr bindingPoint, const GLbitfield flags, const GLbitfield mapFlags ) : + GLBuffer( name, GL_UNIFORM_BUFFER, bindingPoint, flags, mapFlags ) { + } +}; + +class GLAtomicCounterBuffer : public GLBuffer { + public: + GLAtomicCounterBuffer( const char* name, const GLsizeiptr bindingPoint, const GLbitfield flags, const GLbitfield mapFlags ) : + GLBuffer( name, GL_ATOMIC_COUNTER_BUFFER, bindingPoint, flags, mapFlags ) { + } +}; + +class GLVAO { + public: + vboAttributeLayout_t attrs[ATTR_INDEX_MAX]; + uint32_t enabledAttrs; + + GLVAO( const GLuint newVBOBindingPoint ) : + VBOBindingPoint( newVBOBindingPoint ) { + } + + ~GLVAO() = default; + + void Bind() { + glBindVertexArray( id ); + } + + void SetAttrs( const vertexAttributeSpec_t* attrBegin, const vertexAttributeSpec_t* attrEnd ) { + uint32_t ofs = 0; + for ( const vertexAttributeSpec_t* spec = attrBegin; spec < attrEnd; spec++ ) { + vboAttributeLayout_t& attr = attrs[spec->attrIndex]; + ASSERT_NQ( spec->numComponents, 0U ); + attr.componentType = spec->componentStorageType; + if ( attr.componentType == GL_HALF_FLOAT && !glConfig2.halfFloatVertexAvailable ) { + attr.componentType = GL_FLOAT; + } + attr.numComponents = spec->numComponents; + attr.normalize = spec->attrOptions & ATTR_OPTION_NORMALIZE ? GL_TRUE : GL_FALSE; + + attr.ofs = ofs; + ofs += attr.numComponents * R_ComponentSize( attr.componentType ); + ofs = ( ofs + 3 ) & ~3; // 4 is minimum alignment for any vertex attribute + + enabledAttrs |= 1 << spec->attrIndex; + } + + stride = ofs; + + for ( const vertexAttributeSpec_t* spec = attrBegin; spec < attrEnd; spec++ ) { + const int index = spec->attrIndex; + vboAttributeLayout_t& attr = attrs[index]; + + attr.stride = stride; + + glEnableVertexArrayAttrib( id, index ); + glVertexArrayAttribFormat( id, index, attr.numComponents, attr.componentType, + attr.normalize, attr.ofs ); + glVertexArrayAttribBinding( id, index, VBOBindingPoint ); + } + } + + void SetVertexBuffer( const GLBuffer buffer, const GLuint offset ) { + glVertexArrayVertexBuffer( id, VBOBindingPoint, buffer.id, offset, stride ); + } + + void SetIndexBuffer( const GLBuffer buffer ) { + glVertexArrayElementBuffer( id, buffer.id ); + } + + void GenVAO() { + glGenVertexArrays( 1, &id ); + } + + void DelVAO() { + glDeleteVertexArrays( 1, &id ); + } + + private: + GLuint id; + const GLuint VBOBindingPoint; + GLuint stride; +}; void GLBufferCopy( GLBuffer* src, GLBuffer* dst, GLintptr srcOffset, GLintptr dstOffset, GLsizeiptr size ); diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h index 8ce90cbb19..54d1309667 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -40,6 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "gl_shader.h" #include "tr_local.h" +#include "GLMemory.h" static constexpr uint32_t MAX_DRAWCOMMAND_TEXTURES = 64; diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index 1c5dc34c6c..e13df92ff8 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -307,6 +307,58 @@ struct ShaderProgramDescriptor { }; }; +class GLUniform { + public: + const std::string _name; + const std::string _type; + + // In multiples of 4 bytes + GLuint _std430Size; + const GLuint _std430Alignment; + + const bool _global; // This uniform won't go into the materials UBO if true + const int _components; + + protected: + GLShader* _shader; + size_t _firewallIndex; + size_t _locationIndex; + + GLUniform( GLShader* shader, const char* name, const char* type, const GLuint std430Size, const GLuint std430Alignment, + const bool global, const int components = 0 ) : + _name( name ), + _type( type ), + _std430Size( std430Size ), + _std430Alignment( std430Alignment ), + _global( global ), + _components( components ), + _shader( shader ) { + _shader->RegisterUniform( this ); + } + + public: + virtual ~GLUniform() = default; + + void SetFirewallIndex( size_t offSetValue ) { + _firewallIndex = offSetValue; + } + + void SetLocationIndex( size_t index ) { + _locationIndex = index; + } + + // This should return a pointer to the memory right after the one this uniform wrote to + virtual uint32_t* WriteToBuffer( uint32_t* buffer ); + + void UpdateShaderProgramUniformLocation( ShaderProgramDescriptor* shaderProgram ) { + shaderProgram->uniformLocations[_locationIndex] = glGetUniformLocation( shaderProgram->id, _name.c_str() ); + } + + virtual size_t GetSize() { + return 0; + } +}; + class GLShaderManager { std::queue _shaderBuildQueue; std::vector> _shaders; @@ -403,64 +455,6 @@ class GLShaderManager { void UpdateShaderProgramUniformLocations( GLShader* shader, ShaderProgramDescriptor* shaderProgram ) const; }; -class GLUniform -{ -public: - const std::string _name; - const std::string _type; - - // In multiples of 4 bytes - GLuint _std430Size; - const GLuint _std430Alignment; - - const bool _global; // This uniform won't go into the materials UBO if true - const int _components; - -protected: - GLShader *_shader; - size_t _firewallIndex; - size_t _locationIndex; - - GLUniform( GLShader *shader, const char *name, const char* type, const GLuint std430Size, const GLuint std430Alignment, - const bool global, const int components = 0 ) : - _name( name ), - _type( type ), - _std430Size( std430Size ), - _std430Alignment( std430Alignment ), - _global( global ), - _components( components ), - _shader( shader ) - { - _shader->RegisterUniform( this ); - } - -public: - virtual ~GLUniform() = default; - - void SetFirewallIndex( size_t offSetValue ) - { - _firewallIndex = offSetValue; - } - - void SetLocationIndex( size_t index ) - { - _locationIndex = index; - } - - // This should return a pointer to the memory right after the one this uniform wrote to - virtual uint32_t* WriteToBuffer( uint32_t* buffer ); - - void UpdateShaderProgramUniformLocation( ShaderProgramDescriptor* shaderProgram ) - { - shaderProgram->uniformLocations[_locationIndex] = glGetUniformLocation( shaderProgram->id, _name.c_str() ); - } - - virtual size_t GetSize() - { - return 0; - } -}; - class GLUniformSampler : protected GLUniform { protected: GLUniformSampler( GLShader* shader, const char* name, const char* type ) : @@ -1140,248 +1134,6 @@ class GLUniformBlock } }; -class GLBuffer { - public: - friend class GLVAO; - - std::string name; - const GLuint64 SYNC_TIMEOUT = 10000000000; // 10 seconds - - GLuint id; - - GLBuffer( const char* newName, const GLuint newBindingPoint, const GLbitfield newFlags, const GLbitfield newMapFlags ) : - name( newName ), - internalTarget( 0 ), - internalBindingPoint( newBindingPoint ), - flags( newFlags ), - mapFlags( newMapFlags ) { - } - - GLBuffer( const char* newName, const GLenum newTarget, const GLuint newBindingPoint, - const GLbitfield newFlags, const GLbitfield newMapFlags ) : - name( newName ), - internalTarget( newTarget ), - internalBindingPoint( newBindingPoint ), - flags( newFlags ), - mapFlags( newMapFlags ) { - } - - void BindBufferBase( GLenum target = 0, GLuint bindingPoint = 0 ) { - target = target ? target : internalTarget; - bindingPoint = bindingPoint ? bindingPoint : internalBindingPoint; - glBindBufferBase( target, bindingPoint, id ); - } - - void UnBindBufferBase( GLenum target = 0, GLuint bindingPoint = 0 ) { - target = target ? target : internalTarget; - bindingPoint = bindingPoint ? bindingPoint : internalBindingPoint; - glBindBufferBase( target, bindingPoint, 0 ); - } - - void BindBuffer( GLenum target = 0 ) { - target = target ? target : internalTarget; - glBindBuffer( target, id ); - } - - void UnBindBuffer( GLenum target = 0 ) { - target = target ? target : internalTarget; - glBindBuffer( target, 0 ); - } - - void BufferData( const GLsizeiptr size, const void* data, const GLenum usageFlags ) { - glNamedBufferData( id, size * sizeof( uint32_t ), data, usageFlags ); - } - - void BufferStorage( const GLsizeiptr newAreaSize, const GLsizeiptr areaCount, const void* data ) { - areaSize = newAreaSize; - maxAreas = areaCount; - glNamedBufferStorage( id, areaSize * areaCount * sizeof( uint32_t ), data, flags ); - syncs.resize( areaCount ); - - GL_CheckErrors(); - } - - void AreaIncr() { - syncs[area] = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); - area++; - if ( area >= maxAreas ) { - area = 0; - } - } - - void MapAll() { - if ( !mapped ) { - mapped = true; - data = ( uint32_t* ) glMapNamedBufferRange( id, 0, areaSize * maxAreas * sizeof( uint32_t ), flags | mapFlags ); - } - } - - uint32_t* GetCurrentAreaData() { - if ( syncs[area] != nullptr ) { - if ( glClientWaitSync( syncs[area], GL_SYNC_FLUSH_COMMANDS_BIT, SYNC_TIMEOUT ) == GL_TIMEOUT_EXPIRED ) { - Sys::Drop( "Failed buffer %s area %u sync", name, area ); - } - glDeleteSync( syncs[area] ); - } - - return data + area * areaSize; - } - - uint32_t* GetData() { - return data; - } - - void FlushCurrentArea() { - glFlushMappedNamedBufferRange( id, area * areaSize * sizeof( uint32_t ), areaSize * sizeof( uint32_t ) ); - } - - void FlushAll() { - glFlushMappedNamedBufferRange( id, 0, maxAreas * areaSize * sizeof( uint32_t ) ); - } - - void FlushRange( const GLsizeiptr offset, const GLsizeiptr size ) { - glFlushMappedNamedBufferRange( id, offset * sizeof( uint32_t ), size * sizeof( uint32_t ) ); - } - - uint32_t* MapBufferRange( const GLuint count ) { - return MapBufferRange( 0, count ); - } - - uint32_t* MapBufferRange( const GLuint offset, const GLuint count ) { - if ( !mapped ) { - mapped = true; - data = ( uint32_t* ) glMapNamedBufferRange( id, - offset * sizeof( uint32_t ), count * sizeof( uint32_t ), - flags | mapFlags ); - } - - return data; - } - - void UnmapBuffer() { - if ( mapped ) { - mapped = false; - glUnmapNamedBuffer( id ); - } - } - - void GenBuffer() { - glCreateBuffers( 1, &id ); - } - - void DelBuffer() { - glDeleteBuffers( 1, &id ); - mapped = false; - } - - private: - const GLenum internalTarget; - const GLuint internalBindingPoint; - - bool mapped = false; - const GLbitfield flags; - const GLbitfield mapFlags; - - std::vector syncs; - GLsizeiptr area = 0; - GLsizeiptr areaSize = 0; - GLsizeiptr maxAreas = 0; - uint32_t* data; -}; - -// Shorthands for buffers that are only bound to one specific target -class GLSSBO : public GLBuffer { - public: - GLSSBO( const char* name, const GLuint bindingPoint, const GLbitfield flags, const GLbitfield mapFlags ) : - GLBuffer( name, GL_SHADER_STORAGE_BUFFER, bindingPoint, flags, mapFlags ) { - } -}; - -class GLUBO : public GLBuffer { - public: - GLUBO( const char* name, const GLsizeiptr bindingPoint, const GLbitfield flags, const GLbitfield mapFlags ) : - GLBuffer( name, GL_UNIFORM_BUFFER, bindingPoint, flags, mapFlags ) { - } -}; - -class GLAtomicCounterBuffer : public GLBuffer { - public: - GLAtomicCounterBuffer( const char* name, const GLsizeiptr bindingPoint, const GLbitfield flags, const GLbitfield mapFlags ) : - GLBuffer( name, GL_ATOMIC_COUNTER_BUFFER, bindingPoint, flags, mapFlags ) { - } -}; - -class GLVAO { - public: - vboAttributeLayout_t attrs[ATTR_INDEX_MAX]; - uint32_t enabledAttrs; - - GLVAO( const GLuint newVBOBindingPoint ) : - VBOBindingPoint( newVBOBindingPoint ) { - } - - ~GLVAO() = default; - - void Bind() { - glBindVertexArray( id ); - } - - void SetAttrs( const vertexAttributeSpec_t* attrBegin, const vertexAttributeSpec_t* attrEnd ) { - uint32_t ofs = 0; - for ( const vertexAttributeSpec_t* spec = attrBegin; spec < attrEnd; spec++ ) { - vboAttributeLayout_t& attr = attrs[spec->attrIndex]; - ASSERT_NQ( spec->numComponents, 0U ); - attr.componentType = spec->componentStorageType; - if ( attr.componentType == GL_HALF_FLOAT && !glConfig2.halfFloatVertexAvailable ) { - attr.componentType = GL_FLOAT; - } - attr.numComponents = spec->numComponents; - attr.normalize = spec->attrOptions & ATTR_OPTION_NORMALIZE ? GL_TRUE : GL_FALSE; - - attr.ofs = ofs; - ofs += attr.numComponents * R_ComponentSize( attr.componentType ); - ofs = ( ofs + 3 ) & ~3; // 4 is minimum alignment for any vertex attribute - - enabledAttrs |= 1 << spec->attrIndex; - } - - stride = ofs; - - for ( const vertexAttributeSpec_t* spec = attrBegin; spec < attrEnd; spec++ ) { - const int index = spec->attrIndex; - vboAttributeLayout_t& attr = attrs[index]; - - attr.stride = stride; - - glEnableVertexArrayAttrib( id, index ); - glVertexArrayAttribFormat( id, index, attr.numComponents, attr.componentType, - attr.normalize, attr.ofs ); - glVertexArrayAttribBinding( id, index, VBOBindingPoint ); - } - } - - void SetVertexBuffer( const GLBuffer buffer, const GLuint offset ) { - glVertexArrayVertexBuffer( id, VBOBindingPoint, buffer.id, offset, stride ); - } - - void SetIndexBuffer( const GLBuffer buffer ) { - glVertexArrayElementBuffer( id, buffer.id ); - } - - void GenVAO() { - glGenVertexArrays( 1, &id ); - } - - void DelVAO() { - glDeleteVertexArrays( 1, &id ); - } - - private: - GLuint id; - const GLuint VBOBindingPoint; - GLuint stride; -}; - class GLCompileMacro { private: