From d28a3571b5e95d0ab57f1d5055b401511bfade2a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 23 Aug 2024 00:01:08 +0200 Subject: [PATCH] More level mesh buffer fun --- .../hwrenderer/data/hw_levelmesh.cpp | 48 +-- .../rendering/hwrenderer/data/hw_levelmesh.h | 193 ++++++++---- src/common/rendering/vulkan/vk_levelmesh.cpp | 88 +++--- src/rendering/hwrenderer/doom_levelmesh.cpp | 280 ++++++++++-------- src/rendering/hwrenderer/doom_levelmesh.h | 10 +- 5 files changed, 367 insertions(+), 252 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp index 9679394ce..5f9fb459c 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp @@ -4,6 +4,13 @@ LevelMesh::LevelMesh() { + LevelMeshLimits limits; + limits.MaxVertices = 12; + limits.MaxIndexes = 3 * 4; + limits.MaxSurfaces = 1; + limits.MaxUniforms = 1; + Reset(limits); + // Default portal LevelMeshPortal portal; Portals.Push(portal); @@ -11,38 +18,35 @@ LevelMesh::LevelMesh() AddEmptyMesh(); UpdateCollision(); - Mesh.MaxVertices = std::max(Mesh.Vertices.Size() * 2, (unsigned int)10000); - Mesh.MaxIndexes = std::max(Mesh.Indexes.Size() * 2, (unsigned int)10000); - Mesh.MaxSurfaces = std::max(Mesh.SurfaceIndexes.Size() * 2, (unsigned int)10000); - Mesh.MaxUniforms = std::max(Mesh.Uniforms.Size() * 2, (unsigned int)10000); - Mesh.MaxSurfaceIndexes = std::max(Mesh.SurfaceIndexes.Size() * 2, (unsigned int)10000); Mesh.MaxNodes = (int)std::max(Collision->get_nodes().size() * 2, (size_t)10000); - Mesh.MaxLights = 100'000; - Mesh.MaxLightIndexes = 4 * 1024 * 1024; } void LevelMesh::AddEmptyMesh() { + GeometryAllocInfo ginfo = AllocGeometry(12, 3 * 4); + // Default empty mesh (we can't make it completely empty since vulkan doesn't like that) float minval = -100001.0f; float maxval = -100000.0f; - Mesh.Vertices.Push({ minval, minval, minval }); - Mesh.Vertices.Push({ maxval, minval, minval }); - Mesh.Vertices.Push({ maxval, maxval, minval }); - Mesh.Vertices.Push({ minval, minval, minval }); - Mesh.Vertices.Push({ minval, maxval, minval }); - Mesh.Vertices.Push({ maxval, maxval, minval }); - Mesh.Vertices.Push({ minval, minval, maxval }); - Mesh.Vertices.Push({ maxval, minval, maxval }); - Mesh.Vertices.Push({ maxval, maxval, maxval }); - Mesh.Vertices.Push({ minval, minval, maxval }); - Mesh.Vertices.Push({ minval, maxval, maxval }); - Mesh.Vertices.Push({ maxval, maxval, maxval }); + ginfo.Vertices[0] = { minval, minval, minval }; + ginfo.Vertices[1] = { maxval, minval, minval }; + ginfo.Vertices[2] = { maxval, maxval, minval }; + ginfo.Vertices[3] = { minval, minval, minval }; + ginfo.Vertices[4] = { minval, maxval, minval }; + ginfo.Vertices[5] = { maxval, maxval, minval }; + ginfo.Vertices[6] = { minval, minval, maxval }; + ginfo.Vertices[7] = { maxval, minval, maxval }; + ginfo.Vertices[8] = { maxval, maxval, maxval }; + ginfo.Vertices[9] = { minval, minval, maxval }; + ginfo.Vertices[10] = { minval, maxval, maxval }; + ginfo.Vertices[11] = { maxval, maxval, maxval }; for (int i = 0; i < 3 * 4; i++) - Mesh.Indexes.Push(i); + ginfo.Indexes[i] = i; - UploadAll(); + Mesh.IndexCount = ginfo.IndexCount; + + UploadPortals(); } LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, float maxDist) @@ -109,7 +113,7 @@ LevelMeshTileStats LevelMesh::GatherTilePixelStats() void LevelMesh::UpdateCollision() { - Collision = std::make_unique(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.Indexes.Size()); + Collision = std::make_unique(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.IndexCount); UploadCollision(); } diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index 00e38dff1..8361a274d 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -11,6 +11,7 @@ #include "hw_levelmeshsurface.h" #include "hw_materialstate.h" #include "hw_surfaceuniforms.h" +#include "engineerrors.h" #include #include @@ -44,12 +45,32 @@ struct UniformsAllocInfo int Count = 0; }; +struct SurfaceAllocInfo +{ + LevelMeshSurface* Surface = nullptr; + int Index = 0; +}; + +struct LightAllocInfo +{ + LevelMeshLight* Light = nullptr; + int Index = 0; +}; + struct MeshBufferRange { - int Offset = 0; - int Size = 0; + int Start = 0; + int End = 0; - bool operator<(const MeshBufferRange& other) const { return Offset < other.Offset; } + int Count() const { return End - Start; } +}; + +struct LevelMeshLimits +{ + int MaxVertices = 0; + int MaxSurfaces = 0; + int MaxUniforms = 0; + int MaxIndexes = 0; }; class LevelMesh @@ -71,20 +92,18 @@ public: GeometryAllocInfo AllocGeometry(int vertexCount, int indexCount) { GeometryAllocInfo info; - info.VertexStart = Mesh.Vertices.Size(); + info.VertexStart = RemoveRange(FreeLists.Vertex, vertexCount); info.VertexCount = vertexCount; - info.IndexStart = Mesh.Indexes.Size(); + info.IndexStart = RemoveRange(FreeLists.Index, indexCount); info.IndexCount = indexCount; - Mesh.Vertices.Resize(info.VertexStart + vertexCount); - Mesh.UniformIndexes.Resize(info.VertexStart + vertexCount); - Mesh.Indexes.Resize(info.IndexStart + indexCount); info.Vertices = &Mesh.Vertices[info.VertexStart]; info.UniformIndexes = &Mesh.UniformIndexes[info.VertexStart]; info.Indexes = &Mesh.Indexes[info.IndexStart]; - AddRange(UploadRanges.Vertex, { info.VertexStart, info.VertexCount }); - AddRange(UploadRanges.UniformIndexes, { info.VertexStart, info.VertexCount }); - AddRange(UploadRanges.Index, { info.IndexStart, info.IndexCount }); + AddRange(UploadRanges.Vertex, { info.VertexStart, info.VertexStart + info.VertexCount }); + AddRange(UploadRanges.UniformIndexes, { info.VertexStart, info.VertexStart + info.VertexCount }); + AddRange(UploadRanges.Index, { info.IndexStart, info.IndexStart + info.IndexCount }); + AddRange(UploadRanges.SurfaceIndex, { info.IndexStart / 3, (info.IndexStart + info.IndexCount) / 3 + 1 }); return info; } @@ -92,14 +111,23 @@ public: UniformsAllocInfo AllocUniforms(int count) { UniformsAllocInfo info; - info.Start = Mesh.Uniforms.Size(); + info.Start = RemoveRange(FreeLists.Uniforms, count); info.Count = count; - Mesh.Uniforms.Resize(info.Start + count); - Mesh.Materials.Resize(info.Start + count); info.Uniforms = &Mesh.Uniforms[info.Start]; info.Materials = &Mesh.Materials[info.Start]; - AddRange(UploadRanges.Uniforms, { info.Start, info.Count }); + AddRange(UploadRanges.Uniforms, { info.Start, info.Start + info.Count }); + + return info; + } + + SurfaceAllocInfo AllocSurface() + { + SurfaceAllocInfo info; + info.Index = RemoveRange(FreeLists.Surface, 1); + info.Surface = &Mesh.Surfaces[info.Index]; + + AddRange(UploadRanges.Surface, { info.Index, info.Index + 1 }); return info; } @@ -109,10 +137,10 @@ public: // Convert triangles to degenerates for (int i = 0; i < indexCount; i++) Mesh.Indexes[indexStart + i] = 0; - AddRange(UploadRanges.Index, { indexStart, indexCount }); + AddRange(UploadRanges.Index, { indexStart, indexStart + indexCount }); - AddRange(FreeLists.Vertex, { vertexStart, vertexCount }); - AddRange(FreeLists.Index, { indexStart, indexCount }); + AddRange(FreeLists.Vertex, { vertexStart, vertexStart + vertexCount }); + AddRange(FreeLists.Index, { indexStart, indexStart + indexCount }); } void FreeUniforms(int start, int count) @@ -127,6 +155,28 @@ public: AddRange(FreeLists.Surface, { (int)surfaceIndex, 1 }); } + // Sets the sizes of all the GPU buffers and empties the mesh + virtual void Reset(const LevelMeshLimits& limits) + { + Mesh.Vertices.Resize(limits.MaxVertices); + Mesh.UniformIndexes.Resize(limits.MaxVertices); + + Mesh.Surfaces.Resize(limits.MaxSurfaces); + Mesh.Uniforms.Resize(limits.MaxUniforms); + Mesh.Materials.Resize(limits.MaxUniforms); + + Mesh.Lights.Resize(16); + Mesh.LightIndexes.Resize(16); + + Mesh.Indexes.Resize(limits.MaxIndexes); + Mesh.SurfaceIndexes.Resize(limits.MaxIndexes / 3 + 1); + + 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 }); + } + // Data placed in GPU buffers struct { @@ -146,16 +196,10 @@ public: // Index data TArray Indexes; TArray SurfaceIndexes; + int IndexCount = 0; // Index range filled with data - // Above data must not be resized beyond these limits as that's the size of the GPU buffers - int MaxVertices = 0; - int MaxIndexes = 0; - int MaxSurfaces = 0; - int MaxUniforms = 0; - int MaxSurfaceIndexes = 0; + // GPU buffer size for collision nodes int MaxNodes = 0; - int MaxLights = 0; - int MaxLightIndexes = 0; } Mesh; // Ranges in mesh that have changed since last upload @@ -207,26 +251,10 @@ public: void AddEmptyMesh(); - void UploadAll() + void UploadPortals() { - ClearRanges(UploadRanges.Vertex); - AddRange(UploadRanges.Vertex, { 0, (int)Mesh.Vertices.Size() }); - ClearRanges(UploadRanges.Index); - AddRange(UploadRanges.Index, { 0, (int)Mesh.Indexes.Size() }); - ClearRanges(UploadRanges.SurfaceIndex); - AddRange(UploadRanges.SurfaceIndex, { 0, (int)Mesh.SurfaceIndexes.Size() }); - ClearRanges(UploadRanges.Surface); - AddRange(UploadRanges.Surface, { 0, (int)Mesh.Surfaces.Size() }); - ClearRanges(UploadRanges.UniformIndexes); - AddRange(UploadRanges.UniformIndexes, { 0, (int)Mesh.UniformIndexes.Size() }); - ClearRanges(UploadRanges.Uniforms); - AddRange(UploadRanges.Uniforms, { 0, (int)Mesh.Uniforms.Size() }); - ClearRanges(UploadRanges.Portals); + UploadRanges.Portals.Clear(); AddRange(UploadRanges.Portals, { 0, (int)Portals.Size() }); - ClearRanges(UploadRanges.Light); - AddRange(UploadRanges.Light, { 0, (int)Mesh.Lights.Size() }); - ClearRanges(UploadRanges.LightIndex); - AddRange(UploadRanges.LightIndex, { 0, (int)Mesh.LightIndexes.Size() }); } void UploadCollision() @@ -236,42 +264,81 @@ public: UploadRanges.Node.Push({ 0, (int)Collision->get_nodes().size() }); } - void ClearRanges(TArray& ranges) + int RemoveRange(TArray& ranges, int count) { - ranges.Clear(); + for (unsigned int i = ranges.Size(); i > 0; i--) + { + auto& item = ranges[i - 1]; + if (item.End - item.Start >= count) + { + int pos = item.Start; + item.Start += count; + if (item.Start == item.End) + { + ranges.Delete(i - 1); + } + return pos; + } + } + I_FatalError("Could not find space in level mesh buffer"); } void AddRange(TArray& ranges, MeshBufferRange range) { - if (range.Size <= 0) + // Empty range? + if (range.Start == range.End) return; - auto right = std::lower_bound(ranges.begin(), ranges.end(), range); + // First element? + if (ranges.Size() == 0) + { + ranges.push_back(range); + return; + } + // Find start position in ranges + auto right = std::lower_bound(ranges.begin(), ranges.end(), range, [](const auto& a, const auto& b) { return a.Start < b.Start; }); 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 // ##### [--] #### + // Is this a gap between two ranges? + if ((!leftExists || left->End < range.Start) && (!rightExists || right->Start > range.End)) { ranges.Insert(right - ranges.begin(), range); + return; } + + // Are we extending the left or the right range? + if (leftExists && range.Start <= left->End) + { + left->End = std::max(left->End, range.End); + right = left; + } + else // if (rightExists && right->Start <= range.End) + { + right->Start = range.Start; + right->End = std::max(right->End, range.End); + left = right; + } + + // Merge overlaps to the right + while (true) + { + ++right; + if (right == ranges.end() || right->Start > range.End) + break; + left->End = std::max(right->End, range.End); + } + + // Remove ranges now covered by the extended range + //ranges.erase(++left, right); + ++left; + auto leftPos = left - ranges.begin(); + auto rightPos = right - ranges.begin(); + ranges.Delete(leftPos, rightPos - leftPos); } }; diff --git a/src/common/rendering/vulkan/vk_levelmesh.cpp b/src/common/rendering/vulkan/vk_levelmesh.cpp index 5f87289c1..4a1296869 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.cpp +++ b/src/common/rendering/vulkan/vk_levelmesh.cpp @@ -80,7 +80,7 @@ void VkLevelMesh::CreateVulkanObjects() .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT) .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - DynamicBLAS = CreateBLAS(true, 0, Mesh->Mesh.Indexes.Size()); + DynamicBLAS = CreateBLAS(true, 0, Mesh->Mesh.IndexCount); CreateTLASInstanceBuffer(); UploadTLASInstanceBuffer(); @@ -128,7 +128,7 @@ void VkLevelMesh::BeginFrame() deletelist->Add(std::move(DynamicBLAS.AccelStructBuffer)); deletelist->Add(std::move(DynamicBLAS.AccelStruct)); - DynamicBLAS = CreateBLAS(true, 0, Mesh->Mesh.Indexes.Size()); + DynamicBLAS = CreateBLAS(true, 0, Mesh->Mesh.IndexCount); deletelist->Add(std::move(TopLevelAS.TransferBuffer)); deletelist->Add(std::move(TopLevelAS.InstanceBuffer)); @@ -173,7 +173,7 @@ void VkLevelMesh::CreateBuffers() VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size(Mesh->Mesh.MaxVertices * sizeof(FFlatVertex)) + .Size(Mesh->Mesh.Vertices.Size() * sizeof(FFlatVertex)) .DebugName("VertexBuffer") .Create(fb->GetDevice()); @@ -181,7 +181,7 @@ void VkLevelMesh::CreateBuffers() .Usage( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(Mesh->Mesh.MaxVertices * sizeof(int)) + .Size(Mesh->Mesh.UniformIndexes.size() * sizeof(int)) .DebugName("UniformIndexes") .Create(fb->GetDevice()); @@ -193,7 +193,7 @@ void VkLevelMesh::CreateBuffers() VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size((size_t)Mesh->Mesh.MaxIndexes * sizeof(uint32_t)) + .Size((size_t)Mesh->Mesh.Indexes.Size() * sizeof(uint32_t)) .DebugName("IndexBuffer") .Create(fb->GetDevice()); @@ -205,19 +205,19 @@ void VkLevelMesh::CreateBuffers() SurfaceIndexBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(Mesh->Mesh.MaxSurfaceIndexes * sizeof(int)) + .Size(Mesh->Mesh.SurfaceIndexes.Size() * sizeof(int)) .DebugName("SurfaceBuffer") .Create(fb->GetDevice()); SurfaceBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(Mesh->Mesh.MaxSurfaces * sizeof(SurfaceInfo)) + .Size(Mesh->Mesh.Surfaces.Size() * sizeof(SurfaceInfo)) .DebugName("SurfaceBuffer") .Create(fb->GetDevice()); UniformsBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(Mesh->Mesh.MaxUniforms * sizeof(SurfaceUniforms)) + .Size(Mesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms)) .DebugName("SurfaceUniformsBuffer") .Create(fb->GetDevice()); @@ -229,13 +229,13 @@ void VkLevelMesh::CreateBuffers() LightBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(Mesh->Mesh.MaxLights * sizeof(LightInfo)) + .Size(Mesh->Mesh.Lights.Size() * sizeof(LightInfo)) .DebugName("LightBuffer") .Create(fb->GetDevice()); LightIndexBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(Mesh->Mesh.MaxLightIndexes * sizeof(int32_t)) + .Size(Mesh->Mesh.LightIndexes.Size() * sizeof(int32_t)) .DebugName("LightIndexBuffer") .Create(fb->GetDevice()); } @@ -518,9 +518,9 @@ void VkLevelMeshUploader::UploadNodes() { const auto& srcnodes = Mesh->Mesh->Collision->get_nodes(); CollisionNode* nodes = (CollisionNode*)(data + datapos); - for (int i = 0, count = range.Size; i < count; i++) + for (int i = 0, count = range.Count(); i < count; i++) { - const auto& node = srcnodes[range.Offset + i]; + const auto& node = srcnodes[range.Start + i]; CollisionNode info; info.center = SwapYZ(node.aabb.Center); info.extents = SwapYZ(node.aabb.Extents); @@ -530,9 +530,9 @@ void VkLevelMeshUploader::UploadNodes() *(nodes++) = info; } - size_t copysize = range.Size * sizeof(CollisionNode); + size_t copysize = range.Count() * sizeof(CollisionNode); if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, sizeof(CollisionNodeBufferHeader) + range.Offset * sizeof(CollisionNode), copysize); + copyCommands.emplace_back(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, sizeof(CollisionNodeBufferHeader) + range.Start * sizeof(CollisionNode), copysize); datapos += copysize; } } @@ -542,10 +542,10 @@ void VkLevelMeshUploader::UploadRanges(const TArray& ranges, co { for (const MeshBufferRange& range : ranges) { - size_t copysize = range.Size * sizeof(T); - memcpy(data + datapos, srcbuffer + range.Offset, copysize); + size_t copysize = range.Count() * sizeof(T); + memcpy(data + datapos, srcbuffer + range.Start, copysize); if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), destbuffer, datapos, range.Offset * sizeof(T), copysize); + copyCommands.emplace_back(transferBuffer.get(), destbuffer, datapos, range.Start * sizeof(T), copysize); datapos += copysize; } } @@ -555,9 +555,9 @@ void VkLevelMeshUploader::UploadSurfaces() for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Surface) { SurfaceInfo* surfaces = (SurfaceInfo*)(data + datapos); - for (int j = 0, count = range.Size; j < count; j++) + for (int j = 0, count = range.Count(); j < count; j++) { - LevelMeshSurface* surface = &Mesh->Mesh->Mesh.Surfaces[range.Offset + j]; + LevelMeshSurface* surface = &Mesh->Mesh->Mesh.Surfaces[range.Start + j]; SurfaceInfo info; info.Normal = FVector3(surface->Plane.X, surface->Plane.Z, surface->Plane.Y); @@ -579,9 +579,9 @@ void VkLevelMeshUploader::UploadSurfaces() *(surfaces++) = info; } - size_t copysize = range.Size * sizeof(SurfaceInfo); + size_t copysize = range.Count() * sizeof(SurfaceInfo); if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->SurfaceBuffer.get(), datapos, range.Offset * sizeof(SurfaceInfo), copysize); + copyCommands.emplace_back(transferBuffer.get(), Mesh->SurfaceBuffer.get(), datapos, range.Start * sizeof(SurfaceInfo), copysize); datapos += copysize; } } @@ -590,10 +590,10 @@ void VkLevelMeshUploader::UploadUniforms() { for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Uniforms) { - for (int j = 0, count = range.Size; j < count; j++) + for (int j = 0, count = range.Count(); j < count; j++) { - auto& surfaceUniforms = Mesh->Mesh->Mesh.Uniforms[range.Offset + j]; - auto& material = Mesh->Mesh->Mesh.Materials[range.Offset + j]; + auto& surfaceUniforms = Mesh->Mesh->Mesh.Uniforms[range.Start + j]; + auto& material = Mesh->Mesh->Mesh.Materials[range.Start + j]; if (material.mMaterial) { auto source = material.mMaterial->Source(); @@ -607,10 +607,10 @@ void VkLevelMeshUploader::UploadUniforms() } SurfaceUniforms* uniforms = (SurfaceUniforms*)(data + datapos); - size_t copysize = range.Size * sizeof(SurfaceUniforms); + size_t copysize = range.Count() * sizeof(SurfaceUniforms); memcpy(uniforms, Mesh->Mesh->Mesh.Uniforms.Data(), copysize); if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->UniformsBuffer.get(), datapos, range.Offset * sizeof(SurfaceUniforms), copysize); + copyCommands.emplace_back(transferBuffer.get(), Mesh->UniformsBuffer.get(), datapos, range.Start * sizeof(SurfaceUniforms), copysize); datapos += copysize; } } @@ -620,17 +620,17 @@ void VkLevelMeshUploader::UploadPortals() for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Portals) { PortalInfo* portals = (PortalInfo*)(data + datapos); - for (int i = 0, count = range.Size; i < count; i++) + for (int i = 0, count = range.Count(); i < count; i++) { - const auto& portal = Mesh->Mesh->Portals[range.Offset + i]; + const auto& portal = Mesh->Mesh->Portals[range.Start + i]; PortalInfo info; info.transformation = portal.transformation; *(portals++) = info; } - size_t copysize = range.Size * sizeof(PortalInfo); + size_t copysize = range.Count() * sizeof(PortalInfo); if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->PortalBuffer.get(), datapos, range.Offset * sizeof(PortalInfo), copysize); + copyCommands.emplace_back(transferBuffer.get(), Mesh->PortalBuffer.get(), datapos, range.Start * sizeof(PortalInfo), copysize); datapos += copysize; } } @@ -640,9 +640,9 @@ void VkLevelMeshUploader::UploadLights() for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Light) { LightInfo* lights = (LightInfo*)(data + datapos); - for (int i = 0, count = range.Size; i < count; i++) + for (int i = 0, count = range.Count(); i < count; i++) { - const auto& light = Mesh->Mesh->Mesh.Lights[range.Offset + i]; + const auto& light = Mesh->Mesh->Mesh.Lights[range.Start + i]; LightInfo info; info.Origin = SwapYZ(light.Origin); info.RelativeOrigin = SwapYZ(light.RelativeOrigin); @@ -656,9 +656,9 @@ void VkLevelMeshUploader::UploadLights() *(lights++) = info; } - size_t copysize = range.Size * sizeof(LightInfo); + size_t copysize = range.Count() * sizeof(LightInfo); if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->LightBuffer.get(), datapos, range.Offset * sizeof(LightInfo), copysize); + copyCommands.emplace_back(transferBuffer.get(), Mesh->LightBuffer.get(), datapos, range.Start * sizeof(LightInfo), copysize); datapos += copysize; } } @@ -670,16 +670,16 @@ size_t VkLevelMeshUploader::GetTransferSize() if (!Mesh->useRayQuery) { 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->UploadRanges.Node) transferBufferSize += range.Count() * sizeof(CollisionNode); } - 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); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Vertex) transferBufferSize += range.Count() * sizeof(FFlatVertex); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.UniformIndexes) transferBufferSize += range.Count() * sizeof(int); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Index) transferBufferSize += range.Count() * sizeof(uint32_t); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.SurfaceIndex) transferBufferSize += range.Count() * sizeof(int); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Surface) transferBufferSize += range.Count() * sizeof(SurfaceInfo); + for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Uniforms) transferBufferSize += range.Count() * sizeof(SurfaceUniforms); + 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); return transferBufferSize; } diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 233810131..dfd588940 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -150,72 +150,119 @@ EXTERN_CVAR(Float, lm_scale); DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap) { - // Remove the empty mesh added in the LevelMesh constructor - Mesh.Vertices.clear(); - Mesh.Indexes.clear(); + // Try to estimate what the worst case memory needs are for the level + LevelMeshLimits limits; + limits.MaxVertices = (doomMap.vertexes.Size() * 10) * 2; + limits.MaxSurfaces = (doomMap.sides.Size() * 3 + doomMap.subsectors.Size() * 2) * 2; + limits.MaxUniforms = (doomMap.sides.Size() * 3 + doomMap.sectors.Size() * 2) * 2; + limits.MaxIndexes = limits.MaxVertices * 10; + Reset(limits); SunColor = doomMap.SunColor; // TODO keep only one copy? SunDirection = doomMap.SunDirection; + LightmapSampleDistance = doomMap.LightmapSampleDistance; BuildSectorGroups(doomMap); CreatePortals(doomMap); - - LightmapSampleDistance = doomMap.LightmapSampleDistance; - CreateSurfaces(doomMap); - LinkSurfaces(doomMap); SortIndexes(); BuildTileSurfaceLists(); UpdateCollision(); - - // Assume double the size of the static mesh will be enough for anything dynamic. - Mesh.MaxVertices = std::max(Mesh.Vertices.size() * 2, (size_t)10000); - Mesh.MaxIndexes = std::max(Mesh.Indexes.size() * 2, (size_t)10000); - Mesh.MaxSurfaces = std::max(Mesh.SurfaceIndexes.size() * 2, (size_t)10000); - Mesh.MaxUniforms = std::max(Mesh.Uniforms.size() * 2, (size_t)10000); - Mesh.MaxSurfaceIndexes = std::max(Mesh.SurfaceIndexes.size() * 2, (size_t)10000); Mesh.MaxNodes = std::max(Collision->get_nodes().size() * 2, (size_t)10000); - Mesh.MaxLights = 100'000; - Mesh.MaxLightIndexes = 4 * 1024 * 1024; - UploadAll(); + UploadPortals(); +} + +void DoomLevelMesh::BeginFrame(FLevelLocals& doomMap) +{ + CreateLights(doomMap); } void DoomLevelMesh::CreateLights(FLevelLocals& doomMap) { - if (Mesh.Lights.Size() != 0) + if (LightsCreated) return; - for (unsigned int i = 0, count = Mesh.Surfaces.Size(); i < count; i++) + for (const SideSurfaceBlock& side : Sides) { - Mesh.Surfaces[i].LightList.Pos = Mesh.LightIndexes.Size(); - Mesh.Surfaces[i].LightList.Count = 0; - - std::pair nodePortalGroup = GetSurfaceLightNode(i); - FLightNode* node = nodePortalGroup.first; - int portalgroup = nodePortalGroup.second; - if (!node) - continue; - - int listpos = 0; - while (node) + int index = side.FirstSurface; + while (index != -1) { - FDynamicLight* light = node->lightsource; - if (light && light->Trace()) - { - int lightindex = GetLightIndex(light, portalgroup); - if (lightindex >= 0) - { - AddRange(UploadRanges.LightIndex, { (int)Mesh.LightIndexes.Size(), 1 }); - Mesh.LightIndexes.Push(lightindex); - Mesh.Surfaces[i].LightList.Count++; - } - } - node = node->nextLight; + CreateLightList(doomMap, index); + index = DoomSurfaceInfos[index].NextSurface; } } + + for (const FlatSurfaceBlock& flat : Flats) + { + int index = flat.FirstSurface; + while (index != -1) + { + CreateLightList(doomMap, index); + index = DoomSurfaceInfos[index].NextSurface; + } + } + + LightsCreated = true; +} + +void DoomLevelMesh::CreateLightList(FLevelLocals& doomMap, int surfaceIndex) +{ + Mesh.Surfaces[surfaceIndex].LightList.Pos = Mesh.LightIndexes.Size(); + Mesh.Surfaces[surfaceIndex].LightList.Count = 0; + + std::pair nodePortalGroup = GetSurfaceLightNode(surfaceIndex); + FLightNode* node = nodePortalGroup.first; + int portalgroup = nodePortalGroup.second; + if (!node) + return; + + int listpos = 0; + while (node) + { + FDynamicLight* light = node->lightsource; + if (light && light->Trace()) + { + int lightindex = GetLightIndex(light, portalgroup); + if (lightindex >= 0) + { + AddRange(UploadRanges.LightIndex, { (int)Mesh.LightIndexes.Size(), (int)Mesh.LightIndexes.Size() + 1 }); + Mesh.LightIndexes.Push(lightindex); + Mesh.Surfaces[surfaceIndex].LightList.Count++; + } + } + node = node->nextLight; + } +} + +std::pair DoomLevelMesh::GetSurfaceLightNode(int surfaceIndex) +{ + auto doomsurf = &DoomSurfaceInfos[surfaceIndex]; + FLightNode* node = nullptr; + int portalgroup = 0; + if (doomsurf->Type == ST_FLOOR || doomsurf->Type == ST_CEILING) + { + node = doomsurf->Subsector->section->lighthead; + portalgroup = doomsurf->Subsector->sector->PortalGroup; + } + else if (doomsurf->Type == ST_MIDDLESIDE || doomsurf->Type == ST_UPPERSIDE || doomsurf->Type == ST_LOWERSIDE) + { + bool isPolyLine = !!(doomsurf->Side->Flags & WALLF_POLYOBJ); + if (isPolyLine) + { + subsector_t* subsector = level.PointInRenderSubsector((doomsurf->Side->V1()->fPos() + doomsurf->Side->V2()->fPos()) * 0.5); + node = subsector->section->lighthead; + portalgroup = subsector->sector->PortalGroup; + } + else + { + node = doomsurf->Side->lighthead; + portalgroup = doomsurf->Side->sector->PortalGroup; + } + } + return { node, portalgroup }; } int DoomLevelMesh::GetLightIndex(FDynamicLight* light, int portalgroup) @@ -270,16 +317,11 @@ int DoomLevelMesh::GetLightIndex(FDynamicLight* light, int portalgroup) int lightindex = Mesh.Lights.Size(); light->levelmesh[index].index = lightindex + 1; light->levelmesh[index].portalgroup = portalgroup; - AddRange(UploadRanges.Light, { (int)Mesh.Lights.Size(), 1 }); + AddRange(UploadRanges.Light, { (int)Mesh.Lights.Size(), (int)Mesh.Lights.Size() + 1 }); Mesh.Lights.Push(meshlight); return lightindex; } -void DoomLevelMesh::BeginFrame(FLevelLocals& doomMap) -{ - CreateLights(doomMap); -} - bool DoomLevelMesh::TraceSky(const FVector3& start, FVector3 direction, float dist) { FVector3 end = start + direction * dist; @@ -287,34 +329,6 @@ bool DoomLevelMesh::TraceSky(const FVector3& start, FVector3 direction, float di return surface && surface->IsSky; } -std::pair DoomLevelMesh::GetSurfaceLightNode(int surfaceIndex) -{ - auto doomsurf = &DoomSurfaceInfos[surfaceIndex]; - FLightNode* node = nullptr; - int portalgroup = 0; - if (doomsurf->Type == ST_FLOOR || doomsurf->Type == ST_CEILING) - { - node = doomsurf->Subsector->section->lighthead; - portalgroup = doomsurf->Subsector->sector->PortalGroup; - } - else if (doomsurf->Type == ST_MIDDLESIDE || doomsurf->Type == ST_UPPERSIDE || doomsurf->Type == ST_LOWERSIDE) - { - bool isPolyLine = !!(doomsurf->Side->Flags & WALLF_POLYOBJ); - if (isPolyLine) - { - subsector_t* subsector = level.PointInRenderSubsector((doomsurf->Side->V1()->fPos() + doomsurf->Side->V2()->fPos()) * 0.5); - node = subsector->section->lighthead; - portalgroup = subsector->sector->PortalGroup; - } - else - { - node = doomsurf->Side->lighthead; - portalgroup = doomsurf->Side->sector->PortalGroup; - } - } - return { node, portalgroup }; -} - void DoomLevelMesh::CreateSurfaces(FLevelLocals& doomMap) { bindings.clear(); @@ -415,15 +429,15 @@ void DoomLevelMesh::SideTextureChanged(struct side_t* side, int section) void DoomLevelMesh::SectorLightChanged(struct sector_t* sector) { -}; +} void DoomLevelMesh::SectorLightThinkerCreated(struct sector_t* sector, class DLighting* lightthinker) { -}; +} void DoomLevelMesh::SectorLightThinkerDestroyed(struct sector_t* sector, class DLighting* lightthinker) { -}; +} void DoomLevelMesh::UpdateSide(FLevelLocals& doomMap, unsigned int sideIndex) { @@ -557,6 +571,7 @@ void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, Mesh GeometryAllocInfo ginfo = AllocGeometry(numVertices, numIndexes); UniformsAllocInfo uinfo = AllocUniforms(numUniforms); + SurfaceAllocInfo sinfo = AllocSurface(); int pipelineID = 0; int uniformsIndex = uinfo.Start; @@ -613,7 +628,7 @@ void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, Mesh sampleDimension = side->textures[side_t::bottom].LightmapSampleDistance; } - DoomSurfaceInfo info; + DoomSurfaceInfo& info = DoomSurfaceInfos[sinfo.Index]; info.Type = wallpart.LevelMeshInfo.Type; info.ControlSector = wallpart.LevelMeshInfo.ControlSector; info.TypeIndex = side->Index(); @@ -621,26 +636,24 @@ void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, Mesh if (sideIndex < Sides.Size()) { info.NextSurface = Sides[sideIndex].FirstSurface; - Sides[sideIndex].FirstSurface = Mesh.Surfaces.Size(); + Sides[sideIndex].FirstSurface = sinfo.Index; } - LevelMeshSurface surf; - surf.PipelineID = pipelineID; - surf.SectorGroup = sectorGroup[side->sector->Index()]; - surf.Alpha = float(side->linedef->alpha); - surf.MeshLocation.StartVertIndex = ginfo.VertexStart; - surf.MeshLocation.StartElementIndex = ginfo.IndexStart; - surf.MeshLocation.NumVerts = ginfo.VertexCount; - surf.MeshLocation.NumElements = ginfo.IndexCount; - surf.Plane = FVector4(N.X, N.Y, 0.0f, v1 | N); - surf.Texture = wallpart.texture; - surf.PortalIndex = isPortal ? linePortals[side->linedef->Index()] : 0; - surf.IsSky = isPortal ? (wallpart.portaltype == PORTALTYPE_SKY || wallpart.portaltype == PORTALTYPE_SKYBOX || wallpart.portaltype == PORTALTYPE_HORIZON) : false; - surf.Bounds = GetBoundsFromSurface(surf); - surf.LightmapTileIndex = disp.Level->lightmaps ? AddSurfaceToTile(info, surf, sampleDimension, !!(side->sector->Flags & SECF_LM_DYNAMIC)) : -1; + sinfo.Surface->PipelineID = pipelineID; + sinfo.Surface->SectorGroup = sectorGroup[side->sector->Index()]; + sinfo.Surface->Alpha = float(side->linedef->alpha); + sinfo.Surface->MeshLocation.StartVertIndex = ginfo.VertexStart; + sinfo.Surface->MeshLocation.StartElementIndex = ginfo.IndexStart; + sinfo.Surface->MeshLocation.NumVerts = ginfo.VertexCount; + sinfo.Surface->MeshLocation.NumElements = ginfo.IndexCount; + sinfo.Surface->Plane = FVector4(N.X, N.Y, 0.0f, v1 | N); + sinfo.Surface->Texture = wallpart.texture; + sinfo.Surface->PortalIndex = isPortal ? linePortals[side->linedef->Index()] : 0; + sinfo.Surface->IsSky = isPortal ? (wallpart.portaltype == PORTALTYPE_SKY || wallpart.portaltype == PORTALTYPE_SKYBOX || wallpart.portaltype == PORTALTYPE_HORIZON) : false; + sinfo.Surface->Bounds = GetBoundsFromSurface(*sinfo.Surface); + sinfo.Surface->LightmapTileIndex = disp.Level->lightmaps ? AddSurfaceToTile(info, *sinfo.Surface, sampleDimension, !!(side->sector->Flags & SECF_LM_DYNAMIC)) : -1; - Mesh.Surfaces.Push(surf); - DoomSurfaceInfos.Push(info); + SetSideLightmap(sinfo.Index); } } @@ -872,30 +885,55 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state surf.Bounds = GetBoundsFromSurface(surf); surf.LightmapTileIndex = disp.Level->lightmaps ? AddSurfaceToTile(info, surf, sampleDimension, !!(flatpart.sector->Flags & SECF_LM_DYNAMIC)) : -1; + SurfaceAllocInfo sinfo = AllocSurface(); + if (sectorIndex < Flats.Size()) { info.NextSurface = Flats[sectorIndex].FirstSurface; - Flats[sectorIndex].FirstSurface = Mesh.Surfaces.Size(); + Flats[sectorIndex].FirstSurface = sinfo.Index; } - Mesh.Surfaces.Push(surf); - DoomSurfaceInfos.Push(info); + *sinfo.Surface = surf; + DoomSurfaceInfos[sinfo.Index] = info; + + SetSubsectorLightmap(sinfo.Index); } } } void DoomLevelMesh::SortIndexes() { + DrawList.Clear(); + PortalList.Clear(); + // Order surfaces by pipeline std::unordered_map> pipelineSurfaces; - for (size_t i = 0; i < Mesh.Surfaces.Size(); i++) + for (const SideSurfaceBlock& side : Sides) { - LevelMeshSurface* s = &Mesh.Surfaces[i]; - pipelineSurfaces[(int64_t(s->PipelineID) << 32) | int64_t(s->IsSky)].Push(i); + int index = side.FirstSurface; + while (index != -1) + { + LevelMeshSurface* s = &Mesh.Surfaces[index]; + pipelineSurfaces[(int64_t(s->PipelineID) << 32) | int64_t(s->IsSky)].Push(index); + + index = DoomSurfaceInfos[index].NextSurface; + } + } + for (const FlatSurfaceBlock& flat : Flats) + { + int index = flat.FirstSurface; + while (index != -1) + { + LevelMeshSurface* s = &Mesh.Surfaces[index]; + pipelineSurfaces[(int64_t(s->PipelineID) << 32) | int64_t(s->IsSky)].Push(index); + + index = DoomSurfaceInfos[index].NextSurface; + } } - // Create reorder surface indexes by pipeline and create a draw range for each + // Reorder surface indexes by pipeline and create a draw range for each TArray sortedIndexes; + TArray sortedSurfaceIndexes; for (const auto& it : pipelineSurfaces) { LevelSubmeshDrawRange range; @@ -919,7 +957,7 @@ void DoomLevelMesh::SortIndexes() for (unsigned int j = 0; j < count; j += 3) { - Mesh.SurfaceIndexes.Push((int)i); + sortedSurfaceIndexes.Push((int)i); } } @@ -931,21 +969,19 @@ void DoomLevelMesh::SortIndexes() PortalList.Push(range); } - Mesh.Indexes.Swap(sortedIndexes); -} - -void DoomLevelMesh::LinkSurfaces(FLevelLocals& doomMap) -{ - for (unsigned int i = 0, count = Mesh.Surfaces.Size(); i < count; i++) + // Place result at front of buffers and upload { - if (DoomSurfaceInfos[i].Type == ST_FLOOR || DoomSurfaceInfos[i].Type == ST_CEILING) - { - SetSubsectorLightmap(i); - } - else - { - SetSideLightmap(i); - } + int count = sortedIndexes.Size(); + memcpy(Mesh.Indexes.Data(), sortedIndexes.Data(), count * sizeof(uint32_t)); + UploadRanges.Index.Clear(); + UploadRanges.Index.Push({ 0, count }); + Mesh.IndexCount = count; + } + { + int count = sortedSurfaceIndexes.Size(); + memcpy(Mesh.SurfaceIndexes.Data(), sortedSurfaceIndexes.Data(), count * sizeof(int)); + UploadRanges.SurfaceIndex.Clear(); + UploadRanges.SurfaceIndex.Push({ 0, count }); } } @@ -1031,8 +1067,10 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen { auto f = fopen(objFilename.GetChars(), "w"); + // To do: this dumps the entire vertex buffer, including those not in use + fprintf(f, "# DoomLevelMesh debug export\n"); - fprintf(f, "# Vertices: %u, Indexes: %u, Surfaces: %u\n", Mesh.Vertices.Size(), Mesh.Indexes.Size(), Mesh.Surfaces.Size()); + fprintf(f, "# Vertices: %u, Indexes: %u, Surfaces: %u\n", Mesh.Vertices.Size(), Mesh.IndexCount, Mesh.Surfaces.Size()); fprintf(f, "mtllib %s\n", mtlFilename.GetChars()); double scale = 1 / 10.0; @@ -1075,7 +1113,7 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen bool useErrorMaterial = false; int highestUsedAtlasPage = -1; - for (unsigned i = 0, count = Mesh.Indexes.Size(); i + 2 < count; i += 3) + for (unsigned i = 0, count = Mesh.IndexCount; i + 2 < count; i += 3) { auto index = Mesh.SurfaceIndexes[i / 3]; diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index a6793eb8a..f7024d5a7 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -72,8 +72,15 @@ public: void SectorLightThinkerCreated(struct sector_t* sector, class DLighting* lightthinker) override; void SectorLightThinkerDestroyed(struct sector_t* sector, class DLighting* lightthinker) override; + void Reset(const LevelMeshLimits& limits) override + { + LevelMesh::Reset(limits); + DoomSurfaceInfos.Resize(limits.MaxSurfaces); + } + 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); @@ -89,8 +96,6 @@ private: void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray& list, bool isPortal, bool translucent, unsigned int sectorIndex); void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, TArray& list, bool isSky, bool translucent, unsigned int sectorIndex); - void LinkSurfaces(FLevelLocals& doomMap); - BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const; int AddSurfaceToTile(const DoomSurfaceInfo& info, const LevelMeshSurface& surf, uint16_t sampleDimension, bool alwaysUpdate); @@ -108,4 +113,5 @@ private: TArray Flats; std::map bindings; MeshBuilder state; + bool LightsCreated = false; };