diff --git a/src/engine/qcommon/q_shared.h b/src/engine/qcommon/q_shared.h index bb3770cd79..f2d6d6694b 100644 --- a/src/engine/qcommon/q_shared.h +++ b/src/engine/qcommon/q_shared.h @@ -458,6 +458,12 @@ inline void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) cross[ 2 ] = v1[ 0 ] * v2[ 1 ] - v1[ 1 ] * v2[ 0 ]; } +template +A Square( A a ) +{ + return a * a; +} + template void VectorSubtract( const A &a, const B &b, C &&c ) { @@ -2221,8 +2227,6 @@ struct fontInfo_t char name[ MAX_QPATH ]; }; -#define Square( x ) ( ( x ) * ( x ) ) - // real time //============================================= diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index 1070522b60..c9ca0af2db 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -37,7 +37,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Material.h" #include "ShadeCommon.h" -GLSSBO materialsSSBO( "materials", 0, GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); +GLUBO materialsUBO( "materials", 6, GL_MAP_WRITE_BIT, GL_MAP_INVALIDATE_RANGE_BIT ); +GLBuffer texDataBuffer( "texData", 7, GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); +GLUBO lightMapDataUBO( "lightMapData", 8, GL_MAP_WRITE_BIT, GL_MAP_FLUSH_EXPLICIT_BIT ); 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 ); @@ -114,69 +116,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 +126,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; - - bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; - if ( !updated ) { - return; - } - drawSurf->initialized[stage] = true; +void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, bool mayUseVertexOverbright, bool, bool ) { + // shader_t* shader = pStage->shader; - gl_genericShaderMaterial->BindProgram( material.deformIndex ); + materials += pStage->bufferOffset; // u_AlphaThreshold gl_genericShaderMaterial->SetUniform_AlphaTest( pStage->stateBits ); @@ -222,25 +151,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 +165,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]; - - 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 ); +void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, bool, bool vertexLit, bool fullbright ) { + shader_t* shader = pStage->shader; - 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 +176,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 +190,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 ); 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,13 +207,6 @@ 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 ); @@ -349,47 +214,13 @@ void UpdateSurfaceDataLightMapping( uint32_t* materials, Material& material, dra 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]; - - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; +void UpdateSurfaceDataReflection( 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; - - // 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 +246,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 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 +269,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]; +void UpdateSurfaceDataScreen( 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; - - 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]; - - const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); - materials += paddedOffset; +void UpdateSurfaceDataHeatHaze( 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; + 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 +301,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; @@ -563,16 +339,8 @@ void UpdateSurfaceDataLiquid( uint32_t* materials, Material& material, drawSurf_ 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 +353,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; +void UpdateSurfaceDataFog( 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; - - const fog_t* fog = material.fog; - - // u_Color - gl_fogQuake3ShaderMaterial->SetUniform_Color( fog->color ); + materials += pStage->bufferOffset; gl_fogQuake3ShaderMaterial->WriteUniformsToBuffer( materials ); } @@ -609,30 +364,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 +387,156 @@ void UpdateSurfaceDataFog( uint32_t* materials, Material& material, drawSurf_t* void MaterialSystem::GenerateWorldMaterialsBuffer() { Log::Debug( "Generating materials buffer" ); - uint32_t offset = 0; + materialsUBO.BindBuffer(); - materialsSSBO.BindBuffer(); + // 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; + } - // 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 ); + if ( !rhs->dynamic && lhs->dynamic ) { + return false; + } - offset += padding; - material.staticMaterialsSSBOOffset = offset; - offset += paddedSize * material.totalStaticDrawSurfCount; - } - } + return lhs->paddedSize < rhs->paddedSize; + } ); - bool dynamicDrawSurfOffsetSet = false; + uint32_t offset = 0; + dynamicStagesOffset = 0; + bool dynamicStagesOffsetSet = false; - // 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; - } + // 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 ); - material.dynamicMaterialsSSBOOffset = offset; - offset += paddedSize * material.totalDynamicDrawSurfCount; + offset += padding; + + // 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 ) ); + glBufferData( GL_UNIFORM_BUFFER, offset * sizeof( uint32_t ), 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++; } } } +} - materialsSSBO.UnmapBuffer(); +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; + } + + 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,8 +565,6 @@ void MaterialSystem::GenerateWorldCommandBuffer() { Log::Debug( "Total batch count: %u", totalBatchCount ); - drawSurf_t* drawSurf; - surfaceDescriptorsSSBO.BindBuffer(); surfaceDescriptorsCount = totalDrawSurfs; descriptorSize = BOUNDING_SPHERE_SIZE + maxStages; @@ -798,6 +572,69 @@ void MaterialSystem::GenerateWorldCommandBuffer() { nullptr, GL_STATIC_DRAW ); uint32_t* surfaceDescriptors = surfaceDescriptorsSSBO.MapBufferRange( surfaceDescriptorsCount * descriptorSize ); + texDataBufferType = glConfig2.maxUniformBlockSize >= MIN_MATERIAL_UBO_SIZE ? GL_UNIFORM_BUFFER : GL_SHADER_STORAGE_BUFFER; + + texDataBuffer.BindBuffer( texDataBufferType ); + texDataBuffer.BufferStorage( texDataBufferType, ( texData.size() + dynamicTexData.size() ) * TEX_BUNDLE_SIZE, 1, nullptr ); + texDataBuffer.MapAll( texDataBufferType ); + 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( texDataBufferType ); + texDataBuffer.UnmapBuffer(); + texDataBuffer.UnBindBuffer( texDataBufferType ); + + lightMapDataUBO.BindBuffer(); + lightMapDataUBO.BufferStorage( MAX_LIGHTMAPS * LIGHTMAP_SIZE, 1, nullptr ); + lightMapDataUBO.MapAll(); + uint64_t* lightmapData = ( uint64_t* ) lightMapDataUBO.GetData(); + memset( lightmapData, 0, MAX_LIGHTMAPS * LIGHTMAP_SIZE * sizeof( uint32_t ) ); + + 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(); + lightMapDataUBO.UnBindBuffer(); + surfaceCommandsCount = totalBatchCount * SURFACE_COMMANDS_PER_BATCH; surfaceCommandsSSBO.BindBuffer(); @@ -858,7 +695,8 @@ void MaterialSystem::GenerateWorldCommandBuffer() { } 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 +729,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 +738,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 +755,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 +766,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; @@ -1230,6 +1078,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] ); @@ -1392,8 +1242,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; @@ -1426,14 +1390,9 @@ void MaterialSystem::ProcessStage( drawSurf_t* drawSurf, shaderStage_t* pStage, 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 +1421,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,6 +1443,8 @@ 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() { + R_SyncRenderThread(); + const int current_r_nocull = r_nocull->integer; const int current_r_drawworld = r_drawworld->integer; r_nocull->integer = 1; @@ -1494,8 +1453,6 @@ void MaterialSystem::GenerateWorldMaterials() { Log::Debug( "Generating world materials" ); - R_SyncRenderThread(); - ++tr.viewCountNoReset; R_AddWorldSurfaces(); @@ -1506,13 +1463,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; } @@ -1537,7 +1493,7 @@ void MaterialSystem::GenerateWorldMaterials() { 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,14 +1512,17 @@ 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 ); } } */ @@ -1582,8 +1541,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 +1560,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 +1582,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,25 +1606,26 @@ 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 ) { + materialsUBO.BindBuffer(); + 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 ) { + texDataBuffer.BindBuffer( texDataBufferType ); + GL_CheckErrors(); + TexBundle* textureBundles = + ( TexBundle* ) texDataBuffer.MapBufferRange( texDataBufferType, dynamicTexDataOffset, dynamicTexDataSize ); + GL_CheckErrors(); - pStage->surfaceDataUpdater( materialsData, material, &drawSurf, stage ); + GenerateTexturesBuffer( dynamicTexData, textureBundles ); - stage++; - } + texDataBuffer.UnmapBuffer(); } - materialsSSBO.UnmapBuffer(); } void MaterialSystem::UpdateFrameData() { @@ -1890,19 +1879,24 @@ void MaterialSystem::GeneratePortalBoundingSpheres() { 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(); @@ -2064,7 +2058,7 @@ void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderS frameStart = false; } - materialsSSBO.BindBufferBase(); + materialsUBO.BindBufferBase(); for ( MaterialPack& materialPack : materialPacks ) { if ( materialPack.fromSort >= fromSort && materialPack.toSort <= toSort ) { @@ -2206,6 +2200,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; @@ -2320,6 +2317,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..1265541fb5 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -70,14 +70,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; @@ -143,6 +135,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 +223,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 @@ -276,7 +332,9 @@ class MaterialSystem { void GenerateDepthImages( const int width, const int height, imageParams_t imageParms ); - void AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pStage, Material* material ); + 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 +342,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 +369,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 +393,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 +408,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 +434,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..785662be76 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -1359,9 +1359,45 @@ 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 = 6) uniform materialsUBO {\n" + " Material materials[" + std::to_string( count ) + "]; \n" + "};\n\n"; + + std::string texBuf = glConfig2.maxUniformBlockSize >= MIN_MATERIAL_UBO_SIZE ? + "layout(std140, binding = 7) uniform texDataUBO {\n" + " TexData texData[" + std::to_string( MAX_TEX_BUNDLES ) + "]; \n" + "};\n\n" + : "layout(std430, binding = 7) 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 = 8) 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 +1416,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 +1444,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 +1456,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 +1494,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 +2015,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 +2025,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 +2035,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 +2054,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,7 +2213,7 @@ 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 ); } } @@ -2676,7 +2711,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 +2733,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..73dad8d783 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: @@ -1531,6 +1574,10 @@ class GLUBO : public GLBuffer { GLBuffer::BindBuffer( GL_UNIFORM_BUFFER ); } + void UnBindBuffer() { + GLBuffer::UnBindBuffer( GL_UNIFORM_BUFFER ); + } + void BufferStorage( const GLsizeiptr areaSize, const GLsizeiptr areaCount, const void* data ) { GLBuffer::BufferStorage( GL_UNIFORM_BUFFER, areaSize, areaCount, data ); } @@ -2140,6 +2187,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 +2316,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 +2332,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 +2745,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 +3155,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: @@ -4319,7 +4388,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 +4408,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/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..09042277f4 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; @@ -92,9 +95,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/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_backend.cpp b/src/engine/renderer/tr_backend.cpp index e3cd626597..c8e1efe9d3 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -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; @@ -830,9 +830,6 @@ static void RB_SetGL2D() GL_LoadProjectionMatrix( proj ); GL_LoadModelViewMatrix( matrixIdentity ); - // TODO: remove this, state is set wherever drawing is done - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - GL_Cull( cullType_t::CT_TWO_SIDED ); // set time for 2D shaders diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 7256e047df..8ccb74c662 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; @@ -3191,7 +3248,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 ); diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index 526b80ebba..6d795a3f93 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; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index a0d1a50ae1..b54d333563 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -818,11 +818,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; @@ -929,7 +924,10 @@ void Render_generic( shaderStage_t *pStage ) { if ( backEnd.projection2D ) { - glState.glStateBitsMask = ~uint32_t( GLS_DEPTHMASK_TRUE ) | GLS_DEPTHTEST_DISABLE; + constexpr uint32_t lockBits = GLS_DEPTHMASK_TRUE | GLS_DEPTHTEST_DISABLE; + glState.glStateBitsMask = ~lockBits; + GL_State( GLS_DEPTHTEST_DISABLE ); + glState.glStateBitsMask = lockBits; tr.skipSubgroupProfiler = true; Render_generic3D( pStage ); @@ -946,11 +944,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 ); @@ -1235,10 +1228,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 ); @@ -1869,11 +1858,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 ---------------------------------- @@ -1965,11 +1949,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 ); @@ -1995,11 +1974,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 ); @@ -2055,11 +2029,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; @@ -2148,11 +2117,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 ) ); @@ -2247,11 +2211,6 @@ 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 ) ) { return; @@ -2314,7 +2273,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 ] ); @@ -2695,7 +2654,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]; } diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 77b52a80ce..4f6ea8e370 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -5239,6 +5239,8 @@ static void FinishStages() default: break; } + + memset( stage->variantOffsets, -1, ShaderStageVariant::ALL * sizeof( int ) ); } GroupActiveStages(); @@ -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; diff --git a/src/engine/renderer/tr_vbo.cpp b/src/engine/renderer/tr_vbo.cpp index 37c95d6285..e453a62d7e 100644 --- a/src/engine/renderer/tr_vbo.cpp +++ b/src/engine/renderer/tr_vbo.cpp @@ -729,7 +729,9 @@ static void R_InitLightUBO() static void R_InitMaterialBuffers() { if( glConfig2.usingMaterialSystem ) { - materialsSSBO.GenBuffer(); + materialsUBO.GenBuffer(); + texDataBuffer.GenBuffer(); + lightMapDataUBO.GenBuffer(); surfaceDescriptorsSSBO.GenBuffer(); surfaceCommandsSSBO.GenBuffer(); @@ -859,7 +861,9 @@ void R_ShutdownVBOs() } if ( glConfig2.usingMaterialSystem ) { - materialsSSBO.DelBuffer(); + materialsUBO.DelBuffer(); + texDataBuffer.DelBuffer(); + lightMapDataUBO.DelBuffer(); surfaceDescriptorsSSBO.DelBuffer(); surfaceCommandsSSBO.DelBuffer(); diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index 36519fccd3..a6cf29903a 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -2013,6 +2013,7 @@ 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 );