refactor(cleanup): shader/descriptor set helper

This commit is contained in:
PancakeTAS 2025-11-30 13:06:32 +01:00
parent aef82b01c7
commit 28ee6dbce0
No known key found for this signature in database
5 changed files with 262 additions and 1 deletions

View file

@ -1,6 +1,7 @@
set(BACKEND_SOURCES
"src/extraction/dll_reader.cpp"
"src/extraction/shader_registry.cpp")
"src/extraction/shader_registry.cpp"
"src/helpers/managed_shader.cpp")
add_library(lsfg-vk-backend STATIC ${BACKEND_SOURCES})

View file

@ -0,0 +1,120 @@
#include "managed_shader.hpp"
#include "lsfg-vk-common/vulkan/buffer.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include "lsfg-vk-common/vulkan/sampler.hpp"
#include "lsfg-vk-common/vulkan/shader.hpp"
#include "lsfg-vk-common/vulkan/vulkan.hpp"
#include <cstddef>
#include <functional>
#include <utility>
#include <vector>
#include <vulkan/vulkan_core.h>
using namespace ls;
ManagedShaderBuilder& ManagedShaderBuilder::sampled(const vk::Image& image) {
this->sampledImages.push_back(std::ref(image));
return *this;
}
ManagedShaderBuilder& ManagedShaderBuilder::sampleds(
const std::vector<vk::Image>& images,
size_t offset, size_t count) {
if (count == 0 || offset + count > images.size())
count = images.size() - offset;
for (size_t i = 0; i < count; ++i)
this->sampledImages.push_back(std::ref(images[offset + i]));
return *this;
}
ManagedShaderBuilder& ManagedShaderBuilder::storage(const vk::Image& image) {
this->storageImages.push_back(std::ref(image));
return *this;
}
ManagedShaderBuilder& ManagedShaderBuilder::storages(
const std::vector<vk::Image>& images,
size_t offset, size_t count) {
if (count == 0 || offset + count > images.size())
count = images.size() - offset;
for (size_t i = 0; i < count; ++i)
this->storageImages.push_back(std::ref(images[offset + i]));
return *this;
}
ManagedShaderBuilder& ManagedShaderBuilder::sampler(const vk::Sampler& sampler) {
this->imageSamplers.push_back(std::ref(sampler));
return *this;
}
ManagedShaderBuilder& ManagedShaderBuilder::samplers(
const std::vector<vk::Sampler>& samplers) {
for (const auto& sampler : samplers)
this->imageSamplers.push_back(std::ref(sampler));
return *this;
}
ManagedShaderBuilder& ManagedShaderBuilder::buffer(const vk::Buffer& buffer) {
this->constantBuffers.push_back(std::ref(buffer));
return *this;
}
ManagedShader ManagedShaderBuilder::build(const vk::Vulkan& vk,
const vk::Shader& shader) const {
std::vector<vk::Barrier> barriers;
barriers.reserve(this->storageImages.size() + this->sampledImages.size());
for (const auto& img : this->sampledImages)
barriers.push_back({
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.image = img.get().handle(),
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.levelCount = 1,
.layerCount = 1
}
});
for (const auto& img : this->storageImages)
barriers.push_back({
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.image = img.get().handle(),
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.levelCount = 1,
.layerCount = 1
}
});
return {
std::ref(shader),
std::move(barriers),
vk::DescriptorSet(vk, shader,
this->sampledImages,
this->storageImages,
this->imageSamplers,
this->constantBuffers)
};
}
void ManagedShader::dispatch(const vk::CommandBuffer& cmd,
VkExtent2D extent) const {
cmd.dispatch(this->shader,
this->descriptorSet,
this->barriers,
extent.width, extent.height, 1
);
}

View file

@ -0,0 +1,91 @@
#pragma once
#include "lsfg-vk-common/helpers/pointers.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/descriptor_set.hpp"
#include "lsfg-vk-common/vulkan/shader.hpp"
#include <cstddef>
#include <vector>
#include <vulkan/vulkan_core.h>
namespace ls {
/// managed shader handling dispatch and barriers
/// this class is NOT memory-safe
class ManagedShader {
friend class ManagedShaderBuilder;
public:
/// dispatch the managed shader
/// @param cmd command buffer to use
/// @param extent dispatch size
/// @throws ls::vulkan_error on failure
void dispatch(const vk::CommandBuffer& cmd, VkExtent2D extent) const;
private:
ls::R<const vk::Shader> shader;
std::vector<vk::Barrier> barriers;
vk::DescriptorSet descriptorSet;
// simple move constructor
ManagedShader(ls::R<const vk::Shader> shader,
std::vector<vk::Barrier> barriers,
vk::DescriptorSet descriptorSet) :
shader(shader),
barriers(std::move(barriers)),
descriptorSet(std::move(descriptorSet)) {
}
};
/// class for building managed shaders
/// this class is NOT memory-safe
class ManagedShaderBuilder {
public:
/// default constructor
ManagedShaderBuilder() = default;
/// add a sampled image
/// @param image image to add
[[nodiscard]] ManagedShaderBuilder& sampled(const vk::Image& image);
/// add multiple sampled images
/// @param images images to add
/// @param offset offset into images
/// @param count number of images to add (0 = all)
[[nodiscard]] ManagedShaderBuilder& sampleds(const std::vector<vk::Image>& images,
size_t offset = 0, size_t count = 0);
/// add a storage image
/// @param image image to add
[[nodiscard]] ManagedShaderBuilder& storage(const vk::Image& image);
/// add multiple storage images
/// @param images images to add
/// @param offset offset into images
/// @param count number of images to add (0 = all)
[[nodiscard]] ManagedShaderBuilder& storages(const std::vector<vk::Image>& images,
size_t offset = 0, size_t count = 0);
/// add a sampler
/// @param sampler sampler to add
[[nodiscard]] ManagedShaderBuilder& sampler(const vk::Sampler& sampler);
/// add multiple samplers
/// @param samplers samplers to add
[[nodiscard]] ManagedShaderBuilder& samplers(const std::vector<vk::Sampler>& samplers);
/// add a buffer
/// @param buffer buffer to add
[[nodiscard]] ManagedShaderBuilder& buffer(const vk::Buffer& buffer);
/// build the managed shader
/// @param vk the vulkan instance
/// @param shader the shader to use
/// @returns the built managed shader
[[nodiscard]] ManagedShader build(const vk::Vulkan& vk, const vk::Shader& shader) const;
private:
std::vector<ls::R<const vk::Image>> sampledImages;
std::vector<ls::R<const vk::Image>> storageImages;
std::vector<ls::R<const vk::Sampler>> imageSamplers;
std::vector<ls::R<const vk::Buffer>> constantBuffers;
};
}

View file

@ -1,11 +1,19 @@
#pragma once
#include "../helpers/pointers.hpp"
#include "descriptor_set.hpp"
#include "shader.hpp"
#include "vulkan.hpp"
#include <cstdint>
#include <vector>
#include <vulkan/vulkan_core.h>
namespace vk {
using Barrier = VkImageMemoryBarrier;
/// vulkan command buffer
class CommandBuffer {
public:
@ -14,6 +22,17 @@ namespace vk {
/// @throws ls::vulkan_error on failure
CommandBuffer(const vk::Vulkan& vk);
/// dispatch a compute shader
/// @param shader the compute shader
/// @param set the descriptor set
/// @param barriers image memory barriers to apply
/// @param x dispatch size in X
/// @param y dispatch size in Y
/// @param z dispatch size in Z
void dispatch(const vk::Shader& shader, const vk::DescriptorSet& set,
const std::vector<vk::Barrier>& barriers,
uint32_t x, uint32_t y, uint32_t z) const;
/// submit the command buffer
/// @throws ls::vulkan_error on failure
void submit(); // FIXME: method needs to actually submit, depending on needs

View file

@ -1,8 +1,13 @@
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/helpers/errors.hpp"
#include "lsfg-vk-common/helpers/pointers.hpp"
#include "lsfg-vk-common/vulkan/descriptor_set.hpp"
#include "lsfg-vk-common/vulkan/shader.hpp"
#include "lsfg-vk-common/vulkan/vulkan.hpp"
#include <cstdint>
#include <vector>
#include <vulkan/vulkan_core.h>
using namespace vk;
@ -43,6 +48,31 @@ CommandBuffer::CommandBuffer(const vk::Vulkan& vk)
throw ls::vulkan_error(res, "vkBeginCommandBuffer() failed");
}
void CommandBuffer::dispatch(const vk::Shader& shader,
const vk::DescriptorSet& set,
const std::vector<vk::Barrier>& barriers,
uint32_t x, uint32_t y, uint32_t z) const {
vkCmdPipelineBarrier(*this->commandBuffer,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0,
0, nullptr,
0, nullptr,
static_cast<uint32_t>(barriers.size()), barriers.data()
);
vkCmdBindPipeline(*this->commandBuffer,
VK_PIPELINE_BIND_POINT_COMPUTE,
shader.pipeline()
);
vkCmdBindDescriptorSets(*this->commandBuffer,
VK_PIPELINE_BIND_POINT_COMPUTE,
shader.pipelinelayout(),
0, 1, &set.handle(),
0, nullptr
);
vkCmdDispatch(*this->commandBuffer, x, y, z);
}
void CommandBuffer::submit() {
auto res = vkEndCommandBuffer(*this->commandBuffer);
if (res != VK_SUCCESS)