diff --git a/lsfg-vk-backend/include/lsfg-vk-backend/lsfgvk.hpp b/lsfg-vk-backend/include/lsfg-vk-backend/lsfgvk.hpp deleted file mode 100644 index eacb98e..0000000 --- a/lsfg-vk-backend/include/lsfg-vk-backend/lsfgvk.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace lsfgvk::backend { - - class [[gnu::visibility("default")]] ContextImpl; - class [[gnu::visibility("default")]] InstanceImpl; - - using Context = ContextImpl; - - /// - /// Primitive exception class that deliveres a detailed error message - /// - class [[gnu::visibility("default")]] error : public std::runtime_error { - public: - /// - /// Construct an error - /// - /// @param msg Error message. - /// @param inner Inner exception. - /// - explicit error(const std::string &msg, const std::exception &inner); - - /// - /// Construct an error - /// - /// @param msg Error message. - /// - explicit error(const std::string &msg); - - error(const error &) = default; - error &operator=(const error &) = default; - error(error &&) = default; - error &operator=(error &&) = default; - ~error() override; - }; - - /// Function type for picking a device based on its name and IDs - using DevicePicker = std::function ids, // (vendor ID, device ID) 0xXXXX format - const std::optional& pci // (bus:slot.func) if available, no padded zeros - )>; - - /// - /// Main entry point of the library - /// - class [[gnu::visibility("default")]] Instance { - public: - /// - /// Create a lsfg-vk instance - /// - /// @param devicePicker Function that picks a physical device based on some identifiers. - /// @param shaderDllPath Path to the Lossless.dll file to load shaders from. - /// @param allowLowPrecision Whether to load low-precision (FP16) shaders if supported. - /// - /// @throws backend::error on failure - /// - Instance( - const DevicePicker& devicePicker, - const std::filesystem::path& shaderDllPath, - bool allowLowPrecision - ); - - /// - /// Open a frame generation context. - /// - /// The VkFormat of the exchanged images is inferred from whether hdr is true or false: - /// - false: VK_FORMAT_R8G8B8A8_UNORM - /// - true: VK_FORMAT_R16G16B16A16_SFLOAT - /// - /// The application and library must keep track of the frame index. When the next frame - /// is ready, signal the syncFd with one increment (with the first trigger being 1). - /// Each generated frame will increment the semaphore by one: - /// - Application signals 1 -> Start generating with (curr, next) source images - /// - Library signals 1 -> First frame between (curr, next) is ready - /// - Library signals N -> N-th frame between (curr, next) is ready - /// - Application signals N+1 -> Start generating with (next, curr) source images - /// - /// @param sourceFds Pair of file descriptors for the source images alternated between. - /// @param destFds Vector with file descriptors to import output images from. - /// @param syncFd File descriptor for the timeline semaphore used for synchronization. - /// @param width Width of the images. - /// @param height Height of the images. - /// @param hdr Whether the images are HDR. - /// @param flow Motion flow factor. - /// @param perf Whether to enable performance mode. - /// - /// @throws backend::error on failure - /// - Context& openContext( - std::pair sourceFds, - const std::vector& destFds, - int syncFd, - uint32_t width, uint32_t height, - bool hdr, float flow, bool perf - ); - - /// - /// Schedule a new set of generated frames. - /// - /// @param context Context to use. - /// @throws backend::error on failure - /// - void scheduleFrames(Context& context); - - /// - /// Close a frame generation context - /// - /// @param context Context to close. - /// - void closeContext(const Context& context); - - // Non-copyable and non-movable - Instance(const Instance&) = delete; - Instance& operator=(const Instance&) = delete; - Instance(Instance&&) = delete; - Instance& operator=(Instance&&) = delete; - virtual ~Instance(); - private: - std::unique_ptr m_impl; - - std::vector> m_contexts; - }; - - /// - /// Make all lsfg-vk instances leaking. - /// This is to workaround a bug in the Vulkan loader, which - /// makes it impossible to destroy Vulkan instances and devices. - /// - void makeLeaking(); - -} diff --git a/lsfg-vk-backend/include/lsfg-vk/lsfgvk.hpp b/lsfg-vk-backend/include/lsfg-vk/lsfgvk.hpp new file mode 100644 index 0000000..c270afc --- /dev/null +++ b/lsfg-vk-backend/include/lsfg-vk/lsfgvk.hpp @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#pragma once + +#include +#include +#include +#include + +namespace lsfgvk { + + /// Forward declaration of implementation classes + namespace priv { + struct [[gnu::visibility("default")]] Instance; + struct [[gnu::visibility("default")]] Context; + } + + /// + /// Main entrypoint of the library + /// + class [[gnu::visibility("default")]] Instance { + friend class Context; + public: + /// + /// Create a lsfg-vk instance + /// + /// The device identifier may be one of: + /// - Device name (e.g. "NVIDIA GeForce RTX 5080") + /// - Vendor ID + Device ID in lowercase hexadecimal (e.g. "10de:2c02") + /// - PCI bus ID with padded zeroes (e.g. "0000:01:00.0") + /// + /// @param deviceId Device identifier (see above) + /// @param lsfgvkDllPath Path to the lsfg-vk DLL file + /// @param allowFP16 Whether to allow usage of fp16 shader variants + /// @throws std::runtime_error on failure + /// + Instance( + const std::string& deviceId, + const std::filesystem::path& lsfgvkDllPath, + bool allowFP16 + ); + + // Non-copyable, non-movable + Instance(const Instance&) = delete; + Instance& operator=(const Instance&) = delete; + Instance(Instance&&) = delete; + Instance& operator=(Instance&&) = delete; + ~Instance(); + private: + std::unique_ptr m_priv; + }; + + /// + /// File descriptors exported from a context, the user must close them after use. + /// + struct FileDescriptors { + /// + /// File descriptor for a Vulkan memory allocation containing + /// a 2D array of RGBA8 pixels with length 2 and optimal allocation. + /// + /// Starting at iteration 0, the next frame for which frames should be interpolated + /// inbetween should be placed in image `iteration % 2`. + /// + int sourceFd; + + /// + /// File descriptor for a Vulkan memory allocation containing a single RGBA8 + /// image into which each generated frame will be written to. + /// + int destinationFd; + + /// + /// File descriptor for a timeline semaphore. When scheduling frames for generation, + /// a specific value is waited for and signaled on return. It is up to the user to ensure + /// the destination image is not overwritten before it is read. + /// + int syncFd; + }; + + /// A context for generating frames + /// + class [[gnu::visibility("default")]] Context { + public: + /// + /// Create a frame generation context + /// + /// @param instance Parent instance + /// @param width Image width + /// @param height Image height + /// @param flowScale Flow estimation scale factor + /// @param performanceMode Whether to enable performance mode + /// @throws std::runtime_error on failure + /// + Context( + const Instance& instance, + uint32_t width, + uint32_t height, + float flowScale, + bool performanceMode + ); + + /// + /// Export the internal resources + /// + /// @return File descriptors for internal resources + /// @throws std::runtime_error on failure + /// + [[nodiscard]] FileDescriptors exportFds() const; + + /// + /// Dispatch frame generation + /// + /// Let `so - 1` be the current value of the timeline semaphore, starting at 0. + /// The user must signal `so` to start the generation of the next frame, after + /// which lsfg-vk will signal `so + 1`. The user must ensure the previously + /// generated frame is read before signaling the next one (at `so + 2` and so on). + /// + /// @param total Total number of frames to generate + /// @throws std::runtime_error on failure + /// + void dispatch(uint32_t total); + + /// + /// Wait for the device to be idle + /// + void idle() const; + + // Non-copyable, non-movable + Context(const Context&) = delete; + Context& operator=(const Context&) = delete; + Context(Context&&) = delete; + Context& operator=(Context&&) = delete; + ~Context(); + private: + std::unique_ptr m_priv; + }; + +} diff --git a/lsfg-vk-backend/src/extraction/dll_reader.cpp b/lsfg-vk-backend/src/extraction/dll_reader.cpp deleted file mode 100644 index 13fcd07..0000000 --- a/lsfg-vk-backend/src/extraction/dll_reader.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "dll_reader.hpp" -#include "lsfg-vk-common/helpers/errors.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace lsfgvk; -using namespace lsfgvk::backend; - -namespace { - /// DOS file header - struct DOSHeader { - uint16_t magic; // 0x5A4D - std::array pad; - int32_t pe_offset; // file offset - }; - - /// PE header - struct PEHeader { - uint32_t signature; // "PE\0\0" - std::array pad1; - uint16_t sect_count; - std::array pad2; - uint16_t opt_hdr_size; - std::array pad3; - }; - - /// (partial!) PE optional header - struct PEOptionalHeader { - uint16_t magic; // 0x20B - std::array pad4; - std::pair resource_table; // file offset/size - }; - - /// Section header - struct SectionHeader { - std::array pad1; - uint32_t vsize; // virtual - uint32_t vaddress; - uint32_t fsize; // raw - uint32_t foffset; - std::array pad2; - }; - - /// Resource directory - struct ResourceDirectory { - std::array pad; - uint16_t name_count; - uint16_t id_count; - }; - - /// Resource directory entry - struct ResourceDirectoryEntry { - uint32_t id; - uint32_t offset; // high bit = directory - }; - - /// Resource data entry - struct ResourceDataEntry { - uint32_t offset; - uint32_t size; - std::array pad; - }; -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunknown-warning-option" -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" -namespace { - /// Safely cast a vector to a pointer of type T - template - const T* safe_cast(const std::vector& data, size_t offset) { - const size_t end = offset + sizeof(T); - if (end > data.size() || end < offset) - throw ls::error("buffer overflow/underflow during safe cast"); - return reinterpret_cast(&data.at(offset)); - } - - /// Safely cast a vector to a span of T - template - std::span span_cast(const std::vector& data, size_t offset, size_t count) { - const size_t end = offset + (count * sizeof(T)); - if (end > data.size() || end < offset) - throw ls::error("buffer overflow/underflow during safe cast"); - return std::span(reinterpret_cast(&data.at(offset)), count); - } -} -#pragma clang diagnostic pop - -std::unordered_map> backend::extractResourcesFromDLL( - const std::filesystem::path& dll) { - std::ifstream file(dll, std::ios::binary | std::ios::ate); - if (!file.is_open()) - throw ls::error("failed to open dll file"); - - const std::streamsize size = static_cast(file.tellg()); - file.seekg(0, std::ios::beg); - - std::vector data(static_cast(size)); - if (!file.read(reinterpret_cast(data.data()), size)) - throw ls::error("failed to read dll file"); - - // parse dos header - size_t fileOffset = 0; - const auto* dosHdr = safe_cast(data, 0); - if (dosHdr->magic != 0x5A4D) - throw ls::error("dos header magic number is incorrect"); - - // parse pe header - fileOffset += static_cast(dosHdr->pe_offset); - const auto* peHdr = safe_cast(data, fileOffset); - if (peHdr->signature != 0x00004550) - throw ls::error("pe header signature is incorrect"); - - // parse optional pe header - fileOffset += sizeof(PEHeader); - const auto* peOptHdr = safe_cast(data, fileOffset); - if (peOptHdr->magic != 0x20B) - throw ls::error("pe format is not PE32+"); - const auto& [rsrc_rva, rsrc_size] = peOptHdr->resource_table; - - // locate section containing resources - std::optional rsrc_offset; - fileOffset += peHdr->opt_hdr_size; - const auto sectHdrs = span_cast(data, fileOffset, peHdr->sect_count); - for (const auto& sectHdr : sectHdrs) { - if (rsrc_rva < sectHdr.vaddress || rsrc_rva > (sectHdr.vaddress + sectHdr.vsize)) - continue; - - rsrc_offset.emplace((rsrc_rva - sectHdr.vaddress) + sectHdr.foffset); - break; - } - if (!rsrc_offset) - throw ls::error("unable to locate resource section"); - - // parse resource directory - fileOffset = rsrc_offset.value(); - const auto* rsrcDir = safe_cast(data, fileOffset); - if (rsrcDir->id_count < 3) - throw ls::error("resource directory does not have enough entries"); - - // find resource table with data type - std::optional rsrc_tbl_offset; - fileOffset = rsrc_offset.value() + sizeof(ResourceDirectory); - const auto rsrcDirEntries = span_cast( - data, fileOffset, rsrcDir->name_count + rsrcDir->id_count); - for (const auto& rsrcDirEntry : rsrcDirEntries) { - if (rsrcDirEntry.id != 10) // RT_RCDATA - continue; - if ((rsrcDirEntry.offset & 0x80000000) == 0) - throw ls::error("expected resource directory, found data entry"); - - rsrc_tbl_offset.emplace(rsrcDirEntry.offset & 0x7FFFFFFF); - } - if (!rsrc_tbl_offset) - throw ls::error("unabele to locate RT_RCDATA directory"); - - // parse data type resource directory - fileOffset = rsrc_offset.value() + rsrc_tbl_offset.value(); - const auto* rsrcTbl = safe_cast(data, fileOffset); - if (rsrcTbl->id_count < 1) - throw ls::error("RT_RCDATA directory does not have enough entries"); - - // collect all resources - fileOffset += sizeof(ResourceDirectory); - const auto rsrcTblEntries = span_cast( - data, fileOffset, rsrcTbl->name_count + rsrcTbl->id_count); - std::unordered_map> resources; - for (const auto& rsrcTblEntry : rsrcTblEntries) { - if ((rsrcTblEntry.offset & 0x80000000) == 0) - throw ls::error("expected resource directory, found data entry"); - - // skip over language directory - fileOffset = rsrc_offset.value() + (rsrcTblEntry.offset & 0x7FFFFFFF); - const auto* langDir = safe_cast(data, fileOffset); - if (langDir->id_count < 1) - throw ls::error("Incorrect language directory"); - - fileOffset += sizeof(ResourceDirectory); - const auto* langDirEntry = safe_cast(data, fileOffset); - if ((langDirEntry->offset & 0x80000000) != 0) - throw ls::error("expected resource data entry, but found directory"); - - // parse resource data entry - fileOffset = rsrc_offset.value() + (langDirEntry->offset & 0x7FFFFFFF); - const auto* entry = safe_cast(data, fileOffset); - if (entry->offset < rsrc_rva || entry->offset > (rsrc_rva + rsrc_size)) - throw ls::error("resource data entry points outside resource section"); - - // extract resource - std::vector resource(entry->size); - fileOffset = (entry->offset - rsrc_rva) + rsrc_offset.value(); - if (fileOffset + entry->size > data.size()) - throw ls::error("resource data entry points outside file"); - std::copy_n(&data.at(fileOffset), entry->size, resource.data()); - resources.emplace(rsrcTblEntry.id, std::move(resource)); - } - - return resources; -} diff --git a/lsfg-vk-backend/src/extraction/dll_reader.hpp b/lsfg-vk-backend/src/extraction/dll_reader.hpp deleted file mode 100644 index a73e899..0000000 --- a/lsfg-vk-backend/src/extraction/dll_reader.hpp +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#pragma once - -#include -#include -#include -#include - -namespace lsfgvk::backend { - - /// extract all resources from a DLL file - /// @param dll path to the DLL file - /// @return map of resource IDs to their binary data - /// @throws ls::error on various failure points - std::unordered_map> extractResourcesFromDLL( - const std::filesystem::path& dll); - -} diff --git a/lsfg-vk-backend/src/extraction/shader_registry.cpp b/lsfg-vk-backend/src/extraction/shader_registry.cpp deleted file mode 100644 index b9c65e6..0000000 --- a/lsfg-vk-backend/src/extraction/shader_registry.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "shader_registry.hpp" -#include "lsfg-vk-common/helpers/errors.hpp" -#include "lsfg-vk-common/vulkan/shader.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include -#include -#include -#include -#include - -using namespace lsfgvk; -using namespace lsfgvk::backend; - -namespace { - /// get the source code for a shader - const std::vector& getShaderSource(uint32_t id, bool fp16, bool perf, - const std::unordered_map>& resources) { - const size_t BASE_OFFSET = 49; - const size_t OFFSET_PERF = 23; - const size_t OFFSET_FP32 = 49; - - auto it = resources.find(BASE_OFFSET + id + - (perf ? OFFSET_PERF : 0) + - (fp16 ? 0 : OFFSET_FP32)); - if (it == resources.end()) - throw ls::error("unable to find shader with id: " + std::to_string(id)); - - return it->second; - } - /// patch the generate shader - void patchGenerateShader(std::vector& data, bool hdr) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunknown-warning-option" -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container" - auto* _ptr = data.data(); - const std::span words( - reinterpret_cast(_ptr), - data.size() / sizeof(uint32_t) - ); -#pragma clang diagnostic pop - - const uint16_t SpvOpCapability = 17; - const uint16_t SpvOpTypeImage = 25; - const uint32_t SpvCapabilityStorageImageWriteWithoutFormat = 56; - const uint32_t SpvCapabilityShader = 1; - const uint32_t SpvImageFormatRgba16f = 2; - const uint32_t SpvImageFormatRgba8 = 4; - - for (size_t i = 5; i < words.size();) { - const uint32_t& word = words[i]; // NOLINT ([]-usage) - const uint16_t wc = (word >> 16); - const uint16_t op = word & 0xFFFF; - - // remove write without format capability - if (op == SpvOpCapability && wc >= 2) { - uint32_t& cap = words[i + 1]; // NOLINT ([]-usage) - if (cap == SpvCapabilityStorageImageWriteWithoutFormat) - cap = SpvCapabilityShader; - } - - // patch format in image instructions - if (op == SpvOpTypeImage && wc >= 9) { - const uint32_t sampled = words[i + 7]; // NOLINT ([]-usage) - if (sampled == 2) - words[i + 8] = // NOLINT ([]-usage) - hdr ? SpvImageFormatRgba16f : SpvImageFormatRgba8; - } - - i += wc ? wc : 1; - } - } -} - -ShaderRegistry backend::buildShaderRegistry(const vk::Vulkan& vk, bool fp16, - const std::unordered_map>& resources) { - // patch the generate shader - std::vector generate_data = getShaderSource(256, fp16, false, resources); - std::vector generate_data_hdr = generate_data; - patchGenerateShader(generate_data, false); - patchGenerateShader(generate_data_hdr, true); - - // load all other shaders -#define SHADER(id, p1, p2, p3, p4) \ - vk::Shader(vk, getShaderSource(id, fp16, PERF, resources), \ - p1, p2, p3, p4) - - return { -#define PERF false - .mipmaps = SHADER(255, 1, 7, 1, 1), - .generate = vk::Shader(vk, generate_data, 5, 1, 1, 2), - .generate_hdr = vk::Shader(vk, generate_data_hdr, 5, 1, 1, 2), - .quality = { - .alpha = { - SHADER(267, 1, 2, 0, 1), - SHADER(268, 2, 2, 0, 1), - SHADER(269, 2, 4, 0, 1), - SHADER(270, 4, 4, 0, 1) - }, - .beta = { - SHADER(275, 12, 2, 0, 1), - SHADER(276, 2, 2, 0, 1), - SHADER(277, 2, 2, 0, 1), - SHADER(278, 2, 2, 0, 1), - SHADER(279, 2, 6, 1, 1) - }, - .gamma = { - SHADER(257, 9, 3, 1, 2), - SHADER(259, 3, 4, 0, 1), - SHADER(260, 4, 4, 0, 1), - SHADER(261, 4, 4, 0, 1), - SHADER(262, 6, 1, 1, 2) - }, - .delta = { - SHADER(257, 9, 3, 1, 2), - SHADER(263, 3, 4, 0, 1), - SHADER(264, 4, 4, 0, 1), - SHADER(265, 4, 4, 0, 1), - SHADER(266, 6, 1, 1, 2), - SHADER(258, 10, 2, 1, 2), - SHADER(271, 2, 2, 0, 1), - SHADER(272, 2, 2, 0, 1), - SHADER(273, 2, 2, 0, 1), - SHADER(274, 3, 1, 1, 2) - } - }, -#undef PERF -#define PERF true - .performance = { - .alpha = { - SHADER(267, 1, 1, 0, 1), - SHADER(268, 1, 1, 0, 1), - SHADER(269, 1, 2, 0, 1), - SHADER(270, 2, 2, 0, 1) - }, - .beta = { - SHADER(275, 6, 2, 0, 1), - SHADER(276, 2, 2, 0, 1), - SHADER(277, 2, 2, 0, 1), - SHADER(278, 2, 2, 0, 1), - SHADER(279, 2, 6, 1, 1) - }, - .gamma = { - SHADER(257, 5, 3, 1, 2), - SHADER(259, 3, 2, 0, 1), - SHADER(260, 2, 2, 0, 1), - SHADER(261, 2, 2, 0, 1), - SHADER(262, 4, 1, 1, 2) - }, - .delta = { - SHADER(257, 5, 3, 1, 2), - SHADER(263, 3, 2, 0, 1), - SHADER(264, 2, 2, 0, 1), - SHADER(265, 2, 2, 0, 1), - SHADER(266, 4, 1, 1, 2), - SHADER(258, 6, 1, 1, 2), - SHADER(271, 1, 1, 0, 1), - SHADER(272, 1, 1, 0, 1), - SHADER(273, 1, 1, 0, 1), - SHADER(274, 2, 1, 1, 2) - } - }, -#undef PERF - .is_fp16 = fp16 - }; - -#undef SHADER -} diff --git a/lsfg-vk-backend/src/extraction/shader_registry.hpp b/lsfg-vk-backend/src/extraction/shader_registry.hpp deleted file mode 100644 index e2dcee8..0000000 --- a/lsfg-vk-backend/src/extraction/shader_registry.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#pragma once - -#include "lsfg-vk-common/vulkan/shader.hpp" - -#include -#include -#include -#include - -namespace lsfgvk::backend { - - /// shader collection struct - struct Shaders { - std::array alpha; - std::array beta; - std::array gamma; - std::array delta; - }; - - /// shader registry struct - struct ShaderRegistry { - vk::Shader mipmaps; - vk::Shader generate, generate_hdr; - Shaders quality; - Shaders performance; - - bool is_fp16; //!< whether the fp16 shader variants were loaded - }; - - /// build a shader registry from resources - /// @param vk Vulkan instance - /// @param fp16 whether to load fp16 variants - /// @param resources map of resource IDs to their binary data - /// @return constructed shader registry - /// @throws ls::error if shaders are missing - /// @throws vk::vulkan_error on Vulkan errors - ShaderRegistry buildShaderRegistry(const vk::Vulkan& vk, bool fp16, - const std::unordered_map>& resources); - -} diff --git a/lsfg-vk-backend/src/helpers/limits.cpp b/lsfg-vk-backend/src/helpers/limits.cpp deleted file mode 100644 index 32e5e00..0000000 --- a/lsfg-vk-backend/src/helpers/limits.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "limits.hpp" - -#include "lsfg-vk-common/vulkan/descriptor_pool.hpp" - -#include -#include - -using namespace lsfgvk; -using namespace lsfgvk::backend; - -namespace { - const vk::Limits BASE_LIMITS{ - .sets = 51, - .uniform_buffers = 3, - .samplers = 51, - .sampled_images = 165, - .storage_images = 172 - }; - const vk::Limits BASE_LIMITS_PERF{ - .sampled_images = 91, - .storage_images = 102 - }; - const vk::Limits GEN_LIMITS{ - .sets = 93, - .uniform_buffers = 54, - .samplers = 147, - .sampled_images = 567, - .storage_images = 261 - }; - const vk::Limits GEN_LIMITS_PERF{ - .sampled_images = 339, - .storage_images = 183 - }; -} - -vk::Limits backend::calculateDescriptorPoolLimits(size_t count, bool perf) { - const auto m = static_cast(count); - - vk::Limits a{BASE_LIMITS}; - vk::Limits b{GEN_LIMITS}; - if (perf) { - a.sampled_images = BASE_LIMITS_PERF.sampled_images; - b.sampled_images = GEN_LIMITS_PERF.sampled_images; - a.storage_images = BASE_LIMITS_PERF.storage_images; - b.storage_images = GEN_LIMITS_PERF.storage_images; - } - - a.sets += b.sets * m; - a.uniform_buffers += b.uniform_buffers * m; - a.samplers += b.samplers * m; - a.sampled_images += b.sampled_images * m; - a.storage_images += b.storage_images * m; - return a; -} diff --git a/lsfg-vk-backend/src/helpers/limits.hpp b/lsfg-vk-backend/src/helpers/limits.hpp deleted file mode 100644 index 3647f54..0000000 --- a/lsfg-vk-backend/src/helpers/limits.hpp +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#pragma once - -#include "lsfg-vk-common/vulkan/descriptor_pool.hpp" - -#include - -namespace lsfgvk::backend { - /// calculate limits for descriptor pools - /// @param count number of images - /// @param perf whether performance mode is enabled - /// @return calculated limits - vk::Limits calculateDescriptorPoolLimits(size_t count, bool perf); -} diff --git a/lsfg-vk-backend/src/helpers/managed_shader.cpp b/lsfg-vk-backend/src/helpers/managed_shader.cpp deleted file mode 100644 index 0b35ad4..0000000 --- a/lsfg-vk-backend/src/helpers/managed_shader.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "managed_shader.hpp" -#include "lsfg-vk-common/vulkan/buffer.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/descriptor_pool.hpp" -#include "lsfg-vk-common/vulkan/image.hpp" -#include "lsfg-vk-common/vulkan/sampler.hpp" -#include "lsfg-vk-common/vulkan/shader.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include -#include -#include - -#include - -using namespace lsfgvk; -using namespace lsfgvk::backend; - -ManagedShaderBuilder& ManagedShaderBuilder::sampled(const vk::Image& image) { - this->sampledImages.push_back(std::ref(image)); - return *this; -} - -ManagedShaderBuilder& ManagedShaderBuilder::sampleds( - const std::vector& images, - size_t offset, size_t count) { - if (count == 0 || offset + count > images.size()) - count = images.size() - offset; - - for (size_t i = 0; i < count; ++i) - this->sampledImages.push_back(std::ref(images.at(offset + i))); - return *this; -} - - -ManagedShaderBuilder& ManagedShaderBuilder::storage(const vk::Image& image) { - this->storageImages.push_back(std::ref(image)); - return *this; -} - -ManagedShaderBuilder& ManagedShaderBuilder::storages( - const std::vector& images, - size_t offset, size_t count) { - if (count == 0 || offset + count > images.size()) - count = images.size() - offset; - - for (size_t i = 0; i < count; ++i) - this->storageImages.push_back(std::ref(images.at(offset + i))); - return *this; -} - -ManagedShaderBuilder& ManagedShaderBuilder::sampler(const vk::Sampler& sampler) { - this->imageSamplers.push_back(std::ref(sampler)); - return *this; -} - -ManagedShaderBuilder& ManagedShaderBuilder::samplers( - const std::vector& samplers) { - for (const auto& sampler : samplers) - this->imageSamplers.push_back(std::ref(sampler)); - return *this; -} - -ManagedShaderBuilder& ManagedShaderBuilder::buffer(const vk::Buffer& buffer) { - this->constantBuffers.push_back(std::ref(buffer)); - return *this; -} - -ManagedShader ManagedShaderBuilder::build(const vk::Vulkan& vk, - const vk::DescriptorPool& pool, const vk::Shader& shader) const { - std::vector barriers; - barriers.reserve(this->storageImages.size() + this->sampledImages.size()); - - for (const auto& img : this->sampledImages) - barriers.push_back({ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, - .oldLayout = VK_IMAGE_LAYOUT_GENERAL, - .newLayout = VK_IMAGE_LAYOUT_GENERAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = img.get().handle(), - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = 1, - .layerCount = 1 - } - }); - for (const auto& img : this->storageImages) - barriers.push_back({ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_SHADER_READ_BIT, - .dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT, - .oldLayout = VK_IMAGE_LAYOUT_GENERAL, - .newLayout = VK_IMAGE_LAYOUT_GENERAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = img.get().handle(), - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = 1, - .layerCount = 1 - } - }); - - return { - std::ref(shader), - std::move(barriers), - vk::DescriptorSet(vk, pool, shader, - this->sampledImages, - this->storageImages, - this->imageSamplers, - this->constantBuffers) - }; -} - -void ManagedShader::dispatch(const vk::Vulkan& vk, const vk::CommandBuffer& cmd, - VkExtent2D extent) const { - cmd.dispatch(vk, this->shader, - this->descriptorSet, - this->barriers, - extent.width, extent.height, 1 - ); -} diff --git a/lsfg-vk-backend/src/helpers/managed_shader.hpp b/lsfg-vk-backend/src/helpers/managed_shader.hpp deleted file mode 100644 index e0d673f..0000000 --- a/lsfg-vk-backend/src/helpers/managed_shader.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#pragma once - -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/descriptor_pool.hpp" -#include "lsfg-vk-common/vulkan/descriptor_set.hpp" -#include "lsfg-vk-common/vulkan/shader.hpp" - -#include -#include - -#include - -namespace lsfgvk::backend { - - /// managed shader handling dispatch and barriers - /// this class is NOT memory-safe - class ManagedShader { - friend class ManagedShaderBuilder; - public: - /// dispatch the managed shader - /// @param vk the vulkan instance - /// @param cmd command buffer to use - /// @param extent dispatch size - /// @throws ls::vulkan_error on failure - void dispatch(const vk::Vulkan& vk, - const vk::CommandBuffer& cmd, VkExtent2D extent) const; - private: - ls::R shader; - - std::vector barriers; - vk::DescriptorSet descriptorSet; - - // simple move constructor - ManagedShader(ls::R shader, - std::vector barriers, - vk::DescriptorSet descriptorSet) : - shader(shader), - barriers(std::move(barriers)), - descriptorSet(std::move(descriptorSet)) { - } - }; - - /// class for building managed shaders - /// this class is NOT memory-safe - class ManagedShaderBuilder { - public: - /// default constructor - ManagedShaderBuilder() = default; - - /// add a sampled image - /// @param image image to add - [[nodiscard]] ManagedShaderBuilder& sampled(const vk::Image& image); - /// add multiple sampled images - /// @param images images to add - /// @param offset offset into images - /// @param count number of images to add (0 = all) - [[nodiscard]] ManagedShaderBuilder& sampleds(const std::vector& images, - size_t offset = 0, size_t count = 0); - - /// add a storage image - /// @param image image to add - [[nodiscard]] ManagedShaderBuilder& storage(const vk::Image& image); - /// add multiple storage images - /// @param images images to add - /// @param offset offset into images - /// @param count number of images to add (0 = all) - [[nodiscard]] ManagedShaderBuilder& storages(const std::vector& images, - size_t offset = 0, size_t count = 0); - - /// add a sampler - /// @param sampler sampler to add - [[nodiscard]] ManagedShaderBuilder& sampler(const vk::Sampler& sampler); - /// add multiple samplers - /// @param samplers samplers to add - [[nodiscard]] ManagedShaderBuilder& samplers(const std::vector& samplers); - - /// add a buffer - /// @param buffer buffer to add - [[nodiscard]] ManagedShaderBuilder& buffer(const vk::Buffer& buffer); - - /// build the managed shader - /// @param vk the vulkan instance - /// @param pool the descriptor pool to use - /// @param shader the shader to use - /// @returns the built managed shader - [[nodiscard]] ManagedShader build(const vk::Vulkan& vk, - const vk::DescriptorPool& pool, const vk::Shader& shader) const; - private: - std::vector> sampledImages; - std::vector> storageImages; - std::vector> imageSamplers; - std::vector> constantBuffers; - }; - -} diff --git a/lsfg-vk-backend/src/helpers/utils.cpp b/lsfg-vk-backend/src/helpers/utils.cpp deleted file mode 100644 index 3c310cd..0000000 --- a/lsfg-vk-backend/src/helpers/utils.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "utils.hpp" - -#include -#include -#include -#include - -#include - -using namespace lsfgvk; -using namespace lsfgvk::backend; - -ConstantBuffer backend::getDefaultConstantBuffer( - size_t index, size_t total, - bool hdr, float invFlow) { - return ConstantBuffer { - .advancedColorKind = hdr ? 2U : 0U, - .hdrSupport = hdr ? 1U : 0U, - .resolutionInvScale = invFlow, - .timestamp = static_cast(index + 1) / static_cast(total + 1), - .uiThreshold = 0.5F - }; -} - -VkExtent2D backend::shift_extent(VkExtent2D extent, uint32_t i) { - return VkExtent2D{ - .width = extent.width >> i, - .height = extent.height >> i - }; -} - -VkExtent2D backend::add_shift_extent(VkExtent2D extent, uint32_t a, uint32_t i) { - return VkExtent2D{ - .width = (extent.width + a) >> i, - .height = (extent.height + a) >> i - }; -} - -std::string backend::to_hex_id(uint32_t id) { - const std::array chars = std::to_array("0123456789ABCDEF"); - - std::string result = "0x"; - result += chars.at((id >> 12) & 0xF); - result += chars.at((id >> 8) & 0xF); - result += chars.at((id >> 4) & 0xF); - result += chars.at(id & 0xF); - return result; -} diff --git a/lsfg-vk-backend/src/helpers/utils.hpp b/lsfg-vk-backend/src/helpers/utils.hpp deleted file mode 100644 index 202ac0c..0000000 --- a/lsfg-vk-backend/src/helpers/utils.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#pragma once - -#include "../extraction/shader_registry.hpp" -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/buffer.hpp" -#include "lsfg-vk-common/vulkan/descriptor_pool.hpp" -#include "lsfg-vk-common/vulkan/sampler.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include -#include -#include -#include - -#include - -namespace lsfgvk::backend { - /// exposed context data - struct Ctx { - ls::R vk; // safe back reference - ls::R shaders; // safe back reference - - vk::DescriptorPool pool; - - vk::Buffer constantBuffer; - std::vector constantBuffers; - vk::Sampler bnbSampler; //!< border, no compare, black - vk::Sampler bnwSampler; //!< border, no compare, white - vk::Sampler eabSampler; //!< edge, always compare, black - - VkExtent2D sourceExtent; - VkExtent2D flowExtent; - - bool hdr; - float flow; - bool perf; - size_t count; - }; - - /// constant buffer used in shaders - struct ConstantBuffer { - std::array inputOffset; - uint32_t firstIter; - uint32_t firstIterS; - uint32_t advancedColorKind; - uint32_t hdrSupport; - float resolutionInvScale; - float timestamp; - float uiThreshold; - std::array pad; - }; - - /// get a prefilled constant buffer - /// @param index timestamp index - /// @param total total amount of images - /// @param hdr whether HDR is enabled - /// @param invFlow inverted flow scale value - /// @return prefilled constant buffer - ConstantBuffer getDefaultConstantBuffer( - size_t index, size_t total, - bool hdr, float invFlow - ); - - /// round down a VkExtent2D - /// @param extent the extent to shift - /// @param i the amount to shift by - /// @return the shifted extent - VkExtent2D shift_extent(VkExtent2D extent, uint32_t i); - - /// round up a VkExtent2D - /// @param extent the extent to shift - /// @param a the amount to add before shifting - /// @param i the amount to shift by - /// @return the shifted extent - VkExtent2D add_shift_extent(VkExtent2D extent, uint32_t a, uint32_t i); - - /// convert a device/vendor id into a hex string - std::string to_hex_id(uint32_t id); -} diff --git a/lsfg-vk-backend/src/lsfgvk.cpp b/lsfg-vk-backend/src/lsfgvk.cpp index c94cfe1..c5cc874 100644 --- a/lsfg-vk-backend/src/lsfgvk.cpp +++ b/lsfg-vk-backend/src/lsfgvk.cpp @@ -1,666 +1,7 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ -#include "lsfg-vk-backend/lsfgvk.hpp" -#include "extraction/dll_reader.hpp" -#include "extraction/shader_registry.hpp" -#include "helpers/limits.hpp" -#include "helpers/utils.hpp" -#include "lsfg-vk-common/helpers/errors.hpp" -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/buffer.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/fence.hpp" -#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/delta0.hpp" -#include "shaderchains/delta1.hpp" -#include "shaderchains/gamma0.hpp" -#include "shaderchains/gamma1.hpp" -#include "shaderchains/generate.hpp" -#include "shaderchains/mipmaps.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef LSFGVK_TESTING_RENDERDOC -#include -#include -#endif +#include "lsfg-vk/lsfgvk.hpp" using namespace lsfgvk; -using namespace lsfgvk::backend; -namespace lsfgvk::backend { - error::error(const std::string& msg, const std::exception& inner) - : std::runtime_error(msg + "\n- " + inner.what()) {} - error::error(const std::string& msg) - : std::runtime_error(msg) {} - error::~error() = default; - - /// instance class - class InstanceImpl { - public: - /// create an instance - /// (see lsfg-vk documentation) - InstanceImpl(vk::PhysicalDeviceSelector selectPhysicalDevice, - const std::filesystem::path& shaderDllPath, - bool allowLowPrecision); - - /// get the Vulkan instance - /// @return the Vulkan instance - [[nodiscard]] const auto& getVulkan() const { return this->vk; } - /// get the shader registry - /// @return the shader registry - [[nodiscard]] const auto& getShaderRegistry() const { return this->shaders; } -#ifdef LSFGVK_TESTING_RENDERDOC - /// get the RenderDoc API - /// @return the RenderDoc API - [[nodiscard]] const auto& getRenderDocAPI() const { return this->renderdoc; } -#endif - // Movable, non-copyable, custom destructor - InstanceImpl(const InstanceImpl&) = delete; - InstanceImpl& operator=(const InstanceImpl&) = delete; - InstanceImpl(InstanceImpl&&) = default; - InstanceImpl& operator=(InstanceImpl&&) = default; - ~InstanceImpl(); - private: - vk::Vulkan vk; - ShaderRegistry shaders; - -#ifdef LSFGVK_TESTING_RENDERDOC - std::optional renderdoc; -#endif - }; - - /// context class - class ContextImpl { - public: - /// create a context - /// (see lsfg-vk documentation) - ContextImpl(const InstanceImpl& instance, - std::pair sourceFds, const std::vector& destFds, int syncFd, - VkExtent2D extent, bool hdr, float flow, bool perf); - - /// schedule frames - /// (see lsfg-vk documentation) - void scheduleFrames(); - private: - std::pair sourceImages; - std::vector destImages; - vk::Image blackImage; - - vk::TimelineSemaphore syncSemaphore; // imported - vk::TimelineSemaphore prepassSemaphore; - size_t idx{1}; - size_t fidx{0}; // real frame index - - std::vector cmdbufs; - vk::Fence cmdbufFence; - - Ctx ctx; - - Mipmaps mipmaps; - std::array alpha0; - std::array alpha1; - Beta0 beta0; - Beta1 beta1; - struct Pass { - std::vector gamma0; - std::vector gamma1; - - std::vector delta0; - std::vector delta1; - ls::lazy generate; - }; - std::vector passes; - }; -} - -Instance::Instance( - const DevicePicker& devicePicker, - const std::filesystem::path& shaderDllPath, - bool allowLowPrecision) { - const auto selectFunc = [&devicePicker](const vk::VulkanInstanceFuncs funcs, - const std::vector& devices) { - for (const auto& device : devices) { - // check if the physical device supports VK_EXT_pci_bus_info - uint32_t ext_count{}; - funcs.EnumerateDeviceExtensionProperties(device, nullptr, &ext_count, VK_NULL_HANDLE); - - std::vector extensions(ext_count); - funcs.EnumerateDeviceExtensionProperties(device, nullptr, &ext_count, extensions.data()); - - const bool has_pci_ext = std::ranges::find_if(extensions, - [](const VkExtensionProperties& ext) { - return std::string(std::to_array(ext.extensionName).data()) - == VK_EXT_PCI_BUS_INFO_EXTENSION_NAME; - }) != extensions.end(); - - // then fetch all available properties - VkPhysicalDevicePCIBusInfoPropertiesEXT pciInfo{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT - }; - VkPhysicalDeviceProperties2 props{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, - .pNext = has_pci_ext ? &pciInfo : nullptr - }; - funcs.GetPhysicalDeviceProperties2(device, &props); - - std::array devname = std::to_array(props.properties.deviceName); - devname.at(255) = '\0'; // ensure null-termination - - if (devicePicker( - std::string(devname.data()), - { backend::to_hex_id(props.properties.vendorID), - backend::to_hex_id(props.properties.deviceID) }, - has_pci_ext ? std::optional{ - std::to_string(pciInfo.pciBus) + ":" + - std::to_string(pciInfo.pciDevice) + "." + - std::to_string(pciInfo.pciFunction) - } : std::nullopt - )) - return device; - } - - throw ls::vulkan_error("no suitable physical device found"); - }; - - this->m_impl = std::make_unique( - selectFunc, shaderDllPath, allowLowPrecision - ); -} - -namespace { - /// find the cache file path - std::filesystem::path findCacheFilePath() { - const char* xdgCacheHome = std::getenv("XDG_CACHE_HOME"); - if (xdgCacheHome && *xdgCacheHome != '\0') - return std::filesystem::path(xdgCacheHome) / "lsfg-vk_pipeline_cache.bin"; - - const char* home = std::getenv("HOME"); - if (home && *home != '\0') - return std::filesystem::path(home) / ".cache" / "lsfg-vk_pipeline_cache.bin"; - - return{"/tmp/lsfg-vk_pipeline_cache.bin"}; - } - /// create a Vulkan instance - vk::Vulkan createVulkanInstance(vk::PhysicalDeviceSelector selectPhysicalDevice) { - try { - return{ - "lsfg-vk", vk::version{2, 0, 0}, - "lsfg-vk-engine", vk::version{2, 0, 0}, - selectPhysicalDevice, - false, std::nullopt, - findCacheFilePath() - }; - } catch (const std::exception& e) { - throw backend::error("Unable to initialize Vulkan", e); - } - } - /// build a shader registry - ShaderRegistry createShaderRegistry(vk::Vulkan& vk, - const std::filesystem::path& shaderDllPath, - bool allowLowPrecision) { - std::unordered_map> resources{}; - - try { - resources = backend::extractResourcesFromDLL(shaderDllPath); - } catch (const std::exception& e) { - throw backend::error("Unable to parse Lossless Scaling DLL", e); - } - - try { - return backend::buildShaderRegistry( - vk, allowLowPrecision && vk.supportsFP16(), - resources - ); - } catch (const std::exception& e) { - throw backend::error("Unable to build shader registry", e); - } - } -#ifdef LSFGVK_TESTING_RENDERDOC - /// load RenderDoc integration - std::optional loadRenderDocIntegration() { - void* module = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD); - if (!module) - return std::nullopt; - - auto renderdocGetAPI = reinterpret_cast( - dlsym(module, "RENDERDOC_GetAPI")); - if (!renderdocGetAPI) - return std::nullopt; - - RENDERDOC_API_1_6_0* api{}; - renderdocGetAPI(eRENDERDOC_API_Version_1_6_0, reinterpret_cast(&api)); - if (!api) - return std::nullopt; - - return *api; - } -#endif -} - -InstanceImpl::InstanceImpl(vk::PhysicalDeviceSelector selectPhysicalDevice, - const std::filesystem::path& shaderDllPath, - bool allowLowPrecision) - : vk(createVulkanInstance(selectPhysicalDevice)), - shaders(createShaderRegistry(this->vk, shaderDllPath, - allowLowPrecision && vk.supportsFP16())) { -#ifdef LSFGVK_TESTING_RENDERDOC - this->renderdoc = loadRenderDocIntegration(); -#endif - vk.persistPipelineCache(); // will silently fail -} - -Context& Instance::openContext(std::pair sourceFds, const std::vector& destFds, - int syncFd, uint32_t width, uint32_t height, - bool hdr, float flow, bool perf) { - const VkExtent2D extent{ width, height }; - return *this->m_contexts.emplace_back(std::make_unique(*this->m_impl, - sourceFds, destFds, syncFd, - extent, hdr, flow, perf - )).get(); -} - -namespace { - /// import source images - std::pair importImages(const vk::Vulkan& vk, - const std::pair& sourceFds, - VkExtent2D extent, VkFormat format) { - try { - return { - vk::Image(vk, extent, format, - VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, sourceFds.first), - vk::Image(vk, extent, format, - VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, sourceFds.second) - }; - } catch (const std::exception& e) { - throw backend::error("Unable to import destination images", e); - } - } - /// import destination images - std::vector importImages(const vk::Vulkan& vk, - const std::vector& destFds, - VkExtent2D extent, VkFormat format) { - try { - std::vector destImages; - destImages.reserve(destFds.size()); - - for (const auto& fd : destFds) - destImages.emplace_back(vk, extent, format, - VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, fd); - - return destImages; - } catch (const std::exception& e) { - throw backend::error("Unable to import destination images", e); - } - } - /// create a black image - vk::Image createBlackImage(const vk::Vulkan& vk) { - try { - return{vk, - { .width = 4, .height = 4 } - }; - } catch (const std::exception& e) { - throw backend::error("Unable to create black image", e); - } - } - /// import timeline semaphore - vk::TimelineSemaphore importTimelineSemaphore(const vk::Vulkan& vk, int syncFd) { - try { - return{vk, 0, syncFd}; - } catch (const std::exception& e) { - throw backend::error("Unable to import timeline semaphore", e); - } - } - /// create prepass semaphores - vk::TimelineSemaphore createPrepassSemaphore(const vk::Vulkan& vk) { - try { - return{vk, 0}; - } catch (const std::exception& e) { - throw backend::error("Unable to create prepass semaphore", e); - } - } - /// create command buffers - std::vector createCommandBuffers(const vk::Vulkan& vk, size_t count) { - try { - std::vector cmdbufs; - cmdbufs.reserve(count); - - for (size_t i = 0; i < count; ++i) - cmdbufs.emplace_back(vk); - - return cmdbufs; - } catch (const std::exception& e) { - throw backend::error("Unable to create command buffers", e); - } - } - /// create context data - Ctx createCtx(const InstanceImpl& instance, VkExtent2D extent, - bool hdr, float flow, bool perf, size_t count) { - const auto& vk = instance.getVulkan(); - const auto& shaders = instance.getShaderRegistry(); - - try { - std::vector constantBuffers{}; - constantBuffers.reserve(count); - - for (size_t i = 0; i < count; ++i) - constantBuffers.emplace_back(vk, - backend::getDefaultConstantBuffer( - i, count, - hdr, flow - ) - ); - - return { - .vk = std::ref(vk), - .shaders = std::ref(shaders), - .pool{vk, backend::calculateDescriptorPoolLimits(count, perf)}, - .constantBuffer{vk, backend::getDefaultConstantBuffer(0, 1, hdr, flow)}, - .constantBuffers{std::move(constantBuffers)}, - .bnbSampler{vk, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, false}, - .bnwSampler{vk, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true}, - .eabSampler{vk, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false}, - .sourceExtent = extent, - .flowExtent = VkExtent2D { - .width = static_cast(static_cast(extent.width) / flow), - .height = static_cast(static_cast(extent.height) / flow) - }, - .hdr = hdr, - .flow = flow, - .perf = perf, - .count = count - }; - } catch (const std::exception& e) { - throw backend::error("Unable to create context", e); - } - } -} - -ContextImpl::ContextImpl(const InstanceImpl& instance, - std::pair sourceFds, const std::vector& destFds, int syncFd, - VkExtent2D extent, bool hdr, float flow, bool perf) : - sourceImages(importImages(instance.getVulkan(), sourceFds, - extent, hdr ? VK_FORMAT_R16G16B16A16_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM)), - destImages(importImages(instance.getVulkan(), destFds, - extent, hdr ? VK_FORMAT_R16G16B16A16_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM)), - blackImage(createBlackImage(instance.getVulkan())), - syncSemaphore(importTimelineSemaphore(instance.getVulkan(), syncFd)), - prepassSemaphore(createPrepassSemaphore(instance.getVulkan())), - cmdbufs(createCommandBuffers(instance.getVulkan(), destFds.size() + 1)), - cmdbufFence(instance.getVulkan()), - ctx(createCtx(instance, extent, hdr, flow, perf, destFds.size())), - mipmaps(ctx, sourceImages), - alpha0{ - Alpha0(ctx, mipmaps.getImages().at(0)), - Alpha0(ctx, mipmaps.getImages().at(1)), - Alpha0(ctx, mipmaps.getImages().at(2)), - Alpha0(ctx, mipmaps.getImages().at(3)), - Alpha0(ctx, mipmaps.getImages().at(4)), - Alpha0(ctx, mipmaps.getImages().at(5)), - Alpha0(ctx, mipmaps.getImages().at(6)) - }, - alpha1{ - Alpha1(ctx, 3, alpha0.at(0).getImages()), - Alpha1(ctx, 2, alpha0.at(1).getImages()), - Alpha1(ctx, 2, alpha0.at(2).getImages()), - Alpha1(ctx, 2, alpha0.at(3).getImages()), - Alpha1(ctx, 2, alpha0.at(4).getImages()), - Alpha1(ctx, 2, alpha0.at(5).getImages()), - Alpha1(ctx, 2, alpha0.at(6).getImages()) - }, - beta0(ctx, alpha1.at(0).getImages()), - beta1(ctx, beta0.getImages()) { - // build main passes - for (size_t i = 0; i < destImages.size(); ++i) { - auto& pass = this->passes.emplace_back(); - - pass.gamma0.reserve(7); - pass.gamma1.reserve(7); - pass.delta0.reserve(3); - pass.delta1.reserve(3); - for (size_t j = 0; j < 7; j++) { - if (j == 0) { // first pass has no prior data - pass.gamma0.emplace_back(ctx, i, - this->alpha1.at(6 - j).getImages(), - this->blackImage - ); - pass.gamma1.emplace_back(ctx, i, - pass.gamma0.at(j).getImages(), - this->blackImage, - this->beta1.getImages().at(5) - ); - } else { // other passes use prior data - pass.gamma0.emplace_back(ctx, i, - this->alpha1.at(6 - j).getImages(), - pass.gamma1.at(j - 1).getImage() - ); - pass.gamma1.emplace_back(ctx, i, - pass.gamma0.at(j).getImages(), - pass.gamma1.at(j - 1).getImage(), - this->beta1.getImages().at(6 - j) - ); - } - - if (j == 4) { // first special pass has no prior data - pass.delta0.emplace_back(ctx, i, - this->alpha1.at(6 - j).getImages(), - this->blackImage, - pass.gamma1.at(j - 1).getImage() - ); - pass.delta1.emplace_back(ctx, i, - pass.delta0.at(j - 4).getImages0(), - pass.delta0.at(j - 4).getImages1(), - this->blackImage, - this->beta1.getImages().at(6 - j), - this->blackImage - ); - } else if (j > 4) { // further passes do - pass.delta0.emplace_back(ctx, i, - this->alpha1.at(6 - j).getImages(), - pass.delta1.at(j - 5).getImage0(), - pass.gamma1.at(j - 1).getImage() - ); - pass.delta1.emplace_back(ctx, i, - pass.delta0.at(j - 4).getImages0(), - pass.delta0.at(j - 4).getImages1(), - pass.delta1.at(j - 5).getImage0(), - this->beta1.getImages().at(6 - j), - pass.delta1.at(j - 5).getImage1() - ); - } - } - - pass.generate.emplace(ctx, i, - this->sourceImages, - pass.gamma1.at(6).getImage(), - pass.delta1.at(2).getImage0(), - pass.delta1.at(2).getImage1(), - this->destImages.at(i) - ); - } - - // initialize all images - std::vector images{}; - images.push_back(this->blackImage.handle()); - mipmaps.prepare(images); - for (size_t i = 0; i < 7; ++i) { - alpha0.at(i).prepare(images); - alpha1.at(i).prepare(images); - } - beta0.prepare(images); - beta1.prepare(images); - for (const auto& pass : this->passes) { - for (size_t i = 0; i < 7; ++i) { - pass.gamma0.at(i).prepare(images); - pass.gamma1.at(i).prepare(images); - - if (i < 4) continue; - pass.delta0.at(i - 4).prepare(images); - pass.delta1.at(i - 4).prepare(images); - } - } - - std::vector barriers{}; - barriers.reserve(images.size()); - - for (const auto& image : images) { - barriers.emplace_back(vk::Barrier { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .newLayout = VK_IMAGE_LAYOUT_GENERAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = image, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = 1, - .layerCount = 1 - } - }); - } - - const vk::CommandBuffer cmdbuf{ctx.vk}; - cmdbuf.begin(ctx.vk); - cmdbuf.insertBarriers(ctx.vk, barriers); - cmdbuf.end(ctx.vk); - cmdbuf.submit(ctx.vk); // wait for completion -} - -void Instance::scheduleFrames(Context& context) { // NOLINT (static) -#ifdef LSFGVK_TESTING_RENDERDOC - const auto& impl = this->m_impl; - if (impl->getRenderDocAPI()) { - impl->getRenderDocAPI()->StartFrameCapture( - RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(impl->getVulkan().inst()), - nullptr); - } -#endif - try { - context.scheduleFrames(); - } catch (const std::exception& e) { - throw backend::error("Unable to schedule frames", e); - } -#ifdef LSFGVK_TESTING_RENDERDOC - if (impl->getRenderDocAPI()) { - impl->getVulkan().df().DeviceWaitIdle(impl->getVulkan().dev()); - impl->getRenderDocAPI()->EndFrameCapture( - RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(impl->getVulkan().inst()), - nullptr); - } -#endif -} - -void Context::scheduleFrames() { - // wait for previous pre-pass to complete - if (this->fidx && !this->cmdbufFence.wait(this->ctx.vk)) - throw backend::error("Timeout waiting for previous frame to complete"); - this->cmdbufFence.reset(this->ctx.vk); - - // schedule pre-pass - const auto& cmdbuf = this->cmdbufs.at(0); - cmdbuf.begin(ctx.vk); - - this->mipmaps.render(ctx.vk, cmdbuf, this->fidx); - for (size_t i = 0; i < 7; ++i) { - this->alpha0.at(6 - i).render(ctx.vk, cmdbuf); - this->alpha1.at(6 - i).render(ctx.vk, cmdbuf, this->fidx); - } - this->beta0.render(ctx.vk, cmdbuf, this->fidx); - this->beta1.render(ctx.vk, cmdbuf); - - cmdbuf.end(ctx.vk); - cmdbuf.submit(this->ctx.vk, - {}, this->syncSemaphore.handle(), this->idx, - {}, this->prepassSemaphore.handle(), this->idx - ); - - this->idx++; - - // schedule main passes - for (size_t i = 0; i < this->destImages.size(); i++) { - const auto& cmdbuf = this->cmdbufs.at(i + 1); - cmdbuf.begin(ctx.vk); - - const auto& pass = this->passes.at(i); - for (size_t j = 0; j < 7; j++) { - pass.gamma0.at(j).render(ctx.vk, cmdbuf, this->fidx); - pass.gamma1.at(j).render(ctx.vk, cmdbuf); - - if (j < 4) continue; - pass.delta0.at(j - 4).render(ctx.vk, cmdbuf, this->fidx); - pass.delta1.at(j - 4).render(ctx.vk, cmdbuf); - } - pass.generate->render(ctx.vk, cmdbuf, this->fidx); - - cmdbuf.end(ctx.vk); - cmdbuf.submit(this->ctx.vk, - {}, this->prepassSemaphore.handle(), this->idx - 1, - {}, this->syncSemaphore.handle(), this->idx + i, - i == this->destImages.size() - 1 ? this->cmdbufFence.handle() : VK_NULL_HANDLE - ); - } - - this->idx += this->destImages.size(); - this->fidx++; -} - -void Instance::closeContext(const Context& context) { - auto it = std::ranges::find_if(this->m_contexts, - [context = &context](const std::unique_ptr& ctx) { - return ctx.get() == context; - }); - if (it == this->m_contexts.end()) - throw backend::error("attempted to close unknown context", - std::runtime_error("no such context")); - - const auto& vk = this->m_impl->getVulkan(); - vk.df().DeviceWaitIdle(vk.dev()); - - this->m_contexts.erase(it); -} - -Instance::~Instance() = default; - -// leaking shenanigans - -namespace { - bool leaking{false}; // NOLINT (global variable) -} - -InstanceImpl::~InstanceImpl() { - if (!leaking) return; - - try { - new vk::Vulkan(std::move(this->vk)); - } catch (...) { - std::cerr << "lsfg-vk: failed to leak Vulkan instance\n"; - } - -} - -void backend::makeLeaking() { - leaking = true; -} +/* TODO */ diff --git a/lsfg-vk-backend/src/shaderchains/alpha0.cpp b/lsfg-vk-backend/src/shaderchains/alpha0.cpp deleted file mode 100644 index c8229c2..0000000 --- a/lsfg-vk-backend/src/shaderchains/alpha0.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include - -#include - -using namespace lsfgvk::backend; - -Alpha0::Alpha0(const Ctx& ctx, - const vk::Image& sourceImage) { - const size_t m = ctx.perf ? 1 : 2; // multiplier - const VkExtent2D halfExtent = backend::add_shift_extent(sourceImage.getExtent(), 1, 1); - const VkExtent2D quarterExtent = backend::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(ManagedShaderBuilder() - .sampled(sourceImage) - .storages(this->tempImages0) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.alpha.at(0))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages0) - .storages(this->tempImages1) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.alpha.at(1))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages1) - .storages(this->images) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.alpha.at(2))); - - // store dispatch extents - this->dispatchExtent0 = backend::add_shift_extent(halfExtent, 7, 3); - this->dispatchExtent1 = backend::add_shift_extent(quarterExtent, 7, 3); -} - -void Alpha0::prepare(std::vector& images) const { - for (size_t i = 0; i < this->tempImages0.size(); i++) { - images.push_back(this->tempImages0.at(i).handle()); - images.push_back(this->tempImages1.at(i).handle()); - } - - for (const auto& image : this->images) - images.push_back(image.handle()); -} - -void Alpha0::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd) const { - this->sets.at(0).dispatch(vk, cmd, this->dispatchExtent0); - this->sets.at(1).dispatch(vk, cmd, this->dispatchExtent0); - this->sets.at(2).dispatch(vk, cmd, this->dispatchExtent1); -} diff --git a/lsfg-vk-backend/src/shaderchains/alpha0.hpp b/lsfg-vk-backend/src/shaderchains/alpha0.hpp deleted file mode 100644 index 5d48962..0000000 --- a/lsfg-vk-backend/src/shaderchains/alpha0.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// pre-alpha shaderchain - class Alpha0 { - public: - /// create a pre-alpha shaderchain - /// @param ctx context - /// @param sourceImage source image - Alpha0(const Ctx& ctx, - const vk::Image& sourceImage); - - /// prepare the shaderchain initially - /// @param images vector to fill with image handles - void prepare(std::vector& images) const; - - /// render the pre-alpha shaderchain - /// @param vk the vulkan instance - /// @param cmd command buffer - void render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd) const; - - /// get the generated images - /// @return vector of images - [[nodiscard]] const auto& getImages() const { return this->images; } - private: - std::vector tempImages0; - std::vector tempImages1; - std::vector images; - - std::vector sets; - VkExtent2D dispatchExtent0{}; - VkExtent2D dispatchExtent1{}; - }; -} diff --git a/lsfg-vk-backend/src/shaderchains/alpha1.cpp b/lsfg-vk-backend/src/shaderchains/alpha1.cpp deleted file mode 100644 index 34bebf0..0000000 --- a/lsfg-vk-backend/src/shaderchains/alpha1.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include - -#include - -using namespace lsfgvk::backend; - -Alpha1::Alpha1(const Ctx& ctx, size_t temporal, - const std::vector& 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(temporal); - for(size_t i = 0; i < temporal; 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(temporal); - for (size_t i = 0; i < temporal; i++) - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(sourceImages) - .storages(this->images.at(i)) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.alpha.at(3))); - - // store dispatch extents - this->dispatchExtent = backend::add_shift_extent(quarterExtent, 7, 3); -} - -void Alpha1::prepare(std::vector& images) const { - for (const auto& vec : this->images) - for (const auto& img : vec) - images.push_back(img.handle()); -} - -void Alpha1::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd, size_t idx) const { - this->sets.at(idx % this->sets.size()).dispatch(vk, cmd, dispatchExtent); -} diff --git a/lsfg-vk-backend/src/shaderchains/alpha1.hpp b/lsfg-vk-backend/src/shaderchains/alpha1.hpp deleted file mode 100644 index 47073e8..0000000 --- a/lsfg-vk-backend/src/shaderchains/alpha1.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// alpha shaderchain - class Alpha1 { - public: - /// create a alpha shaderchain - /// @param ctx context - /// @param temporal temporal count - /// @param sourceImages source images - Alpha1(const Ctx& ctx, size_t temporal, - const std::vector& sourceImages); - - /// prepare the shaderchain initially - /// @param images vector to fill with image handles - void prepare(std::vector& images) const; - - /// render the alpha shaderchain - /// @param vk the vulkan instance - /// @param cmd command buffer - /// @param idx frame index - void render(const vk::Vulkan& vk, 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> images; - - std::vector sets; - VkExtent2D dispatchExtent{}; - }; -} diff --git a/lsfg-vk-backend/src/shaderchains/beta0.cpp b/lsfg-vk-backend/src/shaderchains/beta0.cpp deleted file mode 100644 index 300cef2..0000000 --- a/lsfg-vk-backend/src/shaderchains/beta0.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include - -#include - -using namespace lsfgvk::backend; - -Beta0::Beta0(const Ctx& ctx, - const std::vector>& 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(sourceImages.size()); - for (size_t i = 0; i < sourceImages.size(); i++) - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(sourceImages.at((i + (sourceImages.size() - 2)) % sourceImages.size())) - .sampleds(sourceImages.at((i + (sourceImages.size() - 1)) % sourceImages.size())) - .sampleds(sourceImages.at(i % sourceImages.size())) - .storages(this->images) - .sampler(ctx.bnwSampler) - .build(ctx.vk, ctx.pool, shader)); - - // store dispatch extents - this->dispatchExtent = backend::add_shift_extent(extent, 7, 3); -} - -void Beta0::prepare(std::vector& images) const { - for (const auto& img : this->images) - images.push_back(img.handle()); -} - -void Beta0::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd, size_t idx) const { - this->sets.at(idx % this->sets.size()).dispatch(vk, cmd, dispatchExtent); -} diff --git a/lsfg-vk-backend/src/shaderchains/beta0.hpp b/lsfg-vk-backend/src/shaderchains/beta0.hpp deleted file mode 100644 index fcd9af7..0000000 --- a/lsfg-vk-backend/src/shaderchains/beta0.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// beta shaderchain - class Beta0 { - public: - /// create a beta shaderchain - /// @param ctx context - /// @param sourceImages source images - Beta0(const Ctx& ctx, - const std::vector>& sourceImages); - - /// prepare the shaderchain initially - /// @param images vector to fill with image handles - void prepare(std::vector& images) const; - - /// render the beta shaderchain - /// @param vk vulkan instance - /// @param cmd command buffer - /// @param idx frame index - void render(const vk::Vulkan& vk, 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 images; - - std::vector sets; - VkExtent2D dispatchExtent{}; - }; -} diff --git a/lsfg-vk-backend/src/shaderchains/beta1.cpp b/lsfg-vk-backend/src/shaderchains/beta1.cpp deleted file mode 100644 index 2499656..0000000 --- a/lsfg-vk-backend/src/shaderchains/beta1.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include -#include - -#include - -using namespace lsfgvk::backend; - -Beta1::Beta1(const Ctx& ctx, - const std::vector& 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, - backend::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(ManagedShaderBuilder() - .sampleds(sourceImages) - .storages(this->tempImages0) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(1))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages0) - .storages(this->tempImages1) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(2))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages1) - .storages(this->tempImages0) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(3))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages0) - .storages(this->images) - .sampler(ctx.bnbSampler) - .buffer(ctx.constantBuffer) - .build(ctx.vk, ctx.pool, shaders.at(4))); - - // store dispatch extents - this->dispatchExtent0 = backend::add_shift_extent(extent, 7, 3); - this->dispatchExtent1 = backend::add_shift_extent(extent, 31, 5); -} - -void Beta1::prepare(std::vector& images) const { - for (size_t i = 0; i < 2; i++) { - images.push_back(this->tempImages0.at(i).handle()); - images.push_back(this->tempImages1.at(i).handle()); - } - for (const auto& img : this->images) - images.push_back(img.handle()); -} - -void Beta1::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd) const { - this->sets.at(0).dispatch(vk, cmd, this->dispatchExtent0); - this->sets.at(1).dispatch(vk, cmd, this->dispatchExtent0); - this->sets.at(2).dispatch(vk, cmd, this->dispatchExtent0); - this->sets.at(3).dispatch(vk, cmd, this->dispatchExtent1); -} diff --git a/lsfg-vk-backend/src/shaderchains/beta1.hpp b/lsfg-vk-backend/src/shaderchains/beta1.hpp deleted file mode 100644 index ea27918..0000000 --- a/lsfg-vk-backend/src/shaderchains/beta1.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// beta shaderchain - class Beta1 { - public: - /// create a beta shaderchain - /// @param ctx context - /// @param sourceImages source images - Beta1(const Ctx& ctx, - const std::vector& sourceImages); - - /// prepare the shaderchain initially - /// @param images vector to fill with image handles - void prepare(std::vector& images) const; - - /// render the beta shaderchain - /// @param vk the vulkan instance - /// @param cmd command buffer - void render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd) const; - - /// get the generated images - /// @return vector of images - [[nodiscard]] const auto& getImages() const { return this->images; } - private: - std::vector tempImages0; - std::vector tempImages1; - std::vector images; - - std::vector sets; - VkExtent2D dispatchExtent0{}; - VkExtent2D dispatchExtent1{}; - }; -} diff --git a/lsfg-vk-backend/src/shaderchains/delta0.cpp b/lsfg-vk-backend/src/shaderchains/delta0.cpp deleted file mode 100644 index 8a5c34b..0000000 --- a/lsfg-vk-backend/src/shaderchains/delta0.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "delta0.hpp" -#include "../helpers/utils.hpp" -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/image.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include - -#include - -using namespace lsfgvk::backend; - -Delta0::Delta0(const Ctx& ctx, size_t idx, - const std::vector>& sourceImages, - const vk::Image& additionalInput0, - const vk::Image& additionalInput1) { - const size_t m = ctx.perf ? 1 : 2; // multiplier - const VkExtent2D extent = sourceImages.at(0).at(0).getExtent(); - - // create output images - this->images0.reserve(3); - for(size_t i = 0; i < 3; i++) - this->images0.emplace_back(ctx.vk, extent); - this->images1.reserve(m); - for (size_t i = 0; i < m; i++) - this->images1.emplace_back(ctx.vk, extent); - - // create descriptor sets - const auto& shaders = (ctx.perf ? - ctx.shaders.get().performance : ctx.shaders.get().quality).delta; - - this->sets0.reserve(sourceImages.size()); - for (size_t i = 0; i < sourceImages.size(); i++) - this->sets0.emplace_back(ManagedShaderBuilder() - .sampleds(sourceImages.at((i + (sourceImages.size() - 1)) % sourceImages.size())) - .sampleds(sourceImages.at(i % sourceImages.size())) - .sampled(additionalInput0) - .storages(this->images0) - .sampler(ctx.bnwSampler) - .sampler(ctx.eabSampler) - .buffer(ctx.constantBuffers.at(idx)) - .build(ctx.vk, ctx.pool, shaders.at(0))); - - this->sets1.reserve(sourceImages.size()); - for (size_t i = 0; i < sourceImages.size(); i++) - this->sets1.emplace_back(ManagedShaderBuilder() - .sampleds(sourceImages.at((i + (sourceImages.size() - 1)) % sourceImages.size())) - .sampleds(sourceImages.at(i % sourceImages.size())) - .sampled(additionalInput1) - .sampled(additionalInput0) - .storages(this->images1) - .sampler(ctx.bnwSampler) - .sampler(ctx.eabSampler) - .buffer(ctx.constantBuffers.at(idx)) - .build(ctx.vk, ctx.pool, shaders.at(5))); - - // store dispatch extents - this->dispatchExtent = backend::add_shift_extent(extent, 7, 3); -} - -void Delta0::prepare(std::vector& images) const { - for (const auto& img : this->images0) - images.push_back(img.handle()); - for (const auto& img : this->images1) - images.push_back(img.handle()); -} - -void Delta0::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd, size_t idx) const { - this->sets0.at(idx % this->sets0.size()).dispatch(vk, cmd, dispatchExtent); - this->sets1.at(idx % this->sets1.size()).dispatch(vk, cmd, dispatchExtent); -} diff --git a/lsfg-vk-backend/src/shaderchains/delta0.hpp b/lsfg-vk-backend/src/shaderchains/delta0.hpp deleted file mode 100644 index 4c66780..0000000 --- a/lsfg-vk-backend/src/shaderchains/delta0.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// delta shaderchain - class Delta0 { - public: - /// create a delta shaderchain - /// @param ctx context - /// @param idx generated frame index - /// @param sourceImages source images - /// @param additionalInput0 additional input image - /// @param additionalInput1 additional input image - Delta0(const Ctx& ctx, size_t idx, - const std::vector>& sourceImages, - const vk::Image& additionalInput0, - const vk::Image& additionalInput1); - - /// prepare the shaderchain initially - /// @param images vector to fill with image handles - void prepare(std::vector& images) const; - - /// render the delta shaderchain - /// @param vk the vulkan instance - /// @param cmd command buffer - /// @param idx frame index - void render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd, size_t idx) const; - - /// get the generated images - /// @return vector of images - [[nodiscard]] const auto& getImages0() const { return this->images0; } - - /// get the other generated images - /// @return vector of images - [[nodiscard]] const auto& getImages1() const { return this->images1; } - private: - std::vector images0; - std::vector images1; - - std::vector sets0; - std::vector sets1; - VkExtent2D dispatchExtent{}; - }; -} diff --git a/lsfg-vk-backend/src/shaderchains/delta1.cpp b/lsfg-vk-backend/src/shaderchains/delta1.cpp deleted file mode 100644 index 7c81902..0000000 --- a/lsfg-vk-backend/src/shaderchains/delta1.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "delta1.hpp" -#include "../helpers/utils.hpp" -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/image.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include - -#include - -using namespace lsfgvk::backend; - -Delta1::Delta1(const Ctx& ctx, size_t idx, - const std::vector& sourceImages0, - const std::vector& sourceImages1, - const vk::Image& additionalInput0, - const vk::Image& additionalInput1, - const vk::Image& additionalInput2) { - const size_t m = ctx.perf ? 1 : 2; // multiplier - const VkExtent2D extent = sourceImages0.at(0).getExtent(); - - // create temporary & output images - for (size_t i = 0; i < (2 * m); i++) { - this->tempImages0.emplace_back(ctx.vk, extent); - this->tempImages1.emplace_back(ctx.vk, extent); - } - this->image0.emplace(ctx.vk, - VkExtent2D { extent.width, extent.height }, - VK_FORMAT_R16G16B16A16_SFLOAT - ); - this->image1.emplace(ctx.vk, - VkExtent2D { extent.width, extent.height }, - VK_FORMAT_R16G16B16A16_SFLOAT - ); - - // create descriptor sets - const auto& shaders = (ctx.perf ? - ctx.shaders.get().performance : ctx.shaders.get().quality).delta; - this->sets.reserve(4 + 4); - - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(sourceImages0) - .storages(this->tempImages0) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(1))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages0) - .storages(this->tempImages1) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(2))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages1) - .storages(this->tempImages0) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(3))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages0) - .sampled(additionalInput0) - .sampled(additionalInput1) - .storage(*this->image0) - .sampler(ctx.bnbSampler) - .sampler(ctx.eabSampler) - .buffer(ctx.constantBuffers.at(idx)) - .build(ctx.vk, ctx.pool, shaders.at(4))); - - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(sourceImages1) - .storages(this->tempImages0, 0, m) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(6))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages0, 0, m) - .storages(this->tempImages1, 0, m) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(7))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages1, 0, m) - .storages(this->tempImages0, 0, m) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(8))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages0, 0, m) - .sampled(additionalInput2) - .storage(*this->image1) - .sampler(ctx.bnbSampler) - .sampler(ctx.eabSampler) - .buffer(ctx.constantBuffers.at(idx)) - .build(ctx.vk, ctx.pool, shaders.at(9))); - - // store dispatch extents - this->dispatchExtent = backend::add_shift_extent(extent, 7, 3); -} - -void Delta1::prepare(std::vector& images) const { - for (size_t i = 0; i < this->tempImages0.size(); i++) { - images.push_back(this->tempImages0.at(i).handle()); - images.push_back(this->tempImages1.at(i).handle()); - } - images.push_back(this->image0->handle()); - images.push_back(this->image1->handle()); -} - -void Delta1::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd) const { - for (const auto& set : this->sets) - set.dispatch(vk, cmd, dispatchExtent); -} diff --git a/lsfg-vk-backend/src/shaderchains/delta1.hpp b/lsfg-vk-backend/src/shaderchains/delta1.hpp deleted file mode 100644 index 716df09..0000000 --- a/lsfg-vk-backend/src/shaderchains/delta1.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#pragma once - -#include "../helpers/managed_shader.hpp" -#include "../helpers/utils.hpp" -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/image.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// gamma shaderchain - class Delta1 { - public: - /// create a gamma shaderchain - /// @param ctx context - /// @param idx generated frame index - /// @param sourceImages0 source images - /// @param sourceImages1 source images - /// @param additionalInput0 additional input image - /// @param additionalInput1 additional input image - /// @param additionalInput2 additional input image - Delta1(const Ctx& ctx, size_t idx, - const std::vector& sourceImages0, - const std::vector& sourceImages1, - const vk::Image& additionalInput0, - const vk::Image& additionalInput1, - const vk::Image& additionalInput2); - - /// prepare the shaderchain initially - /// @param images vector to fill with image handles - void prepare(std::vector& images) const; - - /// render the gamma shaderchain - /// @param vk the vulkan instance - /// @param cmd command buffer - void render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd) const; - - /// get the first generated image - /// @return image - [[nodiscard]] const auto& getImage0() const { return *this->image0; } - - /// get the second generated image - /// @return image - [[nodiscard]] const auto& getImage1() const { return *this->image1; } - private: - std::vector tempImages0; - std::vector tempImages1; - ls::lazy image0; - ls::lazy image1; - - std::vector sets; - VkExtent2D dispatchExtent{}; - }; -} diff --git a/lsfg-vk-backend/src/shaderchains/gamma0.cpp b/lsfg-vk-backend/src/shaderchains/gamma0.cpp deleted file mode 100644 index df10fb8..0000000 --- a/lsfg-vk-backend/src/shaderchains/gamma0.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "gamma0.hpp" -#include "../helpers/utils.hpp" -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/image.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include - -#include - -using namespace lsfgvk::backend; - -Gamma0::Gamma0(const Ctx& ctx, size_t idx, - const std::vector>& sourceImages, - const vk::Image& additionalInput) { - const VkExtent2D extent = sourceImages.at(0).at(0).getExtent(); - - // create output images - this->images.reserve(3); - for(size_t i = 0; i < 3; i++) - this->images.emplace_back(ctx.vk, extent); - - // create descriptor sets - const auto& shader = (ctx.perf ? - ctx.shaders.get().performance : ctx.shaders.get().quality).gamma.at(0); - this->sets.reserve(sourceImages.size()); - for (size_t i = 0; i < sourceImages.size(); i++) - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(sourceImages.at((i + (sourceImages.size() - 1)) % sourceImages.size())) - .sampleds(sourceImages.at(i % sourceImages.size())) - .sampled(additionalInput) - .storages(this->images) - .sampler(ctx.bnwSampler) - .sampler(ctx.eabSampler) - .buffer(ctx.constantBuffers.at(idx)) - .build(ctx.vk, ctx.pool, shader)); - - // store dispatch extents - this->dispatchExtent = backend::add_shift_extent(extent, 7, 3); -} - -void Gamma0::prepare(std::vector& images) const { - for (const auto& img : this->images) - images.push_back(img.handle()); -} - -void Gamma0::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd, size_t idx) const { - this->sets.at(idx % this->sets.size()).dispatch(vk, cmd, dispatchExtent); -} diff --git a/lsfg-vk-backend/src/shaderchains/gamma0.hpp b/lsfg-vk-backend/src/shaderchains/gamma0.hpp deleted file mode 100644 index 87e9813..0000000 --- a/lsfg-vk-backend/src/shaderchains/gamma0.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// gamma shaderchain - class Gamma0 { - public: - /// create a gamma shaderchain - /// @param ctx context - /// @param idx generated frame index - /// @param sourceImages source images - /// @param additionalInput additional input image - Gamma0(const Ctx& ctx, size_t idx, - const std::vector>& sourceImages, - const vk::Image& additionalInput); - - /// prepare the shaderchain initially - /// @param images vector to fill with image handles - void prepare(std::vector& images) const; - - /// render the gamma shaderchain - /// @param vk the vulkan instance - /// @param cmd command buffer - /// @param idx frame index - void render(const vk::Vulkan& vk, 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 images; - - std::vector sets; - VkExtent2D dispatchExtent{}; - }; -} diff --git a/lsfg-vk-backend/src/shaderchains/gamma1.cpp b/lsfg-vk-backend/src/shaderchains/gamma1.cpp deleted file mode 100644 index 2a7e90f..0000000 --- a/lsfg-vk-backend/src/shaderchains/gamma1.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "gamma1.hpp" -#include "../helpers/utils.hpp" -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/image.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include - -#include - -using namespace lsfgvk::backend; - -Gamma1::Gamma1(const Ctx& ctx, size_t idx, - const std::vector& sourceImages, - const vk::Image& additionalInput0, - const vk::Image& additionalInput1) { - const size_t m = ctx.perf ? 1 : 2; // multiplier - const VkExtent2D extent = sourceImages.at(0).getExtent(); - - // create temporary & output images - for (size_t i = 0; i < (2 * m); i++) { - this->tempImages0.emplace_back(ctx.vk, extent); - this->tempImages1.emplace_back(ctx.vk, extent); - } - this->image.emplace(ctx.vk, - VkExtent2D { extent.width, extent.height }, - VK_FORMAT_R16G16B16A16_SFLOAT - ); - - // create descriptor sets - const auto& shaders = (ctx.perf ? - ctx.shaders.get().performance : ctx.shaders.get().quality).gamma; - this->sets.reserve(4); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(sourceImages) - .storages(this->tempImages0) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(1))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages0) - .storages(this->tempImages1) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(2))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages1) - .storages(this->tempImages0) - .sampler(ctx.bnbSampler) - .build(ctx.vk, ctx.pool, shaders.at(3))); - this->sets.emplace_back(ManagedShaderBuilder() - .sampleds(this->tempImages0) - .sampled(additionalInput0) - .sampled(additionalInput1) - .storage(*this->image) - .sampler(ctx.bnbSampler) - .sampler(ctx.eabSampler) - .buffer(ctx.constantBuffers.at(idx)) - .build(ctx.vk, ctx.pool, shaders.at(4))); - - // store dispatch extents - this->dispatchExtent = backend::add_shift_extent(extent, 7, 3); -} - -void Gamma1::prepare(std::vector& images) const { - for (size_t i = 0; i < this->tempImages0.size(); i++) { - images.push_back(this->tempImages0.at(i).handle()); - images.push_back(this->tempImages1.at(i).handle()); - } - images.push_back(this->image->handle()); -} - -void Gamma1::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd) const { - for (const auto& set : this->sets) - set.dispatch(vk, cmd, dispatchExtent); -} diff --git a/lsfg-vk-backend/src/shaderchains/gamma1.hpp b/lsfg-vk-backend/src/shaderchains/gamma1.hpp deleted file mode 100644 index 2104cc7..0000000 --- a/lsfg-vk-backend/src/shaderchains/gamma1.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#pragma once - -#include "../helpers/managed_shader.hpp" -#include "../helpers/utils.hpp" -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/image.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// gamma shaderchain - class Gamma1 { - public: - /// create a gamma shaderchain - /// @param ctx context - /// @param idx generated frame index - /// @param sourceImages source images - /// @param additionalInput0 additional input image - /// @param additionalInput1 additional input image - Gamma1(const Ctx& ctx, size_t idx, - const std::vector& sourceImages, - const vk::Image& additionalInput0, - const vk::Image& additionalInput1); - - /// prepare the shaderchain initially - /// @param images vector to fill with image handles - void prepare(std::vector& images) const; - - /// render the gamma shaderchain - /// @param vk the vulkan instance - /// @param cmd command buffer - void render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd) const; - - /// get the generated image - /// @return image - [[nodiscard]] const auto& getImage() const { return *this->image; } - private: - std::vector tempImages0; - std::vector tempImages1; - ls::lazy image; - - std::vector sets; - VkExtent2D dispatchExtent{}; - }; -} diff --git a/lsfg-vk-backend/src/shaderchains/generate.cpp b/lsfg-vk-backend/src/shaderchains/generate.cpp deleted file mode 100644 index 2375ccf..0000000 --- a/lsfg-vk-backend/src/shaderchains/generate.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "generate.hpp" -#include "../helpers/utils.hpp" -#include "lsfg-vk-common/helpers/pointers.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/image.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include -#include - -#include - -using namespace lsfgvk::backend; - -Generate::Generate(const Ctx& ctx, size_t idx, - const std::pair& sourceImages, - const vk::Image& inputImage1, - const vk::Image& inputImage2, - const vk::Image& inputImage3, - const vk::Image& outputImage) { - // create descriptor sets - const auto& shader = ctx.hdr ? - ctx.shaders.get().generate_hdr : ctx.shaders.get().generate; - this->sets.reserve(2); - this->sets.emplace_back(ManagedShaderBuilder() - .sampled(sourceImages.second) - .sampled(sourceImages.first) - .sampled(inputImage1) - .sampled(inputImage2) - .sampled(inputImage3) - .storage(outputImage) - .sampler(ctx.bnbSampler) - .sampler(ctx.eabSampler) - .buffer(ctx.constantBuffers.at(idx)) - .build(ctx.vk, ctx.pool, shader)); - this->sets.emplace_back(ManagedShaderBuilder() - .sampled(sourceImages.first) - .sampled(sourceImages.second) - .sampled(inputImage1) - .sampled(inputImage2) - .sampled(inputImage3) - .storage(outputImage) - .sampler(ctx.bnbSampler) - .sampler(ctx.eabSampler) - .buffer(ctx.constantBuffers.at(idx)) - .build(ctx.vk, ctx.pool, shader)); - - // store dispatch extent - this->dispatchExtent = backend::add_shift_extent(ctx.sourceExtent, 15, 4); -} - -void Generate::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd, size_t idx) const { - this->sets.at(idx % 2).dispatch(vk, cmd, this->dispatchExtent); -} diff --git a/lsfg-vk-backend/src/shaderchains/generate.hpp b/lsfg-vk-backend/src/shaderchains/generate.hpp deleted file mode 100644 index 5e0b349..0000000 --- a/lsfg-vk-backend/src/shaderchains/generate.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// generate shaderchain - class Generate { - public: - /// create a generate shaderchain - /// @param ctx context - /// @param idx generated frame index - /// @param sourceImages pair of source images - /// @param inputImage1 input image 1 - /// @param inputImage2 input image 2 - /// @param inputImage3 input image 3 - Generate(const Ctx& ctx, size_t idx, - const std::pair& sourceImages, - const vk::Image& inputImage1, - const vk::Image& inputImage2, - const vk::Image& inputImage3, - const vk::Image& outputImage); - - /// render the generate shaderchain - /// @param vk the vulkan instance - /// @param cmd command buffer - /// @param idx frame index - void render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd, size_t idx) const; - private: - std::vector sets; - VkExtent2D dispatchExtent{}; - }; -} diff --git a/lsfg-vk-backend/src/shaderchains/mipmaps.cpp b/lsfg-vk-backend/src/shaderchains/mipmaps.cpp deleted file mode 100644 index 2f04669..0000000 --- a/lsfg-vk-backend/src/shaderchains/mipmaps.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include -#include -#include - -#include - -using namespace lsfgvk::backend; - -Mipmaps::Mipmaps(const Ctx& ctx, - const std::pair& 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, - backend::shift_extent(ctx.flowExtent, i), VK_FORMAT_R8_UNORM); - - // create descriptor sets for both input images - this->sets.reserve(2); - this->sets.emplace_back(ManagedShaderBuilder() - .sampled(sourceImages.first) - .storages(this->images) - .sampler(ctx.bnbSampler) - .buffer(ctx.constantBuffer) - .build(ctx.vk, ctx.pool, ctx.shaders.get().mipmaps)); - this->sets.emplace_back(ManagedShaderBuilder() - .sampled(sourceImages.second) - .storages(this->images) - .sampler(ctx.bnbSampler) - .buffer(ctx.constantBuffer) - .build(ctx.vk, ctx.pool, ctx.shaders.get().mipmaps)); - - // store dispatch extent - this->dispatchExtent = backend::add_shift_extent(ctx.flowExtent, 63, 6); -} - -void Mipmaps::prepare(std::vector& images) const { - for (const auto& img : this->images) - images.push_back(img.handle()); -} - -void Mipmaps::render(const vk::Vulkan& vk, const vk::CommandBuffer& cmd, size_t idx) const { - this->sets.at(idx % 2).dispatch(vk, cmd, this->dispatchExtent); -} diff --git a/lsfg-vk-backend/src/shaderchains/mipmaps.hpp b/lsfg-vk-backend/src/shaderchains/mipmaps.hpp deleted file mode 100644 index 8c1f6a2..0000000 --- a/lsfg-vk-backend/src/shaderchains/mipmaps.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include - -#include - -namespace ctx { struct Ctx; } - -namespace lsfgvk::backend { - /// mipmaps shaderchain - class Mipmaps { - public: - /// create a mipmaps shaderchain - /// @param ctx context - /// @param sourceImages pair of source images - Mipmaps(const Ctx& ctx, - const std::pair& sourceImages); - - /// prepare the shaderchain initially - /// @param images vector to fill with image handles - void prepare(std::vector& images) const; - - /// render the mipmaps shaderchain - /// @param vk the vulkan instance - /// @param cmd command buffer - /// @param idx frame index - void render(const vk::Vulkan& vk, 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 images; - - std::vector sets; - VkExtent2D dispatchExtent{}; - }; -} diff --git a/lsfg-vk-backend/src/utility/logger.cpp b/lsfg-vk-backend/src/utility/logger.cpp new file mode 100644 index 0000000..4b3eaec --- /dev/null +++ b/lsfg-vk-backend/src/utility/logger.cpp @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "logger.hpp" + +#include +#include +#include +#include + +using namespace lsfgvk; +using namespace lsfgvk::logger; + +namespace { + /// Get the current minimum log level + Level& currentLevel() { + static Level level{Level::Debug}; + return level; + } + + /// Format a log level as a string + constexpr std::string_view formatLevel(Level level) { + switch (level) { + case Level::Debug: + return "DEBUG"; + case Level::Info: + return "INFO "; + case Level::Warning: + return "WARN "; + case Level::Error: + return "ERROR"; + } + } +} + +void logger::setLevel(Level level) { +#ifdef NDEBUG + if (level == Level::Debug) { + LOG_WARNING("Release builds do not support debug log level, defaulting to info"); + level = Level::Info; + } +#endif + currentLevel() = level; +} + +void logger::log(Level level, const std::string& message) { + if (level < currentLevel()) + return; + + std::ostringstream log; + log << "(lsfg-vk) [" << formatLevel(level) << "] " << message << '\n'; + + std::cerr << log.str(); +} diff --git a/lsfg-vk-backend/src/utility/logger.hpp b/lsfg-vk-backend/src/utility/logger.hpp new file mode 100644 index 0000000..a900571 --- /dev/null +++ b/lsfg-vk-backend/src/utility/logger.hpp @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#pragma once + +#include +#include // IWYU pragma: keep +#include +#include // IWYU pragma: keep + +namespace lsfgvk::logger { + + /// Various levels for log messages + enum class Level : uint8_t { + /// Detailed debugging information + Debug, + /// General informational messages + Info, + /// Potentially problematic situations + Warning, + /// Irrecoverable errors + Error + }; + + /// + /// Set the minimum log level + /// + /// @param level Inclusive minimum log level + /// + void setLevel(Level level); + + /// + /// Log a message + /// + /// @param level Log level + /// @param message Log message + /// + void log(Level level, const std::string& message); + + // NOLINTBEGIN (macro parentheses) + #define LOG(level, msg) { \ + std::ostringstream _oss; \ + _oss << msg; \ + lsfgvk::logger::log(level, _oss.str()); \ + } + + #define LOG_INFO(msg) LOG(lsfgvk::logger::Level::Info, msg) + #define LOG_WARNING(msg) LOG(lsfgvk::logger::Level::Warning, msg) + #define LOG_ERROR(msg) LOG(lsfgvk::logger::Level::Error, msg) +#ifdef NDEBUG + #define LOG_DEBUG(msg) +#else + #define LOG_DEBUG(msg) LOG(lsfgvk::logger::Level::Debug, msg) +#endif + // NOLINTEND + +}