280 lines
7.9 KiB
C++
280 lines
7.9 KiB
C++
|
|
#pragma once
|
||
|
|
|
||
|
|
#include <cstdint>
|
||
|
|
#include <string>
|
||
|
|
#include <utility>
|
||
|
|
#include <vector>
|
||
|
|
#include <volk.h>
|
||
|
|
#include <memory>
|
||
|
|
#include <exception>
|
||
|
|
#include <assert.h>
|
||
|
|
#include <stdexcept>
|
||
|
|
#include <print>
|
||
|
|
|
||
|
|
#include "resources/Buffer.hpp"
|
||
|
|
#include "resources/Image.hpp"
|
||
|
|
#include "Gpu.hpp"
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ShaderInputSetBufferWrite
|
||
|
|
* For having uniform buffer
|
||
|
|
*/
|
||
|
|
struct ShaderInputSetBufferWrite {
|
||
|
|
private:
|
||
|
|
VkDescriptorType m_type;
|
||
|
|
uint32_t m_binding;
|
||
|
|
VkDescriptorBufferInfo m_bufferInfo;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/**
|
||
|
|
* Creates new shader input set write for Buffer
|
||
|
|
*/
|
||
|
|
ShaderInputSetBufferWrite(VkDescriptorType type, uint32_t binding, const Buffer& buffer,
|
||
|
|
uint32_t offset, uint32_t size) :
|
||
|
|
m_bufferInfo(
|
||
|
|
{
|
||
|
|
.buffer = buffer.buf,
|
||
|
|
.offset = offset,
|
||
|
|
.range = size
|
||
|
|
}
|
||
|
|
),
|
||
|
|
m_binding(binding),
|
||
|
|
m_type(type) {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
const VkDescriptorBufferInfo* info() {
|
||
|
|
return &m_bufferInfo;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
struct ShaderInputSetImageWrite {
|
||
|
|
private:
|
||
|
|
VkDescriptorType m_type;
|
||
|
|
uint32_t m_binding;
|
||
|
|
VkDescriptorImageInfo m_imageInfo;
|
||
|
|
|
||
|
|
public:
|
||
|
|
ShaderInputSetImageWrite(uint32_t binding, const ImageView& view, VkSampler sampler) :
|
||
|
|
m_imageInfo(
|
||
|
|
{
|
||
|
|
.sampler = sampler,
|
||
|
|
.imageView = view.view,
|
||
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||
|
|
}
|
||
|
|
),
|
||
|
|
m_binding(binding),
|
||
|
|
m_type(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
const VkDescriptorImageInfo* info() {
|
||
|
|
return &m_imageInfo;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
union ShaderInputSetWrite {
|
||
|
|
private:
|
||
|
|
struct {
|
||
|
|
VkDescriptorType type;
|
||
|
|
uint32_t binding;
|
||
|
|
} common;
|
||
|
|
ShaderInputSetBufferWrite buffer;
|
||
|
|
ShaderInputSetImageWrite image;
|
||
|
|
|
||
|
|
public:
|
||
|
|
ShaderInputSetWrite() :
|
||
|
|
common() {
|
||
|
|
}
|
||
|
|
|
||
|
|
explicit ShaderInputSetWrite(ShaderInputSetBufferWrite bufferWrite) :
|
||
|
|
buffer(bufferWrite) {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
explicit ShaderInputSetWrite(ShaderInputSetImageWrite imageWrite) :
|
||
|
|
image(imageWrite) {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t is_buffer_write(VkDescriptorType type) {
|
||
|
|
return type > VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
|
||
|
|
}
|
||
|
|
|
||
|
|
VkWriteDescriptorSet to_write(VkDescriptorSet set) {
|
||
|
|
return {
|
||
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||
|
|
.dstSet = set,
|
||
|
|
.dstBinding = common.binding,
|
||
|
|
.dstArrayElement = 0,
|
||
|
|
.descriptorCount = 1,
|
||
|
|
.descriptorType = common.type,
|
||
|
|
.pImageInfo = is_buffer_write(common.type) ? nullptr : image.info(),
|
||
|
|
.pBufferInfo = is_buffer_write(common.type) ? buffer.info() : nullptr,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ShaderInputSetBuilder
|
||
|
|
*
|
||
|
|
* Builds descriptor sets
|
||
|
|
*/
|
||
|
|
struct ShaderInputSetBuilder {
|
||
|
|
private:
|
||
|
|
std::vector<ShaderInputSetWrite> m_writes;
|
||
|
|
|
||
|
|
public:
|
||
|
|
explicit ShaderInputSetBuilder() :
|
||
|
|
m_writes() {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
ShaderInputSetBuilder& image(uint32_t binding, const ImageView& imageView, VkSampler sampler) {
|
||
|
|
assert(imageView.view != VK_NULL_HANDLE);
|
||
|
|
assert(sampler != VK_NULL_HANDLE);
|
||
|
|
|
||
|
|
m_writes.push_back(ShaderInputSetWrite(ShaderInputSetImageWrite(binding, imageView, sampler)));
|
||
|
|
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
ShaderInputSetBuilder& buffer(const VkDescriptorType type, const uint32_t binding, const Buffer& buffer, const uint32_t offset, const uint32_t size) {
|
||
|
|
assert(buffer.buf != VK_NULL_HANDLE);
|
||
|
|
|
||
|
|
m_writes.push_back(ShaderInputSetWrite(ShaderInputSetBufferWrite(type, binding, buffer, offset, size)));
|
||
|
|
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Allocates new descriptor sets from layout.
|
||
|
|
* All the writes must be set already.
|
||
|
|
* @param pGpu Gpu on which to perform
|
||
|
|
* @param layout Descriptor set layout
|
||
|
|
* @return Allocated descriptor set with all the writes.
|
||
|
|
*/
|
||
|
|
VkDescriptorSet build(const Gpu* gpu, VkDescriptorSetLayout layout) {
|
||
|
|
VkDescriptorSetAllocateInfo descriptorInfo = {
|
||
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||
|
|
.descriptorPool = gpu->descriptor_pool(),
|
||
|
|
.descriptorSetCount = 1,
|
||
|
|
.pSetLayouts = &layout
|
||
|
|
};
|
||
|
|
|
||
|
|
VkDescriptorSet set = VK_NULL_HANDLE;
|
||
|
|
if(vkAllocateDescriptorSets(gpu->dev(), &descriptorInfo, &set)) {
|
||
|
|
throw std::runtime_error("Failed to allocate descriptor set");
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<VkWriteDescriptorSet> writes(m_writes.size());
|
||
|
|
for(uint32_t i = 0; i < m_writes.size(); i++) {
|
||
|
|
writes[i] = m_writes[i].to_write(set);
|
||
|
|
}
|
||
|
|
|
||
|
|
vkUpdateDescriptorSets(gpu->dev(), writes.size(), writes.data(),
|
||
|
|
0, nullptr);
|
||
|
|
|
||
|
|
return set;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
struct ShaderInputSet {
|
||
|
|
private:
|
||
|
|
VkDescriptorSet m_descriptorSet;
|
||
|
|
|
||
|
|
public:
|
||
|
|
inline const VkDescriptorSet descriptor_set() const {
|
||
|
|
return m_descriptorSet;
|
||
|
|
}
|
||
|
|
|
||
|
|
ShaderInputSet(VkDescriptorSet descriptorSet) :
|
||
|
|
m_descriptorSet(descriptorSet) {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
ShaderInputSet(const Gpu* gpu, VkDescriptorSetLayout layout) :
|
||
|
|
m_descriptorSet(VK_NULL_HANDLE) {
|
||
|
|
|
||
|
|
VkDescriptorSetAllocateInfo descriptorInfo = {
|
||
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||
|
|
.descriptorPool = gpu->descriptor_pool(),
|
||
|
|
.descriptorSetCount = 1,
|
||
|
|
.pSetLayouts = &layout
|
||
|
|
};
|
||
|
|
|
||
|
|
if(vkAllocateDescriptorSets(gpu->dev(), &descriptorInfo, &m_descriptorSet)) {
|
||
|
|
throw std::runtime_error("Failed to allocate descriptor set");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
enum ShaderInputWriteType {
|
||
|
|
|
||
|
|
};
|
||
|
|
|
||
|
|
class ShaderInputSetWriter {
|
||
|
|
private:
|
||
|
|
const Gpu* m_gpu;
|
||
|
|
std::vector<VkWriteDescriptorSet> m_writes;
|
||
|
|
|
||
|
|
std::vector<std::vector<VkDescriptorImageInfo>> m_imageWrites;
|
||
|
|
std::vector<std::vector<VkDescriptorBufferInfo>> m_bufferWrites;
|
||
|
|
|
||
|
|
public:
|
||
|
|
explicit ShaderInputSetWriter(const Gpu* gpu) :
|
||
|
|
m_gpu(gpu) {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
ShaderInputSetWriter& write_images(const ShaderInputSet& dstInputSet,
|
||
|
|
const uint32_t dstBinding,
|
||
|
|
const uint32_t dstArrayElement,
|
||
|
|
const VkDescriptorType type,
|
||
|
|
const std::vector<VkDescriptorImageInfo>& writes) {
|
||
|
|
/* copy write data, to not lose it */
|
||
|
|
m_imageWrites.push_back(writes);
|
||
|
|
|
||
|
|
m_writes.push_back({
|
||
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||
|
|
.dstSet = dstInputSet.descriptor_set(),
|
||
|
|
.dstBinding = dstBinding,
|
||
|
|
.dstArrayElement = dstArrayElement,
|
||
|
|
.descriptorCount = (uint32_t)writes.size(),
|
||
|
|
.descriptorType = type,
|
||
|
|
.pImageInfo = m_imageWrites[m_imageWrites.size() - 1].data()
|
||
|
|
});
|
||
|
|
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
ShaderInputSetWriter& write_buffer(const ShaderInputSet& dstInputSet,
|
||
|
|
const uint32_t dstBinding,
|
||
|
|
const uint32_t dstArrayElement,
|
||
|
|
const VkDescriptorType type,
|
||
|
|
const std::vector<VkDescriptorBufferInfo>& writes) {
|
||
|
|
/* copy write data, to not lose it */
|
||
|
|
m_bufferWrites.push_back(writes);
|
||
|
|
|
||
|
|
m_writes.push_back({
|
||
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||
|
|
.dstSet = dstInputSet.descriptor_set(),
|
||
|
|
.dstBinding = dstBinding,
|
||
|
|
.dstArrayElement = dstArrayElement,
|
||
|
|
.descriptorCount = (uint32_t)writes.size(),
|
||
|
|
.descriptorType = type,
|
||
|
|
.pBufferInfo = m_bufferWrites[m_bufferWrites.size() - 1].data()
|
||
|
|
});
|
||
|
|
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
ShaderInputSetWriter& write() {
|
||
|
|
vkUpdateDescriptorSets(m_gpu->dev(), m_writes.size(), m_writes.data(), 0, nullptr);
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
};
|