diff --git a/src.cmake b/src.cmake index 7976806708..c765a9c56b 100644 --- a/src.cmake +++ b/src.cmake @@ -115,6 +115,8 @@ set(RENDERERLIST ${ENGINE_DIR}/renderer/tr_fbo.cpp ${ENGINE_DIR}/renderer/tr_flares.cpp ${ENGINE_DIR}/renderer/tr_font.cpp + ${ENGINE_DIR}/renderer/GeometryCache.cpp + ${ENGINE_DIR}/renderer/GeometryCache.h ${ENGINE_DIR}/renderer/InternalImage.cpp ${ENGINE_DIR}/renderer/InternalImage.h ${ENGINE_DIR}/renderer/Material.cpp diff --git a/src/engine/renderer/GeometryCache.cpp b/src/engine/renderer/GeometryCache.cpp new file mode 100644 index 0000000000..a34e9b0cac --- /dev/null +++ b/src/engine/renderer/GeometryCache.cpp @@ -0,0 +1,100 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2025 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== +*/ +// GeometryCache.cpp + +#include "GeometryCache.h" + +#include "tr_local.h" + +GeometryCache geometryCache; + +void GeometryCache::Bind() { + VAO.Bind(); +} + +void GeometryCache::InitGLBuffers() { + inputVBO.GenBuffer(); + VBO.GenBuffer(); + IBO.GenBuffer(); + + VAO.GenVAO(); +} + +void GeometryCache::FreeGLBuffers() { + inputVBO.DelBuffer(); + VBO.DelBuffer(); + IBO.DelBuffer(); + + VAO.DelVAO(); +} + +void GeometryCache::Free() { +} + +void GeometryCache::AllocBuffers() { + VBO.BufferData( mapVerticesNumber * 8, nullptr, GL_STATIC_DRAW ); + + IBO.BufferData( mapIndicesNumber, nullptr, GL_STATIC_DRAW ); +} + +void GeometryCache::AddMapGeometry( const uint32_t verticesNumber, const uint32_t indicesNumber, + const vertexAttributeSpec_t* attrBegin, const vertexAttributeSpec_t* attrEnd, + const glIndex_t* indices ) { + mapVerticesNumber = verticesNumber; + mapIndicesNumber = indicesNumber; + + VAO.Bind(); + + AllocBuffers(); + + VAO.SetAttrs( attrBegin, attrEnd ); + + VAO.SetVertexBuffer( VBO, 0 ); + VAO.SetIndexBuffer( IBO ); + + uint32_t* VBOVerts = VBO.MapBufferRange( mapVerticesNumber * 8 ); + memset( VBOVerts, 0, mapVerticesNumber * 8 * sizeof( uint32_t ) ); + for ( const vertexAttributeSpec_t* spec = attrBegin; spec < attrEnd; spec++ ) { + vboAttributeLayout_t& attr = VAO.attrs[spec->attrIndex]; + + CopyVertexAttribute( attr, *spec, mapVerticesNumber, ( byte* ) VBOVerts ); + } + VBO.UnmapBuffer(); + + uint32_t* VBOIndices = IBO.MapBufferRange( mapIndicesNumber ); + memcpy( VBOIndices, indices, mapIndicesNumber * sizeof( uint32_t ) ); + IBO.UnmapBuffer(); + + glBindVertexArray( backEnd.currentVAO ); +} diff --git a/src/engine/renderer/GeometryCache.h b/src/engine/renderer/GeometryCache.h new file mode 100644 index 0000000000..134b8513bf --- /dev/null +++ b/src/engine/renderer/GeometryCache.h @@ -0,0 +1,70 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2025 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== +*/ +// GeometryCache.h + +#ifndef GEOMETRY_CACHE_H +#define GEOMETRY_CACHE_H + +#include "gl_shader.h" +#include "Material.h" + +class GeometryCache { + public: + void Bind(); + + void InitGLBuffers(); + void FreeGLBuffers(); + + void Free(); + + void AllocBuffers(); + void AddMapGeometry( const uint32_t verticesNumber, const uint32_t indicesNumber, + const vertexAttributeSpec_t* attrBegin, + const vertexAttributeSpec_t* attrEnd, + const glIndex_t* indices ); + + private: + uint32_t mapVerticesNumber; + uint32_t mapIndicesNumber; + + GLVAO VAO = GLVAO( 0 ); + + GLBuffer inputVBO = GLBuffer( "geometryCacheInputVBO", Util::ordinal( BufferBind::GEOMETRY_CACHE_INPUT_VBO ), GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); + GLBuffer VBO = GLBuffer( "geometryCacheVBO", Util::ordinal( BufferBind::GEOMETRY_CACHE_VBO ), GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); + GLBuffer IBO = GLBuffer( "geometryCacheIBO", Util::ordinal( BufferBind::UNUSED ), GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); +}; + +extern GeometryCache geometryCache; + +#endif // GEOMETRY_CACHE_H diff --git a/src/engine/renderer/InternalImage.cpp b/src/engine/renderer/InternalImage.cpp index d0c870b059..08aa8bb155 100644 --- a/src/engine/renderer/InternalImage.cpp +++ b/src/engine/renderer/InternalImage.cpp @@ -139,8 +139,8 @@ int R_GetImageCustomScalingStep( const image_t *image, const imageParams_t &imag return scalingStep; } - int materialMinDimension = r_ignoreMaterialMinDimension->integer ? 0 : imageParams.minDimension; - int materialMaxDimension = r_ignoreMaterialMaxDimension->integer ? 0 : imageParams.maxDimension; + int materialMinDimension = r_ignoreMaterialMinDimension.Get() ? 0 : imageParams.minDimension; + int materialMaxDimension = r_ignoreMaterialMaxDimension.Get() ? 0 : imageParams.maxDimension; int minDimension; @@ -148,7 +148,7 @@ int R_GetImageCustomScalingStep( const image_t *image, const imageParams_t &imag { minDimension = 1; } - else if ( r_replaceMaterialMinDimensionIfPresentWithMaxDimension->integer ) + else if ( r_replaceMaterialMinDimensionIfPresentWithMaxDimension.Get() ) { minDimension = materialMaxDimension > 0 ? materialMaxDimension : std::numeric_limits::max(); } @@ -159,16 +159,16 @@ int R_GetImageCustomScalingStep( const image_t *image, const imageParams_t &imag int maxDimension = materialMaxDimension > 0 ? materialMaxDimension : std::numeric_limits::max(); - if ( r_imageMaxDimension->integer > 0 ) + if ( r_imageMaxDimension.Get() > 0 ) { - maxDimension = std::min( maxDimension, r_imageMaxDimension->integer ); + maxDimension = std::min( maxDimension, r_imageMaxDimension.Get() ); } // 1st priority: scaledDimension >= minDimension // 2nd priority: scaledDimension <= maxDimension - // 3rd priority: scalingStep >= r_picMip->integer + // 3rd priority: scalingStep >= r_picMip.Get() // 4th priority: scalingStep as low as possible - while ( scaledDimension > maxDimension || scalingStep < r_picMip->integer ) + while ( scaledDimension > maxDimension || scalingStep < r_picMip.Get() ) { scaledDimension >>= 1; diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index 1070522b60..3711da3da0 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -36,17 +36,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tr_local.h" #include "Material.h" #include "ShadeCommon.h" +#include "GeometryCache.h" -GLSSBO materialsSSBO( "materials", 0, GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_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]; @@ -114,69 +117,6 @@ static void ComputeDynamics( shaderStage_t* pStage ) { } } - for ( textureBundle_t& bundle : pStage->bundle ) { - for ( size_t i = 0; i < bundle.numTexMods; i++ ) { - switch ( bundle.texMods[i].type ) { - case texMod_t::TMOD_NONE: - case texMod_t::TMOD_SCALE: - case texMod_t::TMOD_TRANSFORM: - break; - - case texMod_t::TMOD_TURBULENT: - case texMod_t::TMOD_ENTITY_TRANSLATE: - case texMod_t::TMOD_SCROLL: - { - pStage->texMatricesDynamic = true; - break; - } - - case texMod_t::TMOD_STRETCH: - { - if( bundle.texMods->wave.func != genFunc_t::GF_NONE ) { - pStage->texMatricesDynamic = true; - } - break; - } - - case texMod_t::TMOD_ROTATE: - { - pStage->texMatricesDynamic = true; - break; - } - - case texMod_t::TMOD_SCROLL2: - case texMod_t::TMOD_SCALE2: - case texMod_t::TMOD_CENTERSCALE: - case texMod_t::TMOD_SHEAR: - { - if ( bundle.texMods[i].sExp.numOps || bundle.texMods[i].tExp.numOps ) { - pStage->texMatricesDynamic = true; - } - break; - } - - case texMod_t::TMOD_ROTATE2: - { - if( bundle.texMods[i].rExp.numOps ) { - pStage->texMatricesDynamic = true; - } - break; - } - - default: - break; - } - } - } - - // TODO: Move this to a different buffer? - for ( const textureBundle_t& bundle : pStage->bundle ) { - if ( bundle.isVideoMap || bundle.numImages > 1 ) { - pStage->texturesDynamic = true; - break; - } - } - // Can we move this to a compute shader too? // Doesn't seem to be used much if at all, so probably not worth the effort to do that pStage->dynamic = pStage->dynamic || pStage->ifExp.numOps; @@ -187,33 +127,23 @@ static void ComputeDynamics( shaderStage_t* pStage ) { || pStage->fogDensityExp.numOps || pStage->fresnelBiasExp.numOps || pStage->fresnelPowerExp.numOps || pStage->fresnelScaleExp.numOps || pStage->normalIntensityExp.numOps || pStage->refractionIndexExp.numOps; - pStage->dynamic = pStage->dynamic || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->texturesDynamic; + pStage->dynamic = pStage->dynamic || pStage->colorDynamic; } // UpdateSurface*() functions will actually write the uniform values to the SSBO // Mirrors parts of the Render_*() functions in tr_shade.cpp -void UpdateSurfaceDataNONE( uint32_t*, Material&, drawSurf_t*, const uint32_t ) { +void UpdateSurfaceDataNONE( uint32_t*, shaderStage_t*, bool, bool, bool ) { ASSERT_UNREACHABLE(); } -void UpdateSurfaceDataNOP( uint32_t*, Material&, drawSurf_t*, const uint32_t ) { +void UpdateSurfaceDataNOP( uint32_t*, shaderStage_t*, bool, bool, bool ) { } -void UpdateSurfaceDataGeneric3D( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { - shader_t* shader = drawSurf->shader; - shaderStage_t* pStage = &shader->stages[stage]; - - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; +void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, bool mayUseVertexOverbright, bool, bool ) { + // shader_t* shader = pStage->shader; - bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; - if ( !updated ) { - return; - } - drawSurf->initialized[stage] = true; - - gl_genericShaderMaterial->BindProgram( material.deformIndex ); + materials += pStage->bufferOffset; // u_AlphaThreshold gl_genericShaderMaterial->SetUniform_AlphaTest( pStage->stateBits ); @@ -222,25 +152,12 @@ void UpdateSurfaceDataGeneric3D( uint32_t* materials, Material& material, drawSu colorGen_t rgbGen = SetRgbGen( pStage ); alphaGen_t alphaGen = SetAlphaGen( pStage ); - bool mayUseVertexOverbright = pStage->type == stageType_t::ST_COLORMAP && drawSurf->bspSurface; const bool styleLightMap = pStage->type == stageType_t::ST_STYLELIGHTMAP || pStage->type == stageType_t::ST_STYLECOLORMAP; gl_genericShaderMaterial->SetUniform_ColorModulateColorGen( rgbGen, alphaGen, mayUseVertexOverbright, styleLightMap ); Tess_ComputeColor( pStage ); gl_genericShaderMaterial->SetUniform_Color( tess.svars.color ); - Tess_ComputeTexMatrices( pStage ); - gl_genericShaderMaterial->SetUniform_TextureMatrix( tess.svars.texMatrices[TB_COLORMAP] ); - - // bind u_ColorMap - if ( pStage->type == stageType_t::ST_STYLELIGHTMAP ) { - gl_genericShaderMaterial->SetUniform_ColorMapBindless( - GL_BindToTMU( 0, GetLightMap( drawSurf ) ) - ); - } else { - gl_genericShaderMaterial->SetUniform_ColorMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); - } - bool hasDepthFade = pStage->hasDepthFade; if ( hasDepthFade ) { gl_genericShaderMaterial->SetUniform_DepthScale( pStage->depthFadeValue ); @@ -249,30 +166,10 @@ void UpdateSurfaceDataGeneric3D( uint32_t* materials, Material& material, drawSu gl_genericShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataLightMapping( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { - shader_t* shader = drawSurf->shader; - shaderStage_t* pStage = &shader->stages[stage]; +void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, bool, bool vertexLit, bool fullbright ) { + shader_t* shader = pStage->shader; - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; - - bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; - if ( !updated ) { - return; - } - drawSurf->initialized[stage] = true; - - gl_lightMappingShaderMaterial->BindProgram( material.deformIndex ); - - gl_lightMappingShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); - - lightMode_t lightMode; - deluxeMode_t deluxeMode; - SetLightDeluxeMode( drawSurf, pStage->type, lightMode, deluxeMode ); - - // u_Map, u_DeluxeMap - image_t* lightmap = SetLightMap( drawSurf, lightMode ); - image_t* deluxemap = SetDeluxeMap( drawSurf, deluxeMode ); + materials += pStage->bufferOffset; // u_ColorModulate colorGen_t rgbGen = SetRgbGen( pStage ); @@ -280,13 +177,13 @@ void UpdateSurfaceDataLightMapping( uint32_t* materials, Material& material, dra Tess_ComputeColor( pStage ); - SetVertexLightingSettings( lightMode, rgbGen ); - - bool enableGridLighting = ( lightMode == lightMode_t::GRID ); - bool enableGridDeluxeMapping = ( deluxeMode == deluxeMode_t::GRID ); + // HACK: This only has effect on vertex-lit surfaces + if ( vertexLit ) { + SetVertexLightingSettings( lightMode_t::VERTEX, rgbGen ); + } // u_ColorModulate - gl_lightMappingShaderMaterial->SetUniform_ColorModulateColorGen( rgbGen, alphaGen, false, lightMode != lightMode_t::FULLBRIGHT ); + gl_lightMappingShaderMaterial->SetUniform_ColorModulateColorGen( rgbGen, alphaGen, false, !fullbright ); // u_Color gl_lightMappingShaderMaterial->SetUniform_Color( tess.svars.color ); @@ -294,37 +191,13 @@ void UpdateSurfaceDataLightMapping( uint32_t* materials, Material& material, dra // u_AlphaThreshold gl_lightMappingShaderMaterial->SetUniform_AlphaTest( pStage->stateBits ); - // bind u_HeightMap + // HeightMap if ( pStage->enableReliefMapping ) { - float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale.Get() ); depthScale *= shader->reliefDepthScale; gl_lightMappingShaderMaterial->SetUniform_ReliefDepthScale( depthScale ); gl_lightMappingShaderMaterial->SetUniform_ReliefOffsetBias( shader->reliefOffsetBias ); - - // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap - if ( !pStage->hasHeightMapInNormalMap ) { - gl_lightMappingShaderMaterial->SetUniform_HeightMapBindless( - GL_BindToTMU( BIND_HEIGHTMAP, pStage->bundle[TB_HEIGHTMAP].image[0] ) - ); - } - } - - // bind u_DiffuseMap - gl_lightMappingShaderMaterial->SetUniform_DiffuseMapBindless( - GL_BindToTMU( BIND_DIFFUSEMAP, pStage->bundle[TB_DIFFUSEMAP].image[0] ) - ); - - if ( pStage->type != stageType_t::ST_LIGHTMAP ) { - Tess_ComputeTexMatrices( pStage ); - gl_lightMappingShaderMaterial->SetUniform_TextureMatrix( tess.svars.texMatrices[TB_DIFFUSEMAP] ); - } - - // bind u_NormalMap - if ( !!r_normalMapping->integer || pStage->hasHeightMapInNormalMap ) { - gl_lightMappingShaderMaterial->SetUniform_NormalMapBindless( - GL_BindToTMU( BIND_NORMALMAP, pStage->bundle[TB_NORMALMAP].image[0] ) - ); } // bind u_NormalScale @@ -335,61 +208,20 @@ void UpdateSurfaceDataLightMapping( uint32_t* materials, Material& material, dra gl_lightMappingShaderMaterial->SetUniform_NormalScale( normalScale ); } - // bind u_MaterialMap - if ( pStage->enableSpecularMapping || pStage->enablePhysicalMapping ) { - gl_lightMappingShaderMaterial->SetUniform_MaterialMapBindless( - GL_BindToTMU( BIND_MATERIALMAP, pStage->bundle[TB_MATERIALMAP].image[0] ) - ); - } - if ( pStage->enableSpecularMapping ) { - float specExpMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); - float specExpMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + float specExpMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin.Get() ); + float specExpMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax.Get() ); gl_lightMappingShaderMaterial->SetUniform_SpecularExponent( specExpMin, specExpMax ); } - // bind u_LightMap - if ( !enableGridLighting ) { - gl_lightMappingShaderMaterial->SetUniform_LightMapBindless( - GL_BindToTMU( BIND_LIGHTMAP, lightmap ) - ); - } - - // bind u_DeluxeMap - if ( !enableGridDeluxeMapping ) { - gl_lightMappingShaderMaterial->SetUniform_DeluxeMapBindless( - GL_BindToTMU( BIND_DELUXEMAP, deluxemap ) - ); - } - - // bind u_GlowMap - if ( !!r_glowMapping->integer ) { - gl_lightMappingShaderMaterial->SetUniform_GlowMapBindless( - GL_BindToTMU( BIND_GLOWMAP, pStage->bundle[TB_GLOWMAP].image[0] ) - ); - } - gl_lightMappingShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataReflection( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { - shader_t* shader = drawSurf->shader; - shaderStage_t* pStage = &shader->stages[stage]; +void UpdateSurfaceDataReflection( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { + shader_t* shader = pStage->shader; - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; - - bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; - if ( !updated ) { - return; - } - drawSurf->initialized[stage] = true; - - // bind u_NormalMap - gl_reflectionShaderMaterial->SetUniform_NormalMapBindless( - GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) - ); + materials += pStage->bufferOffset; // bind u_ColorMap vec3_t position; @@ -415,44 +247,22 @@ void UpdateSurfaceDataReflection( uint32_t* materials, Material& material, drawS gl_reflectionShaderMaterial->SetUniform_NormalScale( normalScale ); } - // bind u_HeightMap u_depthScale u_reliefOffsetBias + // u_depthScale u_reliefOffsetBias if ( pStage->enableReliefMapping ) { - float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale.Get() ); float reliefDepthScale = shader->reliefDepthScale; depthScale *= reliefDepthScale == 0 ? 1 : reliefDepthScale; gl_reflectionShaderMaterial->SetUniform_ReliefDepthScale( depthScale ); gl_reflectionShaderMaterial->SetUniform_ReliefOffsetBias( shader->reliefOffsetBias ); - - // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap - if ( !pStage->hasHeightMapInNormalMap ) { - gl_reflectionShaderMaterial->SetUniform_HeightMapBindless( - GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) - ); - } } gl_reflectionShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataSkybox( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { - shader_t* shader = drawSurf->shader; - shaderStage_t* pStage = &shader->stages[stage]; - - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; +void UpdateSurfaceDataSkybox( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { + // shader_t* shader = pStage->shader; - bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; - if ( !updated ) { - return; - } - drawSurf->initialized[stage] = true; - - gl_skyboxShaderMaterial->BindProgram( material.deformIndex ); - - // bind u_ColorMap - gl_skyboxShaderMaterial->SetUniform_ColorMapCubeBindless( - GL_BindToTMU( 0, pStage->bundle[TB_COLORMAP].image[0] ) - ); + materials += pStage->bufferOffset; // u_AlphaThreshold gl_skyboxShaderMaterial->SetUniform_AlphaTest( GLS_ATEST_NONE ); @@ -460,53 +270,28 @@ void UpdateSurfaceDataSkybox( uint32_t* materials, Material& material, drawSurf_ gl_skyboxShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataScreen( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { - shader_t* shader = drawSurf->shader; - shaderStage_t* pStage = &shader->stages[stage]; - - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; - - bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; - if ( !updated ) { - return; - } - drawSurf->initialized[stage] = true; +void UpdateSurfaceDataScreen( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { + // shader_t* shader = pStage->shader; - gl_screenShaderMaterial->BindProgram( pStage->deformIndex ); + materials += pStage->bufferOffset; // bind u_CurrentMap /* FIXME: This is currently unused, but u_CurrentMap was made global for other shaders, this seems to be the only material system shader that might need it to not be global */ - gl_screenShaderMaterial->SetUniform_CurrentMapBindless( BindAnimatedImage( 0, &drawSurf->shader->stages[stage].bundle[TB_COLORMAP] ) ); + gl_screenShaderMaterial->SetUniform_CurrentMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); gl_screenShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataHeatHaze( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { - shader_t* shader = drawSurf->shader; - shaderStage_t* pStage = &shader->stages[stage]; +void UpdateSurfaceDataHeatHaze( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { + // shader_t* shader = pStage->shader; - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; - - bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; - if ( !updated ) { - return; - } - drawSurf->initialized[stage] = true; + materials += pStage->bufferOffset; float deformMagnitude = RB_EvalExpression( &pStage->deformMagnitudeExp, 1.0 ); gl_heatHazeShaderMaterial->SetUniform_DeformMagnitude( deformMagnitude ); - // bind u_NormalMap - gl_heatHazeShaderMaterial->SetUniform_NormalMapBindless( - GL_BindToTMU( 0, pStage->bundle[TB_NORMALMAP].image[0] ) - ); - if ( pStage->enableNormalMapping ) { - gl_heatHazeShaderMaterial->SetUniform_TextureMatrix( tess.svars.texMatrices[TB_NORMALMAP] ); - vec3_t normalScale; SetNormalScale( pStage, normalScale ); @@ -517,18 +302,10 @@ void UpdateSurfaceDataHeatHaze( uint32_t* materials, Material& material, drawSur gl_heatHazeShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataLiquid( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { - shader_t* shader = drawSurf->shader; - shaderStage_t* pStage = &shader->stages[stage]; +void UpdateSurfaceDataLiquid( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { + // shader_t* shader = pStage->shader; - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; - - bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; - if ( !updated ) { - return; - } - drawSurf->initialized[stage] = true; + materials += pStage->bufferOffset; float fogDensity = RB_EvalExpression( &pStage->fogDensityExp, 0.001 ); vec4_t fogColor; @@ -545,8 +322,8 @@ void UpdateSurfaceDataLiquid( uint32_t* materials, Material& material, drawSurf_ // NOTE: specular component is computed by shader. // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) { - float specMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); - float specMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + float specMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin.Get() ); + float specMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax.Get() ); gl_liquidShaderMaterial->SetUniform_SpecularExponent( specMin, specMax ); } @@ -558,21 +335,13 @@ void UpdateSurfaceDataLiquid( uint32_t* materials, Material& material, drawSurf_ float depthScale; float reliefDepthScale; - depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale.Get() ); reliefDepthScale = tess.surfaceShader->reliefDepthScale; depthScale *= reliefDepthScale == 0 ? 1 : reliefDepthScale; gl_liquidShaderMaterial->SetUniform_ReliefDepthScale( depthScale ); gl_liquidShaderMaterial->SetUniform_ReliefOffsetBias( tess.surfaceShader->reliefOffsetBias ); - - // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap - if ( !pStage->hasHeightMapInNormalMap ) { - gl_liquidShaderMaterial->SetUniform_HeightMapBindless( GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) ); - } } - // bind u_NormalMap - gl_liquidShaderMaterial->SetUniform_NormalMapBindless( GL_BindToTMU( 3, pStage->bundle[TB_NORMALMAP].image[0] ) ); - // bind u_NormalScale if ( pStage->enableNormalMapping ) { vec3_t normalScale; @@ -585,23 +354,10 @@ void UpdateSurfaceDataLiquid( uint32_t* materials, Material& material, drawSurf_ gl_liquidShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataFog( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { - shader_t* shader = drawSurf->shader; - shaderStage_t* pStage = &shader->stages[stage]; - - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; - - bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; - if ( !updated ) { - return; - } - drawSurf->initialized[stage] = true; - - const fog_t* fog = material.fog; +void UpdateSurfaceDataFog( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { + // shader_t* shader = pStage->shader; - // u_Color - gl_fogQuake3ShaderMaterial->SetUniform_Color( fog->color ); + materials += pStage->bufferOffset; gl_fogQuake3ShaderMaterial->WriteUniformsToBuffer( materials ); } @@ -609,30 +365,20 @@ void UpdateSurfaceDataFog( uint32_t* materials, Material& material, drawSurf_t* /* * Buffer layout: * // Static surfaces data: -* // Material0 -* // Surface/stage0_0: +* // Stage0: * uniform0_0 * uniform0_1 * .. * uniform0_x * optional_struct_padding -* // Surface/stage0_1: +* // Stage1: * .. -* // Surface/stage0_y: +* // Stage_y: * uniform0_0 * uniform0_1 * .. * uniform0_x * optional_struct_padding -* optional_material1_padding -* // Material1 -* // Surface/stage1_0: -* .. -* // Surface/stage1_y: -* .. -* .. -* // Materialz: -* .. * .. * // Dynamic surfaces data: * // Same as the static layout @@ -642,125 +388,154 @@ void UpdateSurfaceDataFog( uint32_t* materials, Material& material, drawSurf_t* void MaterialSystem::GenerateWorldMaterialsBuffer() { Log::Debug( "Generating materials buffer" ); - uint32_t offset = 0; + // Sort by padded size to avoid extra padding + std::sort( materialStages.begin(), materialStages.end(), + [&]( const shaderStage_t* lhs, const shaderStage_t* rhs ) { + if ( !lhs->dynamic && rhs->dynamic ) { + return true; + } - materialsSSBO.BindBuffer(); + if ( !rhs->dynamic && lhs->dynamic ) { + return false; + } - // Compute data size for static surfaces - for ( MaterialPack& pack : materialPacks ) { - for ( Material& material : pack.materials ) { - // Any new material in the buffer must start on an offset that is an integer multiple of - // the padded size of the material struct - const uint32_t paddedSize = material.shader->GetPaddedSize(); - const uint32_t padding = ( offset % paddedSize == 0 ) ? 0 : paddedSize - ( offset % paddedSize ); + return lhs->paddedSize < rhs->paddedSize; + } ); - offset += padding; - material.staticMaterialsSSBOOffset = offset; - offset += paddedSize * material.totalStaticDrawSurfCount; - } - } + uint32_t offset = 0; + dynamicStagesOffset = 0; + bool dynamicStagesOffsetSet = false; - bool dynamicDrawSurfOffsetSet = false; + // Compute data size for stages + for ( shaderStage_t* pStage : materialStages ) { + const uint32_t paddedSize = pStage->paddedSize; + const uint32_t padding = !paddedSize || offset % paddedSize == 0 ? 0 : paddedSize - ( offset % paddedSize ); - // Compute data size for dynamic surfaces - for ( MaterialPack& pack : materialPacks ) { - for ( Material& material : pack.materials ) { - // Any new material in the buffer must start on an offset that is an integer multiple of - // the padded size of the material struct - const uint32_t paddedSize = material.shader->GetPaddedSize(); - const uint32_t padding = ( offset % paddedSize == 0 ) ? 0 : paddedSize - ( offset % paddedSize ); - - offset += padding; - - // Make sure padding is taken into account for dynamicDrawSurfsOffset - if ( !dynamicDrawSurfOffsetSet ) { - dynamicDrawSurfsOffset = offset; - dynamicDrawSurfOffsetSet = true; - } + offset += padding; - material.dynamicMaterialsSSBOOffset = offset; - offset += paddedSize * material.totalDynamicDrawSurfCount; + // Make sure padding is taken into account for dynamicStagesOffset + if ( pStage->dynamic ) { + if ( !dynamicStagesOffsetSet ) { + dynamicStagesOffset = offset; + dynamicStagesOffsetSet = true; + } } + + pStage->materialOffset = paddedSize ? offset / paddedSize : 0; + pStage->bufferOffset = offset; + offset += paddedSize * pStage->variantOffset; } - dynamicDrawSurfsSize = offset - dynamicDrawSurfsOffset; + dynamicStagesSize = dynamicStagesOffsetSet ? offset - dynamicStagesOffset : 0; + totalStageSize = offset; // 4 bytes per component - glBufferData( GL_SHADER_STORAGE_BUFFER, offset * sizeof( uint32_t ), nullptr, GL_DYNAMIC_DRAW ); - uint32_t* materialsData = materialsSSBO.MapBufferRange( offset ); - memset( materialsData, 0, offset * sizeof( uint32_t ) ); + materialsUBO.BufferData( offset, nullptr, GL_DYNAMIC_DRAW ); + uint32_t* materialsData = materialsUBO.MapBufferRange( offset ); + + GenerateMaterialsBuffer( materialStages, offset, materialsData ); for ( uint32_t materialPackID = 0; materialPackID < 3; materialPackID++ ) { for ( Material& material : materialPacks[materialPackID].materials ) { - for ( drawSurf_t* drawSurf : material.drawSurfs ) { - bool hasDynamicStages = false; - uint32_t stage = 0; for ( shaderStage_t* pStage = drawSurf->shader->stages; pStage < drawSurf->shader->lastStage; pStage++ ) { if ( drawSurf->materialIDs[stage] != material.id || drawSurf->materialPackIDs[stage] != materialPackID ) { stage++; continue; } - - uint32_t SSBOOffset = 0; - uint32_t drawSurfCount = 0; - if ( pStage->dynamic ) { - SSBOOffset = material.dynamicMaterialsSSBOOffset; - drawSurfCount = material.currentDynamicDrawSurfCount; - material.currentDynamicDrawSurfCount++; - } else { - SSBOOffset = material.staticMaterialsSSBOOffset; - drawSurfCount = material.currentStaticDrawSurfCount; - material.currentStaticDrawSurfCount++; - } - drawSurf->materialsSSBOOffset[stage] = ( SSBOOffset + drawSurfCount * material.shader->GetPaddedSize() ) / - material.shader->GetPaddedSize(); - - if ( pStage->dynamic ) { - hasDynamicStages = true; - } - - AddStageTextures( drawSurf, pStage, &material ); - - pStage->surfaceDataUpdater( materialsData, material, drawSurf, stage ); + // We need some of the values from the remapped stage, but material/materialPack ID has to come from pStage + shaderStage_t* remappedStage = pStage->materialRemappedStage ? pStage->materialRemappedStage : pStage; + const uint32_t SSBOOffset = + remappedStage->materialOffset + remappedStage->variantOffsets[drawSurf->shaderVariant[stage]]; tess.currentDrawSurf = drawSurf; - tess.currentSSBOOffset = tess.currentDrawSurf->materialsSSBOOffset[stage]; - tess.materialID = tess.currentDrawSurf->materialIDs[stage]; - tess.materialPackID = tess.currentDrawSurf->materialPackIDs[stage]; + tess.currentSSBOOffset = SSBOOffset; + tess.materialID = drawSurf->materialIDs[stage]; + tess.materialPackID = drawSurf->materialPackIDs[stage]; Tess_Begin( Tess_StageIteratorDummy, nullptr, nullptr, false, -1, 0 ); rb_surfaceTable[Util::ordinal( *drawSurf->surface )]( drawSurf->surface ); - pStage->colorRenderer( pStage ); + Tess_DrawElements(); Tess_Clear(); drawSurf->drawCommandIDs[stage] = lastCommandID; - if ( pStage->dynamic ) { - drawSurf->materialsSSBOOffset[stage] = ( SSBOOffset - dynamicDrawSurfsOffset + drawSurfCount * - material.shader->GetPaddedSize() ) / material.shader->GetPaddedSize(); - } - stage++; } + } + } + } - if ( hasDynamicStages ) { - // We need a copy here because the memory pointed to by drawSurf will change later - // We'll probably need a separate buffer for entities other than world entity + ensure we don't store a drawSurf with - // invalid pointers - dynamicDrawSurfs.emplace_back( *drawSurf ); - } + for ( shaderStage_t* pStage : materialStages ) { + if ( pStage->dynamic ) { + pStage->bufferOffset -= dynamicStagesOffset; + } + } + + materialsUBO.UnmapBuffer(); +} + +void MaterialSystem::GenerateMaterialsBuffer( std::vector& stages, const uint32_t size, uint32_t* materialsData ) { + // Shader uniforms are set to 0 if they're not specified, so make sure we do that here too + memset( materialsData, 0, size * sizeof( uint32_t ) ); + for ( shaderStage_t* pStage : stages ) { + /* Stage variants are essentially copies of the same stage with slightly different values that + normally come from a drawSurf_t */ + uint32_t variants = 0; + for ( int i = 0; i < ShaderStageVariant::ALL && variants < pStage->variantOffset; i++ ) { + if ( pStage->variantOffsets[i] != -1 ) { + const bool mayUseVertexOverbright = i & ShaderStageVariant::VERTEX_OVERBRIGHT; + const bool vertexLit = i & ShaderStageVariant::VERTEX_LIT; + const bool fullbright = i & ShaderStageVariant::FULLBRIGHT; + + const uint32_t variantOffset = pStage->variantOffsets[i] * pStage->paddedSize; + pStage->bufferOffset += variantOffset; + + pStage->surfaceDataUpdater( materialsData, pStage, mayUseVertexOverbright, vertexLit, fullbright ); + + pStage->bufferOffset -= variantOffset; + variants++; } } } +} + +void MaterialSystem::GenerateTexturesBuffer( std::vector& textures, TexBundle* textureBundles ) { + for ( TextureData& textureData : textures ) { + for ( int i = 0; i < MAX_TEXTURE_BUNDLES; i++ ) { + if ( textureData.texBundlesOverride[i] ) { + textureBundles->textures[i] = textureData.texBundlesOverride[i]->texture->bindlessTextureHandle; + continue; + } - materialsSSBO.UnmapBuffer(); + const textureBundle_t* bundle = textureData.texBundles[i]; + if ( bundle && bundle->image[0] ) { + if ( generatingWorldCommandBuffer ) { + textureBundles->textures[i] = bundle->image[0]->texture->bindlessTextureHandle; + } else { + textureBundles->textures[i] = BindAnimatedImage( 0, bundle ); + } + } + } + + const int bundle = textureData.textureMatrixBundle; + RB_CalcTexMatrix( textureData.texBundles[bundle], tess.svars.texMatrices[bundle] ); + /* We only actually need these 6 components to get the correct texture transformation, + the other ones are unused */ + textureBundles->textureMatrix[0] = tess.svars.texMatrices[bundle][0]; + textureBundles->textureMatrix[1] = tess.svars.texMatrices[bundle][1]; + textureBundles->textureMatrix[2] = tess.svars.texMatrices[bundle][4]; + textureBundles->textureMatrix[3] = tess.svars.texMatrices[bundle][5]; + textureBundles->textureMatrix[4] = tess.svars.texMatrices[bundle][12]; + textureBundles->textureMatrix[5] = tess.svars.texMatrices[bundle][13]; + textureBundles++; + } } -// This generates the buffer GLIndirect commands +// This generates the buffers with indirect rendering commands etc. void MaterialSystem::GenerateWorldCommandBuffer() { Log::Debug( "Generating world command buffer" ); @@ -789,37 +564,88 @@ void MaterialSystem::GenerateWorldCommandBuffer() { Log::Debug( "Total batch count: %u", totalBatchCount ); - drawSurf_t* drawSurf; - - 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.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 ) ); + + GenerateTexturesBuffer( texData, textureBundles ); + + textureBundles += texData.size(); + + GenerateTexturesBuffer( dynamicTexData, textureBundles ); + + dynamicTexDataOffset = texData.size() * TEX_BUNDLE_SIZE; + dynamicTexDataSize = dynamicTexData.size() * TEX_BUNDLE_SIZE; + + texDataBuffer.FlushAll(); + texDataBuffer.UnmapBuffer(); + + 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 ) ); + + 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; + } + 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; + } + + ASSERT_LE( tr.lightmaps.size(), 256 ); // Engine supports up to 256 lightmaps currently, so we use 8 bits to address them + + if ( tr.lightmaps.size() == 256 ) { + /* It's very unlikely that this would actually happen, but put the warn here just in case + If needed, another bit can be added to the lightmap address in rendering commands, but that would mean + that its hex representation would no longer be easily "parsable" by just looking at it in a frame debugger */ + Log::Warn( "Material system only supports up to 255 lightmaps, got 256" ); + } else { + if ( !tr.whiteImage->texture->hasBindlessHandle ) { + tr.whiteImage->texture->GenBindlessHandle(); + } + if ( !tr.blackImage->texture->hasBindlessHandle ) { + 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; + } + + lightMapDataUBO.FlushAll(); + lightMapDataUBO.UnmapBuffer(); + 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] = {}; @@ -838,10 +664,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 ) ); @@ -850,15 +674,15 @@ 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(); } for ( int i = 0; i < tr.refdef.numDrawSurfs; i++ ) { - drawSurf = &tr.refdef.drawSurfs[i]; + const drawSurf_t* drawSurf = &tr.refdef.drawSurfs[i]; + if ( drawSurf->entity != &tr.worldEntity ) { continue; } @@ -891,7 +715,8 @@ void MaterialSystem::GenerateWorldCommandBuffer() { if ( depthPrePass ) { const drawSurf_t* depthDrawSurf = drawSurf->depthSurface; - const Material* material = &materialPacks[depthDrawSurf->materialPackIDs[0]].materials[depthDrawSurf->materialIDs[0]]; + const Material* material = &materialPacks[depthDrawSurf->materialPackIDs[0]] + .materials[depthDrawSurf->materialIDs[0]]; uint cmdID = material->surfaceCommandBatchOffset * SURFACE_COMMANDS_PER_BATCH + depthDrawSurf->drawCommandIDs[0]; // Add 1 because cmd 0 == no-command surface.surfaceCommandIDs[0] = cmdID + 1; @@ -899,6 +724,10 @@ void MaterialSystem::GenerateWorldCommandBuffer() { SurfaceCommand surfaceCommand; surfaceCommand.enabled = 0; surfaceCommand.drawCommand = material->drawCommands[depthDrawSurf->drawCommandIDs[0]].cmd; + // We still need the textures for alpha-tested depth pre-pass surface commands + surfaceCommand.drawCommand.baseInstance |= depthDrawSurf->texDataDynamic[0] + ? ( depthDrawSurf->texDataIDs[0] + texData.size() ) << TEX_BUNDLE_BITS + : depthDrawSurf->texDataIDs[0] << TEX_BUNDLE_BITS; surfaceCommands[cmdID] = surfaceCommand; } @@ -912,6 +741,10 @@ void MaterialSystem::GenerateWorldCommandBuffer() { SurfaceCommand surfaceCommand; surfaceCommand.enabled = 0; surfaceCommand.drawCommand = material->drawCommands[drawSurf->drawCommandIDs[stage]].cmd; + surfaceCommand.drawCommand.baseInstance |= drawSurf->texDataDynamic[stage] + ? ( drawSurf->texDataIDs[stage] + texData.size() ) << TEX_BUNDLE_BITS + : drawSurf->texDataIDs[stage] << TEX_BUNDLE_BITS; + surfaceCommand.drawCommand.baseInstance |= ( HasLightMap( drawSurf ) ? GetLightMapNum( drawSurf ) : 255 ) << LIGHTMAP_BITS; surfaceCommands[cmdID] = surfaceCommand; stage++; @@ -919,7 +752,8 @@ void MaterialSystem::GenerateWorldCommandBuffer() { if ( drawSurf->fogSurface ) { const drawSurf_t* fogDrawSurf = drawSurf->fogSurface; - const Material* material = &materialPacks[fogDrawSurf->materialPackIDs[0]].materials[fogDrawSurf->materialIDs[0]]; + const Material* material = &materialPacks[fogDrawSurf->materialPackIDs[0]] + .materials[fogDrawSurf->materialIDs[0]]; uint cmdID = material->surfaceCommandBatchOffset * SURFACE_COMMANDS_PER_BATCH + fogDrawSurf->drawCommandIDs[0]; // Add 1 because cmd 0 == no-command surface.surfaceCommandIDs[stage + ( depthPrePass ? 1 : 0 )] = cmdID + 1; @@ -938,19 +772,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(); @@ -1230,6 +1059,8 @@ void BindShaderFog( Material* material ) { gl_fogQuake3ShaderMaterial->SetUniform_FogDepthVector( fogDepthVector ); gl_fogQuake3ShaderMaterial->SetUniform_FogEyeT( eyeT ); + gl_fogQuake3ShaderMaterial->SetUniform_ColorGlobal( fog->color ); + gl_fogQuake3ShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_fogQuake3ShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); @@ -1257,12 +1088,6 @@ void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, drawSu material->tcGen_Lightmap = pStage->tcGen_Lightmap; material->deformIndex = pStage->deformIndex; - colorGen_t rgbGen = SetRgbGen( pStage ); - alphaGen_t alphaGen = SetAlphaGen( pStage ); - - material->useAttrColor = rgbGen == colorGen_t::CGEN_VERTEX || rgbGen == colorGen_t::CGEN_ONE_MINUS_VERTEX - || alphaGen == alphaGen_t::AGEN_VERTEX || alphaGen == alphaGen_t::AGEN_ONE_MINUS_VERTEX; - gl_genericShaderMaterial->SetTCGenEnvironment( pStage->tcGen_Environment ); gl_genericShaderMaterial->SetTCGenLightmap( pStage->tcGen_Lightmap ); @@ -1288,14 +1113,6 @@ void ProcessMaterialLightMapping( Material* material, shaderStage_t* pStage, dra DAEMON_ASSERT( !( enableDeluxeMapping && enableGridDeluxeMapping ) ); - // useAttrColor has no effect since the lightMapping shader has ATTR_COLOR forced to be always - // on (_requiredVertexAttribs). If we removed ATTR_COLOR from there, we would need to detect - // implicit vertex lighting as well, not only rgbgen (see SetLightDeluxeMode). - /* colorGen_t rgbGen = SetRgbGen( pStage ); - alphaGen_t alphaGen = SetAlphaGen( pStage ); - material->useAttrColor = rgbGen == colorGen_t::CGEN_VERTEX || rgbGen == colorGen_t::CGEN_ONE_MINUS_VERTEX - || alphaGen == alphaGen_t::AGEN_VERTEX || alphaGen == alphaGen_t::AGEN_ONE_MINUS_VERTEX; */ - material->enableDeluxeMapping = enableDeluxeMapping; material->enableGridLighting = enableGridLighting; material->enableGridDeluxeMapping = enableGridDeluxeMapping; @@ -1392,8 +1209,122 @@ void ProcessMaterialFog( Material* material, shaderStage_t* pStage, drawSurf_t* material->program = gl_fogQuake3ShaderMaterial->GetProgram( pStage->deformIndex ); } +void MaterialSystem::AddStage( drawSurf_t* drawSurf, shaderStage_t* pStage, uint32_t stage, + const bool mayUseVertexOverbright, const bool vertexLit, const bool fullbright ) { + const int variant = ( mayUseVertexOverbright ? ShaderStageVariant::VERTEX_OVERBRIGHT : 0 ) + | ( vertexLit ? ShaderStageVariant::VERTEX_LIT : 0 ) + | ( fullbright ? ShaderStageVariant::FULLBRIGHT : 0 ); + + if ( pStage->variantOffsets[variant] == -1 ) { + pStage->variantOffsets[variant] = pStage->variantOffset; + pStage->variantOffset++; + } + + drawSurf->shaderVariant[stage] = variant; + + // Look for a stage that will have the same data layout and data + data changes themselves + for ( shaderStage_t* pStage2 : materialStages ) { + if ( pStage == pStage2 ) { + return; + } + + if ( pStage->shaderBinder != pStage2->shaderBinder ) { + continue; + } + + if ( pStage->dynamic != pStage2->dynamic ) { + continue; + } + + if ( pStage->ifExp != pStage2->ifExp ) { + continue; + } + + if ( pStage->rgbGen != pStage2->rgbGen ) { + continue; + } + + if ( pStage->rgbGen == colorGen_t::CGEN_WAVEFORM && pStage->rgbWave != pStage2->rgbWave ) { + continue; + } + + if ( pStage->rgbGen == colorGen_t::CGEN_CUSTOM_RGB && pStage->rgbExp != pStage2->rgbExp ) { + continue; + } + + if ( pStage->rgbGen == colorGen_t::CGEN_CUSTOM_RGBs && + !( pStage->redExp == pStage2->redExp && pStage->greenExp == pStage2->greenExp && pStage->blueExp == pStage2->blueExp ) ) { + continue; + } + + if ( ( pStage->type == stageType_t::ST_STYLELIGHTMAP || pStage->type == stageType_t::ST_STYLECOLORMAP + || pStage2->type == stageType_t::ST_STYLELIGHTMAP || pStage2->type == stageType_t::ST_STYLECOLORMAP ) && pStage->type != pStage2->type ) { + continue; + } + + if ( pStage->alphaGen != pStage2->alphaGen ) { + continue; + } + + if ( pStage->alphaGen == alphaGen_t::AGEN_WAVEFORM && pStage->alphaWave != pStage2->alphaWave ) { + continue; + } + + if ( pStage->alphaGen == alphaGen_t::AGEN_CUSTOM && pStage->alphaExp != pStage2->alphaExp ) { + continue; + } + + if ( pStage->constantColor.Red() != pStage2->constantColor.Red() || pStage->constantColor.Green() != pStage2->constantColor.Green() + || pStage->constantColor.Blue() != pStage2->constantColor.Blue() || pStage->constantColor.Alpha() != pStage2->constantColor.Alpha() ) { + continue; + } + + if ( pStage->depthFadeValue != pStage2->depthFadeValue ) { + continue; + } + + // Only GLS_ATEST_BITS affect stage data, the other bits go into the material + if ( ( pStage->stateBits & GLS_ATEST_BITS ) != ( pStage2->stateBits & GLS_ATEST_BITS ) ) { + continue; + } + + if ( pStage->refractionIndexExp != pStage2->refractionIndexExp || pStage->specularExponentMin != pStage2->specularExponentMin + || pStage->specularExponentMax != pStage2->specularExponentMax || pStage->fresnelPowerExp != pStage2->fresnelPowerExp + || pStage->fresnelScaleExp != pStage2->fresnelScaleExp || pStage->fresnelBiasExp != pStage2->fresnelBiasExp + || !VectorCompare( pStage->normalScale, pStage2->normalScale ) || pStage->normalIntensityExp != pStage2->normalIntensityExp + || pStage->fogDensityExp != pStage2->fogDensityExp || pStage->depthScaleExp != pStage2->depthScaleExp ) { + continue; + } + + pStage->materialRemappedStage = pStage2; + + if ( pStage2->variantOffsets[variant] == -1 ) { + pStage2->variantOffsets[variant] = pStage2->variantOffset; + pStage2->variantOffset++; + } + + return; + } + + // Add at the back if we haven't found any matching ones + materialStages.emplace_back( pStage ); + + if ( pStage->dynamic ) { + dynamicStages.emplace_back( pStage ); + } +} + void MaterialSystem::ProcessStage( drawSurf_t* drawSurf, shaderStage_t* pStage, shader_t* shader, uint32_t* packIDs, uint32_t& stage, uint32_t& previousMaterialID ) { + lightMode_t lightMode; + deluxeMode_t deluxeMode; + SetLightDeluxeMode( drawSurf, pStage->type, lightMode, deluxeMode ); + const bool mayUseVertexOverbright = pStage->type == stageType_t::ST_COLORMAP && drawSurf->bspSurface && pStage->shaderBinder == BindShaderGeneric3D; + const bool vertexLit = lightMode == lightMode_t::VERTEX && pStage->shaderBinder == BindShaderLightMapping; + const bool fullbright = lightMode == lightMode_t::FULLBRIGHT && pStage->shaderBinder == BindShaderLightMapping; + + ComputeDynamics( pStage ); + Material material; uint32_t materialPack = 0; @@ -1423,17 +1354,9 @@ void MaterialSystem::ProcessStage( drawSurf_t* drawSurf, shaderStage_t* pStage, material.cullType = shader->cullType; material.usePolygonOffset = shader->polygonOffset; - material.vbo = glState.currentVBO; - material.ibo = glState.currentIBO; - - ComputeDynamics( pStage ); - - if ( pStage->texturesDynamic ) { - drawSurf->texturesDynamic[stage] = true; - } - material.bspSurface = drawSurf->bspSurface; pStage->materialProcessor( &material, pStage, drawSurf ); + pStage->paddedSize = material.shader->GetPaddedSize(); std::vector& materials = materialPacks[materialPack].materials; std::vector::iterator currentSearchIt = materials.begin(); @@ -1462,12 +1385,10 @@ void MaterialSystem::ProcessStage( drawSurf_t* drawSurf, shaderStage_t* pStage, } pStage->useMaterialSystem = true; - materials[previousMaterialID].totalDrawSurfCount++; - if ( pStage->dynamic ) { - materials[previousMaterialID].totalDynamicDrawSurfCount++; - } else { - materials[previousMaterialID].totalStaticDrawSurfCount++; - } + pStage->initialized = true; + + AddStage( drawSurf, pStage, stage, mayUseVertexOverbright, vertexLit, fullbright ); + AddStageTextures( drawSurf, stage, &materials[previousMaterialID] ); if ( std::find( materials[previousMaterialID].drawSurfs.begin(), materials[previousMaterialID].drawSurfs.end(), drawSurf ) == materials[previousMaterialID].drawSurfs.end() ) { @@ -1486,10 +1407,10 @@ void MaterialSystem::ProcessStage( drawSurf_t* drawSurf, shaderStage_t* pStage, * A material represents a distinct global OpenGL state (e. g. blend function, depth test, depth write etc.) * Materials can have a dependency on other materials to make sure that consecutive stages are rendered in the proper order */ void MaterialSystem::GenerateWorldMaterials() { - const int current_r_nocull = r_nocull->integer; - const int current_r_drawworld = r_drawworld->integer; - r_nocull->integer = 1; - r_drawworld->integer = 1; + const bool current_r_nocull = r_nocull.Get(); + const bool current_r_drawworld = r_drawworld.Get(); + r_nocull.Set( true ); + r_drawworld.Set( true ); generatingWorldCommandBuffer = true; Log::Debug( "Generating world materials" ); @@ -1506,13 +1427,12 @@ void MaterialSystem::GenerateWorldMaterials() { backEnd.currentEntity = &tr.worldEntity; - drawSurf_t* drawSurf; totalDrawSurfs = 0; uint32_t packIDs[3] = { 0, 0, 0 }; for ( int i = 0; i < tr.refdef.numDrawSurfs; i++ ) { - drawSurf = &tr.refdef.drawSurfs[i]; + drawSurf_t* drawSurf = &tr.refdef.drawSurfs[i]; if ( drawSurf->entity != &tr.worldEntity ) { continue; } @@ -1532,12 +1452,7 @@ void MaterialSystem::GenerateWorldMaterials() { continue; } - // The verts aren't used; it's only to get the VBO/IBO. - Tess_Begin( Tess_StageIteratorDummy, shader, nullptr, true, -1, 0 ); - rb_surfaceTable[Util::ordinal( *( drawSurf->surface ) )]( drawSurf->surface ); - Tess_Clear(); - - // Only add the main surface for surfaces with depth pre-pass to the total count + // Only add the main surface for surfaces with depth pre-pass or fog to the total count if ( !drawSurf->materialSystemSkip ) { totalDrawSurfs++; } @@ -1556,19 +1471,22 @@ void MaterialSystem::GenerateWorldMaterials() { totalCount += pack.materials.size(); } Log::Notice( "Generated %u materials from %u surfaces", totalCount, tr.refdef.numDrawSurfs ); + Log::Notice( "Materials UBO: total: %.2f kb, dynamic: %.2f kb, texData: %.2f kb", + totalStageSize * 4 / 1024.0f, dynamicStagesSize * 4 / 1024.0f, + ( texData.size() + dynamicTexData.size() ) * TEX_BUNDLE_SIZE * 4 / 1024.0f ); + /* for ( const MaterialPack& materialPack : materialPacks ) { Log::Notice( "materialPack sort: %i %i", Util::ordinal( materialPack.fromSort ), Util::ordinal( materialPack.toSort ) ); for ( const Material& material : materialPack.materials ) { - Log::Notice( "id: %u, useSync: %b, sync: %u, program: %i, stateBits: %u, totalDrawSurfCount: %u, shader: %s, vbo: %s, ibo: %s" - ", staticDrawSurfs: %u, dynamicDrawSurfs: %u, culling: %i", - material.id, material.useSync, material.syncMaterial, material.program, material.stateBits, material.totalDrawSurfCount, - material.shader->GetName(), material.vbo->name, material.ibo->name, material.currentStaticDrawSurfCount, - material.currentDynamicDrawSurfCount, material.cullType ); + Log::Notice( "id: %u, useSync: %b, sync: %u, program: %i, stateBits: %u, total drawSurfs: %u, shader: %s, vbo: %s, ibo: %s" + ", culling: %i", + material.id, material.useSync, material.syncMaterial, material.program, material.stateBits, material.drawSurfs.size(), + material.shader->GetName(), material.vbo->name, material.ibo->name, material.cullType ); } } */ - r_nocull->integer = current_r_nocull; - r_drawworld->integer = current_r_drawworld; + r_nocull.Set( current_r_nocull ); + r_drawworld.Set( current_r_drawworld ); AddAllWorldSurfaces(); GeneratePortalBoundingSpheres(); @@ -1582,8 +1500,15 @@ void MaterialSystem::AddAllWorldSurfaces() { generatingWorldCommandBuffer = false; } -void MaterialSystem::AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pStage, Material* material ) { - for ( const textureBundle_t& bundle : pStage->bundle ) { +void MaterialSystem::AddStageTextures( drawSurf_t* drawSurf, const uint32_t stage, Material* material ) { + TextureData textureData; + const shaderStage_t* pStage = &drawSurf->shader->stages[stage]; + + int bundleNum = 0; + bool dynamic = false; + for ( int i = 0; i < MAX_TEXTURE_BUNDLES; i++ ) { + const textureBundle_t& bundle = pStage->bundle[i]; + if ( bundle.isVideoMap ) { material->AddTexture( tr.cinematicImage[bundle.videoMapHandle]->texture ); continue; @@ -1594,10 +1519,17 @@ void MaterialSystem::AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pSta material->AddTexture( image->texture ); } } + + if ( bundle.numImages > 1 || bundle.numTexMods > 0 ) { + textureData.textureMatrixBundle = i; + dynamic = true; + } + + textureData.texBundles[bundleNum] = &bundle; + bundleNum++; } // Add lightmap and deluxemap for this surface to the material as well - lightMode_t lightMode; deluxeMode_t deluxeMode; SetLightDeluxeMode( drawSurf, pStage->type, lightMode, deluxeMode ); @@ -1609,6 +1541,21 @@ void MaterialSystem::AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pSta material->AddTexture( lightmap->texture ); material->AddTexture( deluxemap->texture ); + if ( pStage->type == stageType_t::ST_STYLELIGHTMAP ) { + textureData.texBundlesOverride[TB_COLORMAP] = lightmap; + } + + std::vector& textures = dynamic ? dynamicTexData : texData; + + std::vector::iterator it = std::find( textures.begin(), textures.end(), textureData ); + if ( it == textures.end() ) { + drawSurf->texDataIDs[stage] = textures.size(); + textures.emplace_back( textureData ); + } else { + drawSurf->texDataIDs[stage] = it - textures.begin(); + } + drawSurf->texDataDynamic[stage] = dynamic; + if ( glConfig2.realtimeLighting ) { if ( r_realtimeLightingRenderer.Get() == Util::ordinal( realtimeLightingRenderer_t::TILED ) ) { material->AddTexture( tr.lighttileRenderImage->texture ); @@ -1618,33 +1565,32 @@ void MaterialSystem::AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pSta // Dynamic surfaces are those whose values in the SSBO can be updated void MaterialSystem::UpdateDynamicSurfaces() { - if ( dynamicDrawSurfsSize == 0 ) { - return; + if ( dynamicStagesSize > 0 ) { + uint32_t* materialsData = materialsUBO.MapBufferRange( dynamicStagesOffset, dynamicStagesSize ); + + GenerateMaterialsBuffer( dynamicStages, dynamicStagesSize, materialsData ); + + materialsUBO.UnmapBuffer(); } - materialsSSBO.BindBuffer(); - uint32_t* materialsData = materialsSSBO.MapBufferRange( dynamicDrawSurfsOffset, dynamicDrawSurfsSize ); - // Shader uniforms are set to 0 if they're not specified, so make sure we do that here too - memset( materialsData, 0, 4 * dynamicDrawSurfsSize ); - for ( drawSurf_t& drawSurf : dynamicDrawSurfs ) { - uint32_t stage = 0; - for ( shaderStage_t* pStage = drawSurf.shader->stages; pStage < drawSurf.shader->lastStage; pStage++ ) { - Material& material = materialPacks[drawSurf.materialPackIDs[stage]].materials[drawSurf.materialIDs[stage]]; + if ( dynamicTexDataSize > 0 ) { + TexBundle* textureBundles = + ( TexBundle* ) texDataBuffer.MapBufferRange( dynamicTexDataOffset, dynamicTexDataSize ); - pStage->surfaceDataUpdater( materialsData, material, &drawSurf, stage ); + GenerateTexturesBuffer( dynamicTexData, textureBundles ); - stage++; - } + texDataBuffer.UnmapBuffer(); } - materialsSSBO.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(); } @@ -1656,7 +1602,7 @@ void MaterialSystem::QueueSurfaceCull( const uint32_t viewID, const vec3_t origi } void MaterialSystem::DepthReduction() { - if ( r_lockpvs->integer ) { + if ( r_lockpvs.Get() ) { if ( !PVSLocked ) { lockedDepthImage = depthImage; } @@ -1763,11 +1709,11 @@ void MaterialSystem::CullSurfaces() { } if ( PVSLocked ) { - if ( r_lockpvs->integer == 0 ) { + if ( !r_lockpvs.Get() ) { PVSLocked = false; } } - if ( r_lockpvs->integer == 1 && !PVSLocked ) { + if ( r_lockpvs.Get() && !PVSLocked ) { PVSLocked = true; for ( int i = 0; i < 6; i++ ) { VectorCopy( frustum[0][i].normal, lockedFrustums[view][i].normal ); @@ -1879,30 +1825,69 @@ 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; - dynamicDrawSurfs.clear(); + materialStages.clear(); + dynamicStages.clear(); autospriteSurfaces.clear(); portalSurfaces.clear(); portalSurfacesTmp.clear(); portalBounds.clear(); skyShaders.clear(); renderedMaterials.clear(); + texData.clear(); + dynamicTexData.clear(); R_SyncRenderThread(); surfaceCommandsSSBO.UnmapBuffer(); culledCommandsBuffer.UnmapBuffer(); atomicCommandCountersBuffer.UnmapBuffer(); + texDataBuffer.UnmapBuffer(); + lightMapDataUBO.UnmapBuffer(); if ( totalPortals > 0 ) { portalSurfacesSSBO.UnmapBuffer(); @@ -2020,7 +2005,7 @@ void MaterialSystem::AddPortalSurfaces() { return; } - if ( r_lockpvs->integer ) { + if ( r_lockpvs.Get() ) { return; } @@ -2045,7 +2030,7 @@ void MaterialSystem::AddAutospriteSurfaces() { } void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderSort_t toSort, const uint32_t viewID ) { - if ( !r_drawworld->integer ) { + if ( !r_drawworld.Get() ) { return; } @@ -2064,7 +2049,9 @@ void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderS frameStart = false; } - materialsSSBO.BindBufferBase(); + materialsUBO.BindBufferBase(); + + geometryCache.Bind(); for ( MaterialPack& materialPack : materialPacks ) { if ( materialPack.fromSort >= fromSort && materialPack.toSort <= toSort ) { @@ -2075,6 +2062,8 @@ void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderS } } + glBindVertexArray( backEnd.currentVAO ); + // Draw the skybox here because we skipped R_AddWorldSurfaces() const bool environmentFogDraw = ( fromSort <= shaderSort_t::SS_ENVIRONMENT_FOG ) && ( toSort >= shaderSort_t::SS_ENVIRONMENT_FOG ); const bool environmentNoFogDraw = ( fromSort <= shaderSort_t::SS_ENVIRONMENT_NOFOG ) && toSort >= ( shaderSort_t::SS_ENVIRONMENT_NOFOG ); @@ -2094,9 +2083,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 ); @@ -2137,23 +2126,17 @@ void MaterialSystem::RenderMaterial( Material& material, const uint32_t viewID ) } if( material.shaderBinder == BindShaderFog ) { - if ( r_noFog->integer || !r_wolfFog->integer || ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { + if ( r_noFog.Get() || !r_wolfFog.Get() || ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { return; } } backEnd.currentEntity = &tr.worldEntity; - if ( material.useAttrColor ) { - material.shader->AddVertexAttribBit( ATTR_COLOR ); - } else { - material.shader->DelVertexAttribBit( ATTR_COLOR ); - } - GL_State( stateBits ); if ( material.usePolygonOffset ) { glEnable( GL_POLYGON_OFFSET_FILL ); - GL_PolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); + GL_PolygonOffset( r_offsetFactor.Get(), r_offsetUnits.Get() ); } else { glDisable( GL_POLYGON_OFFSET_FILL ); } @@ -2164,10 +2147,6 @@ void MaterialSystem::RenderMaterial( Material& material, const uint32_t viewID ) material.shaderBinder( &material ); - R_BindVBO( material.vbo ); - R_BindIBO( material.ibo ); - material.shader->SetRequiredVertexPointers(); - if ( !material.texturesResident ) { for ( Texture* texture : material.textures ) { if ( !texture->IsResident() ) { @@ -2206,6 +2185,9 @@ void MaterialSystem::RenderMaterial( Material& material, const uint32_t viewID ) atomicCommandCountersBuffer.BindBuffer( GL_PARAMETER_BUFFER_ARB ); + texDataBuffer.BindBufferBase( texDataBufferType ); + lightMapDataUBO.BindBufferBase(); + if ( r_showGlobalMaterials.Get() && material.sort != 0 && ( material.shaderBinder == BindShaderLightMapping || material.shaderBinder == BindShaderGeneric3D ) ) { vec3_t color; @@ -2296,7 +2278,7 @@ void MaterialSystem::RenderMaterial( Material& material, const uint32_t viewID ) RenderIndirect( material, viewID ); } - if ( r_showTris->integer + if ( r_showTris.Get() && ( material.stateBits & GLS_DEPTHMASK_TRUE ) == 0 && ( material.shaderBinder == &BindShaderLightMapping || material.shaderBinder == &BindShaderGeneric3D ) ) { @@ -2320,6 +2302,9 @@ void MaterialSystem::RenderMaterial( Material& material, const uint32_t viewID ) atomicCommandCountersBuffer.UnBindBuffer( GL_PARAMETER_BUFFER_ARB ); + texDataBuffer.UnBindBufferBase( texDataBufferType ); + lightMapDataUBO.UnBindBufferBase(); + if ( material.usePolygonOffset ) { glDisable( GL_POLYGON_OFFSET_FILL ); } diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h index 9a41d0093c..aac4e40391 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; @@ -70,14 +78,6 @@ struct DrawCommand { struct Material { uint32_t materialsSSBOOffset = 0; - uint32_t staticMaterialsSSBOOffset = 0; - uint32_t dynamicMaterialsSSBOOffset = 0; - uint32_t totalDrawSurfCount = 0; - uint32_t totalStaticDrawSurfCount = 0; - uint32_t totalDynamicDrawSurfCount = 0; - uint32_t currentDrawSurfCount = 0; - uint32_t currentStaticDrawSurfCount = 0; - uint32_t currentDynamicDrawSurfCount = 0; uint32_t globalID = 0; uint32_t surfaceCommandBatchOffset = 0; @@ -108,17 +108,12 @@ struct Material { bool enableSpecularMapping; bool enablePhysicalMapping; - bool useAttrColor = false; - cullType_t cullType; uint32_t sort; bool usePolygonOffset = false; - VBO_t* vbo; - IBO_t* ibo; - fog_t* fog = nullptr; std::vector drawSurfs; @@ -127,9 +122,8 @@ struct Material { std::vector textures; bool operator==( const Material& other ) { - return program == other.program && stateBits == other.stateBits && vbo == other.vbo && ibo == other.ibo - && fog == other.fog && cullType == other.cullType && usePolygonOffset == other.usePolygonOffset - && useAttrColor == other.useAttrColor; + return program == other.program && stateBits == other.stateBits + && fog == other.fog && cullType == other.cullType && usePolygonOffset == other.usePolygonOffset; } void AddTexture( Texture* texture ) { @@ -143,6 +137,59 @@ struct Material { } }; +struct TexBundle { + vec_t textureMatrix[6]; + GLuint64 textures[MAX_TEXTURE_BUNDLES]; +}; + +struct TextureData { + const textureBundle_t* texBundles[MAX_TEXTURE_BUNDLES] = { nullptr, nullptr, nullptr, nullptr, nullptr }; + // For ST_STYLELIGHTMAP stages + image_t* texBundlesOverride[MAX_TEXTURE_BUNDLES] = { nullptr, nullptr, nullptr, nullptr, nullptr }; + int textureMatrixBundle = 0; + + bool operator==( const TextureData& other ) const { + for ( int i = 0; i < MAX_TEXTURE_BUNDLES; i++ ) { + if ( texBundlesOverride[i] != other.texBundlesOverride[i] ) { + return false; + } + + const textureBundle_t* bundle = texBundles[i]; + const textureBundle_t* otherBundle = other.texBundles[i]; + + // Skip texBundles image check for ST_STYLELIGHTMAP + if ( !texBundlesOverride[i] ) { + if ( bundle->numImages != otherBundle->numImages ) { + return false; + } + + if ( ( bundle->numImages > 1 ) && ( bundle->imageAnimationSpeed != otherBundle->imageAnimationSpeed ) ) { + return false; + } + + const uint8_t numImages = bundle->numImages > 0 ? bundle->numImages : 1; + for ( int j = 0; j < numImages; j++ ) { + if ( bundle->image[j] != otherBundle->image[j] ) { + return false; + } + } + } + + if ( bundle->numTexMods != otherBundle->numTexMods ) { + return false; + } + + for ( size_t j = 0; j < bundle->numTexMods; j++ ) { + if ( bundle->texMods[j] != otherBundle->texMods[j] ) { + return false; + } + } + } + + return true; + } +}; + enum class MaterialDebugMode { NONE, DEPTH, @@ -178,8 +225,19 @@ extern PortalView portalStack[MAX_VIEWS]; #define INDIRECT_COMMAND_SIZE 5 #define SURFACE_COMMAND_SIZE 4 #define SURFACE_COMMAND_BATCH_SIZE 2 +#define TEX_BUNDLE_SIZE 16 +#define TEX_BUNDLE_BITS 12 +#define LIGHTMAP_SIZE 4 +#define LIGHTMAP_BITS 24 #define PORTAL_SURFACE_SIZE 8 +// 64kb min +#define MIN_MATERIAL_UBO_SIZE BIT( 16 ) + +/* 64kb UBO : 54kb texBundles, 4kb lightmaps, 2kb map shader stages, 4kb entity shader stages +Current mapss use up to ~38kb at max, without models */ +#define MAX_TEX_BUNDLES 54 * 1024 / 64 + #define MAX_FRAMES 2 #define MAX_VIEWFRAMES MAX_VIEWS * MAX_FRAMES // Buffer 2 frames for each view @@ -216,6 +274,23 @@ 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, + GEOMETRY_CACHE_INPUT_VBO = 6, + GEOMETRY_CACHE_VBO = 7, + DEBUG = 10, + UNUSED = INT32_MAX +}; + class MaterialSystem { public: bool generatedWorldCommandBuffer = false; @@ -276,7 +351,12 @@ class MaterialSystem { void GenerateDepthImages( const int width, const int height, imageParams_t imageParms ); - void AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pStage, Material* material ); + 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 ); void ProcessStage( drawSurf_t* drawSurf, shaderStage_t* pStage, shader_t* shader, uint32_t* packIDs, uint32_t& stage, uint32_t& previousMaterialID ); void GenerateWorldMaterials(); @@ -284,6 +364,9 @@ class MaterialSystem { void GenerateWorldCommandBuffer(); void GeneratePortalBoundingSpheres(); + void GenerateMaterialsBuffer( std::vector& stages, const uint32_t size, uint32_t* materialsData ); + void GenerateTexturesBuffer( std::vector& textures, TexBundle* textureBundles ); + void AddAllWorldSurfaces(); void Free(); @@ -308,9 +391,18 @@ class MaterialSystem { uint32_t surfaceCommandsCount = 0; uint32_t surfaceDescriptorsCount = 0; - std::vector dynamicDrawSurfs; - uint32_t dynamicDrawSurfsOffset = 0; - uint32_t dynamicDrawSurfsSize = 0; + std::vector materialStages; + std::vector dynamicStages; + + GLenum texDataBufferType; + std::vector texData; + std::vector dynamicTexData; + + uint32_t totalStageSize; + uint32_t dynamicStagesOffset = 0; + uint32_t dynamicStagesSize = 0; + uint32_t dynamicTexDataOffset = 0; + uint32_t dynamicTexDataSize = 0; Frame frames[MAX_FRAMES]; uint32_t currentFrame = 0; @@ -323,7 +415,9 @@ class MaterialSystem { void UpdateFrameData(); }; -extern GLSSBO materialsSSBO; // Global +extern GLUBO materialsUBO; // Global +extern GLBuffer texDataBuffer; // Global +extern GLUBO lightMapDataUBO; // Global extern GLSSBO surfaceDescriptorsSSBO; // Global extern GLSSBO surfaceCommandsSSBO; // Per viewframe, GPU updated @@ -336,16 +430,18 @@ extern GLSSBO debugSSBO; // Global extern MaterialSystem materialSystem; -void UpdateSurfaceDataNONE( uint32_t*, Material&, drawSurf_t*, const uint32_t ); -void UpdateSurfaceDataNOP( uint32_t*, Material&, drawSurf_t*, const uint32_t ); -void UpdateSurfaceDataGeneric3D( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ); -void UpdateSurfaceDataLightMapping( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ); -void UpdateSurfaceDataReflection( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ); -void UpdateSurfaceDataSkybox( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ); -void UpdateSurfaceDataScreen( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ); -void UpdateSurfaceDataHeatHaze( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ); -void UpdateSurfaceDataLiquid( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ); -void UpdateSurfaceDataFog( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ); +void UpdateSurfaceDataNONE( uint32_t*, shaderStage_t*, bool, bool, bool ); +void UpdateSurfaceDataNOP( uint32_t*, shaderStage_t*, bool, bool, bool ); +void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, bool mayUseVertexOverbright, bool, bool ); +void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, bool, bool vertexLit, bool fullbright ); +void UpdateSurfaceDataReflection( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); +void UpdateSurfaceDataSkybox( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); +void UpdateSurfaceDataScreen( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); +void UpdateSurfaceDataHeatHaze( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); +void UpdateSurfaceDataLiquid( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); +void UpdateSurfaceDataFog( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); + +// void UpdateSurf( uint32) void BindShaderNONE( Material* ); void BindShaderNOP( Material* ); @@ -360,7 +456,7 @@ void BindShaderFog( Material* material ); void ProcessMaterialNONE( Material*, shaderStage_t*, drawSurf_t* ); void ProcessMaterialNOP( Material*, shaderStage_t*, drawSurf_t* ); -void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ); +void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, drawSurf_t* /* drawSurf */ ); void ProcessMaterialLightMapping( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ); void ProcessMaterialReflection( Material* material, shaderStage_t* pStage, drawSurf_t* /* drawSurf */ ); void ProcessMaterialSkybox( Material* material, shaderStage_t* pStage, drawSurf_t* /* drawSurf */ ); diff --git a/src/engine/renderer/ShadeCommon.h b/src/engine/renderer/ShadeCommon.h index 79fc32abff..f83f6ecf92 100644 --- a/src/engine/renderer/ShadeCommon.h +++ b/src/engine/renderer/ShadeCommon.h @@ -32,12 +32,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =========================================================================== */ -inline size_t GetLightMapNum( shaderCommands_t* tess ) +inline size_t GetLightMapNum( const shaderCommands_t* tess ) { return tess->lightmapNum; } -inline size_t GetLightMapNum( drawSurf_t* drawSurf ) +inline size_t GetLightMapNum( const drawSurf_t* drawSurf ) { return drawSurf->lightmapNum(); } diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index d37926ffdb..0f15568b58 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"; @@ -599,9 +623,14 @@ static std::string GenEngineConstants() { // Engine constants std::string str; - AddDefine( str, "r_AmbientScale", r_ambientScale.Get() ); - AddDefine( str, "r_SpecularScale", r_specularScale->value ); - AddDefine( str, "r_zNear", r_znear->value ); + if ( r_ambientScale.Get() ) { + AddDefine( str, "r_AmbientScale", 1 ); + } + + if ( r_specularScale.Get() ) { + AddDefine( str, "r_SpecularScale", 1 ); + } + AddDefine( str, "r_zNear", r_znear.Get() ); AddDefine( str, "M_PI", static_cast< float >( M_PI ) ); AddDefine( str, "MAX_SHADOWMAPS", MAX_SHADOWMAPS ); @@ -712,22 +741,23 @@ static std::string GenEngineConstants() { AddDefine( str, "r_realtimeLightingRenderer", r_realtimeLightingRenderer.Get() ); } - if ( r_precomputedLighting->integer ) + if ( r_precomputedLighting.Get() ) { AddDefine( str, "r_precomputedLighting", 1 ); + } - if ( r_showNormalMaps->integer ) + if ( r_showNormalMaps.Get() ) { AddDefine( str, "r_showNormalMaps", 1 ); } - else if ( r_showMaterialMaps->integer ) + else if ( r_showMaterialMaps.Get() ) { AddDefine( str, "r_showMaterialMaps", 1 ); } - else if ( r_showLightMaps->integer ) + else if ( r_showLightMaps.Get() ) { AddDefine( str, "r_showLightMaps", 1 ); } - else if ( r_showDeluxeMaps->integer ) + else if ( r_showDeluxeMaps.Get() ) { AddDefine( str, "r_showDeluxeMaps", 1 ); } @@ -769,16 +799,18 @@ static std::string GenEngineConstants() { AddConst( str, "MAX_GLSL_BONES", 4 ); } - if ( r_halfLambertLighting->integer ) + if ( r_halfLambertLighting.Get() ) + { AddDefine( str, "r_halfLambertLighting", 1 ); + } - if ( r_rimLighting->integer ) + if ( r_rimLighting.Get() ) { AddDefine( str, "r_rimLighting", 1 ); - AddConst( str, "r_RimExponent", r_rimExponent->value ); + AddConst( str, "r_RimExponent", r_rimExponent.Get() ); } - if ( r_showLightTiles->integer ) + if ( r_showLightTiles.Get() ) { AddDefine( str, "r_showLightTiles", 1 ); } @@ -788,7 +820,7 @@ static std::string GenEngineConstants() { AddDefine( str, "r_normalMapping", 1 ); } - if ( r_liquidMapping->integer ) + if ( r_liquidMapping.Get() ) { AddDefine( str, "r_liquidMapping", 1 ); } @@ -803,7 +835,7 @@ static std::string GenEngineConstants() { AddDefine( str, "r_physicalMapping", 1 ); } - if ( r_glowMapping->integer ) + if ( r_glowMapping.Get() ) { AddDefine( str, "r_glowMapping", 1 ); } @@ -813,8 +845,6 @@ static std::string GenEngineConstants() { AddDefine( str, "r_colorGrading", 1 ); } - AddDefine( str, "r_zNear", r_znear->value ); - return str; } @@ -1359,9 +1389,53 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str std::string newShaderText; std::string materialStruct = "\nstruct Material {\n"; - std::string materialBlock = "layout(std430, binding = 0) readonly buffer materialsSSBO {\n" - " Material materials[];\n" - "};\n\n"; + // 6 kb for materials + const uint32_t count = ( 4096 + 2048 ) / shader->GetPaddedSize(); + 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 = " + + 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 = " + + 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 + std::string texDataBlock = "struct TexData {\n" + " vec4 u_TextureMatrix;\n" + " vec2 u_TextureMatrix2;\n" + " uvec2 u_DiffuseMap;\n" + " uvec2 u_NormalMap;\n" + " uvec2 u_HeightMap;\n" + " uvec2 u_MaterialMap;\n" + " uvec2 u_GlowMap;\n" + "};\n\n" + + texBuf + + "#define u_TextureMatrix mat3x2( texData[( baseInstance >> 12 ) & 0xFFF].u_TextureMatrix.xy, texData[( baseInstance >> 12 ) & 0xFFF].u_TextureMatrix.zw, texData[( baseInstance >> 12 ) & 0xFFF].u_TextureMatrix2 )\n" + "#define u_DiffuseMap_initial texData[( baseInstance >> 12 ) & 0xFFF].u_DiffuseMap\n" + "#define u_NormalMap_initial texData[( baseInstance >> 12 ) & 0xFFF].u_NormalMap\n" + "#define u_HeightMap_initial texData[( baseInstance >> 12 ) & 0xFFF].u_HeightMap\n" + "#define u_MaterialMap_initial texData[( baseInstance >> 12 ) & 0xFFF].u_MaterialMap\n" + "#define u_GlowMap_initial texData[( baseInstance >> 12 ) & 0xFFF].u_GlowMap\n\n" + "struct LightMapData {\n" + " uvec2 u_LightMap;\n" + " uvec2 u_DeluxeMap;\n" + "};\n\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" + "#define u_DeluxeMap_initial lightMapData[( baseInstance >> 24 ) & 0xFF].u_DeluxeMap\n\n"; std::string materialDefines; /* Generate the struct and defines in the form of: @@ -1380,24 +1454,25 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str continue; } - if ( uniform->IsTexture() ) { - materialStruct += " uvec2 "; - materialStruct += uniform->GetName(); - } else { - materialStruct += " " + uniform->GetType() + " " + uniform->GetName(); - } + if ( !uniform->IsTexture() ) { + materialStruct += " " + uniform->GetType() + " " + uniform->GetName(); - if ( uniform->GetComponentSize() ) { - materialStruct += "[ " + std::to_string( uniform->GetComponentSize() ) + " ]"; + if ( uniform->GetComponentSize() ) { + materialStruct += "[ " + std::to_string( uniform->GetComponentSize() ) + " ]"; + } + materialStruct += ";\n"; + + // vec3 is aligned to 4 components, so just pad it with int + // TODO: Try to move 1 component uniforms here to avoid wasting memory + if ( uniform->GetSTD430Size() == 3 ) { + materialStruct += " int "; + materialStruct += uniform->GetName(); + materialStruct += "_padding;\n"; + } } - materialStruct += ";\n"; - // vec3 is aligned to 4 components, so just pad it with int - // TODO: Try to move 1 component uniforms here to avoid wasting memory - if ( uniform->GetSTD430Size() == 3 ) { - materialStruct += " int "; - materialStruct += uniform->GetName(); - materialStruct += "_padding;\n"; + if ( uniform->IsTexture() ) { + continue; } materialDefines += "#define "; @@ -1407,7 +1482,7 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str materialDefines += "_initial uvec2("; // We'll need this to create sampler objects later } - materialDefines += " materials[baseInstance]."; + materialDefines += " materials[baseInstance & 0xFFF]."; materialDefines += uniform->GetName(); if ( uniform->IsTexture() ) { @@ -1419,7 +1494,7 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str // Array of structs is aligned to the largest member of the struct for ( uint i = 0; i < shader->padding; i++ ) { - materialStruct += " int material_padding" + std::to_string( i ); + materialStruct += " int material_padding" + std::to_string( i ); materialStruct += ";\n"; } @@ -1457,7 +1532,7 @@ std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::str materialDefines += "\n"; - newShaderText = "#define USE_MATERIAL_SYSTEM\n" + materialStruct + materialBlock + materialDefines + shaderMain; + newShaderText = "#define USE_MATERIAL_SYSTEM\n" + materialStruct + materialBlock + texDataBlock + materialDefines + shaderMain; return newShaderText; } @@ -1978,7 +2053,7 @@ void GLShader::PostProcessUniforms() { std::vector globalUniforms; for ( GLUniform* uniform : _uniforms ) { - if ( uniform->IsGlobal() ) { + if ( uniform->IsGlobal() || uniform->IsTexture() ) { globalUniforms.emplace_back( uniform ); } } @@ -1988,7 +2063,6 @@ void GLShader::PostProcessUniforms() { // Sort uniforms from highest to lowest alignment so we don't need to pad uniforms (other than vec3s) const uint numUniforms = _uniforms.size(); - GLuint structAlignment = 0; GLuint structSize = 0; while ( tmp.size() < numUniforms ) { // Higher-alignment uniforms first to avoid wasting memory @@ -1999,9 +2073,7 @@ void GLShader::PostProcessUniforms() { highestAlignment = _uniforms[i]->GetSTD430Alignment(); highestUniform = i; } - if ( highestAlignment > structAlignment ) { - structAlignment = highestAlignment; - } + if ( highestAlignment == 4 ) { break; // 4-component is the highest alignment in std430 } @@ -2020,6 +2092,7 @@ void GLShader::PostProcessUniforms() { } _uniforms = tmp; + const GLuint structAlignment = 4; // Material buffer is now a UBO, so it uses std140 layout, which is aligned to vec4 if ( structSize > 0 ) { padding = ( structAlignment - ( structSize % structAlignment ) ) % structAlignment; } @@ -2178,14 +2251,14 @@ void GLShader::SetRequiredVertexPointers() void GLShader::WriteUniformsToBuffer( uint32_t* buffer ) { uint32_t* bufPtr = buffer; for ( GLUniform* uniform : _uniforms ) { - if ( !uniform->IsGlobal() ) { + if ( !uniform->IsGlobal() && !uniform->IsTexture() ) { bufPtr = uniform->WriteToBuffer( bufPtr ); } } } GLShader_generic::GLShader_generic( GLShaderManager *manager ) : - GLShader( "generic", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + GLShader( "generic", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_COLOR, manager ), u_ColorMap( this ), u_DepthMap( this ), u_TextureMatrix( this ), @@ -2217,7 +2290,7 @@ void GLShader_generic::SetShaderProgramUniforms( shaderProgram_t *shaderProgram } GLShader_genericMaterial::GLShader_genericMaterial( GLShaderManager* manager ) : - GLShader( "genericMaterial", "generic", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + GLShader( "genericMaterial", "generic", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_COLOR, manager ), u_ColorMap( this ), u_DepthMap( this ), u_TextureMatrix( this ), @@ -2676,7 +2749,7 @@ GLShader_fogQuake3::GLShader_fogQuake3( GLShaderManager *manager ) : u_FogMap( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), - u_Color( this ), + u_ColorGlobal( this ), u_Bones( this ), u_VertexInterpolation( this ), u_FogDistanceVector( this ), @@ -2698,7 +2771,7 @@ GLShader_fogQuake3Material::GLShader_fogQuake3Material( GLShaderManager* manager u_FogMap( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), - u_Color( this ), + u_ColorGlobal( this ), u_FogDistanceVector( this ), u_FogDepthVector( this ), u_FogEyeT( this ), diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index 7c49f7b9d8..6b6672ffa8 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -429,7 +429,8 @@ class GLUniform 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, const bool isTexture = false ) : + const bool global, const int components = 0, + const bool isTexture = false ) : _shader( shader ), _name( name ), _type( type ), @@ -1197,6 +1198,48 @@ class GLUniformMatrix4f : protected GLUniform matrix_t currentValue; }; +class GLUniformMatrix32f : protected GLUniform { + protected: + GLUniformMatrix32f( GLShader* shader, const char* name, const bool global = false ) : + GLUniform( shader, name, "mat3x2", 6, 2, global ) { + } + + inline void SetValue( GLboolean transpose, const vec_t* m ) { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + +#if defined( LOG_GLSL_UNIFORMS ) + if ( r_logFile->integer ) { + GLimp_LogComment( va( "GLSL_SetUniformMatrix32f( %s, shader: %s, transpose: %d, [ %f, %f, %f, %f, %f, %f ] ) ---\n", + this->GetName(), _shader->GetName().c_str(), transpose, + m[0], m[1], m[2], m[3], m[4], m[5] ) ); + } +#endif + + if ( _shader->UseMaterialSystem() && !_global ) { + memcpy( currentValue, m, 6 * sizeof( float ) ); + return; + } + + glUniformMatrix3x2fv( p->uniformLocations[_locationIndex], 1, transpose, m ); + } + public: + size_t GetSize() override { + return 6 * sizeof( float ); + } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, currentValue, 6 * sizeof( float ) ); + return buffer + 6 * _components; + } + + private: + vec_t currentValue[6] {}; +}; + class GLUniformMatrix4fv : protected GLUniform { protected: @@ -1327,43 +1370,58 @@ class GLUniformBlock class GLBuffer { public: - std::string _name; - const GLuint _bindingPoint; - const GLbitfield _flags; - const GLbitfield _mapFlags; + friend class GLVAO; + + 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 ); } @@ -1375,18 +1433,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] ); } @@ -1398,33 +1455,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; @@ -1433,22 +1481,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; @@ -1456,201 +1510,98 @@ 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 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 ) { + GLBuffer( name, GL_ATOMIC_COUNTER_BUFFER, bindingPoint, flags, mapFlags ) { } +}; +class GLVAO { 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 ); - } + vboAttributeLayout_t attrs[ATTR_INDEX_MAX]; + uint32_t enabledAttrs; - void BufferStorage( const GLsizeiptr areaSize, const GLsizeiptr areaCount, const void* data ) { - GLBuffer::BufferStorage( GL_ATOMIC_COUNTER_BUFFER, areaSize, areaCount, data ); + GLVAO( const GLuint newVBOBindingPoint ) : + VBOBindingPoint( newVBOBindingPoint ) { } - 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 ); - } + ~GLVAO() = default; - uint32_t* MapBufferRange( const GLsizeiptr offset, const GLsizeiptr count ) { - return GLBuffer::MapBufferRange( GL_ATOMIC_COUNTER_BUFFER, offset, count ); + void Bind() { + glBindVertexArray( id ); } -}; -class GLIndirectBuffer { - public: + 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 ); + // vbo->attribBits |= 1 << spec->attrIndex; + 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; - struct GLIndirectCommand { - GLuint count; - GLuint instanceCount; - GLuint firstIndex; - GLint baseVertex; - GLuint baseInstance; - }; + attr.ofs = ofs; + ofs += attr.numComponents * ComponentSize( attr.componentType ); + ofs = ( ofs + 3 ) & ~3; // 4 is minimum alignment for any vertex attribute - std::string _name; + enabledAttrs |= 1 << spec->attrIndex; + } - GLIndirectBuffer( const char* name ) : - _name( name ) { - } + stride = ofs; - public: + for ( const vertexAttributeSpec_t* spec = attrBegin; spec < attrEnd; spec++ ) { + const int index = spec->attrIndex; + vboAttributeLayout_t& attr = attrs[index]; - const char* GetName() { - return _name.c_str(); - } + attr.stride = stride; - void BindBuffer() { - glBindBuffer( GL_DRAW_INDIRECT_BUFFER, handle ); + glEnableVertexArrayAttrib( id, index ); + glVertexArrayAttribFormat( id, index, attr.numComponents, attr.componentType, + attr.normalize, attr.ofs ); + glVertexArrayAttribBinding( id, index, VBOBindingPoint ); + } } - 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 SetVertexBuffer( const GLBuffer buffer, const GLuint offset ) { + glVertexArrayVertexBuffer( id, VBOBindingPoint, buffer.id, offset, stride ); } - void UnmapBuffer() const { - glUnmapBuffer( GL_DRAW_INDIRECT_BUFFER ); + void SetIndexBuffer( const GLBuffer buffer ) { + glVertexArrayElementBuffer( id, buffer.id ); } - void GenBuffer() { - glGenBuffers( 1, &handle ); + void GenVAO() { + glGenVertexArrays( 1, &id ); } - void DelBuffer() { - glDeleteBuffers( 1, &handle ); + void DelVAO() { + glDeleteVertexArrays( 1, &id ); } private: - GLuint handle; + GLuint id; + const GLuint VBOBindingPoint; + GLuint stride; }; class GLCompileMacro @@ -2140,6 +2091,7 @@ class u_ColorMap : GLUniformSampler2D { public: u_ColorMap( GLShader* shader ) : + // While u_ColorMap is used for some screen-space shaders, it's never global in material system shaders GLUniformSampler2D( shader, "u_ColorMap" ) { } @@ -2268,7 +2220,7 @@ class u_LightMap : GLUniformSampler { public: u_LightMap( GLShader* shader ) : - GLUniformSampler( shader, "u_LightMap", "sampler2D", 1 ) { + GLUniformSampler( shader, "u_LightMap", "sampler2D", 1, true ) { } void SetUniform_LightMapBindless( GLuint64 bindlessHandle ) { @@ -2284,7 +2236,7 @@ class u_DeluxeMap : GLUniformSampler { public: u_DeluxeMap( GLShader* shader ) : - GLUniformSampler( shader, "u_DeluxeMap", "sampler2D", 1 ) { + GLUniformSampler( shader, "u_DeluxeMap", "sampler2D", 1, true ) { } void SetUniform_DeluxeMapBindless( GLuint64 bindlessHandle ) { @@ -2697,17 +2649,26 @@ class u_ShadowClipMap4 : }; class u_TextureMatrix : - GLUniformMatrix4f + GLUniformMatrix32f { public: u_TextureMatrix( GLShader *shader ) : - GLUniformMatrix4f( shader, "u_TextureMatrix" ) + GLUniformMatrix32f( shader, "u_TextureMatrix", true ) { } void SetUniform_TextureMatrix( const matrix_t m ) { - this->SetValue( GL_FALSE, m ); + /* We only actually need these 6 components to get the correct texture transformation, + the other ones are unused */ + vec_t m2[6]; + m2[0] = m[0]; + m2[1] = m[1]; + m2[2] = m[4]; + m2[3] = m[5]; + m2[4] = m[12]; + m2[5] = m[13]; + this->SetValue( GL_FALSE, m2 ); } }; @@ -3098,6 +3059,18 @@ class u_Color : } }; +class u_ColorGlobal : + GLUniform1ui { + public: + u_ColorGlobal( GLShader* shader ) : + GLUniform1ui( shader, "u_ColorGlobal", true ) { + } + + void SetUniform_ColorGlobal( const Color::Color& color ) { + this->SetValue( packUnorm4x8( color.ToArray() ) ); + } +}; + class u_Frame : GLUniform1ui { public: @@ -3595,7 +3568,8 @@ enum class ColorModulate { COLOR_MINUS_ONE = BIT( 1 ), COLOR_LIGHTFACTOR = BIT( 2 ), ALPHA_ONE = BIT( 3 ), - ALPHA_MINUS_ONE = BIT( 4 ) + ALPHA_MINUS_ONE = BIT( 4 ), + ALPHA_ADD_ONE = BIT( 5 ) }; class u_ColorModulateColorGen : @@ -3625,7 +3599,7 @@ class u_ColorModulateColorGen : // vertexOverbright is only needed for non-lightmapped cases. When there is a // lightmap, this is done by multiplying with the overbright-scaled white image colorModulate |= Util::ordinal( ColorModulate::COLOR_LIGHTFACTOR ); - lightFactor = uint32_t( tr.mapLightFactor ) << 5; + lightFactor = uint32_t( tr.mapLightFactor ) << 6; } else { colorModulate |= Util::ordinal( ColorModulate::COLOR_ONE ); } @@ -3642,10 +3616,10 @@ class u_ColorModulateColorGen : if ( useMapLightFactor ) { ASSERT_EQ( vertexOverbright, false ); - lightFactor = uint32_t( tr.mapLightFactor ) << 5; + lightFactor = uint32_t( tr.mapLightFactor ) << 6; } - colorModulate |= lightFactor ? lightFactor : 1 << 5; + colorModulate |= lightFactor ? lightFactor : 1 << 6; switch ( alphaGen ) { case alphaGen_t::AGEN_VERTEX: @@ -3662,10 +3636,12 @@ class u_ColorModulateColorGen : break; } - if ( needAttrib ) { - _shader->AddVertexAttribBit( ATTR_COLOR ); - } else { - _shader->DelVertexAttribBit( ATTR_COLOR ); + if ( !needAttrib ) { + /* Originally, this controlled whether the vertex color array was used, + now it does the equivalent by setting the color in the shader in such way as if it was using + the default OpenGL values for the disabled arrays (0.0, 0.0, 0.0, 1.0) + This allows to skip the vertex format change */ + colorModulate |= Util::ordinal( ColorModulate::ALPHA_ADD_ONE ); } this->SetValue( colorModulate ); } @@ -4319,7 +4295,7 @@ class GLShader_fogQuake3 : public u_FogMap, public u_ModelMatrix, public u_ModelViewProjectionMatrix, - public u_Color, + public u_ColorGlobal, public u_Bones, public u_VertexInterpolation, public u_FogDistanceVector, @@ -4339,7 +4315,7 @@ class GLShader_fogQuake3Material : public u_FogMap, public u_ModelMatrix, public u_ModelViewProjectionMatrix, - public u_Color, + public u_ColorGlobal, public u_FogDistanceVector, public u_FogDepthVector, public u_FogEyeT, 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/common.glsl b/src/engine/renderer/glsl_source/common.glsl index a539da8276..82850db73e 100644 --- a/src/engine/renderer/glsl_source/common.glsl +++ b/src/engine/renderer/glsl_source/common.glsl @@ -48,7 +48,8 @@ Bit 1: color * ( -1 ) Bit 2: color += lightFactor Bit 3: alpha * 1 Bit 4: alpha * ( -1 ) -Bit 5-7: lightFactor */ +Bit 5: alpha = 1 +Bit 6-9: lightFactor */ float colorModArray[3] = float[3] ( 0.0f, 1.0f, -1.0f ); @@ -65,5 +66,10 @@ vec4 ColorModulateToColor( const in uint colorMod, const in float lightFactor ) } float ColorModulateToLightFactor( const in uint colorMod ) { - return ( colorMod >> 5 ) & 0x7; + return ( colorMod >> 6 ) & 0xF; +} + +// This is used to skip vertex colours if the colorMod doesn't need them +bool ColorModulateToVertexColor( const in uint colorMod ) { + return ( colorMod & 0xFF ) == 0xFF; } 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/fogQuake3_vp.glsl b/src/engine/renderer/glsl_source/fogQuake3_vp.glsl index 77eba51fe1..33b216b485 100644 --- a/src/engine/renderer/glsl_source/fogQuake3_vp.glsl +++ b/src/engine/renderer/glsl_source/fogQuake3_vp.glsl @@ -28,8 +28,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA uniform float u_Time; -uniform vec4 u_ColorModulate; -uniform uint u_Color; +uniform vec4 u_ColorModulate; +uniform uint u_ColorGlobal; uniform mat4 u_ModelMatrix; uniform mat4 u_ModelViewProjectionMatrix; @@ -58,7 +58,7 @@ void main() VertexFetch( position, LB, color, texCoord, lmCoord ); - color = /* color * u_ColorModulate + */ unpackUnorm4x8( u_Color ); + color = /* color * u_ColorModulate + */ unpackUnorm4x8( u_ColorGlobal ); DeformVertex( position, LB.normal, diff --git a/src/engine/renderer/glsl_source/forwardLighting_vp.glsl b/src/engine/renderer/glsl_source/forwardLighting_vp.glsl index 2263d926f3..06f9039df2 100644 --- a/src/engine/renderer/glsl_source/forwardLighting_vp.glsl +++ b/src/engine/renderer/glsl_source/forwardLighting_vp.glsl @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #insert vertexSkinning_vp #insert vertexAnimation_vp -uniform mat4 u_TextureMatrix; +uniform mat3x2 u_TextureMatrix; uniform mat4 u_LightAttenuationMatrix; uniform mat4 u_ModelMatrix; uniform mat4 u_ModelViewProjectionMatrix; @@ -86,7 +86,7 @@ void main() var_TexAttenuation = u_LightAttenuationMatrix * position; // transform diffusemap texcoords - var_TexCoords = (u_TextureMatrix * vec4(texCoord, 0.0, 1.0)).st; + var_TexCoords = (u_TextureMatrix * vec3(texCoord, 1.0)).st; var_Color = color; } diff --git a/src/engine/renderer/glsl_source/generic_vp.glsl b/src/engine/renderer/glsl_source/generic_vp.glsl index 6ea263733f..3affc9a91d 100644 --- a/src/engine/renderer/glsl_source/generic_vp.glsl +++ b/src/engine/renderer/glsl_source/generic_vp.glsl @@ -28,7 +28,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #insert vertexAnimation_vp #insert shaderProfiler_vp -uniform mat4 u_TextureMatrix; +#if !defined(USE_MATERIAL_SYSTEM) + uniform mat3x2 u_TextureMatrix; +#endif + uniform vec3 u_ViewOrigin; uniform float u_Time; @@ -65,6 +68,7 @@ void main() VertexFetch( position, LB, color, texCoord, lmCoord ); float lightFactor = ColorModulateToLightFactor( u_ColorModulateColorGen ); + color.a = ColorModulateToVertexColor( u_ColorModulateColorGen ) ? 1.0 : color.a; color = color * ColorModulateToColor( u_ColorModulateColorGen, lightFactor ) + unpackUnorm4x8( u_Color ) * vec4( lightFactor, lightFactor, lightFactor, 1.0 ); @@ -92,9 +96,9 @@ void main() var_TexCoords = 0.5 + vec2(0.5, -0.5) * reflected.yz; } #elif defined(USE_TCGEN_LIGHTMAP) - var_TexCoords = (u_TextureMatrix * vec4(lmCoord, 0.0, 1.0)).xy; + var_TexCoords = (u_TextureMatrix * vec3(lmCoord, 1.0)).xy; #else - var_TexCoords = (u_TextureMatrix * vec4(texCoord, 0.0, 1.0)).xy; + var_TexCoords = (u_TextureMatrix * vec3(texCoord, 1.0)).xy; #endif #if defined(USE_DEPTH_FADE) diff --git a/src/engine/renderer/glsl_source/heatHaze_vp.glsl b/src/engine/renderer/glsl_source/heatHaze_vp.glsl index 29fd607409..54b7b97206 100644 --- a/src/engine/renderer/glsl_source/heatHaze_vp.glsl +++ b/src/engine/renderer/glsl_source/heatHaze_vp.glsl @@ -28,7 +28,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA uniform float u_Time; -uniform mat4 u_TextureMatrix; +#if !defined(USE_MATERIAL_SYSTEM) + uniform mat3x2 u_TextureMatrix; +#endif + uniform mat4 u_ProjectionMatrixTranspose; uniform mat4 u_ModelViewMatrixTranspose; uniform mat4 u_ModelViewProjectionMatrix; @@ -72,7 +75,7 @@ void main() deformVec.z = dot(u_ModelViewMatrixTranspose[2], position); // transform normalmap texcoords - var_TexCoords = (u_TextureMatrix * vec4(texCoord, 0.0, 1.0)).st; + var_TexCoords = (u_TextureMatrix * vec3(texCoord, 1.0)).st; d1 = dot(u_ProjectionMatrixTranspose[0], deformVec); d2 = dot(u_ProjectionMatrixTranspose[3], deformVec); diff --git a/src/engine/renderer/glsl_source/lightMapping_vp.glsl b/src/engine/renderer/glsl_source/lightMapping_vp.glsl index 6cdae695ed..49bee16a28 100644 --- a/src/engine/renderer/glsl_source/lightMapping_vp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_vp.glsl @@ -36,7 +36,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define USE_LIGHT_MAPPING #endif -uniform mat4 u_TextureMatrix; +#if !defined(USE_MATERIAL_SYSTEM) + uniform mat3x2 u_TextureMatrix; +#endif #if defined(USE_MODEL_SURFACE) uniform mat4 u_ModelMatrix; @@ -104,7 +106,7 @@ void main() SHADER_PROFILER_SET // transform diffusemap texcoords - var_TexCoords = (u_TextureMatrix * vec4(texCoord, 0.0, 1.0)).st; + var_TexCoords = (u_TextureMatrix * vec3(texCoord, 1.0)).st; // assign color var_Color = color; diff --git a/src/engine/renderer/glsl_source/liquid_vp.glsl b/src/engine/renderer/glsl_source/liquid_vp.glsl index b65e2f44e9..08f3ee2626 100644 --- a/src/engine/renderer/glsl_source/liquid_vp.glsl +++ b/src/engine/renderer/glsl_source/liquid_vp.glsl @@ -28,7 +28,10 @@ IN vec3 attr_Tangent; IN vec3 attr_Binormal; IN vec3 attr_Normal; -uniform mat4 u_TextureMatrix; +#if !defined(USE_MATERIAL_SYSTEM) + uniform mat3x2 u_TextureMatrix; +#endif + uniform mat4 u_ModelMatrix; uniform mat4 u_ModelViewProjectionMatrix; @@ -49,7 +52,7 @@ void main() var_Position = (u_ModelMatrix * vec4(attr_Position, 1.0)).xyz; // transform normalmap texcoords - var_TexCoords = (u_TextureMatrix * vec4(attr_TexCoord0, 0.0, 1.0)).st; + var_TexCoords = (u_TextureMatrix * vec3(attr_TexCoord0, 1.0)).st; var_Tangent.xyz = (u_ModelMatrix * vec4(attr_Tangent, 0.0)).xyz; var_Binormal.xyz = (u_ModelMatrix * vec4(attr_Binormal, 0.0)).xyz; diff --git a/src/engine/renderer/glsl_source/material_fp.glsl b/src/engine/renderer/glsl_source/material_fp.glsl index 5584f24fdb..9bf8caf54e 100644 --- a/src/engine/renderer/glsl_source/material_fp.glsl +++ b/src/engine/renderer/glsl_source/material_fp.glsl @@ -59,7 +59,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif // !COMPUTELIGHT_GLSL #if defined(GENERIC_GLSL) - sampler2D u_ColorMap = sampler2D( u_ColorMap_initial ); + sampler2D u_ColorMap = sampler2D( u_DiffuseMap_initial ); #endif // !GENERIC_GLSL #if defined(LIGHTMAPPING_GLSL) @@ -71,7 +71,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif // !LIGHTMAPPING_GLSL #if defined(REFLECTION_CB_GLSL) - samplerCube u_ColorMapCube = samplerCube( u_ColorMapCube_initial ); + samplerCube u_ColorMapCube = samplerCube( u_DiffuseMap_initial ); #endif // !REFLECTION_CB_GLSL #if defined(RELIEFMAPPING_GLSL) @@ -89,8 +89,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif // !RELIEFMAPPING_GLSL #if defined(SKYBOX_GLSL) - samplerCube u_ColorMapCube = samplerCube( u_ColorMapCube_initial ); - sampler2D u_CloudMap = sampler2D( u_CloudMap_initial ); + samplerCube u_ColorMapCube = samplerCube( u_DiffuseMap_initial ); + sampler2D u_CloudMap = sampler2D( u_NormalMap_initial ); #endif // !SKYBOX_GLSL #else // !HAVE_ARB_bindless_texture 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/glsl_source/reflection_CB_vp.glsl b/src/engine/renderer/glsl_source/reflection_CB_vp.glsl index 240f02093d..b87dc20fe5 100644 --- a/src/engine/renderer/glsl_source/reflection_CB_vp.glsl +++ b/src/engine/renderer/glsl_source/reflection_CB_vp.glsl @@ -26,7 +26,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #insert vertexSkinning_vp #insert vertexAnimation_vp -uniform mat4 u_TextureMatrix; +#if !defined(USE_MATERIAL_SYSTEM) + uniform mat3x2 u_TextureMatrix; +#endif + uniform mat4 u_ModelMatrix; uniform mat4 u_ModelViewProjectionMatrix; @@ -82,6 +85,6 @@ void main() var_Normal.xyz = (u_ModelMatrix * vec4(LB.normal, 0.0)).xyz; // transform normalmap texcoords - var_TexCoords = (u_TextureMatrix * vec4(texCoord, 0.0, 1.0)).st; + var_TexCoords = (u_TextureMatrix * vec3(texCoord, 1.0)).st; } diff --git a/src/engine/renderer/glsl_source/shadowFill_vp.glsl b/src/engine/renderer/glsl_source/shadowFill_vp.glsl index 5becd198ff..3ac13c691e 100644 --- a/src/engine/renderer/glsl_source/shadowFill_vp.glsl +++ b/src/engine/renderer/glsl_source/shadowFill_vp.glsl @@ -28,7 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA uniform uint u_Color; -uniform mat4 u_TextureMatrix; +uniform mat3x2 u_TextureMatrix; uniform mat4 u_ModelMatrix; uniform mat4 u_ModelViewProjectionMatrix; @@ -70,7 +70,7 @@ void main() #endif // transform texcoords - var_TexCoords = (u_TextureMatrix * vec4(texCoord, 0.0, 1.0)).st; + var_TexCoords = (u_TextureMatrix * vec3(texCoord, 1.0)).st; // assign color var_Color = unpackUnorm4x8( u_Color ); diff --git a/src/engine/renderer/glsl_source/skybox_fp.glsl b/src/engine/renderer/glsl_source/skybox_fp.glsl index 13f0fa2477..4a4bd38250 100644 --- a/src/engine/renderer/glsl_source/skybox_fp.glsl +++ b/src/engine/renderer/glsl_source/skybox_fp.glsl @@ -33,7 +33,9 @@ uniform sampler2D u_CloudMap; uniform bool u_UseCloudMap; uniform float u_CloudHeight; -uniform mat4 u_TextureMatrix; +#if !defined(USE_MATERIAL_SYSTEM) + uniform mat3x2 u_TextureMatrix; +#endif uniform float u_AlphaThreshold; @@ -66,7 +68,7 @@ void main() incidentRay.z += radiusWorld; incidentRay = normalize( incidentRay ); vec2 st = vec2( acos(incidentRay.x), acos(incidentRay.y) ); - st = (u_TextureMatrix * vec4(st, 0.0, 1.0)).xy; + st = (u_TextureMatrix * vec3(st, 1.0)).xy; color = texture2D( u_CloudMap, st ).rgba; } diff --git a/src/engine/renderer/tr_animation.cpp b/src/engine/renderer/tr_animation.cpp index ea39201019..b1c7ad419e 100644 --- a/src/engine/renderer/tr_animation.cpp +++ b/src/engine/renderer/tr_animation.cpp @@ -683,7 +683,7 @@ void R_AddMD5Surfaces( trRefEntity_t *ent ) // see if we are in a fog volume fogNum = R_FogWorldBox( ent->worldBounds ); - if ( !r_vboModels->integer || !model->numVBOSurfaces || + if ( !r_vboModels.Get() || !model->numVBOSurfaces || ( !glConfig2.vboVertexSkinningAvailable && ent->e.skeleton.type == refSkeletonType_t::SK_ABSOLUTE ) ) { shader_t *shader; @@ -983,7 +983,7 @@ void R_AddMD5Interactions( trRefEntity_t *ent, trRefLight_t *light, interactionT cubeSideBits = R_CalcLightCubeSideBits( light, ent->worldBounds ); - if ( !r_vboModels->integer || !model->numVBOSurfaces || + if ( !r_vboModels.Get() || !model->numVBOSurfaces || ( !glConfig2.vboVertexSkinningAvailable && ent->e.skeleton.type == refSkeletonType_t::SK_ABSOLUTE ) ) { shader_t *shader = nullptr; diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 70352f37ec..c996fdef39 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -55,7 +55,7 @@ void GL_Bind( image_t *image ) texnum = image->texnum; - if ( r_nobind->integer && tr.blackImage ) + if ( r_nobind.Get() && tr.blackImage ) { // performance evaluation option texnum = tr.blackImage->texnum; @@ -82,7 +82,7 @@ void GL_Unbind( image_t *image ) glBindTexture( image->type, 0 ); } -GLuint64 BindAnimatedImage( int unit, textureBundle_t *bundle ) +GLuint64 BindAnimatedImage( int unit, const textureBundle_t *bundle ) { int index; @@ -1239,7 +1239,7 @@ static void RB_RenderInteractions() GLimp_LogComment( "--- RB_RenderInteractions ---\n" ); - if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADING_TIMES)) + if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_SHADING_TIMES ) ) { glFinish(); startTime = ri.Milliseconds(); @@ -1366,7 +1366,7 @@ static void RB_RenderInteractions() GL_CheckErrors(); - if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADING_TIMES) ) + if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_SHADING_TIMES ) ) { glFinish(); endTime = ri.Milliseconds(); @@ -2117,7 +2117,7 @@ static void RB_RenderInteractionsShadowMapped() GLimp_LogComment( "--- RB_RenderInteractionsShadowMapped ---\n" ); - if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADING_TIMES) ) + if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_SHADING_TIMES ) ) { glFinish(); startTime = ri.Milliseconds(); @@ -2665,7 +2665,7 @@ static void RB_RenderInteractionsShadowMapped() GL_CheckErrors(); - if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADING_TIMES) ) + if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_SHADING_TIMES ) ) { glFinish(); endTime = ri.Milliseconds(); @@ -2963,7 +2963,7 @@ void RB_RenderGlobalFog() return; } - if ( r_noFog->integer ) + if ( r_noFog.Get() ) { return; } @@ -3212,7 +3212,7 @@ void RB_RenderSSAO() GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); GL_Cull( cullType_t::CT_TWO_SIDED ); - if ( r_ssao->integer < 0 ) { + if ( r_ssao.Get() < 0 ) { // clear the screen to show only SSAO GL_ClearColor( 1.0, 1.0, 1.0, 1.0 ); glClear( GL_COLOR_BUFFER_BIT ); @@ -3228,9 +3228,9 @@ void RB_RenderSSAO() gl_ssaoShader->SetUniform_zFar( zParams ); vec3_t unprojectionParams; - unprojectionParams[ 0 ] = -r_znear->value * zParams[ 2 ]; - unprojectionParams[ 1 ] = 2.0 * ( zParams[ 2 ] - r_znear->value ); - unprojectionParams[ 2 ] = 2.0 * zParams[ 2 ] - r_znear->value; + unprojectionParams[ 0 ] = -r_znear.Get() * zParams[ 2 ]; + unprojectionParams[ 1 ] = 2.0 * ( zParams[ 2 ] - r_znear.Get() ); + unprojectionParams[ 2 ] = 2.0 * zParams[ 2 ] - r_znear.Get(); gl_ssaoShader->SetUniform_UnprojectionParams( unprojectionParams ); @@ -3267,7 +3267,7 @@ void RB_FXAA() return; } - if ( !r_FXAA->integer || !gl_fxaaShader ) + if ( !r_FXAA.Get() || !gl_fxaaShader ) { return; } @@ -3330,7 +3330,7 @@ void RB_CameraPostFX() gl_cameraEffectsShader->SetUniform_ColorModulate( backEnd.viewParms.gradingWeights ); - gl_cameraEffectsShader->SetUniform_InverseGamma( 1.0 / r_gamma->value ); + gl_cameraEffectsShader->SetUniform_InverseGamma( 1.0 / r_gamma.Get() ); // This shader is run last, so let it render to screen instead of // tr.mainFBO @@ -3359,7 +3359,7 @@ static void RB_RenderDebugUtils() { GLimp_LogComment( "--- RB_RenderDebugUtils ---\n" ); - if ( r_showLightTransforms->integer || r_showShadowLod->integer ) + if ( r_showLightTransforms.Get() || r_showShadowLod->integer ) { const interaction_t *ia; trRefLight_t *light; @@ -3495,7 +3495,7 @@ static void RB_RenderDebugUtils() GL_LoadModelViewMatrix( backEnd.viewParms.world.modelViewMatrix ); } - if ( r_showLightInteractions->integer ) + if ( r_showLightInteractions.Get() ) { int i; int cubeSides; @@ -3617,7 +3617,7 @@ static void RB_RenderDebugUtils() GL_LoadModelViewMatrix( backEnd.viewParms.world.modelViewMatrix ); } - if ( r_showEntityTransforms->integer ) + if ( r_showEntityTransforms.Get() ) { trRefEntity_t *ent; int i; @@ -3679,7 +3679,7 @@ static void RB_RenderDebugUtils() GL_LoadModelViewMatrix( backEnd.viewParms.world.modelViewMatrix ); } - if ( r_showSkeleton->integer ) + if ( r_showSkeleton.Get() ) { int i, j, k, parentIndex; trRefEntity_t *ent; @@ -3897,7 +3897,7 @@ static void RB_RenderDebugUtils() } } - if ( r_showLightScissors->integer ) + if ( r_showLightScissors.Get() ) { interaction_t *ia; int iaCount; @@ -4111,7 +4111,7 @@ static void RB_RenderDebugUtils() GL_LoadModelViewMatrix( backEnd.viewParms.world.modelViewMatrix ); } - if ( r_showLightGrid->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) + if ( r_showLightGrid.Get() && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { int x, y, z, k; vec3_t offset; @@ -4205,7 +4205,7 @@ static void RB_RenderDebugUtils() Tess_End(); } - if ( r_showBspNodes->integer ) + if ( r_showBspNodes.Get() ) { if ( ( backEnd.refdef.rdflags & ( RDF_NOWORLDMODEL ) ) || !tr.world ) { @@ -4388,7 +4388,7 @@ static void RB_RenderDebugUtils() if ( node->contents != -1 ) { - if ( r_showBspNodes->integer == 3 ) + if ( r_showBspNodes.Get() == 3 ) { continue; } @@ -4412,7 +4412,7 @@ static void RB_RenderDebugUtils() } else { - if ( r_showBspNodes->integer == 2 ) + if ( r_showBspNodes.Get() == 2 ) { continue; } @@ -4430,7 +4430,7 @@ static void RB_RenderDebugUtils() if ( node->contents != -1 ) { glEnable( GL_POLYGON_OFFSET_FILL ); - GL_PolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); + GL_PolygonOffset( r_offsetFactor.Get(), r_offsetUnits.Get() ); } Tess_Begin( Tess_StageIteratorDebug, nullptr, nullptr, true, -1, 0 ); @@ -4650,7 +4650,7 @@ static void RB_RenderView( bool depthPass ) GL_CheckErrors(); - if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADING_TIMES) ) + if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_SHADING_TIMES ) ) { glFinish(); startTime = ri.Milliseconds(); @@ -4693,11 +4693,11 @@ static void RB_RenderView( bool depthPass ) RB_RenderDrawSurfaces( shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE, DRAWSURFACES_ALL ); } - if ( r_ssao->integer ) { + if ( r_ssao.Get() ) { RB_RenderSSAO(); } - if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADING_TIMES) ) + if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_SHADING_TIMES ) ) { glFinish(); endTime = ri.Milliseconds(); @@ -4734,7 +4734,7 @@ static void RB_RenderView( bool depthPass ) if ( backEnd.viewParms.portalLevel > 0 ) { - if ( r_liquidMapping->integer ) + if ( r_liquidMapping.Get() ) { // capture current color buffer // liquid shader will then bind tr.portalRenderImage @@ -5376,13 +5376,14 @@ const RenderCommand *ClearBufferCommand::ExecuteSelf( ) const GL_CheckErrors(); // sync with gl if needed - if ( r_finish->integer == 1 && !glState.finishCalled ) + if ( r_finish.Get() && !glState.finishCalled ) { glFinish(); glState.finishCalled = true; } - if ( r_finish->integer == 0 ) + // WTF? + if ( !r_finish.Get() ) { glState.finishCalled = true; } @@ -5672,7 +5673,7 @@ void RB_ShowImages() y = i / 20 * h; // show in proportional size in mode 2 - if ( r_showImages->integer == 2 ) + if ( r_showImages.Get() == 2 ) { w *= image->uploadWidth / 512.0f; h *= image->uploadHeight / 512.0f; @@ -5707,7 +5708,7 @@ const RenderCommand *SwapBuffersCommand::ExecuteSelf( ) const Tess_End(); // texture swapping test - if ( r_showImages->integer ) + if ( r_showImages.Get() ) { RB_ShowImages(); } @@ -5791,7 +5792,7 @@ void RB_ExecuteRenderCommands( const void *data ) t1 = ri.Milliseconds(); - if ( !r_smp->integer || data == backEndData[ 0 ]->commands.cmds ) + if ( !r_smp.Get() || data == backEndData[0]->commands.cmds ) { backEnd.smpFrame = 0; } diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index c1b1c6c32e..eb84440152 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_bsp.c #include "tr_local.h" #include "framework/CommandSystem.h" +#include "GeometryCache.h" /* ======================================================== @@ -488,7 +489,7 @@ R_LoadLightmaps */ static void R_LoadLightmaps( lump_t *l, const char *bspName ) { - tr.worldLightMapping = r_precomputedLighting->integer && tr.lightMode == lightMode_t::MAP; + tr.worldLightMapping = r_precomputedLighting.Get() && tr.lightMode == lightMode_t::MAP; /* All lightmaps will be loaded if either light mapping or deluxe mapping is enabled. */ @@ -975,7 +976,7 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf, in // get shader value surf->shader = ShaderForShaderNum( ds->shaderNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) + if ( r_singleShader.Get() && !surf->shader->isSky ) { surf->shader = tr.defaultShader; } @@ -1186,7 +1187,7 @@ static void ParseMesh( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf ) // get shader value surf->shader = ShaderForShaderNum( ds->shaderNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) + if ( r_singleShader.Get() && !surf->shader->isSky ) { surf->shader = tr.defaultShader; } @@ -1312,7 +1313,7 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf, // get shader surf->shader = ShaderForShaderNum( ds->shaderNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) + if ( r_singleShader.Get() && !surf->shader->isSky ) { surf->shader = tr.defaultShader; } @@ -1492,7 +1493,7 @@ static void ParseFlare( dsurface_t *ds, bspSurface_t *surf ) // get shader surf->shader = ShaderForShaderNum( ds->shaderNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) + if ( r_singleShader.Get() && !surf->shader->isSky ) { surf->shader = tr.defaultShader; } @@ -3208,6 +3209,10 @@ static void R_CreateWorldVBO() { ATTR_INDEX_TEXCOORD, GL_FLOAT, GL_HALF_FLOAT, &vboVerts[ 0 ].st, 4, sizeof( *vboVerts ), 0 }, }; + if ( glConfig2.usingGeometryCache ) { + geometryCache.AddMapGeometry( vboNumVerts, vboNumIndexes, std::begin( attrs ), std::end( attrs ), vboIdxs ); + } + s_worldData.vbo = R_CreateStaticVBO( "staticWorld_VBO", std::begin( attrs ), std::end( attrs ), vboNumVerts ); s_worldData.ibo = R_CreateStaticIBO2( "staticWorld_IBO", numTriangles, vboIdxs ); @@ -3215,7 +3220,7 @@ static void R_CreateWorldVBO() ri.Hunk_FreeTempMemory( vboIdxs ); ri.Hunk_FreeTempMemory( vboVerts ); - if ( r_mergeLeafSurfaces->integer ) + if ( r_mergeLeafSurfaces.Get() ) { // count merged/unmerged surfaces int numUnmergedSurfaces = 0; @@ -3485,17 +3490,17 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) } } - Log::Debug("...loaded %d faces, %i meshes, %i trisurfs, %i flares %i foliages", numFaces, numMeshes, numTriSurfs, + Log::Debug( "...loaded %d faces, %i meshes, %i trisurfs, %i flares %i foliages", numFaces, numMeshes, numTriSurfs, numFlares, numFoliages ); - if ( r_stitchCurves->integer ) + if ( r_stitchCurves.Get() ) { R_StitchAllPatches(); } R_FixSharedVertexLodError(); - if ( r_stitchCurves->integer ) + if ( r_stitchCurves.Get() ) { R_MovePatchSurfacesToHunk(); } @@ -3667,7 +3672,7 @@ static void R_LoadNodesAndLeafs( lump_t *nodeLump, lump_t *leafLump ) backEndData[ 0 ]->traversalList = ( bspNode_t ** ) ri.Hunk_Alloc( sizeof( bspNode_t * ) * s_worldData.numnodes, ha_pref::h_low ); backEndData[ 0 ]->traversalLength = 0; - if ( r_smp->integer ) + if ( r_smp.Get() ) { backEndData[ 1 ]->traversalList = ( bspNode_t ** ) ri.Hunk_Alloc( sizeof( bspNode_t * ) * s_worldData.numnodes, ha_pref::h_low ); backEndData[ 1 ]->traversalLength = 0; @@ -4045,7 +4050,7 @@ void R_LoadLightGrid( lump_t *l ) R_SetConstantColorLightGrid( color ); } - if ( !r_precomputedLighting->integer ) + if ( !r_precomputedLighting.Get() ) { const byte color[3] { 64, 64, 64 }; R_SetConstantColorLightGrid( color ); @@ -4124,10 +4129,11 @@ void R_LoadLightGrid( lump_t *l ) tmpDirected[ 2 ] = in->directed[ 2 ]; tmpDirected[ 3 ] = 255; - if ( tmpAmbient[0] < r_forceAmbient.Get() && - tmpAmbient[1] < r_forceAmbient.Get() && - tmpAmbient[2] < r_forceAmbient.Get() ) { - VectorSet( tmpAmbient, r_forceAmbient.Get(), r_forceAmbient.Get(), r_forceAmbient.Get() ); + const byte forceAmbientNormalised = floatToUnorm8( r_forceAmbient.Get() ); + if ( tmpAmbient[0] < forceAmbientNormalised && + tmpAmbient[1] < forceAmbientNormalised && + tmpAmbient[2] < forceAmbientNormalised ) { + VectorSet( tmpAmbient, forceAmbientNormalised, forceAmbientNormalised, forceAmbientNormalised ); } if ( tr.legacyOverBrightClamping ) @@ -4811,8 +4817,8 @@ void R_BuildCubeMaps() r_gpuOcclusionCulling.Set( false ); // We still need to run the cameraEffects shader for overbright, so set r_gamma to 1.0 here to avoid applying it twice to the reflection - const float gamma = r_gamma->value; - Cvar_SetValue( "r_gamma", 1.0 ); + const float gamma = r_gamma.Get(); + r_gamma.Set( 1.0f ); for ( size_t i = 0; i < tr.cubeProbes.size(); i++ ) { @@ -5013,7 +5019,7 @@ void R_BuildCubeMaps() r_gpuOcclusionCulling.Set( gpuOcclusionCulling ); - Cvar_SetValue( "r_gamma", gamma ); + r_gamma.Set( gamma ); // turn pixel targets off tr.refdef.pixelTarget = nullptr; diff --git a/src/engine/renderer/tr_cmds.cpp b/src/engine/renderer/tr_cmds.cpp index 441da7184a..43635152f7 100644 --- a/src/engine/renderer/tr_cmds.cpp +++ b/src/engine/renderer/tr_cmds.cpp @@ -32,7 +32,7 @@ R_PerformanceCounters */ void R_PerformanceCounters() { - if ( !r_speeds->integer ) + if ( !r_speeds.Get() ) { // clear the counters even if we aren't printing tr.pc = {}; @@ -40,73 +40,73 @@ void R_PerformanceCounters() return; } - if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_GENERAL)) + if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_GENERAL ) ) { - Log::Notice("%i views %i portals %i batches %i surfs %i leafs %i verts %i tris", + Log::Notice( "%i views %i portals %i batches %i surfs %i leafs %i verts %i tris", backEnd.pc.c_views, backEnd.pc.c_portals, backEnd.pc.c_batches, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes, backEnd.pc.c_indexes / 3 ); - Log::Notice("%i lights %i bout %i pvsout %i interactions", + Log::Notice( "%i lights %i bout %i pvsout %i interactions", tr.pc.c_dlights, tr.pc.c_box_cull_light_out, tr.pc.c_pvs_cull_light_out, tr.pc.c_dlightInteractions ); - Log::Notice("%i draws %i vbos %i ibos %i verts %i tris", + Log::Notice( "%i draws %i vbos %i ibos %i verts %i tris", backEnd.pc.c_drawElements, backEnd.pc.c_vboVertexBuffers, backEnd.pc.c_vboIndexBuffers, backEnd.pc.c_vboVertexes, backEnd.pc.c_vboIndexes / 3 ); - Log::Notice("%i multidraws %i primitives %i tris", + Log::Notice( "%i multidraws %i primitives %i tris", backEnd.pc.c_multiDrawElements, backEnd.pc.c_multiDrawPrimitives, backEnd.pc.c_multiVboIndexes / 3 ); } - else if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_CULLING )) + else if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_CULLING ) ) { - Log::Notice("(gen) %i pin %i pout %i bin %i bclip %i bout", + Log::Notice( "(gen) %i pin %i pout %i bin %i bclip %i bout", tr.pc.c_plane_cull_in, tr.pc.c_plane_cull_out, tr.pc.c_box_cull_in, tr.pc.c_box_cull_clip, tr.pc.c_box_cull_out ); - Log::Notice("(mdv) %i sin %i sclip %i sout %i bin %i bclip %i bout", + Log::Notice( "(mdv) %i sin %i sclip %i sout %i bin %i bclip %i bout", tr.pc.c_sphere_cull_mdv_in, tr.pc.c_sphere_cull_mdv_clip, tr.pc.c_sphere_cull_mdv_out, tr.pc.c_box_cull_mdv_in, tr.pc.c_box_cull_mdv_clip, tr.pc.c_box_cull_mdv_out ); - Log::Notice("(md5) %i bin %i bclip %i bout", + Log::Notice( "(md5) %i bin %i bclip %i bout", tr.pc.c_box_cull_md5_in, tr.pc.c_box_cull_md5_clip, tr.pc.c_box_cull_md5_out ); } - else if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_VIEWCLUSTER )) + else if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_VIEWCLUSTER ) ) { - Log::Notice("viewcluster: %i", tr.visClusters[ tr.visIndex ] ); + Log::Notice( "viewcluster: %i", tr.visClusters[ tr.visIndex ] ); } - else if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_LIGHTS )) + else if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_LIGHTS ) ) { - Log::Notice("dlight srf:%i culled:%i", tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled ); + Log::Notice( "dlight srf:%i culled:%i", tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled ); - Log::Notice("dlights:%i interactions:%i", tr.pc.c_dlights, tr.pc.c_dlightInteractions ); + Log::Notice( "dlights:%i interactions:%i", tr.pc.c_dlights, tr.pc.c_dlightInteractions ); } - else if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADOWCUBE_CULLING )) + else if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_SHADOWCUBE_CULLING ) ) { - Log::Notice("omni pyramid tests:%i bin:%i bclip:%i bout:%i", + Log::Notice( "omni pyramid tests:%i bin:%i bclip:%i bout:%i", tr.pc.c_pyramidTests, tr.pc.c_pyramid_cull_ent_in, tr.pc.c_pyramid_cull_ent_clip, tr.pc.c_pyramid_cull_ent_out ); } - else if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_FOG )) + else if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_FOG ) ) { - Log::Notice("fog srf:%i batches:%i", backEnd.pc.c_fogSurfaces, backEnd.pc.c_fogBatches ); + Log::Notice( "fog srf:%i batches:%i", backEnd.pc.c_fogSurfaces, backEnd.pc.c_fogBatches ); } - else if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_FLARES )) + else if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_FLARES ) ) { - Log::Notice("flare adds:%i tests:%i renders:%i", + Log::Notice( "flare adds:%i tests:%i renders:%i", backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders ); } - else if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADING_TIMES )) + else if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_SHADING_TIMES ) ) { - Log::Notice("forward shading times: ambient:%i lighting:%i", backEnd.pc.c_forwardAmbientTime, + Log::Notice( "forward shading times: ambient:%i lighting:%i", backEnd.pc.c_forwardAmbientTime, backEnd.pc.c_forwardLightingTime ); } - else if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_NEAR_FAR )) + else if ( r_speeds.Get() == Util::ordinal( renderSpeeds_t::RSPEEDS_NEAR_FAR ) ) { - Log::Notice("zNear: %.0f zFar: %.0f", tr.viewParms.zNear, tr.viewParms.zFar ); + Log::Notice( "zNear: %.0f zFar: %.0f", tr.viewParms.zNear, tr.viewParms.zFar ); } tr.pc = {}; @@ -140,18 +140,18 @@ void R_IssueRenderCommands( bool runPerformanceCounters ) { c_blockedOnRender++; - if ( r_showSmp->integer ) + if ( r_showSmp.Get() ) { - Log::Notice("R"); + Log::Notice( "R" ); } } else { c_blockedOnMain++; - if ( r_showSmp->integer ) + if ( r_showSmp.Get() ) { - Log::Notice("."); + Log::Notice( "." ); } } @@ -167,7 +167,7 @@ void R_IssueRenderCommands( bool runPerformanceCounters ) } // actually start the commands going - if ( !r_skipBackEnd->integer ) + if ( !r_skipBackEnd.Get() ) { // let it start on the new batch if ( !glConfig.smpActive ) @@ -598,7 +598,7 @@ void RE_2DPolyies( polyVert_t *verts, int numverts, qhandle_t hShader ) { Poly2dCommand *cmd; - if ( r_numPolyVerts + numverts > r_maxPolyVerts->integer ) + if ( r_numPolyVerts + numverts > r_maxPolyVerts.Get() ) { return; } @@ -622,12 +622,12 @@ void RE_2DPolyiesIndexed( polyVert_t *verts, int numverts, int *indexes, int num { Poly2dIndexedCommand *cmd; - if ( r_numPolyVerts + numverts > r_maxPolyVerts->integer ) + if ( r_numPolyVerts + numverts > r_maxPolyVerts.Get() ) { return; } - if ( r_numPolyIndexes + numindexes > r_maxPolyVerts->integer ) + if ( r_numPolyIndexes + numindexes > r_maxPolyVerts.Get() ) { return; } @@ -855,7 +855,7 @@ void RE_BeginFrame() return; } - if ( !Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) ) + if ( !Q_stricmp( r_drawBuffer.Get().c_str(), "GL_FRONT" ) ) { cmd->buffer = ( int ) GL_FRONT; } diff --git a/src/engine/renderer/tr_curve.cpp b/src/engine/renderer/tr_curve.cpp index 2d53d824e4..2b6b70a63b 100644 --- a/src/engine/renderer/tr_curve.cpp +++ b/src/engine/renderer/tr_curve.cpp @@ -420,7 +420,7 @@ static srfGridMesh_t *R_CreateSurfaceGridMesh( int width, int height, // copy the results out to a grid size = sizeof( *grid ); - if ( r_stitchCurves->integer ) + if ( r_stitchCurves.Get() ) { grid = (srfGridMesh_t*)/*ri.Hunk_Alloc */ Z_Calloc( size ); @@ -588,7 +588,7 @@ srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, srfVert_t points[ continue; // can't subdivide any more } - if ( maxLen <= r_subdivisions->value ) + if ( maxLen <= r_subdivisions.Get() ) { errorTable[ dir ][ j + 1 ] = 1.0f / maxLen; continue; // didn't need subdivision diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 974d84848a..df2c15d02c 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -1476,7 +1476,7 @@ image_t *R_CreateImage( const char *name, const byte **pic, int width, int heigh R_UploadImage( name, pic, 1, numMips, image, imageParams ); - if( r_exportTextures->integer ) { + if( r_exportTextures.Get() ) { R_ExportTexture( image ); } @@ -1557,7 +1557,7 @@ image_t *R_CreateCubeImage( const char *name, const byte *pic[ 6 ], int width, i R_UploadImage( name, pic, 6, 1, image, imageParams ); - if( r_exportTextures->integer ) { + if( r_exportTextures.Get() ) { R_ExportTexture( image ); } @@ -1608,7 +1608,7 @@ image_t *R_Create3DImage( const char *name, const byte *pic, int width, int heig ri.Hunk_FreeTempMemory( pics ); } - if( r_exportTextures->integer ) { + if( r_exportTextures.Get() ) { R_ExportTexture( image ); } diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 1354bbc132..2337808966 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "framework/CvarSystem.h" #include "DetectGLVendors.h" #include "Material.h" +#include "GeometryCache.h" glconfig_t glConfig; glconfig2_t glConfig2; @@ -33,9 +34,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static void GfxInfo_f(); - cvar_t *r_glMajorVersion; - cvar_t *r_glMinorVersion; - cvar_t *r_glProfile; Cvar::Cvar r_glDebugProfile( "r_glDebugProfile", "Enable GL debug message callback", Cvar::NONE, false ); Cvar::Range> r_glDebugMode( "r_glDebugMode", "GL debug message callback mode: 0: none, 1: error, 2: deprecated, 3: undefined, 4: portability, 5: performance," @@ -43,34 +41,40 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Util::ordinal( glDebugModes_t::GLDEBUG_NONE ), Util::ordinal( glDebugModes_t::GLDEBUG_NONE ), Util::ordinal( glDebugModes_t::GLDEBUG_ALL ) ); - cvar_t *r_glAllowSoftware; - cvar_t *r_glExtendedValidation; + Cvar::Cvar r_glExtendedValidation( "r_glExtendedValidation", + "Enable extra GL context validation", Cvar::NONE, false ); cvar_t *r_ignore; - cvar_t *r_znear; - cvar_t *r_zfar; + Cvar::Cvar r_znear( "r_znear", "Near frustum plane distance", Cvar::CHEAT, 3.0f ); + Cvar::Cvar r_zfar( "r_zfar", "Near frustum plane distance", Cvar::CHEAT, 0.0f ); - cvar_t *r_smp; - cvar_t *r_showSmp; - cvar_t *r_skipBackEnd; + Cvar::Cvar r_smp( "r_smp", "Enable SMP (use 2 different threads for renderer frontend and backend", + Cvar::NONE, false ); + Cvar::Cvar r_showSmp( "r_showSmp", "Show which of the threads is executing with r_smp on", Cvar::NONE, false ); + Cvar::Cvar r_skipBackEnd( "r_skipBackEnd", "Skip renderer backend", Cvar::NONE, false ); cvar_t *r_measureOverdraw; - cvar_t *r_lodBias; - cvar_t *r_lodScale; - - cvar_t *r_norefresh; - cvar_t *r_drawentities; - cvar_t *r_drawworld; - cvar_t *r_drawpolies; - cvar_t *r_speeds; - cvar_t *r_novis; - cvar_t *r_nocull; - cvar_t *r_facePlaneCull; - cvar_t *r_nocurves; - cvar_t *r_lightScissors; - cvar_t *r_noLightVisCull; + Cvar::Cvar r_lodBias( "r_lodBias", "Add this to model lod selection", Cvar::NONE, 0 ); + Cvar::Cvar r_lodScale( "r_lodScale", "Scale model lod selection by this", Cvar::NONE, 5 ); + + Cvar::Cvar r_norefresh( "r_norefresh", "Skip renderer frontend", Cvar::NONE, false ); + Cvar::Cvar r_drawentities( "r_drawentities", "Render entities", Cvar::NONE, true ); + Cvar::Cvar r_drawworld( "r_drawworld", "Render world", Cvar::CHEAT, true ); + Cvar::Cvar r_drawpolies( "r_drawpolies", "Render polies", Cvar::CHEAT, true ); + Cvar::Range> r_speeds( "r_speeds", + "Renderer timings: 0: disabled, 1: general, 2: culling, 3: view cluster, 4: lights, 5: shadowcube culling," + "6: fog, 7: flares, 8: shading times, 9: chc, 10: show z_near/z_far", Cvar::NONE, + 0, + 0, + Util::ordinal( renderSpeeds_t::RSPEEDS_NEAR_FAR ) ); + Cvar::Cvar r_novis( "r_novis", "Skip PVS for rendering world", Cvar::NONE, false ); + Cvar::Cvar r_nocull( "r_nocull", "Skip culling", Cvar::CHEAT, false ); + Cvar::Cvar r_facePlaneCull( "r_facePlaneCull", "Back-face culling of planar surfaces (CPU-side)", Cvar::NONE, true ); + Cvar::Cvar r_nocurves( "r_nocurves", "Cull all SF_GRID surfaces", Cvar::CHEAT, false ); + Cvar::Range> r_lightScissors( "r_lightScissors", "Light clipping: 0: disabled, 1: near plane, 2: all planes", + Cvar::NONE, 0, 0, 2 ); cvar_t *r_noInteractionSort; Cvar::Range> r_realtimeLightingRenderer( "r_realtimeLightingRenderer", "renderer for real time lights: 0: legacy, 1: tiled", Cvar::NONE, @@ -80,8 +84,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Cvar::Cvar r_realtimeLighting( "r_realtimeLighting", "Enable realtime light rendering", Cvar::NONE, true ); Cvar::Range> r_realtimeLightLayers( "r_realtimeLightLayers", "Dynamic light layers per tile, each layer holds 16 lights", Cvar::NONE, 4, 1, MAX_REF_LIGHTS / 16 ); - cvar_t *r_realtimeLightingCastShadows; - cvar_t *r_precomputedLighting; + Cvar::Cvar r_realtimeLightingCastShadows( "r_realtimeLightingCastShadows", "Enable realtime light shadows", + Cvar::NONE, true ); + Cvar::Cvar r_precomputedLighting( "r_precomputedLighting", "Use lightMaps if available", Cvar::CHEAT, true ); Cvar::Cvar r_overbrightDefaultExponent("r_overbrightDefaultExponent", "default map light color shift (multiply by 2^x)", Cvar::NONE, 2); Cvar::Cvar r_overbrightDefaultClamp("r_overbrightDefaultClamp", "clamp lightmap colors to 1 (in absence of map worldspawn value)", Cvar::NONE, false); Cvar::Cvar r_overbrightIgnoreMapSettings("r_overbrightIgnoreMapSettings", "force usage of r_overbrightDefaultClamp / r_overbrightDefaultExponent, ignoring worldspawn", Cvar::NONE, false); @@ -92,10 +97,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Cvar::Cvar r_gpuFrustumCulling( "r_gpuFrustumCulling", "Use frustum culling on the GPU for the Material System", Cvar::NONE, true ); Cvar::Cvar r_gpuOcclusionCulling( "r_gpuOcclusionCulling", "Use occlusion culling on the GPU for the Material System", Cvar::NONE, false ); Cvar::Cvar r_materialSystemSkip( "r_materialSystemSkip", "Temporarily skip Material System rendering, using only core renderer instead", Cvar::NONE, false ); - cvar_t *r_lightStyles; - cvar_t *r_exportTextures; - cvar_t *r_heatHaze; - cvar_t *r_noMarksOnTrisurfs; + Cvar::Cvar r_geometryCache( "r_geometryCache", "Use Geometry Cache", Cvar::NONE, true ); + Cvar::Cvar r_lightStyles( "r_lightStyles", "Enable light styles", Cvar::ARCHIVE, true ); + Cvar::Cvar r_exportTextures( "r_exportTextures", "Save all textures that get created to /texexp", Cvar::NONE, false ); + Cvar::Cvar r_heatHaze( "r_heatHaze", "Enable heat haze mapping", Cvar::ARCHIVE, true ); + Cvar::Cvar r_noMarksOnTrisurfs( "r_noMarksOnTrisurfs", "Disable marks on SF_TRIANGLES surfaces", Cvar::NONE, true ); /* Default value is 1: Delay GLSL shader build until first map load. @@ -109,12 +115,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA "r_lazyShaders", "build GLSL shaders (0) on startup, (1) on map load or (2) when used", Cvar::NONE, 1, 0, 2); - cvar_t *r_checkGLErrors; + Cvar::Range> r_checkGLErrors( "r_checkGLErrors", "Enable GL error checking: -1: in debug builds, 0: never, 1: always", + Cvar::NONE, -1, -1, 1 ); cvar_t *r_logFile; - cvar_t *r_colorbits; + Cvar::Cvar r_colorbits( "r_colorbits", "Number of desired color bits, only relevant for fullscreen; 0 to set up automatically", + Cvar::NONE, 0 ); - cvar_t *r_drawBuffer; + Cvar::Cvar r_drawBuffer( "r_drawBuffer", "Render to front or back buffer (GL_FRONT and GL_BACK)", + Cvar::NONE, "GL_BACK" ); Cvar::Range> r_shadows( "cg_shadows", "shadowing mode", Cvar::NONE, Util::ordinal(shadowingMode_t::SHADOWING_BLOB), @@ -149,34 +158,35 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA cvar_t *r_parallelShadowSplits; cvar_t *r_parallelShadowSplitWeight; - cvar_t *r_mode; - cvar_t *r_nobind; - cvar_t *r_singleShader; - cvar_t *r_picMip; - cvar_t *r_imageMaxDimension; - cvar_t *r_ignoreMaterialMinDimension; - cvar_t *r_ignoreMaterialMaxDimension; - cvar_t *r_replaceMaterialMinDimensionIfPresentWithMaxDimension; + Cvar::Cvar r_mode( "r_mode", "Video mode", Cvar::ARCHIVE, -2 ); + Cvar::Cvar r_nobind( "r_nobind", "Bind a black image for all textures", Cvar::NONE, false ); + Cvar::Cvar r_singleShader( "r_singleShader", "Use the default shader on most world surfaces", Cvar::CHEAT, false ); + Cvar::Cvar r_picMip( "r_picMip", "Downscale textures this many times", Cvar::ARCHIVE, 0 ); + Cvar::Cvar r_imageMaxDimension( "r_imageMaxDimension", "Downscale textures to this dimension", Cvar::ARCHIVE, 0 ); + Cvar::Cvar r_ignoreMaterialMinDimension( "r_ignoreMaterialMinDimension", "Ignore material min dimension", Cvar::NONE, false ); + Cvar::Cvar r_ignoreMaterialMaxDimension( "r_ignoreMaterialMaxDimension", "Ignore material max dimension", Cvar::NONE, false ); + Cvar::Cvar r_replaceMaterialMinDimensionIfPresentWithMaxDimension( "r_replaceMaterialMinDimensionIfPresentWithMaxDimension", + "Replace material min dimension with max dimension if present", Cvar::NONE, false ); Cvar::Range> r_imageFitScreen("r_imageFitScreen", "downscale “fitscreen” images to fit the screen size: 0: disable, 1: downscale as much as possible without being smaller than screen size (default), 2: downscale to never be larger then screen size", Cvar::NONE, 1, 0, 2); - cvar_t *r_finish; - Cvar::Modified> r_textureMode( - "r_textureMode", "default texture filter mode", Cvar::NONE, "GL_LINEAR_MIPMAP_LINEAR"); - cvar_t *r_offsetFactor; - cvar_t *r_offsetUnits; - - cvar_t *r_physicalMapping; - cvar_t *r_specularExponentMin; - cvar_t *r_specularExponentMax; - cvar_t *r_specularScale; - cvar_t *r_specularMapping; - cvar_t *r_deluxeMapping; - cvar_t *r_normalScale; - cvar_t *r_normalMapping; - cvar_t *r_liquidMapping; - cvar_t *r_highQualityNormalMapping; - cvar_t *r_reliefDepthScale; - cvar_t *r_reliefMapping; - cvar_t *r_glowMapping; + Cvar::Cvar r_finish( "r_finish", "Use glFinish() at the end of rendering a frame", Cvar::NONE, false ); + Cvar::Modified> r_textureMode( "r_textureMode", "default texture filter mode", + Cvar::NONE, "GL_LINEAR_MIPMAP_LINEAR" ); + Cvar::Cvar r_offsetFactor( "r_offsetFactor", "Polygon offset factor", Cvar::CHEAT, -1 ); + Cvar::Cvar r_offsetUnits( "r_offsetUnits", "Polygon offset units", Cvar::CHEAT, -2 ); + + Cvar::Cvar r_physicalMapping( "r_physicalMapping", "Enable PBR", Cvar::ARCHIVE, true ); + Cvar::Cvar r_specularExponentMin( "r_specularExponentMin", "Minimum specular exponent", Cvar::CHEAT, 0.001f ); + Cvar::Cvar r_specularExponentMax( "r_specularExponentMax", "Maximum specular exponent", Cvar::CHEAT, 16.0f ); + Cvar::Cvar r_specularScale( "r_specularScale", "Specular scale", Cvar::CHEAT, 1.0f ); + Cvar::Cvar r_specularMapping( "r_specularMapping", "Enable specular mapping", Cvar::ARCHIVE, true ); + Cvar::Cvar r_deluxeMapping( "r_deluxeMapping", "Enable deluxe mapping", Cvar::ARCHIVE, true ); + Cvar::Cvar r_normalScale( "r_normalScale", "Normal scale", Cvar::NONE, 1.0f ); + Cvar::Cvar r_normalMapping( "r_normalMapping", "Enable normal mapping", Cvar::ARCHIVE, true ); + Cvar::Cvar r_liquidMapping( "r_liquidMapping", "Enable liquid mapping", Cvar::ARCHIVE, false ); + Cvar::Cvar r_highQualityNormalMapping( "r_highQualityNormalMapping", "Enable high quality normal mapping", Cvar::NONE, false ); + Cvar::Cvar r_reliefDepthScale( "r_reliefDepthScale", "Relief mapping depth scale", Cvar::NONE, 0.02f ); + Cvar::Cvar r_reliefMapping( "r_reliefMapping", "Enable relief mapping", Cvar::ARCHIVE, false ); + Cvar::Cvar r_glowMapping( "r_glowMapping", "Enable glow mapping", Cvar::NONE, true ); Cvar::Cvar r_reflectionMapping( "r_reflectionMapping", "Use static reflections", Cvar::NONE, false ); Cvar::Range> r_autoBuildCubeMaps( "r_autoBuildCubeMaps", "Automatically build cube maps when a map is loaded: 0: off, 1: build and store on disk if not found, 2: always build", Cvar::NONE, @@ -188,62 +198,64 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Cvar::Range> r_cubeProbeSpacing( "r_cubeProbeSpacing", "Spacing between the static reflections cubemaps", Cvar::NONE, 256, 64, 1024 ); - cvar_t *r_halfLambertLighting; - cvar_t *r_rimLighting; - cvar_t *r_rimExponent; + Cvar::Cvar r_halfLambertLighting( "r_halfLambertLighting", "Enable half-Lambert lighting (makes models brighter)", + Cvar::ARCHIVE, true ); + Cvar::Cvar r_rimLighting( "r_rimLighting", "Light the edges of modes from behind", Cvar::NONE, true ); + Cvar::Range> r_rimExponent( "r_rimExponent", "Rim lighting exponent", Cvar::NONE, 3.0f, 0.5f, 8.0f ); Cvar::Cvar r_highPrecisionRendering("r_highPrecisionRendering", "use high precision frame buffers for rendering and blending", Cvar::NONE, true); - cvar_t *r_gamma; - cvar_t *r_lockpvs; - cvar_t *r_noportals; + Cvar::Cvar r_gamma( "r_gamma", "Gamma", Cvar::ARCHIVE, 1.0f ); + Cvar::Cvar r_lockpvs( "r_lockpvs", "Lock the culling position and angles at the current viewpos", Cvar::CHEAT, false ); + Cvar::Cvar r_noportals( "r_noportals", "Skip portals", Cvar::CHEAT, false ); - cvar_t *r_max_portal_levels; + Cvar::Cvar r_max_portal_levels( "r_max_portal_levels", "Maximum portal view recursion level", Cvar::NONE, 5 ); - cvar_t *r_subdivisions; - cvar_t *r_stitchCurves; + Cvar::Cvar r_subdivisions( "r_subdivisions", "Quality of patch-mesh sub-division (lower = better)", Cvar::NONE, 4 ); + Cvar::Cvar r_stitchCurves( "r_stitchCurves", "Stitch edges of patch meshes", Cvar::CHEAT, true ); Cvar::Modified> r_fullscreen( "r_fullscreen", "use full-screen window", CVAR_ARCHIVE, true ); - cvar_t *r_customwidth; - cvar_t *r_customheight; + Cvar::Cvar r_customwidth( "r_customwidth", "Window width", Cvar::ARCHIVE, 1600 ); + Cvar::Cvar r_customheight( "r_customheight", "Window height", Cvar::ARCHIVE, 1024 ); - cvar_t *r_debugSurface; + Cvar::Cvar r_debugSurface( "r_debugSurface", "Enable debug surface rendering", Cvar::NONE, false ); - cvar_t *r_showImages; + Cvar::Range> r_showImages( "r_showImages", "Render all textures on screen: 0: disabled, 1: normal, 2: proportional", + Cvar::TEMPORARY, 0, 0, 2 ); - cvar_t *r_wolfFog; - cvar_t *r_noFog; + Cvar::Cvar r_wolfFog( "r_wolfFog", "Enable surface fog", Cvar::NONE, true ); + Cvar::Cvar r_noFog( "r_noFog", "Skip fog", Cvar::CHEAT, false ); Cvar::Range> r_forceAmbient( "r_forceAmbient", "Minimal light amount in lightGrid", Cvar::NONE, 0.125f, 0.0f, 0.3f ); Cvar::Cvar r_ambientScale( "r_ambientScale", "Scale lightGrid produced by ambientColor keyword by this much", Cvar::CHEAT, 1.0 ); cvar_t *r_lightScale; - cvar_t *r_debugSort; - cvar_t *r_printShaders; + Cvar::Cvar r_debugSort( "r_debugSort", "Stop rendering surfaces after this sort value", Cvar::CHEAT, 0 ); + Cvar::Cvar r_printShaders( "r_printShaders", "Print names of q3 shaders that are being loaded", Cvar::NONE, false ); - cvar_t *r_maxPolys; - cvar_t *r_maxPolyVerts; + Cvar::Range> r_maxPolys( "r_maxPolys", "Maximum amount of polys", Cvar::NONE, 10000, 600, 30000 ); + Cvar::Range> r_maxPolyVerts( "r_maxPolyVerts", "Maximum amount of poly vertices", Cvar::NONE, 100000, 3000, 200000 ); - cvar_t *r_showTris; - cvar_t *r_showSky; + Cvar::Cvar r_showTris( "r_showTris", "Render surfaces' wireframe", Cvar::CHEAT, false ); + Cvar::Cvar r_showSky( "r_showSky", "Render sky only", Cvar::NONE, false ); cvar_t *r_showShadowLod; cvar_t *r_showShadowMaps; - cvar_t *r_showSkeleton; - cvar_t *r_showEntityTransforms; - cvar_t *r_showLightTransforms; - cvar_t *r_showLightInteractions; - cvar_t *r_showLightScissors; - cvar_t *r_showLightBatches; - cvar_t *r_showLightGrid; - cvar_t *r_showLightTiles; - cvar_t *r_showBatches; + Cvar::Cvar r_showSkeleton( "r_showSkeleton", "Render model skeletons", Cvar::CHEAT, false ); + Cvar::Cvar r_showEntityTransforms( "r_showEntityTransforms", "Render entity transform bounds", Cvar::CHEAT, false ); + Cvar::Cvar r_showLightTransforms( "r_showLightTransforms", "Render light transform bounds", Cvar::CHEAT, false ); + Cvar::Cvar r_showLightInteractions( "r_showLightInteractions", "Render light interactions", Cvar::CHEAT, false ); + Cvar::Cvar r_showLightScissors( "r_showLightScissors", "Render light scissors", Cvar::ARCHIVE, false ); + Cvar::Cvar r_showLightBatches( "r_showLightBatches", "Render light batches", Cvar::NONE, false ); + Cvar::Cvar r_showLightGrid( "r_showLightGrid", "Render lightGrid", Cvar::NONE, false ); + Cvar::Cvar r_showLightTiles( "r_showLightTiles", "Render light tiles", Cvar::NONE, false ); + Cvar::Cvar r_showBatches( "r_showBatches", "Render batches", Cvar::NONE, false ); Cvar::Cvar r_showVertexColors("r_showVertexColors", "show vertex colors used for vertex lighting", Cvar::CHEAT, false); - cvar_t *r_showLightMaps; - cvar_t *r_showDeluxeMaps; - cvar_t *r_showNormalMaps; - cvar_t *r_showMaterialMaps; + Cvar::Cvar r_showLightMaps( "r_showLightMaps", "Render lightMaps", Cvar::NONE, false ); + Cvar::Cvar r_showDeluxeMaps( "r_showDeluxeMaps", "Render deluxe maps", Cvar::NONE, false ); + Cvar::Cvar r_showNormalMaps( "r_showNormalMaps", "Render normal maps", Cvar::NONE, false ); + Cvar::Cvar r_showMaterialMaps( "r_showMaterialMaps", "Render material maps", Cvar::NONE, false ); Cvar::Cvar r_showReflectionMaps( "r_showReflectionMaps", "Show only the static reflections on surfaces", Cvar::NONE, false ); Cvar::Range> r_showCubeProbes( "r_showCubeProbes", "Show static reflections cubemap placement: 0: off, 1: grid, " "2: unique only", Cvar::NONE, @@ -252,7 +264,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Util::ordinal( showCubeProbesMode::UNIQUE ) ); Cvar::Cvar r_showCubeProbeFace( "r_showCubeProbeFace", "Render from the perspective of a selected static reflection " "cubemap face, -1 to disable", Cvar::NONE, -1 ); - cvar_t *r_showBspNodes; + Cvar::Range> r_showBspNodes( "r_showBspNodes", "Render BSP nodes", Cvar::NONE, 0, 0, 3 ); Cvar::Range> r_showGlobalMaterials( "r_showGlobalMaterials", "Show material system materials: 0: off, 1: depth, " "2: opaque, 3: opaque + transparent", Cvar::NONE, Util::ordinal( MaterialDebugMode::NONE ), @@ -274,19 +286,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Cvar::Cvar r_forceRendererTime( "r_forceRendererTime", "Set a specific time (in ms, since the start of the map) for time-based shader effects; -1 to disable", Cvar::CHEAT, -1 ); - cvar_t *r_vboFaces; - cvar_t *r_vboCurves; - cvar_t *r_vboTriangles; - cvar_t *r_vboModels; - cvar_t *r_vboVertexSkinning; + Cvar::Cvar r_vboFaces( "r_vboFaces", "Use static VBO to render SF_FACE", Cvar::NONE, true ); + Cvar::Cvar r_vboCurves( "r_vboCurves", "Use static VBO to render SF_GRID", Cvar::NONE, true ); + Cvar::Cvar r_vboTriangles( "r_vboTriangles", "Use static VBO to render SF_FACE", Cvar::NONE, true ); + Cvar::Cvar r_vboModels( "r_vboModels", "Use static VBOs for models", Cvar::NONE, true ); + Cvar::Cvar r_vboVertexSkinning( "r_vboVertexSkinning", "Use GPU for skeletal animation transforms", Cvar::NONE, true ); - cvar_t *r_mergeLeafSurfaces; + Cvar::Cvar r_mergeLeafSurfaces( "r_mergeLeafSurfaces", "Merge surfaces in the same BSP leaf", Cvar::NONE, true ); Cvar::Cvar r_bloom( "r_bloom", "Use bloom", Cvar::ARCHIVE, false ); Cvar::Cvar r_bloomBlur( "r_bloomBlur", "Bloom strength", Cvar::NONE, 1.0 ); Cvar::Cvar r_bloomPasses( "r_bloomPasses", "Amount of bloom passes in each direction", Cvar::NONE, 2 ); - cvar_t *r_FXAA; - cvar_t *r_ssao; + Cvar::Cvar r_FXAA( "r_FXAA", "Use FXAA", Cvar::ARCHIVE, false ); + Cvar::Cvar r_ssao( "r_ssao", "Use SSAO", Cvar::ARCHIVE, 0 ); cvar_t *r_evsmPostProcess; @@ -355,18 +367,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA GLSL_InitGPUShaders(); glConfig.smpActive = false; - if ( r_smp->integer ) + if ( r_smp.Get() ) { - Log::Notice("Trying SMP acceleration..." ); + Log::Notice( "Trying SMP acceleration..." ); if ( GLimp_SpawnRenderThread( RB_RenderThread ) ) { - Log::Notice("...succeeded." ); + Log::Notice( "...succeeded." ); glConfig.smpActive = true; } else { - Log::Notice("...failed." ); + Log::Notice( "...failed." ); } } } @@ -508,8 +520,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA } else if ( mode == -1 ) { - *width = r_customwidth->integer; - *height = r_customheight->integer; + *width = r_customwidth.Get(); + *height = r_customheight.Get(); } else { @@ -957,11 +969,11 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Log::Notice("PIXELFORMAT: color(%d-bits)", glConfig.colorBits ); Log::Notice("MODE: %d, %d x %d %s", - r_mode->integer, + r_mode.Get(), glConfig.vidWidth, glConfig.vidHeight, fsstrings[ +r_fullscreen.Get() ] ); - if ( !!r_glExtendedValidation->integer ) + if ( r_glExtendedValidation.Get() ) { Log::Notice("Using OpenGL version %d.%d, requested: %d.%d, highest: %d.%d", glConfig2.glMajor, glConfig2.glMinor, glConfig2.glRequestedMajor, glConfig2.glRequestedMinor, @@ -1070,17 +1082,18 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Log::Notice("Using dual processor acceleration." ); } - if ( r_finish->integer ) + if ( r_finish.Get() ) { - Log::Notice("Forcing glFinish." ); + Log::Notice( "Forcing glFinish()" ); } - Log::Debug("texturemode: %s", r_textureMode.Get() ); - Log::Debug("picmip: %d", r_picMip->integer ); - Log::Debug("imageMaxDimension: %d", r_imageMaxDimension->integer ); - Log::Debug("ignoreMaterialMinDimension: %d", r_ignoreMaterialMinDimension->integer ); - Log::Debug("ignoreMaterialMaxDimension: %d", r_ignoreMaterialMaxDimension->integer ); - Log::Debug("replaceMaterialMinDimensionIfPresentWithMaxDimension: %d", r_replaceMaterialMinDimensionIfPresentWithMaxDimension->integer ); + Log::Debug( "texturemode: %s", r_textureMode.Get() ); + Log::Debug( "picmip: %d", r_picMip.Get() ); + Log::Debug( "imageMaxDimension: %d", r_imageMaxDimension.Get() ); + Log::Debug( "ignoreMaterialMinDimension: %d", r_ignoreMaterialMinDimension.Get() ); + Log::Debug( "ignoreMaterialMaxDimension: %d", r_ignoreMaterialMaxDimension.Get() ); + Log::Debug( "replaceMaterialMinDimensionIfPresentWithMaxDimension: %d", + r_replaceMaterialMinDimensionIfPresentWithMaxDimension.Get() ); } // FIXME: uses regular logging not Print() @@ -1118,6 +1131,19 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p stage->deformIndex = deformIndex; } } + + if ( glConfig2.usingMaterialSystem ) { + /* GLSL shaders linked to materials will be invalidated by glsl_restart, + so regenerate all the material stuff here */ + const uint8_t maxStages = materialSystem.maxStages; + materialSystem.Free(); + materialSystem.FreeGLBuffers(); + + materialSystem.InitGLBuffers(); + materialSystem.maxStages = maxStages; + + materialSystem.GenerateWorldMaterials(); + } } }; static GlslRestartCmd glslRestartCmdRegistration; @@ -1130,49 +1156,38 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p void R_Register() { // OpenGL context selection - r_glMajorVersion = Cvar_Get( "r_glMajorVersion", "", CVAR_LATCH ); - r_glMinorVersion = Cvar_Get( "r_glMinorVersion", "", CVAR_LATCH ); - r_glProfile = Cvar_Get( "r_glProfile", "", CVAR_LATCH ); Cvar::Latch( r_glDebugProfile ); - r_glAllowSoftware = Cvar_Get( "r_glAllowSoftware", "0", CVAR_LATCH ); - r_glExtendedValidation = Cvar_Get( "r_glExtendedValidation", "0", CVAR_LATCH ); + Cvar::Latch( r_glExtendedValidation ); // latched and archived variables - r_picMip = Cvar_Get( "r_picMip", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_imageMaxDimension = Cvar_Get( "r_imageMaxDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_ignoreMaterialMinDimension = Cvar_Get( "r_ignoreMaterialMinDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_ignoreMaterialMaxDimension = Cvar_Get( "r_ignoreMaterialMaxDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_replaceMaterialMinDimensionIfPresentWithMaxDimension - = Cvar_Get( "r_replaceMaterialMinDimensionIfPresentWithMaxDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); - Cvar::Latch(r_imageFitScreen); - r_colorbits = Cvar_Get( "r_colorbits", "0", CVAR_LATCH ); - r_mode = Cvar_Get( "r_mode", "-2", CVAR_LATCH | CVAR_ARCHIVE ); - r_customwidth = Cvar_Get( "r_customwidth", "1600", CVAR_LATCH | CVAR_ARCHIVE ); - r_customheight = Cvar_Get( "r_customheight", "1024", CVAR_LATCH | CVAR_ARCHIVE ); - r_subdivisions = Cvar_Get( "r_subdivisions", "4", CVAR_LATCH ); - r_realtimeLightingCastShadows = Cvar_Get( "r_realtimeLightingCastShadows", "1", 0 ); - r_precomputedLighting = Cvar_Get( "r_precomputedLighting", "1", CVAR_CHEAT | CVAR_LATCH ); + Cvar::Latch( r_picMip ); + Cvar::Latch( r_imageMaxDimension ); + Cvar::Latch( r_ignoreMaterialMinDimension ); + Cvar::Latch( r_ignoreMaterialMaxDimension ); + Cvar::Latch( r_replaceMaterialMinDimensionIfPresentWithMaxDimension ); + Cvar::Latch( r_imageFitScreen ); + Cvar::Latch( r_colorbits ); + Cvar::Latch( r_mode ); + Cvar::Latch( r_customwidth ); + Cvar::Latch( r_customheight ); + Cvar::Latch( r_subdivisions ); + Cvar::Latch( r_precomputedLighting ); Cvar::Latch( r_overbrightDefaultExponent ); Cvar::Latch( r_overbrightDefaultClamp ); Cvar::Latch( r_overbrightIgnoreMapSettings ); Cvar::Latch( r_lightMode ); Cvar::Latch( r_colorGrading ); Cvar::Latch( r_drawSky ); - r_lightStyles = Cvar_Get( "r_lightStyles", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_exportTextures = Cvar_Get( "r_exportTextures", "0", 0 ); - r_heatHaze = Cvar_Get( "r_heatHaze", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_noMarksOnTrisurfs = Cvar_Get( "r_noMarksOnTrisurfs", "1", CVAR_CHEAT ); - - r_wolfFog = Cvar_Get( "r_wolfFog", "1", CVAR_CHEAT ); - r_noFog = Cvar_Get( "r_noFog", "0", CVAR_CHEAT ); + Cvar::Latch( r_lightStyles ); + Cvar::Latch( r_heatHaze ); Cvar::Latch( r_forceAmbient ); - r_smp = Cvar_Get( "r_smp", "0", CVAR_LATCH ); + Cvar::Latch( r_smp ); // temporary latched variables that can only change over a restart - r_singleShader = Cvar_Get( "r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH ); - r_stitchCurves = Cvar_Get( "r_stitchCurves", "1", CVAR_CHEAT | CVAR_LATCH ); + Cvar::Latch( r_singleShader ); + Cvar::Latch( r_stitchCurves ); r_debugShadowMaps = Cvar_Get( "r_debugShadowMaps", "0", CVAR_CHEAT | CVAR_LATCH ); r_shadowMapLinearFilter = Cvar_Get( "r_shadowMapLinearFilter", "1", CVAR_CHEAT | CVAR_LATCH ); r_lightBleedReduction = Cvar_Get( "r_lightBleedReduction", "0", CVAR_CHEAT | CVAR_LATCH ); @@ -1184,43 +1199,21 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p AssertCvarRange( r_parallelShadowSplits, 0, MAX_SHADOWMAPS - 1, true ); // archived variables that can change at any time - r_lodBias = Cvar_Get( "r_lodBias", "0", 0 ); - r_znear = Cvar_Get( "r_znear", "3", CVAR_CHEAT ); - r_zfar = Cvar_Get( "r_zfar", "0", CVAR_CHEAT ); - r_checkGLErrors = Cvar_Get( "r_checkGLErrors", "-1", 0 ); - r_finish = Cvar_Get( "r_finish", "0", CVAR_CHEAT ); - r_gamma = Cvar_Get( "r_gamma", "1.0", CVAR_ARCHIVE ); - r_facePlaneCull = Cvar_Get( "r_facePlaneCull", "1", 0 ); - Cvar::Latch( r_ambientScale ); r_lightScale = Cvar_Get( "r_lightScale", "2", CVAR_CHEAT ); - r_vboFaces = Cvar_Get( "r_vboFaces", "1", CVAR_CHEAT ); - r_vboCurves = Cvar_Get( "r_vboCurves", "1", CVAR_CHEAT ); - r_vboTriangles = Cvar_Get( "r_vboTriangles", "1", CVAR_CHEAT ); - r_vboModels = Cvar_Get( "r_vboModels", "1", CVAR_LATCH ); - r_vboVertexSkinning = Cvar_Get( "r_vboVertexSkinning", "1", CVAR_LATCH ); + Cvar::Latch( r_vboModels ); + Cvar::Latch( r_vboVertexSkinning ); - r_mergeLeafSurfaces = Cvar_Get( "r_mergeLeafSurfaces", "1", CVAR_LATCH ); + Cvar::Latch( r_mergeLeafSurfaces ); r_evsmPostProcess = Cvar_Get( "r_evsmPostProcess", "0", CVAR_LATCH ); - r_printShaders = Cvar_Get( "r_printShaders", "0", 0 ); - Cvar::Latch( r_bloom ); - r_FXAA = Cvar_Get( "r_FXAA", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_ssao = Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE ); + Cvar::Latch( r_FXAA ); + Cvar::Latch( r_ssao ); // temporary variables that can change at any time - r_showImages = Cvar_Get( "r_showImages", "0", CVAR_TEMP ); - - r_debugSort = Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); - - r_nocurves = Cvar_Get( "r_nocurves", "0", CVAR_CHEAT ); - r_lightScissors = Cvar_Get( "r_lightScissors", "1", CVAR_ARCHIVE ); - AssertCvarRange( r_lightScissors, 0, 2, true ); - - r_noLightVisCull = Cvar_Get( "r_noLightVisCull", "0", CVAR_CHEAT ); r_noInteractionSort = Cvar_Get( "r_noInteractionSort", "0", CVAR_CHEAT ); Cvar::Latch( r_realtimeLightingRenderer ); @@ -1228,57 +1221,32 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_realtimeLightLayers ); Cvar::Latch( r_preferBindlessTextures ); Cvar::Latch( r_materialSystem ); - - r_drawworld = Cvar_Get( "r_drawworld", "1", CVAR_CHEAT ); - r_max_portal_levels = Cvar_Get( "r_max_portal_levels", "5", 0 ); - - r_showSmp = Cvar_Get( "r_showSmp", "0", CVAR_CHEAT ); - r_skipBackEnd = Cvar_Get( "r_skipBackEnd", "0", CVAR_CHEAT ); + Cvar::Latch( r_geometryCache ); r_measureOverdraw = Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); - r_lodScale = Cvar_Get( "r_lodScale", "5", CVAR_CHEAT ); - r_norefresh = Cvar_Get( "r_norefresh", "0", CVAR_CHEAT ); - r_drawentities = Cvar_Get( "r_drawentities", "1", CVAR_CHEAT ); - r_drawpolies = Cvar_Get( "r_drawpolies", "1", CVAR_CHEAT ); r_ignore = Cvar_Get( "r_ignore", "1", CVAR_CHEAT ); - r_nocull = Cvar_Get( "r_nocull", "0", CVAR_CHEAT ); - r_novis = Cvar_Get( "r_novis", "0", CVAR_CHEAT ); - r_speeds = Cvar_Get( "r_speeds", "0", 0 ); r_logFile = Cvar_Get( "r_logFile", "0", CVAR_CHEAT ); - r_debugSurface = Cvar_Get( "r_debugSurface", "0", CVAR_CHEAT ); - r_nobind = Cvar_Get( "r_nobind", "0", CVAR_CHEAT ); - r_offsetFactor = Cvar_Get( "r_offsetFactor", "-1", CVAR_CHEAT ); - r_offsetUnits = Cvar_Get( "r_offsetUnits", "-2", CVAR_CHEAT ); - - r_physicalMapping = Cvar_Get( "r_physicalMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_specularExponentMin = Cvar_Get( "r_specularExponentMin", "0.001", CVAR_CHEAT ); - r_specularExponentMax = Cvar_Get( "r_specularExponentMax", "16", CVAR_CHEAT ); - r_specularScale = Cvar_Get( "r_specularScale", "1.0", CVAR_CHEAT | CVAR_LATCH ); - r_specularMapping = Cvar_Get( "r_specularMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_deluxeMapping = Cvar_Get( "r_deluxeMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_normalScale = Cvar_Get( "r_normalScale", "1.0", CVAR_ARCHIVE ); - r_normalMapping = Cvar_Get( "r_normalMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_highQualityNormalMapping = Cvar_Get( "r_highQualityNormalMapping", "0", CVAR_LATCH ); - r_liquidMapping = Cvar_Get( "r_liquidMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_reliefDepthScale = Cvar_Get( "r_reliefDepthScale", "0.02", CVAR_CHEAT ); - r_reliefMapping = Cvar_Get( "r_reliefMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_glowMapping = Cvar_Get( "r_glowMapping", "1", CVAR_LATCH ); + + Cvar::Latch( r_physicalMapping ); + Cvar::Latch( r_specularScale ); + Cvar::Latch( r_specularMapping ); + Cvar::Latch( r_deluxeMapping ); + Cvar::Latch( r_normalMapping ); + Cvar::Latch( r_highQualityNormalMapping ); + Cvar::Latch( r_liquidMapping ); + Cvar::Latch( r_reliefMapping ); + Cvar::Latch( r_glowMapping ); Cvar::Latch( r_reflectionMapping ); Cvar::Latch( r_autoBuildCubeMaps ); Cvar::Latch( r_cubeProbeSize ); Cvar::Latch( r_cubeProbeSpacing ); - r_halfLambertLighting = Cvar_Get( "r_halfLambertLighting", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_rimLighting = Cvar_Get( "r_rimLighting", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_rimExponent = Cvar_Get( "r_rimExponent", "3", CVAR_CHEAT | CVAR_LATCH ); - AssertCvarRange( r_rimExponent, 0.5, 8.0, false ); + Cvar::Latch( r_halfLambertLighting ); + Cvar::Latch( r_rimLighting ); + Cvar::Latch( r_rimExponent ); Cvar::Latch( r_highPrecisionRendering ); - r_drawBuffer = Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); - r_lockpvs = Cvar_Get( "r_lockpvs", "0", CVAR_CHEAT ); - r_noportals = Cvar_Get( "r_noportals", "0", CVAR_CHEAT ); - Cvar::Latch( r_shadows ); r_softShadows = Cvar_Get( "r_softShadows", "0", CVAR_LATCH ); @@ -1336,32 +1304,18 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_cullShadowPyramidFaces = Cvar_Get( "r_cullShadowPyramidFaces", "0", CVAR_CHEAT ); r_noLightFrustums = Cvar_Get( "r_noLightFrustums", "1", CVAR_CHEAT ); - r_maxPolys = Cvar_Get( "r_maxpolys", "10000", CVAR_LATCH ); // 600 in vanilla Q3A - AssertCvarRange( r_maxPolys, 600, 30000, true ); + r_showShadowLod = Cvar_Get( "r_showShadowLod", "0", CVAR_CHEAT ); - r_maxPolyVerts = Cvar_Get( "r_maxpolyverts", "100000", CVAR_LATCH ); // 3000 in vanilla Q3A - AssertCvarRange( r_maxPolyVerts, 3000, 200000, true ); + Cvar::Latch( r_maxPolys ); + Cvar::Latch( r_maxPolyVerts ); - r_showTris = Cvar_Get( "r_showTris", "0", CVAR_CHEAT ); - r_showSky = Cvar_Get( "r_showSky", "0", CVAR_CHEAT ); - r_showShadowLod = Cvar_Get( "r_showShadowLod", "0", CVAR_CHEAT ); - r_showShadowMaps = Cvar_Get( "r_showShadowMaps", "0", CVAR_CHEAT ); - r_showSkeleton = Cvar_Get( "r_showSkeleton", "0", CVAR_CHEAT ); - r_showEntityTransforms = Cvar_Get( "r_showEntityTransforms", "0", CVAR_CHEAT ); - r_showLightTransforms = Cvar_Get( "r_showLightTransforms", "0", CVAR_CHEAT ); - r_showLightInteractions = Cvar_Get( "r_showLightInteractions", "0", CVAR_CHEAT ); - r_showLightScissors = Cvar_Get( "r_showLightScissors", "0", CVAR_CHEAT ); - r_showLightBatches = Cvar_Get( "r_showLightBatches", "0", CVAR_CHEAT ); - r_showLightGrid = Cvar_Get( "r_showLightGrid", "0", CVAR_CHEAT ); - r_showLightTiles = Cvar_Get("r_showLightTiles", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showBatches = Cvar_Get( "r_showBatches", "0", CVAR_CHEAT ); + Cvar::Latch( r_showLightTiles ); Cvar::Latch( r_showVertexColors ); - r_showLightMaps = Cvar_Get( "r_showLightMaps", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showDeluxeMaps = Cvar_Get( "r_showDeluxeMaps", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showNormalMaps = Cvar_Get( "r_showNormalMaps", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showMaterialMaps = Cvar_Get( "r_showMaterialMaps", "0", CVAR_CHEAT | CVAR_LATCH ); + Cvar::Latch( r_showLightMaps ); + Cvar::Latch( r_showDeluxeMaps ); + Cvar::Latch( r_showNormalMaps ); + Cvar::Latch( r_showMaterialMaps ); Cvar::Latch( r_showReflectionMaps ); - r_showBspNodes = Cvar_Get( "r_showBspNodes", "0", CVAR_CHEAT ); Cvar::Latch( r_showGlobalMaterials ); Cvar::Latch( r_materialDebug ); r_showParallelShadowSplits = Cvar_Get( "r_showParallelShadowSplits", "0", CVAR_CHEAT | CVAR_LATCH ); @@ -1444,13 +1398,13 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p } } - if ( r_showNormalMaps->integer - || r_showMaterialMaps->integer ) + if ( r_showNormalMaps.Get() + || r_showMaterialMaps.Get() ) { tr.lightMode = lightMode_t::MAP; } - else if ( r_showLightMaps->integer - || r_showDeluxeMaps->integer ) + else if ( r_showLightMaps.Get() + || r_showDeluxeMaps.Get() ) { tr.lightMode = lightMode_t::MAP; } @@ -1462,38 +1416,38 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p if ( r_reflectionMapping.Get() ) { glConfig2.reflectionMappingAvailable = true; - if ( !r_normalMapping->integer ) { + if ( !r_normalMapping.Get() ) { glConfig2.reflectionMappingAvailable = false; Log::Warn( "Unable to use static reflections without normal mapping, make sure you enable r_normalMapping" ); } - if ( !r_deluxeMapping->integer ) { + if ( !r_deluxeMapping.Get() ) { glConfig2.reflectionMappingAvailable = false; Log::Warn( "Unable to use static reflections without deluxe mapping, make sure you enable r_deluxeMapping" ); } - if ( !r_specularMapping->integer ) { + if ( !r_specularMapping.Get() ) { glConfig2.reflectionMappingAvailable = false; Log::Warn( "Unable to use static reflections without specular mapping, make sure you enable r_specularMapping" ); } - if ( r_physicalMapping->integer ) { + if ( r_physicalMapping.Get() ) { glConfig2.reflectionMappingAvailable = false; Log::Warn( "Unable to use static reflections with physical mapping, make sure you disable r_physicalMapping" ); } } backEndData[ 0 ] = ( backEndData_t * ) ri.Hunk_Alloc( sizeof( *backEndData[ 0 ] ), ha_pref::h_low ); - backEndData[ 0 ]->polys = ( srfPoly_t * ) ri.Hunk_Alloc( r_maxPolys->integer * sizeof( srfPoly_t ), ha_pref::h_low ); - backEndData[ 0 ]->polyVerts = ( polyVert_t * ) ri.Hunk_Alloc( r_maxPolyVerts->integer * sizeof( polyVert_t ), ha_pref::h_low ); - backEndData[ 0 ]->polyIndexes = ( int * ) ri.Hunk_Alloc( r_maxPolyVerts->integer * sizeof( int ), ha_pref::h_low ); + backEndData[ 0 ]->polys = ( srfPoly_t * ) ri.Hunk_Alloc( r_maxPolys.Get() * sizeof( srfPoly_t ), ha_pref::h_low ); + backEndData[ 0 ]->polyVerts = ( polyVert_t * ) ri.Hunk_Alloc( r_maxPolyVerts.Get() * sizeof( polyVert_t ), ha_pref::h_low ); + backEndData[ 0 ]->polyIndexes = ( int * ) ri.Hunk_Alloc( r_maxPolyVerts.Get() * sizeof( int ), ha_pref::h_low ); - if ( r_smp->integer ) + if ( r_smp.Get() ) { backEndData[ 1 ] = ( backEndData_t * ) ri.Hunk_Alloc( sizeof( *backEndData[ 1 ] ), ha_pref::h_low ); - backEndData[ 1 ]->polys = ( srfPoly_t * ) ri.Hunk_Alloc( r_maxPolys->integer * sizeof( srfPoly_t ), ha_pref::h_low ); - backEndData[ 1 ]->polyVerts = ( polyVert_t * ) ri.Hunk_Alloc( r_maxPolyVerts->integer * sizeof( polyVert_t ), ha_pref::h_low ); - backEndData[ 1 ]->polyIndexes = ( int * ) ri.Hunk_Alloc( r_maxPolyVerts->integer * sizeof( int ), ha_pref::h_low ); + backEndData[ 1 ]->polys = ( srfPoly_t * ) ri.Hunk_Alloc( r_maxPolys.Get() * sizeof( srfPoly_t ), ha_pref::h_low ); + backEndData[ 1 ]->polyVerts = ( polyVert_t * ) ri.Hunk_Alloc( r_maxPolyVerts.Get() * sizeof( polyVert_t ), ha_pref::h_low ); + backEndData[ 1 ]->polyIndexes = ( int * ) ri.Hunk_Alloc( r_maxPolyVerts.Get() * sizeof( int ), ha_pref::h_low ); } else { @@ -1553,7 +1507,13 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p R_DoneFreeType(); - materialSystem.Free(); + if ( glConfig2.usingMaterialSystem ) { + materialSystem.Free(); + } + + if ( glConfig2.usingGeometryCache ) { + geometryCache.Free(); + } // shut down platform specific OpenGL stuff if ( destroyWindow ) diff --git a/src/engine/renderer/tr_light.cpp b/src/engine/renderer/tr_light.cpp index c6fbaf27db..ccc919133f 100644 --- a/src/engine/renderer/tr_light.cpp +++ b/src/engine/renderer/tr_light.cpp @@ -1025,7 +1025,7 @@ static void R_AddEdgeToLightScissor( trRefLight_t *light, const vec3_t in_world1 cplane_t *frust; vec3_t clip1, clip2; - if ( r_lightScissors->integer == 1 ) + if ( r_lightScissors.Get() == 1 ) { // only clip against near plane frust = &tr.viewParms.frustums[ 0 ][ FRUSTUM_NEAR ]; @@ -1037,7 +1037,7 @@ static void R_AddEdgeToLightScissor( trRefLight_t *light, const vec3_t in_world1 R_AddPointToLightScissor( light, clip1 ); R_AddPointToLightScissor( light, clip2 ); } - else if ( r_lightScissors->integer == 2 ) + else if ( r_lightScissors.Get() == 2 ) { // clip against all planes for ( i = 0; i < FRUSTUM_PLANES; i++ ) @@ -1486,7 +1486,7 @@ cullResult_t R_CullLightWorldBounds( trRefLight_t *light, vec3_t worldBounds[ 2 bool anyClip; int r; - if ( r_nocull->integer ) + if ( r_nocull.Get() ) { return cullResult_t::CULL_CLIP; } diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 3bf09cf9e7..5ebc87f0ad 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -911,6 +911,24 @@ enum class shaderProfilerRenderSubGroupsMode { { expOperation_t ops[ MAX_EXPRESSION_OPS ]; size_t numOps; + + bool operator==( const expression_t& other ) { + if ( numOps != other.numOps ) { + return false; + } + + for ( size_t i = 0; i < numOps; i++ ) { + if ( ops[i].type != other.ops[i].type || ops[i].value != other.ops[i].value ) { + return false; + } + } + + return true; + } + + bool operator!=( const expression_t& other ) { + return !( *this == other ); + } }; struct waveForm_t @@ -921,6 +939,15 @@ enum class shaderProfilerRenderSubGroupsMode { float amplitude; float phase; float frequency; + + bool operator==( const waveForm_t& other ) { + return func == other.func && base == other.base && amplitude == other.amplitude && phase == other.phase + && frequency == other.frequency; + } + + bool operator!=( const waveForm_t& other ) { + return !( *this == other ); + } }; #define TR_MAX_TEXMODS 4 @@ -988,6 +1015,17 @@ enum class shaderProfilerRenderSubGroupsMode { expression_t sExp; expression_t tExp; expression_t rExp; + + bool operator==( const texModInfo_t& other ) { + return type == other.type && wave == other.wave && MatrixCompare( matrix, other.matrix ) + && scale[0] == other.scale[0] && scale[1] == other.scale[1] && scroll[0] == other.scroll[0] && scroll[1] == other.scroll[1] + && rotateSpeed == other.rotateSpeed + && sExp == other.sExp && tExp == other.tExp && rExp == other.rExp; + } + + bool operator!=( const texModInfo_t& other ) { + return !( *this == other ); + } }; #define MAX_IMAGE_ANIMATIONS 32 @@ -1064,10 +1102,17 @@ enum class shaderProfilerRenderSubGroupsMode { struct drawSurf_t; using stageRenderer_t = void(*)(shaderStage_t *); - using stageSurfaceDataUpdater_t = void(*)(uint32_t*, Material&, drawSurf_t*, const uint32_t); + using surfaceDataUpdater_t = void(*)(uint32_t*, shaderStage_t*, bool, bool, bool); using stageShaderBinder_t = void(*)(Material*); using stageMaterialProcessor_t = void(*)(Material*, shaderStage_t*, drawSurf_t*); + enum ShaderStageVariant { + VERTEX_OVERBRIGHT = 1, + VERTEX_LIT = BIT( 1 ), + FULLBRIGHT = BIT( 2 ), + ALL = BIT( 3 ) + }; + struct shaderStage_t { stageType_t type; @@ -1082,7 +1127,7 @@ enum class shaderProfilerRenderSubGroupsMode { stageRenderer_t colorRenderer; // Material renderer (code path for advanced OpenGL techniques like bindless textures). - stageSurfaceDataUpdater_t surfaceDataUpdater; + surfaceDataUpdater_t surfaceDataUpdater; stageShaderBinder_t shaderBinder; stageMaterialProcessor_t materialProcessor; @@ -1164,12 +1209,22 @@ enum class shaderProfilerRenderSubGroupsMode { bool noFog; // used only for shaders that have fog disabled, so we can enable it for individual stages bool useMaterialSystem = false; - uint materialPackID = 0; - uint materialID = 0; + shader_t* shader; + shaderStage_t* materialRemappedStage = nullptr; + + uint32_t paddedSize = 0; + + uint32_t materialOffset = 0; + uint32_t bufferOffset = 0; + uint32_t dynamicBufferOffset = 0; + + bool initialized = false; + bool dynamic = false; bool colorDynamic = false; - bool texMatricesDynamic = false; - bool texturesDynamic = false; + + int variantOffsets[ShaderStageVariant::ALL]; + uint32_t variantOffset = 0; }; enum cullType_t : int @@ -1606,12 +1661,14 @@ enum class shaderProfilerRenderSubGroupsMode { int fog; int portalNum = -1; - uint materialsSSBOOffset[ MAX_SHADER_STAGES ]; - bool initialized[ MAX_SHADER_STAGES ]; - uint materialIDs[ MAX_SHADER_STAGES ]; - uint materialPackIDs[ MAX_SHADER_STAGES ]; - bool texturesDynamic[ MAX_SHADER_STAGES ]; - uint drawCommandIDs[ MAX_SHADER_STAGES ]; + + uint32_t materialPackIDs[MAX_SHADER_STAGES]; + uint32_t materialIDs[MAX_SHADER_STAGES]; + + uint32_t drawCommandIDs[MAX_SHADER_STAGES]; + uint32_t texDataIDs[MAX_SHADER_STAGES]; + bool texDataDynamic[MAX_SHADER_STAGES]; + uint32_t shaderVariant[MAX_SHADER_STAGES]; drawSurf_t* depthSurface; drawSurf_t* fogSurface; @@ -2861,33 +2918,27 @@ enum class shaderProfilerRenderSubGroupsMode { extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init -// // cvars -// - extern cvar_t *r_glMajorVersion; // override GL version autodetect (for testing) - extern cvar_t *r_glMinorVersion; - extern cvar_t *r_glProfile; extern Cvar::Cvar r_glDebugProfile; extern Cvar::Range> r_glDebugMode; - extern cvar_t *r_glAllowSoftware; - extern cvar_t *r_glExtendedValidation; + extern Cvar::Cvar r_glExtendedValidation; extern cvar_t *r_ignore; // used for debugging anything extern Cvar::Cvar r_dpBlend; - extern cvar_t *r_znear; // near Z clip plane - extern cvar_t *r_zfar; + extern Cvar::Cvar r_znear; // near Z clip plane + extern Cvar::Cvar r_zfar; - extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen + extern Cvar::Cvar r_colorbits; extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement - extern cvar_t *r_lodBias; // push/pull LOD transitions - extern cvar_t *r_lodScale; + extern Cvar::Cvar r_lodBias; // push/pull LOD transitions + extern Cvar::Cvar r_lodScale; - extern cvar_t *r_wolfFog; - extern cvar_t *r_noFog; + extern Cvar::Cvar r_wolfFog; + extern Cvar::Cvar r_noFog; extern Cvar::Range> r_forceAmbient; extern Cvar::Cvar r_ambientScale; @@ -2897,8 +2948,8 @@ enum class shaderProfilerRenderSubGroupsMode { extern Cvar::Range> r_realtimeLightingRenderer; extern Cvar::Cvar r_realtimeLighting; extern Cvar::Range> r_realtimeLightLayers; - extern cvar_t *r_realtimeLightingCastShadows; - extern cvar_t *r_precomputedLighting; + extern Cvar::Cvar r_realtimeLightingCastShadows; + extern Cvar::Cvar r_precomputedLighting; extern Cvar::Cvar r_overbrightDefaultExponent; extern Cvar::Cvar r_overbrightDefaultClamp; extern Cvar::Cvar r_overbrightIgnoreMapSettings; @@ -2909,63 +2960,63 @@ enum class shaderProfilerRenderSubGroupsMode { extern Cvar::Cvar r_gpuFrustumCulling; extern Cvar::Cvar r_gpuOcclusionCulling; extern Cvar::Cvar r_materialSystemSkip; - extern cvar_t *r_lightStyles; - extern cvar_t *r_exportTextures; - extern cvar_t *r_heatHaze; - extern cvar_t *r_noMarksOnTrisurfs; + extern Cvar::Cvar r_geometryCache; + extern Cvar::Cvar r_lightStyles; + extern Cvar::Cvar r_exportTextures; + extern Cvar::Cvar r_heatHaze; + extern Cvar::Cvar r_noMarksOnTrisurfs; extern Cvar::Range> r_lazyShaders; // 0: build all shaders on program start 1: delay shader build until first map load 2: delay shader build until needed - extern cvar_t *r_norefresh; // bypasses the ref rendering - extern cvar_t *r_drawentities; // disable/enable entity rendering - extern cvar_t *r_drawworld; // disable/enable world rendering - extern cvar_t *r_drawpolies; // disable/enable world rendering - extern cvar_t *r_speeds; // various levels of information display - extern cvar_t *r_novis; // disable/enable usage of PVS - extern cvar_t *r_nocull; - extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test - extern cvar_t *r_nocurves; - extern cvar_t *r_lightScissors; - extern cvar_t *r_noLightVisCull; + extern Cvar::Cvar r_norefresh; + extern Cvar::Cvar r_drawentities; + extern Cvar::Cvar r_drawworld; + extern Cvar::Cvar r_drawpolies; + extern Cvar::Range> r_speeds; + extern Cvar::Cvar r_novis; + extern Cvar::Cvar r_nocull; + extern Cvar::Cvar r_facePlaneCull; + extern Cvar::Cvar r_nocurves; + extern Cvar::Range> r_lightScissors; extern cvar_t *r_noInteractionSort; - extern cvar_t *r_mode; // video mode - extern cvar_t *r_gamma; + extern Cvar::Cvar r_mode; + extern Cvar::Cvar r_gamma; - extern cvar_t *r_nobind; // turns off binding to appropriate textures - extern cvar_t *r_singleShader; // make most world faces use default shader - extern cvar_t *r_picMip; // controls picmip values - extern cvar_t *r_imageMaxDimension; - extern cvar_t *r_ignoreMaterialMinDimension; - extern cvar_t *r_ignoreMaterialMaxDimension; - extern cvar_t *r_replaceMaterialMinDimensionIfPresentWithMaxDimension; + extern Cvar::Cvar r_nobind; + extern Cvar::Cvar r_singleShader; + extern Cvar::Cvar r_picMip; + extern Cvar::Cvar r_imageMaxDimension; + extern Cvar::Cvar r_ignoreMaterialMinDimension; + extern Cvar::Cvar r_ignoreMaterialMaxDimension; + extern Cvar::Cvar r_replaceMaterialMinDimensionIfPresentWithMaxDimension; extern Cvar::Range> r_imageFitScreen; - extern cvar_t *r_finish; - extern cvar_t *r_drawBuffer; + extern Cvar::Cvar r_finish; + extern Cvar::Cvar r_drawBuffer; extern Cvar::Modified> r_textureMode; - extern cvar_t *r_offsetFactor; - extern cvar_t *r_offsetUnits; - - extern cvar_t *r_physicalMapping; - extern cvar_t *r_specularExponentMin; - extern cvar_t *r_specularExponentMax; - extern cvar_t *r_specularScale; - extern cvar_t *r_specularMapping; - extern cvar_t *r_deluxeMapping; - extern cvar_t *r_normalScale; - extern cvar_t *r_normalMapping; - extern cvar_t *r_highQualityNormalMapping; - extern cvar_t *r_liquidMapping; - extern cvar_t *r_reliefDepthScale; - extern cvar_t *r_reliefMapping; - extern cvar_t *r_glowMapping; + extern Cvar::Cvar r_offsetFactor; + extern Cvar::Cvar r_offsetUnits; + + extern Cvar::Cvar r_physicalMapping; + extern Cvar::Cvar r_specularExponentMin; + extern Cvar::Cvar r_specularExponentMax; + extern Cvar::Cvar r_specularScale; + extern Cvar::Cvar r_specularMapping; + extern Cvar::Cvar r_deluxeMapping; + extern Cvar::Cvar r_normalScale; + extern Cvar::Cvar r_normalMapping; + extern Cvar::Cvar r_highQualityNormalMapping; + extern Cvar::Cvar r_liquidMapping; + extern Cvar::Cvar r_reliefDepthScale; + extern Cvar::Cvar r_reliefMapping; + extern Cvar::Cvar r_glowMapping; extern Cvar::Cvar r_reflectionMapping; extern Cvar::Range> r_autoBuildCubeMaps; extern Cvar::Range> r_cubeProbeSize; extern Cvar::Range> r_cubeProbeSpacing; - extern cvar_t *r_halfLambertLighting; - extern cvar_t *r_rimLighting; - extern cvar_t *r_rimExponent; + extern Cvar::Cvar r_halfLambertLighting; + extern Cvar::Cvar r_rimLighting; + extern Cvar::Range> r_rimExponent; extern Cvar::Cvar r_highPrecisionRendering; @@ -3001,51 +3052,51 @@ enum class shaderProfilerRenderSubGroupsMode { extern cvar_t *r_parallelShadowSplits; extern cvar_t *r_parallelShadowSplitWeight; - extern cvar_t *r_lockpvs; - extern cvar_t *r_noportals; - extern cvar_t *r_max_portal_levels; + extern Cvar::Cvar r_lockpvs; + extern Cvar::Cvar r_noportals; + extern Cvar::Cvar r_max_portal_levels; - extern cvar_t *r_subdivisions; - extern cvar_t *r_stitchCurves; + extern Cvar::Cvar r_subdivisions; + extern Cvar::Cvar r_stitchCurves; - extern cvar_t *r_smp; - extern cvar_t *r_showSmp; - extern cvar_t *r_skipBackEnd; + extern Cvar::Cvar r_smp; + extern Cvar::Cvar r_showSmp; + extern Cvar::Cvar r_skipBackEnd; - extern cvar_t *r_checkGLErrors; + extern Cvar::Range> r_checkGLErrors; - extern cvar_t *r_debugSurface; + extern Cvar::Cvar r_debugSurface; - extern cvar_t *r_showImages; - extern cvar_t *r_debugSort; + extern Cvar::Range> r_showImages; + extern Cvar::Cvar r_debugSort; - extern cvar_t *r_printShaders; + extern Cvar::Cvar r_printShaders; - extern cvar_t *r_maxPolys; - extern cvar_t *r_maxPolyVerts; + extern Cvar::Range> r_maxPolys; + extern Cvar::Range> r_maxPolyVerts; - extern cvar_t *r_showTris; // enables wireframe rendering of the world - extern cvar_t *r_showSky; // forces sky in front of all surfaces + extern Cvar::Cvar r_showTris; + extern Cvar::Cvar r_showSky; extern cvar_t *r_showShadowLod; extern cvar_t *r_showShadowMaps; - extern cvar_t *r_showSkeleton; - extern cvar_t *r_showEntityTransforms; - extern cvar_t *r_showLightTransforms; - extern cvar_t *r_showLightInteractions; - extern cvar_t *r_showLightScissors; - extern cvar_t *r_showLightBatches; - extern cvar_t *r_showLightGrid; - extern cvar_t *r_showLightTiles; - extern cvar_t *r_showBatches; + extern Cvar::Cvar r_showSkeleton; + extern Cvar::Cvar r_showEntityTransforms; + extern Cvar::Cvar r_showLightTransforms; + extern Cvar::Cvar r_showLightInteractions; + extern Cvar::Cvar r_showLightScissors; + extern Cvar::Cvar r_showLightBatches; + extern Cvar::Cvar r_showLightGrid; + extern Cvar::Cvar r_showLightTiles; + extern Cvar::Cvar r_showBatches; extern Cvar::Cvar r_showVertexColors; - extern cvar_t *r_showLightMaps; // render lightmaps only - extern cvar_t *r_showDeluxeMaps; - extern cvar_t *r_showNormalMaps; - extern cvar_t *r_showMaterialMaps; + extern Cvar::Cvar r_showLightMaps; + extern Cvar::Cvar r_showDeluxeMaps; + extern Cvar::Cvar r_showNormalMaps; + extern Cvar::Cvar r_showMaterialMaps; extern Cvar::Cvar r_showReflectionMaps; extern Cvar::Range> r_showCubeProbes; extern Cvar::Cvar r_showCubeProbeFace; - extern cvar_t *r_showBspNodes; + extern Cvar::Range> r_showBspNodes; extern Cvar::Range> r_showGlobalMaterials; extern Cvar::Cvar r_materialDebug; extern cvar_t *r_showParallelShadowSplits; @@ -3056,19 +3107,19 @@ enum class shaderProfilerRenderSubGroupsMode { extern Cvar::Range> r_profilerRenderSubGroupsMode; extern Cvar::Cvar r_profilerRenderSubGroupsStage; - extern cvar_t *r_vboFaces; - extern cvar_t *r_vboCurves; - extern cvar_t *r_vboTriangles; - extern cvar_t *r_vboModels; - extern cvar_t *r_vboVertexSkinning; + extern Cvar::Cvar r_vboFaces; + extern Cvar::Cvar r_vboCurves; + extern Cvar::Cvar r_vboTriangles; + extern Cvar::Cvar r_vboModels; + extern Cvar::Cvar r_vboVertexSkinning; - extern cvar_t *r_mergeLeafSurfaces; + extern Cvar::Cvar r_mergeLeafSurfaces; extern Cvar::Cvar r_bloom; extern Cvar::Cvar r_bloomBlur; extern Cvar::Cvar r_bloomPasses; - extern cvar_t *r_FXAA; - extern cvar_t *r_ssao; + extern Cvar::Cvar r_FXAA; + extern Cvar::Cvar r_ssao; extern cvar_t *r_evsmPostProcess; @@ -3081,9 +3132,9 @@ enum class shaderProfilerRenderSubGroupsMode { inline bool checkGLErrors() { #ifdef DEBUG_BUILD - return r_checkGLErrors->integer != 0; + return r_checkGLErrors.Get() != 0; #else - return r_checkGLErrors->integer > 0; + return r_checkGLErrors.Get() > 0; #endif } @@ -3192,7 +3243,7 @@ inline bool checkGLErrors() void GL_Bind( image_t *image ); void GL_BindNearestCubeMap( int unit, const vec3_t xyz ); void GL_Unbind( image_t *image ); - GLuint64 BindAnimatedImage( int unit, textureBundle_t *bundle ); + GLuint64 BindAnimatedImage( int unit, const textureBundle_t *bundle ); void GL_TextureFilter( image_t *image, filterType_t filterType ); void GL_BindProgram( shaderProgram_t *program ); GLuint64 GL_BindToTMU( int unit, image_t *image ); @@ -3658,6 +3709,10 @@ inline bool checkGLErrors() ============================================================ */ + uint32_t ComponentSize( GLenum type ); + void CopyVertexAttribute( const vboAttributeLayout_t& attrib, const vertexAttributeSpec_t& spec, + uint32_t count, byte* interleavedData ); + VBO_t *R_CreateStaticVBO( Str::StringRef name, const vertexAttributeSpec_t *attrBegin, const vertexAttributeSpec_t *attrEnd, uint32_t numVerts, uint32_t numFrames = 0 ); diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 2c8ac3d501..4718321886 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -342,7 +342,7 @@ cullResult_t R_CullBox( vec3_t worldBounds[ 2 ] ) cplane_t *frust; int i, r; - if ( r_nocull->integer ) + if ( r_nocull.Get() ) { return cullResult_t::CULL_CLIP; } @@ -421,7 +421,7 @@ cullResult_t R_CullPointAndRadius( vec3_t pt, float radius ) cplane_t *frust; bool mightBeClipped = false; - if ( r_nocull->integer ) + if ( r_nocull.Get() ) { return cullResult_t::CULL_CLIP; } @@ -895,14 +895,14 @@ static void R_SetupProjection( bool infiniteFarClip ) // portal views are constrained to their surface plane if ( tr.viewParms.portalLevel == 0 ) { - tr.viewParms.zNear = r_znear->value; + tr.viewParms.zNear = r_znear.Get(); } zNear = tr.viewParms.zNear; - if ( r_zfar->value ) + if ( r_zfar.Get() ) { - zFar = tr.viewParms.zFar = std::max( tr.viewParms.zFar, r_zfar->value ); + zFar = tr.viewParms.zFar = std::max( tr.viewParms.zFar, r_zfar.Get() ); } else if ( infiniteFarClip ) { @@ -913,7 +913,7 @@ static void R_SetupProjection( bool infiniteFarClip ) zFar = tr.viewParms.zFar; } - if ( zFar <= 0 || infiniteFarClip ) // || r_showBspNodes->integer) + if ( zFar <= 0 || infiniteFarClip ) { MatrixPerspectiveProjectionFovXYInfiniteRH( proj, tr.refdef.fov_x, tr.refdef.fov_y, zNear ); } @@ -1016,7 +1016,7 @@ static void R_SetupFrustum() tr.viewParms.frustums[ 0 ][ FRUSTUM_NEAR ].type = PLANE_NON_AXIAL; VectorCopy( tr.viewParms.orientation.axis[ 0 ], tr.viewParms.frustums[ 0 ][ FRUSTUM_NEAR ].normal ); - VectorMA( tr.viewParms.orientation.origin, r_znear->value, tr.viewParms.frustums[ 0 ][ FRUSTUM_NEAR ].normal, planeOrigin ); + VectorMA( tr.viewParms.orientation.origin, r_znear.Get(), tr.viewParms.frustums[ 0 ][ FRUSTUM_NEAR ].normal, planeOrigin ); tr.viewParms.frustums[ 0 ][ FRUSTUM_NEAR ].dist = DotProduct( planeOrigin, tr.viewParms.frustums[ 0 ][ FRUSTUM_NEAR ].normal ); SetPlaneSignbits( &tr.viewParms.frustums[ 0 ][ FRUSTUM_NEAR ] ); } @@ -1697,7 +1697,7 @@ static void R_SetupPortalFrustum( const viewParms_t& oldParms, const orientation } zNear = sqrtf(zNear); - zNear = std::max(zNear, r_znear->value); + zNear = std::max(zNear, r_znear.Get() ); newParms.zNear = zNear; } @@ -1715,7 +1715,7 @@ bool R_MirrorViewBySurface(drawSurf_t *drawSurf) screenRect_t surfRect; // don't recursively mirror too much - if ( tr.viewParms.portalLevel >= r_max_portal_levels->integer && + if ( tr.viewParms.portalLevel >= r_max_portal_levels.Get() && tr.viewParms.portalLevel > 0 ) { /* Having more than one mirror in a scene is not a bug, @@ -1725,7 +1725,7 @@ bool R_MirrorViewBySurface(drawSurf_t *drawSurf) return false; } - if (r_noportals->integer) + if ( r_noportals.Get() ) { return false; } @@ -2038,16 +2038,15 @@ R_AddEntitySurfaces */ void R_AddEntitySurfaces() { - int i; trRefEntity_t *ent; shader_t *shader; - if ( !r_drawentities->integer ) + if ( !r_drawentities.Get() ) { return; } - for ( i = 0; i < tr.refdef.numEntities; i++ ) + for ( int i = 0; i < tr.refdef.numEntities; i++ ) { ent = tr.currentEntity = &tr.refdef.entities[ i ]; @@ -2148,16 +2147,15 @@ R_AddEntityInteractions */ void R_AddEntityInteractions( trRefLight_t *light ) { - int i; trRefEntity_t *ent; interactionType_t iaType; - if ( !r_drawentities->integer ) + if ( !r_drawentities.Get() ) { return; } - for ( i = 0; i < tr.refdef.numEntities; i++ ) + for ( int i = 0; i < tr.refdef.numEntities; i++ ) { iaType = IA_DEFAULT; @@ -2464,7 +2462,7 @@ Visualization aid for movement clipping debugging */ static void R_DebugGraphics() { - if ( r_debugSurface->integer ) + if ( r_debugSurface.Get() ) { // the render thread can't make callbacks to the main thread R_SyncRenderThread(); diff --git a/src/engine/renderer/tr_marks.cpp b/src/engine/renderer/tr_marks.cpp index c54e82f383..ac67b8cd6a 100644 --- a/src/engine/renderer/tr_marks.cpp +++ b/src/engine/renderer/tr_marks.cpp @@ -479,7 +479,7 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio } } } - else if ( *surfaces[ i ] == surfaceType_t::SF_TRIANGLES && !r_noMarksOnTrisurfs->integer ) + else if ( *surfaces[ i ] == surfaceType_t::SF_TRIANGLES && !r_noMarksOnTrisurfs.Get() ) { trisurf = ( srfTriangles_t * ) surfaces[ i ]; diff --git a/src/engine/renderer/tr_mesh.cpp b/src/engine/renderer/tr_mesh.cpp index 8aefcda50b..76c29701fd 100644 --- a/src/engine/renderer/tr_mesh.cpp +++ b/src/engine/renderer/tr_mesh.cpp @@ -157,7 +157,7 @@ int R_ComputeLOD( trRefEntity_t *ent ) if ( ( projectedRadius = R_ProjectRadius( radius, ent->e.origin ) ) != 0 ) { - lodscale = r_lodScale->value; + lodscale = r_lodScale.Get(); if ( lodscale > 20 ) { @@ -185,7 +185,7 @@ int R_ComputeLOD( trRefEntity_t *ent ) } } - lod += r_lodBias->integer; + lod += r_lodBias.Get(); if ( lod >= tr.currentModel->numLods ) { @@ -306,7 +306,7 @@ void R_AddMDVSurfaces( trRefEntity_t *ent ) fogNum = R_FogWorldBox( ent->worldBounds ); // draw all surfaces - if ( r_vboModels->integer && model->numVBOSurfaces ) + if ( r_vboModels.Get() && model->numVBOSurfaces ) { srfVBOMDVMesh_t *vboSurface; @@ -416,7 +416,7 @@ void R_AddMDVInteractions( trRefEntity_t *ent, trRefLight_t *light, interactionT cubeSideBits = R_CalcLightCubeSideBits( light, ent->worldBounds ); // generate interactions with all surfaces - if ( r_vboModels->integer && model->numVBOSurfaces ) + if ( r_vboModels.Get() && model->numVBOSurfaces ) { // new brute force method: just render everthing with static VBOs srfVBOMDVMesh_t *vboSurface; diff --git a/src/engine/renderer/tr_model_iqm.cpp b/src/engine/renderer/tr_model_iqm.cpp index c865571542..6d937d41a4 100644 --- a/src/engine/renderer/tr_model_iqm.cpp +++ b/src/engine/renderer/tr_model_iqm.cpp @@ -767,7 +767,7 @@ bool R_LoadIQModel( model_t *mod, const void *buffer, int filesize, } // convert data where necessary and create VBO - if( r_vboModels->integer && glConfig2.vboVertexSkinningAvailable + if( r_vboModels.Get() && glConfig2.vboVertexSkinningAvailable && IQModel->num_joints <= glConfig2.maxVertexSkinningBones ) { uint16_t *boneFactorBuf = (uint16_t*)ri.Hunk_AllocateTempMemory( IQModel->num_vertexes * ( 4 * sizeof(uint16_t) ) ); diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index 038c069489..5cf5a414a3 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -77,6 +77,7 @@ struct glconfig2_t char shadingLanguageVersionString[ MAX_STRING_CHARS ]; int shadingLanguageVersion; + int maxUniformBlockSize; int maxVertexUniforms; // int maxVaryingFloats; int maxVertexAttribs; @@ -101,6 +102,8 @@ struct glconfig2_t bool indirectParametersAvailable; bool shadingLanguage420PackAvailable; bool explicitUniformLocationAvailable; + bool directStateAccessAvailable; + bool vertexAttribBindingAvailable; bool shaderImageLoadStoreAvailable; bool shaderAtomicCountersAvailable; bool shaderAtomicCounterOpsAvailable; @@ -115,6 +118,8 @@ struct glconfig2_t bool shaderSubgroupQuadAvailable; bool materialSystemAvailable; // do the driver/hardware support it bool usingMaterialSystem; // are we using it right now + bool geometryCacheAvailable; + bool usingGeometryCache; bool gpuShader4Available; bool gpuShader5Available; bool textureGatherAvailable; diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index aa02565b4a..e6e5793f82 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -52,7 +52,7 @@ R_ToggleSmpFrame */ void R_ToggleSmpFrame() { - if ( r_smp->integer ) + if ( r_smp.Get() ) { // use the other buffers next frame, because another CPU // may still be rendering into the current ones @@ -118,7 +118,7 @@ void R_AddPolygonSurfaces() shader_t *sh; srfPoly_t *poly; - if ( !r_drawpolies->integer ) + if ( !r_drawpolies.Get() ) { return; } @@ -150,7 +150,7 @@ static void R_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t return; } - if ( !r_drawpolies->integer ) + if ( !r_drawpolies.Get() ) { return; } @@ -163,7 +163,7 @@ static void R_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t for ( j = 0; j < numPolys; j++ ) { - if ( r_numPolyVerts + numVerts >= r_maxPolyVerts->integer || r_numPolys >= r_maxPolys->integer ) + if ( r_numPolyVerts + numVerts >= r_maxPolyVerts.Get() || r_numPolys >= r_maxPolys.Get() ) { /* NOTE TTimo this was initially Log::Warn @@ -171,7 +171,7 @@ static void R_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t since we don't plan on changing the const and making for room for those effects simply cut this message to developer only */ - Log::Debug("RE_AddPolyToScene: r_max_polys or r_max_polyverts reached" ); + Log::Debug( "RE_AddPolyToScene: r_max_polys or r_max_polyverts reached" ); return; } @@ -335,7 +335,7 @@ void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensit light->l.color[ 2 ] = b; light->l.inverseShadows = (flags & REF_INVERSE_DLIGHT) != 0; - light->l.noShadows = !r_realtimeLightingCastShadows->integer && !light->l.inverseShadows; + light->l.noShadows = !r_realtimeLightingCastShadows.Get() && !light->l.inverseShadows; if( flags & REF_RESTRICT_DLIGHT ) { light->restrictInteractionFirst = r_numEntities - r_firstSceneEntity; @@ -500,8 +500,6 @@ to handle mirrors, */ void RE_RenderScene( const refdef_t *fd ) { - int startTime; - if ( !tr.registered ) { return; @@ -509,12 +507,12 @@ void RE_RenderScene( const refdef_t *fd ) GLimp_LogComment( "====== RE_RenderScene =====\n" ); - if ( r_norefresh->integer ) + if ( r_norefresh.Get() ) { return; } - startTime = ri.Milliseconds(); + int startTime = ri.Milliseconds(); if ( !tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 235743706a..09b14ee0e3 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -103,11 +103,11 @@ static void EnableAvailableFeatures() } } - glConfig2.deluxeMapping = r_deluxeMapping->integer; - glConfig2.normalMapping = r_normalMapping->integer; - glConfig2.specularMapping = r_specularMapping->integer; - glConfig2.physicalMapping = r_physicalMapping->integer; - glConfig2.reliefMapping = r_reliefMapping->integer; + glConfig2.deluxeMapping = r_deluxeMapping.Get(); + glConfig2.normalMapping = r_normalMapping.Get(); + glConfig2.specularMapping = r_specularMapping.Get(); + glConfig2.physicalMapping = r_physicalMapping.Get(); + glConfig2.reliefMapping = r_reliefMapping.Get(); /* ATI R300 and Intel GMA 3 only have 64 ALU instructions, which is not enough for some shader variants. For example the lightMapping shader permutation with macros USE_GRID_LIGHTING and @@ -177,6 +177,8 @@ static void EnableAvailableFeatures() glConfig2.usingMaterialSystem = r_materialSystem.Get() && glConfig2.materialSystemAvailable; glConfig2.usingBindlessTextures = glConfig2.usingMaterialSystem || ( r_preferBindlessTextures.Get() && glConfig2.bindlessTexturesAvailable ); + glConfig2.usingGeometryCache = glConfig2.usingMaterialSystem + || ( r_geometryCache.Get() && glConfig2.geometryCacheAvailable ); } // For shaders that require map data for compile-time values @@ -306,7 +308,7 @@ static void GLSL_InitGPUShadersOrError() gl_shaderManager.load( gl_fogGlobalShader ); } - if ( r_heatHaze->integer ) + if ( r_heatHaze.Get() ) { // heatHaze post process effect gl_shaderManager.load( gl_heatHazeShader ); @@ -331,7 +333,7 @@ static void GLSL_InitGPUShadersOrError() gl_shaderManager.load( gl_contrastShader ); } - if ( !r_noportals->integer || r_liquidMapping->integer ) + if ( !r_noportals.Get() || r_liquidMapping.Get() ) { // portal process effect gl_shaderManager.load( gl_portalShader ); @@ -355,7 +357,7 @@ static void GLSL_InitGPUShadersOrError() gl_shaderManager.load( gl_debugShadowMapShader ); } - if ( r_liquidMapping->integer != 0 ) + if ( r_liquidMapping.Get() ) { gl_shaderManager.load( gl_liquidShader ); @@ -370,7 +372,7 @@ static void GLSL_InitGPUShadersOrError() gl_shaderManager.load( gl_motionblurShader ); } - if ( r_ssao->integer ) + if ( r_ssao.Get() ) { if ( glConfig2.textureGatherAvailable ) { @@ -382,7 +384,7 @@ static void GLSL_InitGPUShadersOrError() } } - if ( r_FXAA->integer != 0 ) + if ( r_FXAA.Get() != 0 ) { gl_shaderManager.load( gl_fxaaShader ); } @@ -670,7 +672,7 @@ static void DrawTris() // u_AlphaThreshold gl_genericShader->SetUniform_AlphaTest( GLS_ATEST_NONE ); - if ( r_showBatches->integer || r_showLightBatches->integer ) + if ( r_showBatches.Get() || r_showLightBatches.Get() ) { gl_genericShader->SetUniform_Color( Color::Color::Indexed( backEnd.pc.c_batches % 8 ) ); } @@ -800,7 +802,7 @@ void SetNormalScale( const shaderStage_t *pStage, vec3_t normalScale ) r_normalScale is set to zero. This is cool enough to be kept as a feature. Normal Z component equal to zero would be wrong anyway. r_normalScale is only applied on Z. */ - normalScale[ 2 ] = pStage->normalScale[ 2 ] * r_normalScale->value; + normalScale[ 2 ] = pStage->normalScale[ 2 ] * r_normalScale.Get(); } // *INDENT-ON* @@ -818,11 +820,6 @@ void Render_generic3D( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_generic3D ---\n" ); - if ( materialSystem.generatingWorldCommandBuffer ) { - Tess_DrawElements(); - return; - } - GL_State( pStage->stateBits ); bool hasDepthFade = pStage->hasDepthFade; @@ -949,11 +946,6 @@ void Render_lightMapping( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_lightMapping ---\n" ); - if ( materialSystem.generatingWorldCommandBuffer ) { - Tess_DrawElements(); - return; - } - lightMode_t lightMode; deluxeMode_t deluxeMode; SetLightDeluxeMode( &tess, pStage->type, lightMode, deluxeMode ); @@ -970,7 +962,7 @@ void Render_lightMapping( shaderStage_t *pStage ) uint32_t stateBits = pStage->stateBits; - if ( lightMode == lightMode_t::MAP && r_showLightMaps->integer ) + if ( lightMode == lightMode_t::MAP && r_showLightMaps.Get() ) { stateBits &= ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_ATEST_BITS ); } @@ -1074,7 +1066,7 @@ void Render_lightMapping( shaderStage_t *pStage ) // bind u_HeightMap if ( pStage->enableReliefMapping ) { - float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale.Get() ); depthScale *= tess.surfaceShader->reliefDepthScale; gl_lightMappingShader->SetUniform_ReliefDepthScale( depthScale ); @@ -1100,7 +1092,7 @@ void Render_lightMapping( shaderStage_t *pStage ) } // bind u_NormalMap - if ( !!r_normalMapping->integer || pStage->hasHeightMapInNormalMap ) + if ( !!r_normalMapping.Get() || pStage->hasHeightMapInNormalMap ) { gl_lightMappingShader->SetUniform_NormalMapBindless( GL_BindToTMU( BIND_NORMALMAP, pStage->bundle[TB_NORMALMAP].image[0] ) @@ -1126,8 +1118,8 @@ void Render_lightMapping( shaderStage_t *pStage ) if ( pStage->enableSpecularMapping ) { - float specExpMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); - float specExpMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + float specExpMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin.Get() ); + float specExpMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax.Get() ); gl_lightMappingShader->SetUniform_SpecularExponent( specExpMin, specExpMax ); } @@ -1206,7 +1198,7 @@ void Render_lightMapping( shaderStage_t *pStage ) } // bind u_GlowMap - if ( !!r_glowMapping->integer ) + if ( r_glowMapping.Get() ) { gl_lightMappingShader->SetUniform_GlowMapBindless( GL_BindToTMU( BIND_GLOWMAP, pStage->bundle[TB_GLOWMAP].image[0] ) @@ -1238,10 +1230,6 @@ static void Render_shadowFill( shaderStage_t *pStage ) GLimp_LogComment( "--- Render_shadowFill ---\n" ); - if ( materialSystem.generatingWorldCommandBuffer ) { - return; - } - // remove blend modes stateBits = pStage->stateBits; stateBits &= ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ); @@ -1351,7 +1339,7 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, // bind u_HeightMap if ( pStage->enableReliefMapping ) { - float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale.Get() ); depthScale *= tess.surfaceShader->reliefDepthScale; gl_forwardLightingShader_omniXYZ->SetUniform_ReliefDepthScale( depthScale ); @@ -1444,8 +1432,8 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) { - float minSpec = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); - float maxSpec = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + float minSpec = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin.Get() ); + float maxSpec = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax.Get() ); gl_forwardLightingShader_omniXYZ->SetUniform_SpecularExponent( minSpec, maxSpec ); @@ -1526,7 +1514,7 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, // bind u_HeightMap if ( pStage->enableReliefMapping ) { - float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale.Get() ); depthScale *= tess.surfaceShader->reliefDepthScale; gl_forwardLightingShader_projXYZ->SetUniform_ReliefDepthScale( depthScale ); @@ -1625,8 +1613,8 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) { - float minSpec = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); - float maxSpec = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + float minSpec = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin.Get() ); + float maxSpec = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax.Get() ); gl_forwardLightingShader_projXYZ->SetUniform_SpecularExponent( minSpec, maxSpec ); } @@ -1702,7 +1690,7 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef // bind u_HeightMap if ( pStage->enableReliefMapping ) { - float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale.Get() ); depthScale *= tess.surfaceShader->reliefDepthScale; gl_forwardLightingShader_directionalSun->SetUniform_ReliefDepthScale( depthScale ); @@ -1805,8 +1793,8 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) { - float minSpec = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); - float maxSpec = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + float minSpec = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin.Get() ); + float maxSpec = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax.Get() ); gl_forwardLightingShader_directionalSun->SetUniform_SpecularExponent( minSpec, maxSpec ); } @@ -1872,11 +1860,6 @@ void Render_reflection_CB( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_reflection_CB ---\n" ); - if ( materialSystem.generatingWorldCommandBuffer ) { - Tess_DrawElements(); - return; - } - GL_State( pStage->stateBits ); // choose right shader program ---------------------------------- @@ -1942,7 +1925,7 @@ void Render_reflection_CB( shaderStage_t *pStage ) // bind u_HeightMap u_depthScale u_reliefOffsetBias if ( pStage->enableReliefMapping ) { - float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale.Get() ); depthScale *= tess.surfaceShader->reliefDepthScale; gl_reflectionShader->SetUniform_ReliefDepthScale( depthScale ); @@ -1968,11 +1951,6 @@ void Render_skybox( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_skybox ---\n" ); - if ( materialSystem.generatingWorldCommandBuffer ) { - Tess_DrawElements(); - return; - } - GL_State( pStage->stateBits ); gl_skyboxShader->BindProgram( pStage->deformIndex ); @@ -1998,11 +1976,6 @@ void Render_screen( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_screen ---\n" ); - if ( materialSystem.generatingWorldCommandBuffer ) { - Tess_DrawElements(); - return; - } - GL_State( pStage->stateBits ); gl_screenShader->BindProgram( pStage->deformIndex ); @@ -2058,11 +2031,6 @@ void Render_heatHaze( shaderStage_t *pStage ) GLimp_LogComment( "--- Render_heatHaze ---\n" ); - if ( materialSystem.generatingWorldCommandBuffer ) { - Tess_DrawElements(); - return; - } - // remove alpha test stateBits = pStage->stateBits; stateBits &= ~GLS_ATEST_BITS; @@ -2151,11 +2119,6 @@ void Render_liquid( shaderStage_t *pStage ) GLimp_LogComment( "--- Render_liquid ---\n" ); - if ( materialSystem.generatingWorldCommandBuffer ) { - Tess_DrawElements(); - return; - } - // Tr3B: don't allow blend effects GL_State( pStage->stateBits & ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_DEPTHMASK_TRUE ) ); @@ -2198,8 +2161,8 @@ void Render_liquid( shaderStage_t *pStage ) // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) { - float specMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); - float specMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + float specMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin.Get() ); + float specMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax.Get() ); gl_liquidShader->SetUniform_SpecularExponent( specMin, specMax ); } @@ -2215,7 +2178,7 @@ void Render_liquid( shaderStage_t *pStage ) // bind u_HeightMap u_depthScale u_reliefOffsetBias if ( pStage->enableReliefMapping ) { - float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale.Get() ); depthScale *= tess.surfaceShader->reliefDepthScale; gl_liquidShader->SetUniform_ReliefDepthScale( depthScale ); @@ -2250,12 +2213,7 @@ void Render_liquid( shaderStage_t *pStage ) void Render_fog( shaderStage_t* pStage ) { - if ( materialSystem.generatingWorldCommandBuffer ) { - Tess_DrawElements(); - return; - } - - if ( r_noFog->integer || !r_wolfFog->integer || ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) + if ( r_noFog.Get() || !r_wolfFog.Get() || ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { return; } @@ -2317,7 +2275,7 @@ void Render_fog( shaderStage_t* pStage ) gl_fogQuake3Shader->SetUniform_FogEyeT( eyeT ); // u_Color - gl_fogQuake3Shader->SetUniform_Color( fog->color ); + gl_fogQuake3Shader->SetUniform_ColorGlobal( fog->color ); gl_fogQuake3Shader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_fogQuake3Shader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); @@ -2674,7 +2632,7 @@ void Tess_StageIteratorColor() if ( tess.surfaceShader->polygonOffset ) { glEnable( GL_POLYGON_OFFSET_FILL ); - GL_PolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); + GL_PolygonOffset( r_offsetFactor.Get(), r_offsetUnits.Get() ); } // call shader function @@ -2698,7 +2656,7 @@ void Tess_StageIteratorColor() Tess_ComputeTexMatrices( pStage ); if ( materialSystem.generatingWorldCommandBuffer && pStage->useMaterialSystem ) { - tess.currentSSBOOffset = tess.currentDrawSurf->materialsSSBOOffset[stage]; + tess.currentSSBOOffset = pStage->materialOffset; tess.materialID = tess.currentDrawSurf->materialIDs[stage]; tess.materialPackID = tess.currentDrawSurf->materialPackIDs[stage]; } @@ -2787,7 +2745,7 @@ void Tess_StageIteratorShadowFill() if ( tess.surfaceShader->polygonOffset ) { glEnable( GL_POLYGON_OFFSET_FILL ); - GL_PolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); + GL_PolygonOffset( r_offsetFactor.Get(), r_offsetUnits.Get() ); } // call shader function @@ -2865,7 +2823,7 @@ void Tess_StageIteratorLighting() if ( tess.surfaceShader->polygonOffset ) { glEnable( GL_POLYGON_OFFSET_FILL ); - GL_PolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); + GL_PolygonOffset( r_offsetFactor.Get(), r_offsetUnits.Get() ); } // call shader function @@ -2968,8 +2926,8 @@ void Tess_End() } // for debugging of sort order issues, stop rendering after a given sort value - bool skip = r_debugSort->integer && tess.surfaceShader != nullptr - && r_debugSort->integer < tess.surfaceShader->sort; + bool skip = r_debugSort.Get() && tess.surfaceShader != nullptr + && r_debugSort.Get() < tess.surfaceShader->sort; if ( !skip ) { // update performance counter @@ -2985,7 +2943,7 @@ void Tess_End() tess.stageIteratorFunc != Tess_StageIteratorDummy ) { // draw debugging stuff - if ( r_showTris->integer || r_showBatches->integer || ( r_showLightBatches->integer && ( tess.stageIteratorFunc == Tess_StageIteratorLighting ) ) ) + if ( r_showTris.Get() || r_showBatches.Get() || ( r_showLightBatches.Get() && ( tess.stageIteratorFunc == Tess_StageIteratorLighting ) ) ) { // Skybox triangle rendering is done in Tess_StageIteratorSky() if ( tess.stageIteratorFunc != Tess_StageIteratorSky ) { diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 77b52a80ce..efac6283ba 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -1426,7 +1426,7 @@ static bool LoadMap( shaderStage_t *stage, const char *buffer, stageType_t type, || ( type == stageType_t::ST_HEIGHTMAP && !glConfig2.reliefMapping ) || ( type == stageType_t::ST_SPECULARMAP && !glConfig2.specularMapping ) || ( type == stageType_t::ST_PHYSICALMAP && !glConfig2.physicalMapping ) - || ( type == stageType_t::ST_GLOWMAP && !r_glowMapping->integer ) + || ( type == stageType_t::ST_GLOWMAP && !r_glowMapping.Get() ) || ( type == stageType_t::ST_REFLECTIONMAP && !glConfig2.reflectionMappingAvailable ) ) { return true; @@ -1463,7 +1463,7 @@ static bool LoadMap( shaderStage_t *stage, const char *buffer, stageType_t type, So we don't load extra light maps when light styles are not supported. The disablement of the stage is done in the ParseShader() function. */ - if ( ( tr.lightMode != lightMode_t::MAP || r_lightStyles->integer == 0 ) + if ( ( tr.lightMode != lightMode_t::MAP || !r_lightStyles.Get() ) && stage->tcGen_Lightmap ) { /* We don't return false because we properly parsed the stage @@ -1608,7 +1608,7 @@ static void ParseNormalMap( shaderStage_t *stage, const char **text, const int b char buffer[ 1024 ] = ""; // because of collapsing, this affects other textures (diffuse, specular…) too - if ( r_highQualityNormalMapping->integer ) + if ( r_highQualityNormalMapping.Get() ) { stage->overrideFilterType = true; stage->filterType = filterType_t::FT_LINEAR; @@ -4023,7 +4023,7 @@ static bool ParseShader( const char *_text ) So we disable light style stages when light mapping is disabled. */ - if ( tr.lightMode != lightMode_t::MAP || r_lightStyles->integer == 0 ) + if ( tr.lightMode != lightMode_t::MAP || !r_lightStyles.Get() ) { switch ( stage->type ) { @@ -5189,7 +5189,7 @@ static void FinishStages() { shaderStage_t *stage = &stages[ s ]; - if ( r_showLightMaps->integer && lightStageFound ) + if ( r_showLightMaps.Get() && lightStageFound ) { stage->active = false; continue; @@ -5204,11 +5204,11 @@ static void FinishStages() break; case stageType_t::ST_HEATHAZEMAP: - stage->active = r_heatHaze->integer; + stage->active = r_heatHaze.Get(); break; case stageType_t::ST_LIQUIDMAP: - if ( !r_liquidMapping->integer ) + if ( !r_liquidMapping.Get() ) { stage->type = stageType_t::ST_COLLAPSE_DIFFUSEMAP; stage->bundle[ TB_DIFFUSEMAP ].image[ 0 ] = tr.whiteImage; @@ -5239,6 +5239,8 @@ static void FinishStages() default: break; } + + memset( stage->variantOffsets, -1, ShaderStageVariant::ALL * sizeof( int ) ); } GroupActiveStages(); @@ -5269,7 +5271,7 @@ static void FinishStages() stage->enableReliefMapping = glConfig2.reliefMapping && !shader.disableReliefMapping && ( hasHeightMap || stage->hasHeightMapInNormalMap ); - stage->enableGlowMapping = r_glowMapping->integer && hasGlowMap; + stage->enableGlowMapping = r_glowMapping.Get() && hasGlowMap; if ( stage->collapseType == collapseType_t::COLLAPSE_PBR ) { @@ -5372,7 +5374,7 @@ static void SetStagesRenderers() stageRenderer_t colorRenderer; // Material renderer (code path for advanced OpenGL techniques like bindless textures). - stageSurfaceDataUpdater_t surfaceDataUpdater; + surfaceDataUpdater_t surfaceDataUpdater; stageShaderBinder_t shaderBinder; stageMaterialProcessor_t materialProcessor; @@ -5591,6 +5593,8 @@ static shader_t *MakeShaderPermanent() std::copy_n( stages[ s ].bundle[ b ].texMods, newShader->stages[ s ].bundle[ b ].numTexMods, newShader->stages[ s ].bundle[ b ].texMods ); } + + newShader->stages[ s ].shader = newShader; } newShader->lastStage = newShader->stages + numStages; @@ -6329,7 +6333,7 @@ shader_t *R_FindShader( const char *name, shaderType_t type, int flags ) // make sure the render thread is stopped, because we are probably // going to have to upload an image - if ( r_smp->integer ) + if ( r_smp.Get() ) { R_SyncRenderThread(); } @@ -6378,7 +6382,7 @@ shader_t *R_FindShader( const char *name, shaderType_t type, int flags ) { // enable this when building a pak file to get a global list // of all explicit shaders - if ( r_printShaders->integer ) + if ( r_printShaders.Get() ) { Log::Notice("loading explicit shader '%s'", strippedName ); } @@ -6541,7 +6545,7 @@ qhandle_t RE_RegisterShaderFromImage( const char *name, image_t *image ) // make sure the render thread is stopped, because we are probably // going to have to upload an image - if ( r_smp->integer ) + if ( r_smp.Get() ) { R_SyncRenderThread(); } diff --git a/src/engine/renderer/tr_sky.cpp b/src/engine/renderer/tr_sky.cpp index de1c39eb4f..21021d398b 100644 --- a/src/engine/renderer/tr_sky.cpp +++ b/src/engine/renderer/tr_sky.cpp @@ -81,7 +81,7 @@ void Tess_StageIteratorSky() GL_Cull(cullType_t::CT_BACK_SIDED); // r_showSky will draw the whole skybox in front of everything else - if ( r_showSky->integer ) + if ( r_showSky.Get() ) { glDepthRange( 0.0, 0.0 ); } @@ -123,7 +123,7 @@ void Tess_StageIteratorSky() Tess_DrawElements(); } - if ( r_showTris->integer ) { + if ( r_showTris.Get() ) { GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ); // bind u_ColorMap diff --git a/src/engine/renderer/tr_surface.cpp b/src/engine/renderer/tr_surface.cpp index 7540948fb2..eda718fbe5 100644 --- a/src/engine/renderer/tr_surface.cpp +++ b/src/engine/renderer/tr_surface.cpp @@ -748,7 +748,7 @@ static void Tess_SurfaceFace( srfSurfaceFace_t *srf ) { GLimp_LogComment( "--- Tess_SurfaceFace ---\n" ); - if ( !r_vboFaces->integer || !Tess_SurfaceVBO( srf->vbo, srf->ibo, srf->numTriangles * 3, srf->firstIndex ) ) + if ( !r_vboFaces.Get() || !Tess_SurfaceVBO(srf->vbo, srf->ibo, srf->numTriangles * 3, srf->firstIndex) ) { Tess_SurfaceVertsAndTris( srf->verts, srf->triangles, srf->numVerts, srf->numTriangles ); } @@ -763,7 +763,7 @@ static void Tess_SurfaceGrid( srfGridMesh_t *srf ) { GLimp_LogComment( "--- Tess_SurfaceGrid ---\n" ); - if ( !r_vboCurves->integer || !Tess_SurfaceVBO( srf->vbo, srf->ibo, srf->numTriangles * 3, srf->firstIndex ) ) + if ( !r_vboCurves.Get() || !Tess_SurfaceVBO( srf->vbo, srf->ibo, srf->numTriangles * 3, srf->firstIndex ) ) { Tess_SurfaceVertsAndTris( srf->verts, srf->triangles, srf->numVerts, srf->numTriangles ); } @@ -778,7 +778,7 @@ static void Tess_SurfaceTriangles( srfTriangles_t *srf ) { GLimp_LogComment( "--- Tess_SurfaceTriangles ---\n" ); - if ( !r_vboTriangles->integer || !Tess_SurfaceVBO( srf->vbo, srf->ibo, srf->numTriangles * 3, srf->firstIndex ) ) + if ( !r_vboTriangles.Get() || !Tess_SurfaceVBO( srf->vbo, srf->ibo, srf->numTriangles * 3, srf->firstIndex ) ) { Tess_SurfaceVertsAndTris( srf->verts, srf->triangles, srf->numVerts, srf->numTriangles ); } diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index e00a2cd016..48740e47da 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -138,7 +138,7 @@ enum class refEntityType_t // RB: having bone names for each refEntity_t takes several MiBs // in backEndData_t so only use it for debugging and development -// enabling this will show the bone names with r_showSkeleton 1 +// enabling this will show the bone names with r_showSkeleton on struct refBone_t { diff --git a/src/engine/renderer/tr_vbo.cpp b/src/engine/renderer/tr_vbo.cpp index 37c95d6285..b7cb12b398 100644 --- a/src/engine/renderer/tr_vbo.cpp +++ b/src/engine/renderer/tr_vbo.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_vbo.c #include "tr_local.h" #include "Material.h" +#include "GeometryCache.h" // interleaved data: position, colour, qtangent, texcoord // -> struct shaderVertex_t in tr_local.h @@ -74,7 +75,7 @@ static void R_SetVBOAttributeLayouts( VBO_t *vbo ) } } -static uint32_t ComponentSize( GLenum type ) +uint32_t ComponentSize( GLenum type ) { switch ( type ) { @@ -208,7 +209,7 @@ VBO_t *R_CreateDynamicVBO( const char *name, int numVertexes, uint32_t stateBits return vbo; } -static void CopyVertexAttribute( +void CopyVertexAttribute( const vboAttributeLayout_t &attrib, const vertexAttributeSpec_t &spec, uint32_t count, byte *interleavedData ) { @@ -726,25 +727,6 @@ static void R_InitLightUBO() glBindBuffer( GL_UNIFORM_BUFFER, 0 ); } } - -static void R_InitMaterialBuffers() { - if( glConfig2.usingMaterialSystem ) { - materialsSSBO.GenBuffer(); - - surfaceDescriptorsSSBO.GenBuffer(); - surfaceCommandsSSBO.GenBuffer(); - culledCommandsBuffer.GenBuffer(); - surfaceBatchesUBO.GenBuffer(); - atomicCommandCountersBuffer.GenBuffer(); - - portalSurfacesSSBO.GenBuffer(); - - if ( r_materialDebug.Get() ) { - debugSSBO.GenBuffer(); - } - } -} - /* ============ R_InitVBOs @@ -788,7 +770,13 @@ void R_InitVBOs() R_InitLightUBO(); - R_InitMaterialBuffers(); + if ( glConfig2.usingMaterialSystem ) { + materialSystem.InitGLBuffers(); + } + + if ( glConfig2.usingGeometryCache ) { + geometryCache.InitGLBuffers(); + } GL_CheckErrors(); } @@ -859,19 +847,11 @@ void R_ShutdownVBOs() } if ( glConfig2.usingMaterialSystem ) { - materialsSSBO.DelBuffer(); - - surfaceDescriptorsSSBO.DelBuffer(); - surfaceCommandsSSBO.DelBuffer(); - culledCommandsBuffer.DelBuffer(); - surfaceBatchesUBO.DelBuffer(); - atomicCommandCountersBuffer.DelBuffer(); - - portalSurfacesSSBO.DelBuffer(); + materialSystem.FreeGLBuffers(); + } - if ( r_materialDebug.Get() ) { - debugSSBO.DelBuffer(); - } + if ( glConfig2.usingGeometryCache ) { + geometryCache.FreeGLBuffers(); } tess.verts = tess.vertsBuffer = nullptr; diff --git a/src/engine/renderer/tr_world.cpp b/src/engine/renderer/tr_world.cpp index 4ca207aec0..5bc2d7baac 100644 --- a/src/engine/renderer/tr_world.cpp +++ b/src/engine/renderer/tr_world.cpp @@ -45,13 +45,13 @@ static bool R_CullSurface( surfaceType_t *surface, shader_t *shader, int planeBi float d; // allow culling to be disabled - if ( r_nocull->integer ) + if ( r_nocull.Get() ) { return false; } // ydnar: made surface culling generic, inline with q3map2 surface classification - if ( *surface == surfaceType_t::SF_GRID && r_nocurves->integer ) + if ( *surface == surfaceType_t::SF_GRID && r_nocurves.Get() ) { return true; } @@ -65,7 +65,7 @@ static bool R_CullSurface( surfaceType_t *surface, shader_t *shader, int planeBi gen = ( srfGeneric_t * ) surface; // plane cull - if ( *surface == surfaceType_t::SF_FACE && r_facePlaneCull->integer ) + if ( *surface == surfaceType_t::SF_FACE && r_facePlaneCull.Get() ) { srfSurfaceFace_t *srf = ( srfSurfaceFace_t * )gen; d = DotProduct( tr.orientation.viewOrigin, srf->plane.normal ) - srf->plane.dist; @@ -131,13 +131,13 @@ static bool R_CullLightSurface( surfaceType_t *surface, shader_t *shader, trRefL float d; // allow culling to be disabled - if ( r_nocull->integer ) + if ( r_nocull.Get() ) { return false; } // ydnar: made surface culling generic, inline with q3map2 surface classification - if ( *surface == surfaceType_t::SF_GRID && r_nocurves->integer ) + if ( *surface == surfaceType_t::SF_GRID && r_nocurves.Get() ) { return true; } @@ -165,7 +165,7 @@ static bool R_CullLightSurface( surfaceType_t *surface, shader_t *shader, trRefL } // plane cull - if ( *surface == surfaceType_t::SF_FACE && r_facePlaneCull->integer ) + if ( *surface == surfaceType_t::SF_FACE && r_facePlaneCull.Get() ) { srfSurfaceFace_t *srf = ( srfSurfaceFace_t * )gen; if ( light->l.rlType == refLightType_t::RL_DIRECTIONAL ) @@ -418,7 +418,7 @@ static void R_RecursiveWorldNode( bspNode_t *node, int planeBits ) // if the bounding volume is outside the frustum, nothing // inside can be visible - if ( !r_nocull->integer ) + if ( !r_nocull.Get() ) { int i; int r; @@ -492,7 +492,7 @@ static void R_RecursiveInteractionNode( bspNode_t *node, trRefLight_t *light, in // Tr3B - even surfaces that belong to nodes that are outside of the view frustum // can cast shadows into the view frustum - if ( !r_nocull->integer ) + if ( !r_nocull.Get() ) { for ( i = 0; i < FRUSTUM_PLANES; i++ ) { @@ -704,7 +704,7 @@ static void R_MarkLeaves() // lockpvs lets designers walk around to determine the // extent of the current pvs - if ( r_lockpvs->integer ) + if ( r_lockpvs.Get() ) { return; } @@ -750,7 +750,7 @@ static void R_MarkLeaves() Log::Notice("update cluster:%i area:%i index:%i", cluster, leaf->area, tr.visIndex ); } - if ( r_novis->integer || tr.visClusters[ tr.visIndex ] == -1 ) + if ( r_novis.Get() || tr.visClusters[tr.visIndex] == -1 ) { for ( i = 0; i < tr.world->numnodes; i++ ) { @@ -831,7 +831,7 @@ R_AddWorldSurfaces */ void R_AddWorldSurfaces() { - if ( !r_drawworld->integer ) + if ( !r_drawworld.Get() ) { return; } @@ -879,7 +879,7 @@ void R_AddWorldInteractions( trRefLight_t *light ) { int interactionBits; - if ( !r_drawworld->integer ) + if ( !r_drawworld.Get() ) { return; } diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index 36519fccd3..e2a208aa09 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -41,6 +41,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static Log::Logger logger("glconfig", "", Log::Level::NOTICE); +static Cvar::Range> r_glMajorVersion( "r_glMajorVersion", + "Force this GL major version; 0 to set up automatically", Cvar::NONE, 0, 0, 4 ); +static Cvar::Range> r_glMinorVersion( "r_glMinorVersion", + "Force this GL minor version; 0 to set up automatically", Cvar::NONE, 0, 0, 6 ); +static Cvar::Cvar r_glProfile( "r_glProfile", + "Force this GL profile (core or compat); empty to set up automatically", Cvar::NONE, "" ); +static Cvar::Cvar r_glAllowSoftware( "r_glAllowSoftware", "Allow software rendering", Cvar::NONE, false ); + static Cvar::Modified> r_noBorder( "r_noBorder", "draw window without border", Cvar::ARCHIVE, false); static Cvar::Modified>> r_swapInterval( @@ -70,6 +78,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", @@ -106,6 +116,8 @@ static Cvar::Cvar r_arb_texture_gather( "r_arb_texture_gather", "Use GL_ARB_texture_gather if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_uniform_buffer_object( "r_arb_uniform_buffer_object", "Use GL_ARB_uniform_buffer_object if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_vertex_attrib_binding( "r_arb_vertex_attrib_binding", + "Use GL_ARB_vertex_attrib_binding if available", Cvar::NONE, true ); static Cvar::Cvar r_ext_draw_buffers( "r_ext_draw_buffers", "Use GL_EXT_draw_buffers if available", Cvar::NONE, true ); static Cvar::Cvar r_ext_gpu_shader4( "r_ext_gpu_shader4", @@ -766,7 +778,8 @@ static void GLimp_SetAttributes( const glConfiguration &configuration ) SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 0 ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); - if ( !r_glAllowSoftware->integer ) + Cvar::Latch( r_glAllowSoftware ); + if ( !r_glAllowSoftware.Get() ) { SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ); } @@ -1120,9 +1133,9 @@ static rserr_t GLimp_ValidateBestContext( { 1, 0, glProfile::COMPATIBILITY, true }, }; - logger.Debug( "Validating best OpenGL context." ); + logger.Debug( "Validating best OpenGL context" ); - bool needHighestExtended = !!r_glExtendedValidation->integer; + bool needHighestExtended = r_glExtendedValidation.Get(); for ( int colorBits : {24, 16} ) { for ( auto& row : glSupportArray ) @@ -1178,14 +1191,16 @@ static glConfiguration GLimp_ApplyCustomOptions( const int GLEWmajor, const glCo { glConfiguration customConfiguration = {}; - if ( bestConfiguration.profile == glProfile::CORE && !Q_stricmp( r_glProfile->string, "compat" ) ) + Cvar::Latch( r_glProfile ); + const std::string glProfile = r_glProfile.Get(); + if ( bestConfiguration.profile == glProfile::CORE && !Q_stricmp( glProfile.c_str(), "compat") ) { logger.Debug( "Compatibility profile is forced by r_glProfile" ); customConfiguration.profile = glProfile::COMPATIBILITY; } - if ( bestConfiguration.profile == glProfile::COMPATIBILITY && !Q_stricmp( r_glProfile->string, "core" ) ) + if ( bestConfiguration.profile == glProfile::COMPATIBILITY && !Q_stricmp( glProfile.c_str(), "core" ) ) { if ( GLEWmajor < 2 ) { @@ -1200,8 +1215,10 @@ static glConfiguration GLimp_ApplyCustomOptions( const int GLEWmajor, const glCo } } - customConfiguration.major = std::max( 0, r_glMajorVersion->integer ); - customConfiguration.minor = std::max( 0, r_glMinorVersion->integer ); + Cvar::Latch( r_glMajorVersion ); + Cvar::Latch( r_glMinorVersion ); + customConfiguration.major = std::max( 0, r_glMajorVersion.Get() ); + customConfiguration.minor = std::max( 0, r_glMinorVersion.Get() ); if ( customConfiguration.major == 0 ) { @@ -1252,7 +1269,7 @@ static glConfiguration GLimp_ApplyCustomOptions( const int GLEWmajor, const glCo customConfiguration.profile = bestConfiguration.profile; } - customConfiguration.colorBits = std::max( 0, r_colorbits->integer ); + customConfiguration.colorBits = std::max( 0, r_colorbits.Get() ); if ( customConfiguration.colorBits == 0 ) { @@ -1594,11 +1611,11 @@ static rserr_t GLimp_SetMode( const int mode, const bool fullscreen, const bool static glConfiguration bestValidatedConfiguration = {}; // considering only up to OpenGL 3.2 static glConfiguration extendedValidationResult = {}; // max available OpenGL version for diagnostic purposes - if ( r_glExtendedValidation->integer && extendedValidationResult.major != 0 ) + if ( r_glExtendedValidation.Get() && extendedValidationResult.major != 0 ) { logger.Debug( "Previously best validated context: %s", ContextDescription( extendedValidationResult ) ); } - else if ( bestValidatedConfiguration.major == 0 || r_glExtendedValidation->integer ) + else if ( bestValidatedConfiguration.major == 0 || r_glExtendedValidation.Get() ) { // Detect best configuration. rserr_t err = GLimp_ValidateBestContext( GLEWmajor, bestValidatedConfiguration, extendedValidationResult ); @@ -1617,7 +1634,7 @@ static rserr_t GLimp_SetMode( const int mode, const bool fullscreen, const bool } } - if ( r_glExtendedValidation->integer ) + if ( r_glExtendedValidation.Get() ) { logger.Notice( "Highest available context: %s", ContextDescription( extendedValidationResult ) ); } @@ -1975,6 +1992,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 ); @@ -1993,6 +2011,7 @@ static void GLimp_InitExtensions() Cvar::Latch( r_arb_sync ); Cvar::Latch( r_arb_texture_gather ); Cvar::Latch( r_arb_uniform_buffer_object ); + Cvar::Latch( r_arb_vertex_attrib_binding ); Cvar::Latch( r_ext_draw_buffers ); Cvar::Latch( r_ext_gpu_shader4 ); Cvar::Latch( r_ext_texture_filter_anisotropic ); @@ -2013,12 +2032,13 @@ static void GLimp_InitExtensions() } // Shader limits + glGetIntegerv( GL_MAX_UNIFORM_BLOCK_SIZE, &glConfig2.maxUniformBlockSize ); glGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig2.maxVertexUniforms ); glGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig2.maxVertexAttribs ); int reservedComponents = 36 * 10; // approximation how many uniforms we have besides the bone matrices glConfig2.maxVertexSkinningBones = Math::Clamp( ( glConfig2.maxVertexUniforms - reservedComponents ) / 16, 0, MAX_BONES ); - glConfig2.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ( ( glConfig2.maxVertexSkinningBones >= 12 ) ? true : false ); + glConfig2.vboVertexSkinningAvailable = r_vboVertexSkinning.Get() && ( ( glConfig2.maxVertexSkinningBones >= 12 ) ? true : false ); /* On OpenGL Core profile the ARB_fragment_program extension doesn't exist and the related getter functions return 0. We can assume OpenGL 3 Core hardware is featureful enough to not care about those limits. */ @@ -2543,11 +2563,21 @@ 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() ); + + // made required in OpenGL 4.3 + glConfig2.vertexAttribBindingAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_vertex_attrib_binding, r_arb_vertex_attrib_binding.Get() ); + + glConfig2.geometryCacheAvailable = glConfig2.vertexAttribBindingAvailable && glConfig2.directStateAccessAvailable; + 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 + && glConfig2.geometryCacheAvailable; // This requires GLEW 2.2+, so skip if it's a lower version #ifdef GL_KHR_shader_subgroup @@ -2713,7 +2743,7 @@ bool GLimp_Init() Sys::SetEnv( "stub_occlusion_query", "true" ); } - int mode = r_mode->integer; + int mode = r_mode.Get(); bool fullscreen = r_fullscreen.Get(); bool bordered = !r_noBorder.Get(); @@ -2890,7 +2920,7 @@ Responsible for doing a swapbuffers void GLimp_EndFrame() { // don't flip if drawing to front buffer - if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 ) + if ( Q_stricmp( r_drawBuffer.Get().c_str(), "GL_FRONT" ) != 0 ) { SDL_GL_SwapWindow( window ); }