diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2023-10-02 19:51:10 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2023-10-02 19:51:10 -0400 |
| commit | 4899815c69894bba3eb1a6faa8ccbbc676751728 (patch) | |
| tree | e3d5895b35d060d193ec59ccdeaf65dfbad6e145 /src | |
| parent | 2bdee2ce549b1306cafb1d657624eeed4cf7225a (diff) | |
instancing now works as intended
Diffstat (limited to 'src')
| -rw-r--r-- | src/components.hpp | 21 | ||||
| -rw-r--r-- | src/ecs.cpp | 215 | ||||
| -rw-r--r-- | src/ecs.hpp | 3 | ||||
| -rw-r--r-- | src/entities.cpp | 42 | ||||
| -rw-r--r-- | src/game.cpp | 24 | ||||
| -rw-r--r-- | src/window.cpp | 2 |
6 files changed, 185 insertions, 122 deletions
diff --git a/src/components.hpp b/src/components.hpp index 06477da..490e798 100644 --- a/src/components.hpp +++ b/src/components.hpp @@ -4,8 +4,7 @@ #include "macros.hpp" #include "dynamic-array.hpp" -#include <glm/vec2.hpp> -#include <glm/vec3.hpp> +#include <glm/gtc/quaternion.hpp> #include <vulkan/vulkan_core.h> const uint64_t ECS_UNSET_VAL = 0xFFFFFFFFFFFFFFFF; @@ -22,12 +21,6 @@ struct Entity { bool isMarkedForRemoval = false; }; -struct InstPos { - glm::vec3 pos; - glm::vec3 rot; - glm::vec3 scale; -}; - struct CompGrBinds { EntityHandle entHandle = EntityHandle_MAX; GrBindsHandle grBindsHandle = GrBindsHandle_MAX; @@ -53,9 +46,14 @@ struct CompGrBinds { VkBuffer instanceBuffer = VK_NULL_HANDLE; uint32_t instanceFirstBinding = 0; uint32_t instanceBindingCount = 0; + uint32_t instanceCounter = 0; VkDeviceSize instanceOffsets = 0; - DynArray<InstPos> instances{0}; - bool isInstanceBufferNeedingUpdated = false; +}; + +struct InstPos { + glm::vec3 pos; + glm::quat rot; + glm::vec3 scale; }; struct CompInstance { @@ -63,7 +61,8 @@ struct CompInstance { GrBindsHandle grBindsHandle = GrBindsHandle_MAX; InstanceHandle instanceHandle = InstanceHandle_MAX; uint64_t index = ECS_UNSET_VAL; - InstPos *ptr = nullptr; + InstPos instPos; + bool isNeedingUpdated = false; }; #endif /* PKE_COMPONENTS_HPP */ diff --git a/src/ecs.cpp b/src/ecs.cpp index b0f9250..9458506 100644 --- a/src/ecs.cpp +++ b/src/ecs.cpp @@ -1,7 +1,8 @@ #include "ecs.hpp" -#include <new> +#include "vendor/glm_include.hpp" +#include "window.hpp" TypeSafeInt_B(EntityHandle); const uint64_t maxBucketItemCount = 256; @@ -115,7 +116,6 @@ void ECS_Tick_Early(double delta) { instBucketIndex = b; } if (inst != nullptr) { - grBinds->instances.Remove(inst->index); for (long bi = instBucketIndex; bi <= Comp_Instance_BucketContainer.bucketCounter; ++bi) { uint64_t instCounter = 0; if (bi == Comp_Instance_BucketContainer.bucketCounter) { @@ -132,74 +132,139 @@ void ECS_Tick_Early(double delta) { continue; } bucket.instances[ii].index -= 1; + bucket.instances[ii].isNeedingUpdated = true; } } + grBinds->instanceCounter -=1; inst->entHandle = EntityHandle_MAX; inst->grBindsHandle = GrBindsHandle_MAX; inst->index = ECS_UNSET_VAL; inst->instanceHandle = InstanceHandle_MAX; - inst->ptr = CAFE_BABE(InstPos); + inst->isNeedingUpdated = false; } else if (grBinds != nullptr) { /* * 2023-09-05 JB note - the Vulkan assets (device memory, buffers, * pipeline layout, and descriptor set) are unloaded elsewhere, just, * as they were created elsewhere. */ - DynArrayDestroy(&grBinds->instances); } } entitiesMarkedForRemoval.Resize(0); } +struct InstanceBufferCopyChunk { + uint64_t startingIndex; + uint64_t endingIndex; + DynArray<glm::mat4> mats{0}; + VkBufferCopy dstBufferCopy; +}; +struct InstanceBufferCopy { + CompGrBinds *grBinds = nullptr; + VkDeviceSize runningSize = 0; + DynArray<InstanceBufferCopyChunk> chunks{4}; +}; void ECS_Tick_Late(double delta) { - for (long b = 0; b <= Comp_GrBinds_BucketContainer.bucketCounter; ++b) { - auto &bkt = Comp_GrBinds_BucketContainer.buckets[b]; - long count = Comp_GrBinds_BucketContainer.bucketCounter == b ? Comp_GrBinds_BucketContainer.itemCounter >> 32 : maxBucketItemCount; - for (long i = 0; i < count; ++i) { - auto &grBinds = bkt.compGrBinds[i]; - if (grBinds.isInstanceBufferNeedingUpdated) { - VkDeviceSize byteCount = sizeof(InstPos) * grBinds.instances.Count(); - VkBuffer transferBuffer; - VkDeviceMemory transferMemory; - void *deviceData; - BeginTransferBuffer(byteCount, transferBuffer, transferMemory, deviceData); - memcpy(deviceData, grBinds.instances.GetPtr(), byteCount); - { - VkCommandBufferBeginInfo cbbi; - cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cbbi.pNext = nullptr; - cbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - cbbi.pInheritanceInfo = nullptr; - - vkBeginCommandBuffer(transferCommandBuffer, &cbbi); - - VkBufferCopy vkBufferCopy; - vkBufferCopy.srcOffset = 0; - vkBufferCopy.dstOffset = 0; - vkBufferCopy.size = byteCount; - - vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.instanceBuffer, 1, &vkBufferCopy); - - vkEndCommandBuffer(transferCommandBuffer); - - VkSubmitInfo vkSubmitInfo{}; - vkSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - vkSubmitInfo.pNext = nullptr; - vkSubmitInfo.waitSemaphoreCount = 0; - vkSubmitInfo.pWaitSemaphores = nullptr; - vkSubmitInfo.pWaitDstStageMask = nullptr; - vkSubmitInfo.commandBufferCount = 1; - vkSubmitInfo.pCommandBuffers = &transferCommandBuffer; - vkSubmitInfo.signalSemaphoreCount = 0; - vkSubmitInfo.pSignalSemaphores = nullptr; - vkQueueSubmit(transferQueue, 1, &vkSubmitInfo, nullptr); - vkQueueWaitIdle(transferQueue); - vkResetCommandBuffer(transferCommandBuffer, 0); + DynArray<InstanceBufferCopy> bufferUpdates{0}; + for (long b = 0; b <= Comp_Instance_BucketContainer.bucketCounter; ++b) { + auto &bkt = Comp_Instance_BucketContainer.buckets[b]; + long count = Comp_Instance_BucketContainer.bucketCounter == b ? Comp_Instance_BucketContainer.itemCounter >> 32 : maxBucketItemCount; + for (uint32_t i = 0; i < count; ++i) { + auto &inst = bkt.instances[i]; + if (inst.isNeedingUpdated == false) + continue; + + GrBindsHandle_T grBindsHandle_t{static_cast<GrBindsHandle_T>(inst.grBindsHandle)}; + auto b_inner = Buckets_GetBucketIndex(grBindsHandle_t); + auto bi_inner = Buckets_GetItemIndex(grBindsHandle_t); + auto &grBinds = Comp_GrBinds_BucketContainer.buckets[b_inner].compGrBinds[bi_inner]; + + InstanceBufferCopy *bfrUpdate = nullptr; + for (long u = 0; u < bufferUpdates.Count(); ++u) { + if (bufferUpdates[u].grBinds->grBindsHandle == inst.grBindsHandle) { + bfrUpdate = &bufferUpdates[u]; + } + } + if (bfrUpdate == nullptr) { + bufferUpdates.Push({ + .grBinds = &grBinds, + }); + bfrUpdate = &bufferUpdates[bufferUpdates.Count() - 1]; + } + + InstanceBufferCopyChunk *chunk = nullptr; + for (long ii = 0; ii < bfrUpdate->chunks.Count(); ++ii) { + if (bfrUpdate->chunks[ii].endingIndex == inst.index - 1) { + chunk = &bfrUpdate->chunks[ii]; + chunk->endingIndex += 1; + break; } - EndTransferBuffer(transferBuffer, transferMemory); - grBinds.isInstanceBufferNeedingUpdated = false; } + if (chunk == nullptr) { + bfrUpdate->chunks.Push({ + .startingIndex = inst.index, + .endingIndex = inst.index, + }); + chunk = &bfrUpdate->chunks[bfrUpdate->chunks.Count() - 1]; + chunk->dstBufferCopy.dstOffset = sizeof(glm::mat4) * inst.index; + } + + chunk->mats.Push( + glm::translate(glm::mat4(1), inst.instPos.pos) + * glm::mat4_cast(inst.instPos.rot) + * glm::scale(glm::mat4(1), inst.instPos.scale)); + bfrUpdate->runningSize += sizeof(glm::mat4); + inst.isNeedingUpdated = false; + } + } + while (bufferUpdates.Count() > 0) { + InstanceBufferCopy ibc = bufferUpdates.Pop(); + + VkDeviceSize instanceBytes = sizeof(glm::mat4); + VkDeviceSize byteCount = ibc.runningSize; + VkBuffer transferBuffer; + VkDeviceMemory transferMemory; + void *deviceData; + BeginTransferBuffer(byteCount, transferBuffer, transferMemory, deviceData); + VkDeviceSize runningOffset = 0; + for (long i = 0; i < ibc.chunks.Count(); ++i) { + auto *chunk = &ibc.chunks[i]; + memcpy(static_cast<char *>(deviceData) + runningOffset, chunk->mats.GetPtr(), byteCount); + chunk->dstBufferCopy.srcOffset = runningOffset; + chunk->dstBufferCopy.size = instanceBytes * (chunk->endingIndex - chunk->startingIndex + 1); + runningOffset += chunk->dstBufferCopy.size; + } + assert(runningOffset == ibc.runningSize); + + { + VkCommandBufferBeginInfo cbbi; + cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cbbi.pNext = nullptr; + cbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cbbi.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(transferCommandBuffer, &cbbi); + + for (long i = 0; i < ibc.chunks.Count(); ++i) { + vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ibc.grBinds->instanceBuffer, 1, &ibc.chunks[i].dstBufferCopy); + } + + vkEndCommandBuffer(transferCommandBuffer); + + VkSubmitInfo vkSubmitInfo{}; + vkSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + vkSubmitInfo.pNext = nullptr; + vkSubmitInfo.waitSemaphoreCount = 0; + vkSubmitInfo.pWaitSemaphores = nullptr; + vkSubmitInfo.pWaitDstStageMask = nullptr; + vkSubmitInfo.commandBufferCount = 1; + vkSubmitInfo.pCommandBuffers = &transferCommandBuffer; + vkSubmitInfo.signalSemaphoreCount = 0; + vkSubmitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(transferQueue, 1, &vkSubmitInfo, nullptr); + vkQueueWaitIdle(transferQueue); + vkResetCommandBuffer(transferCommandBuffer, 0); } + EndTransferBuffer(transferBuffer, transferMemory); } } @@ -261,25 +326,24 @@ CompInstance &ECS_CreateInstance(EntityHandle entHandle, EntityHandle entityType ent->instanceHandle = InstanceHandle{newHandle}; GrBindsHandle_T grBindsHandle_t{static_cast<GrBindsHandle_T>(entTypeEnt->grBindsHandle)}; - auto b2 = Buckets_GetBucketIndex(grBindsHandle_t); - auto i2 = Buckets_GetItemIndex(grBindsHandle_t); - auto *grBinds = &Comp_GrBinds_BucketContainer.buckets[b2].compGrBinds[i2]; - grBinds->isInstanceBufferNeedingUpdated = true; - grBinds->instanceBindingCount = 1; auto b = Buckets_GetBucketIndex(newHandle); auto i = Buckets_GetItemIndex(newHandle); - auto *comp = &Comp_Instance_BucketContainer.buckets[b].instances[i]; + auto *instBkt = &Comp_Instance_BucketContainer.buckets[b]; + auto *comp = &instBkt->instances[i]; comp = new (comp) CompInstance{}; comp->entHandle = entHandle; + + auto b2 = Buckets_GetBucketIndex(grBindsHandle_t); + auto i2 = Buckets_GetItemIndex(grBindsHandle_t); + auto *grBinds = &Comp_GrBinds_BucketContainer.buckets[b2].compGrBinds[i2]; + comp->grBindsHandle = grBinds->grBindsHandle; comp->instanceHandle = ent->instanceHandle; - comp->index = grBinds->instances.Count(); - grBinds->instances.Push({ - .pos = glm::vec3(0), - .rot = glm::vec3(1), - .scale = glm::vec3(1), - }); - comp->ptr = &grBinds->instances[comp->index]; + comp->index = grBinds->instanceCounter++; + comp->instPos.pos = glm::vec3(0, 0, 0); + comp->instPos.rot = glm::quat(1, 0, 0, 0); + comp->instPos.scale = glm::vec3(1, 1, 1); + comp->isNeedingUpdated = true; return *comp; } @@ -295,16 +359,23 @@ CompInstance *ECS_GetInstance(EntityHandle entHandle) { auto i = Buckets_GetItemIndex(instanceHandle_t); auto *inst = &Comp_Instance_BucketContainer.buckets[b].instances[i]; - if (inst->index == ECS_UNSET_VAL) - return nullptr; - if (inst->grBindsHandle == GrBindsHandle_MAX) - return nullptr; + return inst; +} - GrBindsHandle_T grBindsHandle_t{static_cast<GrBindsHandle_T>(inst->grBindsHandle)}; - auto b2 = Buckets_GetBucketIndex(grBindsHandle_t); - auto i2 = Buckets_GetItemIndex(grBindsHandle_t); - auto grBinds = &Comp_GrBinds_BucketContainer.buckets[b2].compGrBinds[i2]; +void ECS_UpdateInstance(EntityHandle entHandle, const InstPos &instPos) { + Entity *ent = nullptr; + ECS_GetEntity_Inner(entHandle, ent); - inst->ptr = &grBinds->instances[inst->index]; - return inst; + if (ent->instanceHandle == InstanceHandle_MAX) + return; + + InstanceHandle_T instanceHandle_t{static_cast<InstanceHandle_T>(ent->instanceHandle)}; + auto b = Buckets_GetBucketIndex(instanceHandle_t); + auto i = Buckets_GetItemIndex(instanceHandle_t); + auto *inst = &Comp_Instance_BucketContainer.buckets[b].instances[i]; + + inst->instPos.pos = instPos.pos; + inst->instPos.rot = instPos.rot; + inst->instPos.scale = instPos.scale; + inst->isNeedingUpdated = true; } diff --git a/src/ecs.hpp b/src/ecs.hpp index 6293bc9..685dd81 100644 --- a/src/ecs.hpp +++ b/src/ecs.hpp @@ -5,7 +5,6 @@ #include "macros.hpp" #include "memory.hpp" #include "components.hpp" -#include "window.hpp" #include "glm/vec3.hpp" @@ -14,6 +13,7 @@ extern DynArray<EntityHandle> EntitiesToBeRemoved; static struct { uint64_t Entity = 1ULL << 0; uint64_t GrBinds = 1ULL << 1; + uint64_t Instance = 1ULL << 2; } ComponentTypes; void ECS_Init(); @@ -31,5 +31,6 @@ CompGrBinds *ECS_GetGrBinds(uint64_t bucketIndex, uint64_t &itemCount); CompInstance &ECS_CreateInstance(EntityHandle entHandle, EntityHandle entityTypeEntityHandle); CompInstance *ECS_GetInstance(EntityHandle entHandle); +void ECS_UpdateInstance(EntityHandle entHandle, const InstPos &instPos); #endif /* PKE_ECS_HPP */ diff --git a/src/entities.cpp b/src/entities.cpp index 7263bbd..fd55970 100644 --- a/src/entities.cpp +++ b/src/entities.cpp @@ -97,11 +97,10 @@ void EntityType_Init() { // index += 1; // instance vertInputBD[index].binding = index; - vertInputBD[index].stride = sizeof(glm::vec3) * 3; + vertInputBD[index].stride = sizeof(glm::mat4); vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; - const long vertexAttrDescCount = 6; - long runningOffset = 0; + const long vertexAttrDescCount = 7; index = 0; VkVertexInputAttributeDescription vertAttrDesc[vertexAttrDescCount]; for (long i = 0; i < vertexAttrDescCount; ++i) { @@ -111,44 +110,28 @@ void EntityType_Init() { // model vertex vertAttrDesc[index].binding = 0; vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; - vertAttrDesc[index].offset = runningOffset; - runningOffset += sizeof(glm::vec3); + vertAttrDesc[index].offset = 0; index += 1; // model normals vertAttrDesc[index].binding = 1; vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; - vertAttrDesc[index].offset = runningOffset; - runningOffset += sizeof(glm::vec3); + vertAttrDesc[index].offset = 0; index += 1; // model UV vertAttrDesc[index].binding = 2; vertAttrDesc[index].format = VK_FORMAT_R32G32_SFLOAT; - vertAttrDesc[index].offset = runningOffset; - runningOffset += sizeof(glm::vec2); + vertAttrDesc[index].offset = 0; index += 1; - // instance pos - vertAttrDesc[index].binding = 3; - vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; - vertAttrDesc[index].offset = runningOffset; - runningOffset += sizeof(glm::vec3); - index += 1; - - // instance rot - vertAttrDesc[index].binding = 3; - vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; - vertAttrDesc[index].offset = runningOffset; - runningOffset += sizeof(glm::vec3); - index += 1; - - // instance scale - vertAttrDesc[index].binding = 3; - vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; - vertAttrDesc[index].offset = runningOffset; - // runningOffset += sizeof(glm::vec3); - // index += 1; + // instPosRotScale + for (long i = 0; i < 4; ++i) { + vertAttrDesc[index].binding = 3; + vertAttrDesc[index].format = VK_FORMAT_R32G32B32A32_SFLOAT; + vertAttrDesc[index].offset = sizeof(glm::vec4) * i; + index += 1; + } // instance texture index // vertAttrDesc[index].binding = 3; @@ -717,6 +700,7 @@ void EntityType_Load(EntityType &et) { // 2023-09-27 - JCB // I don't know where else to put this grBinds.instanceFirstBinding = index; + grBinds.instanceBindingCount = 1; // no index += 1 because index just happens to be the right value here for // the binding index, whereas binding the IndexBuffer doesn't need a binding index. diff --git a/src/game.cpp b/src/game.cpp index d95e43b..071a2b3 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,6 +1,7 @@ #include "game.hpp" -#include "memory.hpp" + +#include "vendor/glm_include.hpp" #include <cstring> @@ -213,6 +214,10 @@ void Game_Tick(double delta) { EntityHandle newEntity = ECS_CreateEntity(); ECS_CreateInstance(newEntity, createInfo.entityTypeEntityHandle); } + static double accDelta = 0.0; + 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)); ECS_Tick_Late(delta); } @@ -439,8 +444,7 @@ 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); - int64_t count = component->instances.Count(); - ImGui::InputScalar("Instance Count", ImGuiDataType_S64, &count, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("Instance Count", ImGuiDataType_S64, &component->instanceCounter, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); ImGui::Spacing(); } @@ -454,11 +458,15 @@ void RecordImGui_CompInstPos(bool readonly, CompInstance *component) { ImGui::Text("CompInststance + InstPos"); ImGui::Separator(); - ImGui::InputScalar("Instance Index", ImGuiDataType_U64, &component->index, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); - if (component->ptr) { - ImGui::InputScalarN("pos", ImGuiDataType_Float, &component->ptr->pos, 3, nullptr, nullptr, nullptr, inputTextFlags); - ImGui::InputScalarN("rot", ImGuiDataType_Float, &component->ptr->rot, 3, nullptr, nullptr, nullptr, inputTextFlags); - ImGui::InputScalarN("scale", ImGuiDataType_Float, &component->ptr->scale, 3, nullptr, nullptr, nullptr, inputTextFlags); + bool changed = false; + + changed = ImGui::InputScalar("Instance Index", ImGuiDataType_U64, &component->index, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly) || changed; + changed = ImGui::InputScalarN("pos", ImGuiDataType_Float, &component->instPos.pos, 3, nullptr, nullptr, nullptr, inputTextFlags) || changed; + changed = ImGui::InputScalarN("rot", ImGuiDataType_Float, &component->instPos.rot, 4, nullptr, nullptr, nullptr, inputTextFlags) || changed; + changed = ImGui::InputScalarN("scale", ImGuiDataType_Float, &component->instPos.scale, 3, nullptr, nullptr, nullptr, inputTextFlags) || changed; + + if (changed) { + ECS_UpdateInstance(component->entHandle, component->instPos); } ImGui::Spacing(); diff --git a/src/window.cpp b/src/window.cpp index d4ac37b..1a9a584 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1374,7 +1374,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdBindVertexBuffers(commandBuffer, binder->uvFirstBinding, binder->uvBindingCount, &binder->uvBuffer, &binder->uvOffsets); vkCmdBindVertexBuffers(commandBuffer, binder->instanceFirstBinding, binder->instanceBindingCount, &binder->instanceBuffer, &binder->instanceOffsets); - vkCmdDrawIndexed(commandBuffer, binder->indexCount, binder->instances.Count(), 0, 0, 0); + vkCmdDrawIndexed(commandBuffer, binder->indexCount, binder->instanceCounter, 0, 0, 0); } } |
