#include "entities.hpp" DynArray GlobalEntityTypes{16}; VkDescriptorSetLayout vkDescriptorSetLayout_Texture = VK_NULL_HANDLE; VkPipelineLayout vkPipelineLayout_Texture = VK_NULL_HANDLE; VkSampler vkSampler_Texture = VK_NULL_HANDLE; struct ImplementedPipelines { union { VkPipeline pipelines[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; struct { VkPipeline Texture; VkPipeline TextureWireframe; }; }; } vkPipelines; void EntityType_Init() { 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); // pipelines { const long vertexBindingCount = 4; long index = 0; VkVertexInputBindingDescription vertInputBD[vertexBindingCount]; // model vertex vertInputBD[index].binding = index; vertInputBD[index].stride = sizeof(glm::vec3); vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; index += 1; // model normals vertInputBD[index].binding = index; vertInputBD[index].stride = sizeof(glm::vec3); vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; index += 1; // model UV vertInputBD[index].binding = index; vertInputBD[index].stride = sizeof(glm::vec2); vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; index += 1; // model index // vertInputBD[index].binding = index; // vertInputBD[index].stride = sizeof(uint16_t); // vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; // index += 1; // instance vertInputBD[index].binding = index; vertInputBD[index].stride = sizeof(glm::mat4); vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; const long vertexAttrDescCount = 7; index = 0; VkVertexInputAttributeDescription vertAttrDesc[vertexAttrDescCount]; for (long i = 0; i < vertexAttrDescCount; ++i) { vertAttrDesc[i].location = i; } // model vertex vertAttrDesc[index].binding = 0; vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; vertAttrDesc[index].offset = 0; index += 1; // model normals vertAttrDesc[index].binding = 1; vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; vertAttrDesc[index].offset = 0; index += 1; // model UV vertAttrDesc[index].binding = 2; vertAttrDesc[index].format = VK_FORMAT_R32G32_SFLOAT; vertAttrDesc[index].offset = 0; index += 1; // instPosRotScale for (long i = 0; i < 4; ++i) { vertAttrDesc[index].binding = 3; vertAttrDesc[index].format = VK_FORMAT_R32G32B32A32_SFLOAT; vertAttrDesc[index].offset = sizeof(glm::vec4) * i; index += 1; } // instance texture index // vertAttrDesc[index].binding = 3; // vertAttrDesc[index].format = VK_FORMAT_R32_SFLOAT; // vertAttrDesc[index].offset = runningOffset; // runningOffset += sizeof(float); // index += 1; VkPipelineVertexInputStateCreateInfo vkPipelineVertexInputStateCreateInfo; vkPipelineVertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vkPipelineVertexInputStateCreateInfo.pNext = nullptr; vkPipelineVertexInputStateCreateInfo.flags = {}; vkPipelineVertexInputStateCreateInfo.vertexBindingDescriptionCount = vertexBindingCount; vkPipelineVertexInputStateCreateInfo.pVertexBindingDescriptions = vertInputBD; vkPipelineVertexInputStateCreateInfo.vertexAttributeDescriptionCount = vertexAttrDescCount; vkPipelineVertexInputStateCreateInfo.pVertexAttributeDescriptions = vertAttrDesc; VkPipelineInputAssemblyStateCreateInfo vkPipelineInputAssemblyStateCreateInfo; vkPipelineInputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; vkPipelineInputAssemblyStateCreateInfo.pNext = nullptr; vkPipelineInputAssemblyStateCreateInfo.flags = {}; vkPipelineInputAssemblyStateCreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; vkPipelineInputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; // TODO - is this right? set to dynamic later VkPipelineViewportStateCreateInfo vkPipelineViewportStateCreateInfo; vkPipelineViewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; vkPipelineViewportStateCreateInfo.pNext = nullptr; vkPipelineViewportStateCreateInfo.flags = {}; vkPipelineViewportStateCreateInfo.viewportCount = 1; vkPipelineViewportStateCreateInfo.pViewports = nullptr; vkPipelineViewportStateCreateInfo.scissorCount = 1; vkPipelineViewportStateCreateInfo.pScissors = nullptr; VkPipelineRasterizationStateCreateInfo vkPipelineRasterizationStateCreateInfoFill; vkPipelineRasterizationStateCreateInfoFill.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; vkPipelineRasterizationStateCreateInfoFill.pNext = nullptr; vkPipelineRasterizationStateCreateInfoFill.flags = {}; vkPipelineRasterizationStateCreateInfoFill.depthClampEnable = VK_FALSE; vkPipelineRasterizationStateCreateInfoFill.rasterizerDiscardEnable = VK_FALSE; vkPipelineRasterizationStateCreateInfoFill.polygonMode = VK_POLYGON_MODE_FILL; vkPipelineRasterizationStateCreateInfoFill.cullMode = VK_CULL_MODE_BACK_BIT; vkPipelineRasterizationStateCreateInfoFill.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; vkPipelineRasterizationStateCreateInfoFill.depthBiasEnable = VK_FALSE; vkPipelineRasterizationStateCreateInfoFill.depthBiasConstantFactor = 0.0f; vkPipelineRasterizationStateCreateInfoFill.depthBiasClamp = 0.0f; vkPipelineRasterizationStateCreateInfoFill.depthBiasSlopeFactor = 0.0f; vkPipelineRasterizationStateCreateInfoFill.lineWidth = 1.0f; VkPipelineRasterizationStateCreateInfo vkPipelineRasterizationStateCreateInfoLine{vkPipelineRasterizationStateCreateInfoFill}; vkPipelineRasterizationStateCreateInfoLine.polygonMode = VK_POLYGON_MODE_LINE; VkPipelineMultisampleStateCreateInfo vkPipelineMultisampleStateCreateInfo; vkPipelineMultisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; vkPipelineMultisampleStateCreateInfo.pNext = nullptr; vkPipelineMultisampleStateCreateInfo.flags = 0; vkPipelineMultisampleStateCreateInfo.rasterizationSamples = renderSampleCount; vkPipelineMultisampleStateCreateInfo.sampleShadingEnable = VK_FALSE; vkPipelineMultisampleStateCreateInfo.minSampleShading = 0.0f; vkPipelineMultisampleStateCreateInfo.pSampleMask = nullptr; vkPipelineMultisampleStateCreateInfo.alphaToCoverageEnable = VK_FALSE; vkPipelineMultisampleStateCreateInfo.alphaToOneEnable = VK_FALSE; // TODO Transparency VkPipelineColorBlendAttachmentState vkPipelineColorBlendAttachmentState[1]; vkPipelineColorBlendAttachmentState[0].blendEnable = VK_FALSE; vkPipelineColorBlendAttachmentState[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; vkPipelineColorBlendAttachmentState[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; vkPipelineColorBlendAttachmentState[0].colorBlendOp = VK_BLEND_OP_ADD; vkPipelineColorBlendAttachmentState[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; vkPipelineColorBlendAttachmentState[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; vkPipelineColorBlendAttachmentState[0].alphaBlendOp = VK_BLEND_OP_SUBTRACT; vkPipelineColorBlendAttachmentState[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VkPipelineColorBlendStateCreateInfo vkPipelineColorBlendStateCreateInfo; vkPipelineColorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; vkPipelineColorBlendStateCreateInfo.pNext = nullptr; vkPipelineColorBlendStateCreateInfo.flags = {}; vkPipelineColorBlendStateCreateInfo.logicOpEnable = VK_FALSE; vkPipelineColorBlendStateCreateInfo.logicOp = VK_LOGIC_OP_COPY; vkPipelineColorBlendStateCreateInfo.attachmentCount = 1; vkPipelineColorBlendStateCreateInfo.pAttachments = vkPipelineColorBlendAttachmentState; vkPipelineColorBlendStateCreateInfo.blendConstants[0] = 0.0f; vkPipelineColorBlendStateCreateInfo.blendConstants[1] = 0.0f; vkPipelineColorBlendStateCreateInfo.blendConstants[2] = 0.0f; vkPipelineColorBlendStateCreateInfo.blendConstants[3] = 0.0f; VkDynamicState dynamicStates[2] = { VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_VIEWPORT }; VkPipelineDynamicStateCreateInfo vkPipelineDynamicStateCreateInfo; vkPipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; vkPipelineDynamicStateCreateInfo.pNext = nullptr; vkPipelineDynamicStateCreateInfo.flags = {}; vkPipelineDynamicStateCreateInfo.dynamicStateCount = 2; vkPipelineDynamicStateCreateInfo.pDynamicStates = dynamicStates; VkPipelineDepthStencilStateCreateInfo vkPipelineDepthStencilStateCreateInfo; vkPipelineDepthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; vkPipelineDepthStencilStateCreateInfo.pNext = nullptr; vkPipelineDepthStencilStateCreateInfo.flags = {}; vkPipelineDepthStencilStateCreateInfo.depthTestEnable = VK_TRUE; vkPipelineDepthStencilStateCreateInfo.depthWriteEnable = VK_TRUE; vkPipelineDepthStencilStateCreateInfo.depthCompareOp = VK_COMPARE_OP_LESS; vkPipelineDepthStencilStateCreateInfo.depthBoundsTestEnable = VK_FALSE; vkPipelineDepthStencilStateCreateInfo.stencilTestEnable = VK_FALSE; vkPipelineDepthStencilStateCreateInfo.front = {}; vkPipelineDepthStencilStateCreateInfo.back = {}; vkPipelineDepthStencilStateCreateInfo.minDepthBounds = {}; vkPipelineDepthStencilStateCreateInfo.maxDepthBounds = {}; AssetHandle vertShaderAssetHandle = AM_Register("assets/shaders/vert.vert.spv"); AssetHandle textureFragShaderAssetHandle = AM_Register("assets/shaders/texture.frag.spv"); const Asset *vertShaderAsset = AM_Get(vertShaderAssetHandle); const Asset *fragShaderAsset = AM_Get(textureFragShaderAssetHandle); VkShaderModuleCreateInfo vkShaderModuleCreateInfo[2]; vkShaderModuleCreateInfo[0].codeSize = vertShaderAsset->size; vkShaderModuleCreateInfo[0].pCode = reinterpret_cast(vertShaderAsset->ptr); vkShaderModuleCreateInfo[1].codeSize = fragShaderAsset->size; vkShaderModuleCreateInfo[1].pCode = reinterpret_cast(fragShaderAsset->ptr); VkShaderModule shaderModules[2]; VkPipelineShaderStageCreateInfo vkPipelineShaderStageCreateInfo[2]; for (long i = 0; i < 2; ++i) { vkShaderModuleCreateInfo[i].sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vkShaderModuleCreateInfo[i].pNext = nullptr; vkShaderModuleCreateInfo[i].flags = {}; vkPipelineShaderStageCreateInfo[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vkPipelineShaderStageCreateInfo[i].pNext = nullptr; vkPipelineShaderStageCreateInfo[i].flags = {}; vkPipelineShaderStageCreateInfo[i].pName = "main"; vkPipelineShaderStageCreateInfo[i].pSpecializationInfo = nullptr; vkCreateShaderModule(vkDevice, &vkShaderModuleCreateInfo[i], vkAllocator, &shaderModules[i]); } vkPipelineShaderStageCreateInfo[0].module = shaderModules[0]; vkPipelineShaderStageCreateInfo[1].module = shaderModules[1]; vkPipelineShaderStageCreateInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT; vkPipelineShaderStageCreateInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; VkGraphicsPipelineCreateInfo vkGraphicsPipelineCreateInfo[2]; for (long i = 0; i < 2; ++i) { vkGraphicsPipelineCreateInfo[i].sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; vkGraphicsPipelineCreateInfo[i].pNext = nullptr; vkGraphicsPipelineCreateInfo[i].flags = {}; vkGraphicsPipelineCreateInfo[i].stageCount = 2; vkGraphicsPipelineCreateInfo[i].pStages = vkPipelineShaderStageCreateInfo; vkGraphicsPipelineCreateInfo[i].pVertexInputState = &vkPipelineVertexInputStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pInputAssemblyState = &vkPipelineInputAssemblyStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pTessellationState = nullptr; vkGraphicsPipelineCreateInfo[i].pViewportState = &vkPipelineViewportStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pMultisampleState = &vkPipelineMultisampleStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pDepthStencilState = &vkPipelineDepthStencilStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pColorBlendState = &vkPipelineColorBlendStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pDynamicState = &vkPipelineDynamicStateCreateInfo; vkGraphicsPipelineCreateInfo[i].layout = vkPipelineLayout_Texture; vkGraphicsPipelineCreateInfo[i].renderPass = renderRenderPass; vkGraphicsPipelineCreateInfo[i].subpass = 0; vkGraphicsPipelineCreateInfo[i].basePipelineHandle = VK_NULL_HANDLE; vkGraphicsPipelineCreateInfo[i].basePipelineIndex = {}; } vkGraphicsPipelineCreateInfo[0].pRasterizationState = &vkPipelineRasterizationStateCreateInfoFill; vkGraphicsPipelineCreateInfo[1].pRasterizationState = &vkPipelineRasterizationStateCreateInfoLine; vkCreateGraphicsPipelines(vkDevice, VK_NULL_HANDLE, 2, vkGraphicsPipelineCreateInfo, vkAllocator, vkPipelines.pipelines); for (long i = 0; i < 2; ++i) { vkDestroyShaderModule(vkDevice, shaderModules[i], vkAllocator); } AM_Destroy(textureFragShaderAssetHandle); AM_Destroy(vertShaderAssetHandle); } 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; } 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 = vkPipelineLayout_Texture; grBinds.graphicsPipeline = vkPipelines.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] = 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 = 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 bufferCI.size = sizeof(InstPos) * et.startingInstanceCount; bufferCI.usage = 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); // cleanup cgltf_free(gltfData); AM_Destroy(assetHandle); } } 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 (vkSampler_Texture != VK_NULL_HANDLE) vkDestroySampler(vkDevice, vkSampler_Texture, vkAllocator); for (long i = 0; i < 2; ++i) { if (vkPipelines.pipelines[i] != VK_NULL_HANDLE) vkDestroyPipeline(vkDevice, vkPipelines.pipelines[i], vkAllocator); } if (vkPipelineLayout_Texture != VK_NULL_HANDLE) vkDestroyPipelineLayout(vkDevice, vkPipelineLayout_Texture, vkAllocator); if (vkDescriptorSetLayout_Texture != VK_NULL_HANDLE) vkDestroyDescriptorSetLayout(vkDevice, vkDescriptorSetLayout_Texture, vkAllocator); }