Hello,
In my setup I have 2 ‘video cards’, when enumerating the devices they show up in this order
- GeForce GTX 1080
- Intel® UHD Graphics 630
I have a piece of code that selects the physical device to run on and (for testing purposes) I sometimes run on the 630 (as a low end card). However it seems that when I try to create a device for the Intel® UHD Graphics 630, it crashes in VkCreateDevice. Now this only happens if the GeForce GTX 1080 is enabled, since then the vulkan instance enumerates 2 devices. if I disable the 1080 through device manager, the same code works. Vulkan then only enumerates 1 device and it works as you think it would.
I expected the validation layer to give some more information, but unfortunately it does not. I can see the callstack in the crash:
0000000000000000() Unknown
igvk64.dll!00007fff0876aec6() Unknown
igvk64.dll!00007fff0874e11e() Unknown
igvk64.dll!00007fff0873af5a() Unknown
vulkan-1.dll!00007fff23249dbb() Unknown
VkLayer_unique_objects.dll!unique_objects::CreateDevice(VkPhysicalDevice_T * gpu, const VkDeviceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDevice_T * * pDevice) Line 207 C++
VkLayer_threading.dll!threading::CreateDevice(VkPhysicalDevice_T * gpu, const VkDeviceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDevice_T * * pDevice) Line 163 C++
VkLayer_parameter_validation.dll!parameter_validation::vkCreateDevice(VkPhysicalDevice_T * physicalDevice, const VkDeviceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDevice_T * * pDevice) Line 552 C++
VkLayer_object_tracker.dll!object_tracker::CreateDevice(VkPhysicalDevice_T * physicalDevice, const VkDeviceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDevice_T * * pDevice) Line 834 C++
VkLayer_core_validation.dll!core_validation::CreateDevice(VkPhysicalDevice_T * gpu, const VkDeviceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDevice_T * * pDevice) Line 2242 C++
Which seems to indicate that the problem is somewhere in the Intel driver (igvk64.dll)
To make it easy to reproduce I have put together a small piece of code that tries to create a device for each enumerated physical device (attachments seem to not work, so code is copy/pasted below)
I am running Vulkan runtime 1.1.73.0
I am running NVIDIA driver 397.93
I am running Intel UHD Graphics Driver 22.20.16.4758 (supports vulkan version 1.0.50)
Another interesting thing, which does not cause crashes but triggers the validation layer, seems to be that when using the NVIDIA driver you are required to call vkGetPhysicalDeviceQueueFamilyProperties, as just setting the queueFamilyIndex to 0 will trigger validation errors.
#define WIN32_LEAN_AND_MEAN /// vulkan.h includes windows.h, so the Windows defines need to happen before including vulkan.h
#define NOMINMAX
#define VK_USE_PLATFORM_WIN32_KHR
#include <vulkan/vulkan.h>
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#define VK_CHECK_RESULT(x) do { VkResult result = (x); assert(result == VK_SUCCESS); } while(0)
#define VK_CHECK_RESULT_RETURN(x) do { VkResult result = (x); assert(result == VK_SUCCESS); if(result != VK_SUCCESS) return; } while(0)
#define sizeof_array(x) (sizeof(x) / sizeof(x[0]))
void Print(const char* text)
{
printf("%s
", text);
OutputDebugStringA(text);
OutputDebugStringA("
");
}
class TestCreateDevices
{
public:
TestCreateDevices()
{
CreateInstance("");
CreateDevices();
DestroyInstance();
}
private:
void CreateInstance(const char* applicationName)
{
// Enabled Extensions
const char* enabledExtensions[] =
{
"VK_KHR_surface",
"VK_KHR_win32_surface",
};
// Enabled Layers
const char* enabledLayers[] =
{
"VK_LAYER_LUNARG_assistant_layer",
"VK_LAYER_LUNARG_core_validation",
"VK_LAYER_LUNARG_object_tracker",
"VK_LAYER_LUNARG_parameter_validation",
"VK_LAYER_LUNARG_standard_validation",
};
VkApplicationInfo applicationInfo = {};
applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
applicationInfo.pApplicationName = applicationName;
applicationInfo.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
applicationInfo.pEngineName = applicationName;
applicationInfo.engineVersion = VK_MAKE_VERSION(0, 1, 0);
applicationInfo.apiVersion = VK_API_VERSION_1_1;
VkInstanceCreateInfo instanceCI = {};
instanceCI.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCI.pApplicationInfo = &applicationInfo;
instanceCI.ppEnabledExtensionNames = enabledExtensions;
instanceCI.enabledExtensionCount = static_cast<uint32_t>(sizeof_array(enabledExtensions));
instanceCI.ppEnabledLayerNames = enabledLayers;
instanceCI.enabledLayerCount = static_cast<uint32_t>(sizeof_array(enabledLayers));
VK_CHECK_RESULT(vkCreateInstance(&instanceCI, mAllocationCallbacks, &mInstance));
}
void DestroyInstance()
{
vkDestroyInstance(mInstance, mAllocationCallbacks);
mInstance = VK_NULL_HANDLE;
}
void CreateDevices()
{
uint32_t physicalDeviceCount = 0;
VK_CHECK_RESULT_RETURN(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr));
VkPhysicalDevice* physicalDevices = (VkPhysicalDevice*)alloca(sizeof(VkPhysicalDevice) * physicalDeviceCount);
VK_CHECK_RESULT_RETURN(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, physicalDevices));
Print("Devices:");
for (uint32_t i = 0; i < physicalDeviceCount; ++i)
{
VkPhysicalDeviceProperties physicalDeviceProperties;
vkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties);
Print(physicalDeviceProperties.deviceName);
VkPhysicalDeviceFeatures physicalDeviceFeatures;
vkGetPhysicalDeviceFeatures(physicalDevices[i], &physicalDeviceFeatures);
// queueFamilyIndex
uint32_t queueFamilyIndex = 0;
uint32_t queueFamilyPropertyCount;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[i], &queueFamilyPropertyCount, nullptr);
assert(queueFamilyPropertyCount > 0);
VkQueueFamilyProperties* queueFamilyProperties = (VkQueueFamilyProperties*)alloca(sizeof(VkQueueFamilyProperties) * queueFamilyPropertyCount);
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[i], &queueFamilyPropertyCount, queueFamilyProperties);
// queue
float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueCI = {};
queueCI.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCI.pNext = nullptr;
queueCI.flags = 0;
queueCI.queueFamilyIndex = queueFamilyIndex;
queueCI.queueCount = 1;
queueCI.pQueuePriorities = &queuePriority;
const char* enabledExtensions[] =
{
"VK_KHR_swapchain",
};
VkDeviceCreateInfo deviceCI = {};
deviceCI.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCI.pNext = nullptr;
deviceCI.flags = 0;
deviceCI.queueCreateInfoCount = 1;
deviceCI.pQueueCreateInfos = &queueCI;
deviceCI.enabledLayerCount = 0;
deviceCI.ppEnabledLayerNames = nullptr;
deviceCI.ppEnabledExtensionNames = enabledExtensions;
deviceCI.enabledExtensionCount = static_cast<uint32_t>(sizeof_array(enabledExtensions));
deviceCI.pEnabledFeatures = &physicalDeviceFeatures;
VkDevice device;
VK_CHECK_RESULT(vkCreateDevice(physicalDevices[i], &deviceCI, mAllocationCallbacks, &device));
vkDestroyDevice(device, mAllocationCallbacks);
}
}
VkAllocationCallbacks* mAllocationCallbacks = nullptr;
VkInstance mInstance = VK_NULL_HANDLE;
};
int main(int argc, char* argv[])
{
TestCreateDevices();
return 0;
}