summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2023-10-31 16:28:12 -0400
committerJonathan Bradley <jcb@pikum.xyz>2023-11-03 15:03:20 -0400
commit5891af6843661a9d30c12c3ef0f9efeb534aee88 (patch)
tree5e1af54c08f6ff4baaefcd187fbec4d031de76c9
parentcb26bbf9945b7b3badb088e1c3df06efdfc7fad1 (diff)
rebuild instance buffers as they become oversized
-rw-r--r--src/components.hpp1
-rw-r--r--src/ecs.cpp8
-rw-r--r--src/ecs.hpp1
-rw-r--r--src/entities.cpp113
-rw-r--r--src/entities.hpp2
-rw-r--r--src/game.cpp4
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();
}