mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 16:16:16 +03:00
299 lines
10 KiB
C++
299 lines
10 KiB
C++
#include "rhi.h"
|
|
|
|
namespace engine
|
|
{
|
|
static AutoCVarInt32 cVarRHIBindlessMaxCount(
|
|
"r.RHI.BindlessMaxCount",
|
|
"Bindless set max count.",
|
|
"RHI",
|
|
10000,
|
|
CVarFlags::ReadOnly
|
|
);
|
|
|
|
void BindlessBase::initTemplate(const char* name, VkDescriptorType type, const VulkanContext* inContext, uint32_t maxDeviceLimit)
|
|
{
|
|
m_context = inContext;
|
|
m_name = name;
|
|
m_maxDeviceLimitCount = maxDeviceLimit;
|
|
|
|
// Create bindless binding here.
|
|
VkDescriptorSetLayoutBinding binding{};
|
|
binding.descriptorType = type;
|
|
binding.stageFlags = kCommonShaderStage;
|
|
binding.binding = 0;
|
|
|
|
static uint32_t bindlessMaxCountConfig = (uint32_t)cVarRHIBindlessMaxCount.get();
|
|
// LOG_RHI_TRACE("Config max bindless count is {0}, device limit is {1}.", bindlessMaxCountConfig, maxDeviceLimit);
|
|
|
|
// Set max descriptor sampler count to a big number.
|
|
CHECK(bindlessMaxCountConfig < maxDeviceLimit);
|
|
|
|
binding.descriptorCount = bindlessMaxCountConfig;
|
|
|
|
// One binding.
|
|
VkDescriptorSetLayoutCreateInfo setLayoutCreateInfo{};
|
|
setLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
setLayoutCreateInfo.bindingCount = 1;
|
|
setLayoutCreateInfo.pBindings = &binding;
|
|
setLayoutCreateInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT;
|
|
|
|
const VkDescriptorBindingFlagsEXT flags =
|
|
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT |
|
|
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT |
|
|
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT |
|
|
VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT;
|
|
|
|
VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlags{};
|
|
bindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT;
|
|
bindingFlags.bindingCount = 1;
|
|
bindingFlags.pBindingFlags = &flags;
|
|
setLayoutCreateInfo.pNext = &bindingFlags;
|
|
|
|
RHICheck(vkCreateDescriptorSetLayout(m_context->getDevice(), &setLayoutCreateInfo, nullptr, &m_bindlessDescriptorHeap.setLayout));
|
|
|
|
VkDescriptorPoolSize poolSize{};
|
|
poolSize.type = type;
|
|
poolSize.descriptorCount = bindlessMaxCountConfig;
|
|
|
|
VkDescriptorPoolCreateInfo poolCreateInfo{};
|
|
poolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
poolCreateInfo.poolSizeCount = 1;
|
|
poolCreateInfo.pPoolSizes = &poolSize;
|
|
poolCreateInfo.maxSets = 1;
|
|
poolCreateInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT;
|
|
|
|
RHICheck(vkCreateDescriptorPool(m_context->getDevice(), &poolCreateInfo, nullptr, &m_bindlessDescriptorHeap.descriptorPool));
|
|
|
|
VkDescriptorSetAllocateInfo allocateInfo{};
|
|
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
allocateInfo.descriptorPool = m_bindlessDescriptorHeap.descriptorPool;
|
|
allocateInfo.pSetLayouts = &m_bindlessDescriptorHeap.setLayout;
|
|
allocateInfo.descriptorSetCount = 1;
|
|
|
|
VkDescriptorSetVariableDescriptorCountAllocateInfoEXT variableInfo{};
|
|
variableInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT;
|
|
variableInfo.descriptorSetCount = 1;
|
|
allocateInfo.pNext = &variableInfo;
|
|
|
|
const uint32_t NumDescriptors = bindlessMaxCountConfig;
|
|
variableInfo.pDescriptorCounts = &NumDescriptors;
|
|
RHICheck(vkAllocateDescriptorSets(m_context->getDevice(), &allocateInfo, &m_bindlessDescriptorHeap.descriptorSetUpdateAfterBind));
|
|
|
|
m_context->setResourceName(VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)m_bindlessDescriptorHeap.descriptorSetUpdateAfterBind, m_name);
|
|
m_context->setResourceName(VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t)m_bindlessDescriptorHeap.descriptorPool, m_name);
|
|
m_context->setResourceName(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)m_bindlessDescriptorHeap.setLayout, m_name);
|
|
}
|
|
|
|
uint32_t BindlessBase::getCountAndAndOne()
|
|
{
|
|
std::lock_guard lock(m_bindlessElementCountLock);
|
|
|
|
uint32_t index = 0;
|
|
|
|
static const uint32_t maxRHIBindlessCount = (uint32_t)cVarRHIBindlessMaxCount.get();
|
|
static const auto maxFreeIndexSize = maxRHIBindlessCount / 4;
|
|
if (m_freeIndex.size() < maxFreeIndexSize)
|
|
{
|
|
// No free index, increment.
|
|
index = m_bindlessElementCount;
|
|
m_bindlessElementCount++;
|
|
|
|
if (m_bindlessElementCount >= maxRHIBindlessCount)
|
|
{
|
|
LOG_WARN("Too much item use in this set, current bindless count already reach {0}, and the config max is {1}, the device limit is {2}. ",
|
|
m_bindlessElementCount, maxRHIBindlessCount, m_maxDeviceLimitCount);
|
|
|
|
LOG_WARN("We reset bindless set count now, maybe cause some render error after this.");
|
|
|
|
m_bindlessElementCount = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Exist free index, pop first one.
|
|
index = *m_freeIndex.begin();
|
|
m_freeIndex.erase(m_freeIndex.begin());
|
|
}
|
|
return index;
|
|
}
|
|
|
|
void BindlessBase::freeBindless(uint32_t index)
|
|
{
|
|
std::lock_guard lock(m_bindlessElementCountLock);
|
|
|
|
CHECK(!m_freeIndex.contains(index));
|
|
m_freeIndex.insert(index);
|
|
}
|
|
|
|
VkDescriptorSetLayout BindlessBase::getSetLayout() const
|
|
{
|
|
return m_bindlessDescriptorHeap.setLayout;
|
|
}
|
|
|
|
void BindlessBase::release()
|
|
{
|
|
vkDestroyDescriptorSetLayout(m_context->getDevice(), m_bindlessDescriptorHeap.setLayout, nullptr);
|
|
vkDestroyDescriptorPool(m_context->getDevice(), m_bindlessDescriptorHeap.descriptorPool, nullptr);
|
|
}
|
|
|
|
VkDescriptorSet BindlessBase::getSet() const
|
|
{
|
|
return m_bindlessDescriptorHeap.descriptorSetUpdateAfterBind;
|
|
}
|
|
|
|
void BindlessSampler::init(const char* name, const VulkanContext* context)
|
|
{
|
|
initTemplate(name, VK_DESCRIPTOR_TYPE_SAMPLER, context,
|
|
context->getPhysicalDeviceDescriptorIndexingProperties().maxDescriptorSetUpdateAfterBindSamplers);
|
|
}
|
|
|
|
uint32_t BindlessSampler::updateSamplerToBindlessDescriptorSet(VkSampler in)
|
|
{
|
|
VkDescriptorImageInfo imageInfo{};
|
|
imageInfo.sampler = in;
|
|
imageInfo.imageView = VK_NULL_HANDLE;
|
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
VkWriteDescriptorSet write{};
|
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
write.dstSet = getSet();
|
|
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
|
write.dstBinding = 0;
|
|
write.pImageInfo = &imageInfo;
|
|
write.descriptorCount = 1;
|
|
write.dstArrayElement = getCountAndAndOne();
|
|
|
|
vkUpdateDescriptorSets(m_context->getDevice(), 1, &write, 0, nullptr);
|
|
|
|
return write.dstArrayElement;
|
|
}
|
|
|
|
void BindlessSampler::freeBindlessImpl(uint32_t index, VkSampler fallback)
|
|
{
|
|
if (fallback != VK_NULL_HANDLE)
|
|
{
|
|
VkDescriptorImageInfo imageInfo{};
|
|
imageInfo.sampler = fallback;
|
|
imageInfo.imageView = VK_NULL_HANDLE;
|
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
VkWriteDescriptorSet write{};
|
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
write.dstSet = getSet();
|
|
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
|
write.dstBinding = 0;
|
|
write.pImageInfo = &imageInfo;
|
|
write.descriptorCount = 1;
|
|
write.dstArrayElement = index;
|
|
|
|
vkUpdateDescriptorSets(m_context->getDevice(), 1, &write, 0, nullptr);
|
|
}
|
|
|
|
BindlessBase::freeBindless(index);
|
|
}
|
|
|
|
void BindlessTexture::init(const char* name, const VulkanContext* context)
|
|
{
|
|
initTemplate(name, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, context,
|
|
context->getPhysicalDeviceDescriptorIndexingProperties().maxDescriptorSetUpdateAfterBindSampledImages);
|
|
}
|
|
|
|
uint32_t BindlessTexture::updateTextureToBindlessDescriptorSet(VkImageView view, VkImageLayout layout)
|
|
{
|
|
VkDescriptorImageInfo imageInfo{};
|
|
imageInfo.sampler = VK_NULL_HANDLE;
|
|
|
|
imageInfo.imageView = view;
|
|
imageInfo.imageLayout = layout;
|
|
|
|
VkWriteDescriptorSet write{};
|
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
write.dstSet = getSet();
|
|
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
|
write.dstBinding = 0;
|
|
write.pImageInfo = &imageInfo;
|
|
write.descriptorCount = 1;
|
|
write.dstArrayElement = getCountAndAndOne();
|
|
|
|
vkUpdateDescriptorSets(m_context->getDevice(), 1, &write, 0, nullptr);
|
|
|
|
return write.dstArrayElement;
|
|
}
|
|
|
|
void BindlessTexture::freeBindlessImpl(uint32_t index, VulkanImage* fallback)
|
|
{
|
|
// If exist fallback input, we change bindless index to this fallback, so validation will happy to immediately delete current bindless asset.
|
|
if (fallback)
|
|
{
|
|
VkDescriptorImageInfo imageInfo{};
|
|
imageInfo.sampler = VK_NULL_HANDLE;
|
|
imageInfo.imageView = fallback->getOrCreateView(buildBasicImageSubresource());
|
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
|
|
VkWriteDescriptorSet write{};
|
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
write.dstSet = getSet();
|
|
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
|
write.dstBinding = 0;
|
|
write.pImageInfo = &imageInfo;
|
|
write.descriptorCount = 1;
|
|
write.dstArrayElement = index;
|
|
|
|
vkUpdateDescriptorSets(m_context->getDevice(), 1, &write, 0, nullptr);
|
|
}
|
|
|
|
BindlessBase::freeBindless(index);
|
|
}
|
|
|
|
void BindlessStorageBuffer::init(const char* name, const VulkanContext* context)
|
|
{
|
|
initTemplate(name, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, context,
|
|
context->getPhysicalDeviceDescriptorIndexingProperties().maxDescriptorSetUpdateAfterBindStorageBuffers);
|
|
}
|
|
|
|
uint32_t BindlessStorageBuffer::updateBufferToBindlessDescriptorSet(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range)
|
|
{
|
|
VkDescriptorBufferInfo bufferInfo{};
|
|
bufferInfo.buffer = buffer;
|
|
bufferInfo.offset = offset;
|
|
bufferInfo.range = range;
|
|
|
|
VkWriteDescriptorSet write{};
|
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
write.dstSet = getSet();
|
|
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
|
write.dstBinding = 0;
|
|
write.pBufferInfo = &bufferInfo;
|
|
write.descriptorCount = 1;
|
|
write.dstArrayElement = getCountAndAndOne();
|
|
|
|
vkUpdateDescriptorSets(m_context->getDevice(), 1, &write, 0, nullptr);
|
|
|
|
return write.dstArrayElement;
|
|
}
|
|
|
|
void BindlessStorageBuffer::freeBindlessImpl(uint32_t index, VulkanBuffer* fallback)
|
|
{
|
|
// Fallback same logic with texture.
|
|
if (fallback)
|
|
{
|
|
VkDescriptorBufferInfo bufferInfo{};
|
|
bufferInfo.buffer = fallback->getVkBuffer();
|
|
bufferInfo.offset = 0;
|
|
bufferInfo.range = fallback->getSize();
|
|
|
|
VkWriteDescriptorSet write{};
|
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
write.dstSet = getSet();
|
|
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
|
write.dstBinding = 0;
|
|
write.pBufferInfo = &bufferInfo;
|
|
write.descriptorCount = 1;
|
|
write.dstArrayElement = index;
|
|
|
|
vkUpdateDescriptorSets(m_context->getDevice(), 1, &write, 0, nullptr);
|
|
}
|
|
|
|
BindlessBase::freeBindless(index);
|
|
}
|
|
} |