mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-05-10 11:11:40 +00:00
feat(bindless): Create Vulkan helper namespace
This commit is contained in:
parent
97faa0c067
commit
bd77a7917f
2 changed files with 258 additions and 0 deletions
157
lsfg-vk-backend/src/utility/vkhelper.cpp
Normal file
157
lsfg-vk-backend/src/utility/vkhelper.cpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#include "vkhelper.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
/* Device initialization */
|
||||
|
||||
vk::UniqueInstance vkhelper::createInstance(vk::detail::DispatchLoaderDynamic& dld) {
|
||||
dld.init();
|
||||
|
||||
const vk::ApplicationInfo appInfo{
|
||||
.pApplicationName = "lsfg-vk",
|
||||
.applicationVersion = vk::makeVersion(2, 0, 0),
|
||||
.pEngineName = "lsfg-vk",
|
||||
.engineVersion = vk::makeVersion(2, 0, 0),
|
||||
.apiVersion = vk::ApiVersion12 // Fully supported by all Vulkan-capable GPUs
|
||||
};
|
||||
const vk::InstanceCreateInfo instanceInfo{
|
||||
.pApplicationInfo = &appInfo
|
||||
};
|
||||
auto instance{vk::createInstanceUnique(instanceInfo, nullptr, dld)};
|
||||
dld.init(*instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
vk::PhysicalDevice vkhelper::findPhysicalDevice(
|
||||
const vk::detail::DispatchLoaderDynamic& dld,
|
||||
const vk::Instance& instance,
|
||||
const std::string& id
|
||||
) {
|
||||
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};
|
||||
|
||||
// Compare device name
|
||||
props.deviceName.back() = '\0'; // Ensure null-termination
|
||||
if (id == std::string(props.deviceName))
|
||||
return physdev;
|
||||
|
||||
// Compare Vendor ID + Device ID
|
||||
std::ostringstream gpuss;
|
||||
gpuss << std::hex << std::setfill('0')
|
||||
<< std::setw(4) << props.vendorID << ":"
|
||||
<< std::setw(4) << props.deviceID;
|
||||
if (id == gpuss.str())
|
||||
return physdev;
|
||||
|
||||
// Compare 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;
|
||||
if (id == pciss.str())
|
||||
return physdev;
|
||||
}
|
||||
|
||||
throw std::runtime_error("No physical device matching '" + id + "' found");
|
||||
}
|
||||
|
||||
uint32_t vkhelper::findComputeQueueFamilyIndex(
|
||||
const vk::detail::DispatchLoaderDynamic& dld,
|
||||
const vk::PhysicalDevice& physdev
|
||||
) {
|
||||
uint32_t idx{0};
|
||||
for (const auto& qfi : physdev.getQueueFamilyProperties2(dld)) {
|
||||
if (qfi.queueFamilyProperties.queueFlags & vk::QueueFlagBits::eCompute)
|
||||
return idx;
|
||||
idx++;
|
||||
}
|
||||
|
||||
throw std::runtime_error("No compute-capable queue family found");
|
||||
}
|
||||
|
||||
bool vkhelper::checkHalfPrecisionSupport(
|
||||
const vk::detail::DispatchLoaderDynamic& dld,
|
||||
const vk::PhysicalDevice& physdev
|
||||
) {
|
||||
vk::PhysicalDeviceVulkan12Features featuresVulkan12{};
|
||||
vk::PhysicalDeviceFeatures2 features{
|
||||
.pNext = &featuresVulkan12
|
||||
};
|
||||
physdev.getFeatures2(&features, dld);
|
||||
return featuresVulkan12.shaderFloat16;
|
||||
}
|
||||
|
||||
std::pair<vk::UniqueDevice, vk::Queue> vkhelper::createDevice(
|
||||
vk::detail::DispatchLoaderDynamic& dld,
|
||||
const vk::PhysicalDevice& physdev,
|
||||
uint32_t qfi,
|
||||
bool fp16
|
||||
) {
|
||||
constexpr std::array<const char*, 3> EXTENSIONS{
|
||||
vk::KHRSynchronization2ExtensionName,
|
||||
vk::KHRExternalMemoryFdExtensionName,
|
||||
vk::KHRExternalSemaphoreFdExtensionName
|
||||
};
|
||||
|
||||
vk::PhysicalDeviceSynchronization2FeaturesKHR sync2Info{
|
||||
.synchronization2 = VK_TRUE
|
||||
};
|
||||
const vk::PhysicalDeviceVulkan12Features vk12Info{
|
||||
.pNext = &sync2Info,
|
||||
.shaderFloat16 = fp16,
|
||||
.timelineSemaphore = VK_TRUE
|
||||
};
|
||||
const float queuePriority{1.0F}; // Highest priority
|
||||
const vk::DeviceQueueCreateInfo queueInfo{
|
||||
.queueFamilyIndex = qfi,
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &queuePriority
|
||||
};
|
||||
const vk::DeviceCreateInfo deviceInfo{
|
||||
.pNext = &vk12Info,
|
||||
.queueCreateInfoCount = 1,
|
||||
.pQueueCreateInfos = &queueInfo,
|
||||
.enabledExtensionCount = static_cast<uint32_t>(EXTENSIONS.size()),
|
||||
.ppEnabledExtensionNames = EXTENSIONS.data()
|
||||
};
|
||||
auto device{physdev.createDeviceUnique(deviceInfo, nullptr, dld)};
|
||||
dld.init(*device);
|
||||
|
||||
return{
|
||||
std::move(device),
|
||||
device->getQueue(qfi, 0, dld)
|
||||
};
|
||||
}
|
||||
101
lsfg-vk-backend/src/utility/vkhelper.hpp
Normal file
101
lsfg-vk-backend/src/utility/vkhelper.hpp
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
||||
#define VULKAN_HPP_NO_DEFAULT_DISPATCHER 1
|
||||
#define VULKAN_HPP_NO_CONSTRUCTORS 1
|
||||
#include <vulkan/vulkan.hpp> // IWYU pragma: export
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <vulkan/vulkan_enums.hpp>
|
||||
#include <vulkan/vulkan_funcs.hpp>
|
||||
#include <vulkan/vulkan_handles.hpp>
|
||||
#include <vulkan/vulkan_hpp_macros.hpp>
|
||||
#include <vulkan/vulkan_structs.hpp>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace vkhelper {
|
||||
|
||||
/* Device initialization */
|
||||
|
||||
///
|
||||
/// Create a Vulkan 1.2 instance for lsfg-vk
|
||||
///
|
||||
/// @param dld Dynamic dispatch loader
|
||||
/// @return RAII-wrapped Vulkan instance
|
||||
/// @throws std::runtime_error on failure
|
||||
///
|
||||
vk::UniqueInstance createInstance(vk::detail::DispatchLoaderDynamic& dld);
|
||||
|
||||
///
|
||||
/// Find a physical device through a custom identifier
|
||||
///
|
||||
/// The custom identifier may be one of:
|
||||
/// - Device name (e.g. "NVIDIA GeForce RTX 5080")
|
||||
/// - Vendor ID + Device ID in lowercase hexadecimal (e.g. "10de:2c02")
|
||||
/// - PCI bus ID with padded zeroes (e.g. "0000:01:00.0")
|
||||
///
|
||||
/// @param dld Dynamic dispatch loader
|
||||
/// @param instance Vulkan instance
|
||||
/// @param id Custom identifier
|
||||
/// @return Selected physical device
|
||||
/// @throws std::runtime_error if no suitable device found
|
||||
///
|
||||
vk::PhysicalDevice findPhysicalDevice(
|
||||
const vk::detail::DispatchLoaderDynamic& dld,
|
||||
const vk::Instance& instance,
|
||||
const std::string& id
|
||||
);
|
||||
|
||||
///
|
||||
/// Find the first compute-capable queue family index
|
||||
///
|
||||
/// @param dld Dynamic dispatch loader
|
||||
/// @param physdev Physical device
|
||||
/// @return Queue family index
|
||||
/// @throws std::runtime_error if no compute-capable queue found
|
||||
///
|
||||
uint32_t findComputeQueueFamilyIndex(
|
||||
const vk::detail::DispatchLoaderDynamic& dld,
|
||||
const vk::PhysicalDevice& physdev
|
||||
);
|
||||
|
||||
///
|
||||
/// Check a physical device for half-precision float support
|
||||
///
|
||||
/// @param dld Dynamic dispatch loader
|
||||
/// @param physdev Physical device
|
||||
/// @return Whether half-precision float is supported
|
||||
///
|
||||
bool checkHalfPrecisionSupport(
|
||||
const vk::detail::DispatchLoaderDynamic& dld,
|
||||
const vk::PhysicalDevice& physdev
|
||||
);
|
||||
|
||||
///
|
||||
/// Create a Vulkan device for lsfg-vk
|
||||
///
|
||||
/// This device will have the core features timelineSemaphore and shaderFloat16 (if requested)
|
||||
/// enabled, as well as the synchronization2, external memory & semaphore fd extensions.
|
||||
///
|
||||
/// @param dld Dynamic dispatch loader
|
||||
/// @param physdev Physical device
|
||||
/// @param qfi Queue family index of compute-capable queue
|
||||
/// @param fp16 Whether to enable half-precision float support
|
||||
/// @return RAII-wrapped Vulkan device & compute queue
|
||||
/// @throws std::runtime_error on failure
|
||||
///
|
||||
std::pair<vk::UniqueDevice, vk::Queue> createDevice(
|
||||
vk::detail::DispatchLoaderDynamic& dld,
|
||||
const vk::PhysicalDevice& physdev,
|
||||
uint32_t qfi,
|
||||
bool fp16
|
||||
);
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue