diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index b3e112a7f3..07fcaa61d2 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -37,18 +37,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Material.h" #include "ShadeCommon.h" -GLUBO materialsUBO( "materials", 6, GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); -GLBuffer texDataBuffer( "texData", 7, GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); -GLUBO lightMapDataUBO( "lightMapData", 8, GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); +GLUBO materialsUBO( "materials", Util::ordinal( BufferBind::MATERIALS ), GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); +GLBuffer texDataBuffer( "texData", Util::ordinal( BufferBind::TEX_DATA ), GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); +GLUBO lightMapDataUBO( "lightMapData", Util::ordinal( BufferBind::LIGHTMAP_DATA ), GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); -GLSSBO surfaceDescriptorsSSBO( "surfaceDescriptors", 1, GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); -GLSSBO surfaceCommandsSSBO( "surfaceCommands", 2, GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); -GLBuffer culledCommandsBuffer( "culledCommands", 3, GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); -GLUBO surfaceBatchesUBO( "surfaceBatches", 0, GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); -GLBuffer atomicCommandCountersBuffer( "atomicCommandCounters", 4, GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); -GLSSBO portalSurfacesSSBO( "portalSurfaces", 5, GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT, 0 ); +GLSSBO surfaceDescriptorsSSBO( "surfaceDescriptors", Util::ordinal( BufferBind::SURFACE_DESCRIPTORS ), GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); +GLSSBO surfaceCommandsSSBO( "surfaceCommands", Util::ordinal( BufferBind::SURFACE_COMMANDS ), GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); +GLBuffer culledCommandsBuffer( "culledCommands", Util::ordinal( BufferBind::CULLED_COMMANDS ), GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); +GLUBO surfaceBatchesUBO( "surfaceBatches", Util::ordinal( BufferBind::SURFACE_BATCHES ), GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); +GLBuffer atomicCommandCountersBuffer( "atomicCommandCounters", Util::ordinal( BufferBind::COMMAND_COUNTERS_ATOMIC ), GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); +GLSSBO portalSurfacesSSBO( "portalSurfaces", Util::ordinal( BufferBind::PORTAL_SURFACES ), GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT, 0 ); -GLSSBO debugSSBO( "debug", 10, GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); +GLSSBO debugSSBO( "debug", Util::ordinal( BufferBind::DEBUG ), GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); PortalView portalStack[MAX_VIEWS]; @@ -387,8 +387,6 @@ void UpdateSurfaceDataFog( uint32_t* materials, shaderStage_t* pStage, bool, boo void MaterialSystem::GenerateWorldMaterialsBuffer() { Log::Debug( "Generating materials buffer" ); - materialsUBO.BindBuffer(); - // Sort by padded size to avoid extra padding std::sort( materialStages.begin(), materialStages.end(), [&]( const shaderStage_t* lhs, const shaderStage_t* rhs ) { @@ -431,7 +429,7 @@ void MaterialSystem::GenerateWorldMaterialsBuffer() { totalStageSize = offset; // 4 bytes per component - glBufferData( GL_UNIFORM_BUFFER, offset * sizeof( uint32_t ), nullptr, GL_DYNAMIC_DRAW ); + materialsUBO.BufferData( offset, nullptr, GL_DYNAMIC_DRAW ); uint32_t* materialsData = materialsUBO.MapBufferRange( offset ); GenerateMaterialsBuffer( materialStages, offset, materialsData ); @@ -565,18 +563,15 @@ void MaterialSystem::GenerateWorldCommandBuffer() { Log::Debug( "Total batch count: %u", totalBatchCount ); - surfaceDescriptorsSSBO.BindBuffer(); surfaceDescriptorsCount = totalDrawSurfs; descriptorSize = BOUNDING_SPHERE_SIZE + maxStages; - glBufferData( GL_SHADER_STORAGE_BUFFER, surfaceDescriptorsCount * descriptorSize * sizeof( uint32_t ), - nullptr, GL_STATIC_DRAW ); + surfaceDescriptorsSSBO.BufferData( surfaceDescriptorsCount * descriptorSize, nullptr, GL_STATIC_DRAW ); uint32_t* surfaceDescriptors = surfaceDescriptorsSSBO.MapBufferRange( surfaceDescriptorsCount * descriptorSize ); texDataBufferType = glConfig2.maxUniformBlockSize >= MIN_MATERIAL_UBO_SIZE ? GL_UNIFORM_BUFFER : GL_SHADER_STORAGE_BUFFER; - texDataBuffer.BindBuffer( texDataBufferType ); - texDataBuffer.BufferStorage( texDataBufferType, ( texData.size() + dynamicTexData.size() ) * TEX_BUNDLE_SIZE, 1, nullptr ); - texDataBuffer.MapAll( texDataBufferType ); + texDataBuffer.BufferStorage( ( texData.size() + dynamicTexData.size() ) * TEX_BUNDLE_SIZE, 1, nullptr ); + texDataBuffer.MapAll(); TexBundle* textureBundles = ( TexBundle* ) texDataBuffer.GetData(); memset( textureBundles, 0, ( texData.size() + dynamicTexData.size() ) * TEX_BUNDLE_SIZE * sizeof( uint32_t ) ); @@ -589,27 +584,25 @@ void MaterialSystem::GenerateWorldCommandBuffer() { dynamicTexDataOffset = texData.size() * TEX_BUNDLE_SIZE; dynamicTexDataSize = dynamicTexData.size() * TEX_BUNDLE_SIZE; - texDataBuffer.FlushAll( texDataBufferType ); + texDataBuffer.FlushAll(); texDataBuffer.UnmapBuffer(); - texDataBuffer.UnBindBuffer( texDataBufferType ); - lightMapDataUBO.BindBuffer(); lightMapDataUBO.BufferStorage( MAX_LIGHTMAPS * LIGHTMAP_SIZE, 1, nullptr ); lightMapDataUBO.MapAll(); - uint64_t* lightmapData = ( uint64_t* ) lightMapDataUBO.GetData(); - memset( lightmapData, 0, MAX_LIGHTMAPS * LIGHTMAP_SIZE * sizeof( uint32_t ) ); + uint64_t* lightMapData = ( uint64_t* ) lightMapDataUBO.GetData(); + memset( lightMapData, 0, MAX_LIGHTMAPS * LIGHTMAP_SIZE * sizeof( uint32_t ) ); for ( uint32_t i = 0; i < tr.lightmaps.size(); i++ ) { if ( !tr.lightmaps[i]->texture->hasBindlessHandle ) { tr.lightmaps[i]->texture->GenBindlessHandle(); } - lightmapData[i * 2] = tr.lightmaps[i]->texture->bindlessTextureHandle; + lightMapData[i * 2] = tr.lightmaps[i]->texture->bindlessTextureHandle; } for ( uint32_t i = 0; i < tr.deluxemaps.size(); i++ ) { if ( !tr.deluxemaps[i]->texture->hasBindlessHandle ) { tr.deluxemaps[i]->texture->GenBindlessHandle(); } - lightmapData[i * 2 + 1] = tr.deluxemaps[i]->texture->bindlessTextureHandle; + lightMapData[i * 2 + 1] = tr.deluxemaps[i]->texture->bindlessTextureHandle; } ASSERT_LE( tr.lightmaps.size(), 256 ); // Engine supports up to 256 lightmaps currently, so we use 8 bits to address them @@ -627,36 +620,31 @@ void MaterialSystem::GenerateWorldCommandBuffer() { tr.blackImage->texture->GenBindlessHandle(); } // Use lightmap 255 for drawSurfs that use a full white image for their lightmap - lightmapData[255 * 2] = tr.whiteImage->texture->bindlessTextureHandle; - lightmapData[255 * 2 + 1] = tr.blackImage->texture->bindlessTextureHandle; + lightMapData[255 * 2] = tr.whiteImage->texture->bindlessTextureHandle; + lightMapData[255 * 2 + 1] = tr.blackImage->texture->bindlessTextureHandle; } lightMapDataUBO.FlushAll(); lightMapDataUBO.UnmapBuffer(); - lightMapDataUBO.UnBindBuffer(); surfaceCommandsCount = totalBatchCount * SURFACE_COMMANDS_PER_BATCH; - surfaceCommandsSSBO.BindBuffer(); surfaceCommandsSSBO.BufferStorage( surfaceCommandsCount * SURFACE_COMMAND_SIZE * MAX_VIEWFRAMES, 1, nullptr ); surfaceCommandsSSBO.MapAll(); SurfaceCommand* surfaceCommands = ( SurfaceCommand* ) surfaceCommandsSSBO.GetData(); memset( surfaceCommands, 0, surfaceCommandsCount * sizeof( SurfaceCommand ) * MAX_VIEWFRAMES ); - culledCommandsBuffer.BindBuffer( GL_SHADER_STORAGE_BUFFER ); - culledCommandsBuffer.BufferStorage( GL_SHADER_STORAGE_BUFFER, - surfaceCommandsCount * INDIRECT_COMMAND_SIZE * MAX_VIEWFRAMES, 1, nullptr ); - culledCommandsBuffer.MapAll( GL_SHADER_STORAGE_BUFFER ); - GLIndirectBuffer::GLIndirectCommand* culledCommands = ( GLIndirectBuffer::GLIndirectCommand* ) culledCommandsBuffer.GetData(); - memset( culledCommands, 0, surfaceCommandsCount * sizeof( GLIndirectBuffer::GLIndirectCommand ) * MAX_VIEWFRAMES ); - culledCommandsBuffer.FlushAll( GL_SHADER_STORAGE_BUFFER ); + culledCommandsBuffer.BufferStorage( surfaceCommandsCount * INDIRECT_COMMAND_SIZE * MAX_VIEWFRAMES, 1, nullptr ); + culledCommandsBuffer.MapAll(); + GLIndirectCommand* culledCommands = ( GLIndirectCommand* ) culledCommandsBuffer.GetData(); + memset( culledCommands, 0, surfaceCommandsCount * sizeof( GLIndirectCommand ) * MAX_VIEWFRAMES ); + culledCommandsBuffer.FlushAll(); - surfaceBatchesUBO.BindBuffer(); - glBufferData( GL_UNIFORM_BUFFER, MAX_SURFACE_COMMAND_BATCHES * sizeof( SurfaceCommandBatch ), nullptr, GL_STATIC_DRAW ); + surfaceBatchesUBO.BufferData( MAX_SURFACE_COMMAND_BATCHES * SURFACE_COMMAND_BATCH_SIZE, nullptr, GL_STATIC_DRAW ); SurfaceCommandBatch* surfaceCommandBatches = ( SurfaceCommandBatch* ) surfaceBatchesUBO.MapBufferRange( MAX_SURFACE_COMMAND_BATCHES * SURFACE_COMMAND_BATCH_SIZE ); - // memset( (void*) surfaceCommandBatches, 0, MAX_SURFACE_COMMAND_BATCHES * sizeof( SurfaceCommandBatch ) ); + // memset( (void*) surfaceCommandBatches, 0, MAX_SURFACE_COMMAND_BATCHES * SURFACE_COMMAND_BATCH_SIZE ); // Fuck off gcc for ( int i = 0; i < MAX_SURFACE_COMMAND_BATCHES; i++ ) { surfaceCommandBatches[i] = {}; @@ -675,10 +663,8 @@ void MaterialSystem::GenerateWorldCommandBuffer() { } } - atomicCommandCountersBuffer.BindBuffer( GL_ATOMIC_COUNTER_BUFFER ); - atomicCommandCountersBuffer.BufferStorage( GL_ATOMIC_COUNTER_BUFFER, - MAX_COMMAND_COUNTERS * MAX_VIEWS, MAX_FRAMES, nullptr ); - atomicCommandCountersBuffer.MapAll( GL_ATOMIC_COUNTER_BUFFER ); + atomicCommandCountersBuffer.BufferStorage( MAX_COMMAND_COUNTERS * MAX_VIEWS, MAX_FRAMES, nullptr ); + atomicCommandCountersBuffer.MapAll(); uint32_t* atomicCommandCounters = ( uint32_t* ) atomicCommandCountersBuffer.GetData(); memset( atomicCommandCounters, 0, MAX_COMMAND_COUNTERS * MAX_VIEWFRAMES * sizeof( uint32_t ) ); @@ -687,8 +673,7 @@ void MaterialSystem::GenerateWorldCommandBuffer() { if ( r_materialDebug.Get() ) { const uint32_t debugSize = surfaceCommandsCount * 20; - debugSSBO.BindBuffer(); - glBufferData( GL_SHADER_STORAGE_BUFFER, debugSize * sizeof( uint32_t ), nullptr, GL_STATIC_DRAW ); + debugSSBO.BufferData( debugSize, nullptr, GL_STATIC_DRAW ); uint32_t* debugBuffer = debugSSBO.MapBufferRange( debugSize ); memset( debugBuffer, 0, debugSize * sizeof( uint32_t ) ); debugSSBO.UnmapBuffer(); @@ -786,19 +771,14 @@ void MaterialSystem::GenerateWorldCommandBuffer() { memcpy( surfaceCommands + surfaceCommandsCount * i, surfaceCommands, surfaceCommandsCount * sizeof( SurfaceCommand ) ); } - surfaceDescriptorsSSBO.BindBuffer(); surfaceDescriptorsSSBO.UnmapBuffer(); - surfaceCommandsSSBO.BindBuffer(); surfaceCommandsSSBO.UnmapBuffer(); - culledCommandsBuffer.BindBuffer( GL_SHADER_STORAGE_BUFFER ); culledCommandsBuffer.UnmapBuffer(); - atomicCommandCountersBuffer.BindBuffer( GL_ATOMIC_COUNTER_BUFFER); atomicCommandCountersBuffer.UnmapBuffer(); - surfaceBatchesUBO.BindBuffer(); surfaceBatchesUBO.UnmapBuffer(); GL_CheckErrors(); @@ -1593,7 +1573,6 @@ void MaterialSystem::AddStageTextures( drawSurf_t* drawSurf, const uint32_t stag // Dynamic surfaces are those whose values in the SSBO can be updated void MaterialSystem::UpdateDynamicSurfaces() { if ( dynamicStagesSize > 0 ) { - materialsUBO.BindBuffer(); uint32_t* materialsData = materialsUBO.MapBufferRange( dynamicStagesOffset, dynamicStagesSize ); GenerateMaterialsBuffer( dynamicStages, dynamicStagesSize, materialsData ); @@ -1602,24 +1581,23 @@ void MaterialSystem::UpdateDynamicSurfaces() { } if ( dynamicTexDataSize > 0 ) { - texDataBuffer.BindBuffer( texDataBufferType ); - GL_CheckErrors(); TexBundle* textureBundles = - ( TexBundle* ) texDataBuffer.MapBufferRange( texDataBufferType, dynamicTexDataOffset, dynamicTexDataSize ); - GL_CheckErrors(); + ( TexBundle* ) texDataBuffer.MapBufferRange( dynamicTexDataOffset, dynamicTexDataSize ); GenerateTexturesBuffer( dynamicTexData, textureBundles ); texDataBuffer.UnmapBuffer(); } + + GL_CheckErrors(); } void MaterialSystem::UpdateFrameData() { - atomicCommandCountersBuffer.BindBufferBase( GL_SHADER_STORAGE_BUFFER ); + atomicCommandCountersBuffer.BindBufferBase( GL_SHADER_STORAGE_BUFFER, Util::ordinal( BufferBind::COMMAND_COUNTERS_STORAGE ) ); gl_clearSurfacesShader->BindProgram( 0 ); gl_clearSurfacesShader->SetUniform_Frame( nextFrame ); gl_clearSurfacesShader->DispatchCompute( MAX_VIEWS, 1, 1 ); - atomicCommandCountersBuffer.UnBindBufferBase( GL_SHADER_STORAGE_BUFFER ); + atomicCommandCountersBuffer.UnBindBufferBase( GL_SHADER_STORAGE_BUFFER, Util::ordinal( BufferBind::COMMAND_COUNTERS_STORAGE ) ); GL_CheckErrors(); } @@ -1854,14 +1832,48 @@ void MaterialSystem::GeneratePortalBoundingSpheres() { index++; } - portalSurfacesSSBO.BindBuffer(); portalSurfacesSSBO.BufferStorage( totalPortals * PORTAL_SURFACE_SIZE * MAX_VIEWS, 2, portalSurfs ); portalSurfacesSSBO.MapAll(); - portalSurfacesSSBO.UnBindBuffer(); portalSurfacesTmp.clear(); } +void MaterialSystem::InitGLBuffers() { + materialsUBO.GenBuffer(); + texDataBuffer.GenBuffer(); + lightMapDataUBO.GenBuffer(); + + surfaceDescriptorsSSBO.GenBuffer(); + surfaceCommandsSSBO.GenBuffer(); + culledCommandsBuffer.GenBuffer(); + surfaceBatchesUBO.GenBuffer(); + atomicCommandCountersBuffer.GenBuffer(); + + portalSurfacesSSBO.GenBuffer(); + + if ( r_materialDebug.Get() ) { + debugSSBO.GenBuffer(); + } +} + +void MaterialSystem::FreeGLBuffers() { + materialsUBO.DelBuffer(); + texDataBuffer.DelBuffer(); + lightMapDataUBO.DelBuffer(); + + surfaceDescriptorsSSBO.DelBuffer(); + surfaceCommandsSSBO.DelBuffer(); + culledCommandsBuffer.DelBuffer(); + surfaceBatchesUBO.DelBuffer(); + atomicCommandCountersBuffer.DelBuffer(); + + portalSurfacesSSBO.DelBuffer(); + + if ( r_materialDebug.Get() ) { + debugSSBO.DelBuffer(); + } +} + void MaterialSystem::Free() { generatedWorldCommandBuffer = false; @@ -2074,9 +2086,9 @@ void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderS void MaterialSystem::RenderIndirect( const Material& material, const uint32_t viewID, const GLenum mode = GL_TRIANGLES ) { glMultiDrawElementsIndirectCountARB( mode, GL_UNSIGNED_INT, - BUFFER_OFFSET( material.surfaceCommandBatchOffset * SURFACE_COMMANDS_PER_BATCH * sizeof( GLIndirectBuffer::GLIndirectCommand ) + BUFFER_OFFSET( material.surfaceCommandBatchOffset * SURFACE_COMMANDS_PER_BATCH * sizeof( GLIndirectCommand ) + ( surfaceCommandsCount * ( MAX_VIEWS * currentFrame + viewID ) - * sizeof( GLIndirectBuffer::GLIndirectCommand ) ) ), + * sizeof( GLIndirectCommand ) ) ), material.globalID * sizeof( uint32_t ) + ( MAX_COMMAND_COUNTERS * ( MAX_VIEWS * currentFrame + viewID ) ) * sizeof( uint32_t ), material.drawCommands.size(), 0 ); diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h index 286d4a8e0f..ea49e676b1 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -43,7 +43,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static constexpr uint32_t MAX_DRAWCOMMAND_TEXTURES = 64; -/* Similar to GLIndirectBuffer::GLIndirectCommand, but we always set instanceCount to 1 and baseVertex to 0, +struct GLIndirectCommand { + GLuint count; + GLuint instanceCount; + GLuint firstIndex; + GLint baseVertex; + GLuint baseInstance; +}; + +/* Similar to GLIndirectCommand, but we always set instanceCount to 1 and baseVertex to 0, so no need to waste memory on those */ struct IndirectCompactCommand { GLuint count; @@ -269,6 +277,20 @@ struct SurfaceCommandBatch { uint32_t materialIDs[2] { 0, 0 }; }; +enum class BufferBind { + MATERIALS = 1, // LightTile UBO uses binding point 0, so avoid it here + TEX_DATA = 6, + LIGHTMAP_DATA = 2, + SURFACE_DESCRIPTORS = 0, + SURFACE_COMMANDS = 1, + CULLED_COMMANDS = 2, + SURFACE_BATCHES = 3, + COMMAND_COUNTERS_ATOMIC = 0, + COMMAND_COUNTERS_STORAGE = 4, // Avoid needlessly rebinding buffers + PORTAL_SURFACES = 5, + DEBUG = 10 +}; + class MaterialSystem { public: bool generatedWorldCommandBuffer = false; @@ -329,6 +351,9 @@ class MaterialSystem { void GenerateDepthImages( const int width, const int height, imageParams_t imageParms ); + void InitGLBuffers(); + void FreeGLBuffers(); + void AddStageTextures( drawSurf_t* drawSurf, const uint32_t stage, Material* material ); void AddStage( drawSurf_t* drawSurf, shaderStage_t* pStage, uint32_t stage, const bool mayUseVertexOverbright, const bool vertexLit, const bool fullbright ); diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index f3f4882080..058ca81543 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -532,6 +532,12 @@ static std::string GenVertexHeader() { str += "#define baseInstance gl_BaseInstanceARB\n\n"; } + if ( glConfig2.usingMaterialSystem ) { + AddDefine( str, "BIND_MATERIALS", Util::ordinal( BufferBind::MATERIALS ) ); + AddDefine( str, "BIND_TEX_DATA", Util::ordinal( BufferBind::TEX_DATA ) ); + AddDefine( str, "BIND_LIGHTMAP_DATA", Util::ordinal( BufferBind::LIGHTMAP_DATA ) ); + } + return str; } @@ -566,6 +572,12 @@ static std::string GenFragmentHeader() { str += "#define baseInstance in_baseInstance\n\n"; } + if ( glConfig2.usingMaterialSystem ) { + AddDefine( str, "BIND_MATERIALS", Util::ordinal( BufferBind::MATERIALS ) ); + AddDefine( str, "BIND_TEX_DATA", Util::ordinal( BufferBind::TEX_DATA ) ); + AddDefine( str, "BIND_LIGHTMAP_DATA", Util::ordinal( BufferBind::LIGHTMAP_DATA ) ); + } + return str; } @@ -573,11 +585,23 @@ static std::string GenComputeHeader() { std::string str; // Compute shader compatibility defines - AddDefine( str, "MAX_VIEWS", MAX_VIEWS ); - AddDefine( str, "MAX_FRAMES", MAX_FRAMES ); - AddDefine( str, "MAX_VIEWFRAMES", MAX_VIEWFRAMES ); - AddDefine( str, "MAX_SURFACE_COMMAND_BATCHES", MAX_SURFACE_COMMAND_BATCHES ); - AddDefine( str, "MAX_COMMAND_COUNTERS", MAX_COMMAND_COUNTERS ); + if ( glConfig2.usingMaterialSystem ) { + AddDefine( str, "MAX_VIEWS", MAX_VIEWS ); + AddDefine( str, "MAX_FRAMES", MAX_FRAMES ); + AddDefine( str, "MAX_VIEWFRAMES", MAX_VIEWFRAMES ); + AddDefine( str, "MAX_SURFACE_COMMAND_BATCHES", MAX_SURFACE_COMMAND_BATCHES ); + AddDefine( str, "MAX_COMMAND_COUNTERS", MAX_COMMAND_COUNTERS ); + + AddDefine( str, "BIND_SURFACE_DESCRIPTORS", Util::ordinal( BufferBind::SURFACE_DESCRIPTORS ) ); + AddDefine( str, "BIND_SURFACE_COMMANDS", Util::ordinal( BufferBind::SURFACE_COMMANDS ) ); + AddDefine( str, "BIND_CULLED_COMMANDS", Util::ordinal( BufferBind::CULLED_COMMANDS ) ); + AddDefine( str, "BIND_SURFACE_BATCHES", Util::ordinal( BufferBind::SURFACE_BATCHES ) ); + AddDefine( str, "BIND_COMMAND_COUNTERS_ATOMIC", Util::ordinal( BufferBind::COMMAND_COUNTERS_ATOMIC ) ); + AddDefine( str, "BIND_COMMAND_COUNTERS_STORAGE", Util::ordinal( BufferBind::COMMAND_COUNTERS_STORAGE ) ); + AddDefine( str, "BIND_PORTAL_SURFACES", Util::ordinal( BufferBind::PORTAL_SURFACES ) ); + + AddDefine( str, "BIND_DEBUG", Util::ordinal( BufferBind::DEBUG ) ); + } if ( glConfig2.usingBindlessTextures ) { str += "layout(bindless_image) uniform;\n"; @@ -1361,15 +1385,21 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str std::string materialStruct = "\nstruct Material {\n"; // 6 kb for materials const uint32_t count = ( 4096 + 2048 ) / shader->GetPaddedSize(); - std::string materialBlock = "layout(std140, binding = 6) uniform materialsUBO {\n" + std::string materialBlock = "layout(std140, binding = " + + std::to_string( Util::ordinal( BufferBind::MATERIALS ) ) + + ") uniform materialsUBO {\n" " Material materials[" + std::to_string( count ) + "]; \n" "};\n\n"; std::string texBuf = glConfig2.maxUniformBlockSize >= MIN_MATERIAL_UBO_SIZE ? - "layout(std140, binding = 7) uniform texDataUBO {\n" + "layout(std140, binding = " + + std::to_string( Util::ordinal( BufferBind::TEX_DATA ) ) + + ") uniform texDataUBO {\n" " TexData texData[" + std::to_string( MAX_TEX_BUNDLES ) + "]; \n" "};\n\n" - : "layout(std430, binding = 7) restrict readonly buffer texDataSSBO {\n" + : "layout(std430, binding = " + + std::to_string( Util::ordinal( BufferBind::TEX_DATA ) ) + + ") restrict readonly buffer texDataSSBO {\n" " TexData texData[];\n" "};\n\n"; // We have to store u_TextureMatrix as vec4 + vec2 because otherwise it would be aligned to a vec4 under std140 @@ -1393,7 +1423,9 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str " uvec2 u_LightMap;\n" " uvec2 u_DeluxeMap;\n" "};\n\n" - "layout(std140, binding = 8) uniform lightMapDataUBO {\n" + "layout(std140, binding = " + + std::to_string( Util::ordinal( BufferBind::LIGHTMAP_DATA ) ) + + ") uniform lightMapDataUBO {\n" " LightMapData lightMapData[256];\n" "};\n\n" "#define u_LightMap_initial lightMapData[( baseInstance >> 24 ) & 0xFF].u_LightMap\n" diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index 4c515e6cfc..e75a0c6d59 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -1370,43 +1370,56 @@ class GLUniformBlock class GLBuffer { public: - std::string _name; - const GLuint _bindingPoint; - const GLbitfield _flags; - const GLbitfield _mapFlags; + std::string name; const GLuint64 SYNC_TIMEOUT = 10000000000; // 10 seconds - GLBuffer( const char* name, const GLuint bindingPoint, const GLbitfield flags, const GLbitfield mapFlags ) : - _name( name ), - _bindingPoint( bindingPoint ), - _flags( flags ), - _mapFlags( mapFlags ) { + GLBuffer( const char* newName, const GLuint newBindingPoint, const GLbitfield newFlags, const GLbitfield newMapFlags ) : + name( newName ), + internalTarget( 0 ), + internalBindingPoint( newBindingPoint ), + flags( newFlags ), + mapFlags( newMapFlags ) { } - const char* GetName() { - return _name.c_str(); + 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( const GLenum target ) { - glBindBufferBase( target, _bindingPoint, handle ); + void BindBufferBase( GLenum target = 0, GLuint bindingPoint = 0 ) { + target = target ? target : internalTarget; + bindingPoint = bindingPoint ? bindingPoint : internalBindingPoint; + glBindBufferBase( target, bindingPoint, id ); } - void UnBindBufferBase( const GLenum target ) { - glBindBufferBase( target, _bindingPoint, 0 ); + void UnBindBufferBase( GLenum target = 0, GLuint bindingPoint = 0 ) { + target = target ? target : internalTarget; + bindingPoint = bindingPoint ? bindingPoint : internalBindingPoint; + glBindBufferBase( target, bindingPoint, 0 ); } - void BindBuffer( const GLenum target ) { - glBindBuffer( target, handle ); + void BindBuffer( GLenum target = 0 ) { + target = target ? target : internalTarget; + glBindBuffer( target, id ); } - void UnBindBuffer( const GLenum target ) { + void UnBindBuffer( GLenum target = 0 ) { + target = target ? target : internalTarget; glBindBuffer( target, 0 ); } - void BufferStorage( const GLenum target, const GLsizeiptr newAreaSize, const GLsizeiptr areaCount, const void* data ) { + 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; - glBufferStorage( target, areaSize * areaCount * sizeof(uint32_t), data, _flags ); + glNamedBufferStorage( id, areaSize * areaCount * sizeof( uint32_t ), data, flags ); syncs.resize( areaCount ); } @@ -1418,18 +1431,17 @@ class GLBuffer { } } - void MapAll( const GLenum target ) { + void MapAll() { if ( !mapped ) { mapped = true; - mappedTarget = target; - data = ( uint32_t* ) glMapBufferRange( target, 0, areaSize * maxAreas * sizeof( uint32_t ), _flags | _mapFlags ); + 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 ); + Sys::Drop( "Failed buffer %s area %u sync", name, area ); } glDeleteSync( syncs[area] ); } @@ -1441,33 +1453,24 @@ class GLBuffer { return data; } - void FlushCurrentArea( GLenum target ) { - glFlushMappedBufferRange( target, area * areaSize * sizeof( uint32_t ), areaSize * sizeof( uint32_t ) ); + void FlushCurrentArea() { + glFlushMappedNamedBufferRange( id, area * areaSize * sizeof( uint32_t ), areaSize * sizeof( uint32_t ) ); } - void FlushAll( GLenum target ) { - glFlushMappedBufferRange( target, 0, maxAreas * areaSize * sizeof( uint32_t ) ); + void FlushAll() { + glFlushMappedNamedBufferRange( id, 0, maxAreas * areaSize * sizeof( uint32_t ) ); } - uint32_t* MapBufferRange( const GLenum target, const GLuint count ) { - if ( !mapped ) { - mapped = true; - mappedTarget = target; - data = ( uint32_t* ) glMapBufferRange( target, - 0, count * sizeof( uint32_t ), - _flags | _mapFlags ); - } - - return data; + uint32_t* MapBufferRange( const GLuint count ) { + return MapBufferRange( 0, count ); } - uint32_t* MapBufferRange( const GLenum target, const GLuint offset, const GLuint count ) { + uint32_t* MapBufferRange( const GLuint offset, const GLuint count ) { if ( !mapped ) { mapped = true; - mappedTarget = target; - data = ( uint32_t* ) glMapBufferRange( target, + data = ( uint32_t* ) glMapNamedBufferRange( id, offset * sizeof( uint32_t ), count * sizeof( uint32_t ), - _flags | _mapFlags ); + flags | mapFlags ); } return data; @@ -1476,22 +1479,28 @@ class GLBuffer { void UnmapBuffer() { if ( mapped ) { mapped = false; - glUnmapBuffer( mappedTarget ); + glUnmapNamedBuffer( id ); } } void GenBuffer() { - glGenBuffers( 1, &handle ); + glCreateBuffers( 1, &id ); } void DelBuffer() { - glDeleteBuffers( 1, &handle ); + glDeleteBuffers( 1, &id ); } private: - GLenum mappedTarget; - GLuint handle; + const GLenum internalTarget; + const GLuint internalBindingPoint; + + GLuint id; + bool mapped = false; + const GLbitfield flags; + const GLbitfield mapFlags; + std::vector syncs; GLsizeiptr area = 0; GLsizeiptr areaSize = 0; @@ -1499,205 +1508,26 @@ class GLBuffer { 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, bindingPoint, flags, mapFlags ) { - } - - public: - const char* GetName() { - return _name.c_str(); - } - - void BindBufferBase() { - GLBuffer::BindBufferBase( GL_SHADER_STORAGE_BUFFER ); - } - - void UnBindBufferBase() { - GLBuffer::UnBindBufferBase( GL_SHADER_STORAGE_BUFFER ); - } - - void BindBuffer() { - GLBuffer::BindBuffer( GL_SHADER_STORAGE_BUFFER ); - } - - void UnBindBuffer() { - GLBuffer::UnBindBuffer( GL_SHADER_STORAGE_BUFFER ); - } - - void BufferStorage( const GLsizeiptr areaSize, const GLsizeiptr areaCount, const void* data ) { - GLBuffer::BufferStorage( GL_SHADER_STORAGE_BUFFER, areaSize, areaCount, data ); - } - - void MapAll() { - GLBuffer::MapAll( GL_SHADER_STORAGE_BUFFER ); - } - - void FlushCurrentArea() { - GLBuffer::FlushCurrentArea( GL_SHADER_STORAGE_BUFFER ); - } - - void FlushAll() { - GLBuffer::FlushAll( GL_SHADER_STORAGE_BUFFER ); - } - - uint32_t* MapBufferRange( const GLsizeiptr count ) { - return GLBuffer::MapBufferRange( GL_SHADER_STORAGE_BUFFER, count ); - } - - uint32_t* MapBufferRange( const GLsizeiptr offset, const GLsizeiptr count ) { - return GLBuffer::MapBufferRange( GL_SHADER_STORAGE_BUFFER, offset, count ); + 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, bindingPoint, flags, mapFlags ) { - } - - public: - const char* GetName() { - return _name.c_str(); - } - - void BindBufferBase() { - GLBuffer::BindBufferBase( GL_UNIFORM_BUFFER ); - } - - void UnBindBufferBase() { - GLBuffer::UnBindBufferBase( GL_UNIFORM_BUFFER ); - } - - void BindBuffer() { - GLBuffer::BindBuffer( GL_UNIFORM_BUFFER ); - } - - void UnBindBuffer() { - GLBuffer::UnBindBuffer( GL_UNIFORM_BUFFER ); - } - - void BufferStorage( const GLsizeiptr areaSize, const GLsizeiptr areaCount, const void* data ) { - GLBuffer::BufferStorage( GL_UNIFORM_BUFFER, areaSize, areaCount, data ); - } - - void MapAll() { - GLBuffer::MapAll( GL_UNIFORM_BUFFER ); - } - - void FlushCurrentArea() { - GLBuffer::FlushCurrentArea( GL_UNIFORM_BUFFER ); - } - - void FlushAll() { - GLBuffer::FlushAll( GL_UNIFORM_BUFFER ); - } - - uint32_t* MapBufferRange( const GLsizeiptr count ) { - return GLBuffer::MapBufferRange( GL_UNIFORM_BUFFER, count ); - } - - uint32_t* MapBufferRange( const GLsizeiptr offset, const GLsizeiptr count ) { - return GLBuffer::MapBufferRange( GL_UNIFORM_BUFFER, offset, count ); + 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, bindingPoint, flags, mapFlags ) { - } - - public: - const char* GetName() { - return _name.c_str(); - } - - void BindBufferBase() { - GLBuffer::BindBufferBase( GL_ATOMIC_COUNTER_BUFFER ); - } - - void UnBindBufferBase() { - GLBuffer::UnBindBufferBase( GL_ATOMIC_COUNTER_BUFFER ); - } - - void BindBuffer() { - GLBuffer::BindBuffer( GL_ATOMIC_COUNTER_BUFFER ); - } - - void BufferStorage( const GLsizeiptr areaSize, const GLsizeiptr areaCount, const void* data ) { - GLBuffer::BufferStorage( GL_ATOMIC_COUNTER_BUFFER, areaSize, areaCount, data ); - } - - void MapAll() { - GLBuffer::MapAll( GL_ATOMIC_COUNTER_BUFFER ); - } - - void FlushCurrentArea() { - GLBuffer::FlushCurrentArea( GL_ATOMIC_COUNTER_BUFFER ); - } - - void FlushAll() { - GLBuffer::FlushAll( GL_ATOMIC_COUNTER_BUFFER ); - } - - uint32_t* MapBufferRange( const GLsizeiptr count ) { - return GLBuffer::MapBufferRange( GL_ATOMIC_COUNTER_BUFFER, count ); + GLBuffer( name, GL_ATOMIC_COUNTER_BUFFER, bindingPoint, flags, mapFlags ) { } - - uint32_t* MapBufferRange( const GLsizeiptr offset, const GLsizeiptr count ) { - return GLBuffer::MapBufferRange( GL_ATOMIC_COUNTER_BUFFER, offset, count ); - } -}; - -class GLIndirectBuffer { - public: - - struct GLIndirectCommand { - GLuint count; - GLuint instanceCount; - GLuint firstIndex; - GLint baseVertex; - GLuint baseInstance; - }; - - std::string _name; - - GLIndirectBuffer( const char* name ) : - _name( name ) { - } - - public: - - const char* GetName() { - return _name.c_str(); - } - - void BindBuffer() { - glBindBuffer( GL_DRAW_INDIRECT_BUFFER, handle ); - } - - GLIndirectCommand* MapBufferRange( const GLsizeiptr count ) { - return (GLIndirectCommand*) glMapBufferRange( GL_DRAW_INDIRECT_BUFFER, - 0, count * sizeof( GLIndirectCommand ), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ); - } - - void UnmapBuffer() const { - glUnmapBuffer( GL_DRAW_INDIRECT_BUFFER ); - } - - void GenBuffer() { - glGenBuffers( 1, &handle ); - } - - void DelBuffer() { - glDeleteBuffers( 1, &handle ); - } - - private: - GLuint handle; }; class GLCompileMacro diff --git a/src/engine/renderer/glsl_source/clearSurfaces_cp.glsl b/src/engine/renderer/glsl_source/clearSurfaces_cp.glsl index 5ab1b2396d..07ed88da9f 100644 --- a/src/engine/renderer/glsl_source/clearSurfaces_cp.glsl +++ b/src/engine/renderer/glsl_source/clearSurfaces_cp.glsl @@ -38,7 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in; -layout(std430, binding = 4) writeonly buffer atomicCommandCountersBuffer { +layout(std430, binding = BIND_COMMAND_COUNTERS_STORAGE) writeonly buffer atomicCommandCountersBuffer { uint atomicCommandCounters[MAX_COMMAND_COUNTERS * MAX_VIEWFRAMES]; }; diff --git a/src/engine/renderer/glsl_source/cull_cp.glsl b/src/engine/renderer/glsl_source/cull_cp.glsl index eb93e72590..8c19d55706 100644 --- a/src/engine/renderer/glsl_source/cull_cp.glsl +++ b/src/engine/renderer/glsl_source/cull_cp.glsl @@ -41,15 +41,15 @@ layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in; layout(binding = 0) uniform sampler2D depthImage; -layout(std430, binding = 1) readonly restrict buffer surfaceDescriptorsSSBO { +layout(std430, binding = BIND_SURFACE_DESCRIPTORS) readonly restrict buffer surfaceDescriptorsSSBO { SurfaceDescriptor surfaces[]; }; -layout(std430, binding = 2) writeonly restrict buffer surfaceCommandsSSBO { +layout(std430, binding = BIND_SURFACE_COMMANDS) writeonly restrict buffer surfaceCommandsSSBO { SurfaceCommand surfaceCommands[]; }; -layout(std430, binding = 5) restrict buffer portalSurfacesSSBO { +layout(std430, binding = BIND_PORTAL_SURFACES) restrict buffer portalSurfacesSSBO { PortalSurface portalSurfaces[]; }; @@ -57,7 +57,7 @@ layout(std430, binding = 5) restrict buffer portalSurfacesSSBO { #define DEBUG_INVOCATION_SIZE 5 #define DEBUG_ID( id ) ( id * DEBUG_INVOCATION_SIZE ) - layout(std430, binding = 10) writeonly restrict buffer debugSSBO { + layout(std430, binding = BIND_DEBUG) writeonly restrict buffer debugSSBO { uvec4 debug[]; }; #endif diff --git a/src/engine/renderer/glsl_source/processSurfaces_cp.glsl b/src/engine/renderer/glsl_source/processSurfaces_cp.glsl index a3eaa267d0..c5d28513b3 100644 --- a/src/engine/renderer/glsl_source/processSurfaces_cp.glsl +++ b/src/engine/renderer/glsl_source/processSurfaces_cp.glsl @@ -41,19 +41,19 @@ layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in; #define SurfaceCommandBatch uvec4 -layout(std430, binding = 2) readonly restrict buffer surfaceCommandsSSBO { +layout(std430, binding = BIND_SURFACE_COMMANDS) readonly restrict buffer surfaceCommandsSSBO { SurfaceCommand surfaceCommands[]; }; -layout(std430, binding = 3) writeonly restrict buffer culledCommandsSSBO { +layout(std430, binding = BIND_CULLED_COMMANDS) writeonly restrict buffer culledCommandsSSBO { GLIndirectCommand culledCommands[]; }; -layout(std140, binding = 0) uniform ub_SurfaceBatches { +layout(std140, binding = BIND_SURFACE_BATCHES) uniform ub_SurfaceBatches { SurfaceCommandBatch surfaceBatches[MAX_SURFACE_COMMAND_BATCHES]; }; -layout (binding = 4) uniform atomic_uint atomicCommandCounters[MAX_COMMAND_COUNTERS * MAX_VIEWFRAMES]; +layout (binding = BIND_COMMAND_COUNTERS_ATOMIC) uniform atomic_uint atomicCommandCounters[MAX_COMMAND_COUNTERS * MAX_VIEWFRAMES]; uniform uint u_Frame; uniform uint u_ViewID; diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index b5b320a3d9..5f4a253aaf 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -102,6 +102,7 @@ struct glconfig2_t bool indirectParametersAvailable; bool shadingLanguage420PackAvailable; bool explicitUniformLocationAvailable; + bool directStateAccessAvailable; bool shaderImageLoadStoreAvailable; bool shaderAtomicCountersAvailable; bool shaderAtomicCounterOpsAvailable; diff --git a/src/engine/renderer/tr_vbo.cpp b/src/engine/renderer/tr_vbo.cpp index e453a62d7e..85bc83e700 100644 --- a/src/engine/renderer/tr_vbo.cpp +++ b/src/engine/renderer/tr_vbo.cpp @@ -726,27 +726,6 @@ static void R_InitLightUBO() glBindBuffer( GL_UNIFORM_BUFFER, 0 ); } } - -static void R_InitMaterialBuffers() { - if( glConfig2.usingMaterialSystem ) { - materialsUBO.GenBuffer(); - texDataBuffer.GenBuffer(); - lightMapDataUBO.GenBuffer(); - - surfaceDescriptorsSSBO.GenBuffer(); - surfaceCommandsSSBO.GenBuffer(); - culledCommandsBuffer.GenBuffer(); - surfaceBatchesUBO.GenBuffer(); - atomicCommandCountersBuffer.GenBuffer(); - - portalSurfacesSSBO.GenBuffer(); - - if ( r_materialDebug.Get() ) { - debugSSBO.GenBuffer(); - } - } -} - /* ============ R_InitVBOs @@ -790,7 +769,9 @@ void R_InitVBOs() R_InitLightUBO(); - R_InitMaterialBuffers(); + if ( glConfig2.usingMaterialSystem ) { + materialSystem.InitGLBuffers(); + } GL_CheckErrors(); } @@ -861,21 +842,7 @@ void R_ShutdownVBOs() } if ( glConfig2.usingMaterialSystem ) { - materialsUBO.DelBuffer(); - texDataBuffer.DelBuffer(); - lightMapDataUBO.DelBuffer(); - - surfaceDescriptorsSSBO.DelBuffer(); - surfaceCommandsSSBO.DelBuffer(); - culledCommandsBuffer.DelBuffer(); - surfaceBatchesUBO.DelBuffer(); - atomicCommandCountersBuffer.DelBuffer(); - - portalSurfacesSSBO.DelBuffer(); - - if ( r_materialDebug.Get() ) { - debugSSBO.DelBuffer(); - } + materialSystem.FreeGLBuffers(); } tess.verts = tess.vertsBuffer = nullptr; diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index a6cf29903a..9b9d5296a1 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -70,6 +70,8 @@ static Cvar::Cvar r_arb_buffer_storage( "r_arb_buffer_storage", "Use GL_ARB_buffer_storage if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_compute_shader( "r_arb_compute_shader", "Use GL_ARB_compute_shader if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_direct_state_access( "r_arb_direct_state_access", + "Use GL_ARB_direct_state_access if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_framebuffer_object( "r_arb_framebuffer_object", "Use GL_ARB_framebuffer_object if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_explicit_uniform_location( "r_arb_explicit_uniform_location", @@ -1975,6 +1977,7 @@ static void GLimp_InitExtensions() Cvar::Latch( r_arb_bindless_texture ); Cvar::Latch( r_arb_buffer_storage ); Cvar::Latch( r_arb_compute_shader ); + Cvar::Latch( r_arb_direct_state_access ); Cvar::Latch( r_arb_explicit_uniform_location ); Cvar::Latch( r_arb_framebuffer_object ); Cvar::Latch( r_arb_gpu_shader5 ); @@ -2544,11 +2547,15 @@ static void GLimp_InitExtensions() // made required in OpenGL 4.6 glConfig2.indirectParametersAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_indirect_parameters, r_arb_indirect_parameters.Get() ); + // made required in OpenGL 4.5 + glConfig2.directStateAccessAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_direct_state_access, r_arb_direct_state_access.Get() ); + glConfig2.materialSystemAvailable = glConfig2.shaderDrawParametersAvailable && glConfig2.SSBOAvailable && glConfig2.multiDrawIndirectAvailable && glConfig2.bindlessTexturesAvailable && glConfig2.computeShaderAvailable && glConfig2.shadingLanguage420PackAvailable && glConfig2.explicitUniformLocationAvailable && glConfig2.shaderImageLoadStoreAvailable - && glConfig2.shaderAtomicCountersAvailable && glConfig2.indirectParametersAvailable; + && glConfig2.shaderAtomicCountersAvailable && glConfig2.indirectParametersAvailable + && glConfig2.directStateAccessAvailable; // This requires GLEW 2.2+, so skip if it's a lower version #ifdef GL_KHR_shader_subgroup