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

433 lines
14 KiB
C++
Raw Normal View History

2023-11-15 17:42:57 +01:00
#include "Descriptor.h"
2023-10-26 18:37:29 +02:00
#include "Graphics.h"
2023-11-05 10:36:01 +01:00
#include "Texture.h"
2023-11-15 17:42:57 +01:00
#include "Buffer.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)
2021-12-27 15:04:53 +01:00
: Gfx::DescriptorLayout(name)
, graphics(graphics)
, layoutHandle(VK_NULL_HANDLE)
2020-10-03 11:00:10 +02:00
{
}
DescriptorLayout::~DescriptorLayout()
2020-03-09 12:30:07 +01:00
{
2021-12-27 15:04:53 +01:00
if (layoutHandle != VK_NULL_HANDLE)
{
vkDestroyDescriptorSetLayout(graphics->getDevice(), layoutHandle, nullptr);
}
2020-03-09 12:30:07 +01:00
}
void DescriptorLayout::create()
2020-03-09 12:30:07 +01:00
{
2021-12-27 15:04:53 +01:00
if (layoutHandle != VK_NULL_HANDLE)
{
return;
}
bindings.resize(descriptorBindings.size());
2022-04-15 11:19:30 +02:00
Array<VkDescriptorBindingFlags> bindingFlags(descriptorBindings.size());
2021-12-27 15:04:53 +01:00
for (size_t i = 0; i < descriptorBindings.size(); ++i)
{
2023-11-10 22:26:47 +01:00
const Gfx::DescriptorBinding &gfxBinding = descriptorBindings[i];
2023-11-15 17:42:57 +01:00
bindings[i] = {
.binding = gfxBinding.binding,
.descriptorType = cast(gfxBinding.descriptorType),
.descriptorCount = gfxBinding.descriptorCount,
.stageFlags = gfxBinding.shaderStages,
.pImmutableSamplers = nullptr,
};
2023-11-10 22:26:47 +01:00
bindingFlags[i] = gfxBinding.bindingFlags;
2021-12-27 15:04:53 +01:00
}
2023-11-10 22:26:47 +01:00
VkDescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
.pNext = nullptr,
.bindingCount = static_cast<uint32>(bindingFlags.size()),
.pBindingFlags = bindingFlags.data(),
};
2023-11-15 17:42:57 +01:00
VkDescriptorSetLayoutCreateInfo createInfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = &bindingFlagsInfo,
.flags = 0,
.bindingCount = (uint32)bindings.size(),
.pBindings = bindings.data(),
};
2021-12-27 15:04:53 +01:00
VK_CHECK(vkCreateDescriptorSetLayout(graphics->getDevice(), &createInfo, nullptr, &layoutHandle));
2020-03-09 12:30:07 +01:00
2023-11-15 17:42:57 +01:00
pool = new DescriptorPool(graphics, *this);
2020-10-03 11:00:10 +02:00
2022-11-22 22:11:37 +01:00
hash = CRC::Calculate(bindings.data(), sizeof(VkDescriptorSetLayoutBinding) * bindings.size(), CRC::CRC_32());
2020-03-09 12:30:07 +01:00
}
PipelineLayout::~PipelineLayout()
2020-03-13 12:44:33 +01:00
{
}
2023-11-30 11:51:53 +01:00
Map<uint32, VkPipelineLayout> cachedLayouts;
void PipelineLayout::create()
2020-03-09 12:30:07 +01:00
{
2021-12-27 15:04:53 +01:00
vulkanDescriptorLayouts.resize(descriptorSetLayouts.size());
for (size_t i = 0; i < descriptorSetLayouts.size(); ++i)
{
// There could be unused descriptor set indices
if(descriptorSetLayouts[i] == nullptr)
{
vulkanDescriptorLayouts[i] = VK_NULL_HANDLE;
continue;
}
PDescriptorLayout layout = descriptorSetLayouts[i].cast<DescriptorLayout>();
layout->create();
vulkanDescriptorLayouts[i] = layout->getHandle();
}
2020-10-03 11:00:10 +02:00
2021-12-27 15:04:53 +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;
vkPushConstants[i].stageFlags = (VkShaderStageFlagBits)pushConstants[i].stageFlags;
}
2023-11-15 17:42:57 +01:00
VkPipelineLayoutCreateInfo createInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.setLayoutCount = (uint32)vulkanDescriptorLayouts.size(),
.pSetLayouts = vulkanDescriptorLayouts.data(),
.pushConstantRangeCount = (uint32)vkPushConstants.size(),
.pPushConstantRanges = vkPushConstants.data(),
};
2020-03-13 12:44:33 +01:00
2022-11-22 22:11:37 +01:00
layoutHash = CRC::Calculate(createInfo.pPushConstantRanges, sizeof(VkPushConstantRange) * createInfo.pushConstantRangeCount, CRC::CRC_32());
layoutHash = CRC::Calculate(createInfo.pSetLayouts, sizeof(VkDescriptorSetLayout) * createInfo.setLayoutCount, CRC::CRC_32(), layoutHash);
2020-10-03 11:00:10 +02:00
2023-11-30 11:51:53 +01:00
if (cachedLayouts.contains(layoutHash))
{
layoutHandle = cachedLayouts[layoutHash];
return;
}
2021-12-27 15:04:53 +01:00
VK_CHECK(vkCreatePipelineLayout(graphics->getDevice(), &createInfo, nullptr, &layoutHandle));
2023-11-30 11:51:53 +01:00
cachedLayouts[layoutHash] = layoutHandle;
2020-03-13 12:44:33 +01:00
}
2020-06-02 11:46:18 +02:00
void PipelineLayout::reset()
{
2021-12-27 15:04:53 +01:00
vkDestroyPipelineLayout(graphics->getDevice(), layoutHandle, nullptr);
descriptorSetLayouts.clear();
pushConstants.clear();
2020-06-02 11:46:18 +02:00
}
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
{
2021-12-27 15:04:53 +01:00
PUniformBuffer vulkanBuffer = uniformBuffer.cast<UniformBuffer>();
UniformBuffer* cachedBuffer = reinterpret_cast<UniformBuffer*>(cachedData[binding]);
if(vulkanBuffer->isDataEquals(cachedBuffer))
{
2022-04-18 18:08:38 +02:00
//std::cout << "uniform data equal, skip" << std::endl;
2021-12-27 15:04:53 +01:00
return;
}
2023-11-15 17:42:57 +01:00
bufferInfos.add(VkDescriptorBufferInfo{
.buffer = vulkanBuffer->getHandle(),
.offset = 0,
.range = vulkanBuffer->getSize(),
});
2020-03-13 12:44:33 +01:00
2023-11-15 17:42:57 +01:00
writeDescriptors.add(VkWriteDescriptorSet{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = setHandle,
.dstBinding = binding,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.pBufferInfo = &bufferInfos.back(),
});
2020-10-03 11:00:10 +02:00
2023-11-05 10:36:01 +01:00
cachedData[binding] = vulkanBuffer.getHandle();
2020-03-13 12:44:33 +01:00
}
2023-11-05 10:36:01 +01:00
void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PShaderBuffer shaderBuffer)
2020-03-13 12:44:33 +01:00
{
2023-11-05 10:36:01 +01:00
PShaderBuffer vulkanBuffer = shaderBuffer.cast<ShaderBuffer>();
2023-08-28 21:23:13 +02:00
ShaderBuffer* cachedBuffer = reinterpret_cast<ShaderBuffer*>(cachedData[binding]);
2021-12-27 15:04:53 +01:00
if(vulkanBuffer.getHandle() == cachedBuffer)
{
return;
}
2020-03-13 12:44:33 +01:00
2023-11-15 17:42:57 +01:00
bufferInfos.add(VkDescriptorBufferInfo{
.buffer = vulkanBuffer->getHandle(),
.offset = 0,
.range = vulkanBuffer->getSize(),
});
writeDescriptors.add(VkWriteDescriptorSet{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = setHandle,
.dstBinding = binding,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &bufferInfos.back(),
});
2020-10-03 11:00:10 +02:00
2021-12-27 15:04:53 +01:00
cachedData[binding] = vulkanBuffer.getHandle();
2020-03-13 12:44:33 +01:00
}
2023-11-15 17:42:57 +01:00
void DescriptorSet::updateSampler(uint32_t binding, Gfx::PSampler samplerState)
2020-03-13 12:44:33 +01:00
{
2023-11-15 17:42:57 +01:00
PSampler vulkanSampler = samplerState.cast<Sampler>();
2023-11-15 00:06:00 +01:00
Sampler* cachedSampler = reinterpret_cast<Sampler*>(cachedData[binding]);
2021-12-27 15:04:53 +01:00
if(vulkanSampler.getHandle() == cachedSampler)
{
return;
}
2023-11-15 17:42:57 +01:00
imageInfos.add(VkDescriptorImageInfo{
.sampler = vulkanSampler->sampler,
.imageView = VK_NULL_HANDLE,
.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
2020-03-13 12:44:33 +01:00
2023-11-15 17:42:57 +01:00
writeDescriptors.add(VkWriteDescriptorSet{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = setHandle,
.dstBinding = binding,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.pImageInfo = &imageInfos.back(),
});
2020-10-03 11:00:10 +02:00
2021-12-27 15:04:53 +01:00
cachedData[binding] = vulkanSampler.getHandle();
2020-03-13 12:44:33 +01:00
}
2023-11-15 17:42:57 +01:00
void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::PSampler samplerState)
2020-03-13 12:44:33 +01:00
{
2023-11-15 17:42:57 +01:00
TextureBase* vulkanTexture = texture.cast<TextureBase>().getHandle();
TextureBase* cachedTexture = reinterpret_cast<TextureBase*>(cachedData[binding]);
2021-12-27 15:04:53 +01:00
if(vulkanTexture == cachedTexture)
{
return;
}
//It is assumed that the image is in the correct layout
2023-11-15 17:42:57 +01:00
imageInfos.add(VkDescriptorImageInfo{
.sampler = samplerState != nullptr ? samplerState.cast<Sampler>()->sampler : VK_NULL_HANDLE,
.imageView = vulkanTexture->getView(),
.imageLayout = cast(vulkanTexture->getLayout()),
});
2022-04-15 11:19:30 +02:00
VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
if(samplerState != nullptr)
{
descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
}
else if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT)
{
descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
}
2023-11-15 17:42:57 +01:00
writeDescriptors.add(VkWriteDescriptorSet{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = setHandle,
.dstBinding = binding,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = descriptorType,
.pImageInfo = &imageInfos.back(),
});
2020-10-03 11:00:10 +02:00
2021-12-27 15:04:53 +01:00
cachedData[binding] = vulkanTexture;
2020-03-13 12:44:33 +01:00
}
2022-04-15 11:19:30 +02:00
void DescriptorSet::updateTextureArray(uint32_t binding, Array<Gfx::PTexture> textures)
{
// maybe make this a parameter?
uint32 arrayElement = 0;
2023-11-15 17:42:57 +01:00
for(auto& gfxTexture : textures)
2022-04-15 11:19:30 +02:00
{
2023-11-15 17:42:57 +01:00
TextureBase* vulkanTexture = gfxTexture.cast<TextureBase>().getHandle();
imageInfos.add(VkDescriptorImageInfo{
.sampler = VK_NULL_HANDLE,
.imageView = vulkanTexture->getView(),
.imageLayout = cast(vulkanTexture->getLayout()),
});
2022-04-15 11:19:30 +02:00
VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT)
{
descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
}
2023-11-15 17:42:57 +01:00
writeDescriptors.add(VkWriteDescriptorSet{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = setHandle,
.dstBinding = binding,
.dstArrayElement = arrayElement++,
.descriptorCount = 1,
.descriptorType = descriptorType,
.pImageInfo = &imageInfos.back(),
});
2022-04-15 11:19:30 +02:00
}
}
2020-03-13 12:44:33 +01:00
bool DescriptorSet::operator<(Gfx::PDescriptorSet other)
2020-03-13 12:44:33 +01:00
{
2021-12-27 15:04:53 +01:00
PDescriptorSet otherSet = other.cast<DescriptorSet>();
return this < otherSet.getHandle();
2020-03-13 12:44:33 +01:00
}
2021-04-13 23:09:16 +02:00
uint32 DescriptorSet::getSetIndex() const
{
2021-12-27 15:04:53 +01:00
return owner->getLayout().getSetIndex();
2021-04-13 23:09:16 +02:00
}
void DescriptorSet::writeChanges()
2020-03-13 12:44:33 +01:00
{
2021-12-27 15:04:53 +01:00
if (writeDescriptors.size() > 0)
{
if(isCurrentlyBound())
{
std::cout << "Descriptor currently bound, allocate a new one instead" << std::endl;
assert(!isCurrentlyBound());
}
vkUpdateDescriptorSets(graphics->getDevice(), (uint32)writeDescriptors.size(), writeDescriptors.data(), 0, nullptr);
writeDescriptors.clear();
imageInfos.clear();
bufferInfos.clear();
}
2020-03-13 12:44:33 +01:00
}
2023-11-15 17:42:57 +01:00
DescriptorPool::DescriptorPool(PGraphics graphics, DescriptorLayout &layout)
2021-12-27 15:04:53 +01:00
: graphics(graphics)
, layout(layout)
2020-03-13 12:44:33 +01:00
{
2021-12-27 15:04:53 +01:00
for(uint32 i = 0; i < cachedHandles.size(); ++i)
{
cachedHandles[i] = nullptr;
}
2020-10-03 11:00:10 +02:00
2021-12-27 15:04:53 +01:00
uint32 perTypeSizes[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT]; // TODO: FIX ENUM
std::memset(perTypeSizes, 0, sizeof(perTypeSizes));
for (uint32 i = 0; i < layout.getBindings().size(); ++i)
{
auto &binding = layout.getBindings()[i];
int typeIndex = binding.descriptorType;
perTypeSizes[typeIndex] += 256;
}
Array<VkDescriptorPoolSize> poolSizes;
for (uint32 i = 0; i < VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; ++i)
{
if (perTypeSizes[i] > 0)
{
VkDescriptorPoolSize size;
size.descriptorCount = perTypeSizes[i];
size.type = (VkDescriptorType)i;
poolSizes.add(size);
}
}
2023-11-15 17:42:57 +01:00
VkDescriptorPoolCreateInfo createInfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.maxSets = maxSets * Gfx::numFramesBuffered,
.poolSizeCount = (uint32)poolSizes.size(),
.pPoolSizes = poolSizes.data(),
};
2021-12-27 15:04:53 +01:00
VK_CHECK(vkCreateDescriptorPool(graphics->getDevice(), &createInfo, nullptr, &poolHandle));
2020-03-13 12:44:33 +01:00
}
2023-11-15 17:42:57 +01:00
DescriptorPool::~DescriptorPool()
2020-03-13 12:44:33 +01:00
{
2021-12-27 15:04:53 +01:00
vkDestroyDescriptorPool(graphics->getDevice(), poolHandle, nullptr);
graphics = nullptr;
if(nextAlloc)
{
delete nextAlloc;
}
2020-03-13 12:44:33 +01:00
}
2023-11-15 17:42:57 +01:00
Gfx::PDescriptorSet DescriptorPool::allocateDescriptorSet()
2020-03-13 12:44:33 +01:00
{
2021-12-27 15:04:53 +01:00
VkDescriptorSetLayout layoutHandle = layout.getHandle();
2023-11-15 17:42:57 +01:00
VkDescriptorSetVariableDescriptorCountAllocateInfo setCounts = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO,
.pNext = nullptr,
.descriptorSetCount = 1,
};
VkDescriptorSetAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.pNext = nullptr,
.descriptorPool = poolHandle,
.descriptorSetCount = 1,
.pSetLayouts = &layoutHandle,
};
2022-04-15 11:19:30 +02:00
uint32 counts = 0;
for(const auto& binding : layout.bindings)
{
2022-04-15 23:45:44 +02:00
if(binding.descriptorCount > 0)
2022-04-15 11:19:30 +02:00
{
counts = binding.descriptorCount;
}
}
2023-11-12 14:46:22 +01:00
if (layout.bindings.size() > 0)
{
setCounts.pDescriptorCounts = &counts;
allocInfo.pNext = &setCounts;
}
2021-12-27 15:04:53 +01:00
for(uint32 setIndex = 0; setIndex < cachedHandles.size(); ++setIndex)
{
if(cachedHandles[setIndex] == nullptr)
{
cachedHandles[setIndex] = new DescriptorSet(graphics, this);
}
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
VK_CHECK(vkAllocateDescriptorSets(graphics->getDevice(), &allocInfo, &cachedHandles[setIndex]->setHandle));
}
cachedHandles[setIndex]->allocate();
2023-11-05 10:36:01 +01:00
PDescriptorSet vulkanSet = cachedHandles[setIndex];
2021-12-27 15:04:53 +01: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());
//Found set, stop searching
2023-11-05 10:36:01 +01:00
return vulkanSet;
2021-12-27 15:04:53 +01:00
}
if(nextAlloc == nullptr)
{
2023-11-15 17:42:57 +01:00
nextAlloc = new DescriptorPool(graphics, layout);
2021-12-27 15:04:53 +01:00
}
2023-11-17 18:46:37 +01:00
std::cout << "Out of descriptors, forwarding" << std::endl;
2023-11-05 10:36:01 +01:00
return nextAlloc->allocateDescriptorSet();
2021-12-27 15:04:53 +01:00
//throw std::logic_error("Out of descriptor sets");
2020-03-13 12:44:33 +01:00
}
2020-10-03 11:00:10 +02:00
2023-11-15 17:42:57 +01:00
void DescriptorPool::reset()
2020-10-03 11:00:10 +02:00
{
2021-12-27 15:04:53 +01:00
for(uint32 i = 0; i < cachedHandles.size(); ++i)
{
if(cachedHandles[i] == nullptr)
{
return;
}
cachedHandles[i]->free();
}
if(nextAlloc != nullptr)
{
nextAlloc->reset();
}
2020-10-03 11:00:10 +02:00
}