refactor(cleanup): rewrite pre-pass in new abstraction

This commit is contained in:
PancakeTAS 2025-12-01 08:50:20 +01:00
parent 5ca9bc5de9
commit c3d6cdfc28
24 changed files with 568 additions and 1109 deletions

View file

@ -1,62 +0,0 @@
#pragma once
#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>
namespace LSFG_3_1::Shaders {
using namespace LSFG;
///
/// Alpha shader.
///
class Alpha {
public:
Alpha() = default;
///
/// Initialize the shaderchain.
///
/// @param inImg One mipmap level
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Alpha(Vulkan& vk, Core::Image inImg);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount);
/// Get the output images
[[nodiscard]] const auto& getOutImages() const { return this->outImgs; }
/// Trivially copyable, moveable and destructible
Alpha(const Alpha&) noexcept = default;
Alpha& operator=(const Alpha&) noexcept = default;
Alpha(Alpha&&) noexcept = default;
Alpha& operator=(Alpha&&) noexcept = default;
~Alpha() = default;
private:
std::array<Core::ShaderModule, 4> shaderModules;
std::array<Core::Pipeline, 4> pipelines;
Core::Sampler sampler;
std::array<Core::DescriptorSet, 3> descriptorSets;
std::array<Core::DescriptorSet, 3> lastDescriptorSet;
Core::Image inImg;
std::array<Core::Image, 2> tempImgs1;
std::array<Core::Image, 2> tempImgs2;
std::array<Core::Image, 4> tempImgs3;
std::array<std::array<Core::Image, 4>, 3> outImgs;
};
}

View file

@ -1,63 +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>
namespace LSFG_3_1::Shaders {
using namespace LSFG;
///
/// Beta shader.
///
class Beta {
public:
Beta() = default;
///
/// Initialize the shaderchain.
///
/// @param inImgs Three sets of four RGBA images, corresponding to a frame count % 3.
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Beta(Vulkan& vk, std::array<std::array<Core::Image, 4>, 3> inImgs);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount);
/// Get the output images
[[nodiscard]] const auto& getOutImages() const { return this->outImgs; }
/// Trivially copyable, moveable and destructible
Beta(const Beta&) noexcept = default;
Beta& operator=(const Beta&) noexcept = default;
Beta(Beta&&) noexcept = default;
Beta& operator=(Beta&&) noexcept = default;
~Beta() = default;
private:
std::array<Core::ShaderModule, 5> shaderModules;
std::array<Core::Pipeline, 5> pipelines;
std::array<Core::Sampler, 2> samplers;
Core::Buffer buffer;
std::array<Core::DescriptorSet, 3> firstDescriptorSet;
std::array<Core::DescriptorSet, 4> descriptorSets;
std::array<std::array<Core::Image, 4>, 3> inImgs;
std::array<Core::Image, 2> tempImgs1;
std::array<Core::Image, 2> tempImgs2;
std::array<Core::Image, 6> outImgs;
};
}

View file

@ -1,61 +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>
namespace LSFG_3_1::Shaders {
using namespace LSFG;
///
/// Mipmaps shader.
///
class Mipmaps {
public:
Mipmaps() = default;
///
/// Initialize the shaderchain.
///
/// @param inImg_0 The next frame (when fc % 2 == 0)
/// @param inImg_1 The next frame (when fc % 2 == 1)
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Mipmaps(Vulkan& vk, Core::Image inImg_0, Core::Image inImg_1);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount);
/// Get the output images.
[[nodiscard]] const auto& getOutImages() const { return this->outImgs; }
/// Trivially copyable, moveable and destructible
Mipmaps(const Mipmaps&) noexcept = default;
Mipmaps& operator=(const Mipmaps&) noexcept = default;
Mipmaps(Mipmaps&&) noexcept = default;
Mipmaps& operator=(Mipmaps&&) noexcept = default;
~Mipmaps() = default;
private:
Core::ShaderModule shaderModule;
Core::Pipeline pipeline;
Core::Buffer buffer;
Core::Sampler sampler;
std::array<Core::DescriptorSet, 2> descriptorSets;
Core::Image inImg_0, inImg_1;
std::array<Core::Image, 7> outImgs;
};
}

View file

@ -1,140 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1/shaders/alpha.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1::Shaders;
Alpha::Alpha(Vulkan& vk, Core::Image inImg) : inImg(std::move(inImg)) {
// create resources
this->shaderModules = {{
vk.shaders.getShader(vk.device, "alpha[0]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "alpha[1]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "alpha[2]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "alpha[3]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } })
}};
this->pipelines = {{
vk.shaders.getPipeline(vk.device, "alpha[0]"),
vk.shaders.getPipeline(vk.device, "alpha[1]"),
vk.shaders.getPipeline(vk.device, "alpha[2]"),
vk.shaders.getPipeline(vk.device, "alpha[3]")
}};
this->sampler = vk.resources.getSampler(vk.device);
for (size_t i = 0; i < 3; i++)
this->descriptorSets.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModules.at(i));
for (size_t i = 0; i < 3; i++)
this->lastDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModules.at(3));
// create internal images/outputs
const VkExtent2D 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->tempImgs1.at(i) = Core::Image(vk.device, halfExtent);
this->tempImgs2.at(i) = Core::Image(vk.device, halfExtent);
}
const VkExtent2D quarterExtent = {
.width = (halfExtent.width + 1) >> 1,
.height = (halfExtent.height + 1) >> 1
};
for (size_t i = 0; i < 4; i++) {
this->tempImgs3.at(i) = Core::Image(vk.device, quarterExtent);
for (size_t j = 0; j < 3; j++)
this->outImgs.at(j).at(i) = Core::Image(vk.device, quarterExtent);
}
// hook up shaders
this->descriptorSets.at(0).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1)
.build();
this->descriptorSets.at(1).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs2)
.build();
this->descriptorSets.at(2).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs3)
.build();
for (size_t i = 0; i < 3; i++)
this->lastDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs3)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs.at(i))
.build();
}
void Alpha::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount) {
// first pass
const auto halfExtent = this->tempImgs1.at(0).getExtent();
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));
buf.dispatch(threadsX, threadsY, 1);
// second pass
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
const auto quarterExtent = this->tempImgs3.at(0).getExtent();
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));
buf.dispatch(threadsX, threadsY, 1);
// fourth pass
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs3)
.addR2W(this->outImgs.at(frameCount % 3))
.build();
this->pipelines.at(3).bind(buf);
this->lastDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(3));
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,162 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1/shaders/beta.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <array>
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1::Shaders;
Beta::Beta(Vulkan& vk, std::array<std::array<Core::Image, 4>, 3> inImgs)
: inImgs(std::move(inImgs)) {
// create resources
this->shaderModules = {{
vk.shaders.getShader(vk.device, "beta[0]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 12, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "beta[1]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "beta[2]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "beta[3]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "beta[4]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 6, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } })
}};
this->pipelines = {{
vk.shaders.getPipeline(vk.device, "beta[0]"),
vk.shaders.getPipeline(vk.device, "beta[1]"),
vk.shaders.getPipeline(vk.device, "beta[2]"),
vk.shaders.getPipeline(vk.device, "beta[3]"),
vk.shaders.getPipeline(vk.device, "beta[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);
for (size_t i = 0; i < 3; i++)
this->firstDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModules.at(0));
for (size_t i = 0; i < 4; i++)
this->descriptorSets.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModules.at(i + 1));
this->buffer = vk.resources.getBuffer(vk.device, 0.5F);
// create internal images/outputs
const VkExtent2D extent = this->inImgs.at(0).at(0).getExtent();
for (size_t i = 0; i < 2; i++) {
this->tempImgs1.at(i) = Core::Image(vk.device, extent);
this->tempImgs2.at(i) = Core::Image(vk.device, extent);
}
for (size_t i = 0; i < 6; i++)
this->outImgs.at(i) = Core::Image(vk.device,
{ extent.width >> i, extent.height >> i },
VK_FORMAT_R8_UNORM);
// hook up shaders
for (size_t i = 0; i < 3; i++) {
this->firstDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs.at((i + 1) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs.at((i + 2) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs.at(i % 3))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1)
.build();
}
this->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();
this->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();
this->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();
this->descriptorSets.at(3).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, this->buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs)
.build();
}
void Beta::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount) {
// first pass
const auto extent = this->tempImgs1.at(0).getExtent();
uint32_t threadsX = (extent.width + 7) >> 3;
uint32_t threadsY = (extent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->inImgs.at(0))
.addW2R(this->inImgs.at(1))
.addW2R(this->inImgs.at(2))
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(0).bind(buf);
this->firstDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(0));
buf.dispatch(threadsX, threadsY, 1);
// second pass
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(1).bind(buf);
this->descriptorSets.at(0).bind(buf, this->pipelines.at(1));
buf.dispatch(threadsX, threadsY, 1);
// third pass
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(2).bind(buf);
this->descriptorSets.at(1).bind(buf, this->pipelines.at(2));
buf.dispatch(threadsX, threadsY, 1);
// fourth pass
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(3).bind(buf);
this->descriptorSets.at(2).bind(buf, this->pipelines.at(3));
buf.dispatch(threadsX, threadsY, 1);
// fifth pass
threadsX = (extent.width + 31) >> 5;
threadsY = (extent.height + 31) >> 5;
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->outImgs)
.build();
this->pipelines.at(4).bind(buf);
this->descriptorSets.at(3).bind(buf, this->pipelines.at(4));
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,66 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1/shaders/mipmaps.hpp"
#include "common/utils.hpp"
#include "core/image.hpp"
#include "core/commandbuffer.hpp"
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1::Shaders;
Mipmaps::Mipmaps(Vulkan& vk,
Core::Image inImg_0, Core::Image inImg_1)
: inImg_0(std::move(inImg_0)), inImg_1(std::move(inImg_1)) {
// create resources
this->shaderModule = vk.shaders.getShader(vk.device, "mipmaps",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 7, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } });
this->pipeline = vk.shaders.getPipeline(vk.device, "mipmaps");
this->buffer = vk.resources.getBuffer(vk.device);
this->sampler = vk.resources.getSampler(vk.device);
for (size_t i = 0; i < 2; i++)
this->descriptorSets.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModule);
// create outputs
const VkExtent2D flowExtent{
.width = static_cast<uint32_t>(
static_cast<float>(this->inImg_0.getExtent().width) / vk.flowScale),
.height = static_cast<uint32_t>(
static_cast<float>(this->inImg_0.getExtent().height) / vk.flowScale)
};
for (size_t i = 0; i < 7; i++)
this->outImgs.at(i) = Core::Image(vk.device,
{ flowExtent.width >> i, flowExtent.height >> i },
VK_FORMAT_R8_UNORM);
// hook up shaders
for (size_t fc = 0; fc < 2; fc++)
this->descriptorSets.at(fc).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, this->buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, (fc % 2 == 0) ? this->inImg_0 : this->inImg_1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs)
.build();
}
void Mipmaps::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount) {
// first pass
const auto flowExtent = this->outImgs.at(0).getExtent();
const uint32_t threadsX = (flowExtent.width + 63) >> 6;
const uint32_t threadsY = (flowExtent.height + 63) >> 6;
Utils::BarrierBuilder(buf)
.addW2R((frameCount % 2 == 0) ? this->inImg_0 : this->inImg_1)
.addR2W(this->outImgs)
.build();
this->pipeline.bind(buf);
this->descriptorSets.at(frameCount % 2).bind(buf, this->pipeline);
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,62 +0,0 @@
#pragma once
#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>
namespace LSFG_3_1P::Shaders {
using namespace LSFG;
///
/// Alpha shader.
///
class Alpha {
public:
Alpha() = default;
///
/// Initialize the shaderchain.
///
/// @param inImg One mipmap level
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Alpha(Vulkan& vk, Core::Image inImg);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount);
/// Get the output images
[[nodiscard]] const auto& getOutImages() const { return this->outImgs; }
/// Trivially copyable, moveable and destructible
Alpha(const Alpha&) noexcept = default;
Alpha& operator=(const Alpha&) noexcept = default;
Alpha(Alpha&&) noexcept = default;
Alpha& operator=(Alpha&&) noexcept = default;
~Alpha() = default;
private:
std::array<Core::ShaderModule, 4> shaderModules;
std::array<Core::Pipeline, 4> pipelines;
Core::Sampler sampler;
std::array<Core::DescriptorSet, 3> descriptorSets;
std::array<Core::DescriptorSet, 3> lastDescriptorSet;
Core::Image inImg;
Core::Image tempImg1;
Core::Image tempImg2;
std::array<Core::Image, 2> tempImgs3;
std::array<std::array<Core::Image, 2>, 3> outImgs;
};
}

View file

@ -1,63 +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>
namespace LSFG_3_1P::Shaders {
using namespace LSFG;
///
/// Beta shader.
///
class Beta {
public:
Beta() = default;
///
/// Initialize the shaderchain.
///
/// @param inImgs Three sets of two RGBA images, corresponding to a frame count % 3.
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Beta(Vulkan& vk, std::array<std::array<Core::Image, 2>, 3> inImgs);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount);
/// Get the output images
[[nodiscard]] const auto& getOutImages() const { return this->outImgs; }
/// Trivially copyable, moveable and destructible
Beta(const Beta&) noexcept = default;
Beta& operator=(const Beta&) noexcept = default;
Beta(Beta&&) noexcept = default;
Beta& operator=(Beta&&) noexcept = default;
~Beta() = default;
private:
std::array<Core::ShaderModule, 5> shaderModules;
std::array<Core::Pipeline, 5> pipelines;
std::array<Core::Sampler, 2> samplers;
Core::Buffer buffer;
std::array<Core::DescriptorSet, 3> firstDescriptorSet;
std::array<Core::DescriptorSet, 4> descriptorSets;
std::array<std::array<Core::Image, 2>, 3> inImgs;
std::array<Core::Image, 2> tempImgs1;
std::array<Core::Image, 2> tempImgs2;
std::array<Core::Image, 6> outImgs;
};
}

View file

@ -1,61 +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>
namespace LSFG_3_1P::Shaders {
using namespace LSFG;
///
/// Mipmaps shader.
///
class Mipmaps {
public:
Mipmaps() = default;
///
/// Initialize the shaderchain.
///
/// @param inImg_0 The next frame (when fc % 2 == 0)
/// @param inImg_1 The next frame (when fc % 2 == 1)
///
/// @throws LSFG::vulkan_error if resource creation fails.
///
Mipmaps(Vulkan& vk, Core::Image inImg_0, Core::Image inImg_1);
///
/// Dispatch the shaderchain.
///
void Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount);
/// Get the output images.
[[nodiscard]] const auto& getOutImages() const { return this->outImgs; }
/// Trivially copyable, moveable and destructible
Mipmaps(const Mipmaps&) noexcept = default;
Mipmaps& operator=(const Mipmaps&) noexcept = default;
Mipmaps(Mipmaps&&) noexcept = default;
Mipmaps& operator=(Mipmaps&&) noexcept = default;
~Mipmaps() = default;
private:
Core::ShaderModule shaderModule;
Core::Pipeline pipeline;
Core::Buffer buffer;
Core::Sampler sampler;
std::array<Core::DescriptorSet, 2> descriptorSets;
Core::Image inImg_0, inImg_1;
std::array<Core::Image, 7> outImgs;
};
}

View file

@ -1,138 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1p/shaders/alpha.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1P::Shaders;
Alpha::Alpha(Vulkan& vk, Core::Image inImg) : inImg(std::move(inImg)) {
// create resources
this->shaderModules = {{
vk.shaders.getShader(vk.device, "p_alpha[0]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_alpha[1]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_alpha[2]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_alpha[3]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } })
}};
this->pipelines = {{
vk.shaders.getPipeline(vk.device, "p_alpha[0]"),
vk.shaders.getPipeline(vk.device, "p_alpha[1]"),
vk.shaders.getPipeline(vk.device, "p_alpha[2]"),
vk.shaders.getPipeline(vk.device, "p_alpha[3]")
}};
this->sampler = vk.resources.getSampler(vk.device);
for (size_t i = 0; i < 3; i++)
this->descriptorSets.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModules.at(i));
for (size_t i = 0; i < 3; i++)
this->lastDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModules.at(3));
// create internal images/outputs
const VkExtent2D extent = this->inImg.getExtent();
const VkExtent2D halfExtent = {
.width = (extent.width + 1) >> 1,
.height = (extent.height + 1) >> 1
};
this->tempImg1 = Core::Image(vk.device, halfExtent);
this->tempImg2 = Core::Image(vk.device, halfExtent);
const VkExtent2D quarterExtent = {
.width = (halfExtent.width + 1) >> 1,
.height = (halfExtent.height + 1) >> 1
};
for (size_t i = 0; i < 2; i++) {
this->tempImgs3.at(i) = Core::Image(vk.device, quarterExtent);
for (size_t j = 0; j < 3; j++)
this->outImgs.at(j).at(i) = Core::Image(vk.device, quarterExtent);
}
// hook up shaders
this->descriptorSets.at(0).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImg)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImg1)
.build();
this->descriptorSets.at(1).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImg1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImg2)
.build();
this->descriptorSets.at(2).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImg2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs3)
.build();
for (size_t i = 0; i < 3; i++)
this->lastDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs3)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs.at(i))
.build();
}
void Alpha::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount) {
// first pass
const auto halfExtent = this->tempImg1.getExtent();
uint32_t threadsX = (halfExtent.width + 7) >> 3;
uint32_t threadsY = (halfExtent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->inImg)
.addR2W(this->tempImg1)
.build();
this->pipelines.at(0).bind(buf);
this->descriptorSets.at(0).bind(buf, this->pipelines.at(0));
buf.dispatch(threadsX, threadsY, 1);
// second pass
Utils::BarrierBuilder(buf)
.addW2R(this->tempImg1)
.addR2W(this->tempImg2)
.build();
this->pipelines.at(1).bind(buf);
this->descriptorSets.at(1).bind(buf, this->pipelines.at(1));
buf.dispatch(threadsX, threadsY, 1);
// third pass
const auto quarterExtent = this->tempImgs3.at(0).getExtent();
threadsX = (quarterExtent.width + 7) >> 3;
threadsY = (quarterExtent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->tempImg2)
.addR2W(this->tempImgs3)
.build();
this->pipelines.at(2).bind(buf);
this->descriptorSets.at(2).bind(buf, this->pipelines.at(2));
buf.dispatch(threadsX, threadsY, 1);
// fourth pass
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs3)
.addR2W(this->outImgs.at(frameCount % 3))
.build();
this->pipelines.at(3).bind(buf);
this->lastDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(3));
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,162 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1p/shaders/beta.hpp"
#include "common/utils.hpp"
#include "core/commandbuffer.hpp"
#include "core/image.hpp"
#include <array>
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1P::Shaders;
Beta::Beta(Vulkan& vk, std::array<std::array<Core::Image, 2>, 3> inImgs)
: inImgs(std::move(inImgs)) {
// create resources
this->shaderModules = {{
vk.shaders.getShader(vk.device, "p_beta[0]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 6, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_beta[1]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_beta[2]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_beta[3]",
{ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } }),
vk.shaders.getShader(vk.device, "p_beta[4]",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 6, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } })
}};
this->pipelines = {{
vk.shaders.getPipeline(vk.device, "p_beta[0]"),
vk.shaders.getPipeline(vk.device, "p_beta[1]"),
vk.shaders.getPipeline(vk.device, "p_beta[2]"),
vk.shaders.getPipeline(vk.device, "p_beta[3]"),
vk.shaders.getPipeline(vk.device, "p_beta[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);
for (size_t i = 0; i < 3; i++)
this->firstDescriptorSet.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModules.at(0));
for (size_t i = 0; i < 4; i++)
this->descriptorSets.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModules.at(i + 1));
this->buffer = vk.resources.getBuffer(vk.device, 0.5F);
// create internal images/outputs
const VkExtent2D extent = this->inImgs.at(0).at(0).getExtent();
for (size_t i = 0; i < 2; i++) {
this->tempImgs1.at(i) = Core::Image(vk.device, extent);
this->tempImgs2.at(i) = Core::Image(vk.device, extent);
}
for (size_t i = 0; i < 6; i++)
this->outImgs.at(i) = Core::Image(vk.device,
{ extent.width >> i, extent.height >> i },
VK_FORMAT_R8_UNORM);
// hook up shaders
for (size_t i = 0; i < 3; i++) {
this->firstDescriptorSet.at(i).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(1))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs.at((i + 1) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs.at((i + 2) % 3))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->inImgs.at(i % 3))
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->tempImgs1)
.build();
}
this->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();
this->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();
this->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();
this->descriptorSets.at(3).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, this->buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->samplers.at(0))
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, this->tempImgs2)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs)
.build();
}
void Beta::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount) {
// first pass
const auto extent = this->tempImgs1.at(0).getExtent();
uint32_t threadsX = (extent.width + 7) >> 3;
uint32_t threadsY = (extent.height + 7) >> 3;
Utils::BarrierBuilder(buf)
.addW2R(this->inImgs.at(0))
.addW2R(this->inImgs.at(1))
.addW2R(this->inImgs.at(2))
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(0).bind(buf);
this->firstDescriptorSet.at(frameCount % 3).bind(buf, this->pipelines.at(0));
buf.dispatch(threadsX, threadsY, 1);
// second pass
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(1).bind(buf);
this->descriptorSets.at(0).bind(buf, this->pipelines.at(1));
buf.dispatch(threadsX, threadsY, 1);
// third pass
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->tempImgs1)
.build();
this->pipelines.at(2).bind(buf);
this->descriptorSets.at(1).bind(buf, this->pipelines.at(2));
buf.dispatch(threadsX, threadsY, 1);
// fourth pass
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs1)
.addR2W(this->tempImgs2)
.build();
this->pipelines.at(3).bind(buf);
this->descriptorSets.at(2).bind(buf, this->pipelines.at(3));
buf.dispatch(threadsX, threadsY, 1);
// fifth pass
threadsX = (extent.width + 31) >> 5;
threadsY = (extent.height + 31) >> 5;
Utils::BarrierBuilder(buf)
.addW2R(this->tempImgs2)
.addR2W(this->outImgs)
.build();
this->pipelines.at(4).bind(buf);
this->descriptorSets.at(3).bind(buf, this->pipelines.at(4));
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -1,66 +0,0 @@
#include <volk.h>
#include <vulkan/vulkan_core.h>
#include "v3_1p/shaders/mipmaps.hpp"
#include "common/utils.hpp"
#include "core/image.hpp"
#include "core/commandbuffer.hpp"
#include <utility>
#include <cstddef>
#include <cstdint>
using namespace LSFG_3_1P::Shaders;
Mipmaps::Mipmaps(Vulkan& vk,
Core::Image inImg_0, Core::Image inImg_1)
: inImg_0(std::move(inImg_0)), inImg_1(std::move(inImg_1)) {
// create resources
this->shaderModule = vk.shaders.getShader(vk.device, "mipmaps",
{ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
{ 7, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE } });
this->pipeline = vk.shaders.getPipeline(vk.device, "mipmaps");
this->buffer = vk.resources.getBuffer(vk.device);
this->sampler = vk.resources.getSampler(vk.device);
for (size_t i = 0; i < 2; i++)
this->descriptorSets.at(i) = Core::DescriptorSet(vk.device, vk.descriptorPool, this->shaderModule);
// create outputs
const VkExtent2D flowExtent{
.width = static_cast<uint32_t>(
static_cast<float>(this->inImg_0.getExtent().width) / vk.flowScale),
.height = static_cast<uint32_t>(
static_cast<float>(this->inImg_0.getExtent().height) / vk.flowScale)
};
for (size_t i = 0; i < 7; i++)
this->outImgs.at(i) = Core::Image(vk.device,
{ flowExtent.width >> i, flowExtent.height >> i },
VK_FORMAT_R8_UNORM);
// hook up shaders
for (size_t fc = 0; fc < 2; fc++)
this->descriptorSets.at(fc).update(vk.device)
.add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, this->buffer)
.add(VK_DESCRIPTOR_TYPE_SAMPLER, this->sampler)
.add(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, (fc % 2 == 0) ? this->inImg_0 : this->inImg_1)
.add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, this->outImgs)
.build();
}
void Mipmaps::Dispatch(const Core::CommandBuffer& buf, uint64_t frameCount) {
// first pass
const auto flowExtent = this->outImgs.at(0).getExtent();
const uint32_t threadsX = (flowExtent.width + 63) >> 6;
const uint32_t threadsY = (flowExtent.height + 63) >> 6;
Utils::BarrierBuilder(buf)
.addW2R((frameCount % 2 == 0) ? this->inImg_0 : this->inImg_1)
.addR2W(this->outImgs)
.build();
this->pipeline.bind(buf);
this->descriptorSets.at(frameCount % 2).bind(buf, this->pipeline);
buf.dispatch(threadsX, threadsY, 1);
}

View file

@ -3,6 +3,11 @@ set(BACKEND_SOURCES
"src/extraction/shader_registry.cpp"
"src/helpers/managed_shader.cpp"
"src/helpers/utils.cpp"
"src/shaderchains/alpha0.cpp"
"src/shaderchains/alpha1.cpp"
"src/shaderchains/beta0.cpp"
"src/shaderchains/beta1.cpp"
"src/shaderchains/mipmaps.cpp"
"src/lsfgvk.cpp")
add_library(lsfg-vk-backend STATIC ${BACKEND_SOURCES})

View file

@ -7,6 +7,11 @@
#include "lsfg-vk-common/vulkan/image.hpp"
#include "lsfg-vk-common/vulkan/timeline_semaphore.hpp"
#include "lsfg-vk-common/vulkan/vulkan.hpp"
#include "shaderchains/alpha0.hpp"
#include "shaderchains/alpha1.hpp"
#include "shaderchains/beta0.hpp"
#include "shaderchains/beta1.hpp"
#include "shaderchains/mipmaps.hpp"
#include <algorithm>
#include <array>
@ -81,11 +86,18 @@ namespace lsfgvk {
vk::TimelineSemaphore syncSemaphore; // imported
vk::TimelineSemaphore prepassSemaphore;
size_t idx{1};
size_t fidx{0}; // real frame index
std::vector<vk::CommandBuffer> cmdbufs; // TODO: ponder reuse
size_t cmdbuf_idx{0};
ls::Ctx ctx;
chains::Mipmaps mipmaps;
std::array<chains::Alpha0, 7> alpha0;
std::array<chains::Alpha1, 7> alpha1;
chains::Beta0 beta0;
chains::Beta1 beta1;
};
}
@ -296,10 +308,37 @@ ContextImpl::ContextImpl(const InstanceImpl& instance,
syncSemaphore(importTimelineSemaphore(instance.getVulkan(), syncFd)),
prepassSemaphore(createPrepassSemaphore(instance.getVulkan())),
cmdbufs(createCommandBuffers(instance.getVulkan(), 16)),
ctx(createCtx(instance, extent, hdr, flow, perf, destFds.size())) {
ctx(createCtx(instance, extent, hdr, flow, perf, destFds.size())),
mipmaps(ctx, sourceImages),
alpha0{
chains::Alpha0(ctx, mipmaps.getImages().at(0)),
chains::Alpha0(ctx, mipmaps.getImages().at(1)),
chains::Alpha0(ctx, mipmaps.getImages().at(2)),
chains::Alpha0(ctx, mipmaps.getImages().at(3)),
chains::Alpha0(ctx, mipmaps.getImages().at(4)),
chains::Alpha0(ctx, mipmaps.getImages().at(5)),
chains::Alpha0(ctx, mipmaps.getImages().at(6))
},
alpha1{
chains::Alpha1(ctx, alpha0.at(0).getImages()),
chains::Alpha1(ctx, alpha0.at(1).getImages()),
chains::Alpha1(ctx, alpha0.at(2).getImages()),
chains::Alpha1(ctx, alpha0.at(3).getImages()),
chains::Alpha1(ctx, alpha0.at(4).getImages()),
chains::Alpha1(ctx, alpha0.at(5).getImages()),
chains::Alpha1(ctx, alpha0.at(6).getImages())
},
beta0(ctx, alpha1.at(0).getImages()),
beta1(ctx, beta0.getImages()) {
// initialize all images
const vk::CommandBuffer cmdbuf{ctx.vk};
// (...)
mipmaps.prepare(cmdbuf);
for (size_t i = 0; i < 7; ++i) {
alpha0.at(i).prepare(cmdbuf);
alpha1.at(i).prepare(cmdbuf);
}
beta0.prepare(cmdbuf);
beta1.prepare(cmdbuf);
cmdbuf.submit(ctx.vk); // wait for completion
}
@ -332,7 +371,13 @@ void Context::scheduleFrames() {
vk::CommandBuffer& cmdbuf = this->cmdbufs.at(this->cmdbuf_idx++ % this->cmdbufs.size());
cmdbuf = vk::CommandBuffer(this->ctx.vk);
// (...)
this->mipmaps.render(cmdbuf, this->fidx);
for (size_t i = 0; i < 7; ++i) {
this->alpha0.at(6 - i).render(cmdbuf);
this->alpha1.at(6 - i).render(cmdbuf, this->fidx);
}
this->beta0.render(cmdbuf, this->fidx);
this->beta1.render(cmdbuf);
cmdbuf.submit(this->ctx.vk,
this->syncSemaphore, this->idx,
@ -355,6 +400,7 @@ void Context::scheduleFrames() {
}
this->idx += this->destImages.size();
this->fidx++;
}
void Instance::closeContext(const Context& context) {

View file

@ -0,0 +1,72 @@
#include "alpha0.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;
Alpha0::Alpha0(const ls::Ctx& ctx,
const vk::Image& sourceImage) {
const size_t m = ctx.perf ? 1 : 2; // multiplier
const VkExtent2D halfExtent = ls::add_shift_extent(sourceImage.getExtent(), 1, 1);
const VkExtent2D quarterExtent = ls::add_shift_extent(halfExtent, 1, 1);
// create temporary & output images
this->tempImages0.reserve(m);
this->tempImages1.reserve(m);
for (size_t i = 0; i < m; i++) {
this->tempImages0.emplace_back(ctx.vk, halfExtent);
this->tempImages1.emplace_back(ctx.vk, halfExtent);
}
this->images.reserve(2 * m);
for (size_t i = 0; i < (2 * m); i++)
this->images.emplace_back(ctx.vk, quarterExtent);
// create descriptor sets
const auto& shaders = ctx.perf ? ctx.shaders.get().performance : ctx.shaders.get().quality;
this->sets.reserve(3);
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampled(sourceImage)
.storages(this->tempImages0)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.alpha.at(0)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages0)
.storages(this->tempImages1)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.alpha.at(1)));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(this->tempImages1)
.storages(this->images)
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.alpha.at(2)));
// store dispatch extents
this->dispatchExtent0 = ls::add_shift_extent(halfExtent, 7, 3);
this->dispatchExtent1 = ls::add_shift_extent(quarterExtent, 7, 3);
}
void Alpha0::prepare(const vk::CommandBuffer& cmd) const {
// TODO: find a way to batch prepare
for (size_t i = 0; i < this->tempImages0.size(); i++) {
cmd.prepareImage(this->tempImages0.at(i));
cmd.prepareImage(this->tempImages1.at(i));
}
for (const auto& image : this->images)
cmd.prepareImage(image);
}
void Alpha0::render(const vk::CommandBuffer& cmd) const {
this->sets[0].dispatch(cmd, this->dispatchExtent0);
this->sets[1].dispatch(cmd, this->dispatchExtent0);
this->sets[2].dispatch(cmd, this->dispatchExtent1);
}

View file

@ -0,0 +1,44 @@
#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 {
/// pre-alpha shaderchain
class Alpha0 {
public:
/// create a pre-alpha shaderchain
/// @param ctx context
/// @param sourceImage source image
Alpha0(const ls::Ctx& ctx,
const vk::Image& sourceImage);
/// prepare the shaderchain initially
/// @param cmd command buffer
void prepare(const vk::CommandBuffer& cmd) const;
/// render the pre-alpha shaderchain
/// @param cmd command buffer
void render(const vk::CommandBuffer& cmd) const;
/// get the generated images
/// @return vector of images
[[nodiscard]] const auto& getImages() const { return this->images; }
private:
std::vector<vk::Image> tempImages0;
std::vector<vk::Image> tempImages1;
std::vector<vk::Image> images;
std::vector<ls::ManagedShader> sets;
VkExtent2D dispatchExtent0{};
VkExtent2D dispatchExtent1{};
};
}

View file

@ -0,0 +1,52 @@
#include "alpha1.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;
Alpha1::Alpha1(const ls::Ctx& ctx,
const std::vector<vk::Image>& sourceImages) {
const size_t m = ctx.perf ? 1 : 2; // multiplier
const VkExtent2D quarterExtent = sourceImages.at(0).getExtent();
// create output images for mod3
this->images.reserve(3);
for(size_t i = 0; i < 3; i++) {
auto& vec = this->images.emplace_back();
vec.reserve(2 * m);
for (size_t j = 0; j < (2 * m); j++)
vec.emplace_back(ctx.vk, quarterExtent);
}
// create descriptor sets
const auto& shaders = ctx.perf ? ctx.shaders.get().performance : ctx.shaders.get().quality;
this->sets.reserve(3);
for (size_t i = 0; i < 3; i++)
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(sourceImages)
.storages(this->images.at(i))
.sampler(ctx.bnbSampler)
.build(ctx.vk, shaders.alpha.at(3)));
// store dispatch extents
this->dispatchExtent = ls::add_shift_extent(quarterExtent, 7, 3);
}
void Alpha1::prepare(const vk::CommandBuffer& cmd) const {
for (const auto& vec : this->images)
for (const auto& img : vec)
cmd.prepareImage(img);
}
void Alpha1::render(const vk::CommandBuffer& cmd, size_t idx) const {
// FIXME: iirc only one of the 7 instances of alpha1 requires 3 temporal images
this->sets[idx % 3].dispatch(cmd, dispatchExtent);
}

View file

@ -0,0 +1,42 @@
#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 {
/// alpha shaderchain
class Alpha1 {
public:
/// create a alpha shaderchain
/// @param ctx context
/// @param sourceImages source images
Alpha1(const ls::Ctx& ctx,
const std::vector<vk::Image>& sourceImages);
/// prepare the shaderchain initially
/// @param cmd command buffer
void prepare(const vk::CommandBuffer& cmd) const;
/// render the alpha 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<std::vector<vk::Image>> images;
std::vector<ls::ManagedShader> sets;
VkExtent2D dispatchExtent{};
};
}

View file

@ -0,0 +1,47 @@
#include "beta0.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;
Beta0::Beta0(const ls::Ctx& ctx,
const std::vector<std::vector<vk::Image>>& sourceImages) {
const VkExtent2D extent = sourceImages.at(0).at(0).getExtent();
// create output images
this->images.reserve(2);
for(size_t i = 0; i < 2; i++)
this->images.emplace_back(ctx.vk, extent);
// create descriptor sets
const auto& shader = (ctx.perf ?
ctx.shaders.get().performance : ctx.shaders.get().quality).beta.at(0);
this->sets.reserve(3);
for (size_t i = 0; i < 3; i++)
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampleds(sourceImages.at((i + 1) % 3))
.sampleds(sourceImages.at((i + 2) % 3))
.sampleds(sourceImages.at(i % 3))
.storages(this->images)
.sampler(ctx.bnwSampler)
.build(ctx.vk, shader));
// store dispatch extents
this->dispatchExtent = ls::add_shift_extent(extent, 7, 3);
}
void Beta0::prepare(const vk::CommandBuffer& cmd) const {
for (const auto& img : this->images)
cmd.prepareImage(img);
}
void Beta0::render(const vk::CommandBuffer& cmd, size_t idx) const {
this->sets[idx % 3].dispatch(cmd, dispatchExtent);
}

View file

@ -0,0 +1,42 @@
#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 {
/// beta shaderchain
class Beta0 {
public:
/// create a beta shaderchain
/// @param ctx context
/// @param sourceImages source images
Beta0(const ls::Ctx& ctx,
const std::vector<std::vector<vk::Image>>& sourceImages);
/// prepare the shaderchain initially
/// @param cmd command buffer
void prepare(const vk::CommandBuffer& cmd) const;
/// render the beta 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,78 @@
#include "beta1.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 <cstdint>
#include <vector>
#include <vulkan/vulkan_core.h>
using namespace chains;
Beta1::Beta1(const ls::Ctx& ctx,
const std::vector<vk::Image>& sourceImages) {
const VkExtent2D extent = sourceImages.at(0).getExtent();
// create temporary & output images
this->tempImages0.reserve(2);
this->tempImages1.reserve(2);
for(uint32_t i = 0; i < 2; i++) {
this->tempImages0.emplace_back(ctx.vk, extent);
this->tempImages1.emplace_back(ctx.vk, extent);
}
this->images.reserve(6);
for (uint32_t i = 0; i < 6; i++)
this->images.emplace_back(ctx.vk,
ls::shift_extent(extent, i),
VK_FORMAT_R8_UNORM);
// create descriptor sets
const auto& shaders = (ctx.perf ?
ctx.shaders.get().performance : ctx.shaders.get().quality).beta;
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)
.storages(this->images)
.sampler(ctx.bnbSampler)
.buffer(ctx.constantBuffer)
.build(ctx.vk, shaders.at(4)));
// store dispatch extents
this->dispatchExtent0 = ls::add_shift_extent(extent, 7, 3);
this->dispatchExtent1 = ls::add_shift_extent(extent, 31, 5);
}
void Beta1::prepare(const vk::CommandBuffer& cmd) const {
for (size_t i = 0; i < 2; i++) {
cmd.prepareImage(this->tempImages0.at(i));
cmd.prepareImage(this->tempImages1.at(i));
}
for (const auto& img : this->images)
cmd.prepareImage(img);
}
void Beta1::render(const vk::CommandBuffer& cmd) const {
this->sets[0].dispatch(cmd, this->dispatchExtent0);
this->sets[1].dispatch(cmd, this->dispatchExtent0);
this->sets[2].dispatch(cmd, this->dispatchExtent0);
this->sets[3].dispatch(cmd, this->dispatchExtent1);
}

View file

@ -0,0 +1,44 @@
#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 {
/// beta shaderchain
class Beta1 {
public:
/// create a beta shaderchain
/// @param ctx context
/// @param sourceImages source images
Beta1(const ls::Ctx& ctx,
const std::vector<vk::Image>& sourceImages);
/// prepare the shaderchain initially
/// @param cmd command buffer
void prepare(const vk::CommandBuffer& cmd) const;
/// render the beta shaderchain
/// @param cmd command buffer
void render(const vk::CommandBuffer& cmd) const;
/// get the generated images
/// @return vector of images
[[nodiscard]] const auto& getImages() const { return this->images; }
private:
std::vector<vk::Image> tempImages0;
std::vector<vk::Image> tempImages1;
std::vector<vk::Image> images;
std::vector<ls::ManagedShader> sets;
VkExtent2D dispatchExtent0{};
VkExtent2D dispatchExtent1{};
};
}

View file

@ -0,0 +1,50 @@
#include "mipmaps.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 <cstdint>
#include <utility>
#include <vector>
#include <vulkan/vulkan_core.h>
using namespace chains;
Mipmaps::Mipmaps(const ls::Ctx& ctx,
const std::pair<vk::Image, vk::Image>& sourceImages) {
// create output images for base and 6 mips
this->images.reserve(7);
for (uint32_t i = 0; i < 7; i++)
this->images.emplace_back(ctx.vk,
ls::shift_extent(ctx.flowExtent, i), VK_FORMAT_R8_UNORM);
// create descriptor sets for both input images
this->sets.reserve(2);
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampled(sourceImages.first)
.storages(this->images)
.sampler(ctx.bnbSampler)
.buffer(ctx.constantBuffer)
.build(ctx.vk, ctx.shaders.get().mipmaps));
this->sets.emplace_back(ls::ManagedShaderBuilder()
.sampled(sourceImages.second)
.storages(this->images)
.sampler(ctx.bnbSampler)
.buffer(ctx.constantBuffer)
.build(ctx.vk, ctx.shaders.get().mipmaps));
// store dispatch extent
this->dispatchExtent = ls::add_shift_extent(ctx.flowExtent, 63, 6);
}
void Mipmaps::prepare(const vk::CommandBuffer& cmd) const {
for (const auto& img : this->images)
cmd.prepareImage(img);
}
void Mipmaps::render(const vk::CommandBuffer& cmd, size_t idx) const {
this->sets[idx % 2].dispatch(cmd, this->dispatchExtent);
}

View file

@ -0,0 +1,43 @@
#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 {
/// mipmaps shaderchain
class Mipmaps {
public:
/// create a mipmaps shaderchain
/// @param ctx context
/// @param sourceImages pair of source images
Mipmaps(const ls::Ctx& ctx,
const std::pair<vk::Image, vk::Image>& sourceImages);
/// prepare the shaderchain initially
/// @param cmd command buffer
void prepare(const vk::CommandBuffer& cmd) const;
/// render the mipmaps shaderchain
/// @param cmd command buffer
/// @param idx frame index
void render(const vk::CommandBuffer& cmd, size_t idx) const;
/// get the generated mipmap 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{};
};
}