more refactors and fixes

This commit is contained in:
PancakeTAS 2025-06-30 06:52:42 +02:00
parent 50f5153374
commit faff05fb4f
No known key found for this signature in database
18 changed files with 364 additions and 248 deletions

View file

@ -77,6 +77,7 @@ namespace Vulkan::Core {
DescriptorSetUpdateBuilder& add(VkDescriptorType type, const Image& image);
DescriptorSetUpdateBuilder& add(VkDescriptorType type, const Sampler& sampler);
DescriptorSetUpdateBuilder& add(VkDescriptorType type, const Buffer& buffer);
DescriptorSetUpdateBuilder& add(VkDescriptorType type); // empty entry
/// Add a list of resources to the descriptor set update.
DescriptorSetUpdateBuilder& add(VkDescriptorType type, const std::vector<Image>& images) {
@ -97,6 +98,14 @@ namespace Vulkan::Core {
DescriptorSetUpdateBuilder& add(VkDescriptorType type, const std::array<Buffer, N>& buffers) {
for (const auto& buffer : buffers) this->add(type, buffer); return *this; }
/// Add an optional resource to the descriptor set update.
DescriptorSetUpdateBuilder& add(VkDescriptorType type, const std::optional<Image>& image) {
if (image.has_value()) this->add(type, *image); return *this; }
DescriptorSetUpdateBuilder& add(VkDescriptorType type, const std::optional<Sampler>& sampler) {
if (sampler.has_value()) this->add(type, *sampler); return *this; }
DescriptorSetUpdateBuilder& add(VkDescriptorType type, const std::optional<Buffer>& buffer) {
if (buffer.has_value()) this->add(type, *buffer); return *this; }
/// Finish building the descriptor set update.
void build() const;
private:

View file

@ -9,6 +9,8 @@
#include "core/shadermodule.hpp"
#include "device.hpp"
#include <array>
namespace Vulkan::Shaderchains {
///
@ -28,7 +30,7 @@ namespace Vulkan::Shaderchains {
/// @throws ls::vulkan_error if resource creation fails.
///
Alpha(const Device& device, const Core::DescriptorPool& pool,
const Core::Image& inImg);
Core::Image inImg);
///
/// Dispatch the shaderchain.
@ -49,17 +51,17 @@ namespace Vulkan::Shaderchains {
Alpha& operator=(Alpha&&) noexcept = default;
~Alpha() = default;
private:
std::vector<Core::ShaderModule> shaderModules{4};
std::vector<Core::Pipeline> pipelines{4};
std::vector<Core::DescriptorSet> descriptorSets{4};
std::array<Core::ShaderModule, 4> shaderModules;
std::array<Core::Pipeline, 4> pipelines;
std::array<Core::DescriptorSet, 4> descriptorSets;
Core::Image inImg;
std::vector<Core::Image> tempImgs1{2}; // half-size
std::vector<Core::Image> tempImgs2{2}; // half-size
std::vector<Core::Image> tempImgs3{4}; // quarter-size
std::array<Core::Image, 2> tempImgs1; // half-size
std::array<Core::Image, 2> tempImgs2; // half-size
std::array<Core::Image, 4> tempImgs3; // quarter-size
std::vector<Core::Image> outImgs{4}; // quarter-size
std::array<Core::Image, 4> outImgs; // quarter-size
};
}

View file

@ -10,6 +10,8 @@
#include "core/shadermodule.hpp"
#include "device.hpp"
#include <array>
namespace Vulkan::Shaderchains {
///
@ -31,8 +33,8 @@ namespace Vulkan::Shaderchains {
/// @throws ls::vulkan_error if resource creation fails.
///
Beta(const Device& device, const Core::DescriptorPool& pool,
const std::vector<Core::Image>& temporalImgs,
const std::vector<Core::Image>& inImgs);
std::array<Core::Image, 8> temporalImgs,
std::array<Core::Image, 4> inImgs);
///
/// Dispatch the shaderchain.
@ -53,18 +55,18 @@ namespace Vulkan::Shaderchains {
Beta& operator=(Beta&&) noexcept = default;
~Beta() = default;
private:
std::vector<Core::ShaderModule> shaderModules{5};
std::vector<Core::Pipeline> pipelines{5};
std::vector<Core::DescriptorSet> descriptorSets{5};
std::array<Core::ShaderModule, 5> shaderModules;
std::array<Core::Pipeline, 5> pipelines;
std::array<Core::DescriptorSet, 5> descriptorSets;
Core::Buffer buffer;
std::vector<Core::Image> temporalImgs{8};
std::vector<Core::Image> inImgs{4};
std::array<Core::Image, 8> temporalImgs;
std::array<Core::Image, 4> inImgs;
std::vector<Core::Image> tempImgs1{2};
std::vector<Core::Image> tempImgs2{2};
std::array<Core::Image, 2> tempImgs1;
std::array<Core::Image, 2> tempImgs2;
std::vector<Core::Image> outImgs{6};
std::array<Core::Image, 6> outImgs;
};
}

View file

@ -10,6 +10,8 @@
#include "core/shadermodule.hpp"
#include "device.hpp"
#include <array>
namespace Vulkan::Shaderchains {
///
@ -31,8 +33,8 @@ namespace Vulkan::Shaderchains {
/// @throws ls::vulkan_error if resource creation fails.
///
Delta(const Device& device, const Core::DescriptorPool& pool,
const std::vector<Core::Image>& inImgs,
const std::optional<Core::Image>& optImg);
std::array<Core::Image, 2> inImgs,
std::optional<Core::Image> optImg);
///
/// Dispatch the shaderchain.
@ -53,16 +55,16 @@ namespace Vulkan::Shaderchains {
Delta& operator=(Delta&&) noexcept = default;
~Delta() = default;
private:
std::vector<Core::ShaderModule> shaderModules{4};
std::vector<Core::Pipeline> pipelines{4};
std::vector<Core::DescriptorSet> descriptorSets{4};
std::array<Core::ShaderModule, 4> shaderModules;
std::array<Core::Pipeline, 4> pipelines;
std::array<Core::DescriptorSet, 4> descriptorSets;
Core::Buffer buffer;
std::vector<Core::Image> inImg{2};
std::array<Core::Image, 2> inImg;
std::optional<Core::Image> optImg;
std::vector<Core::Image> tempImgs1{2};
std::vector<Core::Image> tempImgs2{2};
std::array<Core::Image, 2> tempImgs1;
std::array<Core::Image, 2> tempImgs2;
Core::Image outImg;
};

View file

@ -10,6 +10,8 @@
#include "core/shadermodule.hpp"
#include "device.hpp"
#include <array>
namespace Vulkan::Shaderchains {
///
@ -29,7 +31,7 @@ namespace Vulkan::Shaderchains {
/// @throws ls::vulkan_error if resource creation fails.
///
Downsample(const Device& device, const Core::DescriptorPool& pool,
const Core::Image& inImg);
Core::Image inImg);
///
/// Dispatch the shaderchain.
@ -57,7 +59,7 @@ namespace Vulkan::Shaderchains {
Core::Image inImg;
std::vector<Core::Image> outImgs{7};
std::array<Core::Image, 7> outImgs;
};
}

View file

@ -10,6 +10,8 @@
#include "core/shadermodule.hpp"
#include "device.hpp"
#include <array>
namespace Vulkan::Shaderchains {
///
@ -32,9 +34,9 @@ namespace Vulkan::Shaderchains {
/// @throws ls::vulkan_error if resource creation fails.
///
Epsilon(const Device& device, const Core::DescriptorPool& pool,
const std::vector<Core::Image>& inImgs1,
const Core::Image& inImg2,
const std::optional<Core::Image>& optImg);
std::array<Core::Image, 3> inImgs1,
Core::Image inImg2,
std::optional<Core::Image> optImg);
///
/// Dispatch the shaderchain.
@ -55,17 +57,17 @@ namespace Vulkan::Shaderchains {
Epsilon& operator=(Epsilon&&) noexcept = default;
~Epsilon() = default;
private:
std::vector<Core::ShaderModule> shaderModules{4};
std::vector<Core::Pipeline> pipelines{4};
std::vector<Core::DescriptorSet> descriptorSets{4};
std::array<Core::ShaderModule, 4> shaderModules;
std::array<Core::Pipeline, 4> pipelines;
std::array<Core::DescriptorSet, 4> descriptorSets;
Core::Buffer buffer;
std::vector<Core::Image> inImgs1{3};
std::array<Core::Image, 3> inImgs1;
Core::Image inImg2;
std::optional<Core::Image> optImg;
std::vector<Core::Image> tempImgs1{4};
std::vector<Core::Image> tempImgs2{4};
std::array<Core::Image, 4> tempImgs1;
std::array<Core::Image, 4> tempImgs2;
Core::Image outImg;
};

View file

@ -9,7 +9,6 @@
#include "core/pipeline.hpp"
#include "core/shadermodule.hpp"
#include "device.hpp"
#include <vulkan/vulkan_core.h>
namespace Vulkan::Shaderchains {

View file

@ -10,6 +10,8 @@
#include "core/shadermodule.hpp"
#include "device.hpp"
#include <array>
namespace Vulkan::Shaderchains {
///
@ -37,11 +39,11 @@ namespace Vulkan::Shaderchains {
/// @throws ls::vulkan_error if resource creation fails.
///
Gamma(const Device& device, const Core::DescriptorPool& pool,
const std::vector<Core::Image>& temporalImgs,
const std::vector<Core::Image>& inImgs1,
const Core::Image& inImg2,
const std::optional<Core::Image>& optImg1,
const std::optional<Core::Image>& optImg2,
std::array<Core::Image, 4> temporalImgs,
std::array<Core::Image, 4> inImgs1,
Core::Image inImg2,
std::optional<Core::Image> optImg1,
std::optional<Core::Image> optImg2,
VkExtent2D outExtent);
///
@ -65,19 +67,19 @@ namespace Vulkan::Shaderchains {
Gamma& operator=(Gamma&&) noexcept = default;
~Gamma() = default;
private:
std::vector<Core::ShaderModule> shaderModules{6};
std::vector<Core::Pipeline> pipelines{6};
std::vector<Core::DescriptorSet> descriptorSets{6};
std::array<Core::ShaderModule, 6> shaderModules;
std::array<Core::Pipeline, 6> pipelines;
std::array<Core::DescriptorSet, 6> descriptorSets;
Core::Buffer buffer;
std::vector<Core::Image> temporalImgs{4};
std::vector<Core::Image> inImgs1{4};
std::array<Core::Image, 4> temporalImgs;
std::array<Core::Image, 4> inImgs1;
Core::Image inImg2;
Core::Image optImg1; // specified or created black
std::optional<Core::Image> optImg2;
std::vector<Core::Image> tempImgs1{4};
std::vector<Core::Image> tempImgs2{4};
std::array<Core::Image, 4> tempImgs1;
std::array<Core::Image, 4> tempImgs2;
Core::Image whiteImg;
Core::Image outImg1;

View file

@ -10,6 +10,8 @@
#include "core/shadermodule.hpp"
#include "device.hpp"
#include <array>
namespace Vulkan::Shaderchains {
///
@ -34,11 +36,11 @@ namespace Vulkan::Shaderchains {
/// @throws ls::vulkan_error if resource creation fails.
///
Magic(const Device& device, const Core::DescriptorPool& pool,
const std::vector<Core::Image>& temporalImgs,
const std::vector<Core::Image>& inImgs1,
std::array<Core::Image, 4>& temporalImgs,
std::array<Core::Image, 4>& inImgs1,
Core::Image inImg2,
Core::Image inImg3,
const std::optional<Core::Image>& optImg);
std::optional<Core::Image> optImg);
///
/// Dispatch the shaderchain.
@ -68,15 +70,15 @@ namespace Vulkan::Shaderchains {
Core::DescriptorSet descriptorSet;
Core::Buffer buffer;
std::vector<Core::Image> temporalImgs{4};
std::vector<Core::Image> inImgs1{4};
std::array<Core::Image, 4> temporalImgs;
std::array<Core::Image, 4> inImgs1;
Core::Image inImg2;
Core::Image inImg3;
std::optional<Core::Image> optImg;
std::vector<Core::Image> outImgs1{3};
std::vector<Core::Image> outImgs2{3};
std::vector<Core::Image> outImgs3{3};
std::array<Core::Image, 3> outImgs1;
std::array<Core::Image, 3> outImgs2;
std::array<Core::Image, 3> outImgs3;
};
}

View file

@ -10,6 +10,8 @@
#include "core/shadermodule.hpp"
#include "device.hpp"
#include <array>
namespace Vulkan::Shaderchains {
///
@ -32,9 +34,9 @@ namespace Vulkan::Shaderchains {
/// @throws ls::vulkan_error if resource creation fails.
///
Zeta(const Device& device, const Core::DescriptorPool& pool,
const std::vector<Core::Image>& inImgs1,
const Core::Image& inImg2,
const Core::Image& inImg3);
std::array<Core::Image, 3> inImgs1,
Core::Image inImg2,
Core::Image inImg3);
///
/// Dispatch the shaderchain.
@ -55,17 +57,17 @@ namespace Vulkan::Shaderchains {
Zeta& operator=(Zeta&&) noexcept = default;
~Zeta() = default;
private:
std::vector<Core::ShaderModule> shaderModules{4};
std::vector<Core::Pipeline> pipelines{4};
std::vector<Core::DescriptorSet> descriptorSets{4};
std::array<Core::ShaderModule, 4> shaderModules;
std::array<Core::Pipeline, 4> pipelines;
std::array<Core::DescriptorSet, 4> descriptorSets;
Core::Buffer buffer;
std::vector<Core::Image> inImgs1{3};
std::array<Core::Image, 3> inImgs1;
Core::Image inImg2;
Core::Image inImg3;
std::vector<Core::Image> tempImgs1{4};
std::vector<Core::Image> tempImgs2{4};
std::array<Core::Image, 4> tempImgs1;
std::array<Core::Image, 4> tempImgs2;
Core::Image outImg;
};

View file

@ -4,6 +4,7 @@
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include "core/sampler.hpp"
#include "device.hpp"
#include <stdexcept>
#include <string>
@ -14,16 +15,47 @@ namespace Vulkan::Utils {
///
/// Insert memory barriers for images in a command buffer.
///
/// @param buffer Command buffer to insert barriers into
/// @param r2wImages Images that are being read and will be written to
/// @param w2rImages Images that are being written to and will be read from
///
/// @throws std::logic_error if the command buffer is not in Recording state
///
void insertBarrier(
const Vulkan::Core::CommandBuffer& buffer,
std::vector<Vulkan::Core::Image> w2rImages,
std::vector<Vulkan::Core::Image> r2wImages);
class BarrierBuilder {
public:
/// Create a barrier builder.
BarrierBuilder(const Core::CommandBuffer& buffer)
: commandBuffer(&buffer) {
this->barriers.reserve(16); // this is performance critical
}
// Add a resource to the barrier builder.
BarrierBuilder& addR2W(Core::Image& image);
BarrierBuilder& addW2R(Core::Image& image);
// Add an optional resource to the barrier builder.
BarrierBuilder& addR2W(std::optional<Core::Image>& image) {
if (image.has_value()) this->addR2W(*image); return *this; }
BarrierBuilder& addW2R(std::optional<Core::Image>& image) {
if (image.has_value()) this->addW2R(*image); return *this; }
/// Add a list of resources to the barrier builder.
BarrierBuilder& addR2W(std::vector<Core::Image>& images) {
for (auto& image : images) this->addR2W(image); return *this; }
BarrierBuilder& addW2R(std::vector<Core::Image>& images) {
for (auto& image : images) this->addW2R(image); return *this; }
/// Add an array of resources to the barrier builder.
template<std::size_t N>
BarrierBuilder& addR2W(std::array<Core::Image, N>& images) {
for (auto& image : images) this->addR2W(image); return *this; }
template<std::size_t N>
BarrierBuilder& addW2R(std::array<Core::Image, N>& images) {
for (auto& image : images) this->addW2R(image); return *this; }
/// Finish building the barrier
void build() const;
private:
const Core::CommandBuffer* commandBuffer;
std::vector<VkImageMemoryBarrier2> barriers;
};
///
/// Upload a DDS file to a Vulkan image.
@ -36,9 +68,19 @@ namespace Vulkan::Utils {
/// @throws std::system_error If the file cannot be opened or read.
/// @throws ls:vulkan_error If the Vulkan image cannot be created or updated.
///
void uploadImage(const Vulkan::Device& device,
const Vulkan::Core::CommandPool& commandPool,
Vulkan::Core::Image& image, const std::string& path);
void uploadImage(const Device& device,
const Core::CommandPool& commandPool,
Core::Image& image, const std::string& path);
///
/// Clear a texture to white during setup.
///
/// @param device The Vulkan device.
/// @param image The image to clear.
///
/// @throws ls::vulkan_error If the Vulkan image cannot be cleared.
///
void clearWhiteImage(const Device& device, Core::Image& image);
}

View file

@ -87,6 +87,19 @@ DescriptorSetUpdateBuilder& DescriptorSetUpdateBuilder::add(VkDescriptorType typ
return *this;
}
DescriptorSetUpdateBuilder& DescriptorSetUpdateBuilder::add(VkDescriptorType type) {
this->entries.push_back({
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = this->descriptorSet->handle(),
.dstBinding = static_cast<uint32_t>(this->entries.size()),
.descriptorCount = 0,
.descriptorType = type,
.pImageInfo = nullptr,
.pBufferInfo = nullptr
});
return *this;
}
void DescriptorSetUpdateBuilder::build() const {
if (this->entries.empty()) return;

View file

@ -4,7 +4,8 @@
using namespace Vulkan::Shaderchains;
Alpha::Alpha(const Device& device, const Core::DescriptorPool& pool,
const Core::Image& inImage) : inImage(inImage) {
Core::Image inImg)
: inImg(std::move(inImg)) {
this->shaderModules = {{
Core::ShaderModule(device, "rsc/shaders/alpha/0.spv",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
@ -30,32 +31,37 @@ Alpha::Alpha(const Device& device, const Core::DescriptorPool& pool,
this->shaderModules.at(i));
}
auto extent = inImage.getExtent();
auto halfWidth = (extent.width + 1) >> 1;
auto halfHeight = (extent.height + 1) >> 1;
auto quarterWidth = (extent.width + 3) >> 2;
auto quarterHeight = (extent.height + 3) >> 2;
const auto extent = this->inImg.getExtent();
const VkExtent2D halfExtent = {
.width = (extent.width + 1) >> 1,
.height = (extent.height + 1) >> 1
};
for (size_t i = 0; i < 2; i++) {
this->tempTex1.at(i) = Core::Image(device,
{ halfWidth, halfHeight },
this->tempImgs1.at(i) = Core::Image(device,
halfExtent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
this->tempTex2.at(i) = Core::Image(device,
{ halfWidth, halfHeight },
this->tempImgs2.at(i) = Core::Image(device,
halfExtent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
}
const VkExtent2D quarterExtent = {
.width = (extent.width + 3) >> 2,
.height = (extent.height + 3) >> 2
};
for (size_t i = 0; i < 4; i++) {
this->tempTex3.at(i) = Core::Image(device,
{ quarterWidth, quarterHeight },
this->tempImgs3.at(i) = Core::Image(device,
quarterExtent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
this->outImages.at(i) = Core::Image(device,
{ quarterWidth, quarterHeight },
this->outImgs.at(i) = Core::Image(device,
quarterExtent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
@ -63,79 +69,73 @@ Alpha::Alpha(const Device& device, const Core::DescriptorPool& pool,
this->descriptorSets.at(0).update(device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, Globals::samplerClampBorder)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, inImage)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempTex1)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1)
.build();
this->descriptorSets.at(1).update(device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, Globals::samplerClampBorder)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempTex1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempTex2)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
this->descriptorSets.at(2).update(device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, Globals::samplerClampBorder)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempTex2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempTex3)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs3)
.build();
this->descriptorSets.at(3).update(device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, Globals::samplerClampBorder)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempTex3)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImages)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs3)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs)
.build();
}
void Alpha::Dispatch(const Core::CommandBuffer& buf) {
const auto halfExtent = this->tempTex1.at(0).getExtent();
const auto quarterExtent = this->tempTex3.at(0).getExtent();
const auto halfExtent = this->tempImgs1.at(0).getExtent();
const auto quarterExtent = this->tempImgs3.at(0).getExtent();
// first pass
Utils::insertBarrier(
buf,
{ this->inImage },
this->tempTex1
);
uint32_t threadsX = (halfExtent.width + 7) >> 3;
uint32_t threadsY = (halfExtent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->inImg)
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(0).bind(buf);
this->descriptorSets.at(0).bind(buf, this->pipelines.at(0));
uint32_t threadsX = (halfExtent.width + 7) >> 3;
uint32_t threadsY = (halfExtent.height + 7) >> 3;
buf.dispatch(threadsX, threadsY, 1);
// second pass
Utils::insertBarrier(
buf,
this->tempTex1,
this->tempTex2
);
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(1).bind(buf);
this->descriptorSets.at(1).bind(buf, this->pipelines.at(1));
buf.dispatch(threadsX, threadsY, 1);
// third pass
Utils::insertBarrier(
buf,
this->tempTex2,
this->tempTex3
);
threadsX = (quarterExtent.width + 7) >> 3;
threadsY = (quarterExtent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->tempImgs3)
.build();
this->pipelines.at(2).bind(buf);
this->descriptorSets.at(2).bind(buf, this->pipelines.at(2));
threadsX = (quarterExtent.width + 7) >> 3;
threadsY = (quarterExtent.height + 7) >> 3;
buf.dispatch(threadsX, threadsY, 1);
// fourth pass
Utils::insertBarrier(
buf,
this->tempTex3,
this->outImages
);
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs3)
.addR2W(this->outImgs)
.build();
this->pipelines.at(3).bind(buf);
this->descriptorSets.at(3).bind(buf, this->pipelines.at(3));
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -4,8 +4,8 @@
using namespace Vulkan::Shaderchains;
Downsample::Downsample(const Device& device, const Core::DescriptorPool& pool,
const Core::Image& inImage) : inImage(inImage) {
// create internal resources
Core::Image inImg)
: inImg(std::move(inImg)) {
this->shaderModule = Core::ShaderModule(device, "rsc/shaders/downsample.spv",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
@ -13,39 +13,35 @@ Downsample::Downsample(const Device& device, const Core::DescriptorPool& pool,
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER } });
this->pipeline = Core::Pipeline(device, this->shaderModule);
this->descriptorSet = Core::DescriptorSet(device, pool, this->shaderModule);
this->buffer = Core::Buffer(device, Globals::fgBuffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
const Globals::FgBuffer data = Globals::fgBuffer;
this->buffer = Core::Buffer(device, data, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
auto extent = inImage.getExtent();
// create output images
auto extent = this->inImg.getExtent();
for (size_t i = 0; i < 7; i++)
this->outImages.at(i) = Core::Image(device,
this->outImgs.at(i) = Core::Image(device,
{ extent.width >> i, extent.height >> i },
VK_FORMAT_R8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
// update descriptor set
this->descriptorSet.update(device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, Globals::samplerClampBorder)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, inImage)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImages)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, this->buffer)
.build();
}
void Downsample::Dispatch(const Core::CommandBuffer& buf) {
auto extent = inImage.getExtent();
auto extent = this->inImg.getExtent();
// first pass
const uint32_t threadsX = (extent.width + 63) >> 6;
const uint32_t threadsY = (extent.height + 63) >> 6;
Utils::insertBarrier(
buf,
{ this->inImage },
this->outImages
);
Utils::BarrierBuilder(buf)
.addW2R(this->inImg)
.addR2W(this->outImgs)
.build();
this->pipeline.bind(buf);
this->descriptorSet.bind(buf, this->pipeline);

View file

@ -1,6 +1,5 @@
#include "shaderchains/extract.hpp"
#include "utils.hpp"
#include <vulkan/vulkan_core.h>
using namespace Vulkan::Shaderchains;
@ -10,7 +9,6 @@ Extract::Extract(const Device& device, const Core::DescriptorPool& pool,
VkExtent2D outExtent)
: inImg1(std::move(inImg1)),
inImg2(std::move(inImg2)) {
// create internal resources
this->shaderModule = Core::ShaderModule(device, "rsc/shaders/extract.spv",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
@ -18,24 +16,19 @@ Extract::Extract(const Device& device, const Core::DescriptorPool& pool,
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER } });
this->pipeline = Core::Pipeline(device, this->shaderModule);
this->descriptorSet = Core::DescriptorSet(device, pool, this->shaderModule);
const Globals::FgBuffer data = Globals::fgBuffer;
this->buffer = Core::Buffer(device, data, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
this->buffer = Core::Buffer(device, Globals::fgBuffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
this->whiteImg = Core::Image(device,
{ outExtent.width, outExtent.height },
outExtent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
// create output images
this->outImg = Core::Image(device,
{ outExtent.width, outExtent.height },
outExtent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
// update descriptor set
this->descriptorSet.update(device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, Globals::samplerClampBorder)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->whiteImg)
@ -44,20 +37,24 @@ Extract::Extract(const Device& device, const Core::DescriptorPool& pool,
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImg)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, this->buffer)
.build();
// clear white image
Utils::clearWhiteImage(device, this->whiteImg);
}
void Extract::Dispatch(const Core::CommandBuffer& buf) {
auto extent = this->whiteImg.getExtent();
// first pass
const uint32_t threadsX = (extent.width + 7) >> 3;
const uint32_t threadsY = (extent.height + 7) >> 3;
// FIXME: clear to white
Utils::insertBarrier(
buf,
{ this->whiteImg, this->inImg1, this->inImg2 },
{ this->outImg }
);
Utils::BarrierBuilder(buf)
.addW2R(this->whiteImg)
.addW2R(this->inImg1)
.addW2R(this->inImg2)
.addR2W(this->outImg)
.build();
this->pipeline.bind(buf);
this->descriptorSet.bind(buf, this->pipeline);

View file

@ -4,14 +4,15 @@
using namespace Vulkan::Shaderchains;
Magic::Magic(const Device& device, const Core::DescriptorPool& pool,
const std::vector<Core::Image>& temporalImgs,
const std::vector<Core::Image>& inImgs1,
std::array<Core::Image, 4>& temporalImgs,
std::array<Core::Image, 4>& inImgs1,
Core::Image inImg2,
Core::Image inImg3,
const std::optional<Core::Image>& optImg)
: temporalImgs(temporalImgs), inImgs1(inImgs1),
inImg2(std::move(inImg2)), inImg3(std::move(inImg3)), optImg(optImg) {
// create internal resources
std::optional<Core::Image> optImg)
: temporalImgs(std::move(temporalImgs)),
inImgs1(std::move(inImgs1)),
inImg2(std::move(inImg2)), inImg3(std::move(inImg3)),
optImg(std::move(optImg)) {
this->shaderModule = Core::ShaderModule(device, "rsc/shaders/magic.spv",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 4+4+2+1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
@ -26,34 +27,32 @@ Magic::Magic(const Device& device, const Core::DescriptorPool& pool,
auto extent = temporalImgs.at(0).getExtent();
// create output images
for (size_t i = 0; i < 2; i++)
this->outImgs1.at(i) = Core::Image(device,
{ extent.width, extent.height },
extent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
for (size_t i = 0; i < 3; i++)
this->outImgs2.at(i) = Core::Image(device,
{ extent.width, extent.height },
extent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
for (size_t i = 0; i < 3; i++)
this->outImgs3.at(i) = Core::Image(device,
{ extent.width, extent.height },
extent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
// update descriptor set
this->descriptorSet.update(device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, Globals::samplerClampBorder)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->temporalImgs)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg2)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg3)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, *this->optImg) // FIXME: invalid resource
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs3)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs1)
@ -63,20 +62,21 @@ Magic::Magic(const Device& device, const Core::DescriptorPool& pool,
void Magic::Dispatch(const Core::CommandBuffer& buf) {
auto extent = this->temporalImgs.at(0).getExtent();
// first pass
const uint32_t threadsX = (extent.width + 7) >> 3;
const uint32_t threadsY = (extent.height + 7) >> 3;
Utils::insertBarrier(
buf,
{ this->temporalImgs.at(0), this->temporalImgs.at(1),
this->temporalImgs.at(2), this->temporalImgs.at(3),
this->inImgs1.at(0), this->inImgs1.at(1),
this->inImgs1.at(2), this->inImgs1.at(3),
this->inImg2, this->inImg3, *this->optImg }, // FIXME: invalid resource
{ this->outImgs3.at(0), this->outImgs3.at(1), this->outImgs3.at(2),
this->outImgs2.at(0), this->outImgs2.at(1), this->outImgs2.at(2),
this->outImgs1.at(0), this->outImgs1.at(1) }
);
Utils::BarrierBuilder(buf)
.addW2R(this->temporalImgs)
.addW2R(this->inImgs1)
.addW2R(this->inImg2)
.addW2R(this->inImg3)
.addW2R(this->optImg)
.addR2W(this->outImgs3)
.addR2W(this->outImgs2)
.addR2W(this->outImgs1)
.build();
this->pipeline.bind(buf);
this->descriptorSet.bind(buf, this->pipeline);

View file

@ -15,7 +15,6 @@ Merge::Merge(const Device& device, const Core::DescriptorPool& pool,
inImg3(std::move(inImg3)),
inImg4(std::move(inImg4)),
inImg5(std::move(inImg5)) {
// create internal resources
this->shaderModule = Core::ShaderModule(device, "rsc/shaders/merge.spv",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 5, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
@ -23,20 +22,16 @@ Merge::Merge(const Device& device, const Core::DescriptorPool& pool,
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER } });
this->pipeline = Core::Pipeline(device, this->shaderModule);
this->descriptorSet = Core::DescriptorSet(device, pool, this->shaderModule);
const Globals::FgBuffer data = Globals::fgBuffer;
this->buffer = Core::Buffer(device, data, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
this->buffer = Core::Buffer(device, Globals::fgBuffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
auto extent = this->inImg1.getExtent();
// create output image
this->outImg = Core::Image(device,
{ extent.width, extent.height },
extent,
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
// update descriptor set
this->descriptorSet.update(device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, Globals::samplerClampBorder)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg1)
@ -51,17 +46,19 @@ Merge::Merge(const Device& device, const Core::DescriptorPool& pool,
void Merge::Dispatch(const Core::CommandBuffer& buf) {
auto extent = this->inImg1.getExtent();
// first pass
const uint32_t threadsX = (extent.width + 15) >> 4;
const uint32_t threadsY = (extent.height + 15) >> 4;
// FIXME: clear to white
Utils::insertBarrier(
buf,
{ this->inImg1, this->inImg2, this->inImg3,
this->inImg4, this->inImg5 },
{ this->outImg }
);
Utils::BarrierBuilder(buf)
.addW2R(this->inImg1)
.addW2R(this->inImg2)
.addW2R(this->inImg3)
.addW2R(this->inImg4)
.addW2R(this->inImg5)
.addR2W(this->outImg)
.build();
this->pipeline.bind(buf);
this->descriptorSet.bind(buf, this->pipeline);

View file

@ -3,58 +3,60 @@
#include <format>
#include <fstream>
#include <vulkan/vulkan_core.h>
using namespace Vulkan;
using namespace Vulkan::Utils;
void Utils::insertBarrier(
const Core::CommandBuffer& buffer,
std::vector<Core::Image> w2rImages,
std::vector<Core::Image> r2wImages) {
std::vector<VkImageMemoryBarrier2> barriers(r2wImages.size() + w2rImages.size());
BarrierBuilder& BarrierBuilder::addR2W(Core::Image& image) {
this->barriers.emplace_back(VkImageMemoryBarrier2 {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.srcAccessMask = VK_ACCESS_2_SHADER_READ_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.dstAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
.oldLayout = image.getLayout(),
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.image = image.handle(),
.subresourceRange = {
.aspectMask = image.getAspectFlags(),
.levelCount = 1,
.layerCount = 1
}
});
image.setLayout(VK_IMAGE_LAYOUT_GENERAL);
size_t index = 0;
for (auto& image : r2wImages) {
barriers[index++] = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.srcAccessMask = VK_ACCESS_2_SHADER_READ_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.dstAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
.oldLayout = image.getLayout(),
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.image = image.handle(),
.subresourceRange = {
.aspectMask = image.getAspectFlags(),
.levelCount = 1,
.layerCount = 1
}
};
image.setLayout(VK_IMAGE_LAYOUT_GENERAL);
}
for (auto& image : w2rImages) {
barriers[index++] = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT,
.oldLayout = image.getLayout(),
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.image = image.handle(),
.subresourceRange = {
.aspectMask = image.getAspectFlags(),
.levelCount = 1,
.layerCount = 1
}
};
image.setLayout(VK_IMAGE_LAYOUT_GENERAL);
}
return *this;
}
BarrierBuilder& BarrierBuilder::addW2R(Core::Image& image) {
this->barriers.emplace_back(VkImageMemoryBarrier2 {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT,
.oldLayout = image.getLayout(),
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.image = image.handle(),
.subresourceRange = {
.aspectMask = image.getAspectFlags(),
.levelCount = 1,
.layerCount = 1
}
});
image.setLayout(VK_IMAGE_LAYOUT_GENERAL);
return *this;
}
void BarrierBuilder::build() const {
const VkDependencyInfo dependencyInfo = {
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
.imageMemoryBarrierCount = static_cast<uint32_t>(barriers.size()),
.pImageMemoryBarriers = barriers.data()
.imageMemoryBarrierCount = static_cast<uint32_t>(this->barriers.size()),
.pImageMemoryBarriers = this->barriers.data()
};
vkCmdPipelineBarrier2(buffer.handle(), &dependencyInfo);
vkCmdPipelineBarrier2(this->commandBuffer->handle(), &dependencyInfo);
}
void Utils::uploadImage(const Device& device, const Core::CommandPool& commandPool,
@ -129,6 +131,51 @@ void Utils::uploadImage(const Device& device, const Core::CommandPool& commandPo
throw ls::vulkan_error(VK_TIMEOUT, "Upload operation timed out");
}
void Utils::clearWhiteImage(const Device& device, Core::Image& image) {
Core::Fence fence(device);
const Core::CommandPool cmdPool(device);
Core::CommandBuffer cmdBuf(device, cmdPool);
cmdBuf.begin();
const VkImageMemoryBarrier2 barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
.oldLayout = image.getLayout(),
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.image = image.handle(),
.subresourceRange = {
.aspectMask = image.getAspectFlags(),
.levelCount = 1,
.layerCount = 1
}
};
const VkDependencyInfo dependencyInfo = {
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
.imageMemoryBarrierCount = 1,
.pImageMemoryBarriers = &barrier
};
image.setLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
vkCmdPipelineBarrier2(cmdBuf.handle(), &dependencyInfo);
const VkClearColorValue clearColor = {{ 1.0F, 1.0F, 1.0F, 1.0F }};
const VkImageSubresourceRange subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.levelCount = 1,
.layerCount = 1
};
vkCmdClearColorImage(cmdBuf.handle(),
image.handle(), image.getLayout(),
&clearColor,
1, &subresourceRange);
cmdBuf.end();
cmdBuf.submit(device.getComputeQueue(), fence);
if (!fence.wait(device))
throw ls::vulkan_error(VK_TIMEOUT, "Failed to wait for clearing fence.");
}
Core::Sampler Globals::samplerClampBorder;
Core::Sampler Globals::samplerClampEdge;
Globals::FgBuffer Globals::fgBuffer;