diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index bb82e869d..842010dfa 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -272,7 +272,7 @@ inline GeometryAllocInfo LevelMesh::AllocGeometry(int vertexCount, int indexCoun UploadRanges.Vertex.Add(info.VertexStart, info.VertexCount); UploadRanges.UniformIndexes.Add(info.VertexStart, info.VertexCount); UploadRanges.Index.Add(info.IndexStart, info.IndexCount); - UploadRanges.SurfaceIndex.Add(info.IndexStart / 3, info.IndexCount); + UploadRanges.SurfaceIndex.Add(info.IndexStart / 3, info.IndexCount / 3); Mesh.IndexCount = std::max(Mesh.IndexCount, info.IndexStart + info.IndexCount); diff --git a/src/common/rendering/vulkan/vk_levelmesh.cpp b/src/common/rendering/vulkan/vk_levelmesh.cpp index e5922c7fb..4da23e443 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.cpp +++ b/src/common/rendering/vulkan/vk_levelmesh.cpp @@ -738,21 +738,29 @@ void VkLevelMeshUploader::Upload() BeginTransfer(transferBufferSize); - UploadNodes(); - 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()); - UploadRanges(Mesh->Mesh->UploadRanges.DrawIndex, Mesh->Mesh->Mesh.DrawIndexes.Data(), Mesh->DrawIndexBuffer.get()); - UploadRanges(Mesh->Mesh->UploadRanges.LightUniforms, Mesh->Mesh->Mesh.LightUniforms.Data(), Mesh->LightUniformsBuffer.get()); - UploadRanges(Mesh->Mesh->UploadRanges.DynLight, Mesh->Mesh->Mesh.DynLights.Data(), Mesh->DynLightBuffer.get()); - UploadSurfaces(); - UploadUniforms(); - UploadPortals(); - UploadLights(); - - EndTransfer(transferBufferSize); + try + { + UploadNodes(); + UploadRanges(Mesh->Mesh->UploadRanges.Vertex, Mesh->Mesh->Mesh.Vertices.Data(), Mesh->VertexBuffer.get(), "VertexBuffer"); + UploadRanges(Mesh->Mesh->UploadRanges.UniformIndexes, Mesh->Mesh->Mesh.UniformIndexes.Data(), Mesh->UniformIndexBuffer.get(), "UniformIndexes"); + UploadRanges(Mesh->Mesh->UploadRanges.Index, Mesh->Mesh->Mesh.Indexes.Data(), Mesh->IndexBuffer.get(), "IndexBuffer"); + UploadRanges(Mesh->Mesh->UploadRanges.SurfaceIndex, Mesh->Mesh->Mesh.SurfaceIndexes.Data(), Mesh->SurfaceIndexBuffer.get(), "SurfaceIndexBuffer"); + UploadRanges(Mesh->Mesh->UploadRanges.LightIndex, Mesh->Mesh->Mesh.LightIndexes.Data(), Mesh->LightIndexBuffer.get(), "LightIndexBuffer"); + UploadRanges(Mesh->Mesh->UploadRanges.DrawIndex, Mesh->Mesh->Mesh.DrawIndexes.Data(), Mesh->DrawIndexBuffer.get(), "DrawIndexBuffer"); + UploadRanges(Mesh->Mesh->UploadRanges.LightUniforms, Mesh->Mesh->Mesh.LightUniforms.Data(), Mesh->LightUniformsBuffer.get(), "LightUniformsBuffer"); + UploadRanges(Mesh->Mesh->UploadRanges.DynLight, Mesh->Mesh->Mesh.DynLights.Data(), Mesh->DynLightBuffer.get(), "DynLightBuffer"); + UploadSurfaces(); + UploadUniforms(); + UploadPortals(); + UploadLights(); + EndTransfer(transferBufferSize); + } + catch (...) + { + // vk_mem_alloc gets angry in an assert if we don't release the mapping of the buffer + transferBuffer->Unmap(); + throw; + } // We can't add these as we go because UploadUniforms might load textures, which may invalidate the transfer command buffer. VulkanCommandBuffer* cmdbuffer = Mesh->fb->GetCommands()->GetTransferCommands(); @@ -793,12 +801,15 @@ void VkLevelMeshUploader::BeginTransfer(size_t transferBufferSize) data = (uint8_t*)transferBuffer->Map(0, transferBufferSize); datapos = 0; + datasize = transferBufferSize; } void VkLevelMeshUploader::EndTransfer(size_t transferBufferSize) { - assert(datapos == transferBufferSize); transferBuffer->Unmap(); + + if (datapos != transferBufferSize) + I_FatalError("Transfer buffer size calculations did not match what was actually uploaded!"); } static FVector3 SwapYZ(const FVector3& v) @@ -806,6 +817,40 @@ static FVector3 SwapYZ(const FVector3& v) return FVector3(v.X, v.Z, v.Y); } +void* VkLevelMeshUploader::GetUploadPtr(size_t size) +{ + if (datapos + size > datasize) + I_FatalError("Out of bounds error in VkLevelMeshUploader (transfer buffer)!"); + return data + datapos; +} + +void VkLevelMeshUploader::UploadData(VulkanBuffer* dest, size_t destOffset, const void* src, size_t size, const char* buffername) +{ + if (size == 0) + return; + + if (datapos + size > datasize) + I_FatalError("Out of bounds error uploading to %s (transfer buffer)!", buffername); + + if (destOffset + size > dest->size) + I_FatalError("Out of bounds error uploading to %s (destination buffer)!", buffername); + + if (src) + memcpy(data + datapos, src, size); + + copyCommands.emplace_back(transferBuffer.get(), dest, datapos, destOffset, size); + datapos += size; +} + +template +void VkLevelMeshUploader::UploadRanges(const MeshBufferUploads& ranges, const T* srcbuffer, VulkanBuffer* destbuffer, const char* buffername) +{ + for (const MeshBufferRange& range : ranges.GetRanges()) + { + UploadData(destbuffer, range.Start * sizeof(T), srcbuffer + range.Start, range.Count() * sizeof(T), buffername); + } +} + void VkLevelMeshUploader::UploadNodes() { if (Mesh->useRayQuery || Mesh->Mesh->UploadRanges.Node.GetRanges().Size() == 0) @@ -814,31 +859,12 @@ void VkLevelMeshUploader::UploadNodes() // Always update the header struct of the collision storage buffer block if something changed CollisionNodeBufferHeader nodesHeader; nodesHeader.root = Mesh->Mesh->Mesh.RootNode; - *((CollisionNodeBufferHeader*)(data + datapos)) = nodesHeader; - copyCommands.emplace_back(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, 0, sizeof(CollisionNodeBufferHeader)); - datapos += sizeof(CollisionNodeBufferHeader); + UploadData(Mesh->NodeBuffer.get(), 0, &nodesHeader, sizeof(CollisionNodeBufferHeader), "NodeBuffer"); // Copy collision nodes for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Node.GetRanges()) { - size_t copysize = range.Count() * sizeof(CollisionNode); - memcpy(data + datapos, Mesh->Mesh->Mesh.Nodes.Data() + range.Start, copysize); - if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, sizeof(CollisionNodeBufferHeader) + range.Start * sizeof(CollisionNode), copysize); - datapos += copysize; - } -} - -template -void VkLevelMeshUploader::UploadRanges(const MeshBufferUploads& ranges, const T* srcbuffer, VulkanBuffer* destbuffer) -{ - for (const MeshBufferRange& range : ranges.GetRanges()) - { - 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.Start * sizeof(T), copysize); - datapos += copysize; + UploadData(Mesh->NodeBuffer.get(), sizeof(CollisionNodeBufferHeader) + range.Start * sizeof(CollisionNode), &Mesh->Mesh->Mesh.Nodes[range.Start], range.Count() * sizeof(CollisionNode), "NodeBuffer"); } } @@ -846,7 +872,8 @@ void VkLevelMeshUploader::UploadSurfaces() { for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Surface.GetRanges()) { - SurfaceInfo* surfaces = (SurfaceInfo*)(data + datapos); + SurfaceInfo* surfaces = (SurfaceInfo*)GetUploadPtr(range.Count() * sizeof(SurfaceInfo)); + for (int j = 0, count = range.Count(); j < count; j++) { LevelMeshSurface* surface = &Mesh->Mesh->Mesh.Surfaces[range.Start + j]; @@ -871,10 +898,7 @@ void VkLevelMeshUploader::UploadSurfaces() *(surfaces++) = info; } - size_t copysize = range.Count() * sizeof(SurfaceInfo); - if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->SurfaceBuffer.get(), datapos, range.Start * sizeof(SurfaceInfo), copysize); - datapos += copysize; + UploadData(Mesh->SurfaceBuffer.get(), range.Start * sizeof(SurfaceInfo), nullptr, range.Count() * sizeof(SurfaceInfo), "SurfaceBuffer"); } } @@ -900,12 +924,7 @@ void VkLevelMeshUploader::UploadUniforms() } } - SurfaceUniforms* uniforms = (SurfaceUniforms*)(data + datapos); - size_t copysize = range.Count() * sizeof(SurfaceUniforms); - memcpy(uniforms, Mesh->Mesh->Mesh.Uniforms.Data() + range.Start, copysize); - if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->UniformsBuffer.get(), datapos, range.Start * sizeof(SurfaceUniforms), copysize); - datapos += copysize; + UploadData(Mesh->UniformsBuffer.get(), range.Start * sizeof(SurfaceUniforms), &Mesh->Mesh->Mesh.Uniforms[range.Start], range.Count() * sizeof(SurfaceUniforms), "SurfaceUniforms"); } } @@ -913,7 +932,7 @@ void VkLevelMeshUploader::UploadPortals() { for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Portals.GetRanges()) { - PortalInfo* portals = (PortalInfo*)(data + datapos); + PortalInfo* portals = (PortalInfo*)GetUploadPtr(range.Count() * sizeof(PortalInfo)); for (int i = 0, count = range.Count(); i < count; i++) { const auto& portal = Mesh->Mesh->Portals[range.Start + i]; @@ -922,10 +941,7 @@ void VkLevelMeshUploader::UploadPortals() *(portals++) = info; } - size_t copysize = range.Count() * sizeof(PortalInfo); - if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->PortalBuffer.get(), datapos, range.Start * sizeof(PortalInfo), copysize); - datapos += copysize; + UploadData(Mesh->PortalBuffer.get(), range.Start * sizeof(PortalInfo), nullptr, range.Count() * sizeof(PortalInfo), "PortalBuffer"); } } @@ -933,7 +949,7 @@ void VkLevelMeshUploader::UploadLights() { for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Light.GetRanges()) { - LightInfo* lights = (LightInfo*)(data + datapos); + LightInfo* lights = (LightInfo*)GetUploadPtr(range.Count() * sizeof(LightInfo)); for (int i = 0, count = range.Count(); i < count; i++) { const auto& light = Mesh->Mesh->Mesh.Lights[range.Start + i]; @@ -950,10 +966,7 @@ void VkLevelMeshUploader::UploadLights() *(lights++) = info; } - size_t copysize = range.Count() * sizeof(LightInfo); - if (copysize > 0) - copyCommands.emplace_back(transferBuffer.get(), Mesh->LightBuffer.get(), datapos, range.Start * sizeof(LightInfo), copysize); - datapos += copysize; + UploadData(Mesh->LightBuffer.get(), range.Start * sizeof(LightInfo), nullptr, range.Count() * sizeof(LightInfo), "LightBuffer"); } } diff --git a/src/common/rendering/vulkan/vk_levelmesh.h b/src/common/rendering/vulkan/vk_levelmesh.h index 6b2f18b0e..ed7032743 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.h +++ b/src/common/rendering/vulkan/vk_levelmesh.h @@ -192,11 +192,15 @@ private: void UploadLights(); template - void UploadRanges(const MeshBufferUploads& ranges, const T* srcbuffer, VulkanBuffer* destbuffer); + void UploadRanges(const MeshBufferUploads& ranges, const T* srcbuffer, VulkanBuffer* destbuffer, const char* buffername); + + void* GetUploadPtr(size_t size); + void UploadData(VulkanBuffer* dest, size_t destOffset, const void* src, size_t size, const char* buffername); VkLevelMesh* Mesh = nullptr; uint8_t* data = nullptr; size_t datapos = 0; + size_t datasize = 0; std::unique_ptr transferBuffer; struct CopyCommand