#include "entities.hpp" DynArray globalEntityTypes{16}; VkDescriptorSetLayout vkDescriptorSetLayout_Texture = VK_NULL_HANDLE; VkPipelineLayout vkPipelineLayout_Texture = VK_NULL_HANDLE; VkSampler vkSampler_Texture = VK_NULL_HANDLE; VkPipelineLayoutCreateInfo sharedVkPipelineLayoutCreateInfo { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .setLayoutCount = 0, .pSetLayouts = nullptr, .pushConstantRangeCount = 0, .pPushConstantRanges = nullptr, }; VkWriteDescriptorSet uboDescriptor { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = nullptr, .dstBinding = 0, .dstArrayElement = 0, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .pImageInfo = nullptr, .pBufferInfo = nullptr, .pTexelBufferView = nullptr, }; VkDescriptorImageInfo textureDescriptorInfo { .sampler = nullptr, .imageView = nullptr, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; VkWriteDescriptorSet samplerDescriptor { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = nullptr, .dstBinding = 1, .dstArrayElement = 0, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &textureDescriptorInfo, .pBufferInfo = nullptr, .pTexelBufferView = nullptr, }; void EntityType_Init() { globalEntityTypes.Push( EntityType { .modelsDir = "assets/models", .modelFile = "cube.gltf", .entityTypeCode = "EntTypeCube", .entityHandle = ECS_CreateEntity(), .startingInstanceCount = 16, .Importer_GLTF = { .AccessorIndexVertex = 0, .AccessorIndexNormal = 1, .AccessorIndexUV = 2, .AccessorIndexIndex = 3, } } ); VkDescriptorSetLayoutBinding vkDescriptorSetLayoutBindings[2]; for (long i = 0; i < 2; ++i) { vkDescriptorSetLayoutBindings[i].pImmutableSamplers = nullptr; } vkDescriptorSetLayoutBindings[0].binding = 0; vkDescriptorSetLayoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; vkDescriptorSetLayoutBindings[0].descriptorCount = 1; vkDescriptorSetLayoutBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; vkDescriptorSetLayoutBindings[1].binding = 1; vkDescriptorSetLayoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; vkDescriptorSetLayoutBindings[1].descriptorCount = 1; vkDescriptorSetLayoutBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; VkDescriptorSetLayoutCreateInfo vkDescriptorSetLayoutCreateInfo { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .bindingCount = 2, .pBindings = vkDescriptorSetLayoutBindings, }; vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &vkDescriptorSetLayout_Texture); VkPipelineLayoutCreateInfo vkPipelineLayoutCreateInfo { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .setLayoutCount = 1, .pSetLayouts = &vkDescriptorSetLayout_Texture, .pushConstantRangeCount = 0, .pPushConstantRanges = nullptr, }; vkCreatePipelineLayout(vkDevice, &vkPipelineLayoutCreateInfo, vkAllocator, &vkPipelineLayout_Texture); VkSamplerCreateInfo vkSamplerCreateInfo; vkSamplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; vkSamplerCreateInfo.pNext = nullptr; vkSamplerCreateInfo.flags = 0; vkSamplerCreateInfo.magFilter = VK_FILTER_NEAREST; vkSamplerCreateInfo.minFilter = VK_FILTER_NEAREST; vkSamplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; vkSamplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; vkSamplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; vkSamplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; vkSamplerCreateInfo.mipLodBias = 0.0f; vkSamplerCreateInfo.anisotropyEnable = VK_TRUE; vkSamplerCreateInfo.maxAnisotropy = vkPhysicalDeviceProperties.limits.maxSamplerAnisotropy; vkSamplerCreateInfo.compareEnable = VK_FALSE; vkSamplerCreateInfo.compareOp = VK_COMPARE_OP_ALWAYS; vkSamplerCreateInfo.minLod = 0.0f; // TODO MipMap vkSamplerCreateInfo.maxLod = 1; vkSamplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; vkSamplerCreateInfo.unnormalizedCoordinates = VK_FALSE; vkCreateSampler(vkDevice, &vkSamplerCreateInfo, vkAllocator, &vkSampler_Texture); 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.vkDescriptorSetLayoutCreateInfo != nullptr && et.vkDescriptorSetLayoutCreateInfo != CAFE_BABE(VkDescriptorSetLayoutCreateInfo) && "EntityType with a defined model must also contain appropriate Vulkan CreateInfos"); // assert(et.vkPipelineLayoutCreateInfo != nullptr && et.vkPipelineLayoutCreateInfo != CAFE_BABE(VkPipelineLayoutCreateInfo) && "EntityType with a defined model must also contain appropriate Vulkan CreateInfos"); 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 = vkPipelineLayout_Texture; // et.textureSampler = vkPipelineLayout_Texture; // VkResult vkResult = vkCreateDescriptorSetLayout(vkDevice, et.vkDescriptorSetLayoutCreateInfo, vkAllocator, &grBinds.vkDescriptorSetLayout); // assert(vkResult == VK_SUCCESS); // vkResult = vkCreatePipelineLayout(vkDevice, et.vkPipelineLayoutCreateInfo, vkAllocator, &grBinds.vkPipelineLayout); // assert(vkResult == VK_SUCCESS); 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, modelPath); assert(result == cgltf_result_success); result = cgltf_validate(gltfData); assert(result == cgltf_result_success); assert(gltfData->images_count < 2); // AssetHandle textureAssetHandle = AssetHandle_MAX; 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; AssetHandle textureAssetHandle{AM_Register(pixels, imageSizeBytes, imagePath)}; const Asset *textureAsset = AM_Get(textureAssetHandle); 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); 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, gltfData->buffers[0].data, gltfData->buffers[0].size); { 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); } // 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, &et.deviceMemoryVert); // bind buffers uint32_t runningOffset = 0; 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, et.deviceMemoryVert, runningOffset); runningOffset += acc.buffer_view->size; } 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, et.deviceMemoryVert, runningOffset); runningOffset += acc.buffer_view->size; } 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 , et.deviceMemoryVert, runningOffset); runningOffset += acc.buffer_view->size; } 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, et.deviceMemoryVert, runningOffset); } // 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, vkMemoryRequirements.size, 0, &data); // memcpy(data, gltfData->buffers[0].data, vkMemoryRequirements.size); uint32_t runningOffset2 = 0; if (et.Importer_GLTF.AccessorIndexVertex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexVertex]; char *dstPtr = static_cast(data) + runningOffset2; char *srcPtr = static_cast(gltfData->buffers[0].data) + acc.buffer_view->offset; memcpy(dstPtr, srcPtr, acc.buffer_view->size); runningOffset2 += acc.buffer_view->size; } if (et.Importer_GLTF.AccessorIndexNormal > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexNormal]; char *dstPtr = static_cast(data) + runningOffset2; char *srcPtr = static_cast(gltfData->buffers[0].data) + acc.buffer_view->offset; memcpy(dstPtr, srcPtr, acc.buffer_view->size); runningOffset2 += acc.buffer_view->size; } if (et.Importer_GLTF.AccessorIndexUV > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexUV]; char *dstPtr = static_cast(data) + runningOffset2; char *srcPtr = static_cast(gltfData->buffers[0].data) + acc.buffer_view->offset; memcpy(dstPtr, srcPtr, acc.buffer_view->size); runningOffset2 += acc.buffer_view->size; } if (et.Importer_GLTF.AccessorIndexIndex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexIndex]; char *dstPtr = static_cast(data) + runningOffset2; char *srcPtr = static_cast(gltfData->buffers[0].data) + acc.buffer_view->offset; memcpy(dstPtr, srcPtr, acc.buffer_view->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, &et.deviceMemoryInst); vkBindBufferMemory(vkDevice, grBinds.instanceBuffer, et.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 *et = &globalEntityTypes[i]; auto *grBinds = ECS_GetGrBinds(globalEntityTypes[i].entityHandle); 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 (vkSampler_Texture != VK_NULL_HANDLE) vkDestroySampler(vkDevice, vkSampler_Texture, vkAllocator); if (vkPipelineLayout_Texture != VK_NULL_HANDLE) vkDestroyPipelineLayout(vkDevice, vkPipelineLayout_Texture, vkAllocator); if (vkDescriptorSetLayout_Texture != VK_NULL_HANDLE) vkDestroyDescriptorSetLayout(vkDevice, vkDescriptorSetLayout_Texture, vkAllocator); }