#include void DescriptorLayoutBuilder::add_binding(uint32_t binding, VkDescriptorType type) { VkDescriptorSetLayoutBinding newbind{}; newbind.binding = binding; newbind.descriptorCount = 1; newbind.descriptorType = type; bindings.push_back(newbind); } void DescriptorLayoutBuilder::clear() { bindings.clear(); } VkDescriptorSetLayout DescriptorLayoutBuilder::build(VkDevice device, VkShaderStageFlags shaderStages, void *pNext, VkDescriptorSetLayoutCreateFlags flags) { for (auto &b: bindings) { b.stageFlags |= shaderStages; } VkDescriptorSetLayoutCreateInfo info = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; info.pNext = pNext; info.pBindings = bindings.data(); info.bindingCount = (uint32_t) bindings.size(); info.flags = flags; VkDescriptorSetLayout set; VK_CHECK(vkCreateDescriptorSetLayout(device, &info, nullptr, &set)); return set; } void DescriptorWriter::write_buffer(int binding, VkBuffer buffer, size_t size, size_t offset, VkDescriptorType type) { VkDescriptorBufferInfo &info = bufferInfos.emplace_back(VkDescriptorBufferInfo{ .buffer = buffer, .offset = offset, .range = size }); VkWriteDescriptorSet write = {.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; write.dstBinding = binding; write.dstSet = VK_NULL_HANDLE; //left empty for now until we need to write it write.descriptorCount = 1; write.descriptorType = type; write.pBufferInfo = &info; writes.push_back(write); } void DescriptorWriter::write_image(int binding, VkImageView image, VkSampler sampler, VkImageLayout layout, VkDescriptorType type) { VkDescriptorImageInfo &info = imageInfos.emplace_back(VkDescriptorImageInfo{ .sampler = sampler, .imageView = image, .imageLayout = layout }); VkWriteDescriptorSet write = {.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; write.dstBinding = binding; write.dstSet = VK_NULL_HANDLE; //left empty for now until we need to write it write.descriptorCount = 1; write.descriptorType = type; write.pImageInfo = &info; writes.push_back(write); } void DescriptorWriter::clear() { imageInfos.clear(); writes.clear(); bufferInfos.clear(); } void DescriptorWriter::update_set(VkDevice device, VkDescriptorSet set) { for (VkWriteDescriptorSet& write : writes) { write.dstSet = set; } vkUpdateDescriptorSets(device, (uint32_t)writes.size(), writes.data(), 0, nullptr); } void DescriptorAllocator::init_pool(VkDevice device, uint32_t maxSets, std::span poolRatios) { std::vector poolSizes; for (PoolSizeRatio ratio: poolRatios) { poolSizes.push_back(VkDescriptorPoolSize{ .type = ratio.type, .descriptorCount = uint32_t(ratio.ratio * maxSets) }); } VkDescriptorPoolCreateInfo pool_info = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; pool_info.flags = 0; pool_info.maxSets = maxSets; pool_info.poolSizeCount = (uint32_t) poolSizes.size(); pool_info.pPoolSizes = poolSizes.data(); vkCreateDescriptorPool(device, &pool_info, nullptr, &pool); } void DescriptorAllocator::clear_descriptors(VkDevice device) { vkResetDescriptorPool(device, pool, 0); } void DescriptorAllocator::destroy_pool(VkDevice device) { vkDestroyDescriptorPool(device, pool, nullptr); } VkDescriptorSet DescriptorAllocator::allocate(VkDevice device, VkDescriptorSetLayout layout) { VkDescriptorSetAllocateInfo allocInfo = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; allocInfo.pNext = nullptr; allocInfo.descriptorPool = pool; allocInfo.descriptorSetCount = 1; allocInfo.pSetLayouts = &layout; VkDescriptorSet ds; VK_CHECK(vkAllocateDescriptorSets(device, &allocInfo, &ds)); return ds; } VkDescriptorPool DescriptorAllocatorGrowable::get_pool(VkDevice device) { VkDescriptorPool newPool; if (readyPools.size() != 0) { newPool = readyPools.back(); readyPools.pop_back(); } else { //need to create a new pool newPool = create_pool(device, setsPerPool, ratios); setsPerPool = setsPerPool * 1.5; if (setsPerPool > 4092) { setsPerPool = 4092; } } return newPool; } VkDescriptorPool DescriptorAllocatorGrowable::create_pool(VkDevice device, uint32_t setCount, std::span poolRatios) { std::vector poolSizes; for (PoolSizeRatio ratio: poolRatios) { poolSizes.push_back(VkDescriptorPoolSize{ .type = ratio.type, .descriptorCount = uint32_t(ratio.ratio * setCount) }); } VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = 0; pool_info.maxSets = setCount; pool_info.poolSizeCount = (uint32_t) poolSizes.size(); pool_info.pPoolSizes = poolSizes.data(); VkDescriptorPool newPool; vkCreateDescriptorPool(device, &pool_info, nullptr, &newPool); return newPool; } void DescriptorAllocatorGrowable::init(VkDevice device, uint32_t maxSets, std::span poolRatios) { ratios.clear(); for (auto r: poolRatios) { ratios.push_back(r); } VkDescriptorPool newPool = create_pool(device, maxSets, poolRatios); setsPerPool = maxSets * 1.5; //grow it next allocation readyPools.push_back(newPool); } void DescriptorAllocatorGrowable::clear_pools(VkDevice device) { for (auto p: readyPools) { vkResetDescriptorPool(device, p, 0); } for (auto p: fullPools) { vkResetDescriptorPool(device, p, 0); readyPools.push_back(p); } fullPools.clear(); } void DescriptorAllocatorGrowable::destroy_pools(VkDevice device) { for (auto p: readyPools) { vkDestroyDescriptorPool(device, p, nullptr); } readyPools.clear(); for (auto p: fullPools) { vkDestroyDescriptorPool(device, p, nullptr); } fullPools.clear(); } VkDescriptorSet DescriptorAllocatorGrowable::allocate(VkDevice device, VkDescriptorSetLayout layout, void *pNext) { //get or create a pool to allocate from VkDescriptorPool poolToUse = get_pool(device); VkDescriptorSetAllocateInfo allocInfo = {}; allocInfo.pNext = pNext; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.descriptorPool = poolToUse; allocInfo.descriptorSetCount = 1; allocInfo.pSetLayouts = &layout; VkDescriptorSet ds; VkResult result = vkAllocateDescriptorSets(device, &allocInfo, &ds); //allocation failed. Try again if (result == VK_ERROR_OUT_OF_POOL_MEMORY || result == VK_ERROR_FRAGMENTED_POOL) { fullPools.push_back(poolToUse); poolToUse = get_pool(device); allocInfo.descriptorPool = poolToUse; VK_CHECK(vkAllocateDescriptorSets(device, &allocInfo, &ds)); } readyPools.push_back(poolToUse); return ds; }