diff --git a/src/engine/renderer/GeometryOptimiser.cpp b/src/engine/renderer/GeometryOptimiser.cpp index 731af91bb0..0f79ee8cb8 100644 --- a/src/engine/renderer/GeometryOptimiser.cpp +++ b/src/engine/renderer/GeometryOptimiser.cpp @@ -315,13 +315,13 @@ void MergeDuplicateVertices( bspSurface_t** rendererSurfaces, int numSurfaces, s srfVert_t& vert = face->verts[triangle->indexes[j]]; uint32_t index = verts[vert]; - ASSERT_LT( idx, ( uint32_t ) numIndicesIn ); + ASSERT_LT( idx, numIndicesIn ); if ( !index ) { verts[vert] = vertIdx + 1; vertices[vertIdx] = vert; indices[idx] = vertIdx; - ASSERT_LT( vertIdx, ( uint32_t ) numVerticesIn ); + ASSERT_LT( vertIdx, numVerticesIn ); vertIdx++; } else { @@ -356,7 +356,7 @@ void MergeDuplicateVertices( bspSurface_t** rendererSurfaces, int numSurfaces, s } } */ -std::vector OptimiseMapGeometryMaterial(bspSurface_t** rendererSurfaces, int numSurfaces ) { +std::vector OptimiseMapGeometryMaterial( world_t* world, int numSurfaces ) { std::vector materialSurfaces; materialSurfaces.reserve( numSurfaces ); @@ -365,43 +365,24 @@ std::vector OptimiseMapGeometryMaterial(bspSurface_t** renderer // std::unordered_map triEdges; - vec3_t worldBounds[2] = {}; - for ( int i = 0; i < numSurfaces; i++ ) { - bspSurface_t* surface = rendererSurfaces[i]; - - if ( surface->BSPModel ) { - // Not implemented yet - continue; - } + int surfaceIndex = 0; + for ( int k = 0; k < world->numSurfaces; k++ ) { + bspSurface_t* surface = &world->surfaces[k]; MaterialSurface srf {}; srf.shader = surface->shader; srf.bspSurface = true; - srf.lightMapNum = surface->lightmapNum; srf.fog = surface->fogIndex; - srf.portalNum = surface->portalNum; srf.firstIndex = ( ( srfGeneric_t* ) surface->data )->firstIndex; - srf.count = ( ( srfGeneric_t* ) surface->data )->numTriangles * 3; + srf.count = ( ( srfGeneric_t* ) surface->data )->numTriangles; srf.verts = ( ( srfGeneric_t* ) surface->data )->verts; srf.tris = ( ( srfGeneric_t* ) surface->data )->triangles; - VectorCopy( ( ( srfGeneric_t* ) surface->data )->origin, srf.origin ); - srf.radius = ( ( srfGeneric_t* ) surface->data )->radius; - - BoundsAdd( worldBounds[0], worldBounds[1], - ( ( srfGeneric_t* ) surface->data )->bounds[0], ( ( srfGeneric_t* ) surface->data )->bounds[1] ); - - materialSystem.GenerateMaterial( &srf ); - materialSurfaces.emplace_back( srf ); + surfaceIndex++; } - materialSystem.GenerateWorldMaterialsBuffer(); - materialSystem.GeneratePortalBoundingSpheres(); - materialSystem.SetWorldBounds( worldBounds ); - materialSystem.GenerateWorldCommandBuffer( materialSurfaces ); - return materialSurfaces; } diff --git a/src/engine/renderer/GeometryOptimiser.h b/src/engine/renderer/GeometryOptimiser.h index 2ce0b066c1..b2f2b43796 100644 --- a/src/engine/renderer/GeometryOptimiser.h +++ b/src/engine/renderer/GeometryOptimiser.h @@ -106,6 +106,6 @@ void OptimiseMapGeometryCore( world_t* world, bspSurface_t** rendererSurfaces, i void MergeLeafSurfacesCore( world_t* world, bspSurface_t** rendererSurfaces, int numSurfaces ); void MergeDuplicateVertices( bspSurface_t** rendererSurfaces, int numSurfaces, srfVert_t* vertices, int numVerticesIn, glIndex_t* indices, int numIndicesIn, int& numVerticesOut, int& numIndicesOut ); -std::vector OptimiseMapGeometryMaterial( bspSurface_t** rendererSurfaces, int numSurfaces ); +std::vector OptimiseMapGeometryMaterial( world_t* world, int numSurfaces ); #endif // GEOMETRY_OPTIMISER_H diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index 08c4b5b04a..d43f34aadd 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -430,6 +430,40 @@ void MaterialSystem::GenerateWorldMaterialsBuffer() { GenerateMaterialsBuffer( materialStages, offset, materialsData ); + for ( uint32_t materialPackID = 0; materialPackID < 3; materialPackID++ ) { + for ( Material& material : materialPacks[materialPackID].materials ) { + for ( drawSurf_t* drawSurf : material.drawSurfs ) { + 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; + } + + // 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 = 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 ); + Tess_DrawElements(); + Tess_Clear(); + + drawSurf->drawCommandIDs[stage] = lastCommandID; + + stage++; + } + } + } + } + for ( shaderStage_t* pStage : materialStages ) { if ( pStage->dynamic ) { pStage->bufferOffset -= dynamicStagesOffset; @@ -474,7 +508,11 @@ void MaterialSystem::GenerateTexturesBuffer( std::vector& textures, const textureBundle_t* bundle = textureData.texBundles[i]; if ( bundle && bundle->image[0] ) { - textureBundles->textures[i] = BindAnimatedImage( 0, bundle ); + if ( generatingWorldCommandBuffer ) { + textureBundles->textures[i] = bundle->image[0]->texture->bindlessTextureHandle; + } else { + textureBundles->textures[i] = BindAnimatedImage( 0, bundle ); + } } } @@ -493,7 +531,7 @@ void MaterialSystem::GenerateTexturesBuffer( std::vector& textures, } // This generates the buffers with indirect rendering commands etc. -void MaterialSystem::GenerateWorldCommandBuffer( std::vector& surfaces ) { +void MaterialSystem::GenerateWorldCommandBuffer() { Log::Debug( "Generating world command buffer" ); totalBatchCount = 0; @@ -504,7 +542,7 @@ void MaterialSystem::GenerateWorldCommandBuffer( std::vector& s for ( Material& material : pack.materials ) { material.surfaceCommandBatchOffset = batchOffset; - const uint32_t cmdCount = material.drawCommandCount; + const uint32_t cmdCount = material.drawCommands.size(); const uint32_t batchCount = cmdCount % SURFACE_COMMANDS_PER_BATCH == 0 ? cmdCount / SURFACE_COMMANDS_PER_BATCH : cmdCount / SURFACE_COMMANDS_PER_BATCH + 1; @@ -637,54 +675,97 @@ void MaterialSystem::GenerateWorldCommandBuffer( std::vector& s debugSSBO.UnmapBuffer(); } - for ( MaterialSurface& surface : surfaces ) { - SurfaceDescriptor surfaceDescriptor; - VectorCopy( surface.origin, surfaceDescriptor.boundingSphere.origin ); - surfaceDescriptor.boundingSphere.radius = surface.radius; + for ( int i = 0; i < tr.refdef.numDrawSurfs; i++ ) { + const drawSurf_t* drawSurf = &tr.refdef.drawSurfs[i]; + + if ( drawSurf->entity != &tr.worldEntity ) { + continue; + } + + shader_t* shader = drawSurf->shader; + if ( !shader ) { + continue; + } + + shader = shader->remappedShader ? shader->remappedShader : shader; + if ( shader->isSky || shader->isPortal || shader->autoSpriteMode ) { + continue; + } + + // Don't add SF_SKIP surfaces + if ( *drawSurf->surface == surfaceType_t::SF_SKIP ) { + continue; + } + + // Depth prepass surfaces are added as stages to the main surface instead + if ( drawSurf->materialSystemSkip ) { + continue; + } - IndirectCompactCommand drawCmd { surface.count, surface.firstIndex }; + SurfaceDescriptor surface; + VectorCopy( ( ( srfGeneric_t* ) drawSurf->surface )->origin, surface.boundingSphere.origin ); + surface.boundingSphere.radius = ( ( srfGeneric_t* ) drawSurf->surface )->radius; - for ( uint8_t stage = 0; stage < surface.stages; stage++ ) { - Material* material = &materialPacks[surface.materialPackIDs[stage]].materials[surface.materialIDs[stage]]; - uint32_t cmdID = material->surfaceCommandBatchOffset * SURFACE_COMMANDS_PER_BATCH + material->drawCommandCount2; + const bool depthPrePass = drawSurf->depthSurface != nullptr; + + if ( depthPrePass ) { + const drawSurf_t* depthDrawSurf = drawSurf->depthSurface; + 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 - surfaceDescriptor.surfaceCommandIDs[stage] = cmdID + 1; + surface.surfaceCommandIDs[0] = cmdID + 1; 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; + } - shaderStage_t* pStage = surface.shaderStages[stage]; - pStage = pStage->materialRemappedStage ? pStage->materialRemappedStage : pStage; - const uint32_t surfaceMaterialID = - pStage->materialOffset + pStage->variantOffsets[surface.shaderVariant[stage]]; - - surfaceCommand.drawCommand = drawCmd; - surfaceCommand.drawCommand.baseInstance = surfaceMaterialID; - surfaceCommand.drawCommand.baseInstance |= surface.texDataDynamic[stage] - ? ( surface.texDataIDs[stage] + texData.size() ) << TEX_BUNDLE_BITS - : surface.texDataIDs[stage] << TEX_BUNDLE_BITS; - surfaceCommand.drawCommand.baseInstance |= ( HasLightMap( &surface ) ? GetLightMapNum( &surface ) : 255 ) << LIGHTMAP_BITS; + uint32_t stage = 0; + for ( shaderStage_t* pStage = drawSurf->shader->stages; pStage < drawSurf->shader->lastStage; pStage++ ) { + const Material* material = &materialPacks[drawSurf->materialPackIDs[stage]].materials[drawSurf->materialIDs[stage]]; + uint32_t cmdID = material->surfaceCommandBatchOffset * SURFACE_COMMANDS_PER_BATCH + drawSurf->drawCommandIDs[stage]; + // Add 1 because cmd 0 == no-command + surface.surfaceCommandIDs[stage + ( depthPrePass ? 1 : 0 )] = cmdID + 1; + + 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; - material->drawCommandCount2++; + stage++; + } + + if ( drawSurf->fogSurface ) { + const drawSurf_t* fogDrawSurf = drawSurf->fogSurface; + 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; + + SurfaceCommand surfaceCommand; + surfaceCommand.enabled = 0; + surfaceCommand.drawCommand = material->drawCommands[fogDrawSurf->drawCommandIDs[0]].cmd; + surfaceCommands[cmdID] = surfaceCommand; } - memcpy( surfaceDescriptors, &surfaceDescriptor, descriptorSize * sizeof( uint32_t ) ); + memcpy( surfaceDescriptors, &surface, descriptorSize * sizeof( uint32_t ) ); surfaceDescriptors += descriptorSize; } for ( int i = 0; i < MAX_VIEWFRAMES; i++ ) { memcpy( surfaceCommands + surfaceCommandsCount * i, surfaceCommands, surfaceCommandsCount * sizeof( SurfaceCommand ) ); } - - uint32_t totalCount = 0; - for ( MaterialPack& pack : materialPacks ) { - totalCount += pack.materials.size(); - } - Log::Notice( "Generated %u BSP materials from %u BSP surfaces", totalCount, surfaces.size() ); - 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 ); surfaceDescriptorsSSBO.UnmapBuffer(); @@ -930,7 +1011,7 @@ void BindShaderFog( Material* material ) { gl_fogQuake3ShaderMaterial->BindProgram( 0 ); // Set shader uniforms. - const fog_t* fog = tr.world->fogs + material->fog; + const fog_t* fog = material->fog; // all fogging distance is based on world Z units vec4_t fogDistanceVector; @@ -984,16 +1065,16 @@ void BindShaderFog( Material* material ) { ); } -void ProcessMaterialNONE( Material*, shaderStage_t*, MaterialSurface* ) { +void ProcessMaterialNONE( Material*, shaderStage_t*, drawSurf_t* ) { ASSERT_UNREACHABLE(); } -void ProcessMaterialNOP( Material*, shaderStage_t*, MaterialSurface* ) { +void ProcessMaterialNOP( Material*, shaderStage_t*, drawSurf_t* ) { } // ProcessMaterial*() are essentially same as BindShader*(), but only set the GL program id to the material, // without actually binding it -void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, MaterialSurface* ) { +void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, drawSurf_t* ) { material->shader = gl_genericShaderMaterial; material->tcGenEnvironment = pStage->tcGen_Environment; @@ -1010,14 +1091,14 @@ void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, Materi material->program = gl_genericShaderMaterial->GetProgram( pStage->deformIndex ); } -void ProcessMaterialLightMapping( Material* material, shaderStage_t* pStage, MaterialSurface* surface ) { +void ProcessMaterialLightMapping( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ) { material->shader = gl_lightMappingShaderMaterial; - gl_lightMappingShaderMaterial->SetBspSurface( surface->bspSurface ); + gl_lightMappingShaderMaterial->SetBspSurface( drawSurf->bspSurface ); lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( surface, pStage->shader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( drawSurf, pStage->type, lightMode, deluxeMode ); bool enableDeluxeMapping = ( deluxeMode == deluxeMode_t::MAP ); bool enableGridLighting = ( lightMode == lightMode_t::GRID ); @@ -1052,7 +1133,7 @@ void ProcessMaterialLightMapping( Material* material, shaderStage_t* pStage, Mat material->program = gl_lightMappingShaderMaterial->GetProgram( pStage->deformIndex ); } -void ProcessMaterialReflection( Material* material, shaderStage_t* pStage, MaterialSurface* /* surface */ ) { +void ProcessMaterialReflection( Material* material, shaderStage_t* pStage, drawSurf_t* /* drawSurf */ ) { material->shader = gl_reflectionShaderMaterial; material->hasHeightMapInNormalMap = pStage->hasHeightMapInNormalMap; @@ -1066,7 +1147,7 @@ void ProcessMaterialReflection( Material* material, shaderStage_t* pStage, Mater material->program = gl_reflectionShaderMaterial->GetProgram( pStage->deformIndex ); } -void ProcessMaterialSkybox( Material* material, shaderStage_t* pStage, MaterialSurface* /* surface */ ) { +void ProcessMaterialSkybox( Material* material, shaderStage_t* pStage, drawSurf_t* /* drawSurf */ ) { material->shader = gl_skyboxShaderMaterial; material->deformIndex = pStage->deformIndex; @@ -1074,7 +1155,7 @@ void ProcessMaterialSkybox( Material* material, shaderStage_t* pStage, MaterialS material->program = gl_skyboxShaderMaterial->GetProgram( pStage->deformIndex ); } -void ProcessMaterialScreen( Material* material, shaderStage_t* pStage, MaterialSurface* /* surface */ ) { +void ProcessMaterialScreen( Material* material, shaderStage_t* pStage, drawSurf_t* /* drawSurf */ ) { material->shader = gl_screenShaderMaterial; material->deformIndex = pStage->deformIndex; @@ -1082,7 +1163,7 @@ void ProcessMaterialScreen( Material* material, shaderStage_t* pStage, MaterialS material->program = gl_screenShaderMaterial->GetProgram( pStage->deformIndex ); } -void ProcessMaterialHeatHaze( Material* material, shaderStage_t* pStage, MaterialSurface* ) { +void ProcessMaterialHeatHaze( Material* material, shaderStage_t* pStage, drawSurf_t* ) { material->shader = gl_heatHazeShaderMaterial; material->deformIndex = pStage->deformIndex; @@ -1090,12 +1171,12 @@ void ProcessMaterialHeatHaze( Material* material, shaderStage_t* pStage, Materia material->program = gl_heatHazeShaderMaterial->GetProgram( pStage->deformIndex ); } -void ProcessMaterialLiquid( Material* material, shaderStage_t* pStage, MaterialSurface* surface ) { +void ProcessMaterialLiquid( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ) { material->shader = gl_liquidShaderMaterial; lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( surface, pStage->shader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( drawSurf, pStage->type, lightMode, deluxeMode ); material->hasHeightMapInNormalMap = pStage->hasHeightMapInNormalMap; material->enableReliefMapping = pStage->enableReliefMapping; @@ -1114,14 +1195,14 @@ void ProcessMaterialLiquid( Material* material, shaderStage_t* pStage, MaterialS material->program = gl_liquidShaderMaterial->GetProgram( pStage->deformIndex ); } -void ProcessMaterialFog( Material* material, shaderStage_t* pStage, MaterialSurface* surface ) { +void ProcessMaterialFog( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ) { material->shader = gl_fogQuake3ShaderMaterial; - material->fog = surface->fog; + material->fog = tr.world->fogs + drawSurf->fog; material->program = gl_fogQuake3ShaderMaterial->GetProgram( pStage->deformIndex ); } -void MaterialSystem::AddStage( MaterialSurface* surface, shaderStage_t* pStage, uint32_t stage, +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 ) @@ -1132,7 +1213,7 @@ void MaterialSystem::AddStage( MaterialSurface* surface, shaderStage_t* pStage, pStage->variantOffset++; } - surface->shaderVariant[stage] = variant; + 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 ) { @@ -1226,13 +1307,12 @@ void MaterialSystem::AddStage( MaterialSurface* surface, shaderStage_t* pStage, } } -void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pStage, shader_t* shader, uint32_t* packIDs, uint32_t& stage, - uint32_t& previousMaterialID, bool skipStageSync ) { +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( surface, shader, pStage->type, lightMode, deluxeMode ); - const bool mayUseVertexOverbright = pStage->type == stageType_t::ST_COLORMAP - && surface->bspSurface && pStage->shaderBinder == BindShaderGeneric3D; + 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; @@ -1254,7 +1334,7 @@ void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pSta // In surfaces with multiple stages each consecutive stage must be drawn after the previous stage, // except if an opaque stage follows a transparent stage etc. - if ( !skipStageSync && stage > 0 ) { + if ( stage > 0 ) { material.useSync = true; material.syncMaterial = previousMaterialID; } @@ -1267,15 +1347,16 @@ void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pSta material.cullType = shader->cullType; material.usePolygonOffset = shader->polygonOffset; - material.bspSurface = surface->bspSurface; - pStage->materialProcessor( &material, pStage, surface ); + material.bspSurface = drawSurf->bspSurface; + pStage->materialProcessor( &material, pStage, drawSurf ); pStage->paddedSize = material.shader->GetPaddedSize(); - // HACK: Copy the shaderStage_t and MaterialSurface that we need into the material, so we can use it with glsl_restart + // HACK: Copy the shaderStage_t and drawSurf_t that we need into the material, so we can use it with glsl_restart material.refStage = pStage; - material.refDrawSurf = *surface; - material.refDrawSurf.verts = nullptr; - material.refDrawSurf.tris = nullptr; + material.refDrawSurf = *drawSurf; + material.refDrawSurf.entity = nullptr; + material.refDrawSurf.depthSurface = nullptr; + material.refDrawSurf.fogSurface = nullptr; std::vector& materials = materialPacks[materialPack].materials; std::vector::iterator currentSearchIt = materials.begin(); @@ -1306,55 +1387,117 @@ void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pSta pStage->useMaterialSystem = true; pStage->initialized = true; - AddStage( surface, pStage, stage, mayUseVertexOverbright, vertexLit, fullbright ); - AddStageTextures( surface, shader, pStage, stage, &materials[previousMaterialID] ); + AddStage( drawSurf, pStage, stage, mayUseVertexOverbright, vertexLit, fullbright ); + AddStageTextures( drawSurf, stage, &materials[previousMaterialID] ); - surface->materialIDs[stage] = previousMaterialID; - surface->materialPackIDs[stage] = materialPack; - surface->shaderStages[stage] = pStage; + if ( std::find( materials[previousMaterialID].drawSurfs.begin(), materials[previousMaterialID].drawSurfs.end(), drawSurf ) + == materials[previousMaterialID].drawSurfs.end() ) { + materials[previousMaterialID].drawSurfs.emplace_back( drawSurf ); + } - packIDs[materialPack] = id; + drawSurf->materialIDs[stage] = previousMaterialID; + drawSurf->materialPackIDs[stage] = materialPack; - materials[previousMaterialID].drawCommandCount++; + packIDs[materialPack] = id; stage++; } -/* This will only generate a material itself -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::GenerateMaterial( MaterialSurface* surface ) { - totalDrawSurfs++; +/* This will only generate the materials themselves +* 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(); - uint32_t stage = 0; - uint32_t previousMaterialID = 0; - - if ( surface->shader->depthShader ) { - uint32_t unused; - ProcessStage( surface, surface->shader->depthShader->stages, surface->shader->depthShader, packIDs, stage, unused, true ); + const int current_r_nocull = r_nocull->integer; + const int current_r_drawworld = r_drawworld->integer; + r_nocull->integer = 1; + r_drawworld->integer = 1; + generatingWorldCommandBuffer = true; - surface->stages++; - } + Log::Debug( "Generating world materials" ); + + ++tr.viewCountNoReset; + R_AddWorldSurfaces(); + + Log::Notice( "World bounds: min: %f %f %f max: %f %f %f", tr.viewParms.visBounds[0][0], tr.viewParms.visBounds[0][1], + tr.viewParms.visBounds[0][2], tr.viewParms.visBounds[1][0], tr.viewParms.visBounds[1][1], tr.viewParms.visBounds[1][2] ); + VectorCopy( tr.viewParms.visBounds[0], worldViewBounds[0] ); + VectorCopy( tr.viewParms.visBounds[1], worldViewBounds[1] ); + + backEnd.currentEntity = &tr.worldEntity; + + totalDrawSurfs = 0; + + uint32_t packIDs[3] = { 0, 0, 0 }; + + for ( int i = 0; i < tr.refdef.numDrawSurfs; i++ ) { + drawSurf_t* drawSurf = &tr.refdef.drawSurfs[i]; + if ( drawSurf->entity != &tr.worldEntity ) { + continue; + } + + shader_t* shader = drawSurf->shader; + if ( !shader ) { + continue; + } + + shader = shader->remappedShader ? shader->remappedShader : shader; + if ( shader->isSky || shader->isPortal || shader->autoSpriteMode ) { + continue; + } - for ( shaderStage_t* pStage = surface->shader->stages; pStage < surface->shader->lastStage; pStage++ ) { - ProcessStage( surface, pStage, surface->shader, packIDs, stage, previousMaterialID ); + // Don't add SF_SKIP surfaces + if ( *drawSurf->surface == surfaceType_t::SF_SKIP ) { + continue; + } - surface->stages++; + // Only add the main surface for surfaces with depth pre-pass or fog to the total count + if ( !drawSurf->materialSystemSkip ) { + totalDrawSurfs++; + } + + uint32_t stage = 0; + uint32_t previousMaterialID = 0; + for ( shaderStage_t* pStage = drawSurf->shader->stages; pStage < drawSurf->shader->lastStage; pStage++ ) { + ProcessStage( drawSurf, pStage, shader, packIDs, stage, previousMaterialID ); + } } - if ( !surface->shader->noFog && surface->fog >= 1 ) { - uint32_t unused; - ProcessStage( surface, surface->shader->fogShader->stages, surface->shader->fogShader, packIDs, stage, unused, true ); + GenerateWorldMaterialsBuffer(); - surface->stages++; + uint32_t totalCount = 0; + for ( MaterialPack& pack : materialPacks ) { + 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, 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; + AddAllWorldSurfaces(); + + GeneratePortalBoundingSpheres(); + + generatedWorldCommandBuffer = true; } -void MaterialSystem::SetWorldBounds( vec3_t bounds[2] ) { - Log::Notice( "World bounds: min: %f %f %f max: %f %f %f", bounds[0][0], bounds[0][1], - bounds[0][2], bounds[1][0], bounds[1][1], bounds[1][2] ); - VectorCopy( bounds[0], worldViewBounds[0] ); - VectorCopy( bounds[1], worldViewBounds[1] ); +void MaterialSystem::AddAllWorldSurfaces() { + GenerateWorldCommandBuffer(); + + generatingWorldCommandBuffer = false; } void MaterialSystem::GLSLRestart() { @@ -1367,8 +1510,9 @@ void MaterialSystem::GLSLRestart() { } } -void MaterialSystem::AddStageTextures( MaterialSurface* surface, shader_t* shader, shaderStage_t* pStage, const uint32_t stage, Material* material ) { +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; @@ -1398,11 +1542,11 @@ void MaterialSystem::AddStageTextures( MaterialSurface* surface, shader_t* shade // Add lightmap and deluxemap for this surface to the material as well lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( surface, shader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( drawSurf, pStage->type, lightMode, deluxeMode ); // u_Map, u_DeluxeMap - image_t* lightmap = SetLightMap( surface, lightMode ); - image_t* deluxemap = SetDeluxeMap( surface, deluxeMode ); + image_t* lightmap = SetLightMap( drawSurf, lightMode ); + image_t* deluxemap = SetDeluxeMap( drawSurf, deluxeMode ); material->AddTexture( lightmap->texture ); material->AddTexture( deluxemap->texture ); @@ -1415,12 +1559,12 @@ void MaterialSystem::AddStageTextures( MaterialSurface* surface, shader_t* shade std::vector::iterator it = std::find( textures.begin(), textures.end(), textureData ); if ( it == textures.end() ) { - surface->texDataIDs[stage] = textures.size(); + drawSurf->texDataIDs[stage] = textures.size(); textures.emplace_back( textureData ); } else { - surface->texDataIDs[stage] = it - textures.begin(); + drawSurf->texDataIDs[stage] = it - textures.begin(); } - surface->texDataDynamic[stage] = dynamic; + drawSurf->texDataDynamic[stage] = dynamic; if ( glConfig2.realtimeLighting ) { if ( r_realtimeLightingRenderer.Get() == Util::ordinal( realtimeLightingRenderer_t::TILED ) ) { @@ -1622,10 +1766,18 @@ void MaterialSystem::CullSurfaces() { } void MaterialSystem::StartFrame() { + if ( !generatedWorldCommandBuffer ) { + return; + } + frames[nextFrame].viewCount = 0; } void MaterialSystem::EndFrame() { + if ( !generatedWorldCommandBuffer ) { + return; + } + currentFrame = nextFrame; nextFrame++; if ( nextFrame >= MAX_FRAMES ) { @@ -1636,7 +1788,7 @@ void MaterialSystem::EndFrame() { void MaterialSystem::GeneratePortalBoundingSpheres() { Log::Debug( "Generating portal bounding spheres" ); - totalPortals = portalSurfaces.size(); + totalPortals = portalSurfacesTmp.size(); if ( totalPortals == 0 ) { return; @@ -1644,15 +1796,33 @@ void MaterialSystem::GeneratePortalBoundingSpheres() { // FIXME: This only requires distance, origin and radius can be moved to surfaceDescriptors SSBO, // drawSurfID is not needed as it's the same as the index in portalSurfacesSSBO - PortalSurface* portalSurfs = - ( PortalSurface* ) ri.Hunk_AllocateTempMemory( totalPortals * MAX_VIEWFRAMES * sizeof( PortalSurface ) ); + PortalSurface* portalSurfs = new PortalSurface[totalPortals * sizeof( PortalSurface ) * MAX_VIEWFRAMES]; uint32_t index = 0; - for ( MaterialSurface& surface : portalSurfaces ) { + for ( drawSurf_t* drawSurf : portalSurfacesTmp ) { + Tess_MapVBOs( /*forceCPU=*/ true ); + Tess_Begin( Tess_StageIteratorDummy, nullptr, nullptr, true, -1, 0 ); + rb_surfaceTable[Util::ordinal( *( drawSurf->surface ) )]( drawSurf->surface ); + const int numVerts = tess.numVertexes; + vec3_t portalCenter{ 0.0, 0.0, 0.0 }; + for ( int vertIndex = 0; vertIndex < numVerts; vertIndex++ ) { + VectorAdd( portalCenter, tess.verts[vertIndex].xyz, portalCenter ); + } + VectorScale( portalCenter, 1.0 / numVerts, portalCenter ); + + float furthestDistance = 0.0; + for ( int vertIndex = 0; vertIndex < numVerts; vertIndex++ ) { + const float distance = Distance( portalCenter, tess.verts[vertIndex].xyz ); + furthestDistance = distance > furthestDistance ? distance : furthestDistance; + } + + Tess_Clear(); + + portalSurfaces.emplace_back( *drawSurf ); PortalSurface sphere; - VectorCopy( surface.origin, sphere.origin ); - sphere.radius = surface.radius; - sphere.drawSurfID = &surface - portalSurfaces.data(); + VectorCopy( portalCenter, sphere.origin ); + sphere.radius = furthestDistance; + sphere.drawSurfID = portalSurfaces.size() - 1; sphere.distance = -1; portalBounds.emplace_back( sphere ); @@ -1667,7 +1837,7 @@ void MaterialSystem::GeneratePortalBoundingSpheres() { portalSurfacesSSBO.BufferStorage( totalPortals * PORTAL_SURFACE_SIZE * MAX_VIEWS, 2, portalSurfs ); portalSurfacesSSBO.MapAll(); - ri.Hunk_FreeTempMemory( portalSurfs ); + portalSurfacesTmp.clear(); } void MaterialSystem::InitGLBuffers() { @@ -1707,10 +1877,13 @@ void MaterialSystem::FreeGLBuffers() { } void MaterialSystem::Free() { + generatedWorldCommandBuffer = false; + materialStages.clear(); dynamicStages.clear(); autospriteSurfaces.clear(); portalSurfaces.clear(); + portalSurfacesTmp.clear(); portalBounds.clear(); skyShaders.clear(); renderedMaterials.clear(); @@ -1729,6 +1902,7 @@ void MaterialSystem::Free() { portalSurfacesSSBO.UnmapBuffer(); for ( PortalView& portalView : portalStack ) { + portalView.drawSurf = nullptr; memset( portalView.views, 0, MAX_VIEWS * sizeof( uint32_t ) ); portalView.count = 0; } @@ -1737,13 +1911,37 @@ void MaterialSystem::Free() { currentFrame = 0; nextFrame = 1; maxStages = 0; - memset( packIDs, 0, sizeof( packIDs ) ); for ( MaterialPack& pack : materialPacks ) { + for ( Material& material : pack.materials ) { + material.drawCommands.clear(); + material.drawSurfs.clear(); + } pack.materials.clear(); } } +// This gets the information for the surface vertex/index data through Tess +void MaterialSystem::AddDrawCommand( const uint32_t materialID, const uint32_t materialPackID, const uint32_t materialsSSBOOffset, + const GLuint count, const GLuint firstIndex ) { + cmd.cmd.count = count; + cmd.cmd.firstIndex = firstIndex; + cmd.cmd.baseInstance = materialsSSBOOffset; + cmd.materialsSSBOOffset = materialsSSBOOffset; + + materialPacks[materialPackID].materials[materialID].drawCommands.emplace_back( cmd ); + lastCommandID = materialPacks[materialPackID].materials[materialID].drawCommands.size() - 1; + cmd.textureCount = 0; +} + +void MaterialSystem::AddTexture( Texture* texture ) { + if ( cmd.textureCount >= MAX_DRAWCOMMAND_TEXTURES ) { + Sys::Drop( "Exceeded max DrawCommand textures" ); + } + cmd.textures[cmd.textureCount] = texture; + cmd.textureCount++; +} + bool MaterialSystem::AddPortalSurface( uint32_t viewID, PortalSurface* portalSurfs ) { uint32_t portalViews[MAX_VIEWS] {}; uint32_t count = 0; @@ -1751,7 +1949,7 @@ bool MaterialSystem::AddPortalSurface( uint32_t viewID, PortalSurface* portalSur frames[nextFrame].viewFrames[viewID].viewCount = 0; portalStack[viewID].count = 0; - PortalSurface* tmpSurfs = ( PortalSurface* ) ri.Hunk_AllocateTempMemory( totalPortals * sizeof( PortalSurface ) );; + PortalSurface* tmpSurfs = new PortalSurface[totalPortals]; memcpy( tmpSurfs, portalSurfs + viewID * totalPortals, totalPortals * sizeof( PortalSurface ) ); std::sort( tmpSurfs, tmpSurfs + totalPortals, []( const PortalSurface& lhs, const PortalSurface& rhs ) { @@ -1767,17 +1965,8 @@ bool MaterialSystem::AddPortalSurface( uint32_t viewID, PortalSurface* portalSur uint32_t portalViewID = viewCount + 1; // This check has to be done first so we can correctly determine when we get to MAX_VIEWS - 1 amount of views screenRect_t surfRect; - drawSurf_t drawSurf; - { - drawSurf.bspSurface = portalSurfaces[portalSurface->drawSurfID].bspSurface; - drawSurf.entity = &tr.worldEntity; - drawSurf.fog = portalSurfaces[portalSurface->drawSurfID].fog; - drawSurf.portalNum = portalSurfaces[portalSurface->drawSurfID].portalNum; - drawSurf.shader = portalSurfaces[portalSurface->drawSurfID].shader; - drawSurf.surface = portalSurfaces[portalSurface->drawSurfID].surface; - } bool offScreenOrOutOfRange = 0 != PortalOffScreenOrOutOfRange( - &drawSurf, surfRect ); + &portalSurfaces[ portalSurface->drawSurfID ], surfRect ); Tess_Clear(); if ( offScreenOrOutOfRange ) { continue; @@ -1792,14 +1981,13 @@ bool MaterialSystem::AddPortalSurface( uint32_t viewID, PortalSurface* portalSur frames[nextFrame].viewFrames[viewID].viewCount++; portalStack[viewID].views[count] = portalViewID; - portalStack[portalViewID].drawSurf = drawSurf; + portalStack[portalViewID].drawSurf = &portalSurfaces[portalSurface->drawSurfID]; portalStack[viewID].count++; count++; viewCount++; if ( count == MAX_VIEWS || viewCount == MAX_VIEWS ) { - ri.Hunk_FreeTempMemory( tmpSurfs ); return false; } @@ -1807,7 +1995,6 @@ bool MaterialSystem::AddPortalSurface( uint32_t viewID, PortalSurface* portalSur uint32_t subView = frames[currentFrame].viewFrames[viewID].portalViews[j]; if ( subView != 0 && portalSurface->drawSurfID == frames[currentFrame].viewFrames[subView].portalSurfaceID ) { if ( !AddPortalSurface( subView, portalSurfs ) ) { - ri.Hunk_FreeTempMemory( tmpSurfs ); return false; } @@ -1819,7 +2006,6 @@ bool MaterialSystem::AddPortalSurface( uint32_t viewID, PortalSurface* portalSur memcpy( frames[nextFrame].viewFrames[viewID].portalViews, portalViews, MAX_VIEWS * sizeof( uint32_t ) ); - ri.Hunk_FreeTempMemory( tmpSurfs ); return true; } @@ -1845,10 +2031,10 @@ void MaterialSystem::AddPortalSurfaces() { void MaterialSystem::AddAutospriteSurfaces() { tr.currentEntity = &tr.worldEntity; - for ( const bspSurface_t* surface : autospriteSurfaces ) + for ( const drawSurf_t &drawSurf : autospriteSurfaces ) { - R_AddDrawSurf( surface->data, surface->shader, - surface->lightmapNum, surface->fogIndex, true ); + R_AddDrawSurf( drawSurf.surface, drawSurf.shader, + drawSurf.lightmapNum(), drawSurf.fog, drawSurf.bspSurface ); } } @@ -1910,7 +2096,7 @@ void MaterialSystem::RenderIndirect( const Material& material, const uint32_t vi * sizeof( GLIndirectCommand ) ) ), material.globalID * sizeof( uint32_t ) + ( MAX_COMMAND_COUNTERS * ( MAX_VIEWS * currentFrame + viewID ) ) * sizeof( uint32_t ), - material.drawCommandCount, 0 ); + material.drawCommands.size(), 0 ); } void MaterialSystem::RenderMaterial( Material& material, const uint32_t viewID ) { diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h index 903f5a6628..0a32e9fa4b 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -63,6 +63,7 @@ struct DrawCommand { IndirectCompactCommand cmd; uint32_t materialsSSBOOffset = 0; uint32_t textureCount = 0; + Texture* textures[MAX_DRAWCOMMAND_TEXTURES]; DrawCommand() { } @@ -71,35 +72,29 @@ struct DrawCommand { cmd = other.cmd; materialsSSBOOffset = other.materialsSSBOOffset; textureCount = other.textureCount; + memcpy( textures, other.textures, textureCount * sizeof( Texture* ) ); } }; struct MaterialSurface { shader_t* shader; - surfaceType_t* surface; bool bspSurface; - int16_t lightMapNum; int fog; int portalNum = -1; GLuint firstIndex; GLuint count; - vec3_t origin; - float radius; - srfVert_t* verts; srfTriangle_t* tris; 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]; - - uint8_t stages = 0; - shaderStage_t* shaderStages[MAX_SHADER_STAGES]; }; struct Material { @@ -121,7 +116,7 @@ struct Material { // Used only for glsl_restart shaderStage_t* refStage; - MaterialSurface refDrawSurf; + drawSurf_t refDrawSurf; int deformIndex; bool tcGenEnvironment; @@ -144,10 +139,10 @@ struct Material { bool usePolygonOffset = false; - int fog = 0; + fog_t* fog = nullptr; - uint32_t drawCommandCount = 0; - uint32_t drawCommandCount2 = 0; + std::vector drawSurfs; + std::vector drawCommands; bool texturesResident = false; std::vector textures; @@ -238,7 +233,7 @@ struct PortalSurface { struct PortalView { uint32_t count; - drawSurf_t drawSurf; + drawSurf_t* drawSurf; uint32_t views[MAX_VIEWS]; }; @@ -323,15 +318,18 @@ enum class BufferBind { class MaterialSystem { public: - vec3_t worldViewBounds[2]; + bool generatedWorldCommandBuffer = false; + bool generatingWorldCommandBuffer = false; + vec3_t worldViewBounds[2] = {}; uint8_t maxStages = 0; uint32_t descriptorSize; std::vector drawCommands; - std::vector portalSurfaces; - std::vector autospriteSurfaces; + std::vector portalSurfacesTmp; + std::vector portalSurfaces; + std::vector autospriteSurfaces; std::vector portalBounds; uint32_t totalPortals; std::vector skyShaders; @@ -360,6 +358,10 @@ class MaterialSystem { bool frameStart = false; + void AddTexture( Texture* texture ); + void AddDrawCommand( const uint32_t materialID, const uint32_t materialPackID, const uint32_t materialsSSBOOffset, + const GLuint count, const GLuint firstIndex ); + void AddPortalSurfaces(); void AddAutospriteSurfaces(); void RenderMaterials( const shaderSort_t fromSort, const shaderSort_t toSort, const uint32_t viewID ); @@ -377,21 +379,21 @@ class MaterialSystem { void InitGLBuffers(); void FreeGLBuffers(); - void AddStageTextures( MaterialSurface* surface, shader_t* shader, shaderStage_t* pStage, const uint32_t stage, Material* material ); - void AddStage( MaterialSurface* surface, shaderStage_t* pStage, uint32_t stage, + 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( MaterialSurface* surface, shaderStage_t* pStage, shader_t* shader, uint32_t* packIDs, uint32_t& stage, - uint32_t& previousMaterialID, bool skipStageSync = false ); - void GenerateMaterial( MaterialSurface* surface ); + void ProcessStage( drawSurf_t* drawSurf, shaderStage_t* pStage, shader_t* shader, uint32_t* packIDs, uint32_t& stage, + uint32_t& previousMaterialID ); + void GenerateWorldMaterials(); void GenerateWorldMaterialsBuffer(); - void GenerateWorldCommandBuffer( std::vector& surfaces ); + void GenerateWorldCommandBuffer(); void GeneratePortalBoundingSpheres(); - void SetWorldBounds( vec3_t bounds[2] ); - void GenerateMaterialsBuffer( std::vector& stages, const uint32_t size, uint32_t* materialsData ); void GenerateTexturesBuffer( std::vector& textures, TexBundle* textureBundles ); + void AddAllWorldSurfaces(); + void GLSLRestart(); void Free(); @@ -408,14 +410,14 @@ class MaterialSystem { image_t* depthImage; int depthImageLevels; + DrawCommand cmd; + uint32_t lastCommandID; uint32_t totalDrawSurfs; uint32_t totalBatchCount = 0; uint32_t surfaceCommandsCount = 0; uint32_t surfaceDescriptorsCount = 0; - uint32_t packIDs[3] = { 0, 0, 0 }; - std::vector materialStages; std::vector dynamicStages; @@ -466,6 +468,8 @@ void UpdateSurfaceDataHeatHaze( uint32_t* materials, shaderStage_t* pStage, 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* ); void BindShaderGeneric3D( Material* material ); @@ -477,15 +481,15 @@ void BindShaderHeatHaze( Material* material ); void BindShaderLiquid( Material* material ); void BindShaderFog( Material* material ); -void ProcessMaterialNONE( Material*, shaderStage_t*, MaterialSurface* ); -void ProcessMaterialNOP( Material*, shaderStage_t*, MaterialSurface* ); -void ProcessMaterialGeneric3D( Material* material, shaderStage_t* pStage, MaterialSurface* /* surface */ ); -void ProcessMaterialLightMapping( Material* material, shaderStage_t* pStage, MaterialSurface* surface ); -void ProcessMaterialReflection( Material* material, shaderStage_t* pStage, MaterialSurface* /* surface */ ); -void ProcessMaterialSkybox( Material* material, shaderStage_t* pStage, MaterialSurface* /* surface */ ); -void ProcessMaterialScreen( Material* material, shaderStage_t* pStage, MaterialSurface* /* surface */ ); -void ProcessMaterialHeatHaze( Material* material, shaderStage_t* pStage, MaterialSurface* surface ); -void ProcessMaterialLiquid( Material* material, shaderStage_t* pStage, MaterialSurface* /* surface */ ); -void ProcessMaterialFog( Material* material, shaderStage_t* pStage, MaterialSurface* surface ); +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 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 */ ); +void ProcessMaterialScreen( Material* material, shaderStage_t* pStage, drawSurf_t* /* drawSurf */ ); +void ProcessMaterialHeatHaze( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ); +void ProcessMaterialLiquid( Material* material, shaderStage_t* pStage, drawSurf_t* /* drawSurf */ ); +void ProcessMaterialFog( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ); #endif // MATERIAL_H diff --git a/src/engine/renderer/ShadeCommon.h b/src/engine/renderer/ShadeCommon.h index 7d8f107439..bae521f9c8 100644 --- a/src/engine/renderer/ShadeCommon.h +++ b/src/engine/renderer/ShadeCommon.h @@ -37,9 +37,9 @@ inline size_t GetLightMapNum( const shaderCommands_t* tess ) return tess->lightmapNum; } -inline size_t GetLightMapNum( const MaterialSurface* surface ) +inline size_t GetLightMapNum( const drawSurf_t* drawSurf ) { - return surface->lightMapNum; + return drawSurf->lightmapNum(); } template bool HasLightMap( Obj* obj ) @@ -77,9 +77,9 @@ inline shader_t* GetSurfaceShader( shaderCommands_t* tess ) return tess->surfaceShader; } -inline shader_t* GetSurfaceShader( shader_t* shader ) +inline shader_t* GetSurfaceShader( drawSurf_t* drawSurf ) { - return shader; + return drawSurf->shader; } template static bool hasExplicitelyDisabledLightMap( Obj* obj ) @@ -92,9 +92,9 @@ inline shaderStage_t* GetSurfaceLastStage( shaderCommands_t* tess ) return tess->surfaceLastStage; } -inline shaderStage_t* GetSurfaceLastStage( shader_t* shader ) +inline shaderStage_t* GetSurfaceLastStage( drawSurf_t* drawSurf ) { - return shader->lastStage; + return drawSurf->shader->lastStage; } inline shaderStage_t* GetSurfaceStages( shaderCommands_t* tess ) @@ -102,9 +102,9 @@ inline shaderStage_t* GetSurfaceStages( shaderCommands_t* tess ) return tess->surfaceStages; } -inline shaderStage_t* GetSurfaceStages( shader_t* shader ) +inline shaderStage_t* GetSurfaceStages( drawSurf_t* drawSurf ) { - return shader->stages; + return drawSurf->shader->stages; } template bool isExplicitelyVertexLitSurface( Obj* obj ) @@ -114,14 +114,14 @@ template bool isExplicitelyVertexLitSurface( Obj* obj ) return lastStage != stages && stages[0].rgbGen == colorGen_t::CGEN_VERTEX; } -template void SetLightDeluxeMode( Obj* obj, shader_t* shader, +template void SetLightDeluxeMode( Obj* obj, stageType_t stageType, lightMode_t& lightMode, deluxeMode_t& deluxeMode ) { lightMode = lightMode_t::FULLBRIGHT; deluxeMode = deluxeMode_t::NONE; - if ( hasExplicitelyDisabledLightMap( shader ) && !isExplicitelyVertexLitSurface( shader ) ) + if ( hasExplicitelyDisabledLightMap( obj ) && !isExplicitelyVertexLitSurface( obj ) ) { // Use fullbright on “surfaceparm nolightmap” materials. } diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 02dc4c0015..f43d773dd7 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -943,8 +943,6 @@ int GLShaderManager::GetDeformShaderIndex( deformStage_t *deforms, int numDeform deformShaderCount++; _deformShaderLookup[steps] = deformShaderCount; - } else { - index--; } return index; diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index d0b282ee27..9199584ca0 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -170,6 +170,11 @@ GLuint64 GL_BindToTMU( int unit, image_t *image ) } if ( glConfig2.usingBindlessTextures ) { + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddTexture( image->texture ); + return image->texture->bindlessTextureHandle; + } + return tr.textureManager.BindTexture( 0, image->texture ); } @@ -853,6 +858,7 @@ static void RB_RenderDrawSurfaces( shaderSort_t fromSort, shaderSort_t toSort, for ( i = backEnd.viewParms.firstDrawSurf[ Util::ordinal(fromSort) ]; i < lastSurf; i++ ) { drawSurf = &backEnd.viewParms.drawSurfs[ i ]; + tess.currentDrawSurf = drawSurf; // FIXME: investigate why this happens. if( drawSurf->surface == nullptr ) diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index 305604f8fd..ec0f0aeefb 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -2538,22 +2538,12 @@ static void R_CreateWorldVBO() { // HACK: portals: don't use VBO because when adding a portal we have to read back the verts CPU-side // Autosprite: don't use VBO because verts are rewritten each time based on view origin if ( surface->shader->isPortal || surface->shader->autoSpriteMode != 0 ) { - if( glConfig2.usingMaterialSystem && surface->shader->autoSpriteMode ) { - materialSystem.autospriteSurfaces.push_back( surface ); - } - if ( surface->shader->isPortal ) { numPortals++; } continue; } - if ( glConfig2.usingMaterialSystem && surface->shader->isSky - && std::find( materialSystem.skyShaders.begin(), materialSystem.skyShaders.end(), surface->shader ) - == materialSystem.skyShaders.end() ) { - materialSystem.skyShaders.emplace_back( surface->shader ); - } - if ( *surface->data == surfaceType_t::SF_FACE || *surface->data == surfaceType_t::SF_GRID || *surface->data == surfaceType_t::SF_TRIANGLES ) { srfGeneric_t* srf = ( srfGeneric_t* ) surface->data; @@ -2565,11 +2555,6 @@ static void R_CreateWorldVBO() { } surface->renderable = true; - - if ( i >= ( int ) s_worldData.models[0].numSurfaces ) { - surface->BSPModel = true; - } - numSurfaces++; } @@ -2577,6 +2562,33 @@ static void R_CreateWorldVBO() { return; } + bspSurface_t** rendererSurfaces = ( bspSurface_t** ) ri.Hunk_AllocateTempMemory( sizeof( bspSurface_t* ) * numSurfaces ); + numSurfaces = 0; + for ( int i = 0; i < s_worldData.numSurfaces; i++ ) { + bspSurface_t* surface = &s_worldData.surfaces[i]; + + if ( surface->renderable ) { + rendererSurfaces[numSurfaces++] = surface; + } + } + + OptimiseMapGeometryCore( &s_worldData, rendererSurfaces, numSurfaces ); + + Log::Debug( "...calculating world VBO ( %i verts %i tris )", numVertsInitial, numTriangles ); + + // Use srfVert_t for the temporary array used to feed R_CreateStaticVBO, despite containing + // extraneous data, so that verts can be conveniently be bulk copied from the surface. + srfVert_t* vboVerts = ( srfVert_t* ) ri.Hunk_AllocateTempMemory( numVertsInitial * sizeof( srfVert_t ) ); + glIndex_t* vboIdxs = ( glIndex_t* ) ri.Hunk_AllocateTempMemory( 3 * numTriangles * sizeof( glIndex_t ) ); + + int numVerts; + int numIndices; + MergeDuplicateVertices( rendererSurfaces, numSurfaces, vboVerts, numVertsInitial, vboIdxs, 3 * numTriangles, numVerts, numIndices ); + + if ( glConfig2.usingMaterialSystem ) { + OptimiseMapGeometryMaterial( &s_worldData, numSurfaces ); + } + s_worldData.numPortals = numPortals; s_worldData.portals = ( AABB* ) ri.Hunk_Alloc( numPortals * sizeof( AABB ), ha_pref::h_low ); int portal = 0; @@ -2610,59 +2622,11 @@ static void R_CreateWorldVBO() { break; } portal++; - - if( glConfig2.usingMaterialSystem ) { - MaterialSurface srf{}; - - srf.shader = surface->shader; - srf.surface = surface->data; - srf.bspSurface = true; - srf.lightMapNum = surface->lightmapNum; - srf.fog = surface->fogIndex; - srf.portalNum = surface->portalNum; - - srf.firstIndex = ( ( srfGeneric_t* ) surface->data )->firstIndex; - srf.count = ( ( srfGeneric_t* ) surface->data )->numTriangles * 3; - srf.verts = ( ( srfGeneric_t* ) surface->data )->verts; - srf.tris = ( ( srfGeneric_t* ) surface->data )->triangles; - - VectorCopy( ( ( srfGeneric_t* ) surface->data )->origin, srf.origin ); - srf.radius = ( ( srfGeneric_t* ) surface->data )->radius; - - materialSystem.portalSurfaces.emplace_back( srf ); - } } else { surface->portalNum = -1; } } - bspSurface_t** rendererSurfaces = ( bspSurface_t** ) ri.Hunk_AllocateTempMemory( sizeof( bspSurface_t* ) * numSurfaces ); - numSurfaces = 0; - for ( int i = 0; i < s_worldData.numSurfaces; i++ ) { - bspSurface_t* surface = &s_worldData.surfaces[i]; - - if ( surface->renderable ) { - rendererSurfaces[numSurfaces++] = surface; - } - } - - OptimiseMapGeometryCore( &s_worldData, rendererSurfaces, numSurfaces ); - - Log::Debug( "...calculating world VBO ( %i verts %i tris )", numVertsInitial, numTriangles ); - - // Use srfVert_t for the temporary array used to feed R_CreateStaticVBO, despite containing - // extraneous data, so that verts can be conveniently be bulk copied from the surface. - srfVert_t* vboVerts = ( srfVert_t* ) ri.Hunk_AllocateTempMemory( numVertsInitial * sizeof( srfVert_t ) ); - glIndex_t* vboIdxs = ( glIndex_t* ) ri.Hunk_AllocateTempMemory( 3 * numTriangles * sizeof( glIndex_t ) ); - - int numVerts; - int numIndices; - MergeDuplicateVertices( rendererSurfaces, numSurfaces, vboVerts, numVertsInitial, vboIdxs, 3 * numTriangles, numVerts, numIndices ); - - if ( glConfig2.usingMaterialSystem ) { - OptimiseMapGeometryMaterial( rendererSurfaces, numSurfaces ); - } - vertexAttributeSpec_t attrs[]{ { ATTR_INDEX_POSITION, GL_FLOAT, GL_FLOAT, &vboVerts[0].xyz, 3, sizeof( *vboVerts ), 0 }, { ATTR_INDEX_COLOR, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE, &vboVerts[0].lightColor, 4, sizeof( *vboVerts ), ATTR_OPTION_NORMALIZE }, @@ -4338,82 +4302,6 @@ static Cmd::LambdaCmd buildCubeMapsCmd( "buildcubemaps", Cmd::RENDERER, "generate cube probes for reflection mapping", []( const Cmd::Args & ) { R_BuildCubeMaps(); }); -static void SetWorldLight() { - tr.worldLight = tr.lightMode; - tr.modelLight = lightMode_t::FULLBRIGHT; - tr.modelDeluxe = deluxeMode_t::NONE; - - // Use fullbright lighting for everything if the world is fullbright. - if ( tr.worldLight != lightMode_t::FULLBRIGHT ) { - if ( tr.worldLight == lightMode_t::MAP ) { - // World surfaces use light mapping. - - if ( !tr.worldLightMapping ) { - /* Use vertex light as a fallback on world surfaces missing a light map, - q3map2 has an option to produce less lightmap files by skipping them when - they are very similar to the vertex color. The vertex color is expected - to match the color of the nearby lightmaps. We better not want to use - the grid light as a fallback as it would be close but not close enough. */ - - tr.worldLight = lightMode_t::VERTEX; - } - } else if ( tr.worldLight == lightMode_t::GRID ) { - if ( !tr.lightGrid1Image ) { - // Use vertex light on world surface if light color grid is missing. - tr.worldLight = lightMode_t::VERTEX; - } - } - - if ( tr.worldDeluxeMapping ) { - if ( tr.worldLight == lightMode_t::MAP ) { - tr.worldDeluxe = deluxeMode_t::MAP; - } - - /* The combination of grid light and deluxe map is - technically doable, but rendering the world with a - light grid while a light map is available is not - the experience we want to provide, so we don't - allow this combination to not compile the related - shaders. */ - } - - /* We can technically use emulated deluxe map from light direction dir - on surfaces with light map but no deluxe map, but this is ugly. - Also, enabling it would require to make some macro not conflicting and - then would increase the amount of GLSL shader variants to be compiled, - this to render legacy maps in a way legacy renderers never rendered them. - It could still be cool as an optional feature, if we use a better - algorithm for emulating the deluxe map from light direction grid. - See https://github.com/DaemonEngine/Daemon/issues/32 */ - - if ( tr.lightGrid1Image ) { - // Game model surfaces use grid lighting, they don't have vertex light colors. - tr.modelLight = lightMode_t::GRID; - } - - if ( glConfig2.deluxeMapping ) { - // Enable deluxe mapping emulation if light direction grid is there. - if ( tr.lightGrid2Image ) { - // Game model surfaces use grid lighting, they don't have vertex light colors. - tr.modelDeluxe = deluxeMode_t::GRID; - - // Only game models use emulated deluxe map from light direction grid. - } - } - } - - /* Set GLSL overbright parameters if the lighting mode is not fullbright. */ - if ( tr.lightMode != lightMode_t::FULLBRIGHT ) { - if ( r_overbrightQ3.Get() ) { - // light factor is applied to entire color buffer; identityLight can be used to cancel it - tr.identityLight = 1.0f / float( 1 << tr.overbrightBits ); - } else { - // light factor is applied wherever a precomputed light is sampled - tr.mapLightFactor = float( 1 << tr.overbrightBits ); - } - } -} - /* ================= RE_LoadWorldMap @@ -4539,9 +4427,6 @@ void RE_LoadWorldMap( const char *name ) R_LoadLightGrid( &header->lumps[ LUMP_LIGHTGRID ] ); // create a static vbo for the world - // Do SetWorldLight() before R_CreateWorldVBO(), because the latter will use the world light values to generate materials - SetWorldLight(); - R_CreateWorldVBO(); R_CreateClusters(); @@ -4550,9 +4435,99 @@ void RE_LoadWorldMap( const char *name ) } s_worldData.dataSize = ( byte * ) ri.Hunk_Alloc( 0, ha_pref::h_low ) - startMarker; + // only set tr.world now that we know the entire level has loaded properly tr.world = &s_worldData; + tr.worldLight = tr.lightMode; + tr.modelLight = lightMode_t::FULLBRIGHT; + tr.modelDeluxe = deluxeMode_t::NONE; + + // Use fullbright lighting for everything if the world is fullbright. + if ( tr.worldLight != lightMode_t::FULLBRIGHT ) + { + if ( tr.worldLight == lightMode_t::MAP ) + { + // World surfaces use light mapping. + + if ( !tr.worldLightMapping ) + { + /* Use vertex light as a fallback on world surfaces missing a light map, + q3map2 has an option to produce less lightmap files by skipping them when + they are very similar to the vertex color. The vertex color is expected + to match the color of the nearby lightmaps. We better not want to use + the grid light as a fallback as it would be close but not close enough. */ + + tr.worldLight = lightMode_t::VERTEX; + } + } + else if ( tr.worldLight == lightMode_t::GRID ) + { + if ( !tr.lightGrid1Image ) + { + // Use vertex light on world surface if light color grid is missing. + tr.worldLight = lightMode_t::VERTEX; + } + } + + if ( tr.worldDeluxeMapping ) + { + if ( tr.worldLight == lightMode_t::MAP ) + { + tr.worldDeluxe = deluxeMode_t::MAP; + } + + /* The combination of grid light and deluxe map is + technically doable, but rendering the world with a + light grid while a light map is available is not + the experience we want to provide, so we don't + allow this combination to not compile the related + shaders. */ + } + + /* We can technically use emulated deluxe map from light direction dir + on surfaces with light map but no deluxe map, but this is ugly. + Also, enabling it would require to make some macro not conflicting and + then would increase the amount of GLSL shader variants to be compiled, + this to render legacy maps in a way legacy renderers never rendered them. + It could still be cool as an optional feature, if we use a better + algorithm for emulating the deluxe map from light direction grid. + See https://github.com/DaemonEngine/Daemon/issues/32 */ + + if ( tr.lightGrid1Image ) + { + // Game model surfaces use grid lighting, they don't have vertex light colors. + tr.modelLight = lightMode_t::GRID; + } + + if ( glConfig2.deluxeMapping ) + { + // Enable deluxe mapping emulation if light direction grid is there. + if ( tr.lightGrid2Image ) + { + // Game model surfaces use grid lighting, they don't have vertex light colors. + tr.modelDeluxe = deluxeMode_t::GRID; + + // Only game models use emulated deluxe map from light direction grid. + } + } + } + + /* Set GLSL overbright parameters if the lighting mode is not fullbright. */ + if ( tr.lightMode != lightMode_t::FULLBRIGHT ) + { + if ( r_overbrightQ3.Get() ) + { + // light factor is applied to entire color buffer; identityLight can be used to cancel it + tr.identityLight = 1.0f / float( 1 << tr.overbrightBits ); + } + else + { + // light factor is applied wherever a precomputed light is sampled + tr.mapLightFactor = float( 1 << tr.overbrightBits ); + } + } + tr.worldLoaded = true; tr.loadingMap = ""; GLSL_InitWorldShaders(); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index ae01b561db..d74eca1cc1 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1093,12 +1093,12 @@ enum class ssaoMode { struct shaderStage_t; struct Material; - struct MaterialSurface; + struct drawSurf_t; using stageRenderer_t = void(*)(shaderStage_t *); using surfaceDataUpdater_t = void(*)(uint32_t*, shaderStage_t*, bool, bool, bool); using stageShaderBinder_t = void(*)(Material*); - using stageMaterialProcessor_t = void(*)(Material*, shaderStage_t*, MaterialSurface*); + using stageMaterialProcessor_t = void(*)(Material*, shaderStage_t*, drawSurf_t*); enum ShaderStageVariant { VERTEX_OVERBRIGHT = 1, @@ -1637,6 +1637,18 @@ enum class ssaoMode { int fog; int portalNum = -1; + 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; + bool materialSystemSkip = false; + inline int index() const { return int( ( sort & SORT_INDEX_MASK ) ); } @@ -1829,7 +1841,6 @@ enum class ssaoMode { int portalNum; bool renderable = false; - bool BSPModel = false; surfaceType_t *data; // any of srf*_t }; @@ -3078,7 +3089,7 @@ inline bool checkGLErrors() void R_AddPolygonSurfaces(); - void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, int fogNum, bool bspSurface = false, int portalNum = -1 ); + int R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, int fogNum, bool bspSurface = false, int portalNum = -1 ); void R_LocalNormalToWorld( const vec3_t local, vec3_t world ); void R_LocalPointToWorld( const vec3_t local, vec3_t world ); @@ -3369,6 +3380,12 @@ void GLimp_LogComment_( std::string comment ); uint32_t numIndexes; uint32_t numVertexes; + // Material system stuff for setting up correct SSBO offsets + uint materialPackID = 0; + uint materialID = 0; + uint currentSSBOOffset = 0; + drawSurf_t* currentDrawSurf; + // Must be set by the stage iterator function if needed. These are *not* // automatically cleared by the likes of Tess_End. stageVars_t svars; diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index e6befc7ce5..47e938794f 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -1840,7 +1840,7 @@ int R_SpriteFogNum( trRefEntity_t *ent ) R_AddDrawSurf ================= */ -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, int fogNum, bool bspSurface, int portalNum ) +int R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, int fogNum, bool bspSurface, int portalNum ) { // instead of checking for overflow, we just mask the index // so it wraps around @@ -1878,13 +1878,42 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, i tr.refdef.numDrawSurfs++; + // Portal and sky surfaces are not handled by the material system at all + if ( materialSystem.generatingWorldCommandBuffer && ( shader->isPortal || shader->isSky || shader->autoSpriteMode ) ) { + if ( shader->isSky && std::find( materialSystem.skyShaders.begin(), materialSystem.skyShaders.end(), shader ) + == materialSystem.skyShaders.end() ) { + materialSystem.skyShaders.emplace_back( shader ); + } + + if ( shader->isPortal ) + { + // R_AddWorldSurfaces guarantees not to add surfaces more than once + ASSERT_EQ( + std::find( materialSystem.portalSurfacesTmp.begin(), materialSystem.portalSurfacesTmp.end(), drawSurf ), + materialSystem.portalSurfacesTmp.end() ); + materialSystem.portalSurfacesTmp.emplace_back( drawSurf ); + } + + if ( shader->autoSpriteMode ) { + materialSystem.autospriteSurfaces.push_back( *drawSurf ); + } + + return baseIndex; + } + if ( shader->depthShader != nullptr ) { - R_AddDrawSurf( surface, shader->depthShader, 0, 0, bspSurface ); + const int depthSurfIndex = R_AddDrawSurf( surface, shader->depthShader, 0, 0, bspSurface ); + drawSurf->depthSurface = &tr.refdef.drawSurfs[depthSurfIndex]; + drawSurf->depthSurface->materialSystemSkip = true; } if( !shader->noFog && fogNum >= 1 ) { - R_AddDrawSurf( surface, shader->fogShader, 0, fogNum, bspSurface ); + const int fogSurfIndex = R_AddDrawSurf( surface, shader->fogShader, 0, fogNum, bspSurface ); + drawSurf->fogSurface = &tr.refdef.drawSurfs[fogSurfIndex]; + drawSurf->fogSurface->materialSystemSkip = true; } + + return baseIndex; } static uint32_t currentView = 0; @@ -1976,7 +2005,7 @@ static void R_SortDrawSurfs() break; } - R_MirrorViewBySurface( &portalStack[portalStack[currentView].views[i]].drawSurf ); + R_MirrorViewBySurface( portalStack[portalStack[currentView].views[i]].drawSurf ); } currentView--; } else { diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index 4626d9dae0..207b7b93b1 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -652,6 +652,10 @@ void RE_RenderScene( const refdef_t *fd ) R_AddClearBufferCmd(); R_AddSetupLightsCmd(); + if ( glConfig2.usingMaterialSystem && !materialSystem.generatedWorldCommandBuffer ) { + materialSystem.GenerateWorldMaterials(); + } + if ( glConfig2.usingMaterialSystem ) { materialSystem.StartFrame(); } diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index eb281927c0..9ceaef65c6 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -529,6 +529,8 @@ Tess_DrawElements */ void Tess_DrawElements() { + int i; + if ( ( tess.numIndexes == 0 || tess.numVertexes == 0 ) && tess.multiDrawPrimitives == 0 ) { return; @@ -539,12 +541,24 @@ void Tess_DrawElements() { if ( tess.multiDrawPrimitives ) { - glMultiDrawElements( GL_TRIANGLES, tess.multiDrawCounts, GL_INDEX_TYPE, ( const GLvoid** ) tess.multiDrawIndexes, tess.multiDrawPrimitives ); + if ( !materialSystem.generatingWorldCommandBuffer ) { + glMultiDrawElements( GL_TRIANGLES, tess.multiDrawCounts, GL_INDEX_TYPE, ( const GLvoid** ) tess.multiDrawIndexes, tess.multiDrawPrimitives ); + } backEnd.pc.c_multiDrawElements++; backEnd.pc.c_multiDrawPrimitives += tess.multiDrawPrimitives; backEnd.pc.c_vboVertexes += tess.numVertexes; + + for ( i = 0; i < tess.multiDrawPrimitives; i++ ) + { + backEnd.pc.c_multiVboIndexes += tess.multiDrawCounts[ i ]; + backEnd.pc.c_indexes += tess.multiDrawCounts[ i ]; + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddDrawCommand( tess.materialID, tess.materialPackID, tess.currentSSBOOffset, + ( GLuint ) tess.multiDrawCounts[i], tess.multiDrawOffsets[i] ); + } + } } else { @@ -554,7 +568,11 @@ void Tess_DrawElements() base = tess.indexBase * sizeof( glIndex_t ); } - glDrawRangeElements( GL_TRIANGLES, 0, tess.numVertexes, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET( base ) ); + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddDrawCommand( tess.materialID, tess.materialPackID, tess.currentSSBOOffset, tess.numIndexes, tess.indexBase ); + } else { + glDrawRangeElements( GL_TRIANGLES, 0, tess.numVertexes, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET( base ) ); + } backEnd.pc.c_drawElements++; @@ -567,7 +585,11 @@ void Tess_DrawElements() } else { - glDrawElements( GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, tess.indexes ); + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddDrawCommand( tess.materialID, tess.materialPackID, tess.currentSSBOOffset, tess.numIndexes, tess.indexBase ); + } else { + glDrawElements( GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, tess.indexes ); + } backEnd.pc.c_drawElements++; @@ -926,7 +948,7 @@ void Render_lightMapping( shaderStage_t *pStage ) lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( &tess, tess.surfaceShader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( &tess, pStage->type, lightMode, deluxeMode ); // u_Map, u_DeluxeMap image_t *lightmap = SetLightMap( &tess, lightMode ); @@ -2099,7 +2121,7 @@ void Render_liquid( shaderStage_t *pStage ) lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( &tess, tess.surfaceShader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( &tess, pStage->type, lightMode, deluxeMode ); // choose right shader program gl_liquidShader->SetHeightMapInNormalMap( pStage->hasHeightMapInNormalMap ); @@ -2597,7 +2619,7 @@ void Tess_StageIteratorColor() int stage = 0; for ( shaderStage_t *pStage = tess.surfaceStages; pStage < tess.surfaceLastStage; pStage++ ) { - if ( !RB_EvalExpression( &pStage->ifExp, 1.0 ) ) + if ( !RB_EvalExpression( &pStage->ifExp, 1.0 ) && !( materialSystem.generatingWorldCommandBuffer && pStage->useMaterialSystem ) ) { continue; } @@ -2613,6 +2635,12 @@ void Tess_StageIteratorColor() Tess_ComputeColor( pStage ); Tess_ComputeTexMatrices( pStage ); + if ( materialSystem.generatingWorldCommandBuffer && pStage->useMaterialSystem ) { + tess.currentSSBOOffset = pStage->materialOffset; + tess.materialID = tess.currentDrawSurf->materialIDs[stage]; + tess.materialPackID = tess.currentDrawSurf->materialPackIDs[stage]; + } + pStage->colorRenderer( pStage ); stage++; diff --git a/src/engine/renderer/tr_world.cpp b/src/engine/renderer/tr_world.cpp index 43b746845d..8d3fd19172 100644 --- a/src/engine/renderer/tr_world.cpp +++ b/src/engine/renderer/tr_world.cpp @@ -405,7 +405,7 @@ static void R_RecursiveWorldNode( bspNode_t *node, int planeBits ) do { // if the node wasn't marked as potentially visible, exit - if ( node->visCounts[ tr.visIndex ] != tr.visCounts[ tr.visIndex ] ) + if ( node->visCounts[ tr.visIndex ] != tr.visCounts[ tr.visIndex ] && !materialSystem.generatingWorldCommandBuffer ) { return; }