Last active
March 29, 2024 07:45
-
-
Save bynmz/35254c4a22aa832412c1fabefb71ebce to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
App3D::App3D() { | |
globalPool = | |
DescriptorPool::Builder(nileDevice) | |
.setMaxSets(SwapChain::MAX_FRAMES_IN_FLIGHT) | |
.addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, SwapChain::MAX_FRAMES_IN_FLIGHT) | |
.build(); | |
// build frame descriptor pools | |
framePools.resize(SwapChain::MAX_FRAMES_IN_FLIGHT); | |
auto framePoolBuilder = DescriptorPool::Builder(nileDevice) | |
.setMaxSets(1000) | |
.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000) | |
.addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000) | |
.setPoolFlags(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT); | |
for (int i = 0; i < framePools.size(); i++) { | |
framePools[i] = framePoolBuilder.build(); | |
} | |
globalSetLayout = | |
DescriptorSetLayout::Builder(nileDevice) | |
.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL_GRAPHICS) | |
.build(); | |
for (int i = 0; i < uboBuffers.size(); i++) { | |
uboBuffers[i] = std::make_unique<Buffer>( | |
nileDevice, | |
sizeof(GlobalUbo), | |
1, | |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, | |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); | |
uboBuffers[i]->map(); | |
} | |
for (int i = 0; i < globalDescriptorSets.size(); i++) { | |
auto bufferInfo = uboBuffers[i]->descriptorInfo(); | |
DescriptorWriter(*globalSetLayout, *globalPool) | |
.writeBuffer(0, &bufferInfo) | |
.build(globalDescriptorSets[i]); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
namespace mge{ | |
class App3D { | |
public: | |
static constexpr int WIDTH = 800; | |
static constexpr int HEIGHT = 600; | |
App3D(); | |
virtual ~App3D(); | |
App3D(const App3D &) = delete; | |
App3D &operator=(const App3D &) = delete; | |
static constexpr int MAX_FRAMES = SwapChain::MAX_FRAMES_IN_FLIGHT; | |
Window Window{WIDTH, HEIGHT, "My Graphics Engine 3D"}; | |
Device Device{Window}; | |
Renderer Renderer{Window, Device}; | |
// note: order of declarations matters | |
std::unique_ptr<DescriptorPool> globalPool{}; | |
std::unique_ptr<DescriptorSetLayout> globalSetLayout{}; | |
std::vector<std::unique_ptr<DescriptorPool>> framePools; | |
GameObjectManager gameObjectManager{Device}; | |
std::vector<std::unique_ptr<Buffer>> uboBuffers{MAX_FRAMES}; | |
std::vector<VkDescriptorSet> globalDescriptorSets{MAX_FRAMES}; | |
Camera camera{}; | |
KeyboardMovementController cameraController{}; | |
virtual void start(); | |
private: | |
virtual void loadGameObjects(); | |
virtual void loop(); | |
}; | |
} // namespace mge |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "descriptors.hpp" | |
// std | |
#include <cassert> | |
#include <stdexcept> | |
namespace mge{ | |
// *************** Descriptor Set Layout Builder ********************* | |
DescriptorSetLayout::Builder &DescriptorSetLayout::Builder::addBinding( | |
uint32_t binding, | |
VkDescriptorType descriptorType, | |
VkShaderStageFlags stageFlags, | |
uint32_t count) { | |
assert(bindings.count(binding) == 0 && "Binding already in use"); | |
VkDescriptorSetLayoutBinding layoutBinding{}; | |
layoutBinding.binding = binding; | |
layoutBinding.descriptorType = descriptorType; | |
layoutBinding.descriptorCount = count; | |
layoutBinding.stageFlags = stageFlags; | |
bindings[binding] = layoutBinding; | |
return *this; | |
} | |
std::unique_ptr<DescriptorSetLayout> DescriptorSetLayout::Builder::build() const { | |
return std::make_unique<DescriptorSetLayout>(Device, bindings); | |
} | |
// *************** Descriptor Set Layout ********************* | |
DescriptorSetLayout::DescriptorSetLayout( | |
Device &Device, std::unordered_map<uint32_t, VkDescriptorSetLayoutBinding> bindings) | |
: Device{Device}, bindings{bindings} { | |
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings{}; | |
for (auto kv : bindings) { | |
setLayoutBindings.push_back(kv.second); | |
} | |
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{}; | |
descriptorSetLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; | |
descriptorSetLayoutInfo.bindingCount = static_cast<uint32_t>(setLayoutBindings.size()); | |
descriptorSetLayoutInfo.pBindings = setLayoutBindings.data(); | |
if (vkCreateDescriptorSetLayout( | |
Device.device(), | |
&descriptorSetLayoutInfo, | |
nullptr, | |
&descriptorSetLayout) != VK_SUCCESS) { | |
throw std::runtime_error("failed to create descriptor set layout!"); | |
} | |
} | |
DescriptorSetLayout::~DescriptorSetLayout() { | |
vkDestroyDescriptorSetLayout(Device.device(), descriptorSetLayout, nullptr); | |
} | |
// *************** Descriptor Pool Builder ********************* | |
DescriptorPool::Builder &DescriptorPool::Builder::addPoolSize( | |
VkDescriptorType descriptorType, uint32_t count) { | |
poolSizes.push_back({descriptorType, count}); | |
return *this; | |
} | |
DescriptorPool::Builder &DescriptorPool::Builder::setPoolFlags( | |
VkDescriptorPoolCreateFlags flags) { | |
poolFlags = flags; | |
return *this; | |
} | |
DescriptorPool::Builder &DescriptorPool::Builder::setMaxSets(uint32_t count) { | |
maxSets = count; | |
return *this; | |
} | |
std::unique_ptr<DescriptorPool> DescriptorPool::Builder::build() const { | |
return std::make_unique<DescriptorPool>(Device, maxSets, poolFlags, poolSizes); | |
} | |
// *************** Descriptor Pool ********************* | |
DescriptorPool::DescriptorPool( | |
Device &Device, | |
uint32_t maxSets, | |
VkDescriptorPoolCreateFlags poolFlags, | |
const std::vector<VkDescriptorPoolSize> &poolSizes) | |
: Device{Device} { | |
VkDescriptorPoolCreateInfo descriptorPoolInfo{}; | |
descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; | |
descriptorPoolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size()); | |
descriptorPoolInfo.pPoolSizes = poolSizes.data(); | |
descriptorPoolInfo.maxSets = maxSets; | |
descriptorPoolInfo.flags = poolFlags; | |
if (vkCreateDescriptorPool(Device.device(), &descriptorPoolInfo, nullptr, &descriptorPool) != | |
VK_SUCCESS) { | |
throw std::runtime_error("failed to create descriptor pool!"); | |
} | |
} | |
DescriptorPool::~DescriptorPool() { | |
vkDestroyDescriptorPool(Device.device(), descriptorPool, nullptr); | |
} | |
bool DescriptorPool::allocateDescriptor( | |
const VkDescriptorSetLayout descriptorSetLayout, VkDescriptorSet &descriptor) const { | |
VkDescriptorSetAllocateInfo allocInfo{}; | |
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; | |
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 | |
if (vkAllocateDescriptorSets(Device.device(), &allocInfo, &descriptor) != VK_SUCCESS) { | |
return false; | |
} | |
return true; | |
} | |
void DescriptorPool::freeDescriptors(std::vector<VkDescriptorSet> &descriptors) const { | |
vkFreeDescriptorSets( | |
Device.device(), | |
descriptorPool, | |
static_cast<uint32_t>(descriptors.size()), | |
descriptors.data()); | |
} | |
void DescriptorPool::resetPool() { | |
vkResetDescriptorPool(Device.device(), descriptorPool, 0); | |
} | |
// *************** Descriptor Writer ********************* | |
DescriptorWriter::DescriptorWriter(DescriptorSetLayout &setLayout, DescriptorPool &pool) | |
: setLayout{setLayout}, pool{pool} {} | |
DescriptorWriter &DescriptorWriter::writeBuffer( | |
uint32_t binding, VkDescriptorBufferInfo *bufferInfo) { | |
assert(setLayout.bindings.count(binding) == 1 && "Layout does not contain specified binding"); | |
auto &bindingDescription = setLayout.bindings[binding]; | |
assert( | |
bindingDescription.descriptorCount == 1 && | |
"Binding single descriptor info, but binding expects multiple"); | |
VkWriteDescriptorSet write{}; | |
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | |
write.descriptorType = bindingDescription.descriptorType; | |
write.dstBinding = binding; | |
write.pBufferInfo = bufferInfo; | |
write.descriptorCount = 1; | |
writes.push_back(write); | |
return *this; | |
} | |
DescriptorWriter &DescriptorWriter::writeImage( | |
uint32_t binding, VkDescriptorImageInfo *imageInfo) { | |
assert(setLayout.bindings.count(binding) == 1 && "Layout does not contain specified binding"); | |
auto &bindingDescription = setLayout.bindings[binding]; | |
assert( | |
bindingDescription.descriptorCount == 1 && | |
"Binding single descriptor info, but binding expects multiple"); | |
VkWriteDescriptorSet write{}; | |
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | |
write.descriptorType = bindingDescription.descriptorType; | |
write.dstBinding = binding; | |
write.pImageInfo = imageInfo; | |
write.descriptorCount = 1; | |
writes.push_back(write); | |
return *this; | |
} | |
bool DescriptorWriter::build(VkDescriptorSet &set) { | |
bool success = pool.allocateDescriptor(setLayout.getDescriptorSetLayout(), set); | |
if (!success) { | |
return false; | |
} | |
overwrite(set); | |
return true; | |
} | |
void DescriptorWriter::overwrite(VkDescriptorSet &set) { | |
for (auto &write : writes) { | |
write.dstSet = set; | |
} | |
vkUpdateDescriptorSets(pool.Device.device(), writes.size(), writes.data(), 0, nullptr); | |
} | |
} // namespace mge |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "device.hpp" | |
// std | |
#include <memory> | |
#include <unordered_map> | |
#include <vector> | |
namespace mge{ | |
class DescriptorSetLayout { | |
public: | |
class Builder { | |
public: | |
Builder(Device &Device) : Device{Device} {} | |
Builder &addBinding( | |
uint32_t binding, | |
VkDescriptorType descriptorType, | |
VkShaderStageFlags stageFlags, | |
uint32_t count = 1); | |
std::unique_ptr<DescriptorSetLayout> build() const; | |
private: | |
Device &Device; | |
std::unordered_map<uint32_t, VkDescriptorSetLayoutBinding> bindings{}; | |
}; | |
DescriptorSetLayout( | |
Device &Device, std::unordered_map<uint32_t, VkDescriptorSetLayoutBinding> bindings); | |
~DescriptorSetLayout(); | |
DescriptorSetLayout(const DescriptorSetLayout &) = delete; | |
DescriptorSetLayout &operator=(const DescriptorSetLayout &) = delete; | |
VkDescriptorSetLayout getDescriptorSetLayout() const { return descriptorSetLayout; } | |
private: | |
Device &Device; | |
VkDescriptorSetLayout descriptorSetLayout; | |
std::unordered_map<uint32_t, VkDescriptorSetLayoutBinding> bindings; | |
friend class DescriptorWriter; | |
}; | |
class DescriptorPool { | |
public: | |
class Builder { | |
public: | |
Builder(Device &Device) : Device{Device} {} | |
Builder &addPoolSize(VkDescriptorType descriptorType, uint32_t count); | |
Builder &setPoolFlags(VkDescriptorPoolCreateFlags flags); | |
Builder &setMaxSets(uint32_t count); | |
std::unique_ptr<DescriptorPool> build() const; | |
private: | |
Device &Device; | |
std::vector<VkDescriptorPoolSize> poolSizes{}; | |
uint32_t maxSets = 1000; | |
VkDescriptorPoolCreateFlags poolFlags = 0; | |
}; | |
DescriptorPool( | |
Device &Device, | |
uint32_t maxSets, | |
VkDescriptorPoolCreateFlags poolFlags, | |
const std::vector<VkDescriptorPoolSize> &poolSizes); | |
~DescriptorPool(); | |
DescriptorPool(const DescriptorPool &) = delete; | |
DescriptorPool &operator=(const DescriptorPool &) = delete; | |
bool allocateDescriptor( | |
const VkDescriptorSetLayout descriptorSetLayout, VkDescriptorSet &descriptor) const; | |
void freeDescriptors(std::vector<VkDescriptorSet> &descriptors) const; | |
void resetPool(); | |
private: | |
Device &Device; | |
VkDescriptorPool descriptorPool; | |
friend class DescriptorWriter; | |
}; | |
class DescriptorWriter { | |
public: | |
DescriptorWriter(DescriptorSetLayout &setLayout, DescriptorPool &pool); | |
DescriptorWriter &writeBuffer(uint32_t binding, VkDescriptorBufferInfo *bufferInfo); | |
DescriptorWriter &writeImage(uint32_t binding, VkDescriptorImageInfo *imageInfo); | |
bool build(VkDescriptorSet &set); | |
void overwrite(VkDescriptorSet &set); | |
private: | |
DescriptorSetLayout &setLayout; | |
DescriptorPool &pool; | |
std::vector<VkWriteDescriptorSet> writes; | |
}; | |
} // namespace mge |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment