From d12cd4d74dfa51682a74183d9fddf2077061ba19 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 28 Aug 2024 19:53:12 +0200 Subject: [PATCH] Sort initial draw lists by pipeline Fix applying pipeline state too often for scattered draw ranges Delay updating sides and sectors until frame start to allow the playsim to mark surfaces dirty multiple times --- .../rendering/hwrenderer/data/hw_levelmesh.h | 8 + src/common/rendering/vulkan/vk_levelmesh.cpp | 10 + src/common/rendering/vulkan/vk_levelmesh.h | 2 + .../rendering/vulkan/vk_renderstate.cpp | 23 +- src/common/rendering/vulkan/vk_renderstate.h | 2 +- src/rendering/hwrenderer/doom_levelmesh.cpp | 229 ++++++++++++++---- src/rendering/hwrenderer/doom_levelmesh.h | 33 ++- 7 files changed, 252 insertions(+), 55 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index ee1df91c1..1df2d3fb5 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -167,10 +167,13 @@ public: Mesh.Indexes.Resize(limits.MaxIndexes); Mesh.SurfaceIndexes.Resize(limits.MaxIndexes / 3 + 1); + Mesh.DrawIndexes.Resize(limits.MaxIndexes); + FreeLists.Vertex.Clear(); FreeLists.Vertex.Push({ 0, limits.MaxVertices }); FreeLists.Index.Clear(); FreeLists.Index.Push({ 0, limits.MaxIndexes }); FreeLists.Uniforms.Clear(); FreeLists.Uniforms.Push({ 0, limits.MaxUniforms }); FreeLists.Surface.Clear(); FreeLists.Surface.Push({ 0, limits.MaxSurfaces }); + FreeLists.DrawIndex.Clear(); FreeLists.DrawIndex.Push({ 0, limits.MaxIndexes }); } // Data placed in GPU buffers @@ -194,6 +197,9 @@ public: TArray SurfaceIndexes; int IndexCount = 0; // Index range filled with data + // Indexes sorted by pipeline + TArray DrawIndexes; + // GPU buffer size for collision nodes int MaxNodes = 0; } Mesh; @@ -211,6 +217,7 @@ public: TArray Portals; TArray Light; TArray LightIndex; + TArray DrawIndex; } UploadRanges; // Ranges in mesh currently not in use @@ -220,6 +227,7 @@ public: TArray Index; TArray Uniforms; TArray Surface; + TArray DrawIndex; } FreeLists; // Data structure for doing mesh traces on the CPU diff --git a/src/common/rendering/vulkan/vk_levelmesh.cpp b/src/common/rendering/vulkan/vk_levelmesh.cpp index cf163cdf9..ce0a2b9e4 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.cpp +++ b/src/common/rendering/vulkan/vk_levelmesh.cpp @@ -57,6 +57,7 @@ void VkLevelMesh::Reset() deletelist->Add(std::move(PortalBuffer)); deletelist->Add(std::move(LightBuffer)); deletelist->Add(std::move(LightIndexBuffer)); + deletelist->Add(std::move(DrawIndexBuffer)); deletelist->Add(std::move(DynamicBLAS.ScratchBuffer)); deletelist->Add(std::move(DynamicBLAS.AccelStructBuffer)); deletelist->Add(std::move(DynamicBLAS.AccelStruct)); @@ -197,6 +198,12 @@ void VkLevelMesh::CreateBuffers() .DebugName("IndexBuffer") .Create(fb->GetDevice()); + DrawIndexBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) + .Size((size_t)Mesh->Mesh.DrawIndexes.Size() * sizeof(uint32_t)) + .DebugName("DrawIndexBuffer") + .Create(fb->GetDevice()); + NodeBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) .Size(sizeof(CollisionNodeBufferHeader) + Mesh->Mesh.MaxNodes * sizeof(CollisionNode)) @@ -440,6 +447,7 @@ void VkLevelMeshUploader::Upload() UploadRanges(Mesh->Mesh->UploadRanges.Index, Mesh->Mesh->Mesh.Indexes.Data(), Mesh->IndexBuffer.get()); UploadRanges(Mesh->Mesh->UploadRanges.SurfaceIndex, Mesh->Mesh->Mesh.SurfaceIndexes.Data(), Mesh->SurfaceIndexBuffer.get()); UploadRanges(Mesh->Mesh->UploadRanges.LightIndex, Mesh->Mesh->Mesh.LightIndexes.Data(), Mesh->LightIndexBuffer.get()); + UploadRanges(Mesh->Mesh->UploadRanges.DrawIndex, Mesh->Mesh->Mesh.DrawIndexes.Data(), Mesh->DrawIndexBuffer.get()); UploadSurfaces(); UploadUniforms(); UploadPortals(); @@ -471,6 +479,7 @@ void VkLevelMeshUploader::ClearRanges() Mesh->Mesh->UploadRanges.Portals.clear(); Mesh->Mesh->UploadRanges.Light.clear(); Mesh->Mesh->UploadRanges.LightIndex.clear(); + Mesh->Mesh->UploadRanges.DrawIndex.clear(); } void VkLevelMeshUploader::BeginTransfer(size_t transferBufferSize) @@ -681,5 +690,6 @@ size_t VkLevelMeshUploader::GetTransferSize() for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Portals) transferBufferSize += range.Count() * sizeof(PortalInfo); for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.LightIndex) transferBufferSize += range.Count() * sizeof(int32_t); for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Light) transferBufferSize += range.Count() * sizeof(LightInfo); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.DrawIndex) transferBufferSize += range.Count() * sizeof(uint32_t); return transferBufferSize; } diff --git a/src/common/rendering/vulkan/vk_levelmesh.h b/src/common/rendering/vulkan/vk_levelmesh.h index e43f3e6d2..6247ea15f 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.h +++ b/src/common/rendering/vulkan/vk_levelmesh.h @@ -83,6 +83,7 @@ public: VulkanBuffer* GetPortalBuffer() { return PortalBuffer.get(); } VulkanBuffer* GetLightBuffer() { return LightBuffer.get(); } VulkanBuffer* GetLightIndexBuffer() { return LightIndexBuffer.get(); } + VulkanBuffer* GetDrawIndexBuffer() { return DrawIndexBuffer.get(); } LevelMesh* GetMesh() { return Mesh; } @@ -122,6 +123,7 @@ private: std::unique_ptr PortalBuffer; std::unique_ptr LightBuffer; std::unique_ptr LightIndexBuffer; + std::unique_ptr DrawIndexBuffer; std::unique_ptr NodeBuffer; diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index 2df40a53b..e902a2681 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -842,7 +842,7 @@ void VkRenderState::ApplyLevelMesh() VkBuffer vertexBuffers[2] = { fb->GetLevelMesh()->GetVertexBuffer()->buffer, fb->GetLevelMesh()->GetUniformIndexBuffer()->buffer }; VkDeviceSize vertexBufferOffsets[] = { 0, 0 }; mCommandBuffer->bindVertexBuffers(0, 2, vertexBuffers, vertexBufferOffsets); - mCommandBuffer->bindIndexBuffer(fb->GetLevelMesh()->GetIndexBuffer()->buffer, 0, VK_INDEX_TYPE_UINT32); + mCommandBuffer->bindIndexBuffer(fb->GetLevelMesh()->GetDrawIndexBuffer()->buffer, 0, VK_INDEX_TYPE_UINT32); } void VkRenderState::DrawLevelMeshSurfaces(bool noFragmentShader) @@ -854,9 +854,12 @@ void VkRenderState::DrawLevelMeshSurfaces(bool noFragmentShader) { int pipelineID = it.first; const VkPipelineKey& key = fb->GetLevelMeshPipelineKey(pipelineID); - for (MeshBufferRange& range : it.second) + if (ApplyLevelMeshPipeline(mCommandBuffer, key, noFragmentShader)) { - DrawLevelMeshRange(mCommandBuffer, key, range.Start, range.End - range.Start, noFragmentShader); + for (MeshBufferRange& range : it.second) + { + mCommandBuffer->drawIndexed(range.End - range.Start, 1, range.Start, 0, 0); + } } } } @@ -870,9 +873,12 @@ void VkRenderState::DrawLevelMeshPortals(bool noFragmentShader) { int pipelineID = it.first; const VkPipelineKey& key = fb->GetLevelMeshPipelineKey(pipelineID); - for (MeshBufferRange& range : it.second) + if (ApplyLevelMeshPipeline(mCommandBuffer, key, noFragmentShader)) { - DrawLevelMeshRange(mCommandBuffer, key, range.Start, range.End - range.Start, noFragmentShader); + for (MeshBufferRange& range : it.second) + { + mCommandBuffer->drawIndexed(range.End - range.Start, 1, range.Start, 0, 0); + } } } } @@ -909,10 +915,10 @@ void VkRenderState::GetQueryResults(int queryStart, int queryCount, TArray } } -void VkRenderState::DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, int start, int count, bool noFragmentShader) +bool VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, bool noFragmentShader) { if (noFragmentShader && pipelineKey.ShaderKey.AlphaTest) - return; + return false; pipelineKey.ShaderKey.NoFragmentShader = noFragmentShader; pipelineKey.DepthTest = mDepthTest; @@ -945,7 +951,8 @@ void VkRenderState::DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, VkPipelin cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetLevelMeshSet(), 4, offsets); cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptors->GetBindlessSet()); cmdbuffer->pushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &pushConstants); - cmdbuffer->drawIndexed(count, 1, start, 0, 0); + + return true; } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/common/rendering/vulkan/vk_renderstate.h b/src/common/rendering/vulkan/vk_renderstate.h index e3bd07754..3e297759f 100644 --- a/src/common/rendering/vulkan/vk_renderstate.h +++ b/src/common/rendering/vulkan/vk_renderstate.h @@ -89,7 +89,7 @@ protected: void WaitForStreamBuffers(); void ApplyLevelMesh(); - void DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, int start, int count, bool noFragmentShader); + bool ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, bool noFragmentShader); VulkanRenderDevice* fb = nullptr; diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 4587f69a9..f1477db3f 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -60,6 +60,13 @@ ADD_STAT(lightmap) return out; } +ADD_STAT(levelmesh) +{ + FString out; + out.Format("Sides=%d, flats=%d", level.levelMesh->LastFrameStats.SidesUpdated, level.levelMesh->LastFrameStats.FlatsUpdated); + return out; +} + CCMD(dumplevelmesh) { if (!RequireLevelMesh()) return; @@ -172,16 +179,35 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap) Mesh.MaxNodes = std::max(Collision->get_nodes().size() * 2, (size_t)10000); UploadPortals(); + + SortDrawLists(); } void DoomLevelMesh::BeginFrame(FLevelLocals& doomMap) { + LastFrameStats = CurFrameStats; + CurFrameStats = Stats(); + // To do: we don't need to always do this. UpdateLevelMesh should tell us when polyobjs move. for (side_t* side : PolySides) { - UpdateSide(doomMap, side->Index()); + UpdateSide(side->Index()); } + for (int sideIndex : SideUpdateList) + { + CreateSide(doomMap, sideIndex); + Sides[sideIndex].InUpdateList = false; + } + SideUpdateList.Clear(); + + for (int flatIndex : FlatUpdateList) + { + CreateFlat(doomMap, flatIndex); + Flats[flatIndex].InUpdateList = false; + } + FlatUpdateList.Clear(); + CreateLights(doomMap); UpdateWallPortals(); } @@ -366,7 +392,7 @@ void DoomLevelMesh::CreateSurfaces(FLevelLocals& doomMap) continue; } - UpdateSide(doomMap, i); + CreateSide(doomMap, i); } // Create surfaces for all flats @@ -375,7 +401,7 @@ void DoomLevelMesh::CreateSurfaces(FLevelLocals& doomMap) sector_t* sector = &doomMap.sectors[i]; if (sector->subsectorcount == 0 || sector->subsectors[0]->flags & SSECF_POLYORG) continue; - UpdateFlat(doomMap, i); + CreateFlat(doomMap, i); } } @@ -394,15 +420,12 @@ void DoomLevelMesh::FreeSide(FLevelLocals& doomMap, unsigned int sideIndex) Sides[sideIndex].FirstSurface = -1; for (auto& geo : Sides[sideIndex].Geometries) - { FreeGeometry(geo.VertexStart, geo.VertexCount, geo.IndexStart, geo.IndexCount); - if (!geo.IsPortal) - RemoveRange(DrawList[geo.PipelineID], { geo.IndexStart, geo.IndexStart + geo.IndexCount }); - else - RemoveRange(PortalList[geo.PipelineID], { geo.IndexStart, geo.IndexStart + geo.IndexCount }); - } Sides[sideIndex].Geometries.Clear(); + RemoveFromDrawList(Sides[sideIndex].DrawRanges); + Sides[sideIndex].DrawRanges.Clear(); + for (auto& uni : Sides[sideIndex].Uniforms) FreeUniforms(uni.Start, uni.Count); Sides[sideIndex].Uniforms.Clear(); @@ -425,15 +448,12 @@ void DoomLevelMesh::FreeFlat(FLevelLocals& doomMap, unsigned int sectorIndex) Flats[sectorIndex].FirstSurface = -1; for (auto& geo : Flats[sectorIndex].Geometries) - { FreeGeometry(geo.VertexStart, geo.VertexCount, geo.IndexStart, geo.IndexCount); - if (!geo.IsPortal) - RemoveRange(DrawList[geo.PipelineID], { geo.IndexStart, geo.IndexStart + geo.IndexCount }); - else - RemoveRange(PortalList[geo.PipelineID], { geo.IndexStart, geo.IndexStart + geo.IndexCount }); - } Flats[sectorIndex].Geometries.Clear(); + RemoveFromDrawList(Flats[sectorIndex].DrawRanges); + Flats[sectorIndex].DrawRanges.Clear(); + for (auto& uni : Flats[sectorIndex].Uniforms) FreeUniforms(uni.Start, uni.Count); Flats[sectorIndex].Uniforms.Clear(); @@ -441,51 +461,51 @@ void DoomLevelMesh::FreeFlat(FLevelLocals& doomMap, unsigned int sectorIndex) void DoomLevelMesh::FloorHeightChanged(struct sector_t* sector) { - UpdateFlat(level, sector->Index()); + UpdateFlat(sector->Index()); for (line_t* line : sector->Lines) { if (line->sidedef[0]) - UpdateSide(level, line->sidedef[0]->Index()); + UpdateSide(line->sidedef[0]->Index()); if (line->sidedef[1]) - UpdateSide(level, line->sidedef[1]->Index()); + UpdateSide(line->sidedef[1]->Index()); } } void DoomLevelMesh::CeilingHeightChanged(struct sector_t* sector) { - UpdateFlat(level, sector->Index()); + UpdateFlat(sector->Index()); for (line_t* line : sector->Lines) { if (line->sidedef[0]) - UpdateSide(level, line->sidedef[0]->Index()); + UpdateSide(line->sidedef[0]->Index()); if (line->sidedef[1]) - UpdateSide(level, line->sidedef[1]->Index()); + UpdateSide(line->sidedef[1]->Index()); } } void DoomLevelMesh::MidTex3DHeightChanged(struct sector_t* sector) { - // UpdateFlat(level, sector->Index()); + // UpdateFlat(sector->Index()); } void DoomLevelMesh::FloorTextureChanged(struct sector_t* sector) { - UpdateFlat(level, sector->Index()); + UpdateFlat(sector->Index()); } void DoomLevelMesh::CeilingTextureChanged(struct sector_t* sector) { - UpdateFlat(level, sector->Index()); + UpdateFlat(sector->Index()); } void DoomLevelMesh::SectorChangedOther(struct sector_t* sector) { - UpdateFlat(level, sector->Index()); + UpdateFlat(sector->Index()); } void DoomLevelMesh::SideTextureChanged(struct side_t* side, int section) { - UpdateSide(level, side->Index()); + UpdateSide(side->Index()); } void DoomLevelMesh::SectorLightChanged(struct sector_t* sector) @@ -495,9 +515,9 @@ void DoomLevelMesh::SectorLightChanged(struct sector_t* sector) for (line_t* line : sector->Lines) { if (line->frontsector == sector && line->sidedef[0]) - UpdateSide(level, line->sidedef[0]->Index()); + UpdateSide(line->sidedef[0]->Index()); else if (line->sidedef[1]) - UpdateSide(level, line->sidedef[1]->Index()); + UpdateSide(line->sidedef[1]->Index()); } */ } @@ -510,8 +530,28 @@ void DoomLevelMesh::SectorLightThinkerDestroyed(struct sector_t* sector, class D { } -void DoomLevelMesh::UpdateSide(FLevelLocals& doomMap, unsigned int sideIndex) +void DoomLevelMesh::UpdateSide(unsigned int sideIndex) { + if (!Sides[sideIndex].InUpdateList) + { + SideUpdateList.Push(sideIndex); + Sides[sideIndex].InUpdateList = true; + } +} + +void DoomLevelMesh::UpdateFlat(unsigned int sectorIndex) +{ + if (!Flats[sectorIndex].InUpdateList) + { + FlatUpdateList.Push(sectorIndex); + Flats[sectorIndex].InUpdateList = true; + } +} + +void DoomLevelMesh::CreateSide(FLevelLocals& doomMap, unsigned int sideIndex) +{ + CurFrameStats.SidesUpdated++; + FreeSide(doomMap, sideIndex); side_t* side = &doomMap.sides[sideIndex]; @@ -576,8 +616,10 @@ void DoomLevelMesh::UpdateSide(FLevelLocals& doomMap, unsigned int sideIndex) */ } -void DoomLevelMesh::UpdateFlat(FLevelLocals& doomMap, unsigned int sectorIndex) +void DoomLevelMesh::CreateFlat(FLevelLocals& doomMap, unsigned int sectorIndex) { + CurFrameStats.FlatsUpdated++; + FreeFlat(doomMap, sectorIndex); sector_t* sector = &doomMap.sectors[sectorIndex]; @@ -751,15 +793,121 @@ void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, Mesh Sides[sideIndex].Geometries.Push({ ginfo, pipelineID, sinfo.Surface->IsSky }); Sides[sideIndex].Uniforms.Push(uinfo); - if (!sinfo.Surface->IsSky) - { - AddRange(DrawList[pipelineID], { ginfo.IndexStart, ginfo.IndexStart + ginfo.IndexCount }); - } + AddToDrawList(Sides[sideIndex].DrawRanges, pipelineID, ginfo.IndexStart, ginfo.IndexCount, sinfo.Surface->IsSky); + } +} + +void DoomLevelMesh::AddToDrawList(TArray& drawRanges, int pipelineID, int indexStart, int indexCount, bool isPortal) +{ + // Remember the location if we have to remove it again + DrawRangeInfo info; + info.DrawIndexStart = RemoveRange(FreeLists.DrawIndex, indexCount); + info.DrawIndexCount = indexCount; + info.IsPortal = isPortal; + info.PipelineID = pipelineID; + drawRanges.Push(info); + + // Copy the indexes over from the unsorted index list + memcpy(&Mesh.DrawIndexes[info.DrawIndexStart], &Mesh.Indexes[indexStart], indexCount * sizeof(uint32_t)); + AddRange(UploadRanges.DrawIndex, { info.DrawIndexStart, info.DrawIndexStart + indexCount }); + + // Add to the draw lists + if (!isPortal) + { + AddRange(DrawList[pipelineID], { info.DrawIndexStart, info.DrawIndexStart + indexCount }); + } + else + { + AddRange(PortalList[pipelineID], { info.DrawIndexStart, info.DrawIndexStart + indexCount }); + } +} + +void DoomLevelMesh::RemoveFromDrawList(const TArray& drawRanges) +{ + for (const DrawRangeInfo& info : drawRanges) + { + int start = info.DrawIndexStart; + int end = info.DrawIndexStart + info.DrawIndexCount; + + if (!info.IsPortal) + RemoveRange(DrawList[info.PipelineID], { start, end }); else + RemoveRange(PortalList[info.PipelineID], { start, end }); + + AddRange(FreeLists.DrawIndex, { start, end }); + } +} + +void DoomLevelMesh::SortDrawLists() +{ + std::unordered_map> sortedDrawList; + std::unordered_map> sortedPortalList; + + for (auto& side : Sides) + { + for (auto& range : side.DrawRanges) { - AddRange(PortalList[pipelineID], { ginfo.IndexStart, ginfo.IndexStart + ginfo.IndexCount }); + if (!range.IsPortal) + sortedDrawList[range.PipelineID].Push(&range); + else + sortedPortalList[range.PipelineID].Push(&range); } } + + for (auto& flat : Flats) + { + for (auto& range : flat.DrawRanges) + { + if (!range.IsPortal) + sortedDrawList[range.PipelineID].Push(&range); + else + sortedPortalList[range.PipelineID].Push(&range); + } + } + + TArray indexes; + + DrawList.clear(); + for (auto& it : sortedDrawList) + { + auto& list = DrawList[it.first]; + int listStart = indexes.Size(); + for (DrawRangeInfo* range : it.second) + { + int sortedStart = indexes.Size(); + int start = range->DrawIndexStart; + int count = range->DrawIndexCount; + for (int i = 0; i < count; i++) + { + indexes.Push(Mesh.DrawIndexes[start + i]); + } + range->DrawIndexStart = sortedStart; + } + int listEnd = indexes.Size(); + list.Push({ listStart, listEnd }); + } + + PortalList.clear(); + for (auto& it : sortedPortalList) + { + auto& list = PortalList[it.first]; + int listStart = indexes.Size(); + for (DrawRangeInfo* range : it.second) + { + int sortedStart = indexes.Size(); + int start = range->DrawIndexStart; + int count = range->DrawIndexCount; + for (int i = 0; i < count; i++) + { + indexes.Push(Mesh.DrawIndexes[start + i]); + } + range->DrawIndexStart = sortedStart; + } + int listEnd = indexes.Size(); + list.Push({ listStart, listEnd }); + } + + memcpy(Mesh.DrawIndexes.Data(), indexes.Data(), indexes.Size() * sizeof(uint32_t)); } int DoomLevelMesh::AddSurfaceToTile(const DoomSurfaceInfo& info, const LevelMeshSurface& surf, uint16_t sampleDimension, bool alwaysUpdate) @@ -897,15 +1045,6 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state Flats[sectorIndex].Geometries.Push({ ginfo, pipelineID, isSky }); Flats[sectorIndex].Uniforms.Push(uinfo); - if (!isSky) - { - AddRange(DrawList[pipelineID], { ginfo.IndexStart, ginfo.IndexStart + ginfo.IndexCount }); - } - else - { - AddRange(PortalList[pipelineID], { ginfo.IndexStart, ginfo.IndexStart + ginfo.IndexCount }); - } - int* surfaceIndexes = &Mesh.SurfaceIndexes[ginfo.IndexStart / 3]; *uinfo.Uniforms = *uniforms; @@ -1019,6 +1158,8 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state SetSubsectorLightmap(sinfo.Index); } + + AddToDrawList(Flats[sectorIndex].DrawRanges, pipelineID, ginfo.IndexStart, ginfo.IndexCount, isSky); } } diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 7529a153f..515e837d4 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -50,6 +50,14 @@ struct GeometryFreeInfo bool IsPortal = false; }; +struct DrawRangeInfo +{ + int PipelineID = 0; + bool IsPortal = false; + int DrawIndexStart = 0; + int DrawIndexCount = 0; +}; + struct SideSurfaceBlock { int FirstSurface = -1; @@ -57,6 +65,8 @@ struct SideSurfaceBlock TArray Uniforms; TArray WallPortals; bool InSidePortalsList = false; + TArray DrawRanges; + bool InUpdateList = false; }; struct FlatSurfaceBlock @@ -64,6 +74,8 @@ struct FlatSurfaceBlock int FirstSurface = -1; TArray Geometries; TArray Uniforms; + TArray DrawRanges; + bool InUpdateList = false; }; class DoomLevelMesh : public LevelMesh, public UpdateLevelMesh @@ -105,12 +117,22 @@ public: DoomSurfaceInfos.Resize(limits.MaxSurfaces); } + struct Stats + { + int FlatsUpdated = 0; + int SidesUpdated = 0; + }; + Stats LastFrameStats, CurFrameStats; + private: void CreateSurfaces(FLevelLocals& doomMap); void CreateLightList(FLevelLocals& doomMap, int surfaceIndex); - void UpdateSide(FLevelLocals& doomMap, unsigned int sideIndex); - void UpdateFlat(FLevelLocals& doomMap, unsigned int sectorIndex); + void UpdateSide(unsigned int sideIndex); + void UpdateFlat(unsigned int sectorIndex); + + void CreateSide(FLevelLocals& doomMap, unsigned int sideIndex); + void CreateFlat(FLevelLocals& doomMap, unsigned int sectorIndex); void FreeSide(FLevelLocals& doomMap, unsigned int sideIndex); void FreeFlat(FLevelLocals& doomMap, unsigned int sectorIndex); @@ -133,6 +155,10 @@ private: int GetLightIndex(FDynamicLight* light, int portalgroup); + void AddToDrawList(TArray& drawRanges, int pipelineID, int indexStart, int indexCount, bool isPortal); + void RemoveFromDrawList(const TArray& drawRanges); + void SortDrawLists(); + TArray DoomSurfaceInfos; TArray> PolyDoomSurfaceInfos; @@ -140,6 +166,9 @@ private: TArray Flats; TArray PolySides; + TArray SideUpdateList; + TArray FlatUpdateList; + std::map bindings; MeshBuilder state; bool LightsCreated = false;