Skip to content

Commit

Permalink
Merge pull request #8635 from unknownbrackets/vulkan-error
Browse files Browse the repository at this point in the history
Handle Vulkan init errors more gracefully
  • Loading branch information
hrydgard committed Mar 13, 2016
2 parents 1093fe4 + 2266cdc commit 04f8896
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 41 deletions.
94 changes: 55 additions & 39 deletions Common/Vulkan/VulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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_);

Expand All @@ -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;
}
}

Expand Down Expand Up @@ -592,36 +600,41 @@ VkBool32 CheckLayers(const std::vector<layer_properties> &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;
}

vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[0], &queue_count, nullptr);
assert(queue_count >= 1);

queue_props.resize(queue_count);
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[0], &queue_count, queue_props.data());
assert(queue_count >= 1);
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++) {
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_);
Expand Down Expand Up @@ -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);

VulkanLoadDeviceFunctions(device_);
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_);
}

return res;
return res;
}

VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata) {
Expand Down
3 changes: 3 additions & 0 deletions Common/Vulkan/VulkanContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ class VulkanContext {

VkResult CreateDevice(int physical_device);

const std::string &InitError() { return init_error_; }

VkDevice GetDevice() { return device_; }
VkInstance GetInstance() { return instance_; }

Expand Down Expand Up @@ -268,6 +270,7 @@ class VulkanContext {
bool prepared;
bool use_staging_buffer_;

std::string init_error_;
std::vector<const char *> instance_layer_names;
std::vector<const char *> instance_extension_names;
std::vector<layer_properties> instance_layer_properties;
Expand Down
5 changes: 5 additions & 0 deletions Windows/EmuThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion Windows/GPU/WindowsVulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion android/jni/app-android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,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) {
Expand Down

0 comments on commit 04f8896

Please sign in to comment.