diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f01bed..5aa0e7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,10 +22,11 @@ file(GLOB SOURCES "src/*.cpp" ) -add_executable(lsfg-vk-base ${SOURCES}) +add_library(lsfg-vk-base SHARED ${SOURCES}) target_include_directories(lsfg-vk-base - PUBLIC include) + PRIVATE include + PUBLIC public) target_link_libraries(lsfg-vk-base PUBLIC vulkan) target_compile_options(lsfg-vk-base PRIVATE diff --git a/include/context.hpp b/include/context.hpp new file mode 100644 index 0000000..15768f3 --- /dev/null +++ b/include/context.hpp @@ -0,0 +1,76 @@ +#ifndef CONTEXT_HPP +#define CONTEXT_HPP + +#include "core/commandpool.hpp" +#include "core/descriptorpool.hpp" +#include "core/image.hpp" +#include "shaderchains/alpha.hpp" +#include "shaderchains/beta.hpp" +#include "shaderchains/delta.hpp" +#include "shaderchains/downsample.hpp" +#include "shaderchains/epsilon.hpp" +#include "shaderchains/extract.hpp" +#include "shaderchains/gamma.hpp" +#include "shaderchains/magic.hpp" +#include "shaderchains/merge.hpp" +#include "shaderchains/zeta.hpp" + +namespace LSFG { + + /// + /// LSFG context. + /// + class Context { + public: + /// + /// Create a generator instance. + /// + /// @param device The Vulkan device to use. + /// @param width Width of the input images. + /// @param height Height of the input images. + /// @param in0 File descriptor for the first input image. + /// @param in1 File descriptor for the second input image. + /// + /// @throws LSFG::vulkan_error if the generator fails to initialize. + /// + Context(const Core::Device& device, uint32_t width, uint32_t height, int in0, int in1); + + /// + /// Schedule the next generation. + /// + /// @param device The Vulkan device to use. + /// @param inSem Semaphore to wait on before starting the generation. + /// @param outSem Semaphore to signal when the generation is complete. + /// + /// @throws LSFG::vulkan_error if the generator fails to present. + /// + void present(const Core::Device& device, int inSem, int outSem); + + // Trivially copyable, moveable and destructible + Context(const Context&) = default; + Context(Context&&) = default; + Context& operator=(const Context&) = default; + Context& operator=(Context&&) = default; + ~Context() = default; + private: + Core::DescriptorPool descPool; + Core::CommandPool cmdPool; + + Core::Image inImg_0, inImg_1; // inImg_0 is next (inImg_1 prev) when fc % 2 == 0 + uint64_t fc{0}; + + Shaderchains::Downsample downsampleChain; + std::array alphaChains; + Shaderchains::Beta betaChain; + std::array gammaChains; + std::array magicChains; + std::array deltaChains; + std::array epsilonChains; + std::array zetaChains; + std::array extractChains; + Shaderchains::Merge mergeChain; + }; + +} + +#endif // CONTEXT_HPP diff --git a/include/core/buffer.hpp b/include/core/buffer.hpp index 2e283f1..a2c369e 100644 --- a/include/core/buffer.hpp +++ b/include/core/buffer.hpp @@ -1,7 +1,7 @@ #ifndef BUFFER_HPP #define BUFFER_HPP -#include "device.hpp" +#include "core/device.hpp" #include @@ -28,7 +28,7 @@ namespace LSFG::Core { /// @throws LSFG::vulkan_error if object creation fails. /// template - Buffer(const Device& device, const T& data, VkBufferUsageFlags usage) + Buffer(const Core::Device& device, const T& data, VkBufferUsageFlags usage) : size(sizeof(T)) { construct(device, reinterpret_cast(&data), usage); } @@ -43,7 +43,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - Buffer(const Device& device, const void* data, size_t size, VkBufferUsageFlags usage) + Buffer(const Core::Device& device, const void* data, size_t size, VkBufferUsageFlags usage) : size(size) { construct(device, data, usage); } @@ -60,7 +60,7 @@ namespace LSFG::Core { Buffer& operator=(Buffer&&) noexcept = default; ~Buffer() = default; private: - void construct(const Device& device, const void* data, VkBufferUsageFlags usage); + void construct(const Core::Device& device, const void* data, VkBufferUsageFlags usage); std::shared_ptr buffer; std::shared_ptr memory; diff --git a/include/core/commandbuffer.hpp b/include/core/commandbuffer.hpp index aaed19e..d9395db 100644 --- a/include/core/commandbuffer.hpp +++ b/include/core/commandbuffer.hpp @@ -4,7 +4,7 @@ #include "core/commandpool.hpp" #include "core/fence.hpp" #include "core/semaphore.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -45,7 +45,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - CommandBuffer(const Device& device, const CommandPool& pool); + CommandBuffer(const Core::Device& device, const CommandPool& pool); /// /// Begin recording commands in the command buffer. diff --git a/include/core/commandpool.hpp b/include/core/commandpool.hpp index d444b4a..9946176 100644 --- a/include/core/commandpool.hpp +++ b/include/core/commandpool.hpp @@ -1,7 +1,7 @@ #ifndef COMMANDPOOL_HPP #define COMMANDPOOL_HPP -#include "device.hpp" +#include "core/device.hpp" #include @@ -25,7 +25,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - CommandPool(const Device& device); + CommandPool(const Core::Device& device); /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->commandPool; } diff --git a/include/core/descriptorpool.hpp b/include/core/descriptorpool.hpp index 5ffac10..76ac03c 100644 --- a/include/core/descriptorpool.hpp +++ b/include/core/descriptorpool.hpp @@ -1,7 +1,7 @@ #ifndef DESCRIPTORPOOL_HPP #define DESCRIPTORPOOL_HPP -#include "device.hpp" +#include "core/device.hpp" #include @@ -25,7 +25,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - DescriptorPool(const Device& device); + DescriptorPool(const Core::Device& device); /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->descriptorPool; } diff --git a/include/core/descriptorset.hpp b/include/core/descriptorset.hpp index 79b2b91..cdd15ad 100644 --- a/include/core/descriptorset.hpp +++ b/include/core/descriptorset.hpp @@ -8,7 +8,7 @@ #include "core/pipeline.hpp" #include "core/sampler.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -36,7 +36,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - DescriptorSet(const Device& device, + DescriptorSet(const Core::Device& device, const DescriptorPool& pool, const ShaderModule& shaderModule); /// @@ -44,7 +44,7 @@ namespace LSFG::Core { /// /// @param device Vulkan device /// - [[nodiscard]] DescriptorSetUpdateBuilder update(const Device& device) const; + [[nodiscard]] DescriptorSetUpdateBuilder update(const Core::Device& device) const; /// /// Bind a descriptor set to a command buffer. @@ -110,9 +110,9 @@ namespace LSFG::Core { void build(); private: const DescriptorSet* descriptorSet; - const Device* device; + const Core::Device* device; - DescriptorSetUpdateBuilder(const DescriptorSet& descriptorSet, const Device& device) + DescriptorSetUpdateBuilder(const DescriptorSet& descriptorSet, const Core::Device& device) : descriptorSet(&descriptorSet), device(&device) {} std::vector entries; diff --git a/include/device.hpp b/include/core/device.hpp similarity index 89% rename from include/device.hpp rename to include/core/device.hpp index 25d2702..2916e86 100644 --- a/include/device.hpp +++ b/include/core/device.hpp @@ -1,14 +1,14 @@ #ifndef DEVICE_HPP #define DEVICE_HPP -#include "instance.hpp" +#include "core/instance.hpp" #include #include #include -namespace LSFG { +namespace LSFG::Core { /// /// C++ wrapper class for a Vulkan device. @@ -36,8 +36,8 @@ namespace LSFG { [[nodiscard]] VkQueue getComputeQueue() const { return this->computeQueue; } // Trivially copyable, moveable and destructible - Device(const Device&) noexcept = default; - Device& operator=(const Device&) noexcept = default; + Device(const Core::Device&) noexcept = default; + Device& operator=(const Core::Device&) noexcept = default; Device(Device&&) noexcept = default; Device& operator=(Device&&) noexcept = default; ~Device() = default; diff --git a/include/core/fence.hpp b/include/core/fence.hpp index 3d7df5f..6a50eb1 100644 --- a/include/core/fence.hpp +++ b/include/core/fence.hpp @@ -1,7 +1,7 @@ #ifndef FENCE_HPP #define FENCE_HPP -#include "device.hpp" +#include "core/device.hpp" #include @@ -25,7 +25,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - Fence(const Device& device); + Fence(const Core::Device& device); /// /// Reset the fence to an unsignaled state. @@ -34,7 +34,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if resetting fails. /// - void reset(const Device& device) const; + void reset(const Core::Device& device) const; /// /// Wait for the fence @@ -45,7 +45,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if waiting fails. /// - [[nodiscard]] bool wait(const Device& device, uint64_t timeout = UINT64_MAX) const; + [[nodiscard]] bool wait(const Core::Device& device, uint64_t timeout = UINT64_MAX) const; /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->fence; } diff --git a/include/core/image.hpp b/include/core/image.hpp index 2b016dc..64dd03c 100644 --- a/include/core/image.hpp +++ b/include/core/image.hpp @@ -1,7 +1,7 @@ #ifndef IMAGE_HPP #define IMAGE_HPP -#include "device.hpp" +#include "core/device.hpp" #include @@ -29,7 +29,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - Image(const Device& device, VkExtent2D extent, VkFormat format, + Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectFlags); /// Get the Vulkan handle. diff --git a/include/instance.hpp b/include/core/instance.hpp similarity index 97% rename from include/instance.hpp rename to include/core/instance.hpp index c957f72..3fb7d26 100644 --- a/include/instance.hpp +++ b/include/core/instance.hpp @@ -5,7 +5,7 @@ #include -namespace LSFG { +namespace LSFG::Core { /// /// C++ wrapper class for a Vulkan instance. diff --git a/include/core/pipeline.hpp b/include/core/pipeline.hpp index 812e76a..6e2f981 100644 --- a/include/core/pipeline.hpp +++ b/include/core/pipeline.hpp @@ -3,7 +3,7 @@ #include "core/commandbuffer.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -28,7 +28,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - Pipeline(const Device& device, const ShaderModule& shader); + Pipeline(const Core::Device& device, const ShaderModule& shader); /// /// Bind the pipeline to a command buffer. diff --git a/include/core/sampler.hpp b/include/core/sampler.hpp index 325d783..7890606 100644 --- a/include/core/sampler.hpp +++ b/include/core/sampler.hpp @@ -1,7 +1,7 @@ #ifndef SAMPLER_HPP #define SAMPLER_HPP -#include "device.hpp" +#include "core/device.hpp" #include @@ -26,7 +26,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - Sampler(const Device& device, VkSamplerAddressMode mode); + Sampler(const Core::Device& device, VkSamplerAddressMode mode); /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->sampler; } diff --git a/include/core/semaphore.hpp b/include/core/semaphore.hpp index cd2ae53..b91fdb4 100644 --- a/include/core/semaphore.hpp +++ b/include/core/semaphore.hpp @@ -1,7 +1,7 @@ #ifndef SEMAPHORE_HPP #define SEMAPHORE_HPP -#include "device.hpp" +#include "core/device.hpp" #include @@ -27,7 +27,7 @@ namespace LSFG::Core { /// /// @throws LSFG::vulkan_error if object creation fails. /// - Semaphore(const Device& device, std::optional initial = std::nullopt); + Semaphore(const Core::Device& device, std::optional initial = std::nullopt); /// /// Signal the semaphore to a specific value. @@ -38,7 +38,7 @@ namespace LSFG::Core { /// @throws std::logic_error if the semaphore is not a timeline semaphore. /// @throws LSFG::vulkan_error if signaling fails. /// - void signal(const Device& device, uint64_t value) const; + void signal(const Core::Device& device, uint64_t value) const; /// /// Wait for the semaphore to reach a specific value. @@ -51,7 +51,7 @@ namespace LSFG::Core { /// @throws std::logic_error if the semaphore is not a timeline semaphore. /// @throws LSFG::vulkan_error if waiting fails. /// - [[nodiscard]] bool wait(const Device& device, uint64_t value, uint64_t timeout = UINT64_MAX) const; + [[nodiscard]] bool wait(const Core::Device& device, uint64_t value, uint64_t timeout = UINT64_MAX) const; /// Get the Vulkan handle. [[nodiscard]] auto handle() const { return *this->semaphore; } diff --git a/include/core/shadermodule.hpp b/include/core/shadermodule.hpp index 4a06541..81d8c10 100644 --- a/include/core/shadermodule.hpp +++ b/include/core/shadermodule.hpp @@ -1,7 +1,7 @@ #ifndef SHADERMODULE_HPP #define SHADERMODULE_HPP -#include "device.hpp" +#include "core/device.hpp" #include @@ -31,7 +31,7 @@ namespace LSFG::Core { /// @throws std::system_error if the shader file cannot be opened or read. /// @throws LSFG::vulkan_error if object creation fails. /// - ShaderModule(const Device& device, const std::string& path, + ShaderModule(const Core::Device& device, const std::string& path, const std::vector>& descriptorTypes); /// Get the Vulkan handle. diff --git a/include/lsfg.hpp b/include/lsfg.hpp deleted file mode 100644 index ea3459b..0000000 --- a/include/lsfg.hpp +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef LSFG_HPP -#define LSFG_HPP - -#include "core/commandpool.hpp" -#include "core/descriptorpool.hpp" -#include "core/image.hpp" -#include "device.hpp" -#include "instance.hpp" -#include "shaderchains/alpha.hpp" -#include "shaderchains/beta.hpp" -#include "shaderchains/delta.hpp" -#include "shaderchains/downsample.hpp" -#include "shaderchains/epsilon.hpp" -#include "shaderchains/extract.hpp" -#include "shaderchains/gamma.hpp" -#include "shaderchains/magic.hpp" -#include "shaderchains/merge.hpp" -#include "shaderchains/zeta.hpp" -#include "utils.hpp" - -namespace LSFG { - - class Generator; - - /// LSFG context. - class Context { - friend class Generator; // FIXME: getters, I'm lazy - public: - /// - /// Initialize the LSFG Vulkan instance. - /// - /// @throws LSFG::vulkan_error if the Vulkan objects cannot be created. - /// - Context() { Globals::initializeGlobals(device); } // FIXME: no need for globals - - /// - /// Create a generator instance. - /// - /// @throws LSFG::vulkan_error if the generator cannot be created. - /// - const Generator& create(); - - /// - /// Present a generator instance. - /// - /// @throws LSFG::vulkan_error if the generator fails to present. - /// - void present(const Generator& gen); - - /// Trivial copyable, moveable and destructible - Context(const Context&) = default; - Context& operator=(const Context&) = default; - Context(Context&&) = default; - Context& operator=(Context&&) = default; - ~Context() { Globals::uninitializeGlobals(); } - private: - Instance instance; - Device device{instance}; - Core::DescriptorPool descPool{device}; - Core::CommandPool cmdPool{device}; - }; - - /// Per-swapchain instance of LSFG. - class Generator { - public: - /// - /// Create a generator instance. - /// - /// @param context The LSFG context to use. - /// - Generator(const Context& context); - - /// - /// Present. - /// - /// @throws LSFG::vulkan_error if the generator fails to present. - /// - void present(const Context& context); - - // Trivially copyable, moveable and destructible - Generator(const Generator&) = default; - Generator(Generator&&) = default; - Generator& operator=(const Generator&) = default; - Generator& operator=(Generator&&) = default; - ~Generator() = default; - private: - Core::Image inImg_0, inImg_1; // inImg_0 is next (inImg_1 prev) when fc % 2 == 0 - uint64_t fc{0}; - - Shaderchains::Downsample downsampleChain; // FIXME: get rid of default constructors (+ core) - std::array alphaChains; - Shaderchains::Beta betaChain; - std::array gammaChains; - std::array magicChains; - std::array deltaChains; - std::array epsilonChains; - std::array zetaChains; - std::array extractChains; - Shaderchains::Merge mergeChain; - }; - - /// Simple exception class for Vulkan errors. - class vulkan_error : public std::runtime_error { - public: - /// - /// Construct a vulkan_error with a message and a Vulkan result code. - /// - /// @param result The Vulkan result code associated with the error. - /// @param message The error message. - /// - explicit vulkan_error(VkResult result, const std::string& message); - - /// Get the Vulkan result code associated with this error. - [[nodiscard]] VkResult error() const { return this->result; } - - // Trivially copyable, moveable and destructible - vulkan_error(const vulkan_error&) = default; - vulkan_error(vulkan_error&&) = default; - vulkan_error& operator=(const vulkan_error&) = default; - vulkan_error& operator=(vulkan_error&&) = default; - ~vulkan_error() noexcept override; - private: - VkResult result; - }; - -} - -#endif // LSFG_HPP diff --git a/include/shaderchains/alpha.hpp b/include/shaderchains/alpha.hpp index fb97e3f..a38e40a 100644 --- a/include/shaderchains/alpha.hpp +++ b/include/shaderchains/alpha.hpp @@ -7,7 +7,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -31,7 +31,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Alpha(const Device& device, const Core::DescriptorPool& pool, + Alpha(const Core::Device& device, const Core::DescriptorPool& pool, Core::Image inImg); /// diff --git a/include/shaderchains/beta.hpp b/include/shaderchains/beta.hpp index 3420ae4..1effbc5 100644 --- a/include/shaderchains/beta.hpp +++ b/include/shaderchains/beta.hpp @@ -8,7 +8,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -35,7 +35,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Beta(const Device& device, const Core::DescriptorPool& pool, + Beta(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs_0, std::array inImgs_1, std::array inImgs_2); diff --git a/include/shaderchains/delta.hpp b/include/shaderchains/delta.hpp index cd67869..33f8fb9 100644 --- a/include/shaderchains/delta.hpp +++ b/include/shaderchains/delta.hpp @@ -8,7 +8,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -34,7 +34,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Delta(const Device& device, const Core::DescriptorPool& pool, + Delta(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs, std::optional optImg); diff --git a/include/shaderchains/downsample.hpp b/include/shaderchains/downsample.hpp index fd7e280..78a9f78 100644 --- a/include/shaderchains/downsample.hpp +++ b/include/shaderchains/downsample.hpp @@ -8,7 +8,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -33,7 +33,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Downsample(const Device& device, const Core::DescriptorPool& pool, + Downsample(const Core::Device& device, const Core::DescriptorPool& pool, Core::Image inImg_0, Core::Image inImg_1); /// diff --git a/include/shaderchains/epsilon.hpp b/include/shaderchains/epsilon.hpp index 97f2d27..28e09d2 100644 --- a/include/shaderchains/epsilon.hpp +++ b/include/shaderchains/epsilon.hpp @@ -8,7 +8,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -35,7 +35,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Epsilon(const Device& device, const Core::DescriptorPool& pool, + Epsilon(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs1, Core::Image inImg2, std::optional optImg); diff --git a/include/shaderchains/extract.hpp b/include/shaderchains/extract.hpp index abf3fcc..a56a401 100644 --- a/include/shaderchains/extract.hpp +++ b/include/shaderchains/extract.hpp @@ -8,7 +8,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" namespace LSFG::Shaderchains { @@ -33,7 +33,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Extract(const Device& device, const Core::DescriptorPool& pool, + Extract(const Core::Device& device, const Core::DescriptorPool& pool, Core::Image inImg1, Core::Image inImg2, VkExtent2D outExtent); diff --git a/include/shaderchains/gamma.hpp b/include/shaderchains/gamma.hpp index a2767d8..9aca275 100644 --- a/include/shaderchains/gamma.hpp +++ b/include/shaderchains/gamma.hpp @@ -8,7 +8,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -41,7 +41,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Gamma(const Device& device, const Core::DescriptorPool& pool, + Gamma(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs1_0, std::array inImgs1_1, std::array inImgs1_2, diff --git a/include/shaderchains/magic.hpp b/include/shaderchains/magic.hpp index f1b287a..7a0b33f 100644 --- a/include/shaderchains/magic.hpp +++ b/include/shaderchains/magic.hpp @@ -8,7 +8,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -38,7 +38,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Magic(const Device& device, const Core::DescriptorPool& pool, + Magic(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs1_0, std::array inImgs1_1, std::array inImgs1_2, diff --git a/include/shaderchains/merge.hpp b/include/shaderchains/merge.hpp index 679522d..3af00cf 100644 --- a/include/shaderchains/merge.hpp +++ b/include/shaderchains/merge.hpp @@ -8,7 +8,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -37,7 +37,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Merge(const Device& device, const Core::DescriptorPool& pool, + Merge(const Core::Device& device, const Core::DescriptorPool& pool, Core::Image inImg1, Core::Image inImg2, Core::Image inImg3, diff --git a/include/shaderchains/zeta.hpp b/include/shaderchains/zeta.hpp index 56eeef4..372c0ae 100644 --- a/include/shaderchains/zeta.hpp +++ b/include/shaderchains/zeta.hpp @@ -8,7 +8,7 @@ #include "core/image.hpp" #include "core/pipeline.hpp" #include "core/shadermodule.hpp" -#include "device.hpp" +#include "core/device.hpp" #include @@ -35,7 +35,7 @@ namespace LSFG::Shaderchains { /// /// @throws LSFG::vulkan_error if resource creation fails. /// - Zeta(const Device& device, const Core::DescriptorPool& pool, + Zeta(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs1, Core::Image inImg2, Core::Image inImg3); diff --git a/include/utils.hpp b/include/utils.hpp index e6f7e64..15c6ce1 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -4,9 +4,8 @@ #include "core/commandbuffer.hpp" #include "core/image.hpp" #include "core/sampler.hpp" -#include "device.hpp" +#include "core/device.hpp" -#include #include #include @@ -68,7 +67,7 @@ namespace LSFG::Utils { /// @throws std::system_error If the file cannot be opened or read. /// @throws ls:vulkan_error If the Vulkan image cannot be created or updated. /// - void uploadImage(const Device& device, + void uploadImage(const Core::Device& device, const Core::CommandPool& commandPool, Core::Image& image, const std::string& path); @@ -81,7 +80,7 @@ namespace LSFG::Utils { /// /// @throws LSFG::vulkan_error If the Vulkan image cannot be cleared. /// - void clearImage(const Device& device, Core::Image& image, bool white = false); + void clearImage(const Core::Device& device, Core::Image& image, bool white = false); } @@ -111,7 +110,7 @@ namespace LSFG::Globals { static_assert(sizeof(FgBuffer) == 48, "FgBuffer must be 48 bytes in size."); /// Initialize global resources. - void initializeGlobals(const Device& device); + void initializeGlobals(const Core::Device& device); /// Uninitialize global resources. void uninitializeGlobals() noexcept; diff --git a/public/lsfg.hpp b/public/lsfg.hpp new file mode 100644 index 0000000..d9a25bf --- /dev/null +++ b/public/lsfg.hpp @@ -0,0 +1,79 @@ +#ifndef PUBLIC_LSFG_HPP +#define PUBLIC_LSFG_HPP + +#include + +#include + +namespace LSFG { + + /// + /// Initialize the LSFG library. + /// + /// @throws LSFG::vulkan_error if Vulkan objects fail to initialize. + /// + void initialize(); + + /// + /// Create a new LSFG context on a swapchain. + /// + /// @param width Width of the input images. + /// @param height Height of the input images. + /// @param in0 File descriptor for the first input image. + /// @param in1 File descriptor for the second input image. + /// @return A unique identifier for the created context. + /// + /// @throws LSFG::vulkan_error if the context cannot be created. + /// + int32_t createContext(uint32_t width, uint32_t height, int in0, int in1); + + /// + /// Present a context. + /// + /// @param id Unique identifier of the context to present. + /// @param inSem Semaphore to wait on before starting the generation. + /// @param outSem Semaphore to signal when the generation is complete. + /// + /// @throws LSFG::vulkan_error if the context cannot be presented. + /// + void presentContext(int32_t id, int inSem, int outSem); + + /// + /// Delete an LSFG context. + /// + /// @param id Unique identifier of the context to delete. + /// + void deleteContext(int32_t id); + + /// + /// Deinitialize the LSFG library. + /// + void finalize(); + + /// Simple exception class for Vulkan errors. + class vulkan_error : public std::runtime_error { + public: + /// + /// Construct a vulkan_error with a message and a Vulkan result code. + /// + /// @param result The Vulkan result code associated with the error. + /// @param message The error message. + /// + explicit vulkan_error(VkResult result, const std::string& message); + + /// Get the Vulkan result code associated with this error. + [[nodiscard]] VkResult error() const { return this->result; } + + // Trivially copyable, moveable and destructible + vulkan_error(const vulkan_error&) = default; + vulkan_error(vulkan_error&&) = default; + vulkan_error& operator=(const vulkan_error&) = default; + vulkan_error& operator=(vulkan_error&&) = default; + ~vulkan_error() noexcept override; + private: + VkResult result; + }; + +} + +#endif // PUBLIC_LSFG_HPP diff --git a/src/context.cpp b/src/context.cpp new file mode 100644 index 0000000..0afd34c --- /dev/null +++ b/src/context.cpp @@ -0,0 +1,111 @@ +#include "context.hpp" +#include "lsfg.hpp" + +#include +#include + +using namespace LSFG; + +Context::Context(const Core::Device& device, uint32_t width, uint32_t height, int in0, int in1) { + // create pools + this->descPool = Core::DescriptorPool(device); + this->cmdPool = Core::CommandPool(device); + + // create shader chains + this->downsampleChain = Shaderchains::Downsample(device, this->descPool, + this->inImg_0, this->inImg_1); + for (size_t i = 0; i < 7; i++) + this->alphaChains.at(i) = Shaderchains::Alpha(device, this->descPool, + this->downsampleChain.getOutImages().at(i)); + this->betaChain = Shaderchains::Beta(device, this->descPool, + this->alphaChains.at(0).getOutImages0(), + this->alphaChains.at(0).getOutImages1(), + this->alphaChains.at(0).getOutImages2()); + for (size_t i = 0; i < 7; i++) { + if (i < 4) { + this->gammaChains.at(i) = Shaderchains::Gamma(device, this->descPool, + this->alphaChains.at(6 - i).getOutImages0(), + this->alphaChains.at(6 - i).getOutImages1(), + this->alphaChains.at(6 - i).getOutImages2(), + this->betaChain.getOutImages().at(std::min(5UL, 6 - i)), + i == 0 ? std::nullopt + : std::optional{this->gammaChains.at(i - 1).getOutImage2()}, + i == 0 ? std::nullopt + : std::optional{this->gammaChains.at(i - 1).getOutImage1()}, + this->alphaChains.at(6 - i - 1).getOutImages0().at(0).getExtent() + ); + } else { + this->magicChains.at(i - 4) = Shaderchains::Magic(device, this->descPool, + this->alphaChains.at(6 - i).getOutImages0(), + this->alphaChains.at(6 - i).getOutImages1(), + this->alphaChains.at(6 - i).getOutImages2(), + i == 4 ? this->gammaChains.at(i - 1).getOutImage2() + : this->extractChains.at(i - 5).getOutImage(), + i == 4 ? this->gammaChains.at(i - 1).getOutImage1() + : this->zetaChains.at(i - 5).getOutImage(), + i == 4 ? std::nullopt : std::optional{this->epsilonChains.at(i - 5).getOutImage()} + ); + this->deltaChains.at(i - 4) = Shaderchains::Delta(device, this->descPool, + this->magicChains.at(i - 4).getOutImages1(), + i == 4 ? std::nullopt + : std::optional{this->deltaChains.at(i - 5).getOutImage()} + ); + this->epsilonChains.at(i - 4) = Shaderchains::Epsilon(device, this->descPool, + this->magicChains.at(i - 4).getOutImages2(), + this->betaChain.getOutImages().at(6 - i), + i == 4 ? std::nullopt + : std::optional{this->epsilonChains.at(i - 5).getOutImage()} + ); + this->zetaChains.at(i - 4) = Shaderchains::Zeta(device, this->descPool, + this->magicChains.at(i - 4).getOutImages3(), + i == 4 ? this->gammaChains.at(i - 1).getOutImage1() + : this->zetaChains.at(i - 5).getOutImage(), + this->betaChain.getOutImages().at(6 - i) + ); + if (i >= 6) + continue; // no extract for i >= 6 + this->extractChains.at(i - 4) = Shaderchains::Extract(device, this->descPool, + this->zetaChains.at(i - 4).getOutImage(), + this->epsilonChains.at(i - 4).getOutImage(), + this->alphaChains.at(6 - i - 1).getOutImages0().at(0).getExtent() + ); + } + } + this->mergeChain = Shaderchains::Merge(device, this->descPool, + this->inImg_1, + this->inImg_0, + this->zetaChains.at(2).getOutImage(), + this->epsilonChains.at(2).getOutImage(), + this->deltaChains.at(2).getOutImage() + ); +} + +void Context::present(const Core::Device& device, int inSem, int outSem) { + Core::CommandBuffer cmdBuffer(device, this->cmdPool); + cmdBuffer.begin(); + + this->downsampleChain.Dispatch(cmdBuffer, fc); + for (size_t i = 0; i < 7; i++) + this->alphaChains.at(6 - i).Dispatch(cmdBuffer, fc); + this->betaChain.Dispatch(cmdBuffer, fc); + for (size_t i = 0; i < 4; i++) + this->gammaChains.at(i).Dispatch(cmdBuffer, fc); + for (size_t i = 0; i < 3; i++) { + this->magicChains.at(i).Dispatch(cmdBuffer, fc); + this->deltaChains.at(i).Dispatch(cmdBuffer); + this->epsilonChains.at(i).Dispatch(cmdBuffer); + this->zetaChains.at(i).Dispatch(cmdBuffer); + if (i < 2) + this->extractChains.at(i).Dispatch(cmdBuffer); + } + this->mergeChain.Dispatch(cmdBuffer, fc); + + cmdBuffer.end(); + + fc++; +} + +vulkan_error::vulkan_error(VkResult result, const std::string& message) + : std::runtime_error(std::format("{} (error {})", message, static_cast(result))), result(result) {} + +vulkan_error::~vulkan_error() noexcept = default; diff --git a/src/core/buffer.cpp b/src/core/buffer.cpp index b446cd4..6a5e225 100644 --- a/src/core/buffer.cpp +++ b/src/core/buffer.cpp @@ -6,7 +6,7 @@ using namespace LSFG::Core; -void Buffer::construct(const Device& device, const void* data, VkBufferUsageFlags usage) { +void Buffer::construct(const Core::Device& device, const void* data, VkBufferUsageFlags usage) { // create buffer const VkBufferCreateInfo desc{ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, diff --git a/src/core/commandbuffer.cpp b/src/core/commandbuffer.cpp index 6c7d99d..c556127 100644 --- a/src/core/commandbuffer.cpp +++ b/src/core/commandbuffer.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Core; -CommandBuffer::CommandBuffer(const Device& device, const CommandPool& pool) { +CommandBuffer::CommandBuffer(const Core::Device& device, const CommandPool& pool) { // create command buffer const VkCommandBufferAllocateInfo desc{ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, diff --git a/src/core/commandpool.cpp b/src/core/commandpool.cpp index efd2098..f1a6030 100644 --- a/src/core/commandpool.cpp +++ b/src/core/commandpool.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Core; -CommandPool::CommandPool(const Device& device) { +CommandPool::CommandPool(const Core::Device& device) { // create command pool const VkCommandPoolCreateInfo desc{ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, diff --git a/src/core/descriptorpool.cpp b/src/core/descriptorpool.cpp index 1761549..75eb627 100644 --- a/src/core/descriptorpool.cpp +++ b/src/core/descriptorpool.cpp @@ -5,7 +5,7 @@ using namespace LSFG::Core; -DescriptorPool::DescriptorPool(const Device& device) { +DescriptorPool::DescriptorPool(const Core::Device& device) { // create descriptor pool const std::array pools{{ // arbitrary limits { .type = VK_DESCRIPTOR_TYPE_SAMPLER, .descriptorCount = 4096 }, diff --git a/src/core/descriptorset.cpp b/src/core/descriptorset.cpp index cb1df1d..c39454e 100644 --- a/src/core/descriptorset.cpp +++ b/src/core/descriptorset.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Core; -DescriptorSet::DescriptorSet(const Device& device, +DescriptorSet::DescriptorSet(const Core::Device& device, const DescriptorPool& pool, const ShaderModule& shaderModule) { // create descriptor set VkDescriptorSetLayout layout = shaderModule.getLayout(); @@ -27,7 +27,7 @@ DescriptorSet::DescriptorSet(const Device& device, ); } -DescriptorSetUpdateBuilder DescriptorSet::update(const Device& device) const { +DescriptorSetUpdateBuilder DescriptorSet::update(const Core::Device& device) const { return { *this, device }; } diff --git a/src/device.cpp b/src/core/device.cpp similarity index 98% rename from src/device.cpp rename to src/core/device.cpp index bbcd4ff..ef7788b 100644 --- a/src/device.cpp +++ b/src/core/device.cpp @@ -1,10 +1,10 @@ -#include "device.hpp" +#include "core/device.hpp" #include "lsfg.hpp" #include #include -using namespace LSFG; +using namespace LSFG::Core; const std::vector requiredExtensions = { "VK_KHR_external_memory_fd", diff --git a/src/core/fence.cpp b/src/core/fence.cpp index f7a12c5..b543df0 100644 --- a/src/core/fence.cpp +++ b/src/core/fence.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Core; -Fence::Fence(const Device& device) { +Fence::Fence(const Core::Device& device) { // create fence const VkFenceCreateInfo desc{ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO @@ -22,14 +22,14 @@ Fence::Fence(const Device& device) { ); } -void Fence::reset(const Device& device) const { +void Fence::reset(const Core::Device& device) const { VkFence fenceHandle = this->handle(); auto res = vkResetFences(device.handle(), 1, &fenceHandle); if (res != VK_SUCCESS) throw LSFG::vulkan_error(res, "Unable to reset fence"); } -bool Fence::wait(const Device& device, uint64_t timeout) const { +bool Fence::wait(const Core::Device& device, uint64_t timeout) const { VkFence fenceHandle = this->handle(); auto res = vkWaitForFences(device.handle(), 1, &fenceHandle, VK_TRUE, timeout); if (res != VK_SUCCESS && res != VK_TIMEOUT) diff --git a/src/core/image.cpp b/src/core/image.cpp index a24ff85..c190bb1 100644 --- a/src/core/image.cpp +++ b/src/core/image.cpp @@ -5,7 +5,7 @@ using namespace LSFG::Core; -Image::Image(const Device& device, VkExtent2D extent, VkFormat format, +Image::Image(const Core::Device& device, VkExtent2D extent, VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectFlags) : extent(extent), format(format), aspectFlags(aspectFlags) { // create image diff --git a/src/instance.cpp b/src/core/instance.cpp similarity index 96% rename from src/instance.cpp rename to src/core/instance.cpp index a97de0f..83a7a24 100644 --- a/src/instance.cpp +++ b/src/core/instance.cpp @@ -1,9 +1,9 @@ -#include "instance.hpp" +#include "core/instance.hpp" #include "lsfg.hpp" #include -using namespace LSFG; +using namespace LSFG::Core; const std::vector requiredExtensions = { diff --git a/src/core/pipeline.cpp b/src/core/pipeline.cpp index 4fc8fa4..9b2986f 100644 --- a/src/core/pipeline.cpp +++ b/src/core/pipeline.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Core; -Pipeline::Pipeline(const Device& device, const ShaderModule& shader) { +Pipeline::Pipeline(const Core::Device& device, const ShaderModule& shader) { // create pipeline layout VkDescriptorSetLayout shaderLayout = shader.getLayout(); const VkPipelineLayoutCreateInfo layoutDesc{ diff --git a/src/core/sampler.cpp b/src/core/sampler.cpp index 768d0c8..6965145 100644 --- a/src/core/sampler.cpp +++ b/src/core/sampler.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Core; -Sampler::Sampler(const Device& device, VkSamplerAddressMode mode) { +Sampler::Sampler(const Core::Device& device, VkSamplerAddressMode mode) { // create sampler const VkSamplerCreateInfo desc{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, diff --git a/src/core/semaphore.cpp b/src/core/semaphore.cpp index 20599cf..d2aee2a 100644 --- a/src/core/semaphore.cpp +++ b/src/core/semaphore.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Core; -Semaphore::Semaphore(const Device& device, std::optional initial) { +Semaphore::Semaphore(const Core::Device& device, std::optional initial) { // create semaphore const VkSemaphoreTypeCreateInfo typeInfo{ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, @@ -29,7 +29,7 @@ Semaphore::Semaphore(const Device& device, std::optional initial) { ); } -void Semaphore::signal(const Device& device, uint64_t value) const { +void Semaphore::signal(const Core::Device& device, uint64_t value) const { if (!this->isTimeline) throw std::logic_error("Invalid timeline semaphore"); @@ -43,7 +43,7 @@ void Semaphore::signal(const Device& device, uint64_t value) const { throw LSFG::vulkan_error(res, "Unable to signal semaphore"); } -bool Semaphore::wait(const Device& device, uint64_t value, uint64_t timeout) const { +bool Semaphore::wait(const Core::Device& device, uint64_t value, uint64_t timeout) const { if (!this->isTimeline) throw std::logic_error("Invalid timeline semaphore"); diff --git a/src/core/shadermodule.cpp b/src/core/shadermodule.cpp index acf0f23..3c8e98f 100644 --- a/src/core/shadermodule.cpp +++ b/src/core/shadermodule.cpp @@ -5,7 +5,7 @@ using namespace LSFG::Core; -ShaderModule::ShaderModule(const Device& device, const std::string& path, +ShaderModule::ShaderModule(const Core::Device& device, const std::string& path, const std::vector>& descriptorTypes) { // read shader bytecode std::ifstream file(path, std::ios::ate | std::ios::binary); diff --git a/src/lsfg.cpp b/src/lsfg.cpp index 90b75c4..d434c24 100644 --- a/src/lsfg.cpp +++ b/src/lsfg.cpp @@ -1,123 +1,67 @@ #include "lsfg.hpp" -#include "core/commandbuffer.hpp" -#include "core/fence.hpp" -#include "core/image.hpp" -#include "utils.hpp" +#include "core/device.hpp" +#include "core/instance.hpp" +#include "context.hpp" -#include -#include +#include +#include +#include +#include using namespace LSFG; -Generator::Generator(const Context& context) { - // TEST: create temporal images - this->inImg_0 = Core::Image(context.device, - { 2560, 1411 }, VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VK_IMAGE_ASPECT_COLOR_BIT - ); - this->inImg_1 = Core::Image(context.device, - { 2560, 1411 }, VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VK_IMAGE_ASPECT_COLOR_BIT - ); - // TEST END - - // create shader chains - this->downsampleChain = Shaderchains::Downsample(context.device, context.descPool, - this->inImg_0, this->inImg_1); - for (size_t i = 0; i < 7; i++) - this->alphaChains.at(i) = Shaderchains::Alpha(context.device, context.descPool, - this->downsampleChain.getOutImages().at(i)); - this->betaChain = Shaderchains::Beta(context.device, context.descPool, - this->alphaChains.at(0).getOutImages0(), - this->alphaChains.at(0).getOutImages1(), - this->alphaChains.at(0).getOutImages2()); - for (size_t i = 0; i < 7; i++) { - if (i < 4) { - this->gammaChains.at(i) = Shaderchains::Gamma(context.device, context.descPool, - this->alphaChains.at(6 - i).getOutImages0(), - this->alphaChains.at(6 - i).getOutImages1(), - this->alphaChains.at(6 - i).getOutImages2(), - this->betaChain.getOutImages().at(std::min(5UL, 6 - i)), - i == 0 ? std::nullopt - : std::optional{this->gammaChains.at(i - 1).getOutImage2()}, - i == 0 ? std::nullopt - : std::optional{this->gammaChains.at(i - 1).getOutImage1()}, - this->alphaChains.at(6 - i - 1).getOutImages0().at(0).getExtent() - ); - } else { - this->magicChains.at(i - 4) = Shaderchains::Magic(context.device, context.descPool, - this->alphaChains.at(6 - i).getOutImages0(), - this->alphaChains.at(6 - i).getOutImages1(), - this->alphaChains.at(6 - i).getOutImages2(), - i == 4 ? this->gammaChains.at(i - 1).getOutImage2() - : this->extractChains.at(i - 5).getOutImage(), - i == 4 ? this->gammaChains.at(i - 1).getOutImage1() - : this->zetaChains.at(i - 5).getOutImage(), - i == 4 ? std::nullopt : std::optional{this->epsilonChains.at(i - 5).getOutImage()} - ); - this->deltaChains.at(i - 4) = Shaderchains::Delta(context.device, context.descPool, - this->magicChains.at(i - 4).getOutImages1(), - i == 4 ? std::nullopt - : std::optional{this->deltaChains.at(i - 5).getOutImage()} - ); - this->epsilonChains.at(i - 4) = Shaderchains::Epsilon(context.device, context.descPool, - this->magicChains.at(i - 4).getOutImages2(), - this->betaChain.getOutImages().at(6 - i), - i == 4 ? std::nullopt - : std::optional{this->epsilonChains.at(i - 5).getOutImage()} - ); - this->zetaChains.at(i - 4) = Shaderchains::Zeta(context.device, context.descPool, - this->magicChains.at(i - 4).getOutImages3(), - i == 4 ? this->gammaChains.at(i - 1).getOutImage1() - : this->zetaChains.at(i - 5).getOutImage(), - this->betaChain.getOutImages().at(6 - i) - ); - if (i >= 6) - continue; // no extract for i >= 6 - this->extractChains.at(i - 4) = Shaderchains::Extract(context.device, context.descPool, - this->zetaChains.at(i - 4).getOutImage(), - this->epsilonChains.at(i - 4).getOutImage(), - this->alphaChains.at(6 - i - 1).getOutImages0().at(0).getExtent() - ); - } - } - this->mergeChain = Shaderchains::Merge(context.device, context.descPool, - this->inImg_1, - this->inImg_0, - this->zetaChains.at(2).getOutImage(), - this->epsilonChains.at(2).getOutImage(), - this->deltaChains.at(2).getOutImage() - ); +namespace { + std::optional instance; + std::optional device; + std::unordered_map contexts; } -void Generator::present(const Context& context) { - Core::CommandBuffer cmdBuffer(context.device, context.cmdPool); - cmdBuffer.begin(); +void LSFG::initialize() { + if (instance.has_value() || device.has_value()) + return; - this->downsampleChain.Dispatch(cmdBuffer, fc); - for (size_t i = 0; i < 7; i++) - this->alphaChains.at(6 - i).Dispatch(cmdBuffer, fc); - this->betaChain.Dispatch(cmdBuffer, fc); - for (size_t i = 0; i < 4; i++) - this->gammaChains.at(i).Dispatch(cmdBuffer, fc); - for (size_t i = 0; i < 3; i++) { - this->magicChains.at(i).Dispatch(cmdBuffer, fc); - this->deltaChains.at(i).Dispatch(cmdBuffer); - this->epsilonChains.at(i).Dispatch(cmdBuffer); - this->zetaChains.at(i).Dispatch(cmdBuffer); - if (i < 2) - this->extractChains.at(i).Dispatch(cmdBuffer); - } - this->mergeChain.Dispatch(cmdBuffer, fc); + instance.emplace(); + device.emplace(*instance); - cmdBuffer.end(); - - fc++; + std::srand(static_cast(std::time(nullptr))); } -vulkan_error::vulkan_error(VkResult result, const std::string& message) - : std::runtime_error(std::format("{} (error {})", message, static_cast(result))), result(result) {} +int32_t LSFG::createContext(uint32_t width, uint32_t height, int in0, int in1) { + if (!instance.has_value() || !device.has_value()) + throw LSFG::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "LSFG not initialized"); -vulkan_error::~vulkan_error() noexcept = default; + auto id = std::rand(); + contexts.emplace(id, Context(*device, width, height, in0, in1)); + return id; +} + +void LSFG::presentContext(int32_t id, int inSem, int outSem) { + if (!instance.has_value() || !device.has_value()) + throw LSFG::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "LSFG not initialized"); + + auto it = contexts.find(id); + if (it == contexts.end()) + throw LSFG::vulkan_error(VK_ERROR_DEVICE_LOST, "No such context"); + + Context& context = it->second; + context.present(*device, inSem, outSem); +} + +void LSFG::deleteContext(int32_t id) { + if (!instance.has_value() || !device.has_value()) + throw LSFG::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "LSFG not initialized"); + + auto it = contexts.find(id); + if (it == contexts.end()) + throw LSFG::vulkan_error(VK_ERROR_DEVICE_LOST, "No such context"); + + contexts.erase(it); +} + +void LSFG::finalize() { + if (!instance.has_value() && !device.has_value()) + return; + + instance.reset(); + device.reset(); +} diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 83b0e26..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "lsfg.hpp" - -#include - -#include -#include -#include - -using namespace LSFG; - -int main() { - // attempt to load renderdoc - RENDERDOC_API_1_6_0* rdoc = nullptr; - if (void* mod_renderdoc = dlopen("/usr/lib/librenderdoc.so", RTLD_NOLOAD | RTLD_NOW)) { - std::cerr << "Found RenderDoc library, setting up frame capture." << '\n'; - - auto GetAPI = reinterpret_cast(dlsym(mod_renderdoc, "RENDERDOC_GetAPI")); - const int ret = GetAPI(eRENDERDOC_API_Version_1_6_0, reinterpret_cast(&rdoc)); - if (ret == 0) { - std::cerr << "Unable to initialize RenderDoc API. Is your RenderDoc up to date?" << '\n'; - rdoc = nullptr; - } - usleep(1000 * 100); // give renderdoc time to load - } - - // initialize test application - LSFG::Context context; - auto gen = LSFG::Generator(context); - - for (int i = 0; i < 3; i++) { - if (rdoc) - rdoc->StartFrameCapture(nullptr, nullptr); - - gen.present(context); - - if (rdoc) - rdoc->EndFrameCapture(nullptr, nullptr); - - // sleep 8 ms - usleep(8000); - } - - usleep(1000 * 100); - - std::cerr << "Application finished" << '\n'; - return 0; -} diff --git a/src/shaderchains/alpha.cpp b/src/shaderchains/alpha.cpp index ba7f4c0..52c55aa 100644 --- a/src/shaderchains/alpha.cpp +++ b/src/shaderchains/alpha.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Alpha::Alpha(const Device& device, const Core::DescriptorPool& pool, +Alpha::Alpha(const Core::Device& device, const Core::DescriptorPool& pool, Core::Image inImg) : inImg(std::move(inImg)) { this->shaderModules = {{ diff --git a/src/shaderchains/beta.cpp b/src/shaderchains/beta.cpp index 698aa34..c3d3a2e 100644 --- a/src/shaderchains/beta.cpp +++ b/src/shaderchains/beta.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Beta::Beta(const Device& device, const Core::DescriptorPool& pool, +Beta::Beta(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs_0, std::array inImgs_1, std::array inImgs_2) diff --git a/src/shaderchains/delta.cpp b/src/shaderchains/delta.cpp index ca25a39..295ce97 100644 --- a/src/shaderchains/delta.cpp +++ b/src/shaderchains/delta.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Delta::Delta(const Device& device, const Core::DescriptorPool& pool, +Delta::Delta(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs, std::optional optImg) : inImgs(std::move(inImgs)), diff --git a/src/shaderchains/downsample.cpp b/src/shaderchains/downsample.cpp index c60e8bc..7b6ac12 100644 --- a/src/shaderchains/downsample.cpp +++ b/src/shaderchains/downsample.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Downsample::Downsample(const Device& device, const Core::DescriptorPool& pool, +Downsample::Downsample(const Core::Device& device, const Core::DescriptorPool& pool, Core::Image inImg_0, Core::Image inImg_1) : inImg_0(std::move(inImg_0)), inImg_1(std::move(inImg_1)) { diff --git a/src/shaderchains/epsilon.cpp b/src/shaderchains/epsilon.cpp index f199d64..8ba9474 100644 --- a/src/shaderchains/epsilon.cpp +++ b/src/shaderchains/epsilon.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Epsilon::Epsilon(const Device& device, const Core::DescriptorPool& pool, +Epsilon::Epsilon(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs1, Core::Image inImg2, std::optional optImg) diff --git a/src/shaderchains/extract.cpp b/src/shaderchains/extract.cpp index 4f66938..ee1fb00 100644 --- a/src/shaderchains/extract.cpp +++ b/src/shaderchains/extract.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Extract::Extract(const Device& device, const Core::DescriptorPool& pool, +Extract::Extract(const Core::Device& device, const Core::DescriptorPool& pool, Core::Image inImg1, Core::Image inImg2, VkExtent2D outExtent) diff --git a/src/shaderchains/gamma.cpp b/src/shaderchains/gamma.cpp index cd1b33b..ad82f10 100644 --- a/src/shaderchains/gamma.cpp +++ b/src/shaderchains/gamma.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Gamma::Gamma(const Device& device, const Core::DescriptorPool& pool, +Gamma::Gamma(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs1_0, std::array inImgs1_1, std::array inImgs1_2, diff --git a/src/shaderchains/magic.cpp b/src/shaderchains/magic.cpp index 3ebd895..450bc91 100644 --- a/src/shaderchains/magic.cpp +++ b/src/shaderchains/magic.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Magic::Magic(const Device& device, const Core::DescriptorPool& pool, +Magic::Magic(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs1_0, std::array inImgs1_1, std::array inImgs1_2, diff --git a/src/shaderchains/merge.cpp b/src/shaderchains/merge.cpp index 25e8e45..43bd957 100644 --- a/src/shaderchains/merge.cpp +++ b/src/shaderchains/merge.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Merge::Merge(const Device& device, const Core::DescriptorPool& pool, +Merge::Merge(const Core::Device& device, const Core::DescriptorPool& pool, Core::Image inImg1, Core::Image inImg2, Core::Image inImg3, diff --git a/src/shaderchains/zeta.cpp b/src/shaderchains/zeta.cpp index cb2bdd6..8b04126 100644 --- a/src/shaderchains/zeta.cpp +++ b/src/shaderchains/zeta.cpp @@ -3,7 +3,7 @@ using namespace LSFG::Shaderchains; -Zeta::Zeta(const Device& device, const Core::DescriptorPool& pool, +Zeta::Zeta(const Core::Device& device, const Core::DescriptorPool& pool, std::array inImgs1, Core::Image inImg2, Core::Image inImg3) diff --git a/src/utils.cpp b/src/utils.cpp index 1e13fbc..60a4274 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -58,7 +58,7 @@ void BarrierBuilder::build() const { vkCmdPipelineBarrier2(this->commandBuffer->handle(), &dependencyInfo); } -void Utils::uploadImage(const Device& device, const Core::CommandPool& commandPool, +void Utils::uploadImage(const Core::Device& device, const Core::CommandPool& commandPool, Core::Image& image, const std::string& path) { // read image bytecode std::ifstream file(path.data(), std::ios::binary | std::ios::ate); @@ -130,7 +130,7 @@ void Utils::uploadImage(const Device& device, const Core::CommandPool& commandPo throw LSFG::vulkan_error(VK_TIMEOUT, "Upload operation timed out"); } -void Utils::clearImage(const Device& device, Core::Image& image, bool white) { +void Utils::clearImage(const Core::Device& device, Core::Image& image, bool white) { Core::Fence fence(device); const Core::CommandPool cmdPool(device); Core::CommandBuffer cmdBuf(device, cmdPool); @@ -180,7 +180,7 @@ Core::Sampler Globals::samplerClampBorder; Core::Sampler Globals::samplerClampEdge; Globals::FgBuffer Globals::fgBuffer; -void Globals::initializeGlobals(const Device& device) { +void Globals::initializeGlobals(const Core::Device& device) { // initialize global samplers samplerClampBorder = Core::Sampler(device, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); samplerClampEdge = Core::Sampler(device, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);