From e0ed0ea2f3cf5a6b5d4ce07d7a1aac820eee2ce7 Mon Sep 17 00:00:00 2001 From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> Date: Fri, 20 May 2022 11:50:42 -0400 Subject: [PATCH] vulkan(Windows): verify vulkan instance creation with vulkan-1.dll Add another supplementary check using functions from the vulkan-1 module before trying with QVulkanInstance. Gitlab: #746 Change-Id: I8975ef8765675aca95c4fee648853ea74c0c8ec9 --- src/app/main.cpp | 15 +++++++++++++++ src/app/utils.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/app/utils.h | 3 +++ 3 files changed, 63 insertions(+) diff --git a/src/app/main.cpp b/src/app/main.cpp index bf56278a3..69abdd5cb 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -20,6 +20,7 @@ #include "mainapplication.h" #include "instancemanager.h" +#include "utils.h" #include "version.h" #include <QCryptographicHash> @@ -117,6 +118,19 @@ main(int argc, char* argv[]) #else if (std::invoke([] { #if defined(HAS_VULKAN) && !defined(Q_OS_LINUX) + // Somehow, several bug reports show that, on Windows, QVulkanInstance + // verification passes, but goes on to fail when creating the QQuickWindow + // with "Failed to initialize graphics backend for Vulkan". + // Here we allow platform-specific checks using native Vulkan libraries. + // Currently only implemented on Windows. + try { + Utils::testVulkanSupport(); + } catch (const std::exception& e) { + qWarning() << "Vulkan instance cannot be created:" << e.what(); + return false; + } + + // Check using Qt's QVulkanInstance. QVulkanInstance inst; inst.setLayers({"VK_LAYER_KHRONOS_validation"}); bool ok = inst.create(); @@ -128,6 +142,7 @@ main(int argc, char* argv[]) qWarning() << "VK_LAYER_KHRONOS_validation layer is not available."; return false; } + return true; #else return false; diff --git a/src/app/utils.cpp b/src/app/utils.cpp index 2114f9b0e..5422c4278 100644 --- a/src/app/utils.cpp +++ b/src/app/utils.cpp @@ -51,6 +51,51 @@ #include <windows.h> #endif +void +Utils::testVulkanSupport() +{ +#if defined(Q_OS_WIN) + // Checks Vulkan support using the vulkan functions loaded directly + // from vulkan-1.dll. + struct DllLoader + { + explicit DllLoader(const std::string& filename) + : module(LoadLibraryA(filename.c_str())) + { + if (module == nullptr) { + throw std::runtime_error("Can't load module."); + } + } + ~DllLoader() + { + FreeLibrary(module); + } + HMODULE module; + } vk {"vulkan-1.dll"}; + + typedef void*(__stdcall * PFN_vkGetInstanceProcAddr)(void*, const char*); + auto vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) + GetProcAddress(vk.module, "vkGetInstanceProcAddr"); + if (!vkGetInstanceProcAddr) { + throw std::runtime_error("Missing vkGetInstanceProcAddr proc."); + } + + typedef int(__stdcall * PFN_vkCreateInstance)(int*, void*, void**); + auto vkCreateInstance = (PFN_vkCreateInstance) vkGetInstanceProcAddr(vk.module, + "vkCreateInstance"); + if (!vkCreateInstance) { + throw std::runtime_error("Missing vkCreateInstance proc."); + } + + void* instance = 0; + int VkInstanceCreateInfo[16] = {1}; + auto result = vkCreateInstance(VkInstanceCreateInfo, 0, &instance); + if (!instance || result != 0) { + throw std::runtime_error("Can't create Vulkan instance."); + } +#endif +} + bool Utils::CreateStartupLink(const std::wstring& wstrAppName) { diff --git a/src/app/utils.h b/src/app/utils.h index a4e6ac8db..35820c0b1 100644 --- a/src/app/utils.h +++ b/src/app/utils.h @@ -56,6 +56,9 @@ class LRCInstance; namespace Utils { +// Throws if Vulkan cannot be instantiated. +void testVulkanSupport(); + // App System bool CreateStartupLink(const std::wstring& wstrAppName); void DeleteStartupLink(const std::wstring& wstrAppName); -- GitLab