diff --git a/framegen/CMakeLists.txt b/framegen/CMakeLists.txt index f01c318..595774e 100644 --- a/framegen/CMakeLists.txt +++ b/framegen/CMakeLists.txt @@ -1,17 +1,8 @@ cmake_minimum_required(VERSION 3.10) -if(NOT LSFGVK_EXCESS_DEBUG) - set(CMAKE_C_VISIBILITY_PRESET "hidden") - set(CMAKE_CXX_VISIBILITY_PRESET "hidden") -endif() - -if(LSFGVK_EXCESS_DEBUG) - add_compile_definitions(LSFGVK_EXCESS_DEBUG) -endif() - project(lsfg-vk-framegen DESCRIPTION "Lossless Scaling Frame Generation Backend" - LANGUAGES C CXX) + LANGUAGES C CXX) # FIXME: get rid of c language file(GLOB SOURCES "src/trans/*.cpp" @@ -26,38 +17,37 @@ file(GLOB SOURCES add_library(lsfg-vk-framegen STATIC ${SOURCES}) -# target set_target_properties(lsfg-vk-framegen PROPERTIES CXX_STANDARD 20 - CXX_STANDARD_REQUIRED ON) + CXX_STANDARD_REQUIRED ON + CXX_VISIBILITY_PRESET "hidden" + EXPORT_COMPILE_COMMANDS ON) target_include_directories(lsfg-vk-framegen SYSTEM PUBLIC include/thirdparty) target_include_directories(lsfg-vk-framegen PUBLIC include) -# diagnostics if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set_target_properties(lsfg-vk-framegen PROPERTIES - EXPORT_COMPILE_COMMANDS ON) -endif() + if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + message(WARNING "Debug builds should use Clang for better diagnostics") + else() + message(STATUS "Building with further diagnostics") -if(LSFGVK_EXCESS_DEBUG) - target_compile_options(lsfg-vk-framegen PRIVATE - -Weverything - # disable compat c++ flags - -Wno-pre-c++20-compat-pedantic - -Wno-pre-c++17-compat - -Wno-c++98-compat-pedantic - -Wno-c++98-compat - # disable other flags - -Wno-missing-designated-field-initializers - -Wno-shadow # allow shadowing - -Wno-switch-enum # ignore missing cases - -Wno-switch-default # ignore missing default - -Wno-padded # ignore automatic padding - -Wno-cast-function-type-strict # for vulkan - ) + set_target_properties(lsfg-vk-framegen PROPERTIES + CXX_CLANG_TIDY clang-tidy) - set_target_properties(lsfg-vk-framegen PROPERTIES - CXX_CLANG_TIDY clang-tidy) + target_compile_options(lsfg-vk-framegen PRIVATE + -Weverything + # disable incompatible warnings + -Wno-pre-c++20-compat-pedantic + -Wno-c++98-compat + -Wno-switch-default + -Wno-switch-enum + # disable noisy warnings + -Wno-missing-designated-field-initializers + -Wno-cast-function-type-strict + -Wno-padded + -Wno-shadow + ) + endif() endif() diff --git a/framegen/include/lsfg.hpp b/framegen/include/lsfg.hpp index 81d879c..5b56ecb 100644 --- a/framegen/include/lsfg.hpp +++ b/framegen/include/lsfg.hpp @@ -7,10 +7,24 @@ #include "vk/registry/shader_registry.hpp" #include +#include namespace LSFG { - // FIXME: device picking + // FIXME: device picking, fp16 logic, etc. + + /// Vulkan (and related) data structure. + struct VKD { + VK::Core::Instance instance; + VK::Core::Device device; + VK::Core::DescriptorPool dpool; + + VK::Registry::ShaderRegistry registry; + + VK::Pool::ShaderPool spool; + + float flow{1.0F}; + }; /// /// Lossless Scaling Frame Generation instance. @@ -25,15 +39,8 @@ namespace LSFG { /// @throws LSFG::error if lsfg creation fails. /// Instance(const std::filesystem::path& dll); - private: - VK::Core::Instance vk; - VK::Core::Device vkd; - - VK::Core::DescriptorPool pool; - - VK::Registry::ShaderRegistry registry; - VK::Pool::ShaderPool shaders; + std::unique_ptr vkd; }; } diff --git a/framegen/include/v31n/shaderchain/mipmaps.hpp b/framegen/include/v31n/shaderchain/mipmaps.hpp new file mode 100644 index 0000000..8a811d0 --- /dev/null +++ b/framegen/include/v31n/shaderchain/mipmaps.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "vk/types/images.hpp" +#include "vk/types/shader.hpp" + +#include + +namespace LSFG { struct VKD; } +namespace LSFG::V31N::Shaderchain { + + class Mipmaps { + public: + Mipmaps(VKD& vkd, + const VK::Core::Image& in1, + const VK::Core::Image& in2); + private: + std::unique_ptr shader; + + VK::Types::Images<7> mipmaps; + }; + +} diff --git a/framegen/include/vk/pool/buffer_pool.hpp b/framegen/include/vk/pool/buffer_pool.hpp new file mode 100644 index 0000000..d1ff9be --- /dev/null +++ b/framegen/include/vk/pool/buffer_pool.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "vk/core/buffer.hpp" + +#include +#include + +namespace VK::Pool { + + /// + /// Pool of initialized buffers. + /// + class BufferPool { + public: + /// + /// Create a buffer pool. + /// + BufferPool() noexcept = default; + + /// + /// Get or create a buffer. + /// + /// @param flow Flow scale + /// @param hdr Whether HDR is enabled + /// @param timestamp Timestamp of the frame + /// @param firstIter Whether this is the first iteration + /// @param firstIterS Whether this is the first iteration for the second pass + /// @return Preallocated buffer + /// + /// @throws VK::vulkan_error if buffer creation fails. + /// + [[nodiscard]] const Core::Buffer& getOrCreate( + const Core::Device& device, float flow, bool hdr, + float timestamp, bool firstIter, bool firstIterS); + private: + std::unordered_map buffers; + }; + +} diff --git a/framegen/include/vk/types/shader.hpp b/framegen/include/vk/types/shader.hpp index 1ea2fd8..2651a69 100644 --- a/framegen/include/vk/types/shader.hpp +++ b/framegen/include/vk/types/shader.hpp @@ -23,15 +23,28 @@ namespace VK::Types { /// Create a new shader instance. /// Shader(Pool::ShaderInstance shader, - std::vector sets) - : shader(std::move(shader)), - sets(std::move(sets)) {} + std::vector sets, + std::vector samplers, + std::optional buffer, + std::vector>> inputs, + std::vector> outputs) + : shader(std::move(shader)), sets(std::move(sets)), + samplers(std::move(samplers)), + buffer(std::move(buffer)), + inputs(std::move(inputs)), + outputs(std::move(outputs)) {} + /// TODO: remaining methods private: Pool::ShaderInstance shader; std::vector sets; + + std::vector samplers; + std::optional buffer; + std::vector>> inputs; + std::vector> outputs; }; /// diff --git a/framegen/src/lsfg.cpp b/framegen/src/lsfg.cpp index 7b80b8d..fafe316 100644 --- a/framegen/src/lsfg.cpp +++ b/framegen/src/lsfg.cpp @@ -1,43 +1,52 @@ #include "lsfg.hpp" +#include "vk/registry/shader_registry.hpp" +#include "vk/pool/shader_pool.hpp" +#include "vk/core/descriptorpool.hpp" +#include "vk/core/instance.hpp" +#include "vk/core/device.hpp" #include "trans/rsrc.hpp" -#include "vk/core/buffer.hpp" -#include "vk/core/image.hpp" -#include "vk/core/sampler.hpp" -#include "vk/types/shader.hpp" - -#include #include -#include +#include +#include using namespace LSFG; +using namespace VK; + +Instance::Instance(const std::filesystem::path& dll) { + VKD vkd{ + .instance = Core::Instance(), + .device = Core::Device(vkd.instance, 0, false), + .dpool = Core::DescriptorPool(vkd.device), + .registry = Registry::ShaderRegistry(), + .spool = Pool::ShaderPool() + }; + this->vkd = std::make_unique(std::move(vkd)); -Instance::Instance(const std::filesystem::path& dll) - : vkd(vk, 0, false), pool(vkd) { // load shaders from dll file - const bool fp16 = vkd.supportsFP16(); - Trans::RSRC::loadResources(dll, this->registry, fp16); + const bool fp16 = this->vkd->device.supportsFP16(); + Trans::RSRC::loadResources(dll, this->vkd->registry, fp16); // ... - const auto sampler1 = - VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_COMPARE_OP_GREATER_OR_EQUAL, false); - const auto sampler2 = - VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_ALWAYS, true); - const auto buffer0 = - VK::Core::Buffer(vkd, 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - const auto input0 = - VK::Core::Image(vkd, { 1920, 1080 }); - const auto input1 = - VK::Core::Image(vkd, { 1920, 1080 }); - const std::vector mipmaps{ - input0, input0 - }; + // const auto sampler1 = + // VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_COMPARE_OP_GREATER_OR_EQUAL, false); + // const auto sampler2 = + // VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_ALWAYS, true); + // const auto buffer0 = + // VK::Core::Buffer(vkd, 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + // const auto input0 = + // VK::Core::Image(vkd, { 1920, 1080 }); + // const auto input1 = + // VK::Core::Image(vkd, { 1920, 1080 }); + // const std::vector mipmaps{ + // input0, input0 + // }; - auto shader = VK::Types::ShaderBuilder(vkd, registry, this->shaders, "alpha[0]") - .withSamplers(sampler1, sampler2) - .withBuffer(buffer0) - .addTemporalInput({ input0, input1 }) - .addOutputs(mipmaps) - .build(vkd, this->pool); + // auto shader = VK::Types::ShaderBuilder(vkd, registry, this->shaders, "alpha[0]") + // .withSamplers(sampler1, sampler2) + // .withBuffer(buffer0) + // .addTemporalInput({ input0, input1 }) + // .addOutputs(mipmaps) + // .build(vkd, this->pool); } diff --git a/framegen/src/v31n/shaderchain/mipmaps.cpp b/framegen/src/v31n/shaderchain/mipmaps.cpp new file mode 100644 index 0000000..ac6a854 --- /dev/null +++ b/framegen/src/v31n/shaderchain/mipmaps.cpp @@ -0,0 +1,48 @@ +#include "v31n/shaderchain/mipmaps.hpp" +#include "vk/types/shader.hpp" +#include "vk/core/sampler.hpp" +#include "vk/core/buffer.hpp" +#include "vk/core/image.hpp" +#include "lsfg.hpp" + +#include + +#include + +using namespace LSFG::V31N::Shaderchain; +using namespace VK; + +Mipmaps::Mipmaps(LSFG::VKD& vkd, const Core::Image& in1, const Core::Image& in2) { + // TODO: logic for buffer and sampler + Core::Sampler sampler{vkd.device, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + VK_COMPARE_OP_NEVER, + false}; + Core::Buffer buffer{vkd.device, nullptr, 0, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT}; + + // create output images + const VkExtent2D extent{ + .width = static_cast( + static_cast(in1.getExtent().width) / vkd.flow), + .height = static_cast( + static_cast(in1.getExtent().height) / vkd.flow) + }; + + std::vector mipmapVector{}; + mipmapVector.reserve(7); + for (size_t i = 0; i < 7; i++) + mipmapVector.emplace_back(vkd.device, + VkExtent2D { extent.width >> i, extent.height >> i }, + VK_FORMAT_R8_UNORM); + this->mipmaps = VK::Types::Images<7>(mipmapVector); + + // create shaders + auto shader = Types::ShaderBuilder( + vkd.device, vkd.registry, vkd.spool, "mipmaps", 2) + .withSamplers(sampler) + .withBuffer(buffer) + .addTemporalInput({ in1, in2 }) + .addOutputs(this->mipmaps.all()) + .build(vkd.device, vkd.dpool); + this->shader = std::make_unique(std::move(shader)); +} diff --git a/framegen/src/vk/pool/buffer_pool.cpp b/framegen/src/vk/pool/buffer_pool.cpp new file mode 100644 index 0000000..b293c06 --- /dev/null +++ b/framegen/src/vk/pool/buffer_pool.cpp @@ -0,0 +1,54 @@ +#include "vk/pool/buffer_pool.hpp" +#include "vk/core/buffer.hpp" +#include "vk/core/device.hpp" + +#include + +#include +#include +#include + +using namespace VK::Pool; + +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; +}; + +const VK::Core::Buffer& BufferPool::getOrCreate( + const Core::Device& device, float flow, bool hdr, + float timestamp, bool firstIter, bool firstIterS) { + uint64_t hash = 0; + const union { float f; uint32_t i; } u{ + .f = timestamp }; + hash |= u.i; // NOLINT + hash |= static_cast(firstIter) << 32; + hash |= static_cast(firstIterS) << 33; + + const auto it = buffers.find(hash); + if (it != buffers.end()) { + return it->second; + } + + // create buffer + const ConstantBuffer data{ + .inputOffset = { 0, 0 }, + .advancedColorKind = hdr ? 2U : 0U, + .hdrSupport = hdr, + .resolutionInvScale = flow, + .timestamp = timestamp, + .uiThreshold = 0.5F, + }; + + Core::Buffer buffer(device, data, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + + const auto i = buffers.emplace(hash, std::move(buffer)); + return i.first->second; +} diff --git a/framegen/src/vk/types/shader.cpp b/framegen/src/vk/types/shader.cpp index e2f7b96..f2c728f 100644 --- a/framegen/src/vk/types/shader.cpp +++ b/framegen/src/vk/types/shader.cpp @@ -1,4 +1,4 @@ -#include "vk/types/shader.hpp" + #include "vk/types/shader.hpp" #include "vk/core/descriptorpool.hpp" #include "vk/core/descriptorset.hpp" #include "vk/core/sampler.hpp" @@ -86,5 +86,11 @@ Shader ShaderBuilder::build(const Core::Device& vkd, std::move(this->inputs.at(i)), std::move(this->outputs.at(i)), this->samplers, this->buffer); - return { this->shader, std::move(sets) }; + return { + this->shader, std::move(sets), + std::move(this->samplers), + std::move(this->buffer), + std::move(this->inputs), + std::move(this->outputs) + }; }