Files
Seele/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp
T

313 lines
9.8 KiB
C++
Raw Normal View History

2020-08-11 21:23:20 +02:00
#include "VulkanDescriptorSets.h"
2020-03-09 12:30:07 +01:00
#include "VulkanGraphicsResources.h"
#include "VulkanGraphicsEnums.h"
#include "VulkanGraphics.h"
#include "VulkanInitializer.h"
#include "VulkanCommandBuffer.h"
2020-03-09 12:30:07 +01:00
using namespace Seele;
using namespace Seele::Vulkan;
2021-05-06 17:02:10 +02:00
DescriptorLayout::DescriptorLayout(PGraphics graphics, const std::string& name)
: Gfx::DescriptorLayout(name)
, graphics(graphics)
2020-10-03 11:00:10 +02:00
, layoutHandle(VK_NULL_HANDLE)
{
}
DescriptorLayout::~DescriptorLayout()
2020-03-09 12:30:07 +01:00
{
if (layoutHandle != VK_NULL_HANDLE)
{
vkDestroyDescriptorSetLayout(graphics->getDevice(), layoutHandle, nullptr);
}
}
void DescriptorLayout::create()
2020-03-09 12:30:07 +01:00
{
if (layoutHandle != VK_NULL_HANDLE)
{
return;
}
bindings.resize(descriptorBindings.size());
for (size_t i = 0; i < descriptorBindings.size(); ++i)
{
2020-04-12 15:47:19 +02:00
VkDescriptorSetLayoutBinding &binding = bindings[i];
const Gfx::DescriptorBinding &rhiBinding = descriptorBindings[i];
2020-03-09 12:30:07 +01:00
binding.binding = rhiBinding.binding;
binding.descriptorCount = rhiBinding.descriptorCount;
binding.descriptorType = cast(rhiBinding.descriptorType);
binding.stageFlags = rhiBinding.shaderStages;
binding.pImmutableSamplers = nullptr;
}
VkDescriptorSetLayoutCreateInfo createInfo =
2021-03-31 12:18:16 +02:00
init::DescriptorSetLayoutCreateInfo(bindings.data(), (uint32)bindings.size());
2020-03-09 12:30:07 +01:00
VK_CHECK(vkCreateDescriptorSetLayout(graphics->getDevice(), &createInfo, nullptr, &layoutHandle));
allocator = new DescriptorAllocator(graphics, *this);
2020-10-03 11:00:10 +02:00
boost::crc_32_type result;
result.process_bytes(bindings.data(), sizeof(VkDescriptorSetLayoutBinding) * bindings.size());
hash = result.checksum();
2020-03-09 12:30:07 +01:00
}
PipelineLayout::~PipelineLayout()
2020-03-13 12:44:33 +01:00
{
if (layoutHandle != VK_NULL_HANDLE)
{
vkDestroyPipelineLayout(graphics->getDevice(), layoutHandle, nullptr);
}
}
2020-10-03 11:00:10 +02:00
static Map<uint32, VkPipelineLayout> layoutCache;
void PipelineLayout::create()
2020-03-09 12:30:07 +01:00
{
vulkanDescriptorLayouts.resize(descriptorSetLayouts.size());
for (size_t i = 0; i < descriptorSetLayouts.size(); ++i)
{
2020-10-03 11:00:10 +02:00
// There could be unused descriptor set indices
if(descriptorSetLayouts[i] == nullptr)
{
2021-05-06 17:02:10 +02:00
vulkanDescriptorLayouts[i] = VK_NULL_HANDLE;
2020-10-03 11:00:10 +02:00
continue;
}
PDescriptorLayout layout = descriptorSetLayouts[i].cast<DescriptorLayout>();
2020-03-09 19:22:21 +01:00
layout->create();
vulkanDescriptorLayouts[i] = layout->getHandle();
2020-03-09 12:30:07 +01:00
}
2020-10-03 11:00:10 +02:00
2020-03-09 19:22:21 +01:00
VkPipelineLayoutCreateInfo createInfo =
2021-03-31 12:18:16 +02:00
init::PipelineLayoutCreateInfo(vulkanDescriptorLayouts.data(), (uint32)vulkanDescriptorLayouts.size());
2020-03-09 19:22:21 +01:00
Array<VkPushConstantRange> vkPushConstants(pushConstants.size());
for (size_t i = 0; i < pushConstants.size(); i++)
{
vkPushConstants[i].offset = pushConstants[i].offset;
vkPushConstants[i].size = pushConstants[i].size;
2021-05-06 17:02:10 +02:00
vkPushConstants[i].stageFlags = (VkShaderStageFlagBits)pushConstants[i].stageFlags;
2020-03-09 19:22:21 +01:00
}
2021-03-31 12:18:16 +02:00
createInfo.pushConstantRangeCount = (uint32)vkPushConstants.size();
2020-03-09 19:22:21 +01:00
createInfo.pPushConstantRanges = vkPushConstants.data();
2020-03-13 12:44:33 +01:00
boost::crc_32_type result;
2020-10-03 11:00:10 +02:00
result.process_bytes(createInfo.pPushConstantRanges, sizeof(VkPushConstantRange) * createInfo.pushConstantRangeCount);
result.process_bytes(createInfo.pSetLayouts, sizeof(VkDescriptorSetLayout) * createInfo.setLayoutCount);
layoutHash = result.checksum();
2020-10-03 11:00:10 +02:00
if(layoutCache[layoutHash] != VK_NULL_HANDLE)
{
layoutHandle = layoutCache[layoutHash];
return;
}
VK_CHECK(vkCreatePipelineLayout(graphics->getDevice(), &createInfo, nullptr, &layoutHandle));
layoutCache[layoutHash] = layoutHandle;
2020-03-13 12:44:33 +01:00
}
2020-06-02 11:46:18 +02:00
void PipelineLayout::reset()
{
vkDestroyPipelineLayout(graphics->getDevice(), layoutHandle, nullptr);
descriptorSetLayouts.clear();
pushConstants.clear();
}
DescriptorSet::~DescriptorSet()
2020-03-13 12:44:33 +01:00
{
}
void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBuffer)
2020-03-13 12:44:33 +01:00
{
PUniformBuffer vulkanBuffer = uniformBuffer.cast<UniformBuffer>();
2021-11-13 19:28:18 +01:00
UniformBuffer* cachedBuffer = reinterpret_cast<UniformBuffer*>(cachedData[binding]);
if(vulkanBuffer->isDataEquals(cachedBuffer))
2020-10-03 11:00:10 +02:00
{
2021-04-25 23:43:40 +02:00
std::cout << "uniform data equal, skip" << std::endl;
2020-10-03 11:00:10 +02:00
return;
2021-11-13 19:28:18 +01:00
}
2020-10-14 01:49:43 +02:00
bufferInfos.add(init::DescriptorBufferInfo(vulkanBuffer->getHandle(), 0, vulkanBuffer->getSize()));
2020-03-13 12:44:33 +01:00
2021-05-10 23:57:55 +02:00
VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, binding, &bufferInfos.back());
2020-03-13 12:44:33 +01:00
writeDescriptors.add(writeDescriptor);
2020-10-03 11:00:10 +02:00
2021-05-10 23:57:55 +02:00
cachedData[binding] = new UniformBuffer(*vulkanBuffer.getHandle());
2020-03-13 12:44:33 +01:00
}
void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PStructuredBuffer uniformBuffer)
2020-03-13 12:44:33 +01:00
{
PStructuredBuffer vulkanBuffer = uniformBuffer.cast<StructuredBuffer>();
2021-05-10 23:57:55 +02:00
StructuredBuffer* cachedBuffer = reinterpret_cast<StructuredBuffer*>(cachedData[binding]);
2020-10-03 11:00:10 +02:00
if(vulkanBuffer.getHandle() == cachedBuffer)
{
return;
}
2020-10-14 01:49:43 +02:00
bufferInfos.add(init::DescriptorBufferInfo(vulkanBuffer->getHandle(), 0, vulkanBuffer->getSize()));
2020-03-13 12:44:33 +01:00
2021-05-10 23:57:55 +02:00
VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, binding, &bufferInfos.back());
2020-03-13 12:44:33 +01:00
writeDescriptors.add(writeDescriptor);
2020-10-03 11:00:10 +02:00
2021-05-10 23:57:55 +02:00
cachedData[binding] = vulkanBuffer.getHandle();
2020-03-13 12:44:33 +01:00
}
void DescriptorSet::updateSampler(uint32_t binding, Gfx::PSamplerState samplerState)
2020-03-13 12:44:33 +01:00
{
PSamplerState vulkanSampler = samplerState.cast<SamplerState>();
2021-05-10 23:57:55 +02:00
SamplerState* cachedSampler = reinterpret_cast<SamplerState*>(cachedData[binding]);
2020-10-03 11:00:10 +02:00
if(vulkanSampler.getHandle() == cachedSampler)
{
return;
}
2020-03-13 12:44:33 +01:00
VkDescriptorImageInfo imageInfo =
init::DescriptorImageInfo(
vulkanSampler->sampler,
VK_NULL_HANDLE,
2020-08-11 22:38:19 +02:00
VK_IMAGE_LAYOUT_UNDEFINED);
2020-03-13 12:44:33 +01:00
imageInfos.add(imageInfo);
2021-05-10 23:57:55 +02:00
VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle, VK_DESCRIPTOR_TYPE_SAMPLER, binding, &imageInfos.back());
2020-03-13 12:44:33 +01:00
writeDescriptors.add(writeDescriptor);
2020-10-03 11:00:10 +02:00
2021-05-10 23:57:55 +02:00
cachedData[binding] = vulkanSampler.getHandle();
2020-03-13 12:44:33 +01:00
}
void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::PSamplerState samplerState)
2020-03-13 12:44:33 +01:00
{
2020-10-03 11:00:10 +02:00
TextureHandle* vulkanTexture = TextureBase::cast(texture);
2021-05-10 23:57:55 +02:00
TextureHandle* cachedTexture = reinterpret_cast<TextureHandle*>(cachedData[binding]);
2020-10-03 11:00:10 +02:00
if(vulkanTexture == cachedTexture)
{
return;
}
2020-03-13 12:44:33 +01:00
//It is assumed that the image is in the correct layout
2020-04-12 15:47:19 +02:00
VkDescriptorImageInfo imageInfo =
init::DescriptorImageInfo(
VK_NULL_HANDLE,
vulkanTexture->getView(),
2021-05-10 23:57:55 +02:00
cast(vulkanTexture->getLayout()));
2020-03-13 12:44:33 +01:00
if (samplerState != nullptr)
{
2020-04-12 15:47:19 +02:00
PSamplerState vulkanSampler = samplerState.cast<SamplerState>();
imageInfo.sampler = vulkanSampler->sampler;
2020-03-13 12:44:33 +01:00
}
2020-04-12 15:47:19 +02:00
imageInfos.add(imageInfo);
2021-04-25 23:43:40 +02:00
VkWriteDescriptorSet writeDescriptor =
init::WriteDescriptorSet(
2021-05-10 23:57:55 +02:00
setHandle,
2021-04-25 23:43:40 +02:00
samplerState != nullptr ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
binding,
&imageInfos.back());
2020-04-12 15:47:19 +02:00
if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT)
2020-03-13 12:44:33 +01:00
{
2020-04-12 15:47:19 +02:00
writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
2020-03-13 12:44:33 +01:00
}
writeDescriptors.add(writeDescriptor);
2020-10-03 11:00:10 +02:00
2021-05-10 23:57:55 +02:00
cachedData[binding] = vulkanTexture;
2020-03-13 12:44:33 +01:00
}
bool DescriptorSet::operator<(Gfx::PDescriptorSet other)
2020-03-13 12:44:33 +01:00
{
PDescriptorSet otherSet = other.cast<DescriptorSet>();
2021-03-31 12:18:16 +02:00
return this < otherSet.getHandle();
2020-03-13 12:44:33 +01:00
}
2021-04-13 23:09:16 +02:00
uint32 DescriptorSet::getSetIndex() const
{
return owner->getLayout().getSetIndex();
}
void DescriptorSet::writeChanges()
2020-03-13 12:44:33 +01:00
{
if (writeDescriptors.size() > 0)
{
2021-04-25 23:43:40 +02:00
if(isCurrentlyBound())
{
std::cout << "Descriptor currently bound, allocate a new one instead" << std::endl;
2021-05-10 23:57:55 +02:00
assert(!isCurrentlyBound());
2021-04-25 23:43:40 +02:00
}
2021-03-31 12:18:16 +02:00
vkUpdateDescriptorSets(graphics->getDevice(), (uint32)writeDescriptors.size(), writeDescriptors.data(), 0, nullptr);
2020-03-13 12:44:33 +01:00
writeDescriptors.clear();
imageInfos.clear();
bufferInfos.clear();
}
}
2020-04-12 15:47:19 +02:00
DescriptorAllocator::DescriptorAllocator(PGraphics graphics, DescriptorLayout &layout)
2021-04-01 16:40:14 +02:00
: graphics(graphics)
, layout(layout)
2020-03-13 12:44:33 +01:00
{
2021-04-13 23:09:16 +02:00
for(uint32 i = 0; i < cachedHandles.size(); ++i)
{
cachedHandles[i] = new DescriptorSet(graphics, this);
}
2020-10-03 11:00:10 +02:00
2020-08-11 22:38:19 +02:00
uint32 perTypeSizes[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT]; // TODO: FIX ENUM
2020-03-13 12:44:33 +01:00
std::memset(perTypeSizes, 0, sizeof(perTypeSizes));
2020-04-12 15:47:19 +02:00
for (uint32 i = 0; i < layout.getBindings().size(); ++i)
2020-03-13 12:44:33 +01:00
{
2020-04-12 15:47:19 +02:00
auto &binding = layout.getBindings()[i];
2020-03-13 12:44:33 +01:00
int typeIndex = binding.descriptorType;
perTypeSizes[typeIndex] += 256;
}
Array<VkDescriptorPoolSize> poolSizes;
2020-08-11 22:38:19 +02:00
for (uint32 i = 0; i < VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; ++i)
2020-03-13 12:44:33 +01:00
{
if (perTypeSizes[i] > 0)
{
VkDescriptorPoolSize size;
size.descriptorCount = perTypeSizes[i];
size.type = (VkDescriptorType)i;
poolSizes.add(size);
}
}
2021-05-10 23:57:55 +02:00
VkDescriptorPoolCreateInfo createInfo
= init::DescriptorPoolCreateInfo(
(uint32)poolSizes.size(),
poolSizes.data(),
maxSets * Gfx::numFramesBuffered);
2020-03-13 12:44:33 +01:00
VK_CHECK(vkCreateDescriptorPool(graphics->getDevice(), &createInfo, nullptr, &poolHandle));
}
DescriptorAllocator::~DescriptorAllocator()
2020-03-13 12:44:33 +01:00
{
vkDestroyDescriptorPool(graphics->getDevice(), poolHandle, nullptr);
2020-04-12 15:47:19 +02:00
graphics = nullptr;
2020-03-13 12:44:33 +01:00
}
2020-04-12 15:47:19 +02:00
void DescriptorAllocator::allocateDescriptorSet(Gfx::PDescriptorSet &descriptorSet)
2020-03-13 12:44:33 +01:00
{
VkDescriptorSetLayout layoutHandle = layout.getHandle();
2021-04-13 23:09:16 +02:00
VkDescriptorSetAllocateInfo allocInfo =
2021-05-10 23:57:55 +02:00
init::DescriptorSetAllocateInfo(poolHandle, &layoutHandle, 1);
2021-04-13 23:09:16 +02:00
for(uint32 setIndex = 0; setIndex < cachedHandles.size(); ++setIndex)
{
if(cachedHandles[setIndex]->isCurrentlyBound() || cachedHandles[setIndex]->isCurrentlyInUse())
{
// Currently in use, skip
continue;
}
if(cachedHandles[setIndex]->getHandle() == VK_NULL_HANDLE)
{
//If it hasnt been initialized, allocate it
2021-05-10 23:57:55 +02:00
VK_CHECK(vkAllocateDescriptorSets(graphics->getDevice(), &allocInfo, &cachedHandles[setIndex]->setHandle));
2021-04-13 23:09:16 +02:00
}
2021-10-16 12:59:11 +02:00
cachedHandles[setIndex]->allocate();
2021-04-13 23:09:16 +02:00
descriptorSet = cachedHandles[setIndex];
PDescriptorSet vulkanSet = descriptorSet.cast<DescriptorSet>();
2021-05-10 23:57:55 +02:00
vulkanSet->cachedData.resize(layout.bindings.size());
// Not really pretty, but this way the set knows which ones are valid
std::memset(vulkanSet->cachedData.data(), 0, sizeof(void*) * vulkanSet->cachedData.size());
2021-04-13 23:09:16 +02:00
//Found set, stop searching
return;
}
throw std::logic_error("Out of descriptor sets");
2020-03-13 12:44:33 +01:00
}
2020-10-03 11:00:10 +02:00
void DescriptorAllocator::reset()
{
2021-04-13 23:09:16 +02:00
for(uint32 i = 0; i < cachedHandles.size(); ++i)
{
cachedHandles[i]->free();
}
2020-10-03 11:00:10 +02:00
}