feat(bindless): Implement backend changes in lsfg-vk-ui

This commit is contained in:
PancakeTAS 2026-04-25 22:55:30 +02:00
parent cee1b7b714
commit fd0746c049
No known key found for this signature in database
6 changed files with 103 additions and 58 deletions

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -9,14 +9,18 @@
#include "lsfg-vk-common/configuration/config.hpp"
#include <atomic>
#include <cstddef>
#include <optional>
#include <stdexcept>
#include <utility>
#include <vector>
#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

View file

@ -5,63 +5,100 @@
#include <QString>
#include "utils.hpp"
#include "lsfg-vk-backend/lsfgvk.hpp"
#include <algorithm>
#include <optional>
#include <stdexcept>
#include <cstddef>
#include <iomanip>
#include <ios>
#include <sstream>
#include <string>
#include <utility>
#include <unordered_map>
#include <vector>
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
#define VULKAN_HPP_NO_DEFAULT_DISPATCHER 1
#define VULKAN_HPP_NO_CONSTRUCTORS 1
#include <vulkan/vulkan.hpp>
using namespace lsfgvk;
using namespace lsfgvk::ui;
QStringList ui::getAvailableGPUs() {
// list of found GPUs and their optional PCI IDs
std::vector<std::pair<std::string, std::optional<std::string>>> 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::string&, const std::string&>,
const std::optional<std::string>& 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<std::string> devicesByName{};
std::vector<std::string> 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<std::string, size_t> 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);

View file

@ -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();
}