descriptor set stuff from old engine

This commit is contained in:
2026-08-23 21:19:01 -07:00
parent 518c664741
commit ce075403d5
6 changed files with 341 additions and 0 deletions
@@ -0,0 +1,89 @@
#include "descriptor_pool.hpp"
#include <stdexcept>
namespace sophia {
DescriptorPool::Builder& DescriptorPool::Builder::addPoolSize(
vk::DescriptorType descriptorType, u32 count) {
this->poolSizes.push_back({descriptorType, count});
return *this;
}
DescriptorPool::Builder& DescriptorPool::Builder::setPoolFlags(
vk::DescriptorPoolCreateFlags flags) {
this->poolFlags = flags;
return *this;
}
DescriptorPool::Builder& DescriptorPool::Builder::setMaxSets(u32 count) {
this->maxSets = count;
return *this;
}
std::unique_ptr<DescriptorPool> DescriptorPool::Builder::build() const {
return std::make_unique<DescriptorPool>(this->device, this->maxSets,
this->poolFlags, this->poolSizes);
}
DescriptorPool::DescriptorPool(
Device& device, u32 maxSets, vk::DescriptorPoolCreateFlags poolFlags,
const std::vector<vk::DescriptorPoolSize>& poolSizes)
: device{device} {
vk::DescriptorPoolCreateInfo descriptorPoolInfo{};
descriptorPoolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
descriptorPoolInfo.pPoolSizes = poolSizes.data();
descriptorPoolInfo.maxSets = maxSets;
descriptorPoolInfo.flags = poolFlags;
vk::Result result = this->device.get()->createDescriptorPool(
&descriptorPoolInfo, nullptr, &this->descriptorPool);
if (result != vk::Result::eSuccess) {
log::fatal("failed to create descriptor pool");
throw std::runtime_error("failed to create descriptor pool");
}
}
DescriptorPool::~DescriptorPool() {
this->device.get()->destroyDescriptorPool(this->descriptorPool);
}
bool DescriptorPool::allocateDescriptorSet(
const vk::DescriptorSetLayout descriptorSetLayout,
vk::DescriptorSet& descriptor) const {
vk::DescriptorSetAllocateInfo allocInfo{};
allocInfo.descriptorPool = descriptorPool;
allocInfo.pSetLayouts = &descriptorSetLayout;
allocInfo.descriptorSetCount = 1;
// Might want to create a "DescriptorPoolManager" class that handles this
// case, and builds a new pool whenever an old pool fills up. But this is
// beyond our current scope
vk::Result result =
this->device.get()->allocateDescriptorSets(&allocInfo, &descriptor);
if (result == vk::Result::eSuccess) {
return true;
}
return false;
}
void DescriptorPool::freeDescriptors(
std::vector<vk::DescriptorSet>& descriptors) const {
vk::Result result = this->device.get()->freeDescriptorSets(
this->descriptorPool, static_cast<u32>(descriptors.size()),
descriptors.data());
if (result != vk::Result::eSuccess) {
log::fatal("failed to free descriptor sets");
throw std::runtime_error("failed to free descriptor sets");
}
}
void DescriptorPool::resetPool() {
this->device.get()->resetDescriptorPool(this->descriptorPool);
}
} // namespace sophia
@@ -0,0 +1,52 @@
#pragma once
#include <memory>
#include <vector>
#include "device.hpp"
namespace sophia {
class DescriptorPool {
public:
DescriptorPool(const DescriptorPool&) = delete;
DescriptorPool& operator=(const DescriptorPool&) = delete;
class Builder {
public:
Builder(Device& device) : device{device} {}
Builder& addPoolSize(vk::DescriptorType descriptorType, u32 count);
Builder& setPoolFlags(vk::DescriptorPoolCreateFlags flags);
Builder& setMaxSets(u32 count);
std::unique_ptr<DescriptorPool> build() const;
private:
Device& device;
std::vector<vk::DescriptorPoolSize> poolSizes{};
u32 maxSets = 1000;
vk::DescriptorPoolCreateFlags poolFlags{};
};
DescriptorPool(Device& device, u32 maxSets,
vk::DescriptorPoolCreateFlags poolFlags,
const std::vector<vk::DescriptorPoolSize>& poolSizes);
~DescriptorPool();
bool allocateDescriptorSet(const vk::DescriptorSetLayout descriptorSetLayout,
vk::DescriptorSet& descriptor) const;
void freeDescriptors(std::vector<vk::DescriptorSet>& descriptors) const;
void resetPool();
const vk::DescriptorPool& get() { return this->descriptorPool; }
private:
Device& device;
vk::DescriptorPool descriptorPool;
friend class DescriptorWriter;
};
} // namespace sophia
@@ -0,0 +1,53 @@
#include "descriptor_set_layout.hpp"
#include <cassert>
#include <stdexcept>
namespace sophia {
DescriptorSetLayout::Builder& DescriptorSetLayout::Builder::addBinding(
u32 binding, vk::DescriptorType descriptorType,
vk::ShaderStageFlags stageFlags, u32 count) {
assert(this->bindings.count(binding) == 0 && "binding already in use");
vk::DescriptorSetLayoutBinding layoutBinding{binding, descriptorType, count,
stageFlags};
this->bindings[binding] = layoutBinding;
return *this;
}
std::unique_ptr<DescriptorSetLayout> DescriptorSetLayout::Builder::build()
const {
return std::make_unique<DescriptorSetLayout>(this->device, this->bindings);
}
DescriptorSetLayout::DescriptorSetLayout(
Device& device,
std::unordered_map<u32, vk::DescriptorSetLayoutBinding> bindings)
: device{device}, bindings{bindings} {
std::vector<vk::DescriptorSetLayoutBinding> setLayoutBindings{};
for (auto binding : bindings) {
setLayoutBindings.push_back(binding.second);
}
vk::DescriptorSetLayoutCreateInfo layoutCreateInfo{};
layoutCreateInfo.bindingCount =
static_cast<uint32_t>(setLayoutBindings.size());
layoutCreateInfo.pBindings = setLayoutBindings.data();
vk::Result result = this->device.get()->createDescriptorSetLayout(
&layoutCreateInfo, nullptr, &this->layout);
if (result != vk::Result::eSuccess) {
log::fatal("failed to create descriptor pool");
throw std::runtime_error("failed to create descriptor set layout");
}
}
DescriptorSetLayout::~DescriptorSetLayout() {
this->device.get()->destroyDescriptorSetLayout(this->layout);
}
} // namespace sophia
@@ -0,0 +1,47 @@
#pragma once
#include <memory>
#include <unordered_map>
#include <vector>
#include "device.hpp"
namespace sophia {
class DescriptorSetLayout {
public:
DescriptorSetLayout(const DescriptorSetLayout&) = delete;
DescriptorSetLayout& operator=(const DescriptorSetLayout&) = delete;
class Builder {
public:
Builder(Device& device) : device{device} {}
Builder& addBinding(u32 binding, vk::DescriptorType descriptorType,
vk::ShaderStageFlags stageFlags, u32 count = 1);
std::unique_ptr<DescriptorSetLayout> build() const;
private:
Device& device;
std::unordered_map<u32, vk::DescriptorSetLayoutBinding> bindings{};
};
DescriptorSetLayout(
Device& device,
std::unordered_map<u32, vk::DescriptorSetLayoutBinding> bindings);
~DescriptorSetLayout();
vk::DescriptorSetLayout getDescriptorSetLayout() const {
return this->layout;
}
private:
Device& device;
vk::DescriptorSetLayout layout;
std::unordered_map<u32, vk::DescriptorSetLayoutBinding> bindings;
friend class DescriptorWriter;
};
} // namespace sophia
@@ -0,0 +1,72 @@
#include "descriptor_writer.hpp"
#include <cassert>
#include <stdexcept>
namespace sophia {
DescriptorWriter::DescriptorWriter(DescriptorSetLayout& setLayout,
DescriptorPool& pool)
: setLayout{setLayout}, pool{pool} {}
DescriptorWriter& DescriptorWriter::writeBuffer(
u32 binding, vk::DescriptorBufferInfo* bufferInfo) {
assert(this->setLayout.bindings.count(binding) == 1 &&
"setLayout does not contain specified binding");
auto& bindingDescription = this->setLayout.bindings[binding];
assert(bindingDescription.descriptorCount == 1 &&
"binding single descriptor info, but binding expects multiple");
vk::WriteDescriptorSet write{};
write.descriptorType = bindingDescription.descriptorType;
write.dstBinding = binding;
write.pBufferInfo = bufferInfo;
write.descriptorCount = 1;
writes.push_back(write);
return *this;
}
DescriptorWriter& DescriptorWriter::writeImage(
u32 binding, vk::DescriptorImageInfo* imageInfo) {
assert(this->setLayout.bindings.count(binding) == 1 &&
"setLayout does not contain specified binding");
auto& bindingDescription = this->setLayout.bindings[binding];
assert(bindingDescription.descriptorCount == 1 &&
"binding single descriptor info, but binding expects multiple");
vk::WriteDescriptorSet write{};
write.descriptorType = bindingDescription.descriptorType;
write.dstBinding = binding;
write.pImageInfo = imageInfo;
write.descriptorCount = 1;
writes.push_back(write);
return *this;
}
bool DescriptorWriter::build(vk::DescriptorSet& set) {
bool success =
this->pool.allocateDescriptorSet(setLayout.getDescriptorSetLayout(), set);
if (!success) {
return false;
}
overwrite(set);
return true;
}
void DescriptorWriter::overwrite(vk::DescriptorSet& set) {
for (auto& write : writes) {
write.dstSet = set;
}
this->pool.device.get()->updateDescriptorSets(writes.size(), writes.data(), 0,
nullptr);
}
} // namespace sophia
@@ -0,0 +1,28 @@
#pragma once
#include <vector>
#include "descriptor_pool.hpp"
#include "descriptor_set_layout.hpp"
#include "device.hpp"
namespace sophia {
class DescriptorWriter {
public:
DescriptorWriter(DescriptorSetLayout& setLayout, DescriptorPool& pool);
DescriptorWriter& writeBuffer(u32 binding,
vk::DescriptorBufferInfo* bufferInfo);
DescriptorWriter& writeImage(u32 binding, vk::DescriptorImageInfo* imageInfo);
bool build(vk::DescriptorSet& set);
void overwrite(vk::DescriptorSet& set);
private:
DescriptorSetLayout& setLayout;
DescriptorPool& pool;
std::vector<vk::WriteDescriptorSet> writes;
};
} // namespace sophia