From fd0746c0498d355b0b0039f187734fa0ee5ce386 Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Sat, 25 Apr 2026 22:55:30 +0200 Subject: [PATCH] feat(bindless): Implement backend changes in lsfg-vk-ui --- lsfg-vk-ui/.clang-tidy | 2 + lsfg-vk-ui/CMakeLists.txt | 5 +- lsfg-vk-ui/src/backend.cpp | 21 +++---- lsfg-vk-ui/src/backend.hpp | 6 +- lsfg-vk-ui/src/utils.cpp | 117 ++++++++++++++++++++++++------------- lsfg-vk-ui/src/utils.hpp | 10 ++-- 6 files changed, 103 insertions(+), 58 deletions(-) diff --git a/lsfg-vk-ui/.clang-tidy b/lsfg-vk-ui/.clang-tidy index 042dd46..33a11dd 100644 --- a/lsfg-vk-ui/.clang-tidy +++ b/lsfg-vk-ui/.clang-tidy @@ -25,3 +25,5 @@ Checks: - -portability-avoid-pragma-once # Qt requires use of raw pointers in many places - -cppcoreguidelines-owning-memory +# Qt seems to break some ranges algorithms in GCC +- -modernize-use-ranges diff --git a/lsfg-vk-ui/CMakeLists.txt b/lsfg-vk-ui/CMakeLists.txt index 39602ea..335c516 100644 --- a/lsfg-vk-ui/CMakeLists.txt +++ b/lsfg-vk-ui/CMakeLists.txt @@ -30,12 +30,11 @@ set_target_properties(lsfg-vk-ui PROPERTIES target_compile_options(lsfg-vk-ui PRIVATE # QT-codegen warnings -Wno-ctad-maybe-unsupported -Wno-unsafe-buffer-usage-in-libc-call - -Wno-global-constructors - -Wno-unsafe-buffer-usage) + -Wno-unsafe-buffer-usage + -Wno-global-constructors) target_link_libraries(lsfg-vk-ui PRIVATE lsfg-vk-common - PRIVATE lsfg-vk-backend PRIVATE Qt6::Quick) install(TARGETS lsfg-vk-ui diff --git a/lsfg-vk-ui/src/backend.cpp b/lsfg-vk-ui/src/backend.cpp index 646ba25..e19c579 100644 --- a/lsfg-vk-ui/src/backend.cpp +++ b/lsfg-vk-ui/src/backend.cpp @@ -19,7 +19,7 @@ using namespace lsfgvk; using namespace lsfgvk::ui; Backend::Backend() { - // load configuration + // Load existing configuration ls::ConfigFile config{}; auto path = ls::findConfigurationFile(); @@ -27,7 +27,8 @@ Backend::Backend() { try { config = ls::ConfigFile(path); } catch (const std::exception&) { - std::cerr << "the configuration file is invalid, it has been backed up to '.old'\n"; + std::cerr << "The existing configuration file is invalid, " + << "it has been backed up to '.old'\n"; std::filesystem::rename(path, path.string() + ".old"); } } @@ -35,17 +36,17 @@ Backend::Backend() { this->m_global = config.global(); this->m_profiles = config.profiles(); - // create gpu list - this->m_gpu_list = ui::getAvailableGPUs(); + // Create gpu list + this->m_gpu_list = ui::queryGPUs(); - // create profile list model + // Create profile list model QStringList profiles; for (const auto& profile : this->m_profiles) profiles.append(QString::fromStdString(profile.name)); this->m_profile_list_model = new QStringListModel(profiles, this); - // create active_in list models + // Create active_in list models this->m_active_in_list_models.reserve(this->m_profiles.size()); for (const auto& profile : this->m_profiles) { QStringList active_in; @@ -55,11 +56,11 @@ Backend::Backend() { this->m_active_in_list_models.push_back(new QStringListModel(active_in, this)); } - // try to select first profile + // Try to select first profile if (!this->m_profiles.empty()) this->m_profile_index = 0; - // spawn saving thread + // Spawn saving thread std::thread([this, path]() { while (true) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); @@ -74,10 +75,10 @@ Backend::Backend() { try { std::filesystem::create_directories(path.parent_path()); if (!std::filesystem::exists(path.parent_path())) - throw ls::error("unable to create configuration directory"); + throw ls::error("Unable to create configuration directory"); config.write(path); } catch (const std::exception& e) { - std::cerr << "unable to write configuration:\n- " << e.what() << "\n"; + std::cerr << "Unable to write configuration:\n- " << e.what() << "\n"; } } }).detach(); diff --git a/lsfg-vk-ui/src/backend.hpp b/lsfg-vk-ui/src/backend.hpp index 9eed642..7c35818 100644 --- a/lsfg-vk-ui/src/backend.hpp +++ b/lsfg-vk-ui/src/backend.hpp @@ -9,14 +9,18 @@ #include "lsfg-vk-common/configuration/config.hpp" #include +#include +#include +#include #include +#include #define getters public #define setters public namespace lsfgvk::ui { - /// Class tying ui and configuration together + /// Class tying UI and Configuration together class Backend : public QObject { Q_OBJECT diff --git a/lsfg-vk-ui/src/utils.cpp b/lsfg-vk-ui/src/utils.cpp index 0866b48..f5371e2 100644 --- a/lsfg-vk-ui/src/utils.cpp +++ b/lsfg-vk-ui/src/utils.cpp @@ -5,63 +5,100 @@ #include #include "utils.hpp" -#include "lsfg-vk-backend/lsfgvk.hpp" -#include -#include -#include +#include +#include +#include +#include #include -#include +#include #include +#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 +#define VULKAN_HPP_NO_DEFAULT_DISPATCHER 1 +#define VULKAN_HPP_NO_CONSTRUCTORS 1 +#include + using namespace lsfgvk; using namespace lsfgvk::ui; -QStringList ui::getAvailableGPUs() { - // list of found GPUs and their optional PCI IDs - std::vector>> gpus{}; +QStringList ui::queryGPUs() { + // Create a Vulkan instance + vk::detail::DispatchLoaderDynamic dld; + dld.init(); - // create a backend to query all GPUs - try { - const backend::DevicePicker picker{[&gpus]( - const std::string& deviceName, - std::pair, - const std::optional& pci - ) { - gpus.emplace_back(deviceName, pci); - return false; // always fail - }}; + const vk::ApplicationInfo appInfo{ + .pApplicationName = "lsfg-vk-ui", + .applicationVersion = vk::makeVersion(2, 0, 0), + .pEngineName = "lsfg-vk-ui", + .engineVersion = vk::makeVersion(2, 0, 0), + .apiVersion = vk::ApiVersion12 // Required by lsfg-vk anyways + }; + const vk::InstanceCreateInfo instanceInfo{ + .pApplicationInfo = &appInfo + }; + const vk::UniqueInstance instance{vk::createInstanceUnique(instanceInfo, nullptr, dld)}; + dld.init(*instance); - const backend::Instance instance{picker, "/non/existent/path", false}; - throw std::runtime_error("???"); - } catch (const backend::error&) { // NOLINT (empty catch) - // expected + // Query physical devices + std::vector devicesByName{}; + std::vector devicesByBusId{}; + + for (const auto& physdev : instance->enumeratePhysicalDevices(dld)) { + // Check for VK_EXT_pci_bus_info + bool supportsPCIEXT{false}; + for (const auto& ext : physdev.enumerateDeviceExtensionProperties(nullptr, dld)) { + if (std::string(ext.extensionName) != vk::EXTPciBusInfoExtensionName) + continue; + + supportsPCIEXT = true; + break; + } + + // Fetch properties + vk::PhysicalDevicePCIBusInfoPropertiesEXT busInfo{}; + vk::PhysicalDeviceProperties2 info{ + .pNext = supportsPCIEXT ? &busInfo : nullptr + }; + physdev.getProperties2(&info, dld); + + auto& props{info.properties}; + + // Append device name + props.deviceName.back() = '\0'; // Ensure null-termination + devicesByName.emplace_back(props.deviceName); + + // Append PCI bus ID + if (!supportsPCIEXT) + continue; + + std::ostringstream pciss; + pciss << std::hex << std::setfill('0') + << std::setw(4) << busInfo.pciDomain << ":" + << std::setw(2) << busInfo.pciBus << ":" + << std::setw(2) << busInfo.pciDevice << "." + << std::setw(1) << busInfo.pciFunction; + devicesByBusId.emplace_back(pciss.str()); } - // NOLINTBEGIN (ranges) [GCC has some issues with ranges] - // first remove 1:1 duplicates - std::sort(gpus.begin(), gpus.end()); - gpus.erase(std::unique(gpus.begin(), gpus.end()), gpus.end()); - // NOLINTEND + // Count duplicate names + std::unordered_map repeats{}; + for (const auto& name : devicesByName) + repeats[name]++; - // build the frontend list + // Build the frontend list QStringList list{"Default"}; - for (const auto& gpu : gpus) { - // check if GPU is in list more than once - auto count = std::count_if(gpus.begin(), gpus.end(), - [&gpu](const auto& other) { - return other.first == gpu.first; - } - ); + for (size_t i = 0; i < devicesByName.size(); i++) { + const auto& name{devicesByName.at(i)}; - // add pci id to distinguish, otherwise add just the name + // Decide whether to show PCI bus ID or device name QString entry; - if (count > 1 && gpu.second.has_value()) - entry = QString::fromStdString(*gpu.second); + if (repeats[name] > 1) + entry = QString::fromStdString(devicesByBusId.at(i)); else - entry = QString::fromStdString(gpu.first); + entry = QString::fromStdString(name); - // ensure no duplicates (flatpak does funny things) + // Append to list if not already present (flatpak does funny things) if (list.contains(entry)) continue; list.append(entry); diff --git a/lsfg-vk-ui/src/utils.hpp b/lsfg-vk-ui/src/utils.hpp index 4ccb312..c523a46 100644 --- a/lsfg-vk-ui/src/utils.hpp +++ b/lsfg-vk-ui/src/utils.hpp @@ -6,9 +6,11 @@ namespace lsfgvk::ui { - /// get the list of available GPUs, automatically - /// switching to PCI IDs if there are duplicates - /// @return list of available GPUs - QStringList getAvailableGPUs(); + /// + /// Query all GPUs available on the system. + /// + /// @return List of available GPUs + /// + QStringList queryGPUs(); }