diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b0fbfe..b9cc47b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,9 +40,10 @@ jobs: -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=./target \ -DCMAKE_CXX_COMPILER=clang++ \ - -DLSFGVK_BUILD_VULKAN_LAYER=On \ - -DLSFGVK_BUILD_USER_INTERFACE=On \ - -DLSFGVK_INSTALL_XDG_FILES=On \ + -DLSFGVK_BUILD_VK_LAYER=ON \ + -DLSFGVK_BUILD_UI=ON \ + -DLSFGVK_BUILD_CLI=ON \ + -DLSFGVK_INSTALL_XDG_FILES=ON \ -DLSFGVK_LAYER_LIBRARY_PATH="../../../lib/liblsfg-vk-layer.so" - name: Build with Ninja run: | diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml index 1f29540..4943d30 100644 --- a/.github/workflows/manual.yml +++ b/.github/workflows/manual.yml @@ -59,9 +59,10 @@ jobs: -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=./target \ -DCMAKE_CXX_COMPILER=clang++ \ - -DLSFGVK_BUILD_VULKAN_LAYER=On \ - -DLSFGVK_BUILD_USER_INTERFACE=On \ - -DLSFGVK_INSTALL_XDG_FILES=On \ + -DLSFGVK_BUILD_VK_LAYER=ON \ + -DLSFGVK_BUILD_UI=ON \ + -DLSFGVK_BUILD_CLI=ON \ + -DLSFGVK_INSTALL_XDG_FILES=ON \ -DLSFGVK_LAYER_LIBRARY_PATH="../../../lib/liblsfg-vk-layer.so" - name: Build with Ninja run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 277e5bf..a2a0398 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,12 +3,13 @@ project(lsfg-vk LANGUAGES CXX) include(GNUInstallDirs) # === READ HERE FOR BUILD OPTIONS === -option(LSFGVK_BUILD_VULKAN_LAYER "Build the Vulkan layer" ON) -option(LSFGVK_BUILD_USER_INTERFACE "Build the user interface" OFF) -option(LSFGVK_BUILD_DEBUG_TOOL "Build the debug tool" OFF) -option(LSFGVK_INSTALL_DEVELOP "Install development libraries and headers" OFF) -option(LSFGVK_INSTALL_XDG_FILES "Install the application icon and desktop files" OFF) -option(LSFGVK_LAYER_LIBRARY_PATH "Change where Vulkan searches for the layer library" liblsfg-vk-layer.so) +option(LSFGVK_BUILD_VK_LAYER "Build the Vulkan layer" ON) +option(LSFGVK_BUILD_UI "Build the user interface" OFF) +option(LSFGVK_BUILD_CLI "Build the command line interface" ON) +option(LSFGVK_INSTALL_DEVELOP "Install development libraries and headers" OFF) +option(LSFGVK_INSTALL_XDG_FILES "Install the application icon and desktop files" OFF) +option(LSFGVK_LAYER_LIBRARY_PATH "Change where Vulkan searches for the layer library" liblsfg-vk-layer.so) +option(LSFGVK_TESTING_RENDERDOC "Enable RenderDoc integration for testing purposes" OFF) # === READ HERE FOR BUILD OPTIONS === set(CMAKE_CXX_STANDARD 20) @@ -43,18 +44,18 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") endif() endif() -if(LSFGVK_BUILD_DEBUG_TOOL) - add_compile_definitions(LSFGVK__RENDERDOC_INTEGRATION) +if(LSFGVK_TESTING_RENDERDOC) + add_compile_definitions(LSFGVK_TESTING_RENDERDOC) endif() add_subdirectory(lsfg-vk-common) add_subdirectory(lsfg-vk-backend) -if(LSFGVK_BUILD_VULKAN_LAYER) +if(LSFGVK_BUILD_VK_LAYER) add_subdirectory(lsfg-vk-layer) endif() -if(LSFGVK_BUILD_USER_INTERFACE) +if(LSFGVK_BUILD_UI) add_subdirectory(lsfg-vk-ui) endif() -if(LSFGVK_BUILD_DEBUG_TOOL) - add_subdirectory(lsfg-vk-debug) +if(LSFGVK_BUILD_CLI) + add_subdirectory(lsfg-vk-cli) endif() diff --git a/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_23.08.yml b/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_23.08.yml index 694dc06..5ae2cde 100644 --- a/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_23.08.yml +++ b/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_23.08.yml @@ -20,8 +20,11 @@ modules: buildsystem: cmake-ninja config-opts: - -DCMAKE_BUILD_TYPE=Release - - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On + - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON - -DCMAKE_CXX_COMPILER=clang++ + - -DLSFGVK_BUILD_VK_LAYER=ON + - -DLSFGVK_BUILD_UI=OFF + - -DLSFGVK_BUILD_CLI=OFF - -DLSFGVK_LAYER_LIBRARY_PATH=/usr/lib/extensions/vulkan/lsfgvk/lib/liblsfg-vk-layer.so sources: - type: dir diff --git a/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_24.08.yml b/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_24.08.yml index 5aabfb5..4615e32 100644 --- a/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_24.08.yml +++ b/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_24.08.yml @@ -20,8 +20,11 @@ modules: buildsystem: cmake-ninja config-opts: - -DCMAKE_BUILD_TYPE=Release - - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On + - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON - -DCMAKE_CXX_COMPILER=clang++ + - -DLSFGVK_BUILD_VK_LAYER=ON + - -DLSFGVK_BUILD_UI=OFF + - -DLSFGVK_BUILD_CLI=OFF - -DLSFGVK_LAYER_LIBRARY_PATH=/usr/lib/extensions/vulkan/lsfgvk/lib/liblsfg-vk-layer.so sources: - type: dir diff --git a/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_25.08.yml b/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_25.08.yml index a4dc150..6377b81 100644 --- a/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_25.08.yml +++ b/dist/flatpak/lsfg-vk-layer/org.freedesktop.Platform.VulkanLayer.lsfgvk_25.08.yml @@ -20,8 +20,11 @@ modules: buildsystem: cmake-ninja config-opts: - -DCMAKE_BUILD_TYPE=Release - - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=On + - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON - -DCMAKE_CXX_COMPILER=clang++ + - -DLSFGVK_BUILD_VK_LAYER=ON + - -DLSFGVK_BUILD_UI=OFF + - -DLSFGVK_BUILD_CLI=OFF - -DLSFGVK_LAYER_LIBRARY_PATH=/usr/lib/extensions/vulkan/lsfgvk/lib/liblsfg-vk-layer.so sources: - type: dir diff --git a/dist/flatpak/lsfg-vk-ui/gay.pancake.lsfg-vk-ui.yml b/dist/flatpak/lsfg-vk-ui/gay.pancake.lsfg-vk-ui.yml index 854a3fa..5f27b1c 100644 --- a/dist/flatpak/lsfg-vk-ui/gay.pancake.lsfg-vk-ui.yml +++ b/dist/flatpak/lsfg-vk-ui/gay.pancake.lsfg-vk-ui.yml @@ -19,9 +19,10 @@ modules: config-opts: - -DCMAKE_BUILD_TYPE=Release - -DCMAKE_INSTALL_PREFIX=/app - - -DLSFGVK_BUILD_VULKAN_LAYER=Off - - -DLSFGVK_BUILD_USER_INTERFACE=On - - -DLSFGVK_INSTALL_XDG_FILES=On + - -DLSFGVK_BUILD_VK_LAYER=OFF + - -DLSFGVK_BUILD_UI=ON + - -DLSFGVK_BUILD_CLI=OFF + - -DLSFGVK_INSTALL_XDG_FILES=ON sources: - type: dir path: ../../.. diff --git a/lsfg-vk-debug/layer_json.json b/dist/local/layer_json.json similarity index 100% rename from lsfg-vk-debug/layer_json.json rename to dist/local/layer_json.json diff --git a/include/utils/benchmark.hpp b/include/utils/benchmark.hpp deleted file mode 100644 index fc7f481..0000000 --- a/include/utils/benchmark.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -namespace Benchmark { - - /// - /// Run the benchmark. - /// - /// @param width The width of the benchmark. - /// @param height The height of the benchmark. - /// - [[noreturn]] void run(uint32_t width, uint32_t height); - -} diff --git a/lsfg-vk-backend/src/lsfgvk.cpp b/lsfg-vk-backend/src/lsfgvk.cpp index 9de1226..1d0b732 100644 --- a/lsfg-vk-backend/src/lsfgvk.cpp +++ b/lsfg-vk-backend/src/lsfgvk.cpp @@ -42,7 +42,7 @@ #include -#ifdef LSFGVK__RENDERDOC_INTEGRATION +#ifdef LSFGVK_TESTING_RENDERDOC #include #include #endif @@ -72,7 +72,7 @@ namespace lsfgvk::backend { /// get the shader registry /// @return the shader registry [[nodiscard]] const auto& getShaderRegistry() const { return this->shaders; } -#ifdef LSFGVK__RENDERDOC_INTEGRATION +#ifdef LSFGVK_TESTING_RENDERDOC /// get the RenderDoc API /// @return the RenderDoc API [[nodiscard]] const auto& getRenderDocAPI() const { return this->renderdoc; } @@ -81,7 +81,7 @@ namespace lsfgvk::backend { vk::Vulkan vk; ShaderRegistry shaders; -#ifdef LSFGVK__RENDERDOC_INTEGRATION +#ifdef LSFGVK_TESTING_RENDERDOC std::optional renderdoc; #endif }; @@ -232,7 +232,7 @@ namespace { throw backend::error("Unable to build shader registry", e); } } -#ifdef LSFGVK__RENDERDOC_INTEGRATION +#ifdef LSFGVK_TESTING_RENDERDOC /// load RenderDoc integration std::optional loadRenderDocIntegration() { void* module = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD); @@ -260,7 +260,7 @@ InstanceImpl::InstanceImpl(vk::PhysicalDeviceSelector selectPhysicalDevice, : vk(createVulkanInstance(selectPhysicalDevice)), shaders(createShaderRegistry(this->vk, shaderDllPath, allowLowPrecision && vk.supportsFP16())) { -#ifdef LSFGVK__RENDERDOC_INTEGRATION +#ifdef LSFGVK_TESTING_RENDERDOC this->renderdoc = loadRenderDocIntegration(); #endif vk.persistPipelineCache(); // will silently fail @@ -540,8 +540,8 @@ ContextImpl::ContextImpl(const InstanceImpl& instance, cmdbuf.submit(ctx.vk); // wait for completion } -void Instance::scheduleFrames(Context& context) { -#ifdef LSFGVK__RENDERDOC_INTEGRATION +void Instance::scheduleFrames(Context& context) { // NOLINT (static) +#ifdef LSFGVK_TESTING_RENDERDOC const auto& impl = this->m_impl; if (impl->getRenderDocAPI()) { impl->getRenderDocAPI()->StartFrameCapture( @@ -554,7 +554,7 @@ void Instance::scheduleFrames(Context& context) { } catch (const std::exception& e) { throw backend::error("Unable to schedule frames", e); } -#ifdef LSFGVK__RENDERDOC_INTEGRATION +#ifdef LSFGVK_TESTING_RENDERDOC if (impl->getRenderDocAPI()) { impl->getVulkan().df().DeviceWaitIdle(impl->getVulkan().dev()); impl->getRenderDocAPI()->EndFrameCapture( diff --git a/lsfg-vk-debug/.clang-tidy b/lsfg-vk-cli/.clang-tidy similarity index 88% rename from lsfg-vk-debug/.clang-tidy rename to lsfg-vk-cli/.clang-tidy index 9567cc4..c7f1ea2 100644 --- a/lsfg-vk-debug/.clang-tidy +++ b/lsfg-vk-cli/.clang-tidy @@ -16,14 +16,17 @@ Checks: - "-readability-math-missing-parentheses" - "-readability-named-parameter" - "-bugprone-easily-swappable-parameters" +- "-misc-non-private-member-variables-in-classes" # configure modernization - "modernize-*" - "-modernize-use-trailing-return-type" +- "-modernize-use-designated-initializers" # configure cppcoreguidelines - "cppcoreguidelines-*" - "-cppcoreguidelines-avoid-magic-numbers" - "-cppcoreguidelines-pro-type-reinterpret-cast" - "-cppcoreguidelines-macro-usage" +- "-cppcoreguidelines-pro-bounds-pointer-arithmetic" # disable slow and pointless checks - "-modernize-use-std-numbers" - "-modernize-type-traits" diff --git a/lsfg-vk-cli/CMakeLists.txt b/lsfg-vk-cli/CMakeLists.txt new file mode 100644 index 0000000..45f25e3 --- /dev/null +++ b/lsfg-vk-cli/CMakeLists.txt @@ -0,0 +1,18 @@ +set(CLI_SOURCES + "src/tools/benchmark.cpp" + "src/tools/debug.cpp" + "src/tools/validate.cpp" + "src/main.cpp") + +add_executable(lsfg-vk-cli ${CLI_SOURCES}) + +target_link_libraries(lsfg-vk-cli + PUBLIC lsfg-vk-common + PUBLIC lsfg-vk-backend) + +target_compile_options(lsfg-vk-cli PRIVATE + -Wno-unknown-warning-option + -Wno-unsafe-buffer-usage) + +install(TARGETS lsfg-vk-cli + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") diff --git a/lsfg-vk-cli/src/main.cpp b/lsfg-vk-cli/src/main.cpp new file mode 100644 index 0000000..71815d5 --- /dev/null +++ b/lsfg-vk-cli/src/main.cpp @@ -0,0 +1,225 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "tools/benchmark.hpp" +#include "tools/debug.hpp" +#include "tools/validate.hpp" + +#include +#include +#include +#include +#include +#include + +#include // NOLINT +#include +#include + +using namespace lsfgvk::cli; + +namespace { + /// print usage information + void usage(const std::string& prog) { + std::cerr << +R"(Validate, benchmark, and debug lsfg-vk. + +USAGE: + )" << prog << R"( [OPTIONS] [ARGS] + +COMMANDS: + validate Validate a configuration file + benchmark Run a benchmark + debug Run lsfg-vk on a set of images + +SUBCOMMAND OPTIONS: + + validate + -c, --config Optional path to the configuration file + + benchmark & debug + -d, --dll Path to Lossless.dll + -a, --allow-fp16 Allow FP16 acceleration + -w, --width Width of the input frames + -h, --height Height of the input frames + -f, --flow Flow scale + -m, --multiplier Multiplier + -p, --performance-mode Use performance mode + -g, --gpu GPU to use + + benchmark + -t, --duration Benchmark duration in seconds + + debug + Path to the debug frames)" << '\n'; + } + + /// parse the validate command options + [[noreturn]] void on_validate(int argc, char** argv) { + validate::Options opts{}; + + const std::array GETOPT {{ + { "config", required_argument, nullptr, 'c' }, + { nullptr, no_argument, nullptr, 0 } + }}; + + int c{0}; + while ((c = getopt_long(argc, argv, "c:", GETOPT.data(), nullptr)) != -1) { + switch (c) { + case 'c': + opts.config.emplace(optarg); + break; + case '?': + default: + usage(*argv); + std::exit(EXIT_FAILURE); + } + } + + if (optind < argc) { + usage(*argv); + std::exit(EXIT_FAILURE); + } + + std::exit(validate::run(opts)); + } + + /// parse the benchmark command options + [[noreturn]] void on_benchmark(int argc, char** argv) { + benchmark::Options opts{}; + + const std::array GETOPT {{ + { "dll", required_argument, nullptr, 'd' }, + { "allow-fp16", no_argument, nullptr, 'a' }, + { "width", required_argument, nullptr, 'w' }, + { "height", required_argument, nullptr, 'h' }, + { "flow", required_argument, nullptr, 'f' }, + { "multiplier", required_argument, nullptr, 'm' }, + { "performance-mode", no_argument, nullptr, 'p' }, + { "gpu", required_argument, nullptr, 'g' }, + { "duration", required_argument, nullptr, 't' }, + { nullptr, no_argument, nullptr, 0 } + }}; + + int c{0}; + while ((c = getopt_long(argc, argv, "d:aw:h:f:m:pg:t:", GETOPT.data(), nullptr)) != -1) { + switch (c) { + case 'd': + opts.dll.emplace(optarg); + break; + case 'a': + opts.allow_fp16 = true; + break; + case 'w': + opts.width = std::stoi(optarg); + break; + case 'h': + opts.height = std::stoi(optarg); + break; + case 'f': + opts.flow = std::stof(optarg); + break; + case 'm': + opts.multiplier = std::stoi(optarg); + break; + case 'p': + opts.performance_mode = true; + break; + case 'g': + opts.gpu.emplace(optarg); + break; + case 't': + opts.duration = std::stoi(optarg); + break; + case '?': + default: + usage(*argv); + std::exit(EXIT_FAILURE); + } + } + + if (optind < argc) { + usage(*argv); + std::exit(EXIT_FAILURE); + } + + std::exit(benchmark::run(opts)); + } + + /// parse the debug command options + [[noreturn]] void on_debug(int argc, char** argv) { + debug::Options opts{}; + + const std::array GETOPT {{ + { "dll", required_argument, nullptr, 'd' }, + { "allow-fp16", no_argument, nullptr, 'a' }, + { "width", required_argument, nullptr, 'w' }, + { "height", required_argument, nullptr, 'h' }, + { "flow", required_argument, nullptr, 'f' }, + { "multiplier", required_argument, nullptr, 'm' }, + { "performance-mode", no_argument, nullptr, 'p' }, + { "gpu", required_argument, nullptr, 'g' }, + { nullptr, no_argument, nullptr, 0 } + }}; + + int c{0}; + while ((c = getopt_long(argc, argv, "d:aw:h:f:m:pg:", GETOPT.data(), nullptr)) != -1) { + switch (c) { + case 'd': + opts.dll.emplace(optarg); + break; + case 'a': + opts.allow_fp16 = true; + break; + case 'w': + opts.width = std::stoi(optarg); + break; + case 'h': + opts.height = std::stoi(optarg); + break; + case 'f': + opts.flow = std::stof(optarg); + break; + case 'm': + opts.multiplier = std::stoi(optarg); + break; + case 'p': + opts.performance_mode = true; + break; + case 'g': + opts.gpu.emplace(optarg); + break; + case '?': + default: + usage(*argv); + std::exit(EXIT_FAILURE); + } + } + + if ((optind + 1) != argc) { + usage(*argv); + std::exit(EXIT_FAILURE); + } + + opts.path = argv[optind]; + + std::exit(debug::run(opts)); + } +} + +int main(int argc, char** argv) { + if (argc < 2) { + usage(*argv); + return EXIT_FAILURE; + } + + const std::string command{argv[1]}; + if (command == "validate") + on_validate(argc - 1, argv + 1); + else if (command == "benchmark") + on_benchmark(argc - 1, argv + 1); + else if (command == "debug") + on_debug(argc - 1, argv + 1); + + usage(*argv); + return EXIT_FAILURE; +} diff --git a/lsfg-vk-cli/src/tools/benchmark.cpp b/lsfg-vk-cli/src/tools/benchmark.cpp new file mode 100644 index 0000000..bee3647 --- /dev/null +++ b/lsfg-vk-cli/src/tools/benchmark.cpp @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "benchmark.hpp" +#include "lsfg-vk-backend/lsfgvk.hpp" +#include "lsfg-vk-common/helpers/errors.hpp" +#include "lsfg-vk-common/helpers/paths.hpp" +#include "lsfg-vk-common/vulkan/image.hpp" +#include "lsfg-vk-common/vulkan/timeline_semaphore.hpp" +#include "lsfg-vk-common/vulkan/vulkan.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace lsfgvk::cli; +using namespace lsfgvk::cli::benchmark; + +namespace { + // get current time in milliseconds + uint64_t ms() { + struct timespec ts{}; + clock_gettime(CLOCK_MONOTONIC, &ts); // NOLINT (IWYU) + + return static_cast(ts.tv_sec) * 1000ULL + + static_cast(ts.tv_nsec) / 1000000ULL; + } +} + +int benchmark::run(const Options& opts) { + try { + // parse options + if (opts.flow < 0.25F || opts.flow > 1.0F) + throw ls::error("flow scale must be between 0.25 and 1.0"); + if (opts.multiplier < 2) + throw ls::error("multiplier must be 2 or greater"); + if (opts.width <= 0 || opts.height <= 0) + throw ls::error("width and height must be positive integers"); + if (opts.duration <= 0) + throw ls::error("duration must be a positive integer"); + const VkExtent2D extent{ + static_cast(opts.width), + static_cast(opts.height) + }; + + // create instance + const vk::Vulkan vk{ + "lsfg-vk-debug", vk::version{2, 0, 0}, + "lsfg-vk-debug-engine", vk::version{2, 0, 0}, + [opts](const vk::VulkanInstanceFuncs fi, + const std::vector& devices) { + if (!opts.gpu.has_value()) + return devices.front(); + + for (const VkPhysicalDevice& device : devices) { + VkPhysicalDeviceProperties2 props{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 + }; + fi.GetPhysicalDeviceProperties2(device, &props); + + auto& properties = props.properties; + std::array devname = std::to_array(properties.deviceName); + devname[255] = '\0'; // ensure null-termination + + if (std::string(devname.data()) == *opts.gpu) + return device; + } + + throw ls::error("failed to find specified GPU: " + *opts.gpu); + } + }; + + std::pair srcfds{}; + const vk::Image frame_0{vk, + extent, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + std::nullopt, &srcfds.first}; + const vk::Image frame_1{vk, + extent, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + std::nullopt, &srcfds.second}; + + std::vector destimgs{}; + std::vector destfds{}; + for (int i = 0; i < (opts.multiplier - 1); i++) { + int fd{}; + destimgs.emplace_back(vk, + extent, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + std::nullopt, + &fd + ); + destfds.push_back(fd); + } + + int syncfd{}; + const vk::TimelineSemaphore sync{vk, 0, std::nullopt, &syncfd}; + + // initialize backend + std::string dll{}; + if (opts.dll.has_value()) + dll = *opts.dll; + else + dll = ls::findShaderDll(); + + lsfgvk::backend::Instance lsfgvk{ + [opts]( + const std::string& gpu_name, + std::pair, + const std::optional& + ) { + return opts.gpu.value_or(gpu_name) == gpu_name; + }, + dll, opts.allow_fp16 + }; + lsfgvk::backend::Context& lsfgvk_ctx = lsfgvk.openContext( + srcfds, destfds, + syncfd, extent.width, extent.height, + false, 1.0F / opts.flow, opts.performance_mode + ); + + // run the benchmark + size_t iterations{0}; + size_t generated_frames{0}; + size_t total_frames{1}; + + uint64_t print_time = ms() + 1000ULL; + const uint64_t end_time = ms() + static_cast(opts.duration) * 1000ULL; + while (ms() < end_time) { + sync.signal(vk, total_frames++); + lsfgvk.scheduleFrames(lsfgvk_ctx); + + for (size_t i = 0; i < destimgs.size(); i++) { + auto success = sync.wait(vk, total_frames++); + if (!success) + throw ls::error("failed to wait for frame"); + + generated_frames++; + } + + iterations++; + + if (ms() >= print_time) { + print_time += 1000ULL; + std::cerr << "." << std::flush; + } + } + + // output results + + std::cerr << (opts.duration < 40 ? "\r" : "\n"); + std::cerr << "benchmark results (ran for " << opts.duration << " seconds):\n"; + std::cerr << " iterations: " << iterations << "\n"; + std::cerr << " generated frames: " << generated_frames << "\n"; + std::cerr << " total frames: " << total_frames << "\n"; + const auto time = static_cast(opts.duration); + const double fps_generated = static_cast(generated_frames) / time; + const double fps_total = static_cast(total_frames) / time; + std::cerr << std::setprecision(2) << std::fixed; + std::cerr << " fps (generated): " << fps_generated << "fps\n"; + std::cerr << " fps (total): " << fps_total << "fps\n"; + + // deinitialize lsfg-vk + lsfgvk.closeContext(lsfgvk_ctx); + return EXIT_SUCCESS; + } catch (const std::exception& e) { + std::cerr << "error: " << e.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/lsfg-vk-cli/src/tools/benchmark.hpp b/lsfg-vk-cli/src/tools/benchmark.hpp new file mode 100644 index 0000000..91fe38e --- /dev/null +++ b/lsfg-vk-cli/src/tools/benchmark.hpp @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#pragma once + +#include +#include + +namespace lsfgvk::cli::benchmark { + + /// options for the "benchmark" command + struct Options { + std::optional dll; + bool allow_fp16{true}; + int width{1920}; + int height{1080}; + + float flow{0.85F}; + int multiplier{2}; + bool performance_mode{true}; + std::optional gpu; + + int duration{10}; + }; + + /// run the "benchmark" command + /// @param opts the command options + int run(const Options& opts); + +} diff --git a/lsfg-vk-cli/src/tools/debug.cpp b/lsfg-vk-cli/src/tools/debug.cpp new file mode 100644 index 0000000..64fe262 --- /dev/null +++ b/lsfg-vk-cli/src/tools/debug.cpp @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "debug.hpp" +#include "lsfg-vk-backend/lsfgvk.hpp" +#include "lsfg-vk-common/helpers/errors.hpp" +#include "lsfg-vk-common/helpers/paths.hpp" +#include "lsfg-vk-common/vulkan/buffer.hpp" +#include "lsfg-vk-common/vulkan/command_buffer.hpp" +#include "lsfg-vk-common/vulkan/image.hpp" +#include "lsfg-vk-common/vulkan/timeline_semaphore.hpp" +#include "lsfg-vk-common/vulkan/vulkan.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace lsfgvk::cli; +using namespace lsfgvk::cli::debug; + +namespace { + /// uploads an image from a dds file + void upload_image(const vk::Vulkan& vk, + const vk::Image& image, const std::string& path) { + // read image bytecode + std::ifstream file(path.data(), std::ios::binary | std::ios::ate); + if (!file.is_open()) + throw ls::error("ifstream::ifstream() failed"); + + std::streamsize size = file.tellg(); + size -= 124 + 4; // dds header and magic bytes + + std::vector code(static_cast(size)); + file.seekg(124 + 4, std::ios::beg); + if (!file.read(code.data(), size)) + throw ls::error("ifstream::read() failed"); + + file.close(); + + // upload to image + const vk::Buffer stagingbuf{vk, code.data(), code.size(), + VK_BUFFER_USAGE_TRANSFER_SRC_BIT}; + + const vk::CommandBuffer cmdbuf{vk}; + cmdbuf.begin(vk); + cmdbuf.copyBufferToImage(vk, stagingbuf, image); + cmdbuf.end(vk); + + const vk::TimelineSemaphore sema{vk, 0}; + cmdbuf.submit(vk); + } +} + +int debug::run(const Options& opts) { + try { + // parse options + if (opts.flow < 0.25F || opts.flow > 1.0F) + throw ls::error("flow scale must be between 0.25 and 1.0"); + if (opts.multiplier < 2) + throw ls::error("multiplier must be 2 or greater"); + if (opts.width <= 0 || opts.height <= 0) + throw ls::error("width and height must be positive integers"); + const VkExtent2D extent{ + static_cast(opts.width), + static_cast(opts.height) + }; + if (!std::filesystem::exists(opts.path)) + throw ls::error("debug path does not exist: " + opts.path.string()); + std::vector paths{}; + for (const auto& entry : std::filesystem::directory_iterator(opts.path)) + paths.push_back(entry.path()); + std::ranges::sort(paths, [](const std::filesystem::path& a, const std::filesystem::path& b) { + auto fa = a.filename().string(); + auto fb = b.filename().string(); + + auto norm_a = fa.find_first_of('.'); + if (norm_a == std::string::npos) + throw ls::error("invalid debug file name: " + fa); + auto norm_b = fb.find_first_of('.'); + if (norm_b == std::string::npos) + throw ls::error("invalid debug file name: " + fb); + + return std::stoi(fa.substr(0, norm_a)) < std::stoi(fb.substr(0, norm_b)); + }); + + // create instance + const vk::Vulkan vk{ + "lsfg-vk-debug", vk::version{2, 0, 0}, + "lsfg-vk-debug-engine", vk::version{2, 0, 0}, + [opts](const vk::VulkanInstanceFuncs fi, + const std::vector& devices) { + if (!opts.gpu.has_value()) + return devices.front(); + + for (const VkPhysicalDevice& device : devices) { + VkPhysicalDeviceProperties2 props{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 + }; + fi.GetPhysicalDeviceProperties2(device, &props); + + auto& properties = props.properties; + std::array devname = std::to_array(properties.deviceName); + devname[255] = '\0'; // ensure null-termination + + if (std::string(devname.data()) == *opts.gpu) + return device; + } + + throw ls::error("failed to find specified GPU: " + *opts.gpu); + } + }; + + std::pair srcfds{}; + const vk::Image frame_0{vk, + extent, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + std::nullopt, &srcfds.first}; + const vk::Image frame_1{vk, + extent, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + std::nullopt, &srcfds.second}; + + std::vector destimgs{}; + std::vector destfds{}; + for (int i = 0; i < (opts.multiplier - 1); i++) { + int fd{}; + destimgs.emplace_back(vk, + extent, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + std::nullopt, + &fd + ); + destfds.push_back(fd); + } + + int syncfd{}; + const vk::TimelineSemaphore sync{vk, 0, std::nullopt, &syncfd}; + + // initialize backend + std::string dll{}; + if (opts.dll.has_value()) + dll = *opts.dll; + else + dll = ls::findShaderDll(); + lsfgvk::backend::Instance lsfgvk{ + [opts]( + const std::string& gpu_name, + std::pair, + const std::optional& + ) { + return opts.gpu.value_or(gpu_name) == gpu_name; + }, + dll, opts.allow_fp16 + }; + lsfgvk::backend::Context& lsfgvk_ctx = lsfgvk.openContext( + srcfds, destfds, + syncfd, extent.width, extent.height, + false, 1.0F / opts.flow, opts.performance_mode + ); + + // render destination images + size_t idx{1}; + for (size_t j = 0; j < paths.size(); j++) { + upload_image(vk, + j % 2 == 0 ? frame_0 : frame_1, + paths.at(j).string() + ); + + sync.signal(vk, idx++); + lsfgvk.scheduleFrames(lsfgvk_ctx); + + for (size_t i = 0; i < destimgs.size(); i++) { + auto success = sync.wait(vk, idx++); + if (!success) + throw ls::error("failed to wait for frame"); + } + } + + // deinitialize lsfg-vk + lsfgvk.closeContext(lsfgvk_ctx); + return EXIT_SUCCESS; + } catch (const std::exception& e) { + std::cerr << "error: " << e.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/lsfg-vk-cli/src/tools/debug.hpp b/lsfg-vk-cli/src/tools/debug.hpp new file mode 100644 index 0000000..631034a --- /dev/null +++ b/lsfg-vk-cli/src/tools/debug.hpp @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#pragma once + +#include +#include +#include + +namespace lsfgvk::cli::debug { + + /// options for the "debug" command + struct Options { + std::optional dll; + bool allow_fp16{true}; + int width{1920}; + int height{1080}; + + float flow{0.85F}; + int multiplier{2}; + bool performance_mode{true}; + std::optional gpu; + + std::filesystem::path path; + }; + + /// run the "debug" command + /// @param opts the command options + int run(const Options& opts); + +} diff --git a/lsfg-vk-cli/src/tools/validate.cpp b/lsfg-vk-cli/src/tools/validate.cpp new file mode 100644 index 0000000..94542db --- /dev/null +++ b/lsfg-vk-cli/src/tools/validate.cpp @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "validate.hpp" +#include "lsfg-vk-common/configuration/config.hpp" + +#include +#include +#include + +using namespace lsfgvk::cli; +using namespace lsfgvk::cli::validate; + +int validate::run(const Options& opts) { + std::filesystem::path path{ls::findConfigurationFile()}; + if (opts.config.has_value()) + path = *opts.config; + + if (!std::filesystem::exists(path)) { + std::cerr << "Validation failed: configuration file does not exist\n"; + return 1; + } + + try { + const ls::ConfigFile config{path}; + std::cerr << "Validation success\n"; + } catch (const std::exception& e) { + std::cerr << "Validation failed: " << e.what() << '\n'; + return 1; + } + return 0; +} diff --git a/lsfg-vk-cli/src/tools/validate.hpp b/lsfg-vk-cli/src/tools/validate.hpp new file mode 100644 index 0000000..ee6d400 --- /dev/null +++ b/lsfg-vk-cli/src/tools/validate.hpp @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#pragma once + +#include +#include + +namespace lsfgvk::cli::validate { + + /// options for the "validate" command + struct Options { + std::optional config; + }; + + /// run the "validate" command + /// @param opts the command options + int run(const Options& opts); + +} diff --git a/lsfg-vk-common/CMakeLists.txt b/lsfg-vk-common/CMakeLists.txt index f422863..b03c78d 100644 --- a/lsfg-vk-common/CMakeLists.txt +++ b/lsfg-vk-common/CMakeLists.txt @@ -2,6 +2,7 @@ set(COMMON_SOURCES "src/configuration/config.cpp" "src/configuration/detection.cpp" "src/helpers/errors.cpp" + "src/helpers/paths.cpp" "src/vulkan/buffer.cpp" "src/vulkan/command_buffer.cpp" "src/vulkan/descriptor_pool.cpp" diff --git a/lsfg-vk-common/include/lsfg-vk-common/helpers/paths.hpp b/lsfg-vk-common/include/lsfg-vk-common/helpers/paths.hpp new file mode 100644 index 0000000..d51225e --- /dev/null +++ b/lsfg-vk-common/include/lsfg-vk-common/helpers/paths.hpp @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#pragma once + +#include + +namespace ls { + + /// find the location of the Lossless.dll + /// @returns the path to the DLL + /// @throws ls::error if the DLL could not be found + std::filesystem::path findShaderDll(); + +} diff --git a/lsfg-vk-common/src/helpers/paths.cpp b/lsfg-vk-common/src/helpers/paths.cpp new file mode 100644 index 0000000..c9ac7ec --- /dev/null +++ b/lsfg-vk-common/src/helpers/paths.cpp @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "lsfg-vk-common/helpers/paths.hpp" +#include "lsfg-vk-common/helpers/errors.hpp" + +#include +#include +#include + +std::filesystem::path ls::findShaderDll() { + const std::vector FRAGMENTS{{ + ".local/share/Steam/steamapps/common", + ".steam/steam/steamapps/common", + ".steam/debian-installation/steamapps/common", + ".var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/common", + "snap/steam/common/.local/share/Steam/steamapps/common" + }}; + + // check XDG overridden location + const char* xdgPath = std::getenv("XDG_DATA_HOME"); + if (xdgPath && *xdgPath != '\0') { + auto base = std::filesystem::path(xdgPath); + + for (const auto& frag : FRAGMENTS) { + auto full = base / frag / "Lossless Scaling" / "Lossless.dll"; + if (std::filesystem::exists(full)) + return full; + } + } + + // check home directory + const char* homePath = std::getenv("HOME"); + if (homePath && *homePath != '\0') { + auto base = std::filesystem::path(homePath); + + for (const auto& frag : FRAGMENTS) { + auto full = base / frag / "Lossless Scaling" / "Lossless.dll"; + if (std::filesystem::exists(full)) + return full; + } + } + + // fallback to same directory + auto local = std::filesystem::current_path() / "Lossless.dll"; + if (std::filesystem::exists(local)) + return local; + + throw ls::error("unable to locate Lossless.dll, please set the path in the configuration"); +} diff --git a/lsfg-vk-debug/CMakeLists.txt b/lsfg-vk-debug/CMakeLists.txt deleted file mode 100644 index 1dd5646..0000000 --- a/lsfg-vk-debug/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -set(DEBUG_SOURCES - "src/debug.cpp") - -add_executable(lsfg-vk-debug ${DEBUG_SOURCES}) - -target_link_libraries(lsfg-vk-debug - PUBLIC lsfg-vk-common - PUBLIC lsfg-vk-backend) diff --git a/lsfg-vk-debug/src/debug.cpp b/lsfg-vk-debug/src/debug.cpp deleted file mode 100644 index a2a107f..0000000 --- a/lsfg-vk-debug/src/debug.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "lsfg-vk-backend/lsfgvk.hpp" -#include "lsfg-vk-common/vulkan/buffer.hpp" -#include "lsfg-vk-common/vulkan/command_buffer.hpp" -#include "lsfg-vk-common/vulkan/image.hpp" -#include "lsfg-vk-common/vulkan/timeline_semaphore.hpp" -#include "lsfg-vk-common/vulkan/vulkan.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include // NOLINT (thanks clang-tidy) - -#include - -const VkExtent2D EXTENT = { 1920, 1080 }; - -namespace { - /// returns the current time in microseconds - uint64_t get_current_time_us() { - struct timespec ts{}; - clock_gettime(CLOCK_MONOTONIC, &ts); - - return static_cast(ts.tv_sec) * 1000000UL - + static_cast(ts.tv_nsec) / 1000UL; - } - /// uploads an image from a dds file - void upload_image( - const vk::Vulkan& vk, - const vk::Image& image, - const std::string& path - ) { - // read image bytecode - std::ifstream file(path.data(), std::ios::binary | std::ios::ate); - if (!file.is_open()) - throw std::runtime_error("ifstream::ifstream() failed"); - - std::streamsize size = file.tellg(); - size -= 124 + 4; // dds header and magic bytes - - std::vector code(static_cast(size)); - file.seekg(124 + 4, std::ios::beg); - if (!file.read(code.data(), size)) - throw std::runtime_error("ifstream::read() failed"); - - file.close(); - - // upload to image - const vk::Buffer stagingbuf{vk, code.data(), code.size(), - VK_BUFFER_USAGE_TRANSFER_SRC_BIT}; - - const vk::CommandBuffer cmdbuf{vk}; - cmdbuf.begin(vk); - cmdbuf.copyBufferToImage(vk, stagingbuf, image); - cmdbuf.end(vk); - - const vk::TimelineSemaphore sema{vk, 0}; - cmdbuf.submit(vk); - } -} - -int main() { - const uint64_t time_us = get_current_time_us(); - - const vk::Vulkan vk{ - "lsfg-vk-debug", vk::version{2, 0, 0}, - "lsfg-vk-debug-engine", vk::version{2, 0, 0}, - [](const vk::VulkanInstanceFuncs, - const std::vector& devices) { - return devices.front(); - } - }; - - std::pair srcfds{}; - const vk::Image frame_0{vk, - EXTENT, VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - std::nullopt, - &srcfds.first - }; - const vk::Image frame_1{vk, - EXTENT, VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - std::nullopt, - &srcfds.second - }; - - std::vector destimgs{}; - std::vector destfds{}; - for (size_t i = 0; i < 4; i++) { - int fd{}; - destimgs.emplace_back(vk, - EXTENT, VK_FORMAT_R8G8B8A8_UNORM, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - std::nullopt, - &fd - ); - destfds.push_back(fd); - } - - int syncfd{}; - const vk::TimelineSemaphore sync{vk, 0, std::nullopt, &syncfd}; - - const uint64_t init_done_us = get_current_time_us(); - std::cerr << "vulkan initialized in " - << (init_done_us - time_us) << "us\n"; - - // initialize lsfg-vk - lsfgvk::backend::Instance lsfgvk{ - []( - const std::string&, - std::pair, - const std::optional& - ) { - return true; - }, - "/home/pancake/.steam/steam/steamapps/common/Lossless Scaling/Lossless.dll", - true - }; - lsfgvk::backend::Context& lsfgvk_ctx = lsfgvk.openContext( - srcfds, destfds, - syncfd, EXTENT.width, EXTENT.height, - false, 1.0F / 0.5F, true - ); - - const uint64_t lsfg_init_done_us = get_current_time_us(); - std::cerr << "lsfg-vk initialized in " - << (lsfg_init_done_us - init_done_us) << "us\n"; - - // render destination images - size_t idx{1}; - for (size_t j = 0; j < 3; j++) { - try { - upload_image(vk, - j % 2 == 0 ? frame_0 : frame_1, - "s" + std::to_string(j + 1) + ".dds" - ); - } catch (const std::exception& e) { - std::cerr << "failed to upload image: " << e.what() << "\n"; - return EXIT_FAILURE; - } - - sync.signal(vk, idx++); - lsfgvk.scheduleFrames(lsfgvk_ctx); - - for (size_t i = 0; i < destimgs.size(); i++) { - auto success = sync.wait(vk, idx++); - if (!success) { - std::cerr << "failed to wait for frame " << j << ":" << i << "\n"; - return EXIT_FAILURE; - } - - const uint64_t frame_done_us = get_current_time_us(); - std::cerr << "frame " << j << ":" << i << " done after " - << (frame_done_us - lsfg_init_done_us) << "us\n"; - } - } - - // deinitialize lsfg-vk - lsfgvk.closeContext(lsfgvk_ctx); - return EXIT_SUCCESS; // let the vulkan objects go out of scope -} diff --git a/lsfg-vk-layer/src/instance.cpp b/lsfg-vk-layer/src/instance.cpp index 145c8c0..8ef93f5 100644 --- a/lsfg-vk-layer/src/instance.cpp +++ b/lsfg-vk-layer/src/instance.cpp @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ #include "instance.hpp" +#include "lsfg-vk-common/helpers/paths.hpp" #include "swapchain.hpp" #include "lsfg-vk-common/configuration/detection.hpp" #include "lsfg-vk-common/helpers/errors.hpp" @@ -10,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -41,47 +41,6 @@ namespace { return extensions; } - // find the shader dll - std::filesystem::path findShaderDll() { - const std::vector FRAGMENTS{{ - ".local/share/Steam/steamapps/common", - ".steam/steam/steamapps/common", - ".steam/debian-installation/steamapps/common", - ".var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/common", - "snap/steam/common/.local/share/Steam/steamapps/common" - }}; - - // check XDG overridden location - const char* xdgPath = std::getenv("XDG_DATA_HOME"); - if (xdgPath && *xdgPath != '\0') { - auto base = std::filesystem::path(xdgPath); - - for (const auto& frag : FRAGMENTS) { - auto full = base / frag / "Lossless Scaling" / "Lossless.dll"; - if (std::filesystem::exists(full)) - return full; - } - } - - // check home directory - const char* homePath = std::getenv("HOME"); - if (homePath && *homePath != '\0') { - auto base = std::filesystem::path(homePath); - - for (const auto& frag : FRAGMENTS) { - auto full = base / frag / "Lossless Scaling" / "Lossless.dll"; - if (std::filesystem::exists(full)) - return full; - } - } - - // fallback to same directory - auto local = std::filesystem::current_path() / "Lossless.dll"; - if (std::filesystem::exists(local)) - return local; - - throw ls::error("unable to locate Lossless.dll, please set the path in the configuration"); - } } Root::Root() { @@ -216,6 +175,12 @@ void Root::createSwapchainContext(const vk::Vulkan& vk, setenv("DISABLE_LSFGVK", "1", 1); // NOLINT (c++-include) try { + std::string dll{}; + if (global.dll.has_value()) + dll = *global.dll; + else + dll = ls::findShaderDll(); + this->backend.emplace( [gpu = profile.gpu]( const std::string& deviceName, @@ -229,8 +194,7 @@ void Root::createSwapchainContext(const vk::Vulkan& vk, || (ids.first + ":" + ids.second == *gpu) || (pci && *pci == *gpu); }, - global.dll.value_or(findShaderDll()), - global.allow_fp16 + dll, global.allow_fp16 ); } catch (const std::exception& e) { unsetenv("DISABLE_LSFGVK"); // NOLINT (c++-include) diff --git a/src/utils/benchmark.cpp b/src/utils/benchmark.cpp deleted file mode 100644 index 099e888..0000000 --- a/src/utils/benchmark.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "utils/benchmark.hpp" -#include "config/config.hpp" -#include "extract/extract.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Benchmark; - -void Benchmark::run(uint32_t width, uint32_t height) { - if (!Config::currentConf.has_value()) - _exit(1); // not possible - const auto& globalConf = Config::globalConf; - const auto& conf = *Config::currentConf; - - auto* lsfgInitialize = LSFG_3_1::initialize; - auto* lsfgCreateContext = LSFG_3_1::createContext; - auto* lsfgPresentContext = LSFG_3_1::presentContext; - if (conf.performance) { - lsfgInitialize = LSFG_3_1P::initialize; - lsfgCreateContext = LSFG_3_1P::createContext; - lsfgPresentContext = LSFG_3_1P::presentContext; - } - - // create the benchmark context - const char* lsfgDeviceUUID = std::getenv("LSFG_DEVICE_UUID"); - const uint64_t deviceUUID = lsfgDeviceUUID - ? std::stoull(std::string(lsfgDeviceUUID), nullptr, 16) : 0x1463ABAC; - - setenv("DISABLE_LSFG", "1", 1); // NOLINT - - Extract::extractShaders(); - lsfgInitialize( - deviceUUID, // some magic number if not given - conf.hdr, 1.0F / conf.flowScale, conf.multiplier - 1, - globalConf.no_fp16, - Extract::getShader - ); - const int32_t ctx = lsfgCreateContext(-1, -1, {}, - { .width = width, .height = height }, - conf.hdr ? VK_FORMAT_R16G16B16A16_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM - ); - - unsetenv("DISABLE_LSFG"); // NOLINT - - // run the benchmark (run 8*n + 1 so the fences are waited on) - const auto now = std::chrono::high_resolution_clock::now(); - const uint64_t iterations = 8 * 500UL; - - std::cerr << "lsfg-vk: Benchmark started, running " << iterations << " iterations...\n"; - for (uint64_t count = 0; count < iterations + 1; count++) { - lsfgPresentContext(ctx, -1, {}); - - if (count % 50 == 0 && count > 0) - std::cerr << "lsfg-vk: " - << std::setprecision(2) << std::fixed - << static_cast(count) / static_cast(iterations) * 100.0F - << "% done (" << count + 1 << "/" << iterations << ")\r"; - } - const auto then = std::chrono::high_resolution_clock::now(); - - // print results - const auto ms = std::chrono::duration_cast(then - now).count(); - - const auto perIteration = static_cast(ms) / static_cast(iterations); - - const uint64_t totalGen = (conf.multiplier - 1) * iterations; - const auto genFps = static_cast(totalGen) / (static_cast(ms) / 1000.0F); - - const uint64_t totalFrames = iterations * conf.multiplier; - const auto totalFps = static_cast(totalFrames) / (static_cast(ms) / 1000.0F); - - std::cerr << "lsfg-vk: Benchmark completed in " << ms << " ms\n"; - std::cerr << " Time taken per real frame: " - << std::setprecision(2) << std::fixed << perIteration << " ms\n"; - std::cerr << " Generated " << totalGen << " frames in total at " - << std::setprecision(2) << std::fixed << genFps << " FPS\n"; - std::cerr << " Total of " << totalFrames << " frames presented at " - << std::setprecision(2) << std::fixed << totalFps << " FPS\n"; - - // sleep for a second, then exit - std::this_thread::sleep_for(std::chrono::seconds(1)); - _exit(0); -}