From 83c3ce68b0c7f70b0ed293dc09dac9b2161f9da8 Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Mon, 15 Dec 2025 00:10:10 +0100 Subject: [PATCH] refactor(cleanup): proper device picker --- .../include/lsfg-vk-backend/lsfgvk.hpp | 12 +++++- lsfg-vk-backend/src/helpers/utils.cpp | 13 ++++++ lsfg-vk-backend/src/helpers/utils.hpp | 4 ++ lsfg-vk-backend/src/lsfgvk.cpp | 40 ++++++++++++++++--- .../include/lsfg-vk-common/vulkan/vulkan.hpp | 3 +- lsfg-vk-common/src/vulkan/vulkan.cpp | 6 ++- lsfg-vk-debug/src/debug.cpp | 6 ++- 7 files changed, 72 insertions(+), 12 deletions(-) diff --git a/lsfg-vk-backend/include/lsfg-vk-backend/lsfgvk.hpp b/lsfg-vk-backend/include/lsfg-vk-backend/lsfgvk.hpp index cd02dc8..28c5535 100644 --- a/lsfg-vk-backend/include/lsfg-vk-backend/lsfgvk.hpp +++ b/lsfg-vk-backend/include/lsfg-vk-backend/lsfgvk.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,13 @@ namespace lsfgvk { ~error() override; }; + /// Function type for picking a device based on its name and IDs + using DevicePicker = std::function ids, // (vendor ID, device ID) in 0xXXXX format + const std::optional& pci // (bus:slot.func) if available, no padded zeros + )>; + /// /// Main entry point of the library /// @@ -46,14 +54,14 @@ namespace lsfgvk { /// /// Create a lsfg-vk instance /// - /// @param devicePicker Function that picks a physical device based on its name. + /// @param devicePicker Function that picks a physical device based on its name or other identifiers. /// @param shaderDllPath Path to the Lossless.dll file to load shaders from. /// @param allowLowPrecision Whether to load low-precision (FP16) shaders if supported by the device. /// /// @throws lsfgvk::error on failure /// Instance( - const std::function& devicePicker, + const DevicePicker& devicePicker, const std::filesystem::path& shaderDllPath, bool allowLowPrecision ); diff --git a/lsfg-vk-backend/src/helpers/utils.cpp b/lsfg-vk-backend/src/helpers/utils.cpp index 3198724..4c7454d 100644 --- a/lsfg-vk-backend/src/helpers/utils.cpp +++ b/lsfg-vk-backend/src/helpers/utils.cpp @@ -1,7 +1,9 @@ #include "utils.hpp" +#include #include #include +#include #include @@ -32,3 +34,14 @@ VkExtent2D ls::add_shift_extent(VkExtent2D extent, uint32_t a, uint32_t i) { .height = (extent.height + a) >> i }; } + +std::string ls::to_hex_id(uint32_t id) { + const std::array chars = std::to_array("0123456789ABCDEF"); + + std::string result = "0x"; + result += chars.at((id >> 12) & 0xF); + result += chars.at((id >> 8) & 0xF); + result += chars.at((id >> 4) & 0xF); + result += chars.at(id & 0xF); + return result; +} diff --git a/lsfg-vk-backend/src/helpers/utils.hpp b/lsfg-vk-backend/src/helpers/utils.hpp index fcbefa8..5a22a3f 100644 --- a/lsfg-vk-backend/src/helpers/utils.hpp +++ b/lsfg-vk-backend/src/helpers/utils.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -70,4 +71,7 @@ namespace ls { /// @param i the amount to shift by /// @return the shifted extent VkExtent2D add_shift_extent(VkExtent2D extent, uint32_t a, uint32_t i); + + /// convert a device/vendor id into a hex string + std::string to_hex_id(uint32_t id); } diff --git a/lsfg-vk-backend/src/lsfgvk.cpp b/lsfg-vk-backend/src/lsfgvk.cpp index 6566e76..1f3f821 100644 --- a/lsfg-vk-backend/src/lsfgvk.cpp +++ b/lsfg-vk-backend/src/lsfgvk.cpp @@ -119,20 +119,48 @@ namespace lsfgvk { } Instance::Instance( - const std::function& devicePicker, + const DevicePicker& devicePicker, const std::filesystem::path& shaderDllPath, bool allowLowPrecision) { const auto selectFunc = [&devicePicker](const vk::VulkanInstanceFuncs funcs, const std::vector& devices) { for (const auto& device : devices) { - VkPhysicalDeviceProperties props; - funcs.GetPhysicalDeviceProperties(device, &props); + // check if the physical device supports VK_EXT_pci_bus_info + uint32_t ext_count{}; + funcs.EnumerateDeviceExtensionProperties(device, nullptr, &ext_count, nullptr); - std::array devname = std::to_array(props.deviceName); + std::vector extensions(ext_count); + funcs.EnumerateDeviceExtensionProperties(device, nullptr, &ext_count, extensions.data()); + + const bool has_pci_ext = std::ranges::find_if(extensions, + [](const VkExtensionProperties& ext) { + return std::string(std::to_array(ext.extensionName).data()) + == VK_EXT_PCI_BUS_INFO_EXTENSION_NAME; + }) != extensions.end(); + + // then fetch all available properties + VkPhysicalDevicePCIBusInfoPropertiesEXT pciInfo{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT + }; + VkPhysicalDeviceProperties2 props{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = has_pci_ext ? &pciInfo : nullptr + }; + funcs.GetPhysicalDeviceProperties2(device, &props); + + std::array devname = std::to_array(props.properties.deviceName); devname[255] = '\0'; // ensure null-termination - const std::string& deviceName{devname.data()}; - if (devicePicker(deviceName)) + if (devicePicker( + std::string(devname.data()), + { ls::to_hex_id(props.properties.vendorID), + ls::to_hex_id(props.properties.deviceID) }, + has_pci_ext ? std::optional{ + std::to_string(pciInfo.pciBus) + ":" + + std::to_string(pciInfo.pciDevice) + "." + + std::to_string(pciInfo.pciFunction) + } : std::nullopt + )) return device; } diff --git a/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp b/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp index 05c8b2a..4611b64 100644 --- a/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp +++ b/lsfg-vk-common/include/lsfg-vk-common/vulkan/vulkan.hpp @@ -17,7 +17,8 @@ namespace vk { struct VulkanInstanceFuncs { PFN_vkDestroyInstance DestroyInstance; PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices; - PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties; + PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties; + PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2; PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties; PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2; PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties; diff --git a/lsfg-vk-common/src/vulkan/vulkan.cpp b/lsfg-vk-common/src/vulkan/vulkan.cpp index 2c7e836..6391695 100644 --- a/lsfg-vk-common/src/vulkan/vulkan.cpp +++ b/lsfg-vk-common/src/vulkan/vulkan.cpp @@ -99,8 +99,10 @@ namespace { .DestroyInstance = ipa(mpa, i, "vkDestroyInstance"), .EnumeratePhysicalDevices = ipa(mpa, i, "vkEnumeratePhysicalDevices"), - .GetPhysicalDeviceProperties = ipa(mpa, i, - "vkGetPhysicalDeviceProperties"), + .EnumerateDeviceExtensionProperties = ipa(mpa, i, + "vkEnumerateDeviceExtensionProperties"), + .GetPhysicalDeviceProperties2 = ipa(mpa, i, + "vkGetPhysicalDeviceProperties2"), .GetPhysicalDeviceQueueFamilyProperties = ipa(mpa, i, "vkGetPhysicalDeviceQueueFamilyProperties"), diff --git a/lsfg-vk-debug/src/debug.cpp b/lsfg-vk-debug/src/debug.cpp index 9e87af2..8f4b1aa 100644 --- a/lsfg-vk-debug/src/debug.cpp +++ b/lsfg-vk-debug/src/debug.cpp @@ -119,7 +119,11 @@ int main() { // initialize lsfg-vk lsfgvk::Instance lsfgvk{ - [](const std::string&) { + []( + const std::string&, + std::pair, + const std::optional& + ) { return true; }, "/home/pancake/.steam/steam/steamapps/common/Lossless Scaling/Lossless.dll",