refactor: vkd struct & buffer pool

This commit is contained in:
PancakeTAS 2025-09-28 23:18:17 +02:00
parent 83ec052f73
commit 24f7b66e99
No known key found for this signature in database
9 changed files with 266 additions and 78 deletions

View file

@ -1,17 +1,8 @@
cmake_minimum_required(VERSION 3.10) 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 project(lsfg-vk-framegen
DESCRIPTION "Lossless Scaling Frame Generation Backend" DESCRIPTION "Lossless Scaling Frame Generation Backend"
LANGUAGES C CXX) LANGUAGES C CXX) # FIXME: get rid of c language
file(GLOB SOURCES file(GLOB SOURCES
"src/trans/*.cpp" "src/trans/*.cpp"
@ -26,38 +17,37 @@ file(GLOB SOURCES
add_library(lsfg-vk-framegen STATIC ${SOURCES}) add_library(lsfg-vk-framegen STATIC ${SOURCES})
# target
set_target_properties(lsfg-vk-framegen PROPERTIES set_target_properties(lsfg-vk-framegen PROPERTIES
CXX_STANDARD 20 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 target_include_directories(lsfg-vk-framegen SYSTEM
PUBLIC include/thirdparty) PUBLIC include/thirdparty)
target_include_directories(lsfg-vk-framegen target_include_directories(lsfg-vk-framegen
PUBLIC include) PUBLIC include)
# diagnostics
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set_target_properties(lsfg-vk-framegen PROPERTIES if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
EXPORT_COMPILE_COMMANDS ON) message(WARNING "Debug builds should use Clang for better diagnostics")
endif() else()
message(STATUS "Building with further diagnostics")
if(LSFGVK_EXCESS_DEBUG) set_target_properties(lsfg-vk-framegen PROPERTIES
target_compile_options(lsfg-vk-framegen PRIVATE CXX_CLANG_TIDY clang-tidy)
-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 target_compile_options(lsfg-vk-framegen PRIVATE
CXX_CLANG_TIDY clang-tidy) -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() endif()

View file

@ -7,10 +7,24 @@
#include "vk/registry/shader_registry.hpp" #include "vk/registry/shader_registry.hpp"
#include <filesystem> #include <filesystem>
#include <memory>
namespace LSFG { 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. /// Lossless Scaling Frame Generation instance.
@ -25,15 +39,8 @@ namespace LSFG {
/// @throws LSFG::error if lsfg creation fails. /// @throws LSFG::error if lsfg creation fails.
/// ///
Instance(const std::filesystem::path& dll); Instance(const std::filesystem::path& dll);
private: private:
VK::Core::Instance vk; std::unique_ptr<VKD> vkd;
VK::Core::Device vkd;
VK::Core::DescriptorPool pool;
VK::Registry::ShaderRegistry registry;
VK::Pool::ShaderPool shaders;
}; };
} }

View file

@ -0,0 +1,22 @@
#pragma once
#include "vk/types/images.hpp"
#include "vk/types/shader.hpp"
#include <memory>
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<VK::Types::Shader> shader;
VK::Types::Images<7> mipmaps;
};
}

View file

@ -0,0 +1,39 @@
#pragma once
#include "vk/core/buffer.hpp"
#include <unordered_map>
#include <cstdint>
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<uint64_t, Core::Buffer> buffers;
};
}

View file

@ -23,15 +23,28 @@ namespace VK::Types {
/// Create a new shader instance. /// Create a new shader instance.
/// ///
Shader(Pool::ShaderInstance shader, Shader(Pool::ShaderInstance shader,
std::vector<Core::DescriptorSet> sets) std::vector<Core::DescriptorSet> sets,
: shader(std::move(shader)), std::vector<Core::Sampler> samplers,
sets(std::move(sets)) {} std::optional<Core::Buffer> buffer,
std::vector<std::vector<std::optional<Core::Image>>> inputs,
std::vector<std::vector<Core::Image>> 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 /// TODO: remaining methods
private: private:
Pool::ShaderInstance shader; Pool::ShaderInstance shader;
std::vector<Core::DescriptorSet> sets; std::vector<Core::DescriptorSet> sets;
std::vector<Core::Sampler> samplers;
std::optional<Core::Buffer> buffer;
std::vector<std::vector<std::optional<Core::Image>>> inputs;
std::vector<std::vector<Core::Image>> outputs;
}; };
/// ///

View file

@ -1,43 +1,52 @@
#include "lsfg.hpp" #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 "trans/rsrc.hpp"
#include "vk/core/buffer.hpp"
#include "vk/core/image.hpp"
#include "vk/core/sampler.hpp"
#include "vk/types/shader.hpp"
#include <vulkan/vulkan_core.h>
#include <filesystem> #include <filesystem>
#include <vector> #include <utility>
#include <memory>
using namespace LSFG; 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<VKD>(std::move(vkd));
Instance::Instance(const std::filesystem::path& dll)
: vkd(vk, 0, false), pool(vkd) {
// load shaders from dll file // load shaders from dll file
const bool fp16 = vkd.supportsFP16(); const bool fp16 = this->vkd->device.supportsFP16();
Trans::RSRC::loadResources(dll, this->registry, fp16); Trans::RSRC::loadResources(dll, this->vkd->registry, fp16);
// ... // ...
const auto sampler1 = // const auto sampler1 =
VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_COMPARE_OP_GREATER_OR_EQUAL, false); // VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_COMPARE_OP_GREATER_OR_EQUAL, false);
const auto sampler2 = // const auto sampler2 =
VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_ALWAYS, true); // VK::Core::Sampler(vkd, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_ALWAYS, true);
const auto buffer0 = // const auto buffer0 =
VK::Core::Buffer(vkd, 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // VK::Core::Buffer(vkd, 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
const auto input0 = // const auto input0 =
VK::Core::Image(vkd, { 1920, 1080 }); // VK::Core::Image(vkd, { 1920, 1080 });
const auto input1 = // const auto input1 =
VK::Core::Image(vkd, { 1920, 1080 }); // VK::Core::Image(vkd, { 1920, 1080 });
const std::vector<VK::Core::Image> mipmaps{ // const std::vector<VK::Core::Image> mipmaps{
input0, input0 // input0, input0
}; // };
auto shader = VK::Types::ShaderBuilder(vkd, registry, this->shaders, "alpha[0]") // auto shader = VK::Types::ShaderBuilder(vkd, registry, this->shaders, "alpha[0]")
.withSamplers(sampler1, sampler2) // .withSamplers(sampler1, sampler2)
.withBuffer(buffer0) // .withBuffer(buffer0)
.addTemporalInput({ input0, input1 }) // .addTemporalInput({ input0, input1 })
.addOutputs(mipmaps) // .addOutputs(mipmaps)
.build(vkd, this->pool); // .build(vkd, this->pool);
} }

View file

@ -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 <vulkan/vulkan_core.h>
#include <vector>
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<uint32_t>(
static_cast<float>(in1.getExtent().width) / vkd.flow),
.height = static_cast<uint32_t>(
static_cast<float>(in1.getExtent().height) / vkd.flow)
};
std::vector<Core::Image> 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<Types::Shader>(std::move(shader));
}

View file

@ -0,0 +1,54 @@
#include "vk/pool/buffer_pool.hpp"
#include "vk/core/buffer.hpp"
#include "vk/core/device.hpp"
#include <vulkan/vulkan_core.h>
#include <cstdint>
#include <utility>
#include <array>
using namespace VK::Pool;
struct ConstantBuffer {
std::array<uint32_t, 2> inputOffset;
uint32_t firstIter;
uint32_t firstIterS;
uint32_t advancedColorKind;
uint32_t hdrSupport;
float resolutionInvScale;
float timestamp;
float uiThreshold;
std::array<uint32_t, 3> 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<uint64_t>(firstIter) << 32;
hash |= static_cast<uint64_t>(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;
}

View file

@ -1,4 +1,4 @@
#include "vk/types/shader.hpp" #include "vk/types/shader.hpp"
#include "vk/core/descriptorpool.hpp" #include "vk/core/descriptorpool.hpp"
#include "vk/core/descriptorset.hpp" #include "vk/core/descriptorset.hpp"
#include "vk/core/sampler.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->inputs.at(i)),
std::move(this->outputs.at(i)), std::move(this->outputs.at(i)),
this->samplers, this->buffer); 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)
};
} }