Skip to content

Commit ae96035

Browse files
committed
GPU Vulkan Display: Switch to Vulkan 1.4
1 parent 4df63c0 commit ae96035

5 files changed

Lines changed: 79 additions & 42 deletions

File tree

‎GPU/GPUTracking/Standalone/CMakeLists.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ if(GPUCA_BUILD_EVENT_DISPLAY)
9696
find_package(Fontconfig REQUIRED)
9797
endif()
9898
if(GPUCA_BUILD_EVENT_DISPLAY_VULKAN)
99-
find_package(Vulkan REQUIRED)
99+
find_package(Vulkan 1.4.328 REQUIRED)
100100
if (Vulkan_GLSLC_EXECUTABLE STREQUAL "Vulkan_GLSLC_EXECUTABLE-NOTFOUND")
101101
message(FATAL_ERROR ${Vulkan_GLSLC_EXECUTABLE})
102102
endif()

‎GPU/GPUTracking/cmake/vulkan_display.cmake‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function(add_glslc_shader TARGET SHADER)
2525

2626
add_custom_command(
2727
OUTPUT ${spirv-file}
28-
COMMAND ${Vulkan_GLSLC_EXECUTABLE} -o ${spirv-file} ${input-file-abs} -MD -MT ${spirv-file} -MF ${spirv-file}.d
28+
COMMAND ${Vulkan_GLSLC_EXECUTABLE} --target-env=vulkan1.4 -o ${spirv-file} ${input-file-abs} -MD -MT ${spirv-file} -MF ${spirv-file}.d
2929
DEPENDS ${input-file-abs}
3030
DEPFILE ${spirv-file}.d
3131
COMMENT "Compiling GLSL to SPIRV: ${SHADER}"

‎GPU/GPUTracking/display/CMakeLists.txt‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ endif()
3232

3333
if(Vulkan_FOUND)
3434
string(FIND "${Vulkan_VERSION}" "." vulkan_dot_index)
35-
if(NOT ${Vulkan_VERSION} VERSION_GREATER_EQUAL "1.3.0" OR vulkan_dot_index EQUAL -1 OR Vulkan_GLSLC_EXECUTABLE STREQUAL "Vulkan_GLSLC_EXECUTABLE-NOTFOUND")
35+
if(NOT ${Vulkan_VERSION} VERSION_GREATER_EQUAL "1.4.328" OR vulkan_dot_index EQUAL -1 OR Vulkan_GLSLC_EXECUTABLE STREQUAL "Vulkan_GLSLC_EXECUTABLE-NOTFOUND")
36+
message(STATUS "Vulkan event display disabled: need Vulkan headers >= 1.4.328 (found ${Vulkan_VERSION}) and glslc")
3637
set(Vulkan_FOUND 0)
3738
endif()
3839
endif()

‎GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.cxx‎

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -273,26 +273,67 @@ static inline void clearVector(T& v, S func, bool downsize = true)
273273

274274
// ---------------------------- VULKAN DEVICE MANAGEMENT ----------------------------
275275

276-
static bool hasFeatures(const vk::PhysicalDeviceFeatures& available, const vk::PhysicalDeviceFeatures& required) // The struct consists only of VkBool32 members
276+
template <class T> // Feature structs: sType, pNext, then only VkBool32 members (possibly followed by padding)
277+
static bool hasFeatures(const T& available, const T& required)
277278
{
278-
static_assert(sizeof(vk::PhysicalDeviceFeatures) % sizeof(vk::Bool32) == 0);
279-
const vk::Bool32* a = reinterpret_cast<const vk::Bool32*>(&available);
280-
const vk::Bool32* r = reinterpret_cast<const vk::Bool32*>(&required);
281-
for (size_t i = 0; i < sizeof(vk::PhysicalDeviceFeatures) / sizeof(vk::Bool32); i++) {
279+
const vk::Bool32* a = reinterpret_cast<const vk::Bool32*>(reinterpret_cast<const char*>(&available) + sizeof(VkBaseOutStructure));
280+
const vk::Bool32* r = reinterpret_cast<const vk::Bool32*>(reinterpret_cast<const char*>(&required) + sizeof(VkBaseOutStructure));
281+
for (size_t i = 0; i < (sizeof(T) - sizeof(VkBaseOutStructure)) / sizeof(vk::Bool32); i++) {
282282
if (r[i] && !a[i]) {
283283
return false;
284284
}
285285
}
286286
return true;
287287
}
288288

289-
double GPUDisplayBackendVulkan::checkDevice(vk::PhysicalDevice device, const std::vector<const char*>& reqDeviceExtensions, const vk::PhysicalDeviceFeatures& reqDeviceFeatures, bool silent)
289+
template <class... T>
290+
static bool hasFeatures(const vk::StructureChain<T...>& available, const vk::StructureChain<T...>& required)
291+
{
292+
return (hasFeatures(available.template get<T>(), required.template get<T>()) && ...);
293+
}
294+
295+
template <class... T>
296+
static void clearFeatures(vk::StructureChain<T...>& chain) // Zero all feature flags including padding, which the member-wise comparison in hasFeatures reads
297+
{
298+
((memset(reinterpret_cast<char*>(&chain.template get<T>()) + sizeof(VkBaseOutStructure), 0, sizeof(T) - sizeof(VkBaseOutStructure))), ...);
299+
}
300+
301+
template <class... T>
302+
static vk::StructureChain<T...> getFeatures(vk::PhysicalDevice device, const vk::StructureChain<T...>&)
303+
{
304+
return device.getFeatures2<T...>();
305+
}
306+
307+
double GPUDisplayBackendVulkan::checkDevice(vk::PhysicalDevice device, const std::vector<const char*>& reqDeviceExtensions, const FeatureChain& reqDeviceFeatures, bool silent)
290308
{
291309
double score = -1.;
292310
vk::PhysicalDeviceProperties deviceProperties = device.getProperties();
293-
vk::PhysicalDeviceFeatures deviceFeatures = device.getFeatures();
294311
vk::PhysicalDeviceMemoryProperties memoryProperties = device.getMemoryProperties();
295-
if (!hasFeatures(deviceFeatures, reqDeviceFeatures)) {
312+
if (deviceProperties.apiVersion < VK_API_VERSION_1_4) {
313+
if (!silent) {
314+
GPUInfo("%s ignored, supports only Vulkan %u.%u", &deviceProperties.deviceName[0], VK_API_VERSION_MAJOR(deviceProperties.apiVersion), VK_API_VERSION_MINOR(deviceProperties.apiVersion));
315+
}
316+
return (-1);
317+
}
318+
319+
std::vector<vk::ExtensionProperties> availableExtensions = device.enumerateDeviceExtensionProperties(nullptr);
320+
uint32_t extensionsFound = 0;
321+
for (uint32_t i = 0; i < reqDeviceExtensions.size(); i++) {
322+
for (uint32_t j = 0; j < availableExtensions.size(); j++) {
323+
if (strcmp(reqDeviceExtensions[i], availableExtensions[j].extensionName) == 0) {
324+
extensionsFound++;
325+
break;
326+
}
327+
}
328+
}
329+
if (extensionsFound < reqDeviceExtensions.size()) {
330+
if (!silent) {
331+
GPUInfo("%s ignored due to missing extensions", &deviceProperties.deviceName[0]);
332+
}
333+
return (-1);
334+
}
335+
336+
if (!hasFeatures(getFeatures(device, reqDeviceFeatures), reqDeviceFeatures)) { // Query only after the version and extension checks, the chain contains 1.4 and extension structs
296337
if (!silent) {
297338
GPUInfo("%s ignored due to missing features", &deviceProperties.deviceName[0]);
298339
}
@@ -320,23 +361,6 @@ double GPUDisplayBackendVulkan::checkDevice(vk::PhysicalDevice device, const std
320361
return (-1);
321362
}
322363

323-
std::vector<vk::ExtensionProperties> availableExtensions = device.enumerateDeviceExtensionProperties(nullptr);
324-
uint32_t extensionsFound = 0;
325-
for (uint32_t i = 0; i < reqDeviceExtensions.size(); i++) {
326-
for (uint32_t j = 0; j < availableExtensions.size(); j++) {
327-
if (strcmp(reqDeviceExtensions[i], availableExtensions[j].extensionName) == 0) {
328-
extensionsFound++;
329-
break;
330-
}
331-
}
332-
}
333-
if (extensionsFound < reqDeviceExtensions.size()) {
334-
if (!silent) {
335-
GPUInfo("%s ignored due to missing extensions", &deviceProperties.deviceName[0]);
336-
}
337-
return (-1);
338-
}
339-
340364
updateSwapChainDetails(device);
341365
if (mSwapChainDetails.formats.empty() || mSwapChainDetails.presentModes.empty()) {
342366
if (!silent) {
@@ -369,14 +393,27 @@ void GPUDisplayBackendVulkan::createDevice()
369393
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
370394
appInfo.pEngineName = "GPU CI Standalone Engine";
371395
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
372-
appInfo.apiVersion = VK_API_VERSION_1_0;
396+
appInfo.apiVersion = VK_API_VERSION_1_4;
373397

374398
vk::InstanceCreateInfo instanceCreateInfo;
375399
instanceCreateInfo.pApplicationInfo = &appInfo;
376400

377401
const char** frontendExtensions;
378402
uint32_t frontendExtensionCount = mDisplay->frontend()->getReqVulkanExtensions(frontendExtensions);
379403
std::vector<const char*> reqInstanceExtensions(frontendExtensions, frontendExtensions + frontendExtensionCount);
404+
reqInstanceExtensions.insert(reqInstanceExtensions.end(), {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, VK_KHR_SURFACE_MAINTENANCE_1_EXTENSION_NAME}); // The latter two are required by VK_KHR_swapchain_maintenance1
405+
std::vector<vk::ExtensionProperties> availableInstanceExtensions = vk::enumerateInstanceExtensionProperties(nullptr);
406+
if (mDisplay->GetProcessingSettings().debugLevel >= 3) {
407+
std::cout << "available instance extensions: " << availableInstanceExtensions.size() << "\n";
408+
for (const auto& extension : availableInstanceExtensions) {
409+
std::cout << '\t' << extension.extensionName << '\n';
410+
}
411+
}
412+
for (const char* ext : reqInstanceExtensions) {
413+
if (std::none_of(availableInstanceExtensions.begin(), availableInstanceExtensions.end(), [ext](const auto& e) { return strcmp(ext, e.extensionName) == 0; })) {
414+
throw std::runtime_error(std::string("Required Vulkan instance extension not available: ") + ext);
415+
}
416+
}
380417

381418
const std::vector<const char*> reqValidationLayers = {"VK_LAYER_KHRONOS_validation"};
382419
auto debugCallback = [](vk::DebugUtilsMessageSeverityFlagBitsEXT messageSeverity, vk::DebugUtilsMessageTypeFlagsEXT messageType, const vk::DebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) -> VkBool32 {
@@ -412,7 +449,6 @@ void GPUDisplayBackendVulkan::createDevice()
412449
if (checkVulkanLayersSupported(reqValidationLayers)) {
413450
throw std::runtime_error("Requested validation layer support not available");
414451
}
415-
reqInstanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
416452
instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(reqValidationLayers.size());
417453
instanceCreateInfo.ppEnabledLayerNames = reqValidationLayers.data();
418454
instanceCreateInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;
@@ -435,21 +471,19 @@ void GPUDisplayBackendVulkan::createDevice()
435471
GPUInfo("Enabling Vulkan Validation Layers");
436472
mDebugMessenger = mInstance.createDebugUtilsMessengerEXT(debugCreateInfo, nullptr);
437473
}
438-
std::vector<vk::ExtensionProperties> extensions = vk::enumerateInstanceExtensionProperties(nullptr);
439-
if (mDisplay->GetProcessingSettings().debugLevel >= 3) {
440-
std::cout << "available instance extensions: " << extensions.size() << "\n";
441-
for (const auto& extension : extensions) {
442-
std::cout << '\t' << extension.extensionName << '\n';
443-
}
444-
}
445474

446475
if (mDisplay->frontend()->getVulkanSurface(&mInstance, &mSurface)) {
447476
throw std::runtime_error("Frontend does not provide Vulkan surface");
448477
}
449478

450-
const std::vector<const char*> reqDeviceExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
451-
vk::PhysicalDeviceFeatures reqDeviceFeatures{};
452-
reqDeviceFeatures.geometryShader = reqDeviceFeatures.wideLines = reqDeviceFeatures.largePoints = VK_TRUE;
479+
const std::vector<const char*> reqDeviceExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, VK_KHR_PRESENT_ID_EXTENSION_NAME, VK_KHR_PRESENT_WAIT_EXTENSION_NAME};
480+
FeatureChain reqDeviceFeatures; // Exactly these features are required and enabled
481+
clearFeatures(reqDeviceFeatures);
482+
auto& reqFeatures10 = reqDeviceFeatures.get<vk::PhysicalDeviceFeatures2>().features;
483+
reqFeatures10.geometryShader = reqFeatures10.wideLines = reqFeatures10.largePoints = VK_TRUE;
484+
reqDeviceFeatures.get<vk::PhysicalDeviceSwapchainMaintenance1FeaturesKHR>().swapchainMaintenance1 = VK_TRUE;
485+
reqDeviceFeatures.get<vk::PhysicalDevicePresentIdFeaturesKHR>().presentId = VK_TRUE;
486+
reqDeviceFeatures.get<vk::PhysicalDevicePresentWaitFeaturesKHR>().presentWait = VK_TRUE;
453487

454488
mPhysicalDevice = VkPhysicalDevice(VK_NULL_HANDLE);
455489
std::vector<vk::PhysicalDevice> devices = mInstance.enumeratePhysicalDevices();
@@ -502,7 +536,8 @@ void GPUDisplayBackendVulkan::createDevice()
502536
vk::DeviceCreateInfo deviceCreateInfo{};
503537
deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
504538
deviceCreateInfo.queueCreateInfoCount = 1;
505-
deviceCreateInfo.pEnabledFeatures = &reqDeviceFeatures;
539+
deviceCreateInfo.pNext = &reqDeviceFeatures.get<vk::PhysicalDeviceFeatures2>();
540+
deviceCreateInfo.pEnabledFeatures = nullptr;
506541
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(reqDeviceExtensions.size());
507542
deviceCreateInfo.ppEnabledExtensionNames = reqDeviceExtensions.data();
508543
mDevice = mPhysicalDevice.createDevice(deviceCreateInfo, nullptr);

‎GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ class GPUDisplayBackendVulkan : public GPUDisplayBackend
8383
float getYFactor() const override { return -1.0f; }
8484
int32_t getMaxMSAA() const override { return mMaxMSAAsupported; }
8585

86-
double checkDevice(vk::PhysicalDevice device, const std::vector<const char*>& reqDeviceExtensions, const vk::PhysicalDeviceFeatures& reqDeviceFeatures, bool silent = false);
86+
using FeatureChain = vk::StructureChain<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan11Features, vk::PhysicalDeviceVulkan12Features, vk::PhysicalDeviceVulkan13Features, vk::PhysicalDeviceVulkan14Features, vk::PhysicalDeviceSwapchainMaintenance1FeaturesKHR, vk::PhysicalDevicePresentIdFeaturesKHR, vk::PhysicalDevicePresentWaitFeaturesKHR>;
87+
double checkDevice(vk::PhysicalDevice device, const std::vector<const char*>& reqDeviceExtensions, const FeatureChain& reqDeviceFeatures, bool silent = false);
8788
vk::Extent2D chooseSwapExtent(const vk::SurfaceCapabilitiesKHR& capabilities);
8889
void transitionImageLayout(vk::CommandBuffer commandBuffer, vk::Image image, vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout);
8990
VulkanBuffer createBuffer(size_t size, const void* srcData = nullptr, vk::BufferUsageFlags type = vk::BufferUsageFlagBits::eVertexBuffer, int32_t deviceMemory = 1);

0 commit comments

Comments
 (0)