diff --git a/src/app/main.cpp b/src/app/main.cpp index bf56278a373c38ec31411f593b996cb967dd6170..69abdd5cb035223764e02fab62758641495faa02 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 2114f9b0e484d1ab3f635e0470c660d701d229ac..5422c4278b2ba8880ba6fbc98b18d3770ea87459 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 a4e6ac8db0dda74e93e529a8c2f88aa765233ee9..35820c0b1e916171db4de8ecbe1a657a86d1ce7c 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);