#pragma once #include "../examples/glfw.hpp" #include "../examples/utils.hpp" #include "vuk/AllocatorHelpers.hpp" #include "vuk/CommandBuffer.hpp" #include "vuk/Context.hpp" #include "vuk/RenderGraph.hpp" #include "vuk/SampledImage.hpp" #include "vuk/resources/DeviceFrameResource.hpp" #include #include #include #include #include #include #include #include namespace vuk { struct BenchRunner; struct CaseBase { std::string_view label; std::vector subcase_labels; std::vector> subcases; std::vector> timings; std::vector> binned; std::vector last_stage_ran; std::vector runs_required; std::vector est_mean; std::vector est_variance; std::vector> min_max; std::vector mean; std::vector variance; }; struct BenchBase { std::string_view name; std::function setup; std::function gui; std::function cleanup; std::function get_case; size_t num_cases; }; template struct Bench { BenchBase base; using Params = std::tuple; struct Case : CaseBase { template Case(std::string_view label, F&& subcase_template) : CaseBase{ label } { std::apply( [this, subcase_template](auto&&... ts) { (subcases.emplace_back([=](BenchRunner& runner, vuk::Allocator& frame_allocator, Query start, Query end) { return subcase_template(runner, frame_allocator, start, end, ts); }), ...); (subcase_labels.emplace_back(ts.description), ...); timings.resize(sizeof...(Args)); runs_required.resize(sizeof...(Args)); mean.resize(sizeof...(Args)); variance.resize(sizeof...(Args)); est_mean.resize(sizeof...(Args)); est_variance.resize(sizeof...(Args)); last_stage_ran.resize(sizeof...(Args)); min_max.resize(sizeof...(Args)); binned.resize(sizeof...(Args)); }, Params{}); } }; std::vector cases; }; } // namespace vuk namespace vuk { struct BenchRunner { VkDevice device; VkPhysicalDevice physical_device; VkQueue graphics_queue; std::optional context; std::optional xdev_rf_alloc; std::optional global; vuk::SwapchainRef swapchain; GLFWwindow* window; VkSurfaceKHR surface; vkb::Instance vkbinstance; vkb::Device vkbdevice; util::ImGuiData imgui_data; plf::colony sampled_images; Query start, end; unsigned current_case = 0; unsigned current_subcase = 0; unsigned current_stage = 0; unsigned num_runs = 0; BenchBase* bench; BenchRunner(); void setup() { // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); // Setup Dear ImGui style ImGui::StyleColorsDark(); // Setup Platform/Renderer bindings ImGui_ImplGlfw_InitForVulkan(window, true); start = context->create_timestamp_query(); end = context->create_timestamp_query(); { imgui_data = util::ImGui_ImplVuk_Init(*global); } bench->setup(*this, *global); } void render(); void cleanup() { context->wait_idle(); if (bench->cleanup) { bench->cleanup(*this, *global); } } ~BenchRunner() { imgui_data.font_texture.view.reset(); imgui_data.font_texture.image.reset(); xdev_rf_alloc.reset(); context.reset(); vkDestroySurfaceKHR(vkbinstance.instance, surface, nullptr); destroy_window_glfw(window); vkb::destroy_device(vkbdevice); vkb::destroy_instance(vkbinstance); } static BenchRunner& get_runner() { static BenchRunner runner; return runner; } }; } // namespace vuk namespace util { struct Register { template Register(vuk::Bench& x) { vuk::BenchRunner::get_runner().bench = &x.base; vuk::BenchRunner::get_runner().bench->get_case = [&x](unsigned i) -> vuk::CaseBase& { return x.cases[i]; }; vuk::BenchRunner::get_runner().bench->num_cases = x.cases.size(); } }; } // namespace util #define CONCAT_IMPL(x, y) x##y #define MACRO_CONCAT(x, y) CONCAT_IMPL(x, y) #define REGISTER_BENCH(x) util::Register MACRO_CONCAT(_reg_, __LINE__)(x)