diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2023-10-31 16:28:12 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2023-11-03 15:03:20 -0400 |
| commit | 5891af6843661a9d30c12c3ef0f9efeb534aee88 (patch) | |
| tree | 5e1af54c08f6ff4baaefcd187fbec4d031de76c9 | |
| parent | cb26bbf9945b7b3badb088e1c3df06efdfc7fad1 (diff) | |
rebuild instance buffers as they become oversized
| -rw-r--r-- | src/components.hpp | 1 | ||||
| -rw-r--r-- | src/ecs.cpp | 8 | ||||
| -rw-r--r-- | src/ecs.hpp | 1 | ||||
| -rw-r--r-- | src/entities.cpp | 113 | ||||
| -rw-r--r-- | src/entities.hpp | 2 | ||||
| -rw-r--r-- | src/game.cpp | 4 |
6 files changed, 126 insertions, 3 deletions
diff --git a/src/components.hpp b/src/components.hpp index 490e798..4d52e39 100644 --- a/src/components.hpp +++ b/src/components.hpp @@ -47,6 +47,7 @@ struct CompGrBinds { uint32_t instanceFirstBinding = 0; uint32_t instanceBindingCount = 0; uint32_t instanceCounter = 0; + uint32_t instanceBufferMaxCount = 0; VkDeviceSize instanceOffsets = 0; }; diff --git a/src/ecs.cpp b/src/ecs.cpp index 03f26db..b4207f8 100644 --- a/src/ecs.cpp +++ b/src/ecs.cpp @@ -21,6 +21,9 @@ DynArray<EntityHandle> EntitiesToBeRemoved{16}; // public DynArray<Entity> entitiesYetToBeRemoved{0, nullptr}; DynArray<EntityHandle> entitiesMarkedForRemoval{16}; + +DynArray<EntityHandle> EntitiesWithExcessInstances{16}; + BucketContainer<EntityBucket, EntityHandle_T> Entities_BucketContainer{}; BucketContainer<GrBindsBucket, GrBindsHandle_T> Comp_GrBinds_BucketContainer{}; BucketContainer<InstanceBucket, InstanceHandle_T> Comp_Instance_BucketContainer{}; @@ -344,6 +347,10 @@ CompInstance &ECS_CreateInstance(EntityHandle entHandle, EntityHandle entityType comp->instPos.rot = glm::quat(1, 0, 0, 0); comp->instPos.scale = glm::vec3(1, 1, 1); comp->isNeedingUpdated = true; + + if (grBinds->instanceCounter > grBinds->instanceBufferMaxCount) { + EntitiesWithExcessInstances.Push(grBinds->entHandle); + } return *comp; } @@ -394,6 +401,7 @@ CompInstance *ECS_GetInstances(uint64_t bucketIndex, uint64_t &itemCount) { } void ECS_Teardown() { + EntitiesWithExcessInstances.~DynArray(); entitiesYetToBeRemoved.~DynArray(); EntitiesToBeRemoved.~DynArray(); entitiesMarkedForRemoval.~DynArray(); diff --git a/src/ecs.hpp b/src/ecs.hpp index 83646af..49d947c 100644 --- a/src/ecs.hpp +++ b/src/ecs.hpp @@ -9,6 +9,7 @@ #include "glm/vec3.hpp" extern DynArray<EntityHandle> EntitiesToBeRemoved; +extern DynArray<EntityHandle> EntitiesWithExcessInstances; static struct { uint64_t Entity = 1ULL << 0; diff --git a/src/entities.cpp b/src/entities.cpp index f61927a..a9108a0 100644 --- a/src/entities.cpp +++ b/src/entities.cpp @@ -1,6 +1,7 @@ #include "entities.hpp" +#include <vulkan/vulkan_core.h> DynArray<EntityType> GlobalEntityTypes{16}; void EntityType_Init() { @@ -597,8 +598,10 @@ void EntityType_Load(EntityType &et) { } // set up instance buffer - bufferCI.size = sizeof(InstPos) * et.startingInstanceCount; - bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + grBinds.instanceBufferMaxCount = et.startingInstanceCount; + grBinds.instanceBufferMaxCount = grBinds.instanceBufferMaxCount < 1 ? 1 : grBinds.instanceBufferMaxCount; + bufferCI.size = sizeof(glm::mat4) * grBinds.instanceBufferMaxCount; + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.instanceBuffer); VkMemoryRequirements vkMemoryRequirementsInst; vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBuffer, &vkMemoryRequirementsInst); @@ -613,6 +616,112 @@ void EntityType_Load(EntityType &et) { } } +void EntityType_Tick_Late(double delta) { + while (EntitiesWithExcessInstances.Count() != 0) { + auto entHandle = EntitiesWithExcessInstances.Pop(); + auto index = EntityType_FindByEntityHandle(entHandle); + auto &et = GlobalEntityTypes[index]; + auto &grBinds = *ECS_GetGrBinds(entHandle); + EntityType_RolloverInstances(et, grBinds); + } +} + +void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { + int32_t oldCount = grBinds.instanceBufferMaxCount; + int32_t newCount = std::ceil(grBinds.instanceBufferMaxCount * 1.5); + newCount = newCount < 4 ? 4 : newCount; + grBinds.instanceBufferMaxCount = newCount; + uint32_t oldSize = sizeof(glm::mat4) * oldCount; + + VkDeviceMemory oldMemory(et.deviceMemoryInst); + VkBuffer oldBuffer(grBinds.instanceBuffer); + + VkBufferCreateInfo vkBufferCreateInfo{}; + vkBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + vkBufferCreateInfo.pNext = nullptr; + vkBufferCreateInfo.flags = 0; + vkBufferCreateInfo.size = sizeof(glm::mat4) * newCount; + vkBufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + vkBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + vkBufferCreateInfo.queueFamilyIndexCount = 1; + vkBufferCreateInfo.pQueueFamilyIndices = &graphicsFamilyIndex; + vkCreateBuffer(vkDevice, &vkBufferCreateInfo, vkAllocator, &grBinds.instanceBuffer); + + VkMemoryRequirements vkMemoryRequirementsInst; + vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBuffer, &vkMemoryRequirementsInst); + + VkMemoryAllocateInfo vkMemoryAllocateInfo; + vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + vkMemoryAllocateInfo.pNext = nullptr; + vkMemoryAllocateInfo.allocationSize = vkMemoryRequirementsInst.size; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(vkMemoryRequirementsInst.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &et.deviceMemoryInst); + + vkBindBufferMemory(vkDevice, grBinds.instanceBuffer, et.deviceMemoryInst, 0); + + // copy data + { + vkResetCommandBuffer(graphicsCommandBuffer, 0); + VkBufferMemoryBarrier memBarriers[2]; + for (long i = 0; i < 2; ++i) { + memBarriers[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + memBarriers[i].pNext = nullptr; + } + + memBarriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + memBarriers[0].dstAccessMask = {}; + memBarriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + memBarriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + memBarriers[0].buffer = oldBuffer; + memBarriers[0].offset = 0; + memBarriers[0].size = oldSize; + + memBarriers[1].srcAccessMask = {}; + memBarriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + memBarriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + memBarriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + memBarriers[1].buffer = grBinds.instanceBuffer; + memBarriers[1].offset = 0; + memBarriers[1].size = vkMemoryRequirementsInst.size; + + VkCommandBufferBeginInfo vkCommandBufferBeginInfo; + vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkCommandBufferBeginInfo.pNext = nullptr; + // TODO consider single-use? + vkCommandBufferBeginInfo.flags = 0; + vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(graphicsCommandBuffer, &vkCommandBufferBeginInfo); + vkCmdPipelineBarrier(graphicsCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 2, memBarriers, 0, nullptr); + + VkBufferCopy vkBufferCopy; + vkBufferCopy.srcOffset = 0; + vkBufferCopy.dstOffset = 0; + vkBufferCopy.size = oldSize; + vkCmdCopyBuffer(graphicsCommandBuffer, oldBuffer, grBinds.instanceBuffer, 1, &vkBufferCopy); + + vkEndCommandBuffer(graphicsCommandBuffer); + + VkSubmitInfo submitInfo; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = nullptr; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &graphicsCommandBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(graphicsQueue, 1, &submitInfo, nullptr); + vkQueueWaitIdle(graphicsQueue); + vkResetCommandBuffer(graphicsCommandBuffer, 0); + } + + // cleanup + vkDestroyBuffer(vkDevice, oldBuffer, vkAllocator); + vkFreeMemory(vkDevice, oldMemory, vkAllocator); +} + void EntityType_Teardown() { long entityTypeCount = GlobalEntityTypes.Count(); for (long i = 0; i < entityTypeCount; ++i) { diff --git a/src/entities.hpp b/src/entities.hpp index 0dc52e9..4c5b498 100644 --- a/src/entities.hpp +++ b/src/entities.hpp @@ -37,6 +37,8 @@ void EntityType_Init(); int64_t EntityType_FindByTypeCode(const char *typeCode); int64_t EntityType_FindByEntityHandle(EntityHandle handle); void EntityType_Load(EntityType &et); +void EntityType_Tick_Late(double delta); +void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds); void EntityType_Teardown(); #endif /* PKE_ENTITIES_HPP */ diff --git a/src/game.cpp b/src/game.cpp index 4540d9e..69e728d 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -365,6 +365,7 @@ void Game_Tick(double delta) { accDelta += delta; UBO.model = glm::rotate(glm::mat4(1.0f), (float)accDelta * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); UBO.view = glm::lookAt(glm::vec3(4.0f, 4.0f, 4.0f), glm::vec3(0), glm::vec3(0.0f, 0.0f, 1.0f)); + EntityType_Tick_Late(delta); ECS_Tick_Late(delta); } @@ -601,7 +602,8 @@ void RecordImGui_CompGrBinds(bool readonly, CompGrBinds *component) { ImGui::InputScalar("InstanceBindingCount", ImGuiDataType_U32, &component->instanceBindingCount, nullptr, nullptr, nullptr, inputTextFlags); ImGui::InputScalar("InstanceOffsets", ImGuiDataType_U64, &component->instanceOffsets, nullptr, nullptr, nullptr, inputTextFlags); - ImGui::InputScalar("Instance Count", ImGuiDataType_S64, &component->instanceCounter, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("InstanceBufferMaxCount", ImGuiDataType_U32, &component->instanceBufferMaxCount, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("Instance Count", ImGuiDataType_U32, &component->instanceCounter, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); ImGui::Spacing(); } |
