From 82205a46609ab0ff66c3c90ba79ff3e94a7867d2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Mar 2016 09:33:39 -0700 Subject: [PATCH] Handle Vulkan init errors more gracefully. --- Common/Vulkan/VulkanContext.cpp | 94 ++++++++++++++++------------ Common/Vulkan/VulkanContext.h | 3 + Windows/EmuThread.cpp | 5 ++ Windows/GPU/WindowsVulkanContext.cpp | 5 +- android/jni/app-android.cpp | 4 +- 5 files changed, 70 insertions(+), 41 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index d95167843f..52a5a3b769 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -67,7 +67,7 @@ VulkanContext::VulkanContext(const char *app_name, int app_ver, uint32_t flags) curFrame_(0) { if (!VulkanLoad()) { - ELOG("Failed to load vulkan"); + init_error_ = "Failed to load Vulkan driver library"; // No DLL? return; } @@ -125,7 +125,10 @@ VulkanContext::VulkanContext(const char *app_name, int app_ver, uint32_t flags) ELOG("Failed to create instance : %d", res); } } - assert(res == VK_SUCCESS); + if (res != VK_SUCCESS) { + init_error_ = "Failed to create Vulkan instance"; + return; + } VulkanLoadInstanceFunctions(instance_); @@ -134,20 +137,25 @@ VulkanContext::VulkanContext(const char *app_name, int app_ver, uint32_t flags) assert(gpu_count); physical_devices_.resize(gpu_count); res = vkEnumeratePhysicalDevices(instance_, &gpu_count, physical_devices_.data()); - assert(!res); + if (res != VK_SUCCESS) { + init_error_ = "Failed to enumerate physical devices"; + return; + } InitGlobalLayerProperties(); InitGlobalExtensionProperties(); if (!CheckLayers(instance_layer_properties, instance_layer_names)) { ELOG("CheckLayers failed"); - exit(1); + init_error_ = "Failed to validate instance layers"; + return; } InitDeviceLayerProperties(); if (!CheckLayers(device_layer_properties, device_layer_names)) { ELOG("CheckLayers failed (2)"); - exit(1); + init_error_ = "Failed to validate device layers"; + return; } } @@ -592,36 +600,41 @@ VkBool32 CheckLayers(const std::vector &layer_props, const std } VkResult VulkanContext::CreateDevice(int physical_device) { - VkResult res; - VkDeviceQueueCreateInfo queue_info = {}; + VkResult res; + VkDeviceQueueCreateInfo queue_info = {}; - vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[0], &queue_count, NULL); - assert(queue_count >= 1); + if (!init_error_.empty()) { + ELOG("Vulkan init failed: %s", init_error_.c_str()); + return VK_ERROR_INITIALIZATION_FAILED; + } - queue_props.resize(queue_count); - vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[0], &queue_count, queue_props.data()); - assert(queue_count >= 1); + vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[0], &queue_count, nullptr); + assert(queue_count >= 1); - bool found = false; - for (int i = 0; i < (int)queue_count; i++) { + queue_props.resize(queue_count); + vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[0], &queue_count, queue_props.data()); + assert(queue_count >= 1); + + bool found = false; + for (int i = 0; i < (int)queue_count; i++) { if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { queue_info.queueFamilyIndex = i; found = true; break; } - } - assert(found); - assert(queue_count >= 1); + } + assert(found); + assert(queue_count >= 1); - // This is as good a place as any to do this - vkGetPhysicalDeviceMemoryProperties(physical_devices_[0], &memory_properties); - vkGetPhysicalDeviceProperties(physical_devices_[0], &gpu_props); + // This is as good a place as any to do this + vkGetPhysicalDeviceMemoryProperties(physical_devices_[0], &memory_properties); + vkGetPhysicalDeviceProperties(physical_devices_[0], &gpu_props); - float queue_priorities[1] = { 0.0 }; - queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_info.pNext = NULL; - queue_info.queueCount = 1; - queue_info.pQueuePriorities = queue_priorities; + float queue_priorities[1] = { 0.0 }; + queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_info.pNext = nullptr; + queue_info.queueCount = 1; + queue_info.pQueuePriorities = queue_priorities; // Optional features vkGetPhysicalDeviceFeatures(physical_devices_[0], &featuresAvailable_); @@ -650,25 +663,28 @@ VkResult VulkanContext::CreateDevice(int physical_device) { featuresEnabled_.depthBounds = true; } - VkDeviceCreateInfo device_info = {}; - device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_info.pNext = NULL; - device_info.queueCreateInfoCount = 1; - device_info.pQueueCreateInfos = &queue_info; - device_info.enabledLayerCount = (uint32_t)device_layer_names.size(); - device_info.ppEnabledLayerNames = + VkDeviceCreateInfo device_info = {}; + device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + device_info.pNext = NULL; + device_info.queueCreateInfoCount = 1; + device_info.pQueueCreateInfos = &queue_info; + device_info.enabledLayerCount = (uint32_t)device_layer_names.size(); + device_info.ppEnabledLayerNames = device_info.enabledLayerCount ? device_layer_names.data() : NULL; - device_info.enabledExtensionCount = (uint32_t)device_extension_names.size(); - device_info.ppEnabledExtensionNames = + device_info.enabledExtensionCount = (uint32_t)device_extension_names.size(); + device_info.ppEnabledExtensionNames = device_info.enabledExtensionCount ? device_extension_names.data() : NULL; device_info.pEnabledFeatures = &featuresEnabled_; - res = vkCreateDevice(physical_devices_[0], &device_info, NULL, &device_); - assert(res == VK_SUCCESS); + res = vkCreateDevice(physical_devices_[0], &device_info, NULL, &device_); + if (res != VK_SUCCESS) { + init_error_ = "Unable to create Vulkan device"; + ELOG("Unable to create Vulkan device"); + } else { + VulkanLoadDeviceFunctions(device_); + } - VulkanLoadDeviceFunctions(device_); - - return res; + return res; } VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata) { diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 14779e3168..5ffa6c2e45 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -155,6 +155,8 @@ public: VkResult CreateDevice(int physical_device); + const std::string &InitError() { return init_error_; } + VkDevice GetDevice() { return device_; } VkInstance GetInstance() { return instance_; } @@ -268,6 +270,7 @@ private: bool prepared; bool use_staging_buffer_; + std::string init_error_; std::vector instance_layer_names; std::vector instance_extension_names; std::vector instance_layer_properties; diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index 753b8cf5f7..abe0797908 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -128,6 +128,7 @@ unsigned int WINAPI TheThread(void *) I18NCategory *err = GetI18NCategory("Error"); Reporting::ReportMessage("Graphics init error: %s", error_string.c_str()); + const char *defaultErrorVulkan = "Failed initializing graphics. Try upgrading your graphics drivers.\n\nWould you like to try switching to OpenGL?\n\nError message:"; const char *defaultErrorOpenGL = "Failed initializing graphics. Try upgrading your graphics drivers.\n\nWould you like to try switching to DirectX 9?\n\nError message:"; const char *defaultErrorDirect3D9 = "Failed initializing graphics. Try upgrading your graphics drivers and directx 9 runtime.\n\nWould you like to try switching to OpenGL?\n\nError message:"; const char *genericError; @@ -137,6 +138,10 @@ unsigned int WINAPI TheThread(void *) nextBackend = GPU_BACKEND_OPENGL; genericError = err->T("GenericDirect3D9Error", defaultErrorDirect3D9); break; + case GPU_BACKEND_VULKAN: + nextBackend = GPU_BACKEND_OPENGL; + genericError = err->T("GenericVulkanError", defaultErrorDirect3D9); + break; case GPU_BACKEND_OPENGL: default: nextBackend = GPU_BACKEND_DIRECT3D9; diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 5d9e0b79c4..32f8b46676 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -166,7 +166,10 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m Version gitVer(PPSSPP_GIT_VERSION); g_Vulkan = new VulkanContext("PPSSPP", gitVer.ToInteger(), (g_validate_ ? VULKAN_FLAG_VALIDATE : 0) | VULKAN_FLAG_PRESENT_MAILBOX); - g_Vulkan->CreateDevice(0); + if (g_Vulkan->CreateDevice(0) != VK_SUCCESS) { + *error_message = g_Vulkan->InitError(); + return false; + } if (g_validate_) { int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; g_Vulkan->InitDebugMsgCallback(Vulkan_Dbg, bits, &g_LogOptions); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 52426ed1ec..853fb3673c 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -253,7 +253,9 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, } ILOG("Creating vulkan device"); - g_Vulkan->CreateDevice(0); + if (g_Vulkan->CreateDevice(0) != VK_SUCCESS) { + return false; + } int width = desiredBackbufferSizeX; int height = desiredBackbufferSizeY; if (!width || !height) {