diff --git a/include/core/descriptorset.hpp b/include/core/descriptorset.hpp index 6ca32f3..3bbacbb 100644 --- a/include/core/descriptorset.hpp +++ b/include/core/descriptorset.hpp @@ -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& images) { @@ -97,6 +98,14 @@ namespace Vulkan::Core { DescriptorSetUpdateBuilder& add(VkDescriptorType type, const std::array& 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) { + if (image.has_value()) this->add(type, *image); return *this; } + DescriptorSetUpdateBuilder& add(VkDescriptorType type, const std::optional& sampler) { + if (sampler.has_value()) this->add(type, *sampler); return *this; } + DescriptorSetUpdateBuilder& add(VkDescriptorType type, const std::optional& buffer) { + if (buffer.has_value()) this->add(type, *buffer); return *this; } + /// Finish building the descriptor set update. void build() const; private: diff --git a/include/shaderchains/alpha.hpp b/include/shaderchains/alpha.hpp index 1f0cbb1..403a1a5 100644 --- a/include/shaderchains/alpha.hpp +++ b/include/shaderchains/alpha.hpp @@ -9,6 +9,8 @@ #include "core/shadermodule.hpp" #include "device.hpp" +#include + 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 shaderModules{4}; - std::vector pipelines{4}; - std::vector descriptorSets{4}; + std::array shaderModules; + std::array pipelines; + std::array descriptorSets; Core::Image inImg; - std::vector tempImgs1{2}; // half-size - std::vector tempImgs2{2}; // half-size - std::vector tempImgs3{4}; // quarter-size + std::array tempImgs1; // half-size + std::array tempImgs2; // half-size + std::array tempImgs3; // quarter-size - std::vector outImgs{4}; // quarter-size + std::array outImgs; // quarter-size }; } diff --git a/include/shaderchains/beta.hpp b/include/shaderchains/beta.hpp index e9efe7d..ca52bd5 100644 --- a/include/shaderchains/beta.hpp +++ b/include/shaderchains/beta.hpp @@ -10,6 +10,8 @@ #include "core/shadermodule.hpp" #include "device.hpp" +#include + 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& temporalImgs, - const std::vector& inImgs); + std::array temporalImgs, + std::array inImgs); /// /// Dispatch the shaderchain. @@ -53,18 +55,18 @@ namespace Vulkan::Shaderchains { Beta& operator=(Beta&&) noexcept = default; ~Beta() = default; private: - std::vector shaderModules{5}; - std::vector pipelines{5}; - std::vector descriptorSets{5}; + std::array shaderModules; + std::array pipelines; + std::array descriptorSets; Core::Buffer buffer; - std::vector temporalImgs{8}; - std::vector inImgs{4}; + std::array temporalImgs; + std::array inImgs; - std::vector tempImgs1{2}; - std::vector tempImgs2{2}; + std::array tempImgs1; + std::array tempImgs2; - std::vector outImgs{6}; + std::array outImgs; }; } diff --git a/include/shaderchains/delta.hpp b/include/shaderchains/delta.hpp index 4a5d7e1..c880e90 100644 --- a/include/shaderchains/delta.hpp +++ b/include/shaderchains/delta.hpp @@ -10,6 +10,8 @@ #include "core/shadermodule.hpp" #include "device.hpp" +#include + 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& inImgs, - const std::optional& optImg); + std::array inImgs, + std::optional optImg); /// /// Dispatch the shaderchain. @@ -53,16 +55,16 @@ namespace Vulkan::Shaderchains { Delta& operator=(Delta&&) noexcept = default; ~Delta() = default; private: - std::vector shaderModules{4}; - std::vector pipelines{4}; - std::vector descriptorSets{4}; + std::array shaderModules; + std::array pipelines; + std::array descriptorSets; Core::Buffer buffer; - std::vector inImg{2}; + std::array inImg; std::optional optImg; - std::vector tempImgs1{2}; - std::vector tempImgs2{2}; + std::array tempImgs1; + std::array tempImgs2; Core::Image outImg; }; diff --git a/include/shaderchains/downsample.hpp b/include/shaderchains/downsample.hpp index 0f9c523..1a5d399 100644 --- a/include/shaderchains/downsample.hpp +++ b/include/shaderchains/downsample.hpp @@ -10,6 +10,8 @@ #include "core/shadermodule.hpp" #include "device.hpp" +#include + 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 outImgs{7}; + std::array outImgs; }; } diff --git a/include/shaderchains/epsilon.hpp b/include/shaderchains/epsilon.hpp index b875a26..6ad438a 100644 --- a/include/shaderchains/epsilon.hpp +++ b/include/shaderchains/epsilon.hpp @@ -10,6 +10,8 @@ #include "core/shadermodule.hpp" #include "device.hpp" +#include + 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& inImgs1, - const Core::Image& inImg2, - const std::optional& optImg); + std::array inImgs1, + Core::Image inImg2, + std::optional optImg); /// /// Dispatch the shaderchain. @@ -55,17 +57,17 @@ namespace Vulkan::Shaderchains { Epsilon& operator=(Epsilon&&) noexcept = default; ~Epsilon() = default; private: - std::vector shaderModules{4}; - std::vector pipelines{4}; - std::vector descriptorSets{4}; + std::array shaderModules; + std::array pipelines; + std::array descriptorSets; Core::Buffer buffer; - std::vector inImgs1{3}; + std::array inImgs1; Core::Image inImg2; std::optional optImg; - std::vector tempImgs1{4}; - std::vector tempImgs2{4}; + std::array tempImgs1; + std::array tempImgs2; Core::Image outImg; }; diff --git a/include/shaderchains/extract.hpp b/include/shaderchains/extract.hpp index e70a8e0..e1a7a72 100644 --- a/include/shaderchains/extract.hpp +++ b/include/shaderchains/extract.hpp @@ -9,7 +9,6 @@ #include "core/pipeline.hpp" #include "core/shadermodule.hpp" #include "device.hpp" -#include namespace Vulkan::Shaderchains { diff --git a/include/shaderchains/gamma.hpp b/include/shaderchains/gamma.hpp index 693a16d..dad16c0 100644 --- a/include/shaderchains/gamma.hpp +++ b/include/shaderchains/gamma.hpp @@ -10,6 +10,8 @@ #include "core/shadermodule.hpp" #include "device.hpp" +#include + 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& temporalImgs, - const std::vector& inImgs1, - const Core::Image& inImg2, - const std::optional& optImg1, - const std::optional& optImg2, + std::array temporalImgs, + std::array inImgs1, + Core::Image inImg2, + std::optional optImg1, + std::optional optImg2, VkExtent2D outExtent); /// @@ -65,19 +67,19 @@ namespace Vulkan::Shaderchains { Gamma& operator=(Gamma&&) noexcept = default; ~Gamma() = default; private: - std::vector shaderModules{6}; - std::vector pipelines{6}; - std::vector descriptorSets{6}; + std::array shaderModules; + std::array pipelines; + std::array descriptorSets; Core::Buffer buffer; - std::vector temporalImgs{4}; - std::vector inImgs1{4}; + std::array temporalImgs; + std::array inImgs1; Core::Image inImg2; Core::Image optImg1; // specified or created black std::optional optImg2; - std::vector tempImgs1{4}; - std::vector tempImgs2{4}; + std::array tempImgs1; + std::array tempImgs2; Core::Image whiteImg; Core::Image outImg1; diff --git a/include/shaderchains/magic.hpp b/include/shaderchains/magic.hpp index 2d5f1cb..6de4525 100644 --- a/include/shaderchains/magic.hpp +++ b/include/shaderchains/magic.hpp @@ -10,6 +10,8 @@ #include "core/shadermodule.hpp" #include "device.hpp" +#include + 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& temporalImgs, - const std::vector& inImgs1, + std::array& temporalImgs, + std::array& inImgs1, Core::Image inImg2, Core::Image inImg3, - const std::optional& optImg); + std::optional optImg); /// /// Dispatch the shaderchain. @@ -68,15 +70,15 @@ namespace Vulkan::Shaderchains { Core::DescriptorSet descriptorSet; Core::Buffer buffer; - std::vector temporalImgs{4}; - std::vector inImgs1{4}; + std::array temporalImgs; + std::array inImgs1; Core::Image inImg2; Core::Image inImg3; std::optional optImg; - std::vector outImgs1{3}; - std::vector outImgs2{3}; - std::vector outImgs3{3}; + std::array outImgs1; + std::array outImgs2; + std::array outImgs3; }; } diff --git a/include/shaderchains/zeta.hpp b/include/shaderchains/zeta.hpp index e0847d1..7e700d3 100644 --- a/include/shaderchains/zeta.hpp +++ b/include/shaderchains/zeta.hpp @@ -10,6 +10,8 @@ #include "core/shadermodule.hpp" #include "device.hpp" +#include + 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& inImgs1, - const Core::Image& inImg2, - const Core::Image& inImg3); + std::array 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 shaderModules{4}; - std::vector pipelines{4}; - std::vector descriptorSets{4}; + std::array shaderModules; + std::array pipelines; + std::array descriptorSets; Core::Buffer buffer; - std::vector inImgs1{3}; + std::array inImgs1; Core::Image inImg2; Core::Image inImg3; - std::vector tempImgs1{4}; - std::vector tempImgs2{4}; + std::array tempImgs1; + std::array tempImgs2; Core::Image outImg; }; diff --git a/include/utils.hpp b/include/utils.hpp index aa968b7..9005e80 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -4,6 +4,7 @@ #include "core/commandbuffer.hpp" #include "core/image.hpp" #include "core/sampler.hpp" +#include "device.hpp" #include #include @@ -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 w2rImages, - std::vector 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& image) { + if (image.has_value()) this->addR2W(*image); return *this; } + BarrierBuilder& addW2R(std::optional& image) { + if (image.has_value()) this->addW2R(*image); return *this; } + + /// Add a list of resources to the barrier builder. + BarrierBuilder& addR2W(std::vector& images) { + for (auto& image : images) this->addR2W(image); return *this; } + BarrierBuilder& addW2R(std::vector& images) { + for (auto& image : images) this->addW2R(image); return *this; } + + /// Add an array of resources to the barrier builder. + template + BarrierBuilder& addR2W(std::array& images) { + for (auto& image : images) this->addR2W(image); return *this; } + template + BarrierBuilder& addW2R(std::array& images) { + for (auto& image : images) this->addW2R(image); return *this; } + + /// Finish building the barrier + void build() const; + private: + const Core::CommandBuffer* commandBuffer; + + std::vector 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); } diff --git a/src/core/descriptorset.cpp b/src/core/descriptorset.cpp index 6a83cb4..b33d1c5 100644 --- a/src/core/descriptorset.cpp +++ b/src/core/descriptorset.cpp @@ -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(this->entries.size()), + .descriptorCount = 0, + .descriptorType = type, + .pImageInfo = nullptr, + .pBufferInfo = nullptr + }); + return *this; +} + void DescriptorSetUpdateBuilder::build() const { if (this->entries.empty()) return; diff --git a/src/shaderchains/alpha.cpp b/src/shaderchains/alpha.cpp index b99c4b1..8bd270e 100644 --- a/src/shaderchains/alpha.cpp +++ b/src/shaderchains/alpha.cpp @@ -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); } diff --git a/src/shaderchains/downsample.cpp b/src/shaderchains/downsample.cpp index d6dc2ea..2d880ba 100644 --- a/src/shaderchains/downsample.cpp +++ b/src/shaderchains/downsample.cpp @@ -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); diff --git a/src/shaderchains/extract.cpp b/src/shaderchains/extract.cpp index 3b12f92..58284f6 100644 --- a/src/shaderchains/extract.cpp +++ b/src/shaderchains/extract.cpp @@ -1,6 +1,5 @@ #include "shaderchains/extract.hpp" #include "utils.hpp" -#include 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); diff --git a/src/shaderchains/magic.cpp b/src/shaderchains/magic.cpp index 3f641d4..da77a8c 100644 --- a/src/shaderchains/magic.cpp +++ b/src/shaderchains/magic.cpp @@ -4,14 +4,15 @@ using namespace Vulkan::Shaderchains; Magic::Magic(const Device& device, const Core::DescriptorPool& pool, - const std::vector& temporalImgs, - const std::vector& inImgs1, + std::array& temporalImgs, + std::array& inImgs1, Core::Image inImg2, Core::Image inImg3, - const std::optional& optImg) - : temporalImgs(temporalImgs), inImgs1(inImgs1), - inImg2(std::move(inImg2)), inImg3(std::move(inImg3)), optImg(optImg) { - // create internal resources + std::optional 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); diff --git a/src/shaderchains/merge.cpp b/src/shaderchains/merge.cpp index 590779b..e93d645 100644 --- a/src/shaderchains/merge.cpp +++ b/src/shaderchains/merge.cpp @@ -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); diff --git a/src/utils.cpp b/src/utils.cpp index bb03b3c..f8fc6a1 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -3,58 +3,60 @@ #include #include +#include using namespace Vulkan; +using namespace Vulkan::Utils; -void Utils::insertBarrier( - const Core::CommandBuffer& buffer, - std::vector w2rImages, - std::vector r2wImages) { - std::vector 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(barriers.size()), - .pImageMemoryBarriers = barriers.data() + .imageMemoryBarrierCount = static_cast(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;