Skip to content

Commit

Permalink
Create builders for descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
Hjaltesorgenfrei committed Oct 3, 2022
1 parent 514f468 commit c9b8051
Show file tree
Hide file tree
Showing 8 changed files with 569 additions and 115 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,24 @@ Some ideas were also taken from [Zeux's blog](https://zeux.io/2020/02/27/writing
- [ ] Create a style to autoformat with
- [ ] Move swap chain to its own class
- [ ] Fix the hash for checking if vertices are equal.

### Descriptor Layout Idea

The DescriptorSet setup could work by creating DescriptorSetLayouts before.
Then validating the created DescriptorSets against a provided layout.
The DescriptorSetLayout could also have a builder
`.addBinding(uint32_t binding, vk::DescriptorType type, vk::ShaderStageFlags stageFlags, uint32t_t count = 1)`
If any binding has > 1 count, then it should be variable length and partially bound.
Only the last binding may have variable length, so this should also be checked. Maybe it should just be a flag?
[VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkDescriptorBindingFlagBits.html)

Using a buffer for the other locations might be a possibility to still add all material properties as bindless. But that is to be looked at.


Then the DescriptorBuilder would have
```cpp
DescriptorBuilder &bindBuffer(uint32_t binding, vk::DescriptorBufferInfo *bufferInfo, vk::DescriptorType type);
DescriptorBuilder &bindImage(uint32_t binding, vk::DescriptorImageInfo *imageInfo, vk::DescriptorType type);
DescriptorBuilder &bindImages(uint32_t binding, std::vector<vk::DescriptorImageInfo>& imageInfos, vk::DescriptorType type);
```
bindImages would also validate that the length is less than the max set in descriptor builder.
10 changes: 5 additions & 5 deletions src/AssetManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

std::shared_ptr<UploadedTexture> AssetManager::getTexture(std::string filename) {
std::shared_ptr<UploadedTexture> AssetManager::getTexture(const std::string& filename) {
if (uploadedTextures.find(filename) == uploadedTextures.end()) {
auto texture = std::make_shared<UploadedTexture>();
createTextureImage(filename.c_str(), texture);
Expand All @@ -15,7 +15,7 @@ std::shared_ptr<UploadedTexture> AssetManager::getTexture(std::string filename)
return uploadedTextures[filename];
}

void AssetManager::createTextureImage(const char *filename, std::shared_ptr<UploadedTexture> texture) {
void AssetManager::createTextureImage(const char *filename, const std::shared_ptr<UploadedTexture>& texture) {
int texWidth, texHeight, texChannels;
stbi_uc* pixels = stbi_load(filename, &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);

Expand Down Expand Up @@ -55,14 +55,14 @@ void AssetManager::createTextureImage(const char *filename, std::shared_ptr<Uplo
});
}

void AssetManager::createTextureImageView(std::shared_ptr<UploadedTexture> texture) {
void AssetManager::createTextureImageView(const std::shared_ptr<UploadedTexture>& texture) {
texture->textureImageView = createImageView(device->device(), texture->textureImage._image, vk::Format::eR8G8B8A8Srgb, vk::ImageAspectFlagBits::eColor, texture->mipLevels);
deletionQueue.push_function([&, texture]() {
device->device().destroyImageView(texture->textureImageView);
});
}

void AssetManager::createTextureSampler(std::shared_ptr<UploadedTexture> texture) {
void AssetManager::createTextureSampler(const std::shared_ptr<UploadedTexture>& texture) {
auto properties = device->physicalDevice().getProperties();

vk::SamplerCreateInfo samplerInfo{
Expand Down Expand Up @@ -120,7 +120,7 @@ AllocatedImage AssetManager::createImage(int width, int height, uint32_t mipLeve
.usage = VMA_MEMORY_USAGE_GPU_ONLY};

VkImage image;
VkImageCreateInfo imageInfoCreate = static_cast<VkImageCreateInfo>(imageInfo); // TODO: Add VMA HPP and fix this soup.
auto imageInfoCreate = static_cast<VkImageCreateInfo>(imageInfo); // TODO: Add VMA HPP and fix this soup.
if (vmaCreateImage(device->allocator(), &imageInfoCreate, &vmaAllocCreateInfo, &image, &allocatedImage._allocation, nullptr) != VK_SUCCESS) {
throw std::runtime_error("Failed to allocate image");
}
Expand Down
8 changes: 4 additions & 4 deletions src/AssetManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class AssetManager {
deletionQueue.flush();
}

std::shared_ptr<UploadedTexture> getTexture(std::string filename);
std::shared_ptr<UploadedTexture> getTexture(const std::string& filename);

[[nodiscard]] AllocatedImage createImage(int width, int height, uint32_t mipLevels, vk::SampleCountFlagBits numSamples, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags flags);

Expand All @@ -38,11 +38,11 @@ class AssetManager {
DeletionQueue deletionQueue{};
std::map<std::string, std::shared_ptr<UploadedTexture>> uploadedTextures;

void createTextureImage(const char* filename, std::shared_ptr<UploadedTexture> texture);
void createTextureImage(const char* filename, const std::shared_ptr<UploadedTexture>& texture);

void createTextureImageView(std::shared_ptr<UploadedTexture> texture);
void createTextureImageView(const std::shared_ptr<UploadedTexture>& texture);

void createTextureSampler(std::shared_ptr<UploadedTexture> texture);
void createTextureSampler(const std::shared_ptr<UploadedTexture>& texture);

template <typename T>
[[nodiscard]] AllocatedBuffer stageData(std::span<T>& dataToStage);
Expand Down
138 changes: 41 additions & 97 deletions src/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ Renderer::Renderer(std::shared_ptr<WindowWrapper> window, std::shared_ptr<Vulkan
: window(window), device{device}, assetManager(assetManager) {
this->renderData = renderData;
try {
descriptorAllocator.init(device->device());
descriptorLayoutCache.init(device->device());
mainDeletionQueue.push_function([&](){
descriptorLayoutCache.cleanup();
descriptorAllocator.cleanup();
});
createSwapChain();
createImageViews();
createRenderPass();
createDescriptorSetLayout();
createTextureDescriptorSetLayout();
createGlobalDescriptorSetLayout();
createMaterialDescriptorSetLayout();
createGraphicsPipelineLayout();
createGraphicsPipeline();
createCommandPool();
Expand Down Expand Up @@ -80,8 +86,26 @@ Material Renderer::createMaterial(std::vector<std::string>& texturePaths) {
textures.push_back(assetManager.getTexture(filename));
}

Material material{};
material.textureSet = createTextureDescriptorSet(textures);

std::vector<vk::DescriptorImageInfo> imageInfos;
for (const auto& texture : textures) {
vk::DescriptorImageInfo imageInfo {
.sampler = texture->textureSampler,
.imageView = texture->textureImageView,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
};
imageInfos.push_back(imageInfo);
}

Material material{};

auto textureResult = DescriptorSetBuilder::begin(materialDescriptorSetLayout, &descriptorAllocator)
.bindImages(0, imageInfos, vk::DescriptorType::eCombinedImageSampler)
.build(material.textureSet);

if(!textureResult) {
throw std::runtime_error("Failed to create Material");
}

return material;
}
Expand Down Expand Up @@ -372,72 +396,36 @@ void Renderer::createRenderPass() {

}

void Renderer::createDescriptorSetLayout() {
vk::DescriptorSetLayoutBinding uboLayoutBinding {
.binding = 0,
.descriptorType = vk::DescriptorType::eUniformBuffer,
.descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eAllGraphics,
.pImmutableSamplers = nullptr
};
void Renderer::createGlobalDescriptorSetLayout() {
auto success = DescriptorSetLayoutBuilder::begin(&descriptorLayoutCache)
.addBinding(0, vk::DescriptorType::eUniformBuffer, vk::ShaderStageFlagBits::eAllGraphics)
.build(uboDescriptorSetLayout);

std::array<vk::DescriptorSetLayoutBinding, 1> bindings = {uboLayoutBinding};

vk::DescriptorSetLayoutCreateInfo layoutInfo {
.bindingCount = static_cast<uint32_t>(bindings.size()),
.pBindings = bindings.data()
};

if(device->device().createDescriptorSetLayout(&layoutInfo, nullptr, &uboDescriptorSetLayout) != vk::Result::eSuccess) {
if(!success) {
throw std::runtime_error("Failed to create descriptor set layout");
}
mainDeletionQueue.push_function([&]() {
device->device().destroyDescriptorSetLayout(uboDescriptorSetLayout);
});
}

void Renderer::createTextureDescriptorSetLayout() {
vk::DescriptorSetLayoutBinding samplerLayoutBinding {
.binding = 0,
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = 256,
.stageFlags = vk::ShaderStageFlagBits::eFragment,
.pImmutableSamplers = nullptr
};

std::array<vk::DescriptorSetLayoutBinding, 1> bindings = {samplerLayoutBinding};

std::array<vk::DescriptorBindingFlags, 1> flags = {vk::DescriptorBindingFlagBits::eVariableDescriptorCount | vk::DescriptorBindingFlagBits::ePartiallyBound};

vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlags {
.bindingCount = static_cast<uint32_t>(bindings.size()),
.pBindingFlags = flags.data()
};

vk::DescriptorSetLayoutCreateInfo layoutInfo {
.pNext = &bindingFlags,
.bindingCount = static_cast<uint32_t>(bindings.size()),
.pBindings = bindings.data()
};
void Renderer::createMaterialDescriptorSetLayout() {
auto success = DescriptorSetLayoutBuilder::begin(&descriptorLayoutCache)
.addBinding(0, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment ,256, vk::DescriptorBindingFlagBits::ePartiallyBound)
.build(materialDescriptorSetLayout);

if(device->device().createDescriptorSetLayout(&layoutInfo, nullptr, &textureDescriptorSetLayout) != vk::Result::eSuccess) {
throw std::runtime_error("Failed to create texture descriptor set layout");
}
mainDeletionQueue.push_function([&]() {
device->device().destroyDescriptorSetLayout(textureDescriptorSetLayout);
});
if(!success) {
throw std::runtime_error("Failed to create Material descriptor set layout");
}
}



void Renderer::createGraphicsPipelineLayout() {
vk::PushConstantRange pushConstantRange {
.stageFlags = vk::ShaderStageFlagBits::eVertex,
.offset = 0,
.size = sizeof(MeshPushConstants)
};

std::array<vk::DescriptorSetLayout, 2> descriptorSetLayouts = {uboDescriptorSetLayout, textureDescriptorSetLayout};
std::array<vk::DescriptorSetLayout, 2> descriptorSetLayouts = {uboDescriptorSetLayout, materialDescriptorSetLayout};

vk::PipelineLayoutCreateInfo pipelineLayoutInfo {
.setLayoutCount = static_cast<uint32_t>(descriptorSetLayouts.size()),
Expand Down Expand Up @@ -901,50 +889,6 @@ void Renderer::createDescriptorSets() {
}
}

vk::DescriptorSet Renderer::createTextureDescriptorSet(std::vector<std::shared_ptr<UploadedTexture>>& textures) {
uint32_t counts[1];
counts[0] = static_cast<uint32_t>(textures.size());

vk::DescriptorSetVariableDescriptorCountAllocateInfo setCounts = {
.descriptorSetCount = 1,
.pDescriptorCounts = counts
};

vk::DescriptorSetAllocateInfo textureAllocInfo {
.pNext = &setCounts,
.descriptorPool = descriptorPool,
.descriptorSetCount = 1,
.pSetLayouts = &textureDescriptorSetLayout
};

vk::DescriptorSet textureSet{};
if(device->device().allocateDescriptorSets(&textureAllocInfo, &textureSet) != vk::Result::eSuccess) {
throw std::runtime_error("Failed to create Texture Descriptor set!");
}

std::vector<vk::DescriptorImageInfo> imageInfos;
for (const auto& texture : textures) {
vk::DescriptorImageInfo imageInfo {
.sampler = texture->textureSampler,
.imageView = texture->textureImageView,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
};
imageInfos.push_back(imageInfo);
}

vk::WriteDescriptorSet imageDescriptor {
.dstSet = textureSet,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = static_cast<uint32_t>(imageInfos.size()),
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.pImageInfo = imageInfos.data(),
};

device->device().updateDescriptorSets(1, &imageDescriptor, 0, nullptr);
return textureSet;
}

void Renderer::copyBuffer(vk::Buffer srcBuffer, vk::Buffer dstBuffer, vk::DeviceSize size) {
device->immediateSubmit([&](vk::CommandBuffer cmd){
vk::BufferCopy copyRegion{
Expand Down
19 changes: 10 additions & 9 deletions src/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "RenderData.h"
#include "VkTypes.h"
#include "VulkanDevice.h"
#include "VkDescriptors.h"

const int MAX_FRAMES_IN_FLIGHT = 2;

Expand All @@ -27,8 +28,10 @@ class Renderer {
public:
Renderer(std::shared_ptr<WindowWrapper> window, std::shared_ptr<VulkanDevice> device, AssetManager &assetManager,
std::shared_ptr<RenderData> &renderData);

~Renderer();
Renderer& operator=(const Renderer&) = delete;
Renderer(const Renderer&) = delete;

void drawFrame();
void frameBufferResized();
Material createMaterial(std::vector<std::string>& texturePaths);
Expand All @@ -52,12 +55,15 @@ class Renderer {
std::vector<vk::ImageView> swapChainImageViews;
std::vector<vk::Framebuffer> swapChainFramebuffers;

vk::DescriptorSetLayout textureDescriptorSetLayout;
vk::DescriptorSetLayout materialDescriptorSetLayout;
vk::DescriptorSetLayout uboDescriptorSetLayout;
std::vector<vk::DescriptorSet> descriptorSets;
vk::DescriptorPool descriptorPool;
vk::RenderPass renderPass;

DescriptorAllocator descriptorAllocator;
DescriptorLayoutCache descriptorLayoutCache;

vk::PipelineLayout pipelineLayout;
vk::Pipeline graphicsPipeline;

Expand All @@ -84,9 +90,6 @@ class Renderer {

bool frameBufferResizePending = false;

Renderer& operator=(const Renderer&) = delete;
Renderer(const Renderer&) = delete;

void initImgui();

void createSwapChain();
Expand All @@ -102,7 +105,8 @@ class Renderer {
void createImageViews();

void createRenderPass();
void createDescriptorSetLayout();
void createGlobalDescriptorSetLayout();
void createMaterialDescriptorSetLayout();

void createGraphicsPipelineLayout();
void createGraphicsPipeline();
Expand All @@ -125,9 +129,6 @@ class Renderer {
template <typename T>
AllocatedBuffer uploadBuffer(std::vector<T>& meshData, VkBufferUsageFlags usage);

void createTextureDescriptorSetLayout();
vk::DescriptorSet createTextureDescriptorSet(std::vector<std::shared_ptr<UploadedTexture>>& texture);

void transitionImageLayout(vk::Image image, vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout, uint32_t mipLevels);

void createUniformBuffers();
Expand Down
Loading

0 comments on commit c9b8051

Please sign in to comment.