#include "entities.hpp" DynArray globalEntityTypes{16}; void EntityType_Init() { globalEntityTypes.Push( EntityType { .modelFile = "assets/models/cube.gltf", .entityTypeCode = "EntTypeCube", .entityHandle = ECS_CreateEntity(), .startingInstanceCount = 16, .Importer_GLTF = { .AccessorIndexVertex = 0, .AccessorIndexNormal = 1, .AccessorIndexUV = 2, .AccessorIndexIndex = 3, } } ); long entityTypeCount = globalEntityTypes.Count(); for (long i = 0; i < entityTypeCount; ++i) { EntityType_Load(globalEntityTypes[i]); } } void EntityType_Load(EntityType &et) { assert(et.startingInstanceCount > 0); if (et.modelFile != nullptr && et.modelFile != CAFE_BABE(char)) { // assert(et.vkPipelineLayoutCreateInfo != nullptr && et.vkPipelineLayoutCreateInfo != CAFE_BABE(VkPipelineLayoutCreateInfo) && "EntityType with a defined model must also contain appropriate Vulkan CreateInfos"); AssetHandle assetHandle{AM_Register(et.modelFile)}; const Asset *asset = AM_Get(assetHandle); CompGrBinds &grBinds = ECS_CreateGrBinds(et.entityHandle); // auto vkResult = vkCreatePipelineLayout(vkDevice, et.vkPipelineLayoutCreateInfo, vkAllocator, &grBinds.vkPipelineLayout); // assert(vkResult == VK_SUCCESS); // TODO grBinds.vkDescriptorSet cgltf_options options{}; // TODO allocator cgltf_data *gltfData = nullptr; cgltf_result result = cgltf_parse(&options, asset->ptr, asset->size, &gltfData); assert(result == cgltf_result_success); // TODO consider using AssetHandler OR loading this directly to the GPU result = cgltf_load_buffers(&options, gltfData, et.modelFile); assert(result == cgltf_result_success); result = cgltf_validate(gltfData); assert(result == cgltf_result_success); // make sure cgltf can interpret our model for (long i = 0; i < gltfData->accessors_count; ++i) { assert(gltfData->accessors[i].type != cgltf_type_invalid); } for (long i = 0; i < gltfData->buffers_count; ++i) { assert(gltfData->buffer_views[i].type != cgltf_buffer_view_type_invalid); } assert(et.Importer_GLTF.AccessorIndexVertex > -1); VkBufferCreateInfo bufferCI; bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferCI.pNext = nullptr; bufferCI.flags = {}; bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferCI.queueFamilyIndexCount = 1; bufferCI.pQueueFamilyIndices = &graphicsFamilyIndex; VkMemoryRequirements vkMemoryRequirements; if (et.Importer_GLTF.AccessorIndexVertex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexVertex]; grBinds.vertexCount = acc.count; bufferCI.size = acc.buffer_view->size; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.vertexBuffer); vkGetBufferMemoryRequirements(vkDevice, grBinds.vertexBuffer, &vkMemoryRequirements); } if (et.Importer_GLTF.AccessorIndexNormal > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexNormal]; grBinds.normalsCount = acc.count; bufferCI.size = acc.buffer_view->size; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.normalsBuffer); VkMemoryRequirements vkMemoryRequirementsNormals; vkGetBufferMemoryRequirements(vkDevice, grBinds.normalsBuffer, &vkMemoryRequirementsNormals); vkMemoryRequirements.memoryTypeBits |= vkMemoryRequirementsNormals.memoryTypeBits; vkMemoryRequirements.size += vkMemoryRequirementsNormals.size; assert(vkMemoryRequirementsNormals.alignment == vkMemoryRequirements.alignment); } if (et.Importer_GLTF.AccessorIndexUV > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexUV]; grBinds.uvCount = acc.count; bufferCI.size = acc.buffer_view->size; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.uvBuffer); VkMemoryRequirements vkMemoryRequirementsUV; vkGetBufferMemoryRequirements(vkDevice, grBinds.uvBuffer, &vkMemoryRequirementsUV); vkMemoryRequirements.memoryTypeBits |= vkMemoryRequirementsUV.memoryTypeBits; vkMemoryRequirements.size += vkMemoryRequirementsUV.size; assert(vkMemoryRequirementsUV.alignment == vkMemoryRequirements.alignment); } if (et.Importer_GLTF.AccessorIndexIndex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexIndex]; grBinds.indexCount = acc.count; bufferCI.size = acc.buffer_view->size; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.indexBuffer); VkMemoryRequirements vkMemoryRequirementsIndex; vkGetBufferMemoryRequirements(vkDevice, grBinds.indexBuffer, &vkMemoryRequirementsIndex); vkMemoryRequirements.memoryTypeBits |= vkMemoryRequirementsIndex.memoryTypeBits; vkMemoryRequirements.size += vkMemoryRequirementsIndex.size; assert(vkMemoryRequirementsIndex.alignment == vkMemoryRequirements.alignment); } // create VkDeviceMemory VkMemoryAllocateInfo vkMemoryAllocateInfo; vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; vkMemoryAllocateInfo.pNext = nullptr; vkMemoryAllocateInfo.allocationSize = vkMemoryRequirements.size; vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(vkMemoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &grBinds.deviceMemoryVert); // bind buffers if (et.Importer_GLTF.AccessorIndexVertex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexVertex]; assert(acc.buffer_view->offset % vkMemoryRequirements.alignment == 0); vkBindBufferMemory(vkDevice, grBinds.vertexBuffer, grBinds.deviceMemoryVert, acc.buffer_view->offset); } if (et.Importer_GLTF.AccessorIndexNormal > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexNormal]; assert(acc.buffer_view->offset % vkMemoryRequirements.alignment == 0); vkBindBufferMemory(vkDevice, grBinds.normalsBuffer, grBinds.deviceMemoryVert, acc.buffer_view->offset); } if (et.Importer_GLTF.AccessorIndexUV > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexUV]; assert(acc.buffer_view->offset % vkMemoryRequirements.alignment == 0); vkBindBufferMemory(vkDevice, grBinds.uvBuffer , grBinds.deviceMemoryVert, acc.buffer_view->offset); } if (et.Importer_GLTF.AccessorIndexIndex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexIndex]; assert(acc.buffer_view->offset % vkMemoryRequirements.alignment == 0); vkBindBufferMemory(vkDevice, grBinds.indexBuffer, grBinds.deviceMemoryVert, acc.buffer_view->offset); } // create transfer items && transfer { // reminder that we don't need to do instance here, because we're just // setting up the type. No instances have been created yet. VkDeviceMemory transferDeviceMemory; VkBuffer transferBuffer; VkMemoryRequirements vkMemoryRequirementsTransfer; bufferCI.size = vkMemoryRequirements.size; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &transferBuffer); vkGetBufferMemoryRequirements(vkDevice, transferBuffer, &vkMemoryRequirementsTransfer); vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(vkMemoryRequirementsTransfer.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); // note, this should be identical (other than memory type) to the dst buffer vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &transferDeviceMemory); vkBindBufferMemory(vkDevice, transferBuffer, transferDeviceMemory, 0); void *data; vkMapMemory(vkDevice, transferDeviceMemory, 0, gltfData->buffers[0].size, 0, &data); memcpy(data, gltfData->buffers[0].data, gltfData->buffers[0].size); vkUnmapMemory(vkDevice, transferDeviceMemory); 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(transferCommandBuffer, &vkCommandBufferBeginInfo); VkBufferCopy bufferCopys[4]; for (long i = 0; i < 4; ++i) { bufferCopys[i].dstOffset = 0; } long index = 0; if (et.Importer_GLTF.AccessorIndexVertex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexVertex]; bufferCopys[index].srcOffset = acc.buffer_view->offset; bufferCopys[index].size = acc.buffer_view->size; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.vertexBuffer, 1, &bufferCopys[index]); index += 1; } if (et.Importer_GLTF.AccessorIndexNormal > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexNormal]; bufferCopys[index].srcOffset = acc.buffer_view->offset; bufferCopys[index].size = acc.buffer_view->size; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.normalsBuffer, 1, &bufferCopys[index]); index += 1; } if (et.Importer_GLTF.AccessorIndexUV > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexUV]; bufferCopys[index].srcOffset = acc.buffer_view->offset; bufferCopys[index].size = acc.buffer_view->size; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.uvBuffer, 1, &bufferCopys[index]); index += 1; } if (et.Importer_GLTF.AccessorIndexIndex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexIndex]; bufferCopys[index].srcOffset = acc.buffer_view->offset; bufferCopys[index].size = acc.buffer_view->size; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.indexBuffer, 1, &bufferCopys[index]); } vkEndCommandBuffer(transferCommandBuffer); 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 = &transferCommandBuffer; submitInfo.signalSemaphoreCount = 0; submitInfo.pSignalSemaphores = nullptr; vkQueueSubmit(transferQueue, 1, &submitInfo, nullptr); vkQueueWaitIdle(transferQueue); vkDestroyBuffer(vkDevice, transferBuffer, vkAllocator); vkFreeMemory(vkDevice, transferDeviceMemory, vkAllocator); } // set up instance buffer bufferCI.size = sizeof(InstPos) * et.startingInstanceCount; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.instanceBuffer); VkMemoryRequirements vkMemoryRequirementsInst; vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBuffer, &vkMemoryRequirementsInst); vkMemoryAllocateInfo.allocationSize = vkMemoryRequirementsInst.size; vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(vkMemoryRequirementsInst.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &grBinds.deviceMemoryInst); vkBindBufferMemory(vkDevice, grBinds.instanceBuffer, grBinds.deviceMemoryInst, 0); // cleanup cgltf_free(gltfData); } } void EntityType_Teardown() { long entityTypeCount = globalEntityTypes.Count(); for (long i = 0; i < entityTypeCount; ++i) { if (globalEntityTypes[i].modelFile == nullptr) continue; auto *grBinds = ECS_GetGrBinds(globalEntityTypes[i].entityHandle); vkDestroyPipelineLayout(vkDevice, grBinds->vkPipelineLayout, vkAllocator); if (grBinds->vertexBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->vertexBuffer, vkAllocator); if (grBinds->normalsBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->normalsBuffer, vkAllocator); if (grBinds->uvBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->uvBuffer, vkAllocator); if (grBinds->indexBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->indexBuffer, vkAllocator); if (grBinds->instanceBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->instanceBuffer, vkAllocator); if (grBinds->deviceMemoryInst != VK_NULL_HANDLE) vkFreeMemory(vkDevice, grBinds->deviceMemoryInst, vkAllocator); if (grBinds->deviceMemoryVert != VK_NULL_HANDLE) vkFreeMemory(vkDevice, grBinds->deviceMemoryVert, vkAllocator); } }