refactor(cleanup): rewrite main pass in new abstraction

This commit is contained in:
PancakeTAS 2025-12-06 16:05:37 +01:00
parent c3d6cdfc28
commit f3536b0895
27 changed files with 790 additions and 1674 deletions

View file

@ -1,81 +0,0 @@
#pragma once
#include "core/buffer.hpp"
#include "core/commandbuffer.hpp"
#include "core/descriptorset.hpp"
#include "core/image.hpp"
#include "core/pipeline.hpp"
#include "core/sampler.hpp"
#include "core/shadermodule.hpp"
#include "common/utils.hpp"
#include <array>
#include <cstdint>
#include <optional>
#include <vector>
namespace LSFG_3_1::Shaders {
using namespace LSFG;
///
/// Delta shader.
///
class Delta {
public:
Delta() = default;
///
/// Initialize the shaderchain.
///
/// @param inImgs1 Three sets of four RGBA images, corresponding to a frame count % 3.
/// @param inImg2 Second Input image
/// @param optImg1 Optional image for non-first passes.
/// @param optImg2 Second optional image for non-first passes.
/// @param optImg3 Third optional image for non-first passes.
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Delta(Vulkan& vk, std::array<std::array<Core::Image, 4>, 3> inImgs1,
Core::Image inImg2,
std::optional<Core::Image> optImg1,
std::optional<Core::Image> optImg2,
std::optional<Core::Image> optImg3);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx);
/// Get the first output image
[[nodiscard]] const auto& getOutImage1() const { return this->outImg1; }
/// Get the second output image
[[nodiscard]] const auto& getOutImage2() const { return this->outImg2; }
/// Trivially copyable, moveable and destructible
Delta(const Delta&) noexcept = default;
Delta& operator=(const Delta&) noexcept = default;
Delta(Delta&&) noexcept = default;
Delta& operator=(Delta&&) noexcept = default;
~Delta() = default;
private:
std::array<Core::ShaderModule, 10> shaderModules;
std::array<Core::Pipeline, 10> pipelines;
std::array<Core::Sampler, 3> samplers;
struct DeltaPass {
Core::Buffer buffer;
std::array<Core::DescriptorSet, 3> firstDescriptorSet;
std::array<Core::DescriptorSet, 8> descriptorSets;
std::array<Core::DescriptorSet, 3> sixthDescriptorSet;
};
std::vector<DeltaPass> passes;
std::array<std::array<Core::Image, 4>, 3> inImgs1;
Core::Image inImg2;
std::optional<Core::Image> optImg1, optImg2, optImg3;
std::array<Core::Image, 4> tempImgs1;
std::array<Core::Image, 4> tempImgs2;
Core::Image outImg1, outImg2;
};
}

View file

@ -1,73 +0,0 @@
#pragma once
#include "core/buffer.hpp"
#include "core/commandbuffer.hpp"
#include "core/descriptorset.hpp"
#include "core/image.hpp"
#include "core/pipeline.hpp"
#include "core/sampler.hpp"
#include "core/shadermodule.hpp"
#include "common/utils.hpp"
#include <array>
#include <cstdint>
#include <optional>
#include <vector>
namespace LSFG_3_1::Shaders {
using namespace LSFG;
///
/// Gamma shader.
///
class Gamma {
public:
Gamma() = default;
///
/// Initialize the shaderchain.
///
/// @param inImgs1 Three sets of four RGBA images, corresponding to a frame count % 3.
/// @param inImg2 Second Input image
/// @param optImg Optional image for non-first passes.
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Gamma(Vulkan& vk, std::array<std::array<Core::Image, 4>, 3> inImgs1,
Core::Image inImg2, std::optional<Core::Image> optImg);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx);
/// Get the output image
[[nodiscard]] const auto& getOutImage() const { return this->outImg; }
/// Trivially copyable, moveable and destructible
Gamma(const Gamma&) noexcept = default;
Gamma& operator=(const Gamma&) noexcept = default;
Gamma(Gamma&&) noexcept = default;
Gamma& operator=(Gamma&&) noexcept = default;
~Gamma() = default;
private:
std::array<Core::ShaderModule, 5> shaderModules;
std::array<Core::Pipeline, 5> pipelines;
std::array<Core::Sampler, 3> samplers;
struct GammaPass {
Core::Buffer buffer;
std::array<Core::DescriptorSet, 3> firstDescriptorSet;
std::array<Core::DescriptorSet, 4> descriptorSets;
};
std::vector<GammaPass> passes;
std::array<std::array<Core::Image, 4>, 3> inImgs1;
Core::Image inImg2;
std::optional<Core::Image> optImg;
std::array<Core::Image, 4> tempImgs1;
std::array<Core::Image, 4> tempImgs2;
Core::Image outImg;
};
}

View file

@ -1,72 +0,0 @@
#pragma once
#include "core/buffer.hpp"
#include "core/commandbuffer.hpp"
#include "core/descriptorset.hpp"
#include "core/image.hpp"
#include "core/pipeline.hpp"
#include "core/sampler.hpp"
#include "core/shadermodule.hpp"
#include "common/utils.hpp"
#include <vulkan/vulkan_core.h>
#include <array>
#include <vector>
#include <cstdint>
namespace LSFG_3_1::Shaders {
using namespace LSFG;
///
/// Generate shader.
///
class Generate {
public:
Generate() = default;
///
/// Initialize the shaderchain.
///
/// @param inImg1 Input image 1.
/// @param inImg2 Input image 2.
/// @param inImg3 Input image 3.
/// @param inImg4 Input image 4.
/// @param inImg5 Input image 5.
/// @param fds File descriptors for the output images.
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Generate(Vulkan& vk,
Core::Image inImg1, Core::Image inImg2,
Core::Image inImg3, Core::Image inImg4, Core::Image inImg5,
const std::vector<int>& fds, VkFormat format);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx);
/// Trivially copyable, moveable and destructible
Generate(const Generate&) noexcept = default;
Generate& operator=(const Generate&) noexcept = default;
Generate(Generate&&) noexcept = default;
Generate& operator=(Generate&&) noexcept = default;
~Generate() = default;
private:
Core::ShaderModule shaderModule;
Core::Pipeline pipeline;
std::array<Core::Sampler, 2> samplers;
struct GeneratePass {
Core::Buffer buffer;
std::array<Core::DescriptorSet, 2> descriptorSet;
};
std::vector<GeneratePass> passes;
Core::Image inImg1, inImg2;
Core::Image inImg3, inImg4, inImg5;
std::vector<Core::Image> outImgs;
};
}

View file

@ -1,340 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1/shaders/delta.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <array>
#include <optional>
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1::Shaders;
Delta::Delta(Vulkan& vk, std::array<std::array<Core::Image, 4>, 3> inImgs1,
Core::Image inImg2,
std::optional<Core::Image> optImg1,
std::optional<Core::Image> optImg2,
std::optional<Core::Image> optImg3)
: inImgs1(std::move(inImgs1)), inImg2(std::move(inImg2)),
optImg1(std::move(optImg1)), optImg2(std::move(optImg2)),
optImg3(std::move(optImg3)) {
// create resources
this->shaderModules = {{
vk.shaders.getShader(vk.device, "delta[0]",
{ { 1 , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 9, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "delta[1]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "delta[2]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "delta[3]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "delta[4]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 6, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "delta[5]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 10, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "delta[6]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "delta[7]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "delta[8]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "delta[9]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } })
}};
this->pipelines = {{
vk.shaders.getPipeline(vk.device, "delta[0]"),
vk.shaders.getPipeline(vk.device, "delta[1]"),
vk.shaders.getPipeline(vk.device, "delta[2]"),
vk.shaders.getPipeline(vk.device, "delta[3]"),
vk.shaders.getPipeline(vk.device, "delta[4]"),
vk.shaders.getPipeline(vk.device, "delta[5]"),
vk.shaders.getPipeline(vk.device, "delta[6]"),
vk.shaders.getPipeline(vk.device, "delta[7]"),
vk.shaders.getPipeline(vk.device, "delta[8]"),
vk.shaders.getPipeline(vk.device, "delta[9]")
}};
this->samplers.at(0) = vk.resources.getSampler(vk.device);
this->samplers.at(1) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true);
this->samplers.at(2) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
// create internal images/outputs
const VkExtent2D extent = this->inImgs1.at(0).at(0).getExtent();
for (size_t i = 0; i < 4; i++) {
this->tempImgs1.at(i) = Core::Image(vk.device, extent);
this->tempImgs2.at(i) = Core::Image(vk.device, extent);
}
this->outImg1 = Core::Image(vk.device,
{ extent.width, extent.height },
VK_FORMAT_R16G16B16A16_SFLOAT);
this->outImg2 = Core::Image(vk.device,
{ extent.width, extent.height },
VK_FORMAT_R16G16B16A16_SFLOAT);
// hook up shaders
for (size_t pass_idx = 0; pass_idx < vk.generationCount; pass_idx++) {
auto& pass = this->passes.emplace_back();
pass.buffer = vk.resources.getBuffer(vk.device,
static_cast<float>(pass_idx + 1) / static_cast<float>(vk.generationCount + 1),
false, !this->optImg1.has_value());
for (size_t i = 0; i < 3; i++) {
pass.firstDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(0));
pass.firstDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at((i + 2) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at(i % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(1))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(2))
.build();
}
pass.descriptorSets.at(0) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(1));
pass.descriptorSets.at(0).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(2))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
pass.descriptorSets.at(1) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(2));
pass.descriptorSets.at(1).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1)
.build();
pass.descriptorSets.at(2) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(3));
pass.descriptorSets.at(2).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
pass.descriptorSets.at(3) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(4));
pass.descriptorSets.at(3).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg1)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImg1)
.build();
for (size_t i = 0; i < 3; i++) {
pass.sixthDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(5));
pass.sixthDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at((i + 2) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at(i % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg1)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2.at(1))
.build();
}
pass.descriptorSets.at(4) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(6));
pass.descriptorSets.at(4).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2.at(1))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(1))
.build();
pass.descriptorSets.at(5) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(7));
pass.descriptorSets.at(5).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(1))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2.at(1))
.build();
pass.descriptorSets.at(6) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(8));
pass.descriptorSets.at(6).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2.at(1))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(1))
.build();
pass.descriptorSets.at(7) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(9));
pass.descriptorSets.at(7).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg3)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImg2)
.build();
}
}
void Delta::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx) {
auto& pass = this->passes.at(pass_idx);
// first shader
const auto extent = this->tempImgs1.at(0).getExtent();
const uint32_t threadsX = (extent.width + 7) >> 3;
const uint32_t threadsY = (extent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->inImgs1.at((frameCount + 2) % 3))
.addW2R(this->inImgs1.at(frameCount % 3))
.addW2R(this->optImg1)
.addR2W(this->tempImgs1.at(0))
.addR2W(this->tempImgs1.at(1))
.addR2W(this->tempImgs1.at(2))
.build();
this->pipelines.at(0).bind(buf);
pass.firstDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(0));
buf.dispatch(threadsX, threadsY, 1);
// second shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1.at(0))
.addW2R(this->tempImgs1.at(1))
.addW2R(this->tempImgs1.at(2))
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(1).bind(buf);
pass.descriptorSets.at(0).bind(buf, this->pipelines.at(1));
buf.dispatch(threadsX, threadsY, 1);
// third shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(2).bind(buf);
pass.descriptorSets.at(1).bind(buf, this->pipelines.at(2));
buf.dispatch(threadsX, threadsY, 1);
// fourth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(3).bind(buf);
pass.descriptorSets.at(2).bind(buf, this->pipelines.at(3));
buf.dispatch(threadsX, threadsY, 1);
// fifth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addW2R(this->optImg1)
.addW2R(this->inImg2)
.addR2W(this->outImg1)
.build();
this->pipelines.at(4).bind(buf);
pass.descriptorSets.at(3).bind(buf, this->pipelines.at(4));
buf.dispatch(threadsX, threadsY, 1);
// sixth shader
Utils::BarrierBuilder(buf)
.addW2R(this->inImgs1.at((frameCount + 2) % 3))
.addW2R(this->inImgs1.at(frameCount % 3))
.addW2R(this->optImg1)
.addW2R(this->optImg2)
.addR2W(this->tempImgs2.at(0))
.addR2W(this->tempImgs2.at(1))
.build();
this->pipelines.at(5).bind(buf);
pass.sixthDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(5));
buf.dispatch(threadsX, threadsY, 1);
// seventh shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2.at(0))
.addW2R(this->tempImgs2.at(1))
.addR2W(this->tempImgs1.at(0))
.addR2W(this->tempImgs1.at(1))
.build();
this->pipelines.at(6).bind(buf);
pass.descriptorSets.at(4).bind(buf, this->pipelines.at(6));
buf.dispatch(threadsX, threadsY, 1);
// eighth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1.at(0))
.addW2R(this->tempImgs1.at(1))
.addR2W(this->tempImgs2.at(0))
.addR2W(this->tempImgs2.at(1))
.build();
this->pipelines.at(7).bind(buf);
pass.descriptorSets.at(5).bind(buf, this->pipelines.at(7));
buf.dispatch(threadsX, threadsY, 1);
// ninth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2.at(0))
.addW2R(this->tempImgs2.at(1))
.addR2W(this->tempImgs1.at(0))
.addR2W(this->tempImgs1.at(1))
.build();
this->pipelines.at(8).bind(buf);
pass.descriptorSets.at(6).bind(buf, this->pipelines.at(8));
buf.dispatch(threadsX, threadsY, 1);
// tenth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1.at(0))
.addW2R(this->tempImgs1.at(1))
.addW2R(this->optImg3)
.addR2W(this->outImg2)
.build();
this->pipelines.at(9).bind(buf);
pass.descriptorSets.at(7).bind(buf, this->pipelines.at(9));
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,193 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1/shaders/gamma.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <array>
#include <optional>
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1::Shaders;
Gamma::Gamma(Vulkan& vk, std::array<std::array<Core::Image, 4>, 3> inImgs1,
Core::Image inImg2,
std::optional<Core::Image> optImg)
: inImgs1(std::move(inImgs1)), inImg2(std::move(inImg2)),
optImg(std::move(optImg)) {
// create resources
this->shaderModules = {{
vk.shaders.getShader(vk.device, "gamma[0]",
{ { 1 , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 9, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "gamma[1]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "gamma[2]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "gamma[3]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "gamma[4]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 6, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } })
}};
this->pipelines = {{
vk.shaders.getPipeline(vk.device, "gamma[0]"),
vk.shaders.getPipeline(vk.device, "gamma[1]"),
vk.shaders.getPipeline(vk.device, "gamma[2]"),
vk.shaders.getPipeline(vk.device, "gamma[3]"),
vk.shaders.getPipeline(vk.device, "gamma[4]")
}};
this->samplers.at(0) = vk.resources.getSampler(vk.device);
this->samplers.at(1) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true);
this->samplers.at(2) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
// create internal images/outputs
const VkExtent2D extent = this->inImgs1.at(0).at(0).getExtent();
for (size_t i = 0; i < 4; i++) {
this->tempImgs1.at(i) = Core::Image(vk.device, extent);
this->tempImgs2.at(i) = Core::Image(vk.device, extent);
}
this->outImg = Core::Image(vk.device,
{ extent.width, extent.height },
VK_FORMAT_R16G16B16A16_SFLOAT);
// hook up shaders
for (size_t pass_idx = 0; pass_idx < vk.generationCount; pass_idx++) {
auto& pass = this->passes.emplace_back();
pass.buffer = vk.resources.getBuffer(vk.device,
static_cast<float>(pass_idx + 1) / static_cast<float>(vk.generationCount + 1),
!this->optImg.has_value());
for (size_t i = 0; i < 3; i++) {
pass.firstDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(0));
pass.firstDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at((i + 2) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at(i % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(1))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(2))
.build();
}
pass.descriptorSets.at(0) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(1));
pass.descriptorSets.at(0).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(2))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
pass.descriptorSets.at(1) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(2));
pass.descriptorSets.at(1).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1)
.build();
pass.descriptorSets.at(2) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(3));
pass.descriptorSets.at(2).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
pass.descriptorSets.at(3) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(4));
pass.descriptorSets.at(3).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImg)
.build();
}
}
void Gamma::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx) {
auto& pass = this->passes.at(pass_idx);
// first shader
const auto extent = this->tempImgs1.at(0).getExtent();
const uint32_t threadsX = (extent.width + 7) >> 3;
const uint32_t threadsY = (extent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->inImgs1.at((frameCount + 2) % 3))
.addW2R(this->inImgs1.at(frameCount % 3))
.addW2R(this->optImg)
.addR2W(this->tempImgs1.at(0))
.addR2W(this->tempImgs1.at(1))
.addR2W(this->tempImgs1.at(2))
.build();
this->pipelines.at(0).bind(buf);
pass.firstDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(0));
buf.dispatch(threadsX, threadsY, 1);
// second shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1.at(0))
.addW2R(this->tempImgs1.at(1))
.addW2R(this->tempImgs1.at(2))
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(1).bind(buf);
pass.descriptorSets.at(0).bind(buf, this->pipelines.at(1));
buf.dispatch(threadsX, threadsY, 1);
// third shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(2).bind(buf);
pass.descriptorSets.at(1).bind(buf, this->pipelines.at(2));
buf.dispatch(threadsX, threadsY, 1);
// fourth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(3).bind(buf);
pass.descriptorSets.at(2).bind(buf, this->pipelines.at(3));
buf.dispatch(threadsX, threadsY, 1);
// fifth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addW2R(this->optImg)
.addW2R(this->inImg2)
.addR2W(this->outImg)
.build();
this->pipelines.at(4).bind(buf);
pass.descriptorSets.at(3).bind(buf, this->pipelines.at(4));
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,83 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1/shaders/generate.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <vector>
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1::Shaders;
Generate::Generate(Vulkan& vk,
Core::Image inImg1, Core::Image inImg2,
Core::Image inImg3, Core::Image inImg4, Core::Image inImg5,
const std::vector<int>& fds, VkFormat format)
: inImg1(std::move(inImg1)), inImg2(std::move(inImg2)),
inImg3(std::move(inImg3)), inImg4(std::move(inImg4)),
inImg5(std::move(inImg5)) {
// create resources
this->shaderModule = vk.shaders.getShader(vk.device, "generate",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 5, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } });
this->pipeline = vk.shaders.getPipeline(vk.device, "generate");
this->samplers.at(0) = vk.resources.getSampler(vk.device);
this->samplers.at(1) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS);
// create internal images/outputs
const VkExtent2D extent = this->inImg1.getExtent();
for (size_t i = 0; i < vk.generationCount; i++)
this->outImgs.emplace_back(vk.device, extent, format,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT, fds.empty() ? -1 : fds.at(i));
// hook up shaders
for (size_t i = 0; i < vk.generationCount; i++) {
auto& pass = this->passes.emplace_back();
pass.buffer = vk.resources.getBuffer(vk.device,
static_cast<float>(i + 1) / static_cast<float>(vk.generationCount + 1));
for (size_t j = 0; j < 2; j++) {
pass.descriptorSet.at(j) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModule);
pass.descriptorSet.at(j).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, j == 0 ? this->inImg2 : this->inImg1)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, j == 0 ? this->inImg1 : this->inImg2)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg3)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg4)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg5)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs.at(i))
.build();
}
}
}
void Generate::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx) {
auto& pass = this->passes.at(pass_idx);
// first pass
const auto extent = this->inImg1.getExtent();
const uint32_t threadsX = (extent.width + 15) >> 4;
const uint32_t threadsY = (extent.height + 15) >> 4;
Utils::BarrierBuilder(buf)
.addW2R(this->inImg1)
.addW2R(this->inImg2)
.addW2R(this->inImg3)
.addW2R(this->inImg4)
.addW2R(this->inImg5)
.addR2W(this->outImgs.at(pass_idx))
.build();
this->pipeline.bind(buf);
pass.descriptorSet.at(frameCount % 2).bind(buf, this->pipeline);
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,81 +0,0 @@
#pragma once
#include "core/buffer.hpp"
#include "core/commandbuffer.hpp"
#include "core/descriptorset.hpp"
#include "core/image.hpp"
#include "core/pipeline.hpp"
#include "core/sampler.hpp"
#include "core/shadermodule.hpp"
#include "common/utils.hpp"
#include <array>
#include <cstdint>
#include <optional>
#include <vector>
namespace LSFG_3_1P::Shaders {
using namespace LSFG;
///
/// Delta shader.
///
class Delta {
public:
Delta() = default;
///
/// Initialize the shaderchain.
///
/// @param inImgs1 Three sets of two RGBA images, corresponding to a frame count % 3.
/// @param inImg2 Second Input image
/// @param optImg1 Optional image for non-first passes.
/// @param optImg2 Second optional image for non-first passes.
/// @param optImg3 Third optional image for non-first passes.
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Delta(Vulkan& vk, std::array<std::array<Core::Image, 2>, 3> inImgs1,
Core::Image inImg2,
std::optional<Core::Image> optImg1,
std::optional<Core::Image> optImg2,
std::optional<Core::Image> optImg3);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx);
/// Get the first output image
[[nodiscard]] const auto& getOutImage1() const { return this->outImg1; }
/// Get the second output image
[[nodiscard]] const auto& getOutImage2() const { return this->outImg2; }
/// Trivially copyable, moveable and destructible
Delta(const Delta&) noexcept = default;
Delta& operator=(const Delta&) noexcept = default;
Delta(Delta&&) noexcept = default;
Delta& operator=(Delta&&) noexcept = default;
~Delta() = default;
private:
std::array<Core::ShaderModule, 10> shaderModules;
std::array<Core::Pipeline, 10> pipelines;
std::array<Core::Sampler, 3> samplers;
struct DeltaPass {
Core::Buffer buffer;
std::array<Core::DescriptorSet, 3> firstDescriptorSet;
std::array<Core::DescriptorSet, 8> descriptorSets;
std::array<Core::DescriptorSet, 3> sixthDescriptorSet;
};
std::vector<DeltaPass> passes;
std::array<std::array<Core::Image, 2>, 3> inImgs1;
Core::Image inImg2;
std::optional<Core::Image> optImg1, optImg2, optImg3;
std::array<Core::Image, 3> tempImgs1;
std::array<Core::Image, 2> tempImgs2;
Core::Image outImg1, outImg2;
};
}

View file

@ -1,73 +0,0 @@
#pragma once
#include "core/buffer.hpp"
#include "core/commandbuffer.hpp"
#include "core/descriptorset.hpp"
#include "core/image.hpp"
#include "core/pipeline.hpp"
#include "core/sampler.hpp"
#include "core/shadermodule.hpp"
#include "common/utils.hpp"
#include <array>
#include <cstdint>
#include <optional>
#include <vector>
namespace LSFG_3_1P::Shaders {
using namespace LSFG;
///
/// Gamma shader.
///
class Gamma {
public:
Gamma() = default;
///
/// Initialize the shaderchain.
///
/// @param inImgs1 Three sets of two RGBA images, corresponding to a frame count % 3.
/// @param inImg2 Second Input image
/// @param optImg Optional image for non-first passes.
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Gamma(Vulkan& vk, std::array<std::array<Core::Image, 2>, 3> inImgs1,
Core::Image inImg2, std::optional<Core::Image> optImg);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx);
/// Get the output image
[[nodiscard]] const auto& getOutImage() const { return this->outImg; }
/// Trivially copyable, moveable and destructible
Gamma(const Gamma&) noexcept = default;
Gamma& operator=(const Gamma&) noexcept = default;
Gamma(Gamma&&) noexcept = default;
Gamma& operator=(Gamma&&) noexcept = default;
~Gamma() = default;
private:
std::array<Core::ShaderModule, 5> shaderModules;
std::array<Core::Pipeline, 5> pipelines;
std::array<Core::Sampler, 3> samplers;
struct GammaPass {
Core::Buffer buffer;
std::array<Core::DescriptorSet, 3> firstDescriptorSet;
std::array<Core::DescriptorSet, 4> descriptorSets;
};
std::vector<GammaPass> passes;
std::array<std::array<Core::Image, 2>, 3> inImgs1;
Core::Image inImg2;
std::optional<Core::Image> optImg;
std::array<Core::Image, 3> tempImgs1;
std::array<Core::Image, 2> tempImgs2;
Core::Image outImg;
};
}

View file

@ -1,72 +0,0 @@
#pragma once
#include "core/buffer.hpp"
#include "core/commandbuffer.hpp"
#include "core/descriptorset.hpp"
#include "core/image.hpp"
#include "core/pipeline.hpp"
#include "core/sampler.hpp"
#include "core/shadermodule.hpp"
#include "common/utils.hpp"
#include <vulkan/vulkan_core.h>
#include <array>
#include <vector>
#include <cstdint>
namespace LSFG_3_1P::Shaders {
using namespace LSFG;
///
/// Generate shader.
///
class Generate {
public:
Generate() = default;
///
/// Initialize the shaderchain.
///
/// @param inImg1 Input image 1.
/// @param inImg2 Input image 2.
/// @param inImg3 Input image 3.
/// @param inImg4 Input image 4.
/// @param inImg5 Input image 5.
/// @param fds File descriptors for the output images.
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Generate(Vulkan& vk,
Core::Image inImg1, Core::Image inImg2,
Core::Image inImg3, Core::Image inImg4, Core::Image inImg5,
const std::vector<int>& fds, VkFormat format);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx);
/// Trivially copyable, moveable and destructible
Generate(const Generate&) noexcept = default;
Generate& operator=(const Generate&) noexcept = default;
Generate(Generate&&) noexcept = default;
Generate& operator=(Generate&&) noexcept = default;
~Generate() = default;
private:
Core::ShaderModule shaderModule;
Core::Pipeline pipeline;
std::array<Core::Sampler, 2> samplers;
struct GeneratePass {
Core::Buffer buffer;
std::array<Core::DescriptorSet, 2> descriptorSet;
};
std::vector<GeneratePass> passes;
Core::Image inImg1, inImg2;
Core::Image inImg3, inImg4, inImg5;
std::vector<Core::Image> outImgs;
};
}

View file

@ -1,322 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1p/shaders/delta.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <array>
#include <optional>
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1P::Shaders;
Delta::Delta(Vulkan& vk, std::array<std::array<Core::Image, 2>, 3> inImgs1,
Core::Image inImg2,
std::optional<Core::Image> optImg1,
std::optional<Core::Image> optImg2,
std::optional<Core::Image> optImg3)
: inImgs1(std::move(inImgs1)), inImg2(std::move(inImg2)),
optImg1(std::move(optImg1)), optImg2(std::move(optImg2)),
optImg3(std::move(optImg3)) {
// create resources
this->shaderModules = {{
vk.shaders.getShader(vk.device, "p_delta[0]",
{ { 1 , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 5, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_delta[1]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_delta[2]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_delta[3]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_delta[4]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_delta[5]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 6, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_delta[6]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_delta[7]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_delta[8]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_delta[9]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } })
}};
this->pipelines = {{
vk.shaders.getPipeline(vk.device, "p_delta[0]"),
vk.shaders.getPipeline(vk.device, "p_delta[1]"),
vk.shaders.getPipeline(vk.device, "p_delta[2]"),
vk.shaders.getPipeline(vk.device, "p_delta[3]"),
vk.shaders.getPipeline(vk.device, "p_delta[4]"),
vk.shaders.getPipeline(vk.device, "p_delta[5]"),
vk.shaders.getPipeline(vk.device, "p_delta[6]"),
vk.shaders.getPipeline(vk.device, "p_delta[7]"),
vk.shaders.getPipeline(vk.device, "p_delta[8]"),
vk.shaders.getPipeline(vk.device, "p_delta[9]")
}};
this->samplers.at(0) = vk.resources.getSampler(vk.device);
this->samplers.at(1) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true);
this->samplers.at(2) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
// create internal images/outputs
const VkExtent2D extent = this->inImgs1.at(0).at(0).getExtent();
for (size_t i = 0; i < 3; i++)
this->tempImgs1.at(i) = Core::Image(vk.device, extent);
for (size_t i = 0; i < 2; i++)
this->tempImgs2.at(i) = Core::Image(vk.device, extent);
this->outImg1 = Core::Image(vk.device,
{ extent.width, extent.height },
VK_FORMAT_R16G16B16A16_SFLOAT);
this->outImg2 = Core::Image(vk.device,
{ extent.width, extent.height },
VK_FORMAT_R16G16B16A16_SFLOAT);
// hook up shaders
for (size_t pass_idx = 0; pass_idx < vk.generationCount; pass_idx++) {
auto& pass = this->passes.emplace_back();
pass.buffer = vk.resources.getBuffer(vk.device,
static_cast<float>(pass_idx + 1) / static_cast<float>(vk.generationCount + 1),
false, !this->optImg1.has_value());
for (size_t i = 0; i < 3; i++) {
pass.firstDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(0));
pass.firstDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at((i + 2) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at(i % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1)
.build();
}
pass.descriptorSets.at(0) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(1));
pass.descriptorSets.at(0).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
pass.descriptorSets.at(1) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(2));
pass.descriptorSets.at(1).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(1))
.build();
pass.descriptorSets.at(2) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(3));
pass.descriptorSets.at(2).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(1))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
pass.descriptorSets.at(3) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(4));
pass.descriptorSets.at(3).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg1)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImg1)
.build();
for (size_t i = 0; i < 3; i++) {
pass.sixthDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(5));
pass.sixthDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at((i + 2) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at(i % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg1)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2.at(0))
.build();
}
pass.descriptorSets.at(4) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(6));
pass.descriptorSets.at(4).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(0))
.build();
pass.descriptorSets.at(5) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(7));
pass.descriptorSets.at(5).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2.at(0))
.build();
pass.descriptorSets.at(6) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(8));
pass.descriptorSets.at(6).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(0))
.build();
pass.descriptorSets.at(7) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(9));
pass.descriptorSets.at(7).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg3)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImg2)
.build();
}
}
void Delta::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx) {
auto& pass = this->passes.at(pass_idx);
// first shader
const auto extent = this->tempImgs1.at(0).getExtent();
const uint32_t threadsX = (extent.width + 7) >> 3;
const uint32_t threadsY = (extent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->inImgs1.at((frameCount + 2) % 3))
.addW2R(this->inImgs1.at(frameCount % 3))
.addW2R(this->optImg1)
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(0).bind(buf);
pass.firstDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(0));
buf.dispatch(threadsX, threadsY, 1);
// second shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(1).bind(buf);
pass.descriptorSets.at(0).bind(buf, this->pipelines.at(1));
buf.dispatch(threadsX, threadsY, 1);
// third shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(2).bind(buf);
pass.descriptorSets.at(1).bind(buf, this->pipelines.at(2));
buf.dispatch(threadsX, threadsY, 1);
// fourth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(3).bind(buf);
pass.descriptorSets.at(2).bind(buf, this->pipelines.at(3));
buf.dispatch(threadsX, threadsY, 1);
// fifth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addW2R(this->optImg1)
.addW2R(this->inImg2)
.addR2W(this->outImg1)
.build();
this->pipelines.at(4).bind(buf);
pass.descriptorSets.at(3).bind(buf, this->pipelines.at(4));
buf.dispatch(threadsX, threadsY, 1);
// sixth shader
Utils::BarrierBuilder(buf)
.addW2R(this->inImgs1.at((frameCount + 2) % 3))
.addW2R(this->inImgs1.at(frameCount % 3))
.addW2R(this->optImg1)
.addW2R(this->optImg2)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(5).bind(buf);
pass.sixthDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(5));
buf.dispatch(threadsX, threadsY, 1);
// seventh shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->tempImgs1.at(0))
.addR2W(this->tempImgs1.at(1))
.build();
this->pipelines.at(6).bind(buf);
pass.descriptorSets.at(4).bind(buf, this->pipelines.at(6));
buf.dispatch(threadsX, threadsY, 1);
// eighth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1.at(0))
.addW2R(this->tempImgs1.at(1))
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(7).bind(buf);
pass.descriptorSets.at(5).bind(buf, this->pipelines.at(7));
buf.dispatch(threadsX, threadsY, 1);
// ninth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->tempImgs1.at(0))
.addR2W(this->tempImgs1.at(1))
.build();
this->pipelines.at(8).bind(buf);
pass.descriptorSets.at(6).bind(buf, this->pipelines.at(8));
buf.dispatch(threadsX, threadsY, 1);
// tenth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1.at(0))
.addW2R(this->tempImgs1.at(1))
.addW2R(this->optImg3)
.addR2W(this->outImg2)
.build();
this->pipelines.at(9).bind(buf);
pass.descriptorSets.at(7).bind(buf, this->pipelines.at(9));
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,189 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1p/shaders/gamma.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <array>
#include <optional>
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1P::Shaders;
Gamma::Gamma(Vulkan& vk, std::array<std::array<Core::Image, 2>, 3> inImgs1,
Core::Image inImg2,
std::optional<Core::Image> optImg)
: inImgs1(std::move(inImgs1)), inImg2(std::move(inImg2)),
optImg(std::move(optImg)) {
// create resources
this->shaderModules = {{
vk.shaders.getShader(vk.device, "p_gamma[0]",
{ { 1 , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 5, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_gamma[1]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_gamma[2]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_gamma[3]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_gamma[4]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } })
}};
this->pipelines = {{
vk.shaders.getPipeline(vk.device, "p_gamma[0]"),
vk.shaders.getPipeline(vk.device, "p_gamma[1]"),
vk.shaders.getPipeline(vk.device, "p_gamma[2]"),
vk.shaders.getPipeline(vk.device, "p_gamma[3]"),
vk.shaders.getPipeline(vk.device, "p_gamma[4]")
}};
this->samplers.at(0) = vk.resources.getSampler(vk.device);
this->samplers.at(1) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true);
this->samplers.at(2) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
// create internal images/outputs
const VkExtent2D extent = this->inImgs1.at(0).at(0).getExtent();
for (size_t i = 0; i < 3; i++)
this->tempImgs1.at(i) = Core::Image(vk.device, extent);
for (size_t i = 0; i < 2; i++)
this->tempImgs2.at(i) = Core::Image(vk.device, extent);
this->outImg = Core::Image(vk.device,
{ extent.width, extent.height },
VK_FORMAT_R16G16B16A16_SFLOAT);
// hook up shaders
for (size_t pass_idx = 0; pass_idx < vk.generationCount; pass_idx++) {
auto& pass = this->passes.emplace_back();
pass.buffer = vk.resources.getBuffer(vk.device,
static_cast<float>(pass_idx + 1) / static_cast<float>(vk.generationCount + 1),
!this->optImg.has_value());
for (size_t i = 0; i < 3; i++) {
pass.firstDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(0));
pass.firstDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at((i + 2) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs1.at(i % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1)
.build();
}
pass.descriptorSets.at(0) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(1));
pass.descriptorSets.at(0).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
pass.descriptorSets.at(1) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(2));
pass.descriptorSets.at(1).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1.at(1))
.build();
pass.descriptorSets.at(2) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(3));
pass.descriptorSets.at(2).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1.at(1))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
pass.descriptorSets.at(3) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModules.at(4));
pass.descriptorSets.at(3).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(2))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->optImg)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImg)
.build();
}
}
void Gamma::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx) {
auto& pass = this->passes.at(pass_idx);
// first shader
const auto extent = this->tempImgs1.at(0).getExtent();
const uint32_t threadsX = (extent.width + 7) >> 3;
const uint32_t threadsY = (extent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->inImgs1.at((frameCount + 2) % 3))
.addW2R(this->inImgs1.at(frameCount % 3))
.addW2R(this->optImg)
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(0).bind(buf);
pass.firstDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(0));
buf.dispatch(threadsX, threadsY, 1);
// second shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(1).bind(buf);
pass.descriptorSets.at(0).bind(buf, this->pipelines.at(1));
buf.dispatch(threadsX, threadsY, 1);
// third shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->tempImgs1.at(0))
.addR2W(this->tempImgs1.at(1))
.build();
this->pipelines.at(2).bind(buf);
pass.descriptorSets.at(1).bind(buf, this->pipelines.at(2));
buf.dispatch(threadsX, threadsY, 1);
// fourth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1.at(0))
.addW2R(this->tempImgs1.at(1))
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(3).bind(buf);
pass.descriptorSets.at(2).bind(buf, this->pipelines.at(3));
buf.dispatch(threadsX, threadsY, 1);
// fifth shader
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addW2R(this->optImg)
.addW2R(this->inImg2)
.addR2W(this->outImg)
.build();
this->pipelines.at(4).bind(buf);
pass.descriptorSets.at(3).bind(buf, this->pipelines.at(4));
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,83 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1p/shaders/generate.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <vector>
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1P::Shaders;
Generate::Generate(Vulkan& vk,
Core::Image inImg1, Core::Image inImg2,
Core::Image inImg3, Core::Image inImg4, Core::Image inImg5,
const std::vector<int>& fds, VkFormat format)
: inImg1(std::move(inImg1)), inImg2(std::move(inImg2)),
inImg3(std::move(inImg3)), inImg4(std::move(inImg4)),
inImg5(std::move(inImg5)) {
// create resources
this->shaderModule = vk.shaders.getShader(vk.device, "generate",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 5, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } });
this->pipeline = vk.shaders.getPipeline(vk.device, "generate");
this->samplers.at(0) = vk.resources.getSampler(vk.device);
this->samplers.at(1) = vk.resources.getSampler(vk.device,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS);
// create internal images/outputs
const VkExtent2D extent = this->inImg1.getExtent();
for (size_t i = 0; i < vk.generationCount; i++)
this->outImgs.emplace_back(vk.device, extent, format,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_IMAGE_ASPECT_COLOR_BIT, fds.empty() ? -1 : fds.at(i));
// hook up shaders
for (size_t i = 0; i < vk.generationCount; i++) {
auto& pass = this->passes.emplace_back();
pass.buffer = vk.resources.getBuffer(vk.device,
static_cast<float>(i + 1) / static_cast<float>(vk.generationCount + 1));
for (size_t j = 0; j < 2; j++) {
pass.descriptorSet.at(j) = Core::DescriptorSet(vk.device, vk.descriptorPool,
this->shaderModule);
pass.descriptorSet.at(j).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, pass.buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, j == 0 ? this->inImg2 : this->inImg1)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, j == 0 ? this->inImg1 : this->inImg2)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg3)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg4)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg5)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs.at(i))
.build();
}
}
}
void Generate::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount, uint64_t pass_idx) {
auto& pass = this->passes.at(pass_idx);
// first pass
const auto extent = this->inImg1.getExtent();
const uint32_t threadsX = (extent.width + 15) >> 4;
const uint32_t threadsY = (extent.height + 15) >> 4;
Utils::BarrierBuilder(buf)
.addW2R(this->inImg1)
.addW2R(this->inImg2)
.addW2R(this->inImg3)
.addW2R(this->inImg4)
.addW2R(this->inImg5)
.addR2W(this->outImgs.at(pass_idx))
.build();
this->pipeline.bind(buf);
pass.descriptorSet.at(frameCount % 2).bind(buf, this->pipeline);
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -7,6 +7,11 @@ set(BACKEND_SOURCES
"src/shaderchains/alpha1.cpp"
"src/shaderchains/beta0.cpp"
"src/shaderchains/beta1.cpp"
"src/shaderchains/delta0.cpp"
"src/shaderchains/delta1.cpp"
"src/shaderchains/gamma0.cpp"
"src/shaderchains/gamma1.cpp"
"src/shaderchains/generate.cpp"
"src/shaderchains/mipmaps.cpp"
"src/lsfgvk.cpp")

View file

@ -9,11 +9,8 @@ using namespace ls;
ConstantBuffer ls::getDefaultConstantBuffer(
size_t index, size_t total,
bool hdr, float invFlow,
bool isFirst, bool isFirst2) {
bool hdr, float invFlow) {
return ConstantBuffer {
.firstIter = isFirst ? 1U : 0U,
.firstIterS = isFirst2 ? 1U : 0U,
.advancedColorKind = hdr ? 2U : 0U,
.hdrSupport = hdr ? 1U : 0U,
.resolutionInvScale = invFlow,

View file

@ -9,6 +9,7 @@
#include <array>
#include <cstddef>
#include <cstdint>
#include <vector>
#include <vulkan/vulkan_core.h>
@ -19,6 +20,7 @@ namespace ls {
ls::R<const extr::ShaderRegistry> shaders; // safe back reference
vk::Buffer constantBuffer;
std::vector<vk::Buffer> constantBuffers;
vk::Sampler bnbSampler; //!< border, no compare, black
vk::Sampler bnwSampler; //!< border, no compare, white
vk::Sampler eabSampler; //!< edge, always compare, black
@ -50,13 +52,10 @@ namespace ls {
/// @param total total amount of images
/// @param hdr whether HDR is enabled
/// @param invFlow inverted flow scale value
/// @param isFirst whether this is the first iteration
/// @param isFirst2 whether this is the first iteration (second flag)
/// @return prefilled constant buffer
ConstantBuffer getDefaultConstantBuffer(
size_t index, size_t total,
bool hdr, float invFlow,
bool isFirst, bool isFirst2 // TODO: figure out if necessary
bool hdr, float invFlow
);
/// round down a VkExtent2D

View file

@ -3,6 +3,8 @@
#include "extraction/shader_registry.hpp"
#include "helpers/utils.hpp"
#include "lsfg-vk-common/helpers/errors.hpp"
#include "lsfg-vk-common/helpers/pointers.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/timeline_semaphore.hpp"
@ -11,6 +13,11 @@
#include "shaderchains/alpha1.hpp"
#include "shaderchains/beta0.hpp"
#include "shaderchains/beta1.hpp"
#include "shaderchains/delta0.hpp"
#include "shaderchains/delta1.hpp"
#include "shaderchains/gamma0.hpp"
#include "shaderchains/gamma1.hpp"
#include "shaderchains/generate.hpp"
#include "shaderchains/mipmaps.hpp"
#include <algorithm>
@ -82,6 +89,7 @@ namespace lsfgvk {
private:
std::pair<vk::Image, vk::Image> sourceImages;
std::vector<vk::Image> destImages;
vk::Image blackImage;
vk::TimelineSemaphore syncSemaphore; // imported
vk::TimelineSemaphore prepassSemaphore;
@ -98,6 +106,15 @@ namespace lsfgvk {
std::array<chains::Alpha1, 7> alpha1;
chains::Beta0 beta0;
chains::Beta1 beta1;
struct Pass {
std::vector<chains::Gamma0> gamma0;
std::vector<chains::Gamma1> gamma1;
std::vector<chains::Delta0> delta0;
std::vector<chains::Delta1> delta1;
ls::lazy<chains::Generate> generate;
};
std::vector<Pass> passes;
};
}
@ -236,6 +253,16 @@ namespace {
throw lsfgvk::error("Unable to import destination images", e);
}
}
/// create a black image
vk::Image createBlackImage(const vk::Vulkan& vk) {
try {
return{vk,
{ .width = 4, .height = 4 }
};
} catch (const std::exception& e) {
throw lsfgvk::error("Unable to create black image", e);
}
}
/// import timeline semaphore
vk::TimelineSemaphore importTimelineSemaphore(const vk::Vulkan& vk, int syncFd) {
try {
@ -273,12 +300,23 @@ namespace {
const auto& shaders = instance.getShaderRegistry();
try {
std::vector<vk::Buffer> constantBuffers{};
constantBuffers.reserve(count);
for (size_t i = 0; i < count; ++i)
constantBuffers.emplace_back(vk,
ls::getDefaultConstantBuffer(
i, count,
hdr, flow
)
);
return {
.vk = std::ref(vk),
.shaders = std::ref(shaders),
.constantBuffer{vk,
ls::getDefaultConstantBuffer(0, 1,
hdr, flow, false, false)},
ls::getDefaultConstantBuffer(0, 1, hdr, flow)},
.constantBuffers{std::move(constantBuffers)},
.bnbSampler{vk, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, false},
.bnwSampler{vk, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true},
.eabSampler{vk, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false},
@ -305,6 +343,7 @@ ContextImpl::ContextImpl(const InstanceImpl& instance,
extent, hdr ? VK_FORMAT_R16G16B16A16_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM)),
destImages(importImages(instance.getVulkan(), destFds,
extent, hdr ? VK_FORMAT_R16G16B16A16_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM)),
blackImage(createBlackImage(instance.getVulkan())),
syncSemaphore(importTimelineSemaphore(instance.getVulkan(), syncFd)),
prepassSemaphore(createPrepassSemaphore(instance.getVulkan())),
cmdbufs(createCommandBuffers(instance.getVulkan(), 16)),
@ -330,8 +369,80 @@ ContextImpl::ContextImpl(const InstanceImpl& instance,
},
beta0(ctx, alpha1.at(0).getImages()),
beta1(ctx, beta0.getImages()) {
// build main passes
for (size_t i = 0; i < destImages.size(); ++i) {
auto& pass = this->passes.emplace_back();
pass.gamma0.reserve(7);
pass.gamma1.reserve(7);
pass.delta0.reserve(3);
pass.delta1.reserve(3);
for (size_t j = 0; j < 7; j++) {
if (j == 0) { // first pass has no prior data
pass.gamma0.emplace_back(ctx, i,
this->alpha1.at(6 - j).getImages(),
this->blackImage
);
pass.gamma1.emplace_back(ctx, i,
pass.gamma0.at(j).getImages(),
this->blackImage,
this->beta1.getImages().at(5)
);
} else { // other passes use prior data
pass.gamma0.emplace_back(ctx, i,
this->alpha1.at(6 - j).getImages(),
pass.gamma1.at(j - 1).getImage()
);
pass.gamma1.emplace_back(ctx, i,
pass.gamma0.at(j).getImages(),
pass.gamma1.at(j - 1).getImage(),
this->beta1.getImages().at(6 - j)
);
}
if (j == 4) { // first special pass has no prior data
pass.delta0.emplace_back(ctx, i,
this->alpha1.at(6 - j).getImages(),
this->blackImage,
pass.gamma1.at(j - 1).getImage(),
this->blackImage
);
pass.delta1.emplace_back(ctx, i,
pass.delta0.at(j - 4).getImages0(),
pass.delta0.at(j - 4).getImages1(),
this->blackImage,
this->beta1.getImages().at(6 - j),
this->blackImage
);
} else if (j > 4) { // further passes do
pass.delta0.emplace_back(ctx, i,
this->alpha1.at(6 - j).getImages(),
pass.delta1.at(j - 5).getImage0(),
pass.gamma1.at(j - 1).getImage(),
this->beta1.getImages().at(6 - j)
);
pass.delta1.emplace_back(ctx, i,
pass.delta0.at(j - 4).getImages0(),
pass.delta0.at(j - 4).getImages1(),
pass.delta1.at(j - 5).getImage0(),
this->beta1.getImages().at(6 - j),
pass.delta1.at(j - 5).getImage1()
);
}
}
pass.generate.emplace(ctx, i,
this->sourceImages,
pass.gamma1.at(6).getImage(),
pass.delta1.at(2).getImage0(),
pass.delta1.at(2).getImage1(),
this->destImages.at(i)
);
}
// initialize all images
const vk::CommandBuffer cmdbuf{ctx.vk};
cmdbuf.prepareImage(this->blackImage);
mipmaps.prepare(cmdbuf);
for (size_t i = 0; i < 7; ++i) {
alpha0.at(i).prepare(cmdbuf);
@ -339,6 +450,16 @@ ContextImpl::ContextImpl(const InstanceImpl& instance,
}
beta0.prepare(cmdbuf);
beta1.prepare(cmdbuf);
for (const auto& pass : this->passes) {
for (size_t i = 0; i < 7; ++i) {
pass.gamma0.at(i).prepare(cmdbuf);
pass.gamma1.at(i).prepare(cmdbuf);
if (i < 4) continue;
pass.delta0.at(i - 4).prepare(cmdbuf);
pass.delta1.at(i - 4).prepare(cmdbuf);
}
}
cmdbuf.submit(ctx.vk); // wait for completion
}
@ -387,11 +508,20 @@ void Context::scheduleFrames() {
this->idx++;
// schedule main passes
for (size_t i = 0; i < this->destImages.size(); ++i) {
for (size_t i = 0; i < this->destImages.size(); i++) {
vk::CommandBuffer& cmdbuf = this->cmdbufs.at(this->cmdbuf_idx++ % this->cmdbufs.size());
cmdbuf = vk::CommandBuffer(this->ctx.vk);
// (...)
const auto& pass = this->passes.at(i);
for (size_t j = 0; j < 7; j++) {
pass.gamma0.at(j).render(cmdbuf, this->fidx);
pass.gamma1.at(j).render(cmdbuf);
if (j < 4) continue;
pass.delta0.at(j - 4).render(cmdbuf, this->fidx);
pass.delta1.at(j - 4).render(cmdbuf);
}
pass.generate->render(cmdbuf, this->fidx);
cmdbuf.submit(this->ctx.vk,
this->prepassSemaphore, this->idx - 1,

View file

@ -0,0 +1,73 @@
#include "delta0.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/helpers/pointers.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <cstddef>
#include <vector>
#include <vulkan/vulkan_core.h>
using namespace chains;
Delta0::Delta0(const ls::Ctx& ctx, size_t idx,
const std::vector<std::vector<vk::Image>>& sourceImages,
const vk::Image& additionalInput0,
const vk::Image& additionalInput1,
const vk::Image& additionalInput2) {
const size_t m = ctx.perf ? 1 : 2; // multiplier
const VkExtent2D extent = sourceImages.at(0).at(0).getExtent();
// create output images
this->images0.reserve(3);
for(size_t i = 0; i < 3; i++)
this->images0.emplace_back(ctx.vk, extent);
this->images1.reserve(m);
for (size_t i = 0; i < m; i++)
this->images1.emplace_back(ctx.vk, extent);
// create descriptor sets
const auto& shaders = (ctx.perf ?
ctx.shaders.get().performance : ctx.shaders.get().quality).delta;
this->sets0.reserve(3);
for (size_t i = 0; i < 3; i++)
this->sets0.emplace_back(ls::ManagedShaderBuilder()
.sampleds(sourceImages.at((i + 2) % 3))
.sampleds(sourceImages.at(i % 3))
.sampled(additionalInput0)
.storages(this->images0)
.sampler(ctx.bnwSampler)
.sampler(ctx.eabSampler)
.buffer(ctx.constantBuffers.at(idx))
.build(ctx.vk, shaders.at(0)));
this->sets1.reserve(3);
for (size_t i = 0; i < 3; i++)
this->sets1.emplace_back(ls::ManagedShaderBuilder()
.sampleds(sourceImages.at((i + 2) % 3))
.sampleds(sourceImages.at(i % 3))
.sampled(additionalInput1)
.sampled(additionalInput2)
.storages(this->images1)
.sampler(ctx.bnwSampler)
.sampler(ctx.eabSampler)
.buffer(ctx.constantBuffers.at(idx))
.build(ctx.vk, shaders.at(5)));
// store dispatch extents
this->dispatchExtent = ls::add_shift_extent(extent, 7, 3);
}
void Delta0::prepare(const vk::CommandBuffer& cmd) const {
for (const auto& img : this->images0)
cmd.prepareImage(img);
for (const auto& img : this->images1)
cmd.prepareImage(img);
}
void Delta0::render(const vk::CommandBuffer& cmd, size_t idx) const {
this->sets0[idx % 3].dispatch(cmd, dispatchExtent);
this->sets1[idx % 3].dispatch(cmd, dispatchExtent);
}

View file

@ -0,0 +1,55 @@
#pragma once
#include "../helpers/managed_shader.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <vector>
#include <vulkan/vulkan_core.h>
namespace ctx { struct Ctx; }
namespace chains {
/// delta shaderchain
class Delta0 {
public:
/// create a delta shaderchain
/// @param ctx context
/// @param idx generated frame index
/// @param sourceImages source images
/// @param additionalInput0 additional input image
/// @param additionalInput1 additional input image
/// @param additionalInput2 additional input image
Delta0(const ls::Ctx& ctx, size_t idx,
const std::vector<std::vector<vk::Image>>& sourceImages,
const vk::Image& additionalInput0,
const vk::Image& additionalInput1,
const vk::Image& additionalInput2);
/// prepare the shaderchain initially
/// @param cmd command buffer
void prepare(const vk::CommandBuffer& cmd) const;
/// render the delta shaderchain
/// @param cmd command buffer
/// @param idx frame index
void render(const vk::CommandBuffer& cmd, size_t idx) const;
/// get the generated images
/// @return vector of images
[[nodiscard]] const auto& getImages0() const { return this->images0; }
/// get the other generated images
/// @return vector of images
[[nodiscard]] const auto& getImages1() const { return this->images1; }
private:
std::vector<vk::Image> images0;
std::vector<vk::Image> images1;
std::vector<ls::ManagedShader> sets0;
std::vector<ls::ManagedShader> sets1;
VkExtent2D dispatchExtent{};
};
}

View file

@ -0,0 +1,107 @@
#include "delta1.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/helpers/pointers.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <cstddef>
#include <vector>
#include <vulkan/vulkan_core.h>
using namespace chains;
Delta1::Delta1(const ls::Ctx& ctx, size_t idx,
const std::vector<vk::Image>& sourceImages0,
const std::vector<vk::Image>& sourceImages1,
const vk::Image& additionalInput0,
const vk::Image& additionalInput1,
const vk::Image& additionalInput2) {
const size_t m = ctx.perf ? 1 : 2; // multiplier
const VkExtent2D extent = sourceImages0.at(0).getExtent();
// create temporary & output images
for (size_t i = 0; i < (2 * m); i++) {
this->tempImages0.emplace_back(ctx.vk, extent);
this->tempImages1.emplace_back(ctx.vk, extent);
}
this->image0.emplace(ctx.vk,
VkExtent2D { extent.width, extent.height },
VK_FORMAT_R16G16B16A16_SFLOAT
);
this->image1.emplace(ctx.vk,
VkExtent2D { extent.width, extent.height },
VK_FORMAT_R16G16B16A16_SFLOAT
);
// create descriptor sets
const auto& shaders = (ctx.perf ?
ctx.shaders.get().performance : ctx.shaders.get().quality).delta;
this->sets.reserve(4 + 4);
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(sourceImages0)
.storages(this->tempImages0)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.at(1)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages0)
.storages(this->tempImages1)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.at(2)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages1)
.storages(this->tempImages0)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.at(3)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages0)
.sampled(additionalInput0)
.sampled(additionalInput1)
.storage(*this->image0)
.sampler(ctx.bnbSampler)
.sampler(ctx.eabSampler)
.buffer(ctx.constantBuffers.at(idx))
.build(ctx.vk, shaders.at(4)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(sourceImages1)
.storages(this->tempImages0, 0, m)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.at(6)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages0, 0, m)
.storages(this->tempImages1, 0, m)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.at(7)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages1, 0, m)
.storages(this->tempImages0, 0, m)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.at(8)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages0, 0, m)
.sampled(additionalInput2)
.storage(*this->image1)
.sampler(ctx.bnbSampler)
.sampler(ctx.eabSampler)
.buffer(ctx.constantBuffers.at(idx))
.build(ctx.vk, shaders.at(9)));
// store dispatch extents
this->dispatchExtent = ls::add_shift_extent(extent, 7, 3);
}
void Delta1::prepare(const vk::CommandBuffer& cmd) const {
for (size_t i = 0; i < this->tempImages0.size(); i++) {
cmd.prepareImage(this->tempImages0.at(i));
cmd.prepareImage(this->tempImages1.at(i));
}
cmd.prepareImage(*this->image0);
cmd.prepareImage(*this->image1);
}
void Delta1::render(const vk::CommandBuffer& cmd) const {
for (const auto& set : this->sets)
set.dispatch(cmd, dispatchExtent);
}

View file

@ -0,0 +1,58 @@
#pragma once
#include "../helpers/managed_shader.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/helpers/pointers.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <vector>
#include <vulkan/vulkan_core.h>
namespace ctx { struct Ctx; }
namespace chains {
/// gamma shaderchain
class Delta1 {
public:
/// create a gamma shaderchain
/// @param ctx context
/// @param idx generated frame index
/// @param sourceImages0 source images
/// @param sourceImages1 source images
/// @param additionalInput0 additional input image
/// @param additionalInput1 additional input image
/// @param additionalInput2 additional input image
Delta1(const ls::Ctx& ctx, size_t idx,
const std::vector<vk::Image>& sourceImages0,
const std::vector<vk::Image>& sourceImages1,
const vk::Image& additionalInput0,
const vk::Image& additionalInput1,
const vk::Image& additionalInput2);
/// prepare the shaderchain initially
/// @param cmd command buffer
void prepare(const vk::CommandBuffer& cmd) const;
/// render the gamma shaderchain
/// @param cmd command buffer
void render(const vk::CommandBuffer& cmd) const;
/// get the first generated image
/// @return image
[[nodiscard]] const auto& getImage0() const { return *this->image0; }
/// get the second generated image
/// @return image
[[nodiscard]] const auto& getImage1() const { return *this->image1; }
private:
std::vector<vk::Image> tempImages0;
std::vector<vk::Image> tempImages1;
ls::lazy<vk::Image> image0;
ls::lazy<vk::Image> image1;
std::vector<ls::ManagedShader> sets;
VkExtent2D dispatchExtent{};
};
}

View file

@ -0,0 +1,50 @@
#include "gamma0.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/helpers/pointers.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <cstddef>
#include <vector>
#include <vulkan/vulkan_core.h>
using namespace chains;
Gamma0::Gamma0(const ls::Ctx& ctx, size_t idx,
const std::vector<std::vector<vk::Image>>& sourceImages,
const vk::Image& additionalInput) {
const VkExtent2D extent = sourceImages.at(0).at(0).getExtent();
// create output images
this->images.reserve(3);
for(size_t i = 0; i < 3; i++)
this->images.emplace_back(ctx.vk, extent);
// create descriptor sets
const auto& shader = (ctx.perf ?
ctx.shaders.get().performance : ctx.shaders.get().quality).gamma.at(0);
this->sets.reserve(3);
for (size_t i = 0; i < 3; i++)
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(sourceImages.at((i + 2) % 3))
.sampleds(sourceImages.at(i % 3))
.sampled(additionalInput)
.storages(this->images)
.sampler(ctx.bnwSampler)
.sampler(ctx.eabSampler)
.buffer(ctx.constantBuffers.at(idx))
.build(ctx.vk, shader));
// store dispatch extents
this->dispatchExtent = ls::add_shift_extent(extent, 7, 3);
}
void Gamma0::prepare(const vk::CommandBuffer& cmd) const {
for (const auto& img : this->images)
cmd.prepareImage(img);
}
void Gamma0::render(const vk::CommandBuffer& cmd, size_t idx) const {
this->sets[idx % 3].dispatch(cmd, dispatchExtent);
}

View file

@ -0,0 +1,45 @@
#pragma once
#include "../helpers/managed_shader.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <vector>
#include <vulkan/vulkan_core.h>
namespace ctx { struct Ctx; }
namespace chains {
/// gamma shaderchain
class Gamma0 {
public:
/// create a gamma shaderchain
/// @param ctx context
/// @param idx generated frame index
/// @param sourceImages source images
/// @param additionalInput additional input image
Gamma0(const ls::Ctx& ctx, size_t idx,
const std::vector<std::vector<vk::Image>>& sourceImages,
const vk::Image& additionalInput);
/// prepare the shaderchain initially
/// @param cmd command buffer
void prepare(const vk::CommandBuffer& cmd) const;
/// render the gamma shaderchain
/// @param cmd command buffer
/// @param idx frame index
void render(const vk::CommandBuffer& cmd, size_t idx) const;
/// get the generated images
/// @return vector of images
[[nodiscard]] const auto& getImages() const { return this->images; }
private:
std::vector<vk::Image> images;
std::vector<ls::ManagedShader> sets;
VkExtent2D dispatchExtent{};
};
}

View file

@ -0,0 +1,75 @@
#include "gamma1.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/helpers/pointers.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <cstddef>
#include <vector>
#include <vulkan/vulkan_core.h>
using namespace chains;
Gamma1::Gamma1(const ls::Ctx& ctx, size_t idx,
const std::vector<vk::Image>& sourceImages,
const vk::Image& additionalInput0,
const vk::Image& additionalInput1) {
const size_t m = ctx.perf ? 1 : 2; // multiplier
const VkExtent2D extent = sourceImages.at(0).getExtent();
// create temporary & output images
for (size_t i = 0; i < (2 * m); i++) {
this->tempImages0.emplace_back(ctx.vk, extent);
this->tempImages1.emplace_back(ctx.vk, extent);
}
this->image.emplace(ctx.vk,
VkExtent2D { extent.width, extent.height },
VK_FORMAT_R16G16B16A16_SFLOAT
);
// create descriptor sets
const auto& shaders = (ctx.perf ?
ctx.shaders.get().performance : ctx.shaders.get().quality).gamma;
this->sets.reserve(4);
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(sourceImages)
.storages(this->tempImages0)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.at(1)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages0)
.storages(this->tempImages1)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.at(2)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages1)
.storages(this->tempImages0)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.at(3)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages0)
.sampled(additionalInput0)
.sampled(additionalInput1)
.storage(*this->image)
.sampler(ctx.bnbSampler)
.sampler(ctx.eabSampler)
.buffer(ctx.constantBuffers.at(idx))
.build(ctx.vk, shaders.at(4)));
// store dispatch extents
this->dispatchExtent = ls::add_shift_extent(extent, 7, 3);
}
void Gamma1::prepare(const vk::CommandBuffer& cmd) const {
for (size_t i = 0; i < this->tempImages0.size(); i++) {
cmd.prepareImage(this->tempImages0.at(i));
cmd.prepareImage(this->tempImages1.at(i));
}
cmd.prepareImage(*this->image);
}
void Gamma1::render(const vk::CommandBuffer& cmd) const {
for (const auto& set : this->sets)
set.dispatch(cmd, dispatchExtent);
}

View file

@ -0,0 +1,49 @@
#pragma once
#include "../helpers/managed_shader.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/helpers/pointers.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <vector>
#include <vulkan/vulkan_core.h>
namespace ctx { struct Ctx; }
namespace chains {
/// gamma shaderchain
class Gamma1 {
public:
/// create a gamma shaderchain
/// @param ctx context
/// @param idx generated frame index
/// @param sourceImages source images
/// @param additionalInput0 additional input image
/// @param additionalInput1 additional input image
Gamma1(const ls::Ctx& ctx, size_t idx,
const std::vector<vk::Image>& sourceImages,
const vk::Image& additionalInput0,
const vk::Image& additionalInput1);
/// prepare the shaderchain initially
/// @param cmd command buffer
void prepare(const vk::CommandBuffer& cmd) const;
/// render the gamma shaderchain
/// @param cmd command buffer
void render(const vk::CommandBuffer& cmd) const;
/// get the generated image
/// @return image
[[nodiscard]] const auto& getImage() const { return *this->image; }
private:
std::vector<vk::Image> tempImages0;
std::vector<vk::Image> tempImages1;
ls::lazy<vk::Image> image;
std::vector<ls::ManagedShader> sets;
VkExtent2D dispatchExtent{};
};
}

View file

@ -0,0 +1,52 @@
#include "generate.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/helpers/pointers.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <cstddef>
#include <utility>
#include <vector>
#include <vulkan/vulkan_core.h>
using namespace chains;
Generate::Generate(const ls::Ctx& ctx, size_t idx,
const std::pair<vk::Image, vk::Image>& sourceImages,
const vk::Image& inputImage1,
const vk::Image& inputImage2,
const vk::Image& inputImage3,
const vk::Image& outputImage) {
// create descriptor sets
this->sets.reserve(2);
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampled(sourceImages.second)
.sampled(sourceImages.first)
.sampled(inputImage1)
.sampled(inputImage2)
.sampled(inputImage3)
.storage(outputImage)
.sampler(ctx.bnbSampler)
.sampler(ctx.eabSampler)
.buffer(ctx.constantBuffers.at(idx))
.build(ctx.vk, ctx.shaders.get().generate));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampled(sourceImages.first)
.sampled(sourceImages.second)
.sampled(inputImage1)
.sampled(inputImage2)
.sampled(inputImage3)
.storage(outputImage)
.sampler(ctx.bnbSampler)
.sampler(ctx.eabSampler)
.buffer(ctx.constantBuffers.at(idx))
.build(ctx.vk, ctx.shaders.get().generate));
// store dispatch extent
this->dispatchExtent = ls::add_shift_extent(ctx.sourceExtent, 15, 4);
}
void Generate::render(const vk::CommandBuffer& cmd, size_t idx) const {
this->sets[idx % 2].dispatch(cmd, this->dispatchExtent);
}

View file

@ -0,0 +1,41 @@
#pragma once
#include "../helpers/managed_shader.hpp"
#include "../helpers/utils.hpp"
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
#include "lsfg-vk-common/vulkan/image.hpp"
#include <cstddef>
#include <vector>
#include <vulkan/vulkan_core.h>
namespace ctx { struct Ctx; }
namespace chains {
/// generate shaderchain
class Generate {
public:
/// create a generate shaderchain
/// @param ctx context
/// @param idx generated frame index
/// @param sourceImages pair of source images
/// @param inputImage1 input image 1
/// @param inputImage2 input image 2
/// @param inputImage3 input image 3
Generate(const ls::Ctx& ctx, size_t idx,
const std::pair<vk::Image, vk::Image>& sourceImages,
const vk::Image& inputImage1,
const vk::Image& inputImage2,
const vk::Image& inputImage3,
const vk::Image& outputImage);
/// render the generate shaderchain
/// @param cmd command buffer
/// @param idx frame index
void render(const vk::CommandBuffer& cmd, size_t idx) const;
private:
std::vector<ls::ManagedShader> sets;
VkExtent2D dispatchExtent{};
};
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <functional>
#include <optional>
#include <stdexcept>
namespace ls {
@ -8,6 +9,47 @@ namespace ls {
template<typename T>
using R = std::reference_wrapper<T>;
/// helper (eyecandy) alias for std::optional
template<typename T>
class lazy {
public:
/// default constructor
lazy() = default;
/// emplace value
/// @param args constructor arguments
/// @return reference to constructed value
/// @throws std::logic_error if value already present
template<typename... Args>
T& emplace(Args&&... args) {
if (this->opt.has_value())
throw std::logic_error("lazy: value already present");
this->opt.emplace(std::forward<Args>(args)...);
return *this->opt;
}
/// get reference to value
/// @return reference to value
/// @throws std::logic_error if no value present
const T& operator*() const {
if (!this->opt.has_value())
throw std::logic_error("lazy: no value present");
return *this->opt;
}
/// get pointer to value
/// @return pointer to value
/// @throws std::logic_error if no value present
const T* operator->() const {
if (!this->opt.has_value())
throw std::logic_error("lazy: no value present");
return &(*this->opt);
}
private:
std::optional<T> opt{};
};
/// simplified alternative to std::optional<std::unique_ptr>
template<typename T>
class owned_ptr {