#include "entities.hpp" #include "bucketed-array.hpp" #include "ecs.hpp" #include "game-settings.hpp" #include "level.hpp" #include "math-helpers.hpp" #include "memory.hpp" #include "physics.hpp" #include "static/missing-texture.hpp" #include "window.hpp" #include #include #include #include #include BucketContainer EntityType_BC{}; struct EntToTeardown { EntityHandle handle = EntityHandle_MAX; CompGrBinds *grBinds[1] = {nullptr}; uint8_t ticksToWait = 0; }; DynArray EntityTypesToTeardown{16}; void EntityType_Init() { Buckets_Init(EntityType_BC); } EntityType *EntityType_Create() { EntityTypeHandle entTypeHandle{Buckets_NewHandle(EntityType_BC)}; EntityType &entityType = EntityType_BC.buckets[entTypeHandle.bucketIndex][entTypeHandle.itemIndex]; new (&entityType) EntityType{}; ECS_CreateEntity(&entityType); return &entityType; } Entity_Base *EntityType_CreateGenericInstance(EntityType *et, Entity_Base *levelEnt, CompInstance *srcInstance, InstPos *instPos) { assert(et != nullptr); Entity_Base *genericEntity = ECS_CreateGenericEntity(); ECS_CreateEntity(genericEntity, levelEnt); for (size_t i = 0; i < et->detailsCount; ++i) { auto &etd = et->details[i]; auto *compInst = ECS_CreateInstance(genericEntity, etd.grBinds); btVector3 scaling{1.f,1.f,1.f}; btTransform posRot{}; btScalar mass = 1.f; if (srcInstance != nullptr) { if (srcInstance->collisionCallback.name[0] != '\0') { strncpy(compInst->collisionCallback.name, srcInstance->collisionCallback.name, CallbackSignatureLength); PkePlugin_SetSignatureFunc(&compInst->collisionCallback); } compInst->physicsLayer = srcInstance->physicsLayer; compInst->physicsMask = srcInstance->physicsMask; posRot = instPos->posRot; } else { compInst->physicsLayer = etd.bt.startingCollisionLayer; compInst->physicsMask = etd.bt.startingCollisionMask; posRot.setIdentity(); } if (instPos != nullptr) { mass = instPos->mass; scaling = instPos->scale; } else { mass = etd.bt.startingMass; } btVector3 localInertia(0, 0, 0); etd.bt.shape->calculateLocalInertia(mass, localInertia); compInst->bt.motionState = Pke_New(MemBkt_Bullet); new (compInst->bt.motionState) btDefaultMotionState(posRot); compInst->bt.rigidBody = Pke_New(MemBkt_Bullet); new (compInst->bt.rigidBody) btRigidBody(mass, compInst->bt.motionState, etd.bt.shape, localInertia); compInst->bt.rigidBody->setLinearVelocity(btVector3(0,0,0)); compInst->bt.rigidBody->setAngularVelocity(btVector3(0,0,0)); compInst->bt.rigidBody->getCollisionShape()->setLocalScaling(scaling); BtDynamicsWorld->addRigidBody(compInst->bt.rigidBody); compInst->bt.rigidBody->getBroadphaseProxy()->m_collisionFilterGroup = static_cast(compInst->physicsLayer); compInst->bt.rigidBody->getBroadphaseProxy()->m_collisionFilterMask = static_cast(compInst->physicsMask); compInst->bt.rigidBody->setUserPointer(reinterpret_cast(compInst)); } return genericEntity; } EntityType *EntityType_FindByTypeCode(const char *typeCode) { for (PkeHandleBucketIndex_T b = 0; b <= EntityType_BC.pkeHandle.bucketIndex; ++b) { auto &bkt = EntityType_BC.buckets[b]; long itemCount = EntityType_BC.pkeHandle.bucketIndex == b ? EntityType_BC.pkeHandle.itemIndex : EntityType_BC.limits.itemIndex; for (PkeHandleItemIndex_T i = 0; i < itemCount; ++i) { auto &entityType = bkt[i]; if (entityType.handle == EntityHandle_MAX) continue; if (strcmp(typeCode, entityType.entityTypeCode) == 0) { return &entityType; } } } return nullptr; } EntityType *EntityType_FindByEntityHandle(EntityHandle handle) { if (handle == EntityHandle_MAX) return nullptr; for (PkeHandleBucketIndex_T b = 0; b <= EntityType_BC.pkeHandle.bucketIndex; ++b) { auto &bkt = EntityType_BC.buckets[b]; long itemCount = EntityType_BC.pkeHandle.bucketIndex == b ? EntityType_BC.pkeHandle.itemIndex : EntityType_BC.limits.itemIndex; for (PkeHandleItemIndex_T i = 0; i < itemCount; ++i) { auto &entityType = bkt[i]; if (entityType.handle == handle) { return &entityType; } } } return nullptr; } void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs) { combinedMemReqs.size = 0; combinedMemReqs.alignment = memReqs[0].alignment; combinedMemReqs.memoryTypeBits = memReqs[0].memoryTypeBits; for (long i = 1; i < memReqsCount; ++i) { combinedMemReqs.memoryTypeBits |= memReqs[i].memoryTypeBits; if (combinedMemReqs.alignment == memReqs[i].alignment) { continue; } VkDeviceSize larger, smaller; if (combinedMemReqs.alignment > memReqs[i].alignment) { larger = combinedMemReqs.alignment; smaller = memReqs[i].alignment; } else { larger = memReqs[i].alignment; smaller = combinedMemReqs.alignment; } if (larger % smaller == 0) { combinedMemReqs.alignment = larger; continue; } int combined = larger * smaller; while ((combined / 2) % 2 == 0 && (combined / 2) % larger == 0) { combined /= 2; } combinedMemReqs.alignment = combined; } for (long i = 0; i < memReqsCount; ++i) { uint32_t alignmentPadding = memReqs[i].size % combinedMemReqs.alignment; memReqs[i].size += (alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding); combinedMemReqs.size += memReqs[i].size; } } struct EntityTypeDetails_LoadHelperStruct { EntityTypeDetails *etd = nullptr; AssetHandle textureAssetHandle = AssetHandle_MAX; const Asset *textureAsset = nullptr; struct { DynArray *vertexes = nullptr; DynArray *normals = nullptr; DynArray *uv = nullptr; DynArray *indexes = nullptr; } physDbg; }; struct EntityType_LoadHelperStruct { MemBucket *bkt = nullptr; EntityType &et; DynArray *etdHelpers = nullptr; const cgltf_data *gltfData = nullptr; const Asset *modelBinAsset = nullptr; DynArray *vertMemoryRequirements = nullptr; DynArray *instMemoryRequirements = nullptr; DynArray *physVertMemoryRequirements = nullptr; DynArray *textureMemoryRequirements = nullptr; VkMemoryRequirements vertMemoryRequirementsCombined{}; VkMemoryRequirements instMemoryRequirementsCombined{}; VkMemoryRequirements physVertMemoryRequirementsCombined{}; VkMemoryRequirements textureMemoryRequirementsCombined{}; }; void EntityType_PreLoad(EntityType_LoadHelperStruct &helper) { const long expectedBufferCount = 4; helper.vertMemoryRequirements->Reserve(helper.et.detailsCount * expectedBufferCount); helper.instMemoryRequirements->Reserve(helper.et.detailsCount); helper.physVertMemoryRequirements->Reserve(helper.et.detailsCount * expectedBufferCount); helper.textureMemoryRequirements->Reserve(helper.et.detailsCount); VkBuffer buffer; 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; VkImage image; VkImageCreateInfo vkImageCreateInfo; vkImageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; vkImageCreateInfo.pNext = nullptr; vkImageCreateInfo.flags = 0; vkImageCreateInfo.imageType = VK_IMAGE_TYPE_2D; vkImageCreateInfo.mipLevels = 1; vkImageCreateInfo.arrayLayers = 1; vkImageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; vkImageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; vkImageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; vkImageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkImageCreateInfo.queueFamilyIndexCount = 0; vkImageCreateInfo.pQueueFamilyIndices = nullptr; vkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; for (int64_t i = 0; i < helper.et.detailsCount; ++i) { EntityTypeDetails &etd = helper.et.details[i]; EntityTypeDetails_LoadHelperStruct &etdHelper = helper.etdHelpers->Push(); etdHelper.etd = &etd; etd.grBinds = ECS_CreateGrBinds(&helper.et);; etdHelper.physDbg.vertexes = reinterpret_cast *>(Pke_New(sizeof(DynArray), 64, helper.bkt)); etdHelper.physDbg.normals = reinterpret_cast *>(Pke_New(sizeof(DynArray), 64, helper.bkt)); etdHelper.physDbg.uv = reinterpret_cast *>(Pke_New(sizeof(DynArray), 64, helper.bkt)); etdHelper.physDbg.indexes = reinterpret_cast *>(Pke_New(sizeof(DynArray), 64, helper.bkt)); new (etdHelper.physDbg.vertexes) DynArray(helper.bkt); new (etdHelper.physDbg.normals) DynArray(helper.bkt); new (etdHelper.physDbg.uv) DynArray(helper.bkt); new (etdHelper.physDbg.indexes) DynArray(helper.bkt); /* * phys */ btConvexHullShape *shape; { shape = Pke_New(MemBkt_Bullet); btScalar *vertDataPointer = reinterpret_cast(helper.modelBinAsset->ptr); /* TODO JCB - 2024-01-02 * we shouldn't assume that the first index is the vertexes */ uint64_t vertIndex = (i * expectedBufferCount); vertDataPointer += helper.gltfData->accessors[vertIndex].buffer_view->offset; new (shape) btConvexHullShape(vertDataPointer, helper.gltfData->accessors[vertIndex].count, helper.gltfData->accessors[vertIndex].stride); shape->optimizeConvexHull(); shape->initializePolyhedralFeatures(); etd.bt.shape = shape; } assert(shape != nullptr); // convex hull debug const btConvexPolyhedron *pol = shape->getConvexPolyhedron(); etdHelper.physDbg.vertexes->Reserve(pol->m_vertices.size()); etdHelper.physDbg.normals->Reserve(pol->m_vertices.size()); etdHelper.physDbg.uv->Reserve(pol->m_vertices.size()); etdHelper.physDbg.indexes->Reserve(pol->m_faces.size()); for (long k = 0; k < pol->m_vertices.size(); ++k) { btVector3 norm = pol->m_vertices[k]; auto &glmVert = etdHelper.physDbg.vertexes->Push(); BulletToGlm(norm, glmVert); norm.safeNormalize(); auto &glmNorm = etdHelper.physDbg.normals->Push(); BulletToGlm(norm, glmNorm); etdHelper.physDbg.uv->Push({norm.x(), norm.y()}); } for (long ii = 0; ii < pol->m_faces.size(); ++ii) { for (long k = 2; k < pol->m_faces[ii].m_indices.size(); ++k) { etdHelper.physDbg.indexes->Push(pol->m_faces[ii].m_indices[0]); etdHelper.physDbg.indexes->Push(pol->m_faces[ii].m_indices[k - 1]); etdHelper.physDbg.indexes->Push(pol->m_faces[ii].m_indices[k]); } } for (int64_t index = 0; index < expectedBufferCount; ++index) { /* TODO JCB - 2024-01-02 * lol */ if (index == 0) { bufferCI.size = sizeof(glm::vec3) * etdHelper.physDbg.vertexes->Count(); } else if (index == 1) { bufferCI.size = sizeof(glm::vec3) * etdHelper.physDbg.normals->Count(); } else if (index == 2) { bufferCI.size = sizeof(glm::vec2) * etdHelper.physDbg.uv->Count(); } else if (index == 3) { bufferCI.size = sizeof(uint16_t) * etdHelper.physDbg.indexes->Count(); } if (index == 3) { bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; } else { bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; } vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &buffer); vkGetBufferMemoryRequirements(vkDevice, buffer, &helper.physVertMemoryRequirements->Push()); vkDestroyBuffer(vkDevice, buffer, vkAllocator); } /* * verts */ for (int64_t index = 0; index < expectedBufferCount; ++index) { const auto &acc = helper.gltfData->accessors[(expectedBufferCount * i) + index]; bufferCI.size = acc.buffer_view->size; /* TODO JCB - 2024-01-02 * If our bindings ever change, == 3 isn't good enough to determine * which of all the buffers is the index buffer */ if (index == 3) { bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; } else { bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; } vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &buffer); vkGetBufferMemoryRequirements(vkDevice, buffer, &helper.vertMemoryRequirements->Push()); vkDestroyBuffer(vkDevice, buffer, vkAllocator); } /* * instance */ uint32_t instBufferStartingCount = etd.startingInstanceCount; instBufferStartingCount = instBufferStartingCount < 1 ? 1 : instBufferStartingCount; bufferCI.size = sizeof(glm::mat4) * instBufferStartingCount; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &buffer); vkGetBufferMemoryRequirements(vkDevice, buffer, &helper.instMemoryRequirements->Push()); vkDestroyBuffer(vkDevice, buffer, vkAllocator); /* * texture */ int32_t pixelWidth, pixelHeight, pixelChannels; etdHelper.textureAssetHandle = AssetHandle{AM_GetHandle(etd.textureAssetKey)}; if (etdHelper.textureAssetHandle != AssetHandle_MAX) { etdHelper.textureAsset = AM_Get(etdHelper.textureAssetHandle); stbi_uc *pixels = stbi_load_from_memory(static_cast(etdHelper.textureAsset->ptr), etdHelper.textureAsset->size, &pixelWidth, &pixelHeight, &pixelChannels, STBI_rgb_alpha); assert(pixels != nullptr && "sbti_load failed to load image."); stbi_image_free(pixels); } else { pixelWidth = 2; pixelHeight = 2; pixelChannels = 4; } VkFormat imageFormat = VK_FORMAT_R8G8B8A8_SRGB; if (pixelChannels == 3) { imageFormat = VK_FORMAT_R8G8B8_SRGB; } else if (pixelChannels == 2) { imageFormat = VK_FORMAT_R8G8_SRGB; } else if (pixelChannels == 1) { imageFormat = VK_FORMAT_R8_SRGB; } else { assert(pixelChannels != 0 && pixelChannels < 5); } vkImageCreateInfo.format = imageFormat; vkImageCreateInfo.extent = VkExtent3D { .width = static_cast(pixelWidth), .height = static_cast(pixelHeight), .depth = 1 }; vkCreateImage(vkDevice, &vkImageCreateInfo, vkAllocator, &image); vkGetImageMemoryRequirements(vkDevice, image, &helper.textureMemoryRequirements->Push()); vkDestroyImage(vkDevice, image, vkAllocator); } VkMemoryAllocateInfo vkMemoryAllocateInfo; vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; vkMemoryAllocateInfo.pNext = nullptr; /* * phys */ CalculateCombinedMemReqs(helper.physVertMemoryRequirements->Count(), helper.physVertMemoryRequirements->GetPtr(), helper.physVertMemoryRequirementsCombined); vkMemoryAllocateInfo.allocationSize = helper.physVertMemoryRequirementsCombined.size; vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(helper.physVertMemoryRequirementsCombined.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &helper.et.deviceMemoryPhysVert); /* * verts */ CalculateCombinedMemReqs(helper.vertMemoryRequirements->Count(), helper.vertMemoryRequirements->GetPtr(), helper.vertMemoryRequirementsCombined); vkMemoryAllocateInfo.allocationSize = helper.vertMemoryRequirementsCombined.size; vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(helper.vertMemoryRequirementsCombined.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &helper.et.deviceMemoryVert); /* * instance */ CalculateCombinedMemReqs(helper.instMemoryRequirements->Count(), helper.instMemoryRequirements->GetPtr(), helper.instMemoryRequirementsCombined); vkMemoryAllocateInfo.allocationSize = helper.instMemoryRequirementsCombined.size; vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(helper.instMemoryRequirementsCombined.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &helper.et.deviceMemoryInst); /* * texture */ CalculateCombinedMemReqs(helper.textureMemoryRequirements->Count(), helper.textureMemoryRequirements->GetPtr(), helper.textureMemoryRequirementsCombined); vkMemoryAllocateInfo.allocationSize = helper.textureMemoryRequirementsCombined.size; vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(helper.textureMemoryRequirementsCombined.memoryTypeBits, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); if (vkMemoryAllocateInfo.memoryTypeIndex == 0) { vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(helper.textureMemoryRequirementsCombined.memoryTypeBits, 0); } vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &helper.et.deviceMemoryTexture); } void EntityType_LoadTexture(EntityType_LoadHelperStruct &helper, const int64_t index) { EntityTypeDetails_LoadHelperStruct &etdHelper = (*helper.etdHelpers)[index]; int32_t pixelWidth, pixelHeight, pixelChannels; stbi_uc *pixels = nullptr; if (etdHelper.textureAssetHandle != AssetHandle_MAX) { pixels = stbi_load_from_memory(static_cast(etdHelper.textureAsset->ptr), etdHelper.textureAsset->size, &pixelWidth, &pixelHeight, &pixelChannels, STBI_rgb_alpha); assert(pixels != nullptr && "sbti_load failed to load image."); } else { pixelWidth = 2; pixelHeight = 2; pixelChannels = 4; pixels = const_cast(&PKE_MISSING_TEXTURE_DATA[0]); } uint32_t imageSizeBytes = pixelWidth * pixelHeight * pixelChannels; VkFormat imageFormat = VK_FORMAT_R8G8B8A8_SRGB; if (pixelChannels == 3) { imageFormat = VK_FORMAT_R8G8B8_SRGB; } else if (pixelChannels == 2) { imageFormat = VK_FORMAT_R8G8_SRGB; } else if (pixelChannels == 1) { imageFormat = VK_FORMAT_R8_SRGB; } else { assert(pixelChannels != 0 && pixelChannels < 5); } VkImageCreateInfo vkImageCreateInfo; vkImageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; vkImageCreateInfo.pNext = nullptr; vkImageCreateInfo.flags = 0; vkImageCreateInfo.imageType = VK_IMAGE_TYPE_2D; vkImageCreateInfo.format = imageFormat; vkImageCreateInfo.extent = VkExtent3D { .width = static_cast(pixelWidth), .height = static_cast(pixelHeight), .depth = 1 }; vkImageCreateInfo.mipLevels = 1; vkImageCreateInfo.arrayLayers = 1; vkImageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; vkImageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; vkImageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; vkImageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkImageCreateInfo.queueFamilyIndexCount = 0; vkImageCreateInfo.pQueueFamilyIndices = nullptr; vkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; vkCreateImage(vkDevice, &vkImageCreateInfo, vkAllocator, &etdHelper.etd->textureImage); // TODO calculate padding vkBindImageMemory(vkDevice, etdHelper.etd->textureImage, helper.et.deviceMemoryTexture, 0); VkImageViewCreateInfo vkImageViewCreateInfo; vkImageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; vkImageViewCreateInfo.pNext = nullptr; vkImageViewCreateInfo.flags = 0; vkImageViewCreateInfo.image = etdHelper.etd->textureImage; // TODO animated textures vkImageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; vkImageViewCreateInfo.format = imageFormat; vkImageViewCreateInfo.components = VkComponentMapping { .r = VK_COMPONENT_SWIZZLE_IDENTITY, .g = VK_COMPONENT_SWIZZLE_IDENTITY, .b = VK_COMPONENT_SWIZZLE_IDENTITY, .a = VK_COMPONENT_SWIZZLE_IDENTITY, }; vkImageViewCreateInfo.subresourceRange = VkImageSubresourceRange { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, // TODO MapMap .levelCount = 1, .baseArrayLayer = 0, // TODO animated textures .layerCount = 1, }; vkCreateImageView(vkDevice, &vkImageViewCreateInfo, vkAllocator, &etdHelper.etd->textureImageView); // transition image layout and copy to buffer VkBuffer transferImageBuffer; VkDeviceMemory transferImageMemory; void *deviceData; BeginTransferBuffer(imageSizeBytes, transferImageBuffer, transferImageMemory, deviceData); memcpy(deviceData, pixels, imageSizeBytes); { VkImageMemoryBarrier vkImageMemoryBarrier; vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; vkImageMemoryBarrier.pNext = nullptr; vkImageMemoryBarrier.srcAccessMask = {}; vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkImageMemoryBarrier.image = etdHelper.etd->textureImage; vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, // TODO MipMap .levelCount = 1, .baseArrayLayer = 0, // TODO animated textures .layerCount = 1, }; VkCommandBufferBeginInfo vkCommandBufferBeginInfo; vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vkCommandBufferBeginInfo.pNext = nullptr; vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; vkBeginCommandBuffer(transferCommandBuffer, &vkCommandBufferBeginInfo); vkCmdPipelineBarrier(transferCommandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); // TODO animated textures / texture array - make this an array VkBufferImageCopy vkBufferImageCopy; vkBufferImageCopy.bufferOffset = 0; vkBufferImageCopy.bufferRowLength = pixelWidth; vkBufferImageCopy.bufferImageHeight = pixelHeight; vkBufferImageCopy.imageSubresource = VkImageSubresourceLayers { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, // TODO animated textures .baseArrayLayer = 0, .layerCount = 1, }; vkBufferImageCopy.imageOffset = VkOffset3D { .x = 0, .y = 0, .z = 0, }; vkBufferImageCopy.imageExtent = VkExtent3D { .width = static_cast(pixelWidth), .height = static_cast(pixelHeight), .depth = 1, }; vkCmdCopyBufferToImage(transferCommandBuffer, transferImageBuffer, etdHelper.etd->textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vkBufferImageCopy); 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); vkResetCommandBuffer(transferCommandBuffer, 0); } EndTransferBuffer(transferImageBuffer, transferImageMemory); { VkImageMemoryBarrier vkImageMemoryBarrier; vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; vkImageMemoryBarrier.pNext = nullptr; vkImageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkImageMemoryBarrier.image = etdHelper.etd->textureImage; vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, // TODO MipMap .levelCount = 1, .baseArrayLayer = 0, // TODO animated textures .layerCount = 1, }; VkCommandBufferBeginInfo vkCommandBufferBeginInfo; vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vkCommandBufferBeginInfo.pNext = nullptr; vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; vkBeginCommandBuffer(graphicsCommandBuffer, &vkCommandBufferBeginInfo); vkCmdPipelineBarrier(graphicsCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); 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); } // TODO double-check this? if (etdHelper.textureAssetHandle != AssetHandle_MAX) { stbi_image_free(pixels); AM_Release(etdHelper.textureAssetHandle); } // descriptor pool & sets VkDescriptorPoolSize descriptorPoolSizes[2]; descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptorPoolSizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT; descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorPoolSizes[1].descriptorCount = MAX_FRAMES_IN_FLIGHT; VkDescriptorPoolCreateInfo vkDescriptorPoolCreateInfo; vkDescriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; vkDescriptorPoolCreateInfo.pNext = nullptr; vkDescriptorPoolCreateInfo.flags = 0; vkDescriptorPoolCreateInfo.maxSets = MAX_FRAMES_IN_FLIGHT; vkDescriptorPoolCreateInfo.poolSizeCount = (uint32_t)2; vkDescriptorPoolCreateInfo.pPoolSizes = descriptorPoolSizes; // consider making me a global pool auto vkResult = vkCreateDescriptorPool(vkDevice, &vkDescriptorPoolCreateInfo, vkAllocator, &etdHelper.etd->vkDescriptorPool); assert(vkResult == VK_SUCCESS); VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT]; for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { descriptorSets[i] = pkePipelines.vkDescriptorSetLayout_Texture; } VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo; vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; vkDescriptorSetAllocateInfo.pNext = nullptr; vkDescriptorSetAllocateInfo.descriptorPool = etdHelper.etd->vkDescriptorPool; vkDescriptorSetAllocateInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT; vkDescriptorSetAllocateInfo.pSetLayouts = descriptorSets; etdHelper.etd->grBinds->vkDescriptorSets = Pke_New(MAX_FRAMES_IN_FLIGHT); for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { etdHelper.etd->grBinds->vkDescriptorSets[i] = VkDescriptorSet{}; } vkResult = vkAllocateDescriptorSets(vkDevice, &vkDescriptorSetAllocateInfo, etdHelper.etd->grBinds->vkDescriptorSets); assert(vkResult == VK_SUCCESS); VkWriteDescriptorSet writeDescriptorSets[2 * MAX_FRAMES_IN_FLIGHT]; for (long i = 0; i < 2 * MAX_FRAMES_IN_FLIGHT; ++i) { writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptorSets[i].pNext = nullptr; writeDescriptorSets[i].dstSet = nullptr; writeDescriptorSets[i].dstBinding = i % 2; writeDescriptorSets[i].dstArrayElement = 0; writeDescriptorSets[i].descriptorCount = 1; writeDescriptorSets[i].descriptorType = (i % 2) == 0 ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; writeDescriptorSets[i].pImageInfo = nullptr; writeDescriptorSets[i].pBufferInfo = nullptr; writeDescriptorSets[i].pTexelBufferView = nullptr; } VkDescriptorImageInfo textureDescriptorInfo; textureDescriptorInfo.sampler = pkePipelines.vkSampler_Texture; textureDescriptorInfo.imageView = etdHelper.etd->textureImageView; textureDescriptorInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkDescriptorBufferInfo vkDescriptorBufferInfo[MAX_FRAMES_IN_FLIGHT]; for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { vkDescriptorBufferInfo[i].buffer = UniformBuffers[i]; vkDescriptorBufferInfo[i].offset = 0; vkDescriptorBufferInfo[i].range = sizeof(UniformBufferObject); long uboIndex = i * 2; long samplerIndex = uboIndex + 1; writeDescriptorSets[uboIndex].pBufferInfo = &vkDescriptorBufferInfo[i]; writeDescriptorSets[uboIndex].dstSet = etdHelper.etd->grBinds->vkDescriptorSets[i]; writeDescriptorSets[samplerIndex].pImageInfo = &textureDescriptorInfo; writeDescriptorSets[samplerIndex].dstSet = etdHelper.etd->grBinds->vkDescriptorSets[i]; } vkUpdateDescriptorSets(vkDevice, 2 * MAX_FRAMES_IN_FLIGHT, writeDescriptorSets, 0, nullptr); } void EntityType_LoadMesh(EntityType_LoadHelperStruct &helper, const int64_t meshIndex) { EntityTypeDetails_LoadHelperStruct &etdHelper = (*helper.etdHelpers)[meshIndex]; // create and bind buffers // TODO load me from gltf data const long expectedBufferCount = 4; int64_t accessorIndexVertex = (meshIndex * expectedBufferCount) + 0; int64_t accessorIndexNormal = (meshIndex * expectedBufferCount) + 1; int64_t accessorIndexUV = (meshIndex * expectedBufferCount) + 2; int64_t accessorIndexIndex = (meshIndex * expectedBufferCount) + 3; 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; long index = 0; uint32_t runningOffset = 0; uint32_t alignmentPadding = 0; // vertex const auto &accVert = helper.gltfData->accessors[accessorIndexVertex]; uint32_t offsetVert = runningOffset; uint32_t sizeVert = accVert.buffer_view->size; etdHelper.etd->grBinds->vertexFirstBinding = index; etdHelper.etd->grBinds->vertexBindingCount = 1; alignmentPadding = sizeVert % helper.vertMemoryRequirementsCombined.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : helper.vertMemoryRequirementsCombined.alignment - alignmentPadding; sizeVert += alignmentPadding; bufferCI.size = sizeVert; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->vertexBuffer); vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->vertexBuffer, helper.et.deviceMemoryVert, offsetVert); runningOffset += sizeVert; index += 1; // normals const auto &accNorm = helper.gltfData->accessors[accessorIndexNormal]; uint32_t offsetNorm = runningOffset; uint32_t sizeNorm = accNorm.buffer_view->size; etdHelper.etd->grBinds->normalsFirstBinding = index; etdHelper.etd->grBinds->normalsBindingCount = 1; alignmentPadding = sizeNorm % helper.vertMemoryRequirementsCombined.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : helper.vertMemoryRequirementsCombined.alignment - alignmentPadding; sizeNorm += alignmentPadding; bufferCI.size = sizeNorm; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->normalsBuffer); vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->normalsBuffer, helper.et.deviceMemoryVert, offsetNorm); runningOffset += sizeNorm; index += 1; // uv const auto &accUV = helper.gltfData->accessors[accessorIndexUV]; uint32_t offsetUV = runningOffset; uint32_t sizeUV = accUV.buffer_view->size; etdHelper.etd->grBinds->uvFirstBinding = index; etdHelper.etd->grBinds->uvBindingCount = 1; alignmentPadding = sizeUV % helper.vertMemoryRequirementsCombined.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : helper.vertMemoryRequirementsCombined.alignment - alignmentPadding; sizeUV += alignmentPadding; bufferCI.size = sizeUV; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->uvBuffer); vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->uvBuffer , helper.et.deviceMemoryVert, offsetUV); runningOffset += sizeUV; index += 1; // 2023-09-27 - JCB // I don't know where else to put this etdHelper.etd->grBinds->instanceFirstBinding = index; etdHelper.etd->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. // index const auto &accIndex = helper.gltfData->accessors[accessorIndexIndex]; uint32_t offsetIndex = runningOffset; uint32_t sizeIndex = accIndex.buffer_view->size; etdHelper.etd->grBinds->indexBindingCount = 1; etdHelper.etd->grBinds->indexCount = accIndex.count; alignmentPadding = sizeIndex % helper.vertMemoryRequirementsCombined.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : helper.vertMemoryRequirementsCombined.alignment - alignmentPadding; sizeIndex += alignmentPadding; bufferCI.size = sizeIndex; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->indexBuffer); vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->indexBuffer, helper.et.deviceMemoryVert, offsetIndex); runningOffset += sizeIndex; // index += 1; assert(runningOffset == helper.vertMemoryRequirementsCombined.size); // create transfer items && transfer { VkDeviceMemory transferDeviceMemory; VkBuffer transferBuffer; void *data; BeginTransferBuffer(helper.vertMemoryRequirementsCombined.size, transferBuffer, transferDeviceMemory, data); memset(data, '\0', helper.vertMemoryRequirementsCombined.size); char *dstPtr = nullptr; char *srcPtr = nullptr; dstPtr = static_cast(data) + offsetVert; srcPtr = static_cast(helper.modelBinAsset->ptr) + accVert.buffer_view->offset; memcpy(dstPtr, srcPtr, accVert.buffer_view->size); dstPtr = static_cast(data) + offsetNorm; srcPtr = static_cast(helper.modelBinAsset->ptr) + accNorm.buffer_view->offset; memcpy(dstPtr, srcPtr, accNorm.buffer_view->size); dstPtr = static_cast(data) + offsetUV; srcPtr = static_cast(helper.modelBinAsset->ptr) + accUV.buffer_view->offset; memcpy(dstPtr, srcPtr, accUV.buffer_view->size); dstPtr = static_cast(data) + offsetIndex; srcPtr = static_cast(helper.modelBinAsset->ptr) + accIndex.buffer_view->offset; memcpy(dstPtr, srcPtr, accIndex.buffer_view->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(transferCommandBuffer, &vkCommandBufferBeginInfo); VkBufferCopy bufferCopys[expectedBufferCount]; for (long i = 0; i < expectedBufferCount; ++i) { bufferCopys[i].dstOffset = 0; } index = 0; bufferCopys[index].srcOffset = offsetVert; bufferCopys[index].size = sizeVert; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, etdHelper.etd->grBinds->vertexBuffer, 1, &bufferCopys[index]); index+=1; bufferCopys[index].srcOffset = offsetNorm; bufferCopys[index].size = sizeNorm; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, etdHelper.etd->grBinds->normalsBuffer, 1, &bufferCopys[index]); index+=1; bufferCopys[index].srcOffset = offsetUV; bufferCopys[index].size = sizeUV; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, etdHelper.etd->grBinds->uvBuffer, 1, &bufferCopys[index]); index+=1; bufferCopys[index].srcOffset = offsetIndex; bufferCopys[index].size = sizeIndex; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, etdHelper.etd->grBinds->indexBuffer, 1, &bufferCopys[index]); // index+=1; 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); EndTransferBuffer(transferBuffer, transferDeviceMemory); } // set up instance buffer etdHelper.etd->grBinds->instanceBufferMaxCount = etdHelper.etd->startingInstanceCount; etdHelper.etd->grBinds->instanceBufferMaxCount = etdHelper.etd->grBinds->instanceBufferMaxCount < 1 ? 1 : etdHelper.etd->grBinds->instanceBufferMaxCount; bufferCI.size = sizeof(glm::mat4) * etdHelper.etd->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, &etdHelper.etd->grBinds->instanceBuffer); vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->instanceBuffer, helper.et.deviceMemoryInst, 0); // bullet // set up convex hull debug { index = 0; runningOffset = 0; // vertex offsetVert = runningOffset; sizeVert = sizeof(glm::vec3) * etdHelper.physDbg.vertexes->Count(); etdHelper.etd->grBinds->physVertBD.firstBinding = index; etdHelper.etd->grBinds->physVertBD.bindingCount = 1; alignmentPadding = sizeVert % helper.physVertMemoryRequirementsCombined.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : helper.physVertMemoryRequirementsCombined.alignment - alignmentPadding; sizeVert += alignmentPadding; bufferCI.size = sizeVert; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->physVertBD.buffer); vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->physVertBD.buffer, helper.et.deviceMemoryPhysVert, offsetVert); runningOffset += sizeVert; // norm index = 1; offsetNorm = runningOffset; sizeNorm = sizeof(glm::vec3) * etdHelper.physDbg.normals->Count(); etdHelper.etd->grBinds->physNormBD.firstBinding = index; etdHelper.etd->grBinds->physNormBD.bindingCount = 1; alignmentPadding = sizeNorm % helper.physVertMemoryRequirementsCombined.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : helper.physVertMemoryRequirementsCombined.alignment - alignmentPadding; sizeNorm += alignmentPadding; bufferCI.size = sizeNorm; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->physNormBD.buffer); vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->physNormBD.buffer, helper.et.deviceMemoryPhysVert, offsetNorm); runningOffset += sizeNorm; // uv index = 2; offsetUV = runningOffset; sizeUV = sizeof(glm::vec2) * etdHelper.physDbg.uv->Count(); etdHelper.etd->grBinds->physUvBD.firstBinding = index; etdHelper.etd->grBinds->physUvBD.bindingCount = 1; alignmentPadding = sizeUV % helper.physVertMemoryRequirementsCombined.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : helper.physVertMemoryRequirementsCombined.alignment - alignmentPadding; sizeUV += alignmentPadding; bufferCI.size = sizeUV; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->physUvBD.buffer); vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->physUvBD.buffer, helper.et.deviceMemoryPhysVert, offsetUV); runningOffset += sizeUV; // index index = 3; offsetIndex = runningOffset; sizeIndex = sizeof(uint16_t) * etdHelper.physDbg.indexes->Count(); etdHelper.etd->grBinds->physIndxBD.firstBinding = index; etdHelper.etd->grBinds->physIndxBD.bindingCount = 1; alignmentPadding = sizeIndex % helper.physVertMemoryRequirementsCombined.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : helper.physVertMemoryRequirementsCombined.alignment - alignmentPadding; sizeIndex += alignmentPadding; bufferCI.size = sizeIndex; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->physIndxBD.buffer); vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->physIndxBD.buffer, helper.et.deviceMemoryPhysVert, offsetIndex); runningOffset += sizeIndex; assert(runningOffset == helper.physVertMemoryRequirementsCombined.size); // create transfer items && transfer { VkDeviceMemory transferDeviceMemory; VkBuffer transferBuffer; void *data; BeginTransferBuffer(helper.physVertMemoryRequirementsCombined.size, transferBuffer, transferDeviceMemory, data); memset(data, '\0', helper.physVertMemoryRequirementsCombined.size); runningOffset = 0; char *dstPtr = nullptr; char *srcPtr = nullptr; dstPtr = static_cast(data) + runningOffset; srcPtr = reinterpret_cast(etdHelper.physDbg.vertexes->GetPtr()); memcpy(dstPtr, srcPtr, sizeVert); runningOffset += sizeVert; dstPtr = static_cast(data) + runningOffset; srcPtr = reinterpret_cast(etdHelper.physDbg.normals->GetPtr()); memcpy(dstPtr, srcPtr, sizeNorm); runningOffset += sizeNorm; dstPtr = static_cast(data) + runningOffset; srcPtr = reinterpret_cast(etdHelper.physDbg.uv->GetPtr()); memcpy(dstPtr, srcPtr, sizeUV); runningOffset += sizeUV; dstPtr = static_cast(data) + runningOffset; srcPtr = reinterpret_cast(etdHelper.physDbg.indexes->GetPtr()); memcpy(dstPtr, srcPtr, sizeIndex); 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[expectedBufferCount]; for (long i = 0; i < expectedBufferCount; ++i) { bufferCopys[i].dstOffset = 0; } index = 0; runningOffset = 0; bufferCopys[index].srcOffset = runningOffset; bufferCopys[index].size = sizeVert; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, etdHelper.etd->grBinds->physVertBD.buffer, 1, &bufferCopys[index]); runningOffset += sizeVert; index+=1; bufferCopys[index].srcOffset = runningOffset; bufferCopys[index].size = sizeNorm; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, etdHelper.etd->grBinds->physNormBD.buffer, 1, &bufferCopys[index]); runningOffset += sizeNorm; index+=1; bufferCopys[index].srcOffset = runningOffset; bufferCopys[index].size = sizeUV; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, etdHelper.etd->grBinds->physUvBD.buffer, 1, &bufferCopys[index]); runningOffset += sizeUV; index+=1; bufferCopys[index].srcOffset = runningOffset; bufferCopys[index].size = sizeIndex; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, etdHelper.etd->grBinds->physIndxBD.buffer, 1, &bufferCopys[index]); // runningOffset += sizeIndex; // index+=1; 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); EndTransferBuffer(transferBuffer, transferDeviceMemory); } } } void EntityType_Load(EntityType &et) { AssetHandle assetHandle{AM_GetHandle(et.modelAssetKey)}; assert(assetHandle != AssetHandle_MAX); const Asset *asset = AM_Get(assetHandle); 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); result = cgltf_validate(gltfData); assert(result == cgltf_result_success); assert(gltfData->buffers_count == 1); // 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); } et.detailsCount = gltfData->nodes_count; assert(et.detailsCount <= EntityTypeDetails_MAX && "Maximum supported number of meshes in gltf is hard-coded, update _MAX if not unreasonable"); std::filesystem::path gltfPath{asset->basePath}; gltfPath.replace_filename(gltfData->buffers[0].uri); AssetHandle modelBinHandle = AM_Register(gltfPath.c_str(), PKE_ASSET_TYPE_UNSET); const Asset *modelBinAsset = AM_Get(modelBinHandle); MemBucket *entLoaderBkt = Pke_BeginTransientBucket(); EntityType_LoadHelperStruct helper { .bkt = entLoaderBkt, .et = et, .etdHelpers = reinterpret_cast *>(Pke_New(sizeof(DynArray), 64, entLoaderBkt)), .gltfData = gltfData, .modelBinAsset = modelBinAsset, .vertMemoryRequirements = reinterpret_cast *>(Pke_New(sizeof(DynArray), 64, entLoaderBkt)), .instMemoryRequirements = reinterpret_cast *>(Pke_New(sizeof(DynArray), 64, entLoaderBkt)), .physVertMemoryRequirements = reinterpret_cast *>(Pke_New(sizeof(DynArray), 64, entLoaderBkt)), .textureMemoryRequirements = reinterpret_cast *>(Pke_New(sizeof(DynArray), 64, entLoaderBkt)), }; new (helper.etdHelpers) DynArray{entLoaderBkt}; new (helper.vertMemoryRequirements) DynArray{entLoaderBkt}; new (helper.instMemoryRequirements) DynArray{entLoaderBkt}; new (helper.physVertMemoryRequirements) DynArray{entLoaderBkt}; new (helper.textureMemoryRequirements) DynArray{entLoaderBkt}; EntityType_PreLoad(helper); for (int64_t i = 0; i < et.detailsCount; ++i) { EntityTypeDetails_LoadHelperStruct &etdHelper = (*helper.etdHelpers)[i]; /* * 2023-09-13 - JCB * I don't like that we're just copying this. * This should be moved to window.cpp. */ etdHelper.etd->grBinds->vkPipelineLayout = pkePipelines.vkPipelineLayout_Texture; etdHelper.etd->grBinds->graphicsPipeline = pkePipelines.pipelines.Texture; // handle texture EntityType_LoadTexture(helper, i); //handle mesh EntityType_LoadMesh(helper, i); } // TODO DeviceMemory // cleanup AM_Release(modelBinHandle); AM_Release(assetHandle); Pke_EndTransientBucket(helper.bkt); } void EntityType_Unload(EntityType &et, CompGrBinds *grBindsArr[1]) { if (et.modelAssetKey[0] == '\0') return; et.modelAssetKey[0] = '\0'; for (long k = 0; k < et.detailsCount; ++k) { EntityTypeDetails &etd = et.details[k]; auto *grBinds = grBindsArr[k]; if (grBinds != nullptr) { if (grBinds->vkDescriptorSets != nullptr && etd.vkDescriptorPool != VK_NULL_HANDLE) { // 2023-09-27 - JCB // We are not setting the pool flag for allowing freeing descriptor sets // so all we need to do is destroy the pool // If we switch to a global pool, we will need to free here, and // destroy the pool outside of this loop vkDestroyDescriptorPool(vkDevice, etd.vkDescriptorPool, vkAllocator); grBinds->vkDescriptorSets = CAFE_BABE(VkDescriptorSet); } if (grBinds->vertexBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->vertexBuffer, vkAllocator); grBinds->vertexBuffer = VK_NULL_HANDLE; grBinds->vertexFirstBinding = 0; grBinds->vertexBindingCount = 0; grBinds->vertexOffsets = 0; if (grBinds->normalsBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->normalsBuffer, vkAllocator); grBinds->normalsBuffer = VK_NULL_HANDLE; grBinds->normalsFirstBinding = 0; grBinds->normalsBindingCount = 0; grBinds->normalsOffsets = 0; if (grBinds->uvBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->uvBuffer, vkAllocator); grBinds->uvBuffer = VK_NULL_HANDLE; grBinds->uvFirstBinding = 0; grBinds->uvBindingCount = 0; grBinds->uvOffsets = 0; if (grBinds->indexBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->indexBuffer, vkAllocator); grBinds->indexBuffer = VK_NULL_HANDLE; grBinds->indexBindingCount = 0; grBinds->indexOffsets = 0; grBinds->indexCount = 0; if (grBinds->physVertBD.buffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->physVertBD.buffer, vkAllocator); grBinds->physVertBD.buffer = VK_NULL_HANDLE; grBinds->physVertBD.firstBinding = 0; grBinds->physVertBD.bindingCount = 0; grBinds->physVertBD.offsets[0] = 0; if (grBinds->physNormBD.buffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->physNormBD.buffer, vkAllocator); grBinds->physNormBD.buffer = VK_NULL_HANDLE; grBinds->physNormBD.firstBinding = 0; grBinds->physNormBD.bindingCount = 0; grBinds->physNormBD.offsets[0] = 0; if (grBinds->physUvBD.buffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->physUvBD.buffer, vkAllocator); grBinds->physUvBD.buffer = VK_NULL_HANDLE; grBinds->physUvBD.firstBinding = 0; grBinds->physUvBD.bindingCount = 0; grBinds->physUvBD.offsets[0] = 0; if (grBinds->physIndxBD.buffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->physIndxBD.buffer, vkAllocator); grBinds->physIndxBD.buffer = VK_NULL_HANDLE; grBinds->physIndxBD.firstBinding = 0; grBinds->physIndxBD.bindingCount = 0; grBinds->physIndxBD.offsets[0] = 0; if (grBinds->instanceBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->instanceBuffer, vkAllocator); grBinds->instanceBuffer = VK_NULL_HANDLE; grBinds->instanceFirstBinding = 0; grBinds->instanceBindingCount = 0; grBinds->instanceCounter = 0; grBinds->instanceBufferMaxCount = 0; grBinds->instanceOffsets = 0; } if (etd.textureImageView != VK_NULL_HANDLE) vkDestroyImageView(vkDevice, etd.textureImageView, vkAllocator); etd.textureImageView = VK_NULL_HANDLE; if (etd.textureImage != VK_NULL_HANDLE) vkDestroyImage(vkDevice, etd.textureImage, vkAllocator); etd.textureImage = VK_NULL_HANDLE; } if (et.deviceMemoryInst != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et.deviceMemoryInst, vkAllocator); et.deviceMemoryInst = VK_NULL_HANDLE; if (et.deviceMemoryVert != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et.deviceMemoryVert, vkAllocator); et.deviceMemoryVert = VK_NULL_HANDLE; if (et.deviceMemoryPhysVert != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et.deviceMemoryPhysVert, vkAllocator); et.deviceMemoryPhysVert = VK_NULL_HANDLE; if (et.deviceMemoryTexture != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et.deviceMemoryTexture, vkAllocator); et.deviceMemoryTexture = VK_NULL_HANDLE; if (et.entityTypeCode) Pke_Delete(et.entityTypeCode, strlen(et.entityTypeCode)); et.entityTypeCode = CAFE_BABE(char); } void EntityType_Tick(double delta) { const auto count = EntitiesToBeRemoved.Count(); for (long i = 0; i < count; ++i) { auto *entTypePtr = EntityType_FindByEntityHandle(EntitiesToBeRemoved[i]->handle); if (entTypePtr != nullptr) { auto &entType = *entTypePtr; auto &td = EntityTypesToTeardown.Push(); td.handle = EntitiesToBeRemoved[i]->handle; td.ticksToWait = 1; for (long k = 0; k < entType.detailsCount; ++k) { td.grBinds[k] = entType.details[k].grBinds; } } } } void EntityType_Tick_Late(double delta) { while (EntitiesWithExcessInstances.Count() != 0) { auto *entity = EntitiesWithExcessInstances.Pop(); auto *etPtr = EntityType_FindByEntityHandle(entity->handle); assert(etPtr != nullptr); auto &et = *etPtr; for (int64_t i = 0; i < et.detailsCount; ++i) { auto &etd = et.details[i]; assert(etd.grBinds != nullptr); EntityType_RolloverInstances(et, *etd.grBinds); } } for (int64_t i = EntityTypesToTeardown.Count() - 1; i >= 0; --i) { auto &td = EntityTypesToTeardown[i]; td.ticksToWait -= 1; if (td.ticksToWait == 0) { auto *entityType = EntityType_FindByEntityHandle(td.handle); assert(entityType != nullptr); EntityType_Unload(*entityType, td.grBinds); EntityTypesToTeardown.Remove(i); } } } 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); } PkeHandleBucketIndex_T EntityType_GetBucketCount() { return EntityType_BC.pkeHandle.bucketIndex + 1; } EntityType *EntityType_GetEntityTypes(PkeHandleBucketIndex_T bucketIndex, PkeHandleItemIndex_T &itemCount) { assert(bucketIndex <= EntityType_BC.pkeHandle.bucketIndex); if (bucketIndex == EntityType_BC.pkeHandle.bucketIndex) { itemCount = EntityType_BC.pkeHandle.itemIndex; } else { itemCount = EntityType_BC.limits.itemIndex; } return EntityType_BC.buckets[bucketIndex]; } void EntityType_Teardown() { for (PkeHandleBucketIndex_T b = 0; b <= EntityType_BC.pkeHandle.bucketIndex; ++b) { auto &bkt = EntityType_BC.buckets[b]; long itemCount = EntityType_BC.pkeHandle.bucketIndex == b ? EntityType_BC.pkeHandle.itemIndex : EntityType_BC.limits.itemIndex; for (PkeHandleItemIndex_T i = 0; i < itemCount; ++i) { auto &et = bkt[i]; if (et.modelAssetKey[0] == '\0') continue; CompGrBinds *grBindsArr[EntityTypeDetails_MAX] = {nullptr}; for (long k = 0; k < et.detailsCount; ++k) { const EntityTypeDetails &etd = et.details[k]; grBindsArr[k] = etd.grBinds; } EntityType_Unload(et, grBindsArr); } } Buckets_Destroy(EntityType_BC); EntityTypesToTeardown.~DynArray(); }