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;