#include "entities.hpp" #include "physics.hpp" #include #include DynArray GlobalEntityTypes{16}; void EntityType_Init() { long entityTypeCount = GlobalEntityTypes.Count(); for (long i = 0; i < entityTypeCount; ++i) { EntityType_Load(GlobalEntityTypes[i]); } } int64_t EntityType_FindByTypeCode(const char *typeCode) { for (int64_t i = 0; i < GlobalEntityTypes.Count(); ++i) { if (strcmp(typeCode, GlobalEntityTypes[i].entityTypeCode) == 0) { return i; } } return -1; } int64_t EntityType_FindByEntityHandle(EntityHandle handle) { for (int64_t i = 0; i < GlobalEntityTypes.Count(); ++i) { if (GlobalEntityTypes[i].entityHandle == handle) { return i; } } return -1; } void EntityType_Load(EntityType &et) { assert(et.startingInstanceCount > 0); if (et.modelFile != nullptr && et.modelFile != CAFE_BABE(char)) { char modelPath[128]; memset(modelPath, '\0', 128); snprintf(modelPath, 128, "%s/%s", et.modelsDir, et.modelFile); AssetHandle assetHandle{AM_Register(modelPath)}; const Asset *asset = AM_Get(assetHandle); CompGrBinds &grBinds = ECS_CreateGrBinds(et.entityHandle); /* * 2023-09-13 - JCB * I don't like that we're just copying this. * This should be moved to window.cpp. */ grBinds.vkPipelineLayout = pkePipelines.vkPipelineLayout_Texture; grBinds.graphicsPipeline = pkePipelines.pipelines.Texture; et.grBindsHandle = grBinds.grBindsHandle; 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_load_buffers(&options, gltfData, modelPath); assert(result == cgltf_result_success); result = cgltf_validate(gltfData); assert(result == cgltf_result_success); assert(gltfData->images_count < 2); if (gltfData->images_count == 1) { char imagePath[128]; memset(imagePath, '\0', 128); snprintf(imagePath, 128, "%s/%s", et.modelsDir, gltfData->images[0].uri); int pixelWidth, pixelHeight, pixelChannels; auto *pixels = stbi_load(imagePath, &pixelWidth, &pixelHeight, &pixelChannels, STBI_rgb_alpha); assert(pixels != nullptr && "sbti_load failed to load image."); 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, &et.textureImage); VkMemoryRequirements imageMemReqs; vkGetImageMemoryRequirements(vkDevice, et.textureImage, &imageMemReqs); VkMemoryAllocateInfo imageAllocInfo; imageAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; imageAllocInfo.pNext = nullptr; imageAllocInfo.allocationSize = imageMemReqs.size; imageAllocInfo.memoryTypeIndex = FindMemoryTypeIndex(imageMemReqs.memoryTypeBits, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); if (imageAllocInfo.memoryTypeIndex == 0) { imageAllocInfo.memoryTypeIndex = FindMemoryTypeIndex(imageMemReqs.memoryTypeBits, 0); } vkAllocateMemory(vkDevice, &imageAllocInfo, vkAllocator, &et.deviceMemoryTexture); vkBindImageMemory(vkDevice, et.textureImage, et.deviceMemoryTexture, 0); VkImageViewCreateInfo vkImageViewCreateInfo; vkImageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; vkImageViewCreateInfo.pNext = nullptr; vkImageViewCreateInfo.flags = 0; vkImageViewCreateInfo.image = et.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, &et.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 = et.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, et.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 = et.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); } stbi_image_free(pixels); // 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, &et.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 = et.vkDescriptorPool; vkDescriptorSetAllocateInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT; vkDescriptorSetAllocateInfo.pSetLayouts = descriptorSets; grBinds.vkDescriptorSets = Pke_New(MAX_FRAMES_IN_FLIGHT); for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { grBinds.vkDescriptorSets[i] = VkDescriptorSet{}; } vkResult = vkAllocateDescriptorSets(vkDevice, &vkDescriptorSetAllocateInfo, 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 = et.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 = grBinds.vkDescriptorSets[i]; writeDescriptorSets[samplerIndex].pImageInfo = &textureDescriptorInfo; writeDescriptorSets[samplerIndex].dstSet = grBinds.vkDescriptorSets[i]; } vkUpdateDescriptorSets(vkDevice, 2 * MAX_FRAMES_IN_FLIGHT, writeDescriptorSets, 0, nullptr); } // 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); assert(et.Importer_GLTF.AccessorIndexNormal > -1); assert(et.Importer_GLTF.AccessorIndexUV > -1); assert(et.Importer_GLTF.AccessorIndexIndex > -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; const long expectedBufferCount = 4; VkMemoryRequirements vkMemoryRequirements[expectedBufferCount]; long index = 0; // vertex assert(et.Importer_GLTF.AccessorIndexVertex > -1); const auto &accVert = gltfData->accessors[et.Importer_GLTF.AccessorIndexVertex]; grBinds.vertexFirstBinding = index; grBinds.vertexBindingCount = 1; bufferCI.size = accVert.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[index]); index += 1; // normals assert(et.Importer_GLTF.AccessorIndexNormal > -1); const auto &accNorm = gltfData->accessors[et.Importer_GLTF.AccessorIndexNormal]; grBinds.normalsFirstBinding = index; grBinds.normalsBindingCount = 1; bufferCI.size = accNorm.buffer_view->size; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.normalsBuffer); vkGetBufferMemoryRequirements(vkDevice, grBinds.normalsBuffer, &vkMemoryRequirements[index]); index += 1; // uv assert(et.Importer_GLTF.AccessorIndexUV > -1); const auto &accUV = gltfData->accessors[et.Importer_GLTF.AccessorIndexUV]; grBinds.uvFirstBinding = index; grBinds.uvBindingCount = 1; bufferCI.size = accUV.buffer_view->size; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.uvBuffer); vkGetBufferMemoryRequirements(vkDevice, grBinds.uvBuffer, &vkMemoryRequirements[index]); index += 1; // 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. // index assert(et.Importer_GLTF.AccessorIndexIndex > -1); const auto &accIndex = gltfData->accessors[et.Importer_GLTF.AccessorIndexIndex]; grBinds.indexBindingCount = 1; grBinds.indexCount = accIndex.count; bufferCI.size = accIndex.buffer_view->size; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.indexBuffer); vkGetBufferMemoryRequirements(vkDevice, grBinds.indexBuffer, &vkMemoryRequirements[index]); // index += 1; vkDestroyBuffer(vkDevice, grBinds.indexBuffer, vkAllocator); vkDestroyBuffer(vkDevice, grBinds.uvBuffer, vkAllocator); vkDestroyBuffer(vkDevice, grBinds.normalsBuffer, vkAllocator); vkDestroyBuffer(vkDevice, grBinds.vertexBuffer, vkAllocator); VkMemoryRequirements combinedMemReqs{}; combinedMemReqs.alignment = vkMemoryRequirements[0].alignment; combinedMemReqs.memoryTypeBits = 0; combinedMemReqs.size = 0; for (long i = 1; i < expectedBufferCount; ++i) { if (combinedMemReqs.alignment == vkMemoryRequirements[i].alignment) { continue; } int larger, smaller; if (combinedMemReqs.alignment > vkMemoryRequirements[i].alignment) { larger = combinedMemReqs.alignment; smaller = vkMemoryRequirements[i].alignment; } else { larger = vkMemoryRequirements[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 < expectedBufferCount; ++i) { uint32_t alignmentPadding = vkMemoryRequirements[i].size % combinedMemReqs.alignment; combinedMemReqs.size += vkMemoryRequirements[i].size + (alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding); combinedMemReqs.memoryTypeBits |= vkMemoryRequirements[i].memoryTypeBits; } // create VkDeviceMemory VkMemoryAllocateInfo vkMemoryAllocateInfo; vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; vkMemoryAllocateInfo.pNext = nullptr; vkMemoryAllocateInfo.allocationSize = combinedMemReqs.size; vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combinedMemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &et.deviceMemoryVert); // bind buffers uint32_t runningOffset = 0; uint32_t alignmentPadding; // vertex uint32_t offsetVert = runningOffset; uint32_t sizeVert = accVert.buffer_view->size; alignmentPadding = sizeVert % combinedMemReqs.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : combinedMemReqs.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, &grBinds.vertexBuffer); vkBindBufferMemory(vkDevice, grBinds.vertexBuffer, et.deviceMemoryVert, offsetVert); runningOffset += sizeVert; // norm uint32_t offsetNorm = runningOffset; uint32_t sizeNorm = accNorm.buffer_view->size; alignmentPadding = sizeNorm % combinedMemReqs.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding; sizeNorm += alignmentPadding; bufferCI.size = sizeNorm; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.normalsBuffer); vkBindBufferMemory(vkDevice, grBinds.normalsBuffer, et.deviceMemoryVert, offsetNorm); runningOffset += sizeNorm; // uv uint32_t offsetUV = runningOffset; uint32_t sizeUV = accUV.buffer_view->size; alignmentPadding = sizeUV % combinedMemReqs.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding; sizeUV += alignmentPadding; bufferCI.size = sizeUV; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.uvBuffer); vkBindBufferMemory(vkDevice, grBinds.uvBuffer , et.deviceMemoryVert, offsetUV); runningOffset += sizeUV; // index uint32_t offsetIndex = runningOffset; uint32_t sizeIndex = accIndex.buffer_view->size; alignmentPadding = sizeIndex % combinedMemReqs.alignment; alignmentPadding = alignmentPadding == 0 ? 0 : combinedMemReqs.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, &grBinds.indexBuffer); vkBindBufferMemory(vkDevice, grBinds.indexBuffer, et.deviceMemoryVert, offsetIndex); runningOffset += sizeIndex; assert(runningOffset == combinedMemReqs.size); // create transfer items && transfer { VkDeviceMemory transferDeviceMemory; VkBuffer transferBuffer; void *data; BeginTransferBuffer(combinedMemReqs.size, transferBuffer, transferDeviceMemory, data); memset(data, '\0', combinedMemReqs.size); char *dstPtr = nullptr; char *srcPtr = nullptr; dstPtr = static_cast(data) + offsetVert; srcPtr = static_cast(gltfData->buffers[0].data) + accVert.buffer_view->offset; memcpy(dstPtr, srcPtr, accVert.buffer_view->size); dstPtr = static_cast(data) + offsetNorm; srcPtr = static_cast(gltfData->buffers[0].data) + accNorm.buffer_view->offset; memcpy(dstPtr, srcPtr, accNorm.buffer_view->size); dstPtr = static_cast(data) + offsetUV; srcPtr = static_cast(gltfData->buffers[0].data) + accUV.buffer_view->offset; memcpy(dstPtr, srcPtr, accUV.buffer_view->size); dstPtr = static_cast(data) + offsetIndex; srcPtr = static_cast(gltfData->buffers[0].data) + 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, grBinds.vertexBuffer, 1, &bufferCopys[index]); index+=1; bufferCopys[index].srcOffset = offsetNorm; bufferCopys[index].size = sizeNorm; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.normalsBuffer, 1, &bufferCopys[index]); index+=1; bufferCopys[index].srcOffset = offsetUV; bufferCopys[index].size = sizeUV; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.uvBuffer, 1, &bufferCopys[index]); index+=1; bufferCopys[index].srcOffset = offsetIndex; bufferCopys[index].size = sizeIndex; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, 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 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); 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); // bullet { et.bt.shape = Pke_New(MemBkt_Bullet); btScalar *vertDataPointer = reinterpret_cast(accVert.buffer_view->buffer->data); vertDataPointer += accVert.buffer_view->offset; new (et.bt.shape) btConvexHullShape(vertDataPointer, accVert.count, accVert.stride); } // cleanup cgltf_free(gltfData); AM_Destroy(assetHandle); } } 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) { if (GlobalEntityTypes[i].modelFile == nullptr) continue; auto *et = &GlobalEntityTypes[i]; auto *grBinds = ECS_GetGrBinds(GlobalEntityTypes[i].entityHandle); if (grBinds->vkDescriptorSets != nullptr && et->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, et->vkDescriptorPool, vkAllocator); Pke_Delete(grBinds->vkDescriptorSets, MAX_FRAMES_IN_FLIGHT); } 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 (et->textureImageView != VK_NULL_HANDLE) vkDestroyImageView(vkDevice, et->textureImageView, vkAllocator); if (et->textureImage != VK_NULL_HANDLE) vkDestroyImage(vkDevice, et->textureImage, vkAllocator); if (et->deviceMemoryInst != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et->deviceMemoryInst, vkAllocator); if (et->deviceMemoryVert != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et->deviceMemoryVert, vkAllocator); if (et->deviceMemoryTexture != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et->deviceMemoryTexture, vkAllocator); if (et->modelsDir) Pke_Delete(et->modelsDir, strlen(et->modelsDir)); if (et->modelFile) Pke_Delete(et->modelFile, strlen(et->modelFile)); if (et->entityTypeCode) Pke_Delete(et->entityTypeCode, strlen(et->entityTypeCode)); } GlobalEntityTypes.~DynArray(); }