diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp index a9b7b4528..fe51d4a32 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp @@ -81,14 +81,14 @@ LevelSubmesh::LevelSubmesh() Mesh.Vertices.Push({ maxval, maxval, maxval }); for (int i = 0; i < 3 * 4; i++) - Mesh.Elements.Push(i); + Mesh.Indexes.Push(i); UpdateCollision(); } void LevelSubmesh::UpdateCollision() { - Collision = std::make_unique(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Elements.Data(), Mesh.Elements.Size()); + Collision = std::make_unique(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.Indexes.Size()); } void LevelSubmesh::GatherSurfacePixelStats(LevelMeshSurfaceStats& stats) diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index 9786c4c28..f48cc640d 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -259,7 +259,7 @@ public: struct { TArray Vertices; - TArray Elements; + TArray Indexes; TArray SurfaceIndexes; TArray UniformIndexes; TArray Uniforms; diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp index 218d17ea5..12ff1b385 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp @@ -91,7 +91,7 @@ void VkDescriptorSetManager::UpdateLevelMeshSet() WriteDescriptors() .AddBuffer(LevelMesh.Set.get(), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, rsbuffers->Viewpoint.UBO.get(), 0, sizeof(HWViewpointUniforms)) .AddBuffer(LevelMesh.Set.get(), 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, rsbuffers->MatrixBuffer->UBO(), 0, sizeof(MatricesUBO)) - .AddBuffer(LevelMesh.Set.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetSurfaceUniformsBuffer()) + .AddBuffer(LevelMesh.Set.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetUniformsBuffer()) .AddBuffer(LevelMesh.Set.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, rsbuffers->Lightbuffer.UBO.get(), 0, sizeof(LightBufferUBO)) .AddBuffer(LevelMesh.Set.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, rsbuffers->Bonebuffer.SSO.get()) .Execute(fb->GetDevice()); diff --git a/src/common/rendering/vulkan/vk_levelmesh.cpp b/src/common/rendering/vulkan/vk_levelmesh.cpp index aaa74ddc6..8d1bf92db 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.cpp +++ b/src/common/rendering/vulkan/vk_levelmesh.cpp @@ -53,7 +53,7 @@ void VkLevelMesh::Reset() deletelist->Add(std::move(IndexBuffer)); deletelist->Add(std::move(NodeBuffer)); deletelist->Add(std::move(SurfaceBuffer)); - deletelist->Add(std::move(SurfaceUniformsBuffer)); + deletelist->Add(std::move(UniformsBuffer)); deletelist->Add(std::move(SurfaceIndexBuffer)); deletelist->Add(std::move(PortalBuffer)); deletelist->Add(std::move(StaticBLAS.ScratchBuffer)); @@ -93,289 +93,8 @@ void VkLevelMesh::BeginFrame() void VkLevelMesh::UploadMeshes(bool dynamicOnly) { - TArray locations(2); - - // Find submesh buffer sizes - for (LevelSubmesh* submesh : { Mesh->StaticMesh.get(), Mesh->DynamicMesh.get() }) - { - SubmeshBufferLocation location; - location.Submesh = submesh; - location.VertexSize = submesh->Mesh.Vertices.Size(); - location.IndexSize = submesh->Mesh.Elements.Size(); - location.NodeSize = (int)submesh->Collision->get_nodes().size(); - location.SurfaceIndexSize = submesh->Mesh.SurfaceIndexes.Size(); - location.SurfaceSize = submesh->GetSurfaceCount(); - location.UniformsSize = submesh->Mesh.Uniforms.Size(); - locations.Push(location); - } - - // Find submesh locations in buffers - for (unsigned int i = 1, count = locations.Size(); i < count; i++) - { - const SubmeshBufferLocation& prev = locations[i - 1]; - SubmeshBufferLocation& cur = locations[i]; - cur.VertexOffset = prev.VertexOffset + prev.VertexSize; - cur.IndexOffset = prev.IndexOffset + prev.IndexSize; - cur.NodeOffset = prev.NodeOffset + prev.NodeSize; - cur.SurfaceIndexOffset = prev.SurfaceIndexOffset + prev.SurfaceIndexSize; - cur.SurfaceOffset = prev.SurfaceOffset + prev.SurfaceSize; - cur.UniformsOffset = prev.UniformsOffset + prev.UniformsSize; - - if ( - cur.VertexOffset + cur.VertexSize > GetMaxVertexBufferSize() || - cur.IndexOffset + cur.IndexSize > GetMaxIndexBufferSize() || - cur.NodeOffset + cur.NodeSize > GetMaxNodeBufferSize() || - cur.SurfaceOffset + cur.SurfaceSize > GetMaxSurfaceBufferSize() || - cur.UniformsOffset + cur.UniformsSize > GetMaxUniformsBufferSize() || - cur.SurfaceIndexOffset + cur.SurfaceIndexSize > GetMaxSurfaceIndexBufferSize()) - { - I_FatalError("Dynamic accel struct buffers are too small!"); - } - } - - unsigned int start = dynamicOnly; - unsigned int end = locations.Size(); - - // Figure out how much memory we need to transfer it to the GPU - size_t transferBufferSize = sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode); - for (unsigned int i = start; i < end; i++) - { - const SubmeshBufferLocation& cur = locations[i]; - transferBufferSize += cur.Submesh->Mesh.Vertices.Size() * sizeof(FFlatVertex); - transferBufferSize += cur.Submesh->Mesh.UniformIndexes.Size() * sizeof(int); - transferBufferSize += cur.Submesh->Mesh.Elements.Size() * sizeof(uint32_t); - transferBufferSize += cur.Submesh->Collision->get_nodes().size() * sizeof(CollisionNode); - transferBufferSize += cur.Submesh->Mesh.SurfaceIndexes.Size() * sizeof(int); - transferBufferSize += cur.Submesh->GetSurfaceCount() * sizeof(SurfaceInfo); - transferBufferSize += cur.Submesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms); - } - if (!dynamicOnly) - transferBufferSize += Mesh->StaticMesh->Portals.Size() * sizeof(PortalInfo); - - // Begin the transfer - auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); - auto transferBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .Size(transferBufferSize) - .DebugName("UploadMeshes") - .Create(fb->GetDevice()); - - uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferBufferSize); - size_t datapos = 0; - - // Copy node buffer header and create a root node that merges the static and dynamic AABB trees - if (locations[1].Submesh->Collision->get_root() != -1) - { - int root0 = locations[0].Submesh->Collision->get_root(); - int root1 = locations[1].Submesh->Collision->get_root(); - const auto& node0 = locations[0].Submesh->Collision->get_nodes()[root0]; - const auto& node1 = locations[1].Submesh->Collision->get_nodes()[root1]; - - FVector3 aabbMin(std::min(node0.aabb.min.X, node1.aabb.min.X), std::min(node0.aabb.min.Y, node1.aabb.min.Y), std::min(node0.aabb.min.Z, node1.aabb.min.Z)); - FVector3 aabbMax(std::max(node0.aabb.max.X, node1.aabb.max.X), std::max(node0.aabb.max.Y, node1.aabb.max.Y), std::max(node0.aabb.max.Z, node1.aabb.max.Z)); - CollisionBBox bbox(aabbMin, aabbMax); - - CollisionNodeBufferHeader nodesHeader; - nodesHeader.root = locations[1].NodeOffset + locations[1].NodeSize; - - CollisionNode info; - info.center = bbox.Center; - info.extents = bbox.Extents; - info.left = locations[0].NodeOffset + root0; - info.right = locations[1].NodeOffset + root1; - info.element_index = -1; - - *((CollisionNodeBufferHeader*)(data + datapos)) = nodesHeader; - *((CollisionNode*)(data + datapos + sizeof(CollisionNodeBufferHeader))) = info; - - cmdbuffer->copyBuffer(transferBuffer.get(), NodeBuffer.get(), datapos, 0, sizeof(CollisionNodeBufferHeader)); - cmdbuffer->copyBuffer(transferBuffer.get(), NodeBuffer.get(), datapos + sizeof(CollisionNodeBufferHeader), sizeof(CollisionNodeBufferHeader) + nodesHeader.root * sizeof(CollisionNode), sizeof(CollisionNode)); - } - else // second submesh is empty, just point the header at the first one - { - CollisionNodeBufferHeader nodesHeader; - nodesHeader.root = locations[0].Submesh->Collision->get_root(); - - *((CollisionNodeBufferHeader*)(data + datapos)) = nodesHeader; - cmdbuffer->copyBuffer(transferBuffer.get(), NodeBuffer.get(), datapos, 0, sizeof(CollisionNodeBufferHeader)); - } - datapos += sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode); - - // Copy vertices - for (unsigned int i = start; i < end; i++) - { - const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - - size_t copysize = submesh->Mesh.Vertices.Size() * sizeof(FFlatVertex); - memcpy(data + datapos, submesh->Mesh.Vertices.Data(), copysize); - if (copysize > 0) - cmdbuffer->copyBuffer(transferBuffer.get(), VertexBuffer.get(), datapos, cur.VertexOffset * sizeof(FFlatVertex), copysize); - datapos += copysize; - } - - // Copy uniform indexes - for (unsigned int i = start; i < end; i++) - { - const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - - size_t copysize = submesh->Mesh.UniformIndexes.Size() * sizeof(int); - memcpy(data + datapos, submesh->Mesh.UniformIndexes.Data(), copysize); - if (copysize > 0) - cmdbuffer->copyBuffer(transferBuffer.get(), UniformIndexBuffer.get(), datapos, cur.VertexOffset * sizeof(int), copysize); - datapos += copysize; - } - - // Copy indexes - for (unsigned int i = start; i < end; i++) - { - const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - - uint32_t* indexes = (uint32_t*)(data + datapos); - for (int j = 0, count = submesh->Mesh.Elements.Size(); j < count; ++j) - *(indexes++) = cur.VertexOffset + submesh->Mesh.Elements[j]; - - size_t copysize = submesh->Mesh.Elements.Size() * sizeof(uint32_t); - if (copysize > 0) - cmdbuffer->copyBuffer(transferBuffer.get(), IndexBuffer.get(), datapos, cur.IndexOffset * sizeof(uint32_t), copysize); - datapos += copysize; - } - - // Copy collision nodes - for (unsigned int i = start; i < end; i++) - { - const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - - CollisionNode* nodes = (CollisionNode*)(data + datapos); - for (auto& node : submesh->Collision->get_nodes()) - { - CollisionNode info; - info.center = node.aabb.Center; - info.extents = node.aabb.Extents; - info.left = node.left != -1 ? node.left + cur.NodeOffset : -1; - info.right = node.right != -1 ? node.right + cur.NodeOffset : -1; - info.element_index = node.element_index != -1 ? node.element_index + cur.IndexOffset : -1; - *(nodes++) = info; - } - - size_t copysize = submesh->Collision->get_nodes().size() * sizeof(CollisionNode); - if (copysize > 0) - cmdbuffer->copyBuffer(transferBuffer.get(), NodeBuffer.get(), datapos, +sizeof(CollisionNodeBufferHeader) + cur.NodeOffset * sizeof(CollisionNode), copysize); - datapos += copysize; - } - - // Copy surface indexes - for (unsigned int i = start; i < end; i++) - { - const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - - int* indexes = (int*)(data + datapos); - for (int j = 0, count = submesh->Mesh.SurfaceIndexes.Size(); j < count; ++j) - *(indexes++) = cur.SurfaceIndexOffset + submesh->Mesh.SurfaceIndexes[j]; - - size_t copysize = submesh->Mesh.SurfaceIndexes.Size() * sizeof(int); - if (copysize > 0) - cmdbuffer->copyBuffer(transferBuffer.get(), SurfaceIndexBuffer.get(), datapos, cur.SurfaceIndexOffset * sizeof(int), copysize); - datapos += copysize; - } - - // Copy surfaces - for (unsigned int i = start; i < end; i++) - { - const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - - SurfaceInfo* surfaces = (SurfaceInfo*)(data + datapos); - for (int j = 0, count = submesh->GetSurfaceCount(); j < count; ++j) - { - LevelMeshSurface* surface = submesh->GetSurface(j); - - SurfaceInfo info; - info.Normal = FVector3(surface->plane.X, surface->plane.Z, surface->plane.Y); - info.PortalIndex = surface->portalIndex; - info.SamplingDistance = (float)surface->sampleDimension; - info.Sky = surface->bSky; - info.Alpha = surface->alpha; - if (surface->texture) - { - auto mat = FMaterial::ValidateTexture(surface->texture, 0); - info.TextureIndex = fb->GetBindlessTextureIndex(mat, CLAMP_NONE, 0); - } - else - { - info.TextureIndex = 0; - } - - *(surfaces++) = info; - } - - size_t copysize = submesh->GetSurfaceCount() * sizeof(SurfaceInfo); - if (copysize > 0) - cmdbuffer->copyBuffer(transferBuffer.get(), SurfaceBuffer.get(), datapos, cur.SurfaceOffset * sizeof(SurfaceInfo), copysize); - datapos += copysize; - } - - // Copy surface uniforms - for (unsigned int i = start; i < end; i++) - { - const SubmeshBufferLocation& cur = locations[i]; - auto submesh = cur.Submesh; - - for (int j = 0, count = submesh->Mesh.Uniforms.Size(); j < count; j++) - { - auto& surfaceUniforms = submesh->Mesh.Uniforms[j]; - auto& material = submesh->Mesh.Materials[j]; - if (material.mMaterial) - { - auto source = material.mMaterial->Source(); - surfaceUniforms.uSpecularMaterial = { source->GetGlossiness(), source->GetSpecularLevel() }; - surfaceUniforms.uTextureIndex = fb->GetBindlessTextureIndex(material.mMaterial, material.mClampMode, material.mTranslation); - } - else - { - surfaceUniforms.uTextureIndex = 0; - } - } - - SurfaceUniforms* uniforms = (SurfaceUniforms*)(data + datapos); - size_t copysize = submesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms); - memcpy(uniforms, submesh->Mesh.Uniforms.Data(), copysize); - if (copysize > 0) - cmdbuffer->copyBuffer(transferBuffer.get(), SurfaceUniformsBuffer.get(), datapos, cur.UniformsOffset * sizeof(SurfaceUniforms), copysize); - datapos += copysize; - } - - // Copy portals - if (!dynamicOnly) - { - PortalInfo* portals = (PortalInfo*)(data + datapos); - for (auto& portal : Mesh->StaticMesh->Portals) - { - PortalInfo info; - info.transformation = portal.transformation; - *(portals++) = info; - } - - size_t copysize = Mesh->StaticMesh->Portals.Size() * sizeof(PortalInfo); - if (copysize > 0) - cmdbuffer->copyBuffer(transferBuffer.get(), PortalBuffer.get(), datapos, 0, copysize); - datapos += copysize; - } - - assert(datapos == transferBufferSize); - - // End the transfer - transferBuffer->Unmap(); - - fb->GetCommands()->TransferDeleteList->Add(std::move(transferBuffer)); - - PipelineBarrier() - .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, useRayQuery ? VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR : VK_ACCESS_SHADER_READ_BIT) - .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, useRayQuery ? VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + VkLevelMeshUploader uploader(this); + uploader.Upload(dynamicOnly); } int VkLevelMesh::GetMaxVertexBufferSize() @@ -385,7 +104,7 @@ int VkLevelMesh::GetMaxVertexBufferSize() int VkLevelMesh::GetMaxIndexBufferSize() { - return Mesh->StaticMesh->Mesh.Elements.Size() + MaxDynamicIndexes; + return Mesh->StaticMesh->Mesh.Indexes.Size() + MaxDynamicIndexes; } int VkLevelMesh::GetMaxNodeBufferSize() @@ -460,7 +179,7 @@ void VkLevelMesh::CreateBuffers() .DebugName("SurfaceBuffer") .Create(fb->GetDevice()); - SurfaceUniformsBuffer = BufferBuilder() + UniformsBuffer = BufferBuilder() .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) .Size(GetMaxUniformsBufferSize() * sizeof(SurfaceUniforms)) .DebugName("SurfaceUniformsBuffer") @@ -497,7 +216,7 @@ VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(LevelSubmesh* submesh, bool preferFast buildInfo.geometryCount = 1; buildInfo.ppGeometries = geometries; - uint32_t maxPrimitiveCount = submesh->Mesh.Elements.Size() / 3; + uint32_t maxPrimitiveCount = submesh->Mesh.Indexes.Size() / 3; VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR }; vkGetAccelerationStructureBuildSizesKHR(fb->GetDevice()->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxPrimitiveCount, &sizeInfo); @@ -545,7 +264,7 @@ void VkLevelMesh::CreateStaticBLAS() void VkLevelMesh::CreateDynamicBLAS() { - DynamicBLAS = CreateBLAS(Mesh->DynamicMesh.get(), true, Mesh->StaticMesh->Mesh.Vertices.Size(), Mesh->StaticMesh->Mesh.Elements.Size()); + DynamicBLAS = CreateBLAS(Mesh->DynamicMesh.get(), true, Mesh->StaticMesh->Mesh.Vertices.Size(), Mesh->StaticMesh->Mesh.Indexes.Size()); } void VkLevelMesh::CreateTopLevelAS() @@ -657,7 +376,7 @@ void VkLevelMesh::UpdateDynamicBLAS() deletelist->Add(std::move(DynamicBLAS.AccelStructBuffer)); deletelist->Add(std::move(DynamicBLAS.AccelStruct)); - DynamicBLAS = CreateBLAS(Mesh->DynamicMesh.get(), true, Mesh->StaticMesh->Mesh.Vertices.Size(), Mesh->StaticMesh->Mesh.Elements.Size()); + DynamicBLAS = CreateBLAS(Mesh->DynamicMesh.get(), true, Mesh->StaticMesh->Mesh.Vertices.Size(), Mesh->StaticMesh->Mesh.Indexes.Size()); } void VkLevelMesh::UpdateTopLevelAS() @@ -717,3 +436,345 @@ void VkLevelMesh::UpdateTopLevelAS() .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); } +///////////////////////////////////////////////////////////////////////////// + +VkLevelMeshUploader::VkLevelMeshUploader(VkLevelMesh* mesh) : Mesh(mesh) +{ +} + +void VkLevelMeshUploader::Upload(bool dynamicOnly) +{ + UpdateSizes(); + UpdateLocations(); + + start = dynamicOnly; + end = locations.Size(); + + size_t transferBufferSize = GetTransferSize(); + if (transferBufferSize == 0) + return; + + BeginTransfer(transferBufferSize); + + UploadNodes(); + UploadVertices(); + UploadUniformIndexes(); + UploadIndexes(); + UploadSurfaceIndexes(); + UploadSurfaces(); + UploadUniforms(); + UploadPortals(); + + EndTransfer(transferBufferSize); +} + +void VkLevelMeshUploader::BeginTransfer(size_t transferBufferSize) +{ + cmdbuffer = Mesh->fb->GetCommands()->GetTransferCommands(); + transferBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .Size(transferBufferSize) + .DebugName("UploadMeshes") + .Create(Mesh->fb->GetDevice()); + + data = (uint8_t*)transferBuffer->Map(0, transferBufferSize); + datapos = 0; +} + +void VkLevelMeshUploader::EndTransfer(size_t transferBufferSize) +{ + assert(datapos == transferBufferSize); + + transferBuffer->Unmap(); + + Mesh->fb->GetCommands()->TransferDeleteList->Add(std::move(transferBuffer)); + + PipelineBarrier() + .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, Mesh->useRayQuery ? VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR : VK_ACCESS_SHADER_READ_BIT) + .Execute(Mesh->fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, Mesh->useRayQuery ? VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); +} + +void VkLevelMeshUploader::UploadNodes() +{ + // Copy node buffer header and create a root node that merges the static and dynamic AABB trees + if (locations[1].Submesh->Collision->get_root() != -1) + { + int root0 = locations[0].Submesh->Collision->get_root(); + int root1 = locations[1].Submesh->Collision->get_root(); + const auto& node0 = locations[0].Submesh->Collision->get_nodes()[root0]; + const auto& node1 = locations[1].Submesh->Collision->get_nodes()[root1]; + + FVector3 aabbMin(std::min(node0.aabb.min.X, node1.aabb.min.X), std::min(node0.aabb.min.Y, node1.aabb.min.Y), std::min(node0.aabb.min.Z, node1.aabb.min.Z)); + FVector3 aabbMax(std::max(node0.aabb.max.X, node1.aabb.max.X), std::max(node0.aabb.max.Y, node1.aabb.max.Y), std::max(node0.aabb.max.Z, node1.aabb.max.Z)); + CollisionBBox bbox(aabbMin, aabbMax); + + CollisionNodeBufferHeader nodesHeader; + nodesHeader.root = locations[1].Node.Offset + locations[1].Node.Size; + + CollisionNode info; + info.center = bbox.Center; + info.extents = bbox.Extents; + info.left = locations[0].Node.Offset + root0; + info.right = locations[1].Node.Offset + root1; + info.element_index = -1; + + *((CollisionNodeBufferHeader*)(data + datapos)) = nodesHeader; + *((CollisionNode*)(data + datapos + sizeof(CollisionNodeBufferHeader))) = info; + + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, 0, sizeof(CollisionNodeBufferHeader)); + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos + sizeof(CollisionNodeBufferHeader), sizeof(CollisionNodeBufferHeader) + nodesHeader.root * sizeof(CollisionNode), sizeof(CollisionNode)); + } + else // second submesh is empty, just point the header at the first one + { + CollisionNodeBufferHeader nodesHeader; + nodesHeader.root = locations[0].Submesh->Collision->get_root(); + + *((CollisionNodeBufferHeader*)(data + datapos)) = nodesHeader; + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, 0, sizeof(CollisionNodeBufferHeader)); + } + datapos += sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode); + + // Copy collision nodes + for (unsigned int i = start; i < end; i++) + { + const SubmeshBufferLocation& cur = locations[i]; + auto submesh = cur.Submesh; + + CollisionNode* nodes = (CollisionNode*)(data + datapos); + for (auto& node : submesh->Collision->get_nodes()) + { + CollisionNode info; + info.center = node.aabb.Center; + info.extents = node.aabb.Extents; + info.left = node.left != -1 ? node.left + cur.Node.Offset : -1; + info.right = node.right != -1 ? node.right + cur.Node.Offset : -1; + info.element_index = node.element_index != -1 ? node.element_index + cur.Index.Offset : -1; + *(nodes++) = info; + } + + size_t copysize = submesh->Collision->get_nodes().size() * sizeof(CollisionNode); + if (copysize > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, +sizeof(CollisionNodeBufferHeader) + cur.Node.Offset * sizeof(CollisionNode), copysize); + datapos += copysize; + } +} + +void VkLevelMeshUploader::UploadVertices() +{ + for (unsigned int i = start; i < end; i++) + { + const SubmeshBufferLocation& cur = locations[i]; + auto submesh = cur.Submesh; + + size_t copysize = submesh->Mesh.Vertices.Size() * sizeof(FFlatVertex); + memcpy(data + datapos, submesh->Mesh.Vertices.Data(), copysize); + if (copysize > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->VertexBuffer.get(), datapos, cur.Vertex.Offset * sizeof(FFlatVertex), copysize); + datapos += copysize; + } +} + +void VkLevelMeshUploader::UploadUniformIndexes() +{ + for (unsigned int i = start; i < end; i++) + { + const SubmeshBufferLocation& cur = locations[i]; + auto submesh = cur.Submesh; + + size_t copysize = submesh->Mesh.UniformIndexes.Size() * sizeof(int); + memcpy(data + datapos, submesh->Mesh.UniformIndexes.Data(), copysize); + if (copysize > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->UniformIndexBuffer.get(), datapos, cur.UniformIndexes.Offset * sizeof(int), copysize); + datapos += copysize; + } +} + +void VkLevelMeshUploader::UploadIndexes() +{ + for (unsigned int i = start; i < end; i++) + { + const SubmeshBufferLocation& cur = locations[i]; + auto submesh = cur.Submesh; + + uint32_t* indexes = (uint32_t*)(data + datapos); + for (int j = 0, count = submesh->Mesh.Indexes.Size(); j < count; ++j) + *(indexes++) = cur.Vertex.Offset + submesh->Mesh.Indexes[j]; + + size_t copysize = submesh->Mesh.Indexes.Size() * sizeof(uint32_t); + if (copysize > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->IndexBuffer.get(), datapos, cur.Index.Offset * sizeof(uint32_t), copysize); + datapos += copysize; + } +} + +void VkLevelMeshUploader::UploadSurfaceIndexes() +{ + for (unsigned int i = start; i < end; i++) + { + const SubmeshBufferLocation& cur = locations[i]; + auto submesh = cur.Submesh; + + int* indexes = (int*)(data + datapos); + for (int j = 0, count = submesh->Mesh.SurfaceIndexes.Size(); j < count; ++j) + *(indexes++) = cur.SurfaceIndex.Offset + submesh->Mesh.SurfaceIndexes[j]; + + size_t copysize = submesh->Mesh.SurfaceIndexes.Size() * sizeof(int); + if (copysize > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->SurfaceIndexBuffer.get(), datapos, cur.SurfaceIndex.Offset * sizeof(int), copysize); + datapos += copysize; + } +} + +void VkLevelMeshUploader::UploadSurfaces() +{ + for (unsigned int i = start; i < end; i++) + { + const SubmeshBufferLocation& cur = locations[i]; + auto submesh = cur.Submesh; + + SurfaceInfo* surfaces = (SurfaceInfo*)(data + datapos); + for (int j = 0, count = submesh->GetSurfaceCount(); j < count; ++j) + { + LevelMeshSurface* surface = submesh->GetSurface(j); + + SurfaceInfo info; + info.Normal = FVector3(surface->plane.X, surface->plane.Z, surface->plane.Y); + info.PortalIndex = surface->portalIndex; + info.SamplingDistance = (float)surface->sampleDimension; + info.Sky = surface->bSky; + info.Alpha = surface->alpha; + if (surface->texture) + { + auto mat = FMaterial::ValidateTexture(surface->texture, 0); + info.TextureIndex = Mesh->fb->GetBindlessTextureIndex(mat, CLAMP_NONE, 0); + } + else + { + info.TextureIndex = 0; + } + + *(surfaces++) = info; + } + + size_t copysize = submesh->GetSurfaceCount() * sizeof(SurfaceInfo); + if (copysize > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->SurfaceBuffer.get(), datapos, cur.Surface.Offset * sizeof(SurfaceInfo), copysize); + datapos += copysize; + } +} + +void VkLevelMeshUploader::UploadUniforms() +{ + for (unsigned int i = start; i < end; i++) + { + const SubmeshBufferLocation& cur = locations[i]; + auto submesh = cur.Submesh; + + for (int j = 0, count = submesh->Mesh.Uniforms.Size(); j < count; j++) + { + auto& surfaceUniforms = submesh->Mesh.Uniforms[j]; + auto& material = submesh->Mesh.Materials[j]; + if (material.mMaterial) + { + auto source = material.mMaterial->Source(); + surfaceUniforms.uSpecularMaterial = { source->GetGlossiness(), source->GetSpecularLevel() }; + surfaceUniforms.uTextureIndex = Mesh->fb->GetBindlessTextureIndex(material.mMaterial, material.mClampMode, material.mTranslation); + } + else + { + surfaceUniforms.uTextureIndex = 0; + } + } + + SurfaceUniforms* uniforms = (SurfaceUniforms*)(data + datapos); + size_t copysize = submesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms); + memcpy(uniforms, submesh->Mesh.Uniforms.Data(), copysize); + if (copysize > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->UniformsBuffer.get(), datapos, cur.Uniforms.Offset * sizeof(SurfaceUniforms), copysize); + datapos += copysize; + } +} + +void VkLevelMeshUploader::UploadPortals() +{ + if (start == 0) + { + PortalInfo* portals = (PortalInfo*)(data + datapos); + for (auto& portal : Mesh->Mesh->StaticMesh->Portals) + { + PortalInfo info; + info.transformation = portal.transformation; + *(portals++) = info; + } + + size_t copysize = Mesh->Mesh->StaticMesh->Portals.Size() * sizeof(PortalInfo); + if (copysize > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->PortalBuffer.get(), datapos, 0, copysize); + datapos += copysize; + } +} + +void VkLevelMeshUploader::UpdateSizes() +{ + for (LevelSubmesh* submesh : { Mesh->GetMesh()->StaticMesh.get(), Mesh->GetMesh()->DynamicMesh.get() }) + { + SubmeshBufferLocation location; + location.Submesh = submesh; + location.Vertex.Size = submesh->Mesh.Vertices.Size(); + location.Index.Size = submesh->Mesh.Indexes.Size(); + location.Node.Size = (int)submesh->Collision->get_nodes().size(); + location.SurfaceIndex.Size = submesh->Mesh.SurfaceIndexes.Size(); + location.Surface.Size = submesh->GetSurfaceCount(); + location.UniformIndexes.Size = submesh->Mesh.UniformIndexes.Size(); + location.Uniforms.Size = submesh->Mesh.Uniforms.Size(); + locations.Push(location); + } +} + +void VkLevelMeshUploader::UpdateLocations() +{ + for (unsigned int i = 1, count = locations.Size(); i < count; i++) + { + const SubmeshBufferLocation& prev = locations[i - 1]; + SubmeshBufferLocation& cur = locations[i]; + cur.Vertex.Offset = prev.Vertex.Offset + prev.Vertex.Size; + cur.Index.Offset = prev.Index.Offset + prev.Index.Size; + cur.Node.Offset = prev.Node.Offset + prev.Node.Size; + cur.SurfaceIndex.Offset = prev.SurfaceIndex.Offset + prev.SurfaceIndex.Size; + cur.Surface.Offset = prev.Surface.Offset + prev.Surface.Size; + cur.UniformIndexes.Offset = prev.UniformIndexes.Offset + prev.UniformIndexes.Size; + cur.Uniforms.Offset = prev.Uniforms.Offset + prev.Uniforms.Size; + + if ( + cur.Vertex.Offset + cur.Vertex.Size > Mesh->GetMaxVertexBufferSize() || + cur.Index.Offset + cur.Index.Size > Mesh->GetMaxIndexBufferSize() || + cur.Node.Offset + cur.Node.Size > Mesh->GetMaxNodeBufferSize() || + cur.SurfaceIndex.Offset + cur.SurfaceIndex.Size > Mesh->GetMaxSurfaceIndexBufferSize() || + cur.Surface.Offset + cur.Surface.Size > Mesh->GetMaxSurfaceBufferSize() || + cur.UniformIndexes.Offset + cur.UniformIndexes.Size > Mesh->GetMaxVertexBufferSize() || + cur.Uniforms.Offset + cur.Uniforms.Size > Mesh->GetMaxUniformsBufferSize()) + { + I_FatalError("Dynamic accel struct buffers are too small!"); + } + } +} + +size_t VkLevelMeshUploader::GetTransferSize() +{ + // Figure out how much memory we need to transfer it to the GPU + size_t transferBufferSize = sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode); + for (unsigned int i = start; i < end; i++) + { + const SubmeshBufferLocation& cur = locations[i]; + transferBufferSize += cur.Submesh->Mesh.Vertices.Size() * sizeof(FFlatVertex); + transferBufferSize += cur.Submesh->Mesh.UniformIndexes.Size() * sizeof(int); + transferBufferSize += cur.Submesh->Mesh.Indexes.Size() * sizeof(uint32_t); + transferBufferSize += cur.Submesh->Collision->get_nodes().size() * sizeof(CollisionNode); + transferBufferSize += cur.Submesh->Mesh.SurfaceIndexes.Size() * sizeof(int); + transferBufferSize += cur.Submesh->GetSurfaceCount() * sizeof(SurfaceInfo); + transferBufferSize += cur.Submesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms); + } + if (start == 0) + transferBufferSize += Mesh->GetMesh()->StaticMesh->Portals.Size() * sizeof(PortalInfo); + return transferBufferSize; +} diff --git a/src/common/rendering/vulkan/vk_levelmesh.h b/src/common/rendering/vulkan/vk_levelmesh.h index cc4c33a98..35f428c51 100644 --- a/src/common/rendering/vulkan/vk_levelmesh.h +++ b/src/common/rendering/vulkan/vk_levelmesh.h @@ -42,21 +42,22 @@ struct PortalInfo VSMatrix transformation; }; +struct SubmeshBufferRange +{ + int Offset = 0; + int Size = 0; +}; + struct SubmeshBufferLocation { LevelSubmesh* Submesh = nullptr; - int VertexOffset = 0; - int VertexSize = 0; - int IndexOffset = 0; - int IndexSize = 0; - int NodeOffset = 0; - int NodeSize = 0; - int SurfaceIndexOffset = 0; - int SurfaceIndexSize = 0; - int SurfaceOffset = 0; - int SurfaceSize = 0; - int UniformsOffset = 0; - int UniformsSize = 0; + SubmeshBufferRange Vertex; + SubmeshBufferRange Index; + SubmeshBufferRange Node; + SubmeshBufferRange SurfaceIndex; + SubmeshBufferRange Surface; + SubmeshBufferRange UniformIndexes; + SubmeshBufferRange Uniforms; }; class VkLevelMesh @@ -74,7 +75,7 @@ public: VulkanBuffer* GetNodeBuffer() { return NodeBuffer.get(); } VulkanBuffer* GetSurfaceIndexBuffer() { return SurfaceIndexBuffer.get(); } VulkanBuffer* GetSurfaceBuffer() { return SurfaceBuffer.get(); } - VulkanBuffer* GetSurfaceUniformsBuffer() { return SurfaceUniformsBuffer.get(); } + VulkanBuffer* GetUniformsBuffer() { return UniformsBuffer.get(); } VulkanBuffer* GetPortalBuffer() { return PortalBuffer.get(); } LevelMesh* GetMesh() { return Mesh; } @@ -118,7 +119,7 @@ private: std::unique_ptr IndexBuffer; std::unique_ptr SurfaceIndexBuffer; std::unique_ptr SurfaceBuffer; - std::unique_ptr SurfaceUniformsBuffer; + std::unique_ptr UniformsBuffer; std::unique_ptr PortalBuffer; std::unique_ptr NodeBuffer; @@ -142,4 +143,38 @@ private: std::unique_ptr AccelStructBuffer; std::unique_ptr AccelStruct; } TopLevelAS; + + friend class VkLevelMeshUploader; +}; + +class VkLevelMeshUploader +{ +public: + VkLevelMeshUploader(VkLevelMesh* mesh); + + void Upload(bool dynamicOnly); + +private: + void BeginTransfer(size_t transferBufferSize); + void EndTransfer(size_t transferBufferSize); + void UploadNodes(); + void UploadVertices(); + void UploadUniformIndexes(); + void UploadIndexes(); + void UploadSurfaceIndexes(); + void UploadSurfaces(); + void UploadUniforms(); + void UploadPortals(); + void UpdateSizes(); + void UpdateLocations(); + size_t GetTransferSize(); + + VkLevelMesh* Mesh; + TArray locations; + unsigned int start = 0; + unsigned int end = 0; + uint8_t* data = nullptr; + size_t datapos = 0; + VulkanCommandBuffer* cmdbuffer = nullptr; + std::unique_ptr transferBuffer; }; diff --git a/src/common/rendering/vulkan/vk_lightmapper.cpp b/src/common/rendering/vulkan/vk_lightmapper.cpp index dc6b54fc2..5c84685dd 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.cpp +++ b/src/common/rendering/vulkan/vk_lightmapper.cpp @@ -190,7 +190,7 @@ void VkLightmapper::Render() if (targetSurface->Submesh != mesh->StaticMesh.get()) { surfaceIndexOffset = mesh->StaticMesh->GetSurfaceCount(); - firstIndexOffset = mesh->StaticMesh->Mesh.Elements.Size(); + firstIndexOffset = mesh->StaticMesh->Mesh.Indexes.Size(); } LightmapRaytracePC pc; diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 7001b0433..b1b3754fd 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -251,7 +251,7 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen auto f = fopen(objFilename.GetChars(), "w"); fprintf(f, "# DoomLevelMesh debug export\n"); - fprintf(f, "# MeshVertices: %u, MeshElements: %u, Surfaces: %u\n", submesh->Mesh.Vertices.Size(), submesh->Mesh.Elements.Size(), submesh->Surfaces.Size()); + fprintf(f, "# Vertices: %u, Indexes: %u, Surfaces: %u\n", submesh->Mesh.Vertices.Size(), submesh->Mesh.Indexes.Size(), submesh->Surfaces.Size()); fprintf(f, "mtllib %s\n", mtlFilename.GetChars()); double scale = 1 / 10.0; @@ -294,7 +294,7 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen bool useErrorMaterial = false; int highestUsedAtlasPage = -1; - for (unsigned i = 0, count = submesh->Mesh.Elements.Size(); i + 2 < count; i += 3) + for (unsigned i = 0, count = submesh->Mesh.Indexes.Size(); i + 2 < count; i += 3) { auto index = submesh->Mesh.SurfaceIndexes[i / 3]; @@ -324,9 +324,9 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen // fprintf(f, "f %d %d %d\n", MeshElements[i] + 1, MeshElements[i + 1] + 1, MeshElements[i + 2] + 1); fprintf(f, "f %d/%d %d/%d %d/%d\n", - submesh->Mesh.Elements[i + 0] + 1, submesh->Mesh.Elements[i + 0] + 1, - submesh->Mesh.Elements[i + 1] + 1, submesh->Mesh.Elements[i + 1] + 1, - submesh->Mesh.Elements[i + 2] + 1, submesh->Mesh.Elements[i + 2] + 1); + submesh->Mesh.Indexes[i + 0] + 1, submesh->Mesh.Indexes[i + 0] + 1, + submesh->Mesh.Indexes[i + 1] + 1, submesh->Mesh.Indexes[i + 1] + 1, + submesh->Mesh.Indexes[i + 2] + 1, submesh->Mesh.Indexes[i + 2] + 1); } diff --git a/src/rendering/hwrenderer/doom_levelsubmesh.cpp b/src/rendering/hwrenderer/doom_levelsubmesh.cpp index 97edf4e04..dd1696f88 100644 --- a/src/rendering/hwrenderer/doom_levelsubmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelsubmesh.cpp @@ -65,7 +65,7 @@ void DoomLevelSubmesh::Reset() Surfaces.Clear(); WallPortals.Clear(); Mesh.Vertices.Clear(); - Mesh.Elements.Clear(); + Mesh.Indexes.Clear(); Mesh.SurfaceIndexes.Clear(); Mesh.UniformIndexes.Clear(); Mesh.Uniforms.Clear(); @@ -328,7 +328,7 @@ void DoomLevelSubmesh::CreateIndexes() { LevelSubmeshDrawRange range; range.PipelineID = it.first >> 32; - range.Start = Mesh.Elements.Size(); + range.Start = Mesh.Indexes.Size(); for (unsigned int i : it.second) { DoomLevelMeshSurface& s = Surfaces[i]; @@ -337,7 +337,7 @@ void DoomLevelSubmesh::CreateIndexes() FFlatVertex* verts = &Mesh.Vertices[pos]; s.Vertices = verts; - s.startElementIndex = Mesh.Elements.Size(); + s.startElementIndex = Mesh.Indexes.Size(); s.numElements = 0; if (s.Type == ST_CEILING) @@ -346,9 +346,9 @@ void DoomLevelSubmesh::CreateIndexes() { if (!IsDegenerate(verts[0].fPos(), verts[j - 1].fPos(), verts[j].fPos())) { - Mesh.Elements.Push(pos); - Mesh.Elements.Push(pos + j - 1); - Mesh.Elements.Push(pos + j); + Mesh.Indexes.Push(pos); + Mesh.Indexes.Push(pos + j - 1); + Mesh.Indexes.Push(pos + j); Mesh.SurfaceIndexes.Push((int)i); s.numElements += 3; } @@ -360,9 +360,9 @@ void DoomLevelSubmesh::CreateIndexes() { if (!IsDegenerate(verts[0].fPos(), verts[j - 1].fPos(), verts[j].fPos())) { - Mesh.Elements.Push(pos + j); - Mesh.Elements.Push(pos + j - 1); - Mesh.Elements.Push(pos); + Mesh.Indexes.Push(pos + j); + Mesh.Indexes.Push(pos + j - 1); + Mesh.Indexes.Push(pos); Mesh.SurfaceIndexes.Push((int)i); s.numElements += 3; } @@ -372,23 +372,23 @@ void DoomLevelSubmesh::CreateIndexes() { if (!IsDegenerate(verts[0].fPos(), verts[2].fPos(), verts[1].fPos())) { - Mesh.Elements.Push(pos + 0); - Mesh.Elements.Push(pos + 1); - Mesh.Elements.Push(pos + 2); + Mesh.Indexes.Push(pos + 0); + Mesh.Indexes.Push(pos + 1); + Mesh.Indexes.Push(pos + 2); Mesh.SurfaceIndexes.Push((int)i); s.numElements += 3; } if (!IsDegenerate(verts[0].fPos(), verts[2].fPos(), verts[3].fPos())) { - Mesh.Elements.Push(pos + 0); - Mesh.Elements.Push(pos + 2); - Mesh.Elements.Push(pos + 3); + Mesh.Indexes.Push(pos + 0); + Mesh.Indexes.Push(pos + 2); + Mesh.Indexes.Push(pos + 3); Mesh.SurfaceIndexes.Push((int)i); s.numElements += 3; } } } - range.Count = Mesh.Elements.Size() - range.Start; + range.Count = Mesh.Indexes.Size() - range.Start; if ((it.first & 1) == 0) DrawList.Push(range);