diff --git a/framegen/include/lsfg.hpp b/framegen/include/lsfg.hpp index 0e55d7c..81d879c 100644 --- a/framegen/include/lsfg.hpp +++ b/framegen/include/lsfg.hpp @@ -1,5 +1,6 @@ #pragma once +#include "vk/core/descriptorpool.hpp" #include "vk/core/device.hpp" #include "vk/core/instance.hpp" #include "vk/pool/shader_pool.hpp" @@ -29,6 +30,8 @@ namespace LSFG { VK::Core::Instance vk; VK::Core::Device vkd; + VK::Core::DescriptorPool pool; + VK::Registry::ShaderRegistry registry; VK::Pool::ShaderPool shaders; }; diff --git a/framegen/include/vk/types/shader.hpp b/framegen/include/vk/types/shader.hpp new file mode 100644 index 0000000..1ea2fd8 --- /dev/null +++ b/framegen/include/vk/types/shader.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include "vk/core/descriptorset.hpp" +#include "vk/core/sampler.hpp" +#include "vk/core/buffer.hpp" +#include "vk/core/device.hpp" +#include "vk/core/image.hpp" +#include "vk/pool/shader_pool.hpp" +#include "vk/registry/shader_registry.hpp" + +#include +#include +#include + +namespace VK::Types { + + /// + /// Temporal shader and sets + /// + class Shader { + public: + /// + /// Create a new shader instance. + /// + Shader(Pool::ShaderInstance shader, + std::vector sets) + : shader(std::move(shader)), + sets(std::move(sets)) {} + + /// TODO: remaining methods + + private: + Pool::ShaderInstance shader; + std::vector sets; + }; + + /// + /// Helper class for building a shader instance. + /// + /// The lifetime of this class should not exceed a single line. + /// + class ShaderBuilder { + public: + /// + /// Create a new shader builder. + /// + /// @param vkd The Vulkan device to use. + /// @param registry The shader registry to use. + /// @param pool The shader pool to allocate from. + /// @param name The name of the shader module to use. + /// @param variants The number of variants to create. + /// + /// @throws std::out_of_range if no such shader exists in the registry. + /// @throws VK::vulkan_error if shader module or pipeline creation fails. + /// + ShaderBuilder(const Core::Device& vkd, + const Registry::ShaderRegistry& registry, + Pool::ShaderPool& pool, + const std::string& name, + size_t variants = 1) + : shader(pool.getOrCreate(vkd, registry, name)), + inputs(variants), outputs(variants) {} + + /// Set the sampler to bind to the shader. + ShaderBuilder& withSamplers( + const Core::Sampler& sampler1); + /// Set the samplers to bind to the shader. + ShaderBuilder& withSamplers( + const Core::Sampler& sampler1, + const Core::Sampler& sampler2); + /// Set the buffer to bind to the shader. + ShaderBuilder& withBuffer( + const Core::Buffer& buffer); + + /// Add an input image to the shader. + ShaderBuilder& addInput( + const std::optional& image); + // Add an output image to the shader. + ShaderBuilder& addOutput( + const Core::Image& image); + + /// Add several input images to the shader. + ShaderBuilder& addInputs( + const std::vector>& images, + size_t offset = 0, size_t count = 0); + /// Add several output images to the shader. + ShaderBuilder& addOutputs( + const std::vector& images, + size_t offset = 0, size_t count = 0); + + /// Add a temporal input image to the shader. + ShaderBuilder& addTemporalInput( + const std::vector>& images); + /// Add a temporal output image to the shader. + ShaderBuilder& addTemporalOutput( + const std::vector& images); + + /// + /// Build the shader instance. + /// + /// @param vkd The Vulkan device to use. + /// @param pool The descriptor pool to allocate from. + /// + /// @throws VK::vulkan_error if descriptor set allocation or update fails. + /// + Shader build(const Core::Device& vkd, + const Core::DescriptorPool& pool); + private: + Pool::ShaderInstance shader; + + std::vector samplers; + std::optional buffer; + std::vector>> inputs; + std::vector> outputs; + }; + +} diff --git a/framegen/src/lsfg.cpp b/framegen/src/lsfg.cpp index c6508f3..7b80b8d 100644 --- a/framegen/src/lsfg.cpp +++ b/framegen/src/lsfg.cpp @@ -1,15 +1,43 @@ #include "lsfg.hpp" #include "trans/rsrc.hpp" +#include "vk/core/buffer.hpp" +#include "vk/core/image.hpp" +#include "vk/core/sampler.hpp" +#include "vk/types/shader.hpp" + +#include #include +#include using namespace LSFG; Instance::Instance(const std::filesystem::path& dll) - : vkd(vk, 0, false) { + : vkd(vk, 0, false), pool(vkd) { // load shaders from dll file const bool fp16 = vkd.supportsFP16(); Trans::RSRC::loadResources(dll, this->registry, fp16); // ... + + const auto sampler1 = + VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_COMPARE_OP_GREATER_OR_EQUAL, false); + const auto sampler2 = + VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_ALWAYS, true); + const auto buffer0 = + VK::Core::Buffer(vkd, 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + const auto input0 = + VK::Core::Image(vkd, { 1920, 1080 }); + const auto input1 = + VK::Core::Image(vkd, { 1920, 1080 }); + const std::vector mipmaps{ + input0, input0 + }; + + auto shader = VK::Types::ShaderBuilder(vkd, registry, this->shaders, "alpha[0]") + .withSamplers(sampler1, sampler2) + .withBuffer(buffer0) + .addTemporalInput({ input0, input1 }) + .addOutputs(mipmaps) + .build(vkd, this->pool); } diff --git a/framegen/src/vk/types/shader.cpp b/framegen/src/vk/types/shader.cpp new file mode 100644 index 0000000..45d53ae --- /dev/null +++ b/framegen/src/vk/types/shader.cpp @@ -0,0 +1,82 @@ +#include "vk/types/shader.hpp" +#include "vk/core/descriptorpool.hpp" +#include "vk/core/descriptorset.hpp" +#include "vk/core/sampler.hpp" + +using namespace VK::Types; + +ShaderBuilder& ShaderBuilder::withSamplers( + const Core::Sampler& sampler1) { + this->samplers = { sampler1 }; + return *this; +} + +ShaderBuilder& ShaderBuilder::withSamplers( + const Core::Sampler& sampler1, + const Core::Sampler& sampler2) { + this->samplers = { sampler1, sampler2 }; + return *this; +} + +ShaderBuilder& ShaderBuilder::withBuffer( + const Core::Buffer& buffer) { + this->buffer = buffer; + return *this; +} + +ShaderBuilder& ShaderBuilder::addInput( + const std::optional& image) { + for (auto& variant : this->inputs) + variant.emplace_back(image); + return *this; +} + +ShaderBuilder& ShaderBuilder::addOutput( + const Core::Image& image) { + for (auto& variant : this->outputs) + variant.emplace_back(image); + return *this; +} + +ShaderBuilder& ShaderBuilder::addInputs( + const std::vector>& images, + size_t offset, size_t count) { + for (size_t i = 0; i < count; i++) + this->addInput(images.at(offset + i)); + return *this; +} + +ShaderBuilder& ShaderBuilder::addOutputs( + const std::vector& images, + size_t offset, size_t count) { + for (size_t i = 0; i < count; i++) + this->addOutput(images.at(offset + i)); + return *this; +} + +ShaderBuilder& ShaderBuilder::addTemporalInput( + const std::vector>& images) { + for (size_t v = 0; v < images.size(); v++) + this->inputs.at(v).push_back(images.at(v)); + return *this; +} + +ShaderBuilder& ShaderBuilder::addTemporalOutput( + const std::vector& images) { + for (size_t v = 0; v < images.size(); v++) + this->outputs.at(v).push_back(images.at(v)); + return *this; +} + +Shader ShaderBuilder::build(const Core::Device& vkd, + const Core::DescriptorPool& pool) { + std::vector sets; + sets.reserve(this->inputs.size()); + for (size_t i = 0; i < sets.size(); i++) + sets.emplace_back(vkd, pool, + this->shader.first, + std::move(this->inputs.at(i)), + std::move(this->outputs.at(i)), + this->samplers, this->buffer); + return { this->shader, std::move(sets) }; +}