From b27d094defa12578311c0c93d9d5a950a2ff7995 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 May 2025 22:43:30 +0200 Subject: [PATCH] Improve GetVisibleSurfaces performance --- src/rendering/hwrenderer/doom_levelmesh.cpp | 92 ++++++++++++++++----- src/rendering/hwrenderer/doom_levelmesh.h | 8 ++ 2 files changed, 81 insertions(+), 19 deletions(-) diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 8ff8ce032..a257ec36e 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -228,6 +228,9 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap) r_viewpoint.extralight = 0; r_viewpoint.camera = nullptr; + BuildSideVisibilityLists(doomMap); + BuildSubsectorVisibilityLists(doomMap); + BuildSectorGroups(doomMap); CreatePortals(doomMap); CreateSurfaces(doomMap); @@ -251,6 +254,34 @@ DoomLevelMesh::~DoomLevelMesh() { } +void DoomLevelMesh::BuildSideVisibilityLists(FLevelLocals& doomMap) +{ + VisibleSides.resize(doomMap.sides.size()); + for (size_t i = 0, count = VisibleSides.size(); i < count; i++) + { + side_t* side = &doomMap.sides[i]; + + // Always bake the side + VisibleSides[i].Push(i); + + // To do: use side->LeftSide and side->RightSide or maybe blockmap to find sides closeby we also want included in the bake + } +} + +void DoomLevelMesh::BuildSubsectorVisibilityLists(FLevelLocals& doomMap) +{ + VisibleSubsectors.resize(doomMap.subsectors.size()); + for (size_t i = 0, count = VisibleSubsectors.size(); i < count; i++) + { + subsector_t* sub = &doomMap.subsectors[i]; + + // Always bake the subsector + VisibleSubsectors[i].Push(i); + + // To do: use sub->firstline to find neighbouring subsectors we want included in a tile bake + } +} + void DoomLevelMesh::SetLimits(FLevelLocals& doomMap) { // Try to estimate what the worst case memory needs are for the level @@ -529,7 +560,10 @@ void DoomLevelMesh::CreateSurfaces(FLevelLocals& doomMap) Sides.clear(); Flats.clear(); Sides.resize(doomMap.sides.size()); - Flats.resize(doomMap.sectors.Size()); + Flats.resize(doomMap.sectors.size()); + SubsectorSurfaces.resize(doomMap.subsectors.size()); + for (int& i : SubsectorSurfaces) + i = -1; // Create surface objects for all sides for (unsigned int i = 0; i < doomMap.sides.Size(); i++) @@ -618,6 +652,14 @@ void DoomLevelMesh::FreeFlat(FLevelLocals& doomMap, unsigned int sectorIndex) if (sectorIndex < 0 || sectorIndex >= Flats.Size()) return; + for (FSection& section : level.sections.SectionsForSector(&doomMap.sectors[sectorIndex])) + { + for (subsector_t* subsector : section.subsectors) + { + SubsectorSurfaces[subsector->Index()] = -1; + } + } + ReleaseTiles(Flats[sectorIndex].FirstSurface); int surf = Flats[sectorIndex].FirstSurface; @@ -1067,6 +1109,20 @@ void DoomLevelMesh::CreateFlat(FLevelLocals& doomMap, unsigned int sectorIndex) lightlistSection++; } + + // Sort the generated surfaces into subsectors + int surf = Flats[sectorIndex].FirstSurface; + while (surf != -1) + { + auto& sinfo = DoomSurfaceInfos[surf]; + if (sinfo.Subsector) + { + int subsectorIndex = sinfo.Subsector->Index(); + sinfo.NextSubsectorSurface = SubsectorSurfaces[subsectorIndex]; + SubsectorSurfaces[subsectorIndex] = surf; + } + surf = sinfo.NextSurface; + } } void DoomLevelMesh::SetSideLights(FLevelLocals& doomMap, unsigned int sideIndex) @@ -1733,37 +1789,35 @@ void DoomLevelMesh::GetVisibleSurfaces(LightmapTile* tile, TArray& outSurfa { if (tile->Binding.Type == ST_MIDDLESIDE || tile->Binding.Type == ST_UPPERSIDE || tile->Binding.Type == ST_LOWERSIDE) { - int sideIndex = tile->Binding.TypeIndex; - int surf = Sides[sideIndex].FirstSurface; - while (surf != -1) + for (int sideIndex : VisibleSides[tile->Binding.TypeIndex]) { - const auto& sinfo = DoomSurfaceInfos[surf]; - if (sinfo.Type == tile->Binding.Type) + int surf = Sides[sideIndex].FirstSurface; + while (surf != -1) { - outSurfaces.Push(surf); + const auto& sinfo = DoomSurfaceInfos[surf]; + if (sinfo.Type == tile->Binding.Type) + { + outSurfaces.Push(surf); + } + surf = sinfo.NextSurface; } - surf = sinfo.NextSurface; } } else if (tile->Binding.Type == ST_CEILING || tile->Binding.Type == ST_FLOOR) { - int subsectorIndex = tile->Binding.TypeIndex; - int sectorIndex = level.subsectors[subsectorIndex].sector->Index(); - int surf = Flats[sectorIndex].FirstSurface; - while (surf != -1) + for (int subsectorIndex : VisibleSubsectors[tile->Binding.TypeIndex]) { - const auto& sinfo = DoomSurfaceInfos[surf]; - int controlSector = sinfo.ControlSector ? sinfo.ControlSector->Index() : (int)0xffffffffUL; - if (sinfo.Type == tile->Binding.Type && controlSector == tile->Binding.ControlSector) + int surf = SubsectorSurfaces[subsectorIndex]; + while (surf != -1) { - FVector2 minUV = tile->ToUV(Mesh.Surfaces[surf].Bounds.min); - FVector2 maxUV = tile->ToUV(Mesh.Surfaces[surf].Bounds.max); - if (!(maxUV.X < 0.0f || maxUV.Y < 0.0f || minUV.X > 1.0f || minUV.Y > 1.0f)) + const auto& sinfo = DoomSurfaceInfos[surf]; + int controlSector = sinfo.ControlSector ? sinfo.ControlSector->Index() : (int)0xffffffffUL; + if (sinfo.Type == tile->Binding.Type && controlSector == tile->Binding.ControlSector) { outSurfaces.Push(surf); } + surf = sinfo.NextSubsectorSurface; } - surf = sinfo.NextSurface; } } } diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 61cc11322..b923f41b9 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -31,6 +31,7 @@ struct DoomSurfaceInfo int LightListSection = 0; int NextSurface = -1; + int NextSubsectorSurface = -1; }; struct GeometryFreeInfo @@ -203,15 +204,22 @@ private: void ReleaseTiles(int surfaceIndex); + void BuildSideVisibilityLists(FLevelLocals& doomMap); + void BuildSubsectorVisibilityLists(FLevelLocals& doomMap); + TArray DoomSurfaceInfos; TArray Sides; TArray Flats; + TArray SubsectorSurfaces; TArray PolySides; TArray SideUpdateList; TArray FlatUpdateList; + TArray> VisibleSides; + TArray> VisibleSubsectors; + std::map TileBindings; MeshBuilder state; };