diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp index ebf2d0b1d..6892be941 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp @@ -42,7 +42,7 @@ void LevelMesh::AddEmptyMesh() for (int i = 0; i < 3 * 4; i++) Mesh.Indexes.Push(i); - MarkAllDirty(); + UploadAll(); } LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, float maxDist) @@ -111,7 +111,7 @@ LevelMeshTileStats LevelMesh::GatherTilePixelStats() void LevelMesh::UpdateCollision() { Collision = std::make_unique(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.Indexes.Size()); - MarkCollisionDirty(); + UploadCollision(); } struct LevelMeshPlaneGroup diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index dda3971b7..93d39beca 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -48,6 +48,8 @@ struct MeshBufferRange { int Offset = 0; int Size = 0; + + bool operator<(const MeshBufferRange& other) const { return Offset < other.Offset; } }; class LevelMesh @@ -83,7 +85,11 @@ public: info.Vertices = &Mesh.Vertices[info.VertexStart]; info.UniformIndexes = &Mesh.UniformIndexes[info.VertexStart]; info.Indexes = &Mesh.Indexes[info.IndexStart]; - // To do: mark range as dirty + + AddRange(UploadRanges.Vertex, { info.VertexStart, info.VertexCount }); + AddRange(UploadRanges.UniformIndexes, { info.VertexStart, info.VertexCount }); + AddRange(UploadRanges.Index, { info.IndexStart, info.IndexCount }); + return info; } @@ -96,27 +102,33 @@ public: Mesh.Materials.Resize(info.Start + count); info.Uniforms = &Mesh.Uniforms[info.Start]; info.Materials = &Mesh.Materials[info.Start]; - // To do: mark range as dirty + + AddRange(UploadRanges.Uniforms, { info.Start, info.Count }); + return info; } void FreeGeometry(int vertexStart, int vertexCount, int indexStart, int indexCount) { + // Convert triangles to degenerates for (int i = 0; i < indexCount; i++) Mesh.Indexes[indexStart + i] = 0; - // To do: add to a free list - // To do: mark range as dirty + AddRange(UploadRanges.Index, { indexStart, indexCount }); + + AddRange(FreeLists.Vertex, { vertexStart, vertexCount }); + AddRange(FreeLists.Index, { indexStart, indexCount }); } void FreeUniforms(int start, int count) { - // To do: add to a free list + AddRange(FreeLists.Uniforms, { start, count }); } void FreeSurface(unsigned int surfaceIndex) { // To do: remove the surface from the surface tile, if attached - // To do: add to a free list + + AddRange(FreeLists.Surface, { (int)surfaceIndex, 1 }); } struct @@ -161,7 +173,15 @@ public: TArray Portals; TArray Light; TArray LightIndex; - } DirtyRanges; + } UploadRanges; + + struct + { + TArray Vertex; + TArray Index; + TArray Uniforms; + TArray Surface; + } FreeLists; std::unique_ptr Collision; @@ -186,38 +206,68 @@ public: void AddEmptyMesh(); - void MarkAllDirty() + void UploadAll() { - DirtyRanges.Vertex.Clear(); - DirtyRanges.Vertex.Push({ 0, (int)Mesh.Vertices.Size() }); - DirtyRanges.Index.Clear(); - DirtyRanges.Index.Push({ 0, (int)Mesh.Indexes.Size() }); - DirtyRanges.SurfaceIndex.Clear(); - DirtyRanges.SurfaceIndex.Push({ 0, (int)Mesh.SurfaceIndexes.Size() }); - DirtyRanges.Surface.Clear(); - DirtyRanges.Surface.Push({ 0, GetSurfaceCount() }); - DirtyRanges.UniformIndexes.Clear(); - DirtyRanges.UniformIndexes.Push({ 0, (int)Mesh.UniformIndexes.Size() }); - DirtyRanges.Uniforms.Clear(); - DirtyRanges.Uniforms.Push({ 0, (int)Mesh.Uniforms.Size() }); - DirtyRanges.Portals.Clear(); - DirtyRanges.Portals.Push({ 0, (int)Portals.Size() }); - DirtyRanges.Light.Clear(); - DirtyRanges.Light.Push({ 0, (int)Mesh.Lights.Size() }); - DirtyRanges.LightIndex.Clear(); - DirtyRanges.LightIndex.Push({ 0, (int)Mesh.LightIndexes.Size() }); + UploadRanges.Vertex.Clear(); + UploadRanges.Vertex.Push({ 0, (int)Mesh.Vertices.Size() }); + UploadRanges.Index.Clear(); + UploadRanges.Index.Push({ 0, (int)Mesh.Indexes.Size() }); + UploadRanges.SurfaceIndex.Clear(); + UploadRanges.SurfaceIndex.Push({ 0, (int)Mesh.SurfaceIndexes.Size() }); + UploadRanges.Surface.Clear(); + UploadRanges.Surface.Push({ 0, GetSurfaceCount() }); + UploadRanges.UniformIndexes.Clear(); + UploadRanges.UniformIndexes.Push({ 0, (int)Mesh.UniformIndexes.Size() }); + UploadRanges.Uniforms.Clear(); + UploadRanges.Uniforms.Push({ 0, (int)Mesh.Uniforms.Size() }); + UploadRanges.Portals.Clear(); + UploadRanges.Portals.Push({ 0, (int)Portals.Size() }); + UploadRanges.Light.Clear(); + UploadRanges.Light.Push({ 0, (int)Mesh.Lights.Size() }); + UploadRanges.LightIndex.Clear(); + UploadRanges.LightIndex.Push({ 0, (int)Mesh.LightIndexes.Size() }); } - void MarkCollisionDirty() + void UploadCollision() { - DirtyRanges.Node.Clear(); + UploadRanges.Node.Clear(); if (Collision) - DirtyRanges.Node.Push({ 0, (int)Collision->get_nodes().size() }); + UploadRanges.Node.Push({ 0, (int)Collision->get_nodes().size() }); } - void MarkDynamicDirty() + void UploadDynamic() { - DirtyRanges.Index.Push({ Mesh.DynamicIndexStart, (int)(Mesh.Indexes.Size() - Mesh.DynamicIndexStart) }); + UploadRanges.Index.Push({ Mesh.DynamicIndexStart, (int)(Mesh.Indexes.Size() - Mesh.DynamicIndexStart) }); + } + + void AddRange(TArray& ranges, MeshBufferRange range) + { + auto right = std::lower_bound(ranges.begin(), ranges.end(), range); + + bool leftExists = right != ranges.begin(); + bool rightExists = right != ranges.end(); + + auto left = right; + if (leftExists) + --left; + + if (leftExists && rightExists && left->Offset + left->Size == range.Offset && right->Offset == range.Offset + range.Size) // ####[--]#### + { + left->Size += range.Size + right->Size; + ranges.Delete(right - ranges.begin()); + } + else if (leftExists && left->Offset + left->Size == range.Offset) // ####[--] #### + { + left->Size += range.Size; + } + else if (rightExists && right->Offset == range.Offset + range.Size) // #### [--]#### + { + right->Offset -= range.Size; + } + else // ##### [--] #### + { + ranges.Insert(right - ranges.begin(), range); + } } }; diff --git a/src/common/rendering/vulkan/vk_levelmesh.cpp b/src/common/rendering/vulkan/vk_levelmesh.cpp index 4f6a17f81..f5f4c0c18 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.cpp +++ b/src/common/rendering/vulkan/vk_levelmesh.cpp @@ -448,11 +448,11 @@ void VkLevelMeshUploader::Upload() BeginTransfer(transferBufferSize); UploadNodes(); - UploadRanges(Mesh->Mesh->DirtyRanges.Vertex, Mesh->Mesh->Mesh.Vertices.Data(), Mesh->VertexBuffer.get()); - UploadRanges(Mesh->Mesh->DirtyRanges.UniformIndexes, Mesh->Mesh->Mesh.UniformIndexes.Data(), Mesh->UniformIndexBuffer.get()); - UploadRanges(Mesh->Mesh->DirtyRanges.Index, Mesh->Mesh->Mesh.Indexes.Data(), Mesh->IndexBuffer.get()); - UploadRanges(Mesh->Mesh->DirtyRanges.SurfaceIndex, Mesh->Mesh->Mesh.SurfaceIndexes.Data(), Mesh->SurfaceIndexBuffer.get()); - UploadRanges(Mesh->Mesh->DirtyRanges.LightIndex, Mesh->Mesh->Mesh.LightIndexes.Data(), Mesh->LightIndexBuffer.get()); + UploadRanges(Mesh->Mesh->UploadRanges.Vertex, Mesh->Mesh->Mesh.Vertices.Data(), Mesh->VertexBuffer.get()); + UploadRanges(Mesh->Mesh->UploadRanges.UniformIndexes, Mesh->Mesh->Mesh.UniformIndexes.Data(), Mesh->UniformIndexBuffer.get()); + 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()); UploadSurfaces(); UploadUniforms(); UploadPortals(); @@ -474,16 +474,16 @@ void VkLevelMeshUploader::Upload() void VkLevelMeshUploader::ClearRanges() { - Mesh->Mesh->DirtyRanges.Vertex.clear(); - Mesh->Mesh->DirtyRanges.Index.clear(); - Mesh->Mesh->DirtyRanges.Node.clear(); - Mesh->Mesh->DirtyRanges.SurfaceIndex.clear(); - Mesh->Mesh->DirtyRanges.Surface.clear(); - Mesh->Mesh->DirtyRanges.UniformIndexes.clear(); - Mesh->Mesh->DirtyRanges.Uniforms.clear(); - Mesh->Mesh->DirtyRanges.Portals.clear(); - Mesh->Mesh->DirtyRanges.Light.clear(); - Mesh->Mesh->DirtyRanges.LightIndex.clear(); + Mesh->Mesh->UploadRanges.Vertex.clear(); + Mesh->Mesh->UploadRanges.Index.clear(); + Mesh->Mesh->UploadRanges.Node.clear(); + Mesh->Mesh->UploadRanges.SurfaceIndex.clear(); + Mesh->Mesh->UploadRanges.Surface.clear(); + Mesh->Mesh->UploadRanges.UniformIndexes.clear(); + Mesh->Mesh->UploadRanges.Uniforms.clear(); + Mesh->Mesh->UploadRanges.Portals.clear(); + Mesh->Mesh->UploadRanges.Light.clear(); + Mesh->Mesh->UploadRanges.LightIndex.clear(); } void VkLevelMeshUploader::BeginTransfer(size_t transferBufferSize) @@ -515,7 +515,7 @@ void VkLevelMeshUploader::UploadNodes() return; // Always update the header struct of the collision storage buffer block if something changed - if (Mesh->Mesh->DirtyRanges.Node.Size() > 0) + if (Mesh->Mesh->UploadRanges.Node.Size() > 0) { CollisionNodeBufferHeader nodesHeader; nodesHeader.root = Mesh->Mesh->Collision->get_root(); @@ -527,7 +527,7 @@ void VkLevelMeshUploader::UploadNodes() } // Copy collision nodes - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Node) + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Node) { const auto& srcnodes = Mesh->Mesh->Collision->get_nodes(); CollisionNode* nodes = (CollisionNode*)(data + datapos); @@ -565,7 +565,7 @@ void VkLevelMeshUploader::UploadRanges(const TArray& ranges, co void VkLevelMeshUploader::UploadSurfaces() { - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Surface) + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Surface) { SurfaceInfo* surfaces = (SurfaceInfo*)(data + datapos); for (int j = 0, count = range.Size; j < count; j++) @@ -601,7 +601,7 @@ void VkLevelMeshUploader::UploadSurfaces() void VkLevelMeshUploader::UploadUniforms() { - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Uniforms) + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Uniforms) { for (int j = 0, count = range.Size; j < count; j++) { @@ -630,7 +630,7 @@ void VkLevelMeshUploader::UploadUniforms() void VkLevelMeshUploader::UploadPortals() { - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Portals) + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Portals) { PortalInfo* portals = (PortalInfo*)(data + datapos); for (int i = 0, count = range.Size; i < count; i++) @@ -650,7 +650,7 @@ void VkLevelMeshUploader::UploadPortals() void VkLevelMeshUploader::UploadLights() { - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Light) + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Light) { LightInfo* lights = (LightInfo*)(data + datapos); for (int i = 0, count = range.Size; i < count; i++) @@ -682,17 +682,17 @@ size_t VkLevelMeshUploader::GetTransferSize() size_t transferBufferSize = 0; if (!Mesh->useRayQuery) { - if (Mesh->Mesh->DirtyRanges.Node.Size() > 0) transferBufferSize += sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode); - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Node) transferBufferSize += range.Size * sizeof(CollisionNode); + if (Mesh->Mesh->UploadRanges.Node.Size() > 0) transferBufferSize += sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Node) transferBufferSize += range.Size * sizeof(CollisionNode); } - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Vertex) transferBufferSize += range.Size * sizeof(FFlatVertex); - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.UniformIndexes) transferBufferSize += range.Size * sizeof(int); - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Index) transferBufferSize += range.Size * sizeof(uint32_t); - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.SurfaceIndex) transferBufferSize += range.Size * sizeof(int); - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Surface) transferBufferSize += range.Size * sizeof(SurfaceInfo); - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Uniforms) transferBufferSize += range.Size * sizeof(SurfaceUniforms); - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Portals) transferBufferSize += range.Size * sizeof(PortalInfo); - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.LightIndex) transferBufferSize += range.Size * sizeof(int32_t); - for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Light) transferBufferSize += range.Size * sizeof(LightInfo); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Vertex) transferBufferSize += range.Size * sizeof(FFlatVertex); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.UniformIndexes) transferBufferSize += range.Size * sizeof(int); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Index) transferBufferSize += range.Size * sizeof(uint32_t); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.SurfaceIndex) transferBufferSize += range.Size * sizeof(int); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Surface) transferBufferSize += range.Size * sizeof(SurfaceInfo); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Uniforms) transferBufferSize += range.Size * sizeof(SurfaceUniforms); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Portals) transferBufferSize += range.Size * sizeof(PortalInfo); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.LightIndex) transferBufferSize += range.Size * sizeof(int32_t); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Light) transferBufferSize += range.Size * sizeof(LightInfo); return transferBufferSize; } diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 898dfdade..fd874df93 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -178,7 +178,7 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap) Mesh.MaxLights = 100'000; Mesh.MaxLightIndexes = 4 * 1024 * 1024; - MarkAllDirty(); + UploadAll(); } void DoomLevelMesh::CreateLights(FLevelLocals& doomMap)