Add initial support for shader binding sets (WIP)

This commit is contained in:
Jérôme Leclercq
2021-06-14 22:35:05 +02:00
parent 815a7b0c62
commit f22b501e25
53 changed files with 885 additions and 511 deletions

View File

@@ -105,13 +105,20 @@ namespace Nz
m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkBinding.Get(*m_currentRenderPass, m_currentSubpassIndex));
}
void VulkanCommandBufferBuilder::BindShaderBinding(const ShaderBinding& binding)
void VulkanCommandBufferBuilder::BindShaderBinding(UInt32 set, const ShaderBinding& binding)
{
const VulkanShaderBinding& vkBinding = static_cast<const VulkanShaderBinding&>(binding);
const VulkanRenderPipelineLayout& pipelineLayout = vkBinding.GetOwner();
m_commandBuffer.BindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.GetPipelineLayout(), 0U, vkBinding.GetDescriptorSet());
m_commandBuffer.BindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.GetPipelineLayout(), set, vkBinding.GetDescriptorSet());
}
void VulkanCommandBufferBuilder::BindShaderBinding(const RenderPipelineLayout& pipelineLayout, UInt32 set, const ShaderBinding& binding)
{
const VulkanRenderPipelineLayout& vkPipelineLayout = static_cast<const VulkanRenderPipelineLayout&>(pipelineLayout);
const VulkanShaderBinding& vkBinding = static_cast<const VulkanShaderBinding&>(binding);
m_commandBuffer.BindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipelineLayout.GetPipelineLayout(), set, vkBinding.GetDescriptorSet());
}
void VulkanCommandBufferBuilder::BindVertexBuffer(UInt32 binding, Nz::AbstractBuffer* vertexBuffer, UInt64 offset)

View File

@@ -3,8 +3,10 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
#include <Nazara/VulkanRenderer/VulkanDescriptorSetLayoutCache.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Core/MemoryHelper.hpp>
#include <Nazara/Core/StackArray.hpp>
#include <Nazara/Core/StackVector.hpp>
#include <Nazara/VulkanRenderer/Utils.hpp>
#include <cassert>
@@ -22,11 +24,13 @@ namespace Nz
}
}
ShaderBindingPtr VulkanRenderPipelineLayout::AllocateShaderBinding()
ShaderBindingPtr VulkanRenderPipelineLayout::AllocateShaderBinding(UInt32 setIndex)
{
NazaraAssert(setIndex < m_descriptorSetLayouts.size(), "invalid set index");
for (std::size_t i = 0; i < m_descriptorPools.size(); ++i)
{
ShaderBindingPtr bindingPtr = AllocateFromPool(i);
ShaderBindingPtr bindingPtr = AllocateFromPool(i, setIndex);
if (!bindingPtr)
continue;
@@ -37,7 +41,7 @@ namespace Nz
std::size_t newPoolIndex = m_descriptorPools.size();
AllocatePool();
ShaderBindingPtr bindingPtr = AllocateFromPool(newPoolIndex);
ShaderBindingPtr bindingPtr = AllocateFromPool(newPoolIndex, setIndex);
if (!bindingPtr)
throw std::runtime_error("Failed to allocate shader binding");
@@ -49,21 +53,35 @@ namespace Nz
m_device = &device;
m_layoutInfo = std::move(layoutInfo);
StackVector<VkDescriptorSetLayoutBinding> layoutBindings = NazaraStackVector(VkDescriptorSetLayoutBinding, m_layoutInfo.bindings.size());
UInt32 setCount = 0;
for (const auto& bindingInfo : m_layoutInfo.bindings)
setCount = std::max(setCount, bindingInfo.setIndex + 1);
//TODO: Assert set count before stack allocation
StackArray<VulkanDescriptorSetLayoutInfo> setLayoutInfo = NazaraStackArray(VulkanDescriptorSetLayoutInfo, setCount);
StackArray<VkDescriptorSetLayout> setLayouts = NazaraStackArrayNoInit(VkDescriptorSetLayout, setCount);
m_descriptorSetLayouts.resize(setCount);
for (const auto& bindingInfo : m_layoutInfo.bindings)
{
VkDescriptorSetLayoutBinding& layoutBinding = layoutBindings.emplace_back();
layoutBinding.binding = bindingInfo.index;
VulkanDescriptorSetLayoutInfo& descriptorSetLayoutInfo = setLayoutInfo[bindingInfo.setIndex];
VkDescriptorSetLayoutBinding& layoutBinding = descriptorSetLayoutInfo.bindings.emplace_back();
layoutBinding.binding = bindingInfo.bindingIndex;
layoutBinding.descriptorCount = 1U;
layoutBinding.descriptorType = ToVulkan(bindingInfo.type);
layoutBinding.pImmutableSamplers = nullptr;
layoutBinding.stageFlags = ToVulkan(bindingInfo.shaderStageFlags);
}
if (!m_descriptorSetLayout.Create(*m_device, UInt32(layoutBindings.size()), layoutBindings.data()))
return false;
for (UInt32 i = 0; i < setCount; ++i)
{
m_descriptorSetLayouts[i] = &device.GetDescriptorSetLayoutCache().Get(setLayoutInfo[i]);
setLayouts[i] = *m_descriptorSetLayouts[i];
}
if (!m_pipelineLayout.Create(*m_device, m_descriptorSetLayout))
if (!m_pipelineLayout.Create(*m_device, UInt32(setLayouts.size()), setLayouts.data()))
return false;
return true;
@@ -94,7 +112,7 @@ namespace Nz
return m_descriptorPools.emplace_back(std::move(pool));
}
ShaderBindingPtr VulkanRenderPipelineLayout::AllocateFromPool(std::size_t poolIndex)
ShaderBindingPtr VulkanRenderPipelineLayout::AllocateFromPool(std::size_t poolIndex, UInt32 setIndex)
{
auto& pool = m_descriptorPools[poolIndex];
@@ -102,7 +120,7 @@ namespace Nz
if (freeBindingId == pool.freeBindings.npos)
return {}; //< No free binding in this pool
Vk::DescriptorSet descriptorSet = pool.descriptorPool->AllocateDescriptorSet(m_descriptorSetLayout);
Vk::DescriptorSet descriptorSet = pool.descriptorPool->AllocateDescriptorSet(*m_descriptorSetLayouts[setIndex]);
if (!descriptorSet)
{
NazaraWarning("Failed to allocate descriptor set: " + TranslateVulkanError(pool.descriptorPool->GetLastErrorCode()));

View File

@@ -17,7 +17,7 @@ namespace Nz
nullptr,
m_handle,
1U,
& setLayouts
&setLayouts
};
VkDescriptorSet handle = VK_NULL_HANDLE;

View File

@@ -6,6 +6,7 @@
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/VulkanRenderer/VulkanDescriptorSetLayoutCache.hpp>
#include <Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp>
#include <Nazara/VulkanRenderer/Wrapper/CommandPool.hpp>
#include <Nazara/VulkanRenderer/Wrapper/QueueHandle.hpp>
@@ -23,7 +24,13 @@ namespace Nz
{
struct Device::InternalData
{
InternalData(Device& device) :
setLayoutCache(device)
{
}
std::array<Vk::CommandPool, QueueCount> commandPools;
VulkanDescriptorSetLayoutCache setLayoutCache;
};
Device::Device(Instance& instance) :
@@ -131,7 +138,7 @@ namespace Nz
for (const QueueFamilyInfo& familyInfo : m_enabledQueuesInfos)
m_queuesByFamily[familyInfo.familyIndex] = &familyInfo.queues;
m_internalData = std::make_unique<InternalData>();
m_internalData = std::make_unique<InternalData>(*this);
m_defaultQueues.fill(InvalidQueue);
for (QueueType queueType : { QueueType::Graphics, QueueType::Compute, QueueType::Transfer })
@@ -243,6 +250,12 @@ namespace Nz
}
}
const VulkanDescriptorSetLayoutCache& Device::GetDescriptorSetLayoutCache() const
{
assert(m_internalData);
return m_internalData->setLayoutCache;
}
QueueHandle Device::GetQueue(UInt32 queueFamilyIndex, UInt32 queueIndex)
{
const auto& queues = GetEnabledQueues(queueFamilyIndex);