From c51a9f655248e69a7f311fae3d4602f39326d10e Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Sun, 20 Oct 2024 15:10:19 +0200 Subject: [PATCH] start of runtime control for soft bodies --- imgui.ini | 16 ++- include/application.hpp | 18 ++- include/constraints.hpp | 1 + include/soft_body.hpp | 2 +- include/vulkan/buffer.hpp | 30 ++++- src/application.cpp | 231 +++++++++++++++++--------------------- src/constraints.cpp | 33 ++++++ src/soft_body.cpp | 2 +- src/vulkan/buffer.cpp | 102 +++++++++++++++-- 9 files changed, 280 insertions(+), 155 deletions(-) diff --git a/imgui.ini b/imgui.ini index 2001fb6..cc319fc 100644 --- a/imgui.ini +++ b/imgui.ini @@ -30,16 +30,24 @@ Collapsed=0 [Window][Performance] Pos=1716,2 -Size=203,1002 +Size=203,345 Collapsed=0 -DockId=0x00000001,0 +DockId=0x00000002,0 [Window][Performance 2] Pos=1617,2 Size=302,1002 Collapsed=0 -DockId=0x00000001,1 +DockId=0x00000002,1 + +[Window][Scene] +Pos=1716,349 +Size=203,655 +Collapsed=0 +DockId=0x00000004,0 [Docking][Data] -DockNode ID=0x00000001 Pos=1716,2 Size=203,1002 Selected=0x60B79D0E +DockNode ID=0x00000001 Pos=1716,2 Size=203,1002 Split=Y Selected=0x60B79D0E + DockNode ID=0x00000002 Parent=0x00000001 SizeRef=203,345 Selected=0x60B79D0E + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=203,655 Selected=0xE192E354 diff --git a/include/application.hpp b/include/application.hpp index c5fcb74..f76b00b 100644 --- a/include/application.hpp +++ b/include/application.hpp @@ -23,6 +23,7 @@ using std::unique_ptr, std::make_unique; using std::vector; +using std::optional; class SoftBody; class Instance; @@ -37,6 +38,7 @@ class Semaphore; class Camera; class DescriptorPool; class Grabber; +struct SizesUniformData; class Application { public: @@ -75,17 +77,21 @@ private: unique_ptr grabber; unique_ptr grabBuffer; - void createMeshBuffers(); + void addSoftBody(const std::string& modelFile, size_t count=1); + void removeSoftBody(const unique_ptr& softBody); + void updateConstraintBuffers(VkCommandBuffer commandBuffer); + size_t currentDrawVertexBuffer = 0; - unique_ptr vertexBuffers[2]; - unique_ptr faceBuffer; - unique_ptr edgeBuffer; - unique_ptr triangleBuffer; - unique_ptr tetrahedronBuffer; + optional> vertexBuffers[2]; + optional> faceBuffer; + optional> edgeBuffer; + optional> triangleBuffer; + optional> tetrahedronBuffer; ConstraintData constraintData {}; vector> softBodies; unique_ptr sizeInformationBuffer; + SizesUniformData *sizeInformation = nullptr; unique_ptr simulationPropertiesBuffer; diff --git a/include/constraints.hpp b/include/constraints.hpp index 134fd73..5d57df7 100644 --- a/include/constraints.hpp +++ b/include/constraints.hpp @@ -51,6 +51,7 @@ struct ConstraintData { void recordNewPartition(); void writePartitionInformation(); + void insert(const ConstraintData& other); private: uint32_t prePartitionEdgeCount; uint32_t prePartitionTetrahedronCount; diff --git a/include/soft_body.hpp b/include/soft_body.hpp index 72dbefd..77e28ca 100644 --- a/include/soft_body.hpp +++ b/include/soft_body.hpp @@ -28,7 +28,7 @@ public: vector faces; ConstraintData constraintData; - void applyVertexOffset(const glm::vec3& offset); + void applyVertexWorldOffset(const glm::vec3& offset); SoftBody& operator =(const SoftBody& other) = delete; private: diff --git a/include/vulkan/buffer.hpp b/include/vulkan/buffer.hpp index 536f9cb..c50c3d5 100644 --- a/include/vulkan/buffer.hpp +++ b/include/vulkan/buffer.hpp @@ -4,27 +4,45 @@ #include #include "vertex.hpp" #include "vk_mem_alloc.h" +#include +#include + +using std::unique_ptr; +using std::shared_ptr; +using std::make_shared; +using std::make_unique; +using std::optional; class Image; class Buffer { public: - explicit Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsage, + Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags); - explicit Buffer(VkDeviceSize bufferSize, void* initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsage, + Buffer(VkDeviceSize bufferSize, void* initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags); - ~Buffer(); + static unique_ptr Append(const Buffer& old, void* data, VkDeviceSize size, VkCommandBuffer commandBuffer=VK_NULL_HANDLE); + static unique_ptr Replace(const Buffer& old, void* data, VkDeviceSize size, VkCommandBuffer commandBuffer=VK_NULL_HANDLE); + virtual ~Buffer(); VkBuffer handle = VK_NULL_HANDLE; VmaAllocation allocation = VK_NULL_HANDLE; VmaAllocationInfo allocationInfo {}; VkDeviceSize size; - void setName(const std::string& name); + void setName(const std::string& newName); template T& access(){ return *reinterpret_cast(allocationInfo.pMappedData); } + void copyTo(Buffer* buffer) const; + void copyTo(Image* image) const; + void setData(void* data, VkDeviceSize offset, VkDeviceSize size, VkCommandBuffer commandBuffer=VK_NULL_HANDLE); + shared_ptr getStagingBuffer(); Buffer(const Buffer& other) = delete; Buffer& operator =(const Buffer& other) = delete; - void copyTo(Buffer* buffer); - void copyTo(Image* image); +private: + optional> stagingBufferOptional; + std::string name; + VkBufferUsageFlags bufferUsageFlags; + VmaMemoryUsage memoryUsage; + VmaAllocationCreateFlags allocationCreateFlags; }; \ No newline at end of file diff --git a/src/application.cpp b/src/application.cpp index f1daf5d..3e8c049 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -86,17 +86,15 @@ Application::Application() { grabBuffer->setName("Grab"); grabber = make_unique(); - createMeshBuffers(); - - SizesUniformData sizeInformation {}; - sizeInformation.vertexCount = vertexBuffers[0]->size / sizeof(Vertex); - sizeInformation.faceCount = faceBuffer->size / sizeof(Face); - sizeInformationBuffer = make_unique( - sizeof(SizesUniformData), &sizeInformation, sizeof(sizeInformation), + sizeof(SizesUniformData), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); sizeInformationBuffer->setName("Sizes"); + sizeInformation = &sizeInformationBuffer->access(); + + addSoftBody("models/bunny_medium.ply"); SimulationUniformData simulationUniformData { .gravity = {0, -9.81, 0}, @@ -127,7 +125,7 @@ Application::Application() { descriptorPool->bindBuffer(*vertexBuffers[1 - currentDrawVertexBuffer], VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0); descriptorPool->bindBuffer(*faceBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 1); descriptorPool->bindBuffer(*edgeBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 2); - descriptorPool->bindBuffer(*triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3); + // descriptorPool->bindBuffer(*triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3); descriptorPool->bindBuffer(*tetrahedronBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 4); descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5); @@ -148,7 +146,8 @@ void Application::mainLoop() { auto t2 = system_clock::now(); auto measuredUpdateDuration = duration(t2 - t1); - auto requestedUpdateDuration = duration(simulationPropertiesBuffer->access().dt); + auto requestedUpdateDuration = duration( + simulationPropertiesBuffer->access().dt); std::this_thread::sleep_for(requestedUpdateDuration - measuredUpdateDuration); performanceInformation.updateDuration = measuredUpdateDuration.count(); @@ -183,128 +182,101 @@ void Application::createSyncObjects() { transferFence = make_unique(false); } -void Application::createMeshBuffers() { - Mesh sphere("models/icosphere_medium.ply"); - Mesh bunny("models/bunny_medium.ply"); - - auto body = std::make_unique(&sphere, 1.f / 60); - - for (size_t i = 0; i < 10; i++){ - auto copy = std::make_unique(*body.get()); - copy->applyVertexOffset({i * 2, 0, 0}); - softBodies.push_back(std::move(copy)); - } - - body = std::make_unique(&bunny, 1.f / 10); - for (size_t i = 0; i < 10; i++){ - auto copy = std::make_unique(*body.get()); - copy->applyVertexOffset({i * 2, 0, 2}); - softBodies.push_back(std::move(copy)); - } - - vector vertices; - vector faces; - - for (std::unique_ptr ¤tSoftBody : softBodies){ - currentSoftBody->firstIndex = faces.size() * 3; - currentSoftBody->vertexOffset = static_cast(vertices.size()); - - int32_t vertexOffset = currentSoftBody->vertexOffset; - - for (auto &face : currentSoftBody->faces){ - face.a += vertexOffset; - face.b += vertexOffset; - face.c += vertexOffset; - } - - for (auto &edge : currentSoftBody->constraintData.edges){ - edge.a += vertexOffset; - edge.b += vertexOffset; - } - - for (auto &triangle : currentSoftBody->constraintData.triangles){ - triangle.a += vertexOffset; - triangle.b += vertexOffset; - triangle.c += vertexOffset; - } - - for (auto &tetrahedron : currentSoftBody->constraintData.tetrahedra){ - tetrahedron.a += vertexOffset; - tetrahedron.b += vertexOffset; - tetrahedron.c += vertexOffset; - tetrahedron.d += vertexOffset; - } - - vertices.insert(vertices.end(), currentSoftBody->vertices.begin(), currentSoftBody->vertices.end()); - faces.insert(faces.end(), currentSoftBody->faces.begin(), currentSoftBody->faces.end()); +void Application::addSoftBody(const std::string &modelFile, size_t count) { + Mesh mesh(modelFile); - constraintData.partitionCount = std::max(constraintData.partitionCount, currentSoftBody->constraintData.partitionCount); + // Do SoftBody calculations once in constructor, will be copied from now on + auto original = std::make_unique(&mesh, 1.f / 60); - auto combine = [¤tSoftBody, this] ( - auto &globalIndices, auto &bodyIndices, - vector &globalPartitions, vector &bodyPartitions){ - if (globalPartitions.size() < currentSoftBody->constraintData.partitionCount) - globalPartitions.resize(currentSoftBody->constraintData.partitionCount); + vector newVertices; + vector newFaces; - uint32_t offsetAdded = 0; + for (size_t i = 0; i < count; i++){ - for (uint32_t partition = 0; partition < constraintData.partitionCount; partition++){ + // Local copy + auto softBody = std::make_unique(*original.get()); - ConstraintData::Partition &globalPartition = globalPartitions[partition]; - globalPartition.offset += offsetAdded; + softBody->applyVertexWorldOffset({i * 2, 0, 0}); - if (partition < bodyPartitions.size()){ - const ConstraintData::Partition &bodyPartition = bodyPartitions[partition]; + // Position in face buffer + softBody->firstIndex = (sizeInformation->faceCount + newFaces.size()) * 3; - auto dst = globalIndices.begin() + globalPartition.offset; - auto srcStart = bodyIndices.begin() + bodyPartition.offset; - uint32_t count = bodyPartition.size; - globalIndices.insert(dst, srcStart, srcStart + count); + // Position in vertex buffer + softBody->vertexOffset = static_cast(sizeInformation->vertexCount + newVertices.size()); - globalPartition.size += count; - - offsetAdded += count; - } + // Vertex offset added manually for easy access in Compute Shaders + { + auto vertexOffset = softBody->vertexOffset; + for (auto &face : softBody->faces){ + face.a += vertexOffset; + face.b += vertexOffset; + face.c += vertexOffset; + } + for (auto &edge : softBody->constraintData.edges){ + edge.a += vertexOffset; + edge.b += vertexOffset; } - }; + for (auto &triangle : softBody->constraintData.triangles){ + triangle.a += vertexOffset; + triangle.b += vertexOffset; + triangle.c += vertexOffset; + } + for (auto &tetrahedron : softBody->constraintData.tetrahedra){ + tetrahedron.a += vertexOffset; + tetrahedron.b += vertexOffset; + tetrahedron.c += vertexOffset; + tetrahedron.d += vertexOffset; + } + } - combine(constraintData.edges, currentSoftBody->constraintData.edges, - constraintData.edgePartitions, currentSoftBody->constraintData.edgePartitions); + // Append data to vertices and faces + newVertices.insert(newVertices.end(), softBody->vertices.begin(), softBody->vertices.end()); + newFaces.insert(newFaces.end(), softBody->faces.begin(), softBody->faces.end()); - combine(constraintData.tetrahedra, currentSoftBody->constraintData.tetrahedra, - constraintData.tetrahedronPartitions, currentSoftBody->constraintData.tetrahedronPartitions); + // Insert data at the right places in this->constraintData + constraintData.insert(softBody->constraintData); - constraintData.triangles.insert(constraintData.triangles.end(), currentSoftBody->constraintData.triangles.begin(), currentSoftBody->constraintData.triangles.end()); - constraintData.tetrahedra.insert(constraintData.tetrahedra.end(), currentSoftBody->constraintData.tetrahedra.begin(), currentSoftBody->constraintData.tetrahedra.end()); + softBodies.push_back(std::move(softBody)); } - printf("Vertices: %zu\nFaces: %zu\nEdges: %zu\nTriangles: %zu\nTetrahedra: %zu\nTotal Constraints: %zu\n", - vertices.size(), faces.size(), constraintData.edges.size(), constraintData.triangles.size(), constraintData.tetrahedra.size(), - constraintData.edges.size() + constraintData.tetrahedra.size()); + sizeInformation->vertexCount += newVertices.size(); + sizeInformation->faceCount += newFaces.size(); - printf("Partitions: %u\n", constraintData.partitionCount); - - class SimulationBuffer : public Buffer { - public: - SimulationBuffer(void* data, VkDeviceSize size, VkBufferUsageFlags additionalUsageFlags=0) - : Buffer(size, data, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | additionalUsageFlags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0) {} - }; + auto commandBuffer = Instance::instance->renderingCommandPool->beginSingleTimeCommandBuffer(); + vertexBuffers[0] = Buffer::Append(*vertexBuffers[0], newVertices.data(), newVertices.size() * sizeof(Vertex), commandBuffer); + vertexBuffers[1] = Buffer::Append(*vertexBuffers[1], newVertices.data(), newVertices.size() * sizeof(Vertex), commandBuffer); + faceBuffer = Buffer::Append(*faceBuffer, newFaces.data(), newFaces.size() * sizeof(Face), commandBuffer); + edgeBuffer = Buffer::Replace(*edgeBuffer, constraintData.edges.data(), constraintData.edges.size() * sizeof(Edge), commandBuffer); + // triangleBuffer = Buffer::Replace(*triangleBuffer, constraintData.triangles.data(), constraintData.triangles.size() * sizeof(Triangle), commandBuffer); + tetrahedronBuffer = Buffer::Replace(*tetrahedronBuffer, constraintData.tetrahedra.data(), constraintData.tetrahedra.size() * sizeof(Tetrahedron), commandBuffer); - vertexBuffers[0] = make_unique(vertices.data(), vertices.size() * sizeof(Vertex), - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); - vertexBuffers[1] = make_unique(vertices.data(), vertices.size() * sizeof(Vertex), - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); - faceBuffer = make_unique(faces.data(), faces.size() * sizeof(Face), VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - edgeBuffer = make_unique(constraintData.edges.data(), constraintData.edges.size() * sizeof(Edge)); - triangleBuffer = make_unique(constraintData.triangles.data(), constraintData.triangles.size() * sizeof(Triangle)); - tetrahedronBuffer = make_unique(constraintData.tetrahedra.data(), constraintData.tetrahedra.size() * sizeof(Tetrahedron)); + vertexBuffers[0] = make_unique(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + vertexBuffers[1] = make_unique(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + faceBuffer = make_unique(VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + edgeBuffer = make_unique(); + // triangleBuffer = make_unique(); + tetrahedronBuffer = make_unique(); vertexBuffers[0]->setName("Vertices 0"); vertexBuffers[1]->setName("Vertices 1"); faceBuffer->setName("Faces"); edgeBuffer->setName("Edges"); - triangleBuffer->setName("Triangles"); + // triangleBuffer->setName("Triangles"); tetrahedronBuffer->setName("Tetrahedra"); + + VkQueue queue = Instance::instance->graphicsAndPresentQueue; + Instance::instance->renderingCommandPool->endSingleTimeCommandBuffer(commandBuffer, queue); +} + +void Application::removeSoftBody(const unique_ptr &softBody) { + // cpu: remove in constraintData, reduce partition sizes and offsets + // cpu: reduce firstIndex and vertexOffset in following bodies + + + // gpu: update constraintData + // gpu: update vertices and faces, take from remaining softbodies + + // cpu: erase vector element } void Application::createComputePipelines() { @@ -388,7 +360,7 @@ void Application::drawFrame(float dt) { VkBufferMemoryBarrier vertexBufferBarrier{}; vertexBufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - vertexBufferBarrier.size = vertexBuffers[currentDrawVertexBuffer]->size; + vertexBufferBarrier.size = vertexBuffers[currentDrawVertexBuffer]->allocationInfo.size; vertexBufferBarrier.offset = 0; vertexBufferBarrier.buffer = vertexBuffers[currentDrawVertexBuffer]->handle; vertexBufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; @@ -530,7 +502,7 @@ void Application::update() { vkBeginCommandBuffer(cmdBuffer, &beginInfo); VkBufferCopy copyRegion {}; - copyRegion.size = vertexBuffers[1 - currentDrawVertexBuffer]->size; + copyRegion.size = vertexBuffers[1 - currentDrawVertexBuffer]->allocationInfo.size; copyRegion.srcOffset = 0; copyRegion.dstOffset = 0; @@ -584,7 +556,7 @@ void Application::recordGrabCommands(VkCommandBuffer commandBuffer) { pushConstants.screenPosition = grabber->previousCursorPosition; vkCmdPushConstants(commandBuffer, grabPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(GrabPushData), &pushConstants); - uint32_t faceInvocations = GetGroupCount(faceBuffer->size / sizeof(Face), BLOCK_SIZE_GRAB); + uint32_t faceInvocations = GetGroupCount(sizeInformation->faceCount, BLOCK_SIZE_GRAB); vkCmdDispatch(commandBuffer, faceInvocations, 1, 1); computePipelineBarrier(commandBuffer); @@ -616,7 +588,7 @@ void Application::recordGrabCommands(VkCommandBuffer commandBuffer) { } void Application::recordPBDCommands(VkCommandBuffer commandBuffer) { - uint32_t vertexGroupCount = GetGroupCount(vertexBuffers[1 - currentDrawVertexBuffer]->size / sizeof(Vertex), BLOCK_SIZE_PBD); + uint32_t vertexGroupCount = GetGroupCount(sizeInformation->vertexCount, BLOCK_SIZE_PBD); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->handle); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr); @@ -661,8 +633,8 @@ void Application::recordPBDCommands(VkCommandBuffer commandBuffer) { } void Application::recordNormalCommands(VkCommandBuffer commandBuffer) { - uint32_t vertexGroupCount = GetGroupCount(vertexBuffers[1 - currentDrawVertexBuffer]->size / sizeof(Vertex), BLOCK_SIZE_NORMAL); - uint32_t faceGroupCount = GetGroupCount(faceBuffer->size / sizeof(Face), BLOCK_SIZE_NORMAL); + uint32_t vertexGroupCount = GetGroupCount(sizeInformation->vertexCount, BLOCK_SIZE_NORMAL); + uint32_t faceGroupCount = GetGroupCount(sizeInformation->faceCount, BLOCK_SIZE_NORMAL); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->handle); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr); @@ -693,7 +665,7 @@ void Application::computePipelineBarrier(VkCommandBuffer commandBuffer) { VkBufferMemoryBarrier bufferMemoryBarrier {}; bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; bufferMemoryBarrier.buffer = buffer.handle; - bufferMemoryBarrier.size = buffer.size; + bufferMemoryBarrier.size = buffer.allocationInfo.size; bufferMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; bufferMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; bufferMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -712,15 +684,22 @@ void Application::imGuiWindows() { ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); - ImGui::Begin("Performance"); - - float updateMS = performanceInformation.updateDuration * 1000.f; - float updateHZ = 1 / performanceInformation.recentTotalUpdateDurations.average(); - ImGui::Text("Updates: %.0fms | %.1fHz", updateMS, updateHZ); + ImGui::Begin("Performance"); { + float updateMS = performanceInformation.updateDuration * 1000.f; + float updateHZ = 1 / performanceInformation.recentTotalUpdateDurations.average(); + ImGui::Text("Updates: %2.0fms | %.1fHz", updateMS, updateHZ); - float frameMS = performanceInformation.recentFrameDurations.average() * 1000.f; - float frameHZ = 1 / performanceInformation.recentFrameDurations.average(); - ImGui::Text("Frames: %.2fms | %.1fHz", frameMS, frameHZ); + float frameMS = performanceInformation.recentFrameDurations.average() * 1000.f; + float frameHZ = 1 / performanceInformation.recentFrameDurations.average(); + ImGui::Text("Frames: %.2fms | %.1fHz", frameMS, frameHZ); + } ImGui::End(); - ImGui::End(); + ImGui::Begin("Scene"); { + if (ImGui::Button("Add")){ + addSoftBody("models/bunny_medium.ply"); + } + for (const auto &softBody: softBodies){ + ImGui::Text("Some softbody"); + } + } ImGui::End(); } diff --git a/src/constraints.cpp b/src/constraints.cpp index 09aee67..c60a479 100644 --- a/src/constraints.cpp +++ b/src/constraints.cpp @@ -10,6 +10,39 @@ void ConstraintData::writePartitionInformation() { tetrahedronPartitions.emplace_back(prePartitionTetrahedronCount, tetrahedra.size() - prePartitionTetrahedronCount); } +void ConstraintData::insert(const ConstraintData &other) { + if (other.partitionCount > partitionCount){ + edgePartitions.resize(other.partitionCount); + tetrahedronPartitions.resize(other.partitionCount); + } + + // insert constraints, increase partition offsets and sizes + for (size_t i = 0; i < other.partitionCount; i++){ + + edgePartitions[i].offset += other.edgePartitions[i].offset; + tetrahedronPartitions[i].offset += other.tetrahedronPartitions[i].offset; + + auto baseEdgeInsert = other.edges.begin() + other.edgePartitions[i].offset; + edges.insert(edges.begin() + edgePartitions[i].offset + edgePartitions[i].size, + baseEdgeInsert, baseEdgeInsert + other.edgePartitions[i].size); + + auto baseTetrahedronInsert = other.tetrahedra.begin() + other.tetrahedronPartitions[i].offset; + tetrahedra.insert(tetrahedra.begin() + tetrahedronPartitions[i].offset + tetrahedronPartitions[i].size, + baseTetrahedronInsert, baseTetrahedronInsert + other.tetrahedronPartitions[i].size); + + edgePartitions[i].size += other.edgePartitions[i].size; + tetrahedronPartitions[i].size += other.tetrahedronPartitions[i].size; + } + + // increase offsets for remaining partitions + for (size_t i = other.partitionCount; i < partitionCount; i++){ + edgePartitions[i].offset += other.edgePartitions[other.partitionCount - 1].offset; + tetrahedronPartitions[i].offset += other.tetrahedronPartitions[other.partitionCount - 1].offset; + } + + partitionCount = std::max(partitionCount, other.partitionCount); +} + void DistanceConstraint::writeData(ConstraintData &dataLists) const { dataLists.edges.push_back(Edge(a, b, length, compliance)); } diff --git a/src/soft_body.cpp b/src/soft_body.cpp index a365ce9..6edb7a9 100644 --- a/src/soft_body.cpp +++ b/src/soft_body.cpp @@ -112,7 +112,7 @@ SoftBody::SoftBody(Mesh* mesh, float edgeCompliance, float triangleCompliance, f splitConstraints(); } -void SoftBody::applyVertexOffset(const glm::vec3 &offset) { +void SoftBody::applyVertexWorldOffset(const glm::vec3 &offset) { for (Vertex& vertex : vertices){ vertex.position += offset; } diff --git a/src/vulkan/buffer.cpp b/src/vulkan/buffer.cpp index 318301a..c2f799f 100644 --- a/src/vulkan/buffer.cpp +++ b/src/vulkan/buffer.cpp @@ -6,23 +6,25 @@ #include "vulkan/image.hpp" #include "vk_mem_alloc.h" -Buffer::Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags) : size(bufferSize) { +Buffer::Buffer(VkDeviceSize bufferSize, VkBufferUsageFlags bufferUsageFlags, VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags) +: size(bufferSize), bufferUsageFlags(bufferUsageFlags), memoryUsage(memoryUsage), allocationCreateFlags(allocationFlags) { + VkBufferCreateInfo bufferCreateInfo {}; bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferCreateInfo.size = bufferSize; - bufferCreateInfo.usage = bufferUsage; + bufferCreateInfo.usage = bufferUsageFlags; bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VmaAllocationCreateInfo allocationCreateInfo {}; allocationCreateInfo.usage = memoryUsage; - allocationCreateInfo.flags = vmaAllocationFlags; + allocationCreateInfo.flags = allocationFlags; vmaCreateBuffer(Instance::GetAllocator(), &bufferCreateInfo, &allocationCreateInfo, &handle, &allocation, &allocationInfo); } -Buffer::Buffer(VkDeviceSize bufferSize, void *initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsage, - VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags vmaAllocationFlags) - : Buffer(bufferSize, bufferUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT, memoryUsage, vmaAllocationFlags){ +Buffer::Buffer(VkDeviceSize bufferSize, void *initialData, VkDeviceSize initialDataSize, VkBufferUsageFlags bufferUsageFlags, + VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags) + : Buffer(bufferSize, bufferUsageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT, memoryUsage, allocationFlags){ Buffer stagingBuffer( bufferSize, @@ -39,20 +41,20 @@ Buffer::~Buffer() { vmaDestroyBuffer(Instance::GetAllocator(), handle, allocation); } -void Buffer::copyTo(Buffer *buffer) { +void Buffer::copyTo(Buffer *buffer) const { VkQueue queue = Instance::instance->graphicsAndPresentQueue; CommandPool* commandPool = Instance::instance->renderingCommandPool; VkCommandBuffer commandBuffer = commandPool->beginSingleTimeCommandBuffer(); VkBufferCopy copyRegion {}; - copyRegion.size = size; + copyRegion.size = allocationInfo.size; vkCmdCopyBuffer(commandBuffer, handle, buffer->handle, 1, ©Region); commandPool->endSingleTimeCommandBuffer(commandBuffer, queue); } -void Buffer::copyTo(Image *image) { +void Buffer::copyTo(Image *image) const { VkQueue queue = Instance::instance->graphicsAndPresentQueue; CommandPool* commandPool = Instance::instance->renderingCommandPool; @@ -74,6 +76,84 @@ void Buffer::copyTo(Image *image) { commandPool->endSingleTimeCommandBuffer(commandBuffer, queue); } -void Buffer::setName(const std::string &name) { - vmaSetAllocationName(Instance::GetAllocator(), allocation, name.data()); +void Buffer::setData(void *data, VkDeviceSize offset, VkDeviceSize size, VkCommandBuffer commandBuffer) { + if (allocationInfo.pMappedData){ + memcpy(allocationInfo.pMappedData, reinterpret_cast(data) + offset, size); + VkMemoryPropertyFlags flags; + vmaGetAllocationMemoryProperties(Instance::GetAllocator(), allocation, &flags); + assert(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + } else { + auto stagingBuffer = getStagingBuffer(); + stagingBuffer->setData(data, offset, size); + + VkBufferMemoryBarrier bufferMemoryBarrier {}; + bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + bufferMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + bufferMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + bufferMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferMemoryBarrier.buffer = stagingBuffer->handle; + bufferMemoryBarrier.size = size; + bufferMemoryBarrier.offset = offset; + + vkCmdPipelineBarrier( + commandBuffer, + VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, nullptr, + 1, &bufferMemoryBarrier, + 0, nullptr); + + VkBufferCopy region {}; + region.srcOffset = offset; + region.dstOffset = offset; + region.size = size; + + vkCmdCopyBuffer(commandBuffer, stagingBuffer->handle, handle, 1, ®ion); + } +} + +void Buffer::setName(const std::string &newName) { + name = newName; + vmaSetAllocationName(Instance::GetAllocator(), allocation, newName.data()); +} + +unique_ptr Buffer::Append(const Buffer &old, void *data, VkDeviceSize size, VkCommandBuffer commandBuffer) { + auto buffer = make_unique(old.size + size, + old.bufferUsageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + old.memoryUsage, + old.allocationCreateFlags); + + VkBufferCopy copyRegion {}; + copyRegion.size = old.size; + vkCmdCopyBuffer(commandBuffer, old.handle, buffer->handle, 1, ©Region); + + buffer->setData(data, old.size, size, commandBuffer); + + return buffer; +} + +unique_ptr Buffer::Replace(const Buffer &old, void *data, VkDeviceSize size, VkCommandBuffer commandBuffer) { + auto buffer = make_unique(size, + old.bufferUsageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + old.memoryUsage, + old.allocationCreateFlags); + + buffer->setData(data, 0, size, commandBuffer); + + return buffer; +} + +shared_ptr Buffer::getStagingBuffer() { + if (stagingBufferOptional.has_value()) + return stagingBufferOptional.value(); + + stagingBufferOptional = make_shared( + allocationInfo.size, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VMA_MEMORY_USAGE_AUTO, + VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); + + return stagingBufferOptional.value(); }