Crazy Values about the graphic card and missing Extensions


#1

Hello,
I experimented with the Vulkan API a little bit.
I created a VkInstance, get the VkPhysicalDevice and created the VKDevice.
Additionally I created a window using GLFW.
But my problem is, that I can get different values from the graphic card (an Gigabyte AMD RX 580)
So now I’m trying to output some values of these graphic cards. But these values cannot be correct, they are really unrealistic:

Amount of Graphic Cards: 1
Amount of Queue Families: 3
Queue-Familiy #0
VK_QUEUE_GRAPHICS_BIT 0
VK_QUEUE_COMPUTE_BIT 0
VK_QUEUE_TRANSFER_BIT 0
VK_QUEUE_SPARS_BINDING_BIT 0
Amount Of Queues: 488
Timestamp Valid Bits: 1752378880
Min Image TimeStamp Granularity: 1953657971,771777121,1954047348
Queue-Familiy #1
VK_QUEUE_GRAPHICS_BIT 0
VK_QUEUE_COMPUTE_BIT 0
VK_QUEUE_TRANSFER_BIT 0
VK_QUEUE_SPARS_BINDING_BIT 0
Amount Of Queues: 771776884
Timestamp Valid Bits: 1835888483
Min Image TimeStamp Granularity: 7630437,1920234286,6447476
Queue-Familiy #2
VK_QUEUE_GRAPHICS_BIT 0
VK_QUEUE_COMPUTE_BIT 2
VK_QUEUE_TRANSFER_BIT 4
VK_QUEUE_SPARS_BINDING_BIT 8
Amount Of Queues: 6447476
Timestamp Valid Bits: 1953459758
Min Image TimeStamp Granularity: 2147483749,16,3342436
Surface capabilities:
        minImageCount:           0
        maxImageCount:           0
        currentExtent:           0/0
        minImageExtent:          0/0
        maxImageExtent:          0/0
        maxImageArrayLayers:     0
        supportedTransforms:     0
        currentTransform:        0
        supportedCompositeAlpha: 0
        supportedUsageFlags:     0 

Additionaly I get the VkResult = -7 while creating the surface. The extensions for the surface I get with following code:

uint32_t amountOfGLFWExtensions = 0;
auto glfwExtensions = glfwGetRequiredInstanceExtensions(&amountOfExtensions);<

And this is the code for adding the extensions:

instanceCreateInfo.enabledExtensionCount = amountOfGLFWExtensions;
instanceCreateInfo.ppEnabledExtensionNames = glfwExtensions;

What mistake is responsible for these values and the missing extension?
My platform is Windows 10. Compile version from Visual Studio 2017 is Release, x64.

At testing a little bit on other Computers I get the same unrealistic values.
So the graphic cards GTX 670 (4G), GTX 980 and AMD RX 580 produce these unrealistic values…


#2

Try running vulkaninfo.
If it works, then you do something wrong. Can’t say more without code.


#3

Okay, I run vulkaninfo and for me all seems to be normal…
Because you have asked for the code:
Header-File:

#pragma once
//#include "vulkan/vulkan.hpp"
#include <iostream>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vector>
class GraphicEngine
{
public:
	GraphicEngine();
	~GraphicEngine();
private:
	VkInstance instance;
	VkPhysicalDevice physicalDevice;
	VkDevice device;
	GLFWwindow *window;
	VkSurfaceKHR surface;
	void startGLFW();
	void startVulkan();
	void gameLoop();
	void shutdownVulkan();
	void shutdownGLFW();
	void handleVulkanResult(VkResult result);
};

Code:

#include "pch.h"
#include "GraphicEngine.h"
#define ASSERT_VULKAN(val)\
	if(val != VK_SUCCESS) {\
		__debugbreak();\
	}
GraphicEngine::GraphicEngine()
{
	startGLFW();
	startVulkan();
	gameLoop();
	shutdownVulkan();
	shutdownGLFW();
}
GraphicEngine::~GraphicEngine()
{ 
}
void GraphicEngine::startGLFW()
{
	glfwInit();
	glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
	glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
	window = glfwCreateWindow(400, 300, "Universe Evolution", nullptr, nullptr);
}
void GraphicEngine::startVulkan()
{
	//VkApplicationInfo create
	VkApplicationInfo appInfo;
	appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
	appInfo.pNext = NULL;
	appInfo.pApplicationName = "Universe Evolution";
	appInfo.applicationVersion = VK_MAKE_VERSION(0, 0, 1);
	appInfo.engineVersion = VK_MAKE_VERSION(0, 0, 1);
	appInfo.apiVersion = VK_API_VERSION_1_1;
	//get possible Layers
	uint32_t amountOfLayers = 0;
	vkEnumerateInstanceLayerProperties(&amountOfLayers, NULL);
	VkLayerProperties *layers = new VkLayerProperties[amountOfLayers];
	vkEnumerateInstanceLayerProperties(&amountOfLayers, layers);
	std::cout << "Amount of Layers: " << amountOfLayers << std::endl;
	for (int i = 0; i < amountOfLayers; i++)
	{
		std::cout << std::endl;
		std::cout << "Name: " << layers[i].layerName << std::endl;
		std::cout << "Spec-Version: " << layers[i].specVersion << std::endl;
		std::cout << "Impl-Version: " << layers[i].implementationVersion << std::endl;
		std::cout << "Description: " << layers[i].description << std::endl;
	}
	uint32_t amountOfExtensions = 0;
	vkEnumerateInstanceExtensionProperties(NULL, &amountOfExtensions, NULL);
	VkExtensionProperties *extensions = new VkExtensionProperties[amountOfExtensions];
	vkEnumerateInstanceExtensionProperties(NULL, &amountOfExtensions, extensions);
	std::cout << std::endl;
	std::cout << "Amount of Extensions: " << amountOfExtensions << std::endl;
	for (int i = 0; i < amountOfExtensions; i++)
	{
		std::cout << std::endl;
		std::cout << "Name: " << extensions[i].extensionName << std::endl;
		std::cout << "Spec-Version: " << extensions[i].specVersion << std::endl;
	}
	const std::vector<const char*> validationLayers = {
		"VK_LAYER_LUNARG_standard_validation"
	};
	uint32_t amountOfGLFWExtensions = 0;
	auto glfwExtensions = glfwGetRequiredInstanceExtensions(&amountOfExtensions);
//VkInstanceCreateInfo create
	VkInstanceCreateInfo instanceCreateInfo;
	instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
	instanceCreateInfo.pNext = NULL;
	instanceCreateInfo.flags = 0;
	instanceCreateInfo.pApplicationInfo = &appInfo;
	instanceCreateInfo.enabledLayerCount = validationLayers.size();
	instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
	instanceCreateInfo.enabledExtensionCount = amountOfGLFWExtensions;
	instanceCreateInfo.ppEnabledExtensionNames = glfwExtensions;
	//Vulkan Instance create
	VkResult result = vkCreateInstance(&instanceCreateInfo, NULL, &instance);
	//Fehlerbehandlung
	if (result != VK_SUCCESS)
	{
		std::cerr << "Vulkan-Mistake at creating Instance of Vulkan" << result <<std::endl;
	}
	result = glfwCreateWindowSurface(instance, window, nullptr, &surface);
	if (result != VK_SUCCESS)
	{
		std::cerr << "Vulkan-Mistake at creating VulkanWindowSurface: " << result << std::endl;
	}
	delete[] layers;
	delete[] extensions;
	//get amount of gpus
	uint32_t amountOfPhysicalDevices = 0;
	vkEnumeratePhysicalDevices(instance, &amountOfPhysicalDevices, NULL);
	std::cout << "Amount of Graphic Cards: " << amountOfPhysicalDevices << std::endl;
	//listing all physical devices
	if (amountOfPhysicalDevices > 0)
	{
		VkPhysicalDevice * physicalDevices = new VkPhysicalDevice[amountOfPhysicalDevices];
		vkEnumeratePhysicalDevices(instance, &amountOfPhysicalDevices, physicalDevices);
		physicalDevice = physicalDevices[0];
		//Possibility to get Features of PhysicalDevice
		uint32_t amountOfQueueFamilies = 0;
		vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &amountOfQueueFamilies, NULL);
		VkQueueFamilyProperties* queueFamilyProperties = new VkQueueFamilyProperties[amountOfQueueFamilies];
		//Properties of QueueFamilies:
		std::cout << "Amount of Queue Families: " << amountOfQueueFamilies << std::endl;
		for (int i = 0; i < amountOfQueueFamilies; i++)
		{
			std::cout << std::endl;
			std::cout << "Queue-Familiy #" << i << std::endl;
			std::cout << "VK_QUEUE_GRAPHICS_BIT " << ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) << std::endl;
			std::cout << "VK_QUEUE_COMPUTE_BIT " << ((queueFamilyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT)) << std::endl;
			std::cout << "VK_QUEUE_TRANSFER_BIT " << ((queueFamilyProperties[i].queueFlags & VK_QUEUE_TRANSFER_BIT)) << std::endl;
			std::cout << "VK_QUEUE_SPARS_BINDING_BIT " << ((queueFamilyProperties[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)) << std::endl;
			std::cout << "Amount Of Queues: " << queueFamilyProperties[i].queueCount << std::endl;
			std::cout << "Timestamp Valid Bits: " << queueFamilyProperties[i].timestampValidBits << std::endl;
			std::cout << "Min Image TimeStamp Granularity: " << queueFamilyProperties[i].minImageTransferGranularity.width << "," << queueFamilyProperties[i].minImageTransferGranularity.height << "," << queueFamilyProperties[i].minImageTransferGranularity.depth << std::endl;
		}
		VkSurfaceCapabilitiesKHR surfaceCapabilities;
		vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCapabilities);
		std::cout << "Surface capabilities: " << std::endl;
		std::cout << "\tminImageCount:           " << surfaceCapabilities.minImageCount << std::endl;
		std::cout << "\tmaxImageCount:           " << surfaceCapabilities.maxImageCount << std::endl;
		std::cout << "\tcurrentExtent:           " << surfaceCapabilities.currentExtent.width << "/" <<surfaceCapabilities.currentExtent.height << std::endl;
		std::cout << "\tminImageExtent:          " << surfaceCapabilities.minImageExtent.width << "/" << surfaceCapabilities.minImageExtent.height << std::endl;
		std::cout << "\tmaxImageExtent:          " << surfaceCapabilities.maxImageExtent.width << "/" << surfaceCapabilities.minImageExtent.height << std::endl;
		std::cout << "\tmaxImageArrayLayers:     " << surfaceCapabilities.maxImageArrayLayers << std::endl;
		std::cout << "\tsupportedTransforms:     " << surfaceCapabilities.supportedTransforms << std::endl;
		std::cout << "\tcurrentTransform:        " << surfaceCapabilities.currentTransform << std::endl;
		std::cout << "\tsupportedCompositeAlpha: " << surfaceCapabilities.supportedCompositeAlpha << std::endl;
		std::cout << "\tsupportedUsageFlags:     " << surfaceCapabilities.supportedUsageFlags << std::endl;
		const float queuePrios[] = { 1.0f };
		VkDeviceQueueCreateInfo deviceQueueCreateInfo;
		deviceQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
		deviceQueueCreateInfo.pNext = NULL;
		deviceQueueCreateInfo.flags = 0;
		deviceQueueCreateInfo.queueFamilyIndex = 0;	//TODO Pick best QueueFamilyIndex for my application -> What is best?
		int amountOfQueues = 1;
		if (queueFamilyProperties[0].queueCount >= amountOfQueues)
		{
			deviceQueueCreateInfo.queueCount = amountOfQueues;
		}
		else
		{
			deviceQueueCreateInfo.queueCount = queueFamilyProperties[0].queueCount;
		}
		deviceQueueCreateInfo.pQueuePriorities = queuePrios;
		VkPhysicalDeviceFeatures usedFeatures = {};
		VkDeviceCreateInfo deviceCreateInfo;
		deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
		deviceCreateInfo.pNext = NULL;
		deviceCreateInfo.flags = 0;
		deviceCreateInfo.queueCreateInfoCount = 1;
		deviceCreateInfo.pQueueCreateInfos = &deviceQueueCreateInfo;
		deviceCreateInfo.enabledLayerCount = 0;
		deviceCreateInfo.ppEnabledLayerNames = NULL;
		deviceCreateInfo.enabledExtensionCount = 0;
		deviceCreateInfo.ppEnabledExtensionNames = NULL;
		deviceCreateInfo.pEnabledFeatures = &usedFeatures;
		VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, NULL, &device); //TODO pick best device
		if (result != VK_SUCCESS)
		{
			std::cerr << "Vulkan-Mistake at Creating logical Device" << std::endl;
		}
		VkQueue queue;
		vkGetDeviceQueue(device, 0, 0, &queue);
		delete[] physicalDevices;
		delete[] queueFamilyProperties;
	}
}
void GraphicEngine::gameLoop()
{
	while (!glfwWindowShouldClose(window))
	{
		glfwPollEvents();
	}
}
void GraphicEngine::shutdownVulkan()
{
	vkDeviceWaitIdle(device);
	vkDestroySurfaceKHR(instance, surface, nullptr);
	vkDestroyDevice(device, NULL);
	vkDestroyInstance(instance, NULL);
}
void GraphicEngine::shutdownGLFW()
{
	glfwDestroyWindow(window);
}

The error while creating the surface cannot be the cause for the unnormal values at the queueFamilies. I think the bits of the graphic_bit, computing_bit should be 0 or 1 but not 2 or 4 as at my example.
But maybe I’ve made a little mistake in my code?


#4

Vulkan requires little bit of discipline. I suggest to fight “laziness” and start to submit to it early (in the end saves you time and nerves). Your code lacks error checking of VkResults, and returns of glfw commands, meaning you do not even know if they completed (so any code after it may be meaningless and behave erratically).

if(val != VK_SUCCESS) __debugbreak(); is not quite conceptually right. Most VkResults are “real” runtime errors, meaning they should be catched in release build as well (not just in debug build). For logical errors there are the Validation Layers instead (to be used only in debug build).

Not sure what the empty #include does.

Do not use naked new, infidel! There is std::vector or std::string for that.

glfwVulkanSupported should be called for GLFW initialization I think.

You have uninitialized value for appInfo.pEngineName. Undefined Behavior.

const std::vector<const char> validationLayers. Should be <const char*>, I think. Funny that compiler accepted that…

I suggest you to also use glfwSetErrorCallback which should give you more specific error from GLFW.

Technically vkEnumerate* can return smaller count than you gave it. You should be checking amountOfPhysicalDevices for 0 even after vkEnumeratePhysicalDevices

Your immediate problem is you never call vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &amountOfQueueFamilies, queueFamilyProperties); so all of the props are unitialized when you print them.

Oh, and pls post code with appropriate formatting; your indenting is gone (do not use “quote”, use ``` block.


#5

Thanks for your help :slight_smile:
I repaired the little mistakes and created a better error-handling. With GLFW I have the problem, that I don’t know how to set the error-callback. I’ve tried to create a new Method for this:

void GraphicEngine::handleGLFWError(int error, const char * description)
{
	fprintf(stderr, "Error: %s\n", description);
} 

Then I tried to call the glfwSetErrorCallback function:

glfwSetErrorCallback(handleGLFWError);

But the argument is not compatible with parameter-type “GLFWerrorfun” - Any Ideas how to solve this issue?

An other issue while creating the surface is the result of 7 at creating the windowSurface:

result = glfwCreateWindowSurface(instance, window, NULL, &surface);

I get the needed Extensions for creating the instance through

uint32_t amountOfGLFWExtensions = 0;
auto glfwExtensions = glfwGetRequiredInstanceExtensions(&amountOfExtensions);

Through a short check the amountOfGLFWExtensions is updated correctly, it’s 2.

I’ve created a short list of all available extensions:

  • VK_KHR_surface
  • VK_KHR_win32_surface
  • VK_KHR_get_physical_device_properties2
  • VK_KHR_get_surface_capabilities2
  • VK_KHR_external_memory_capabilities
  • VK_KHR_device_group_creation
  • VK_KHR_external_semaphore_capabilities
  • VK_KHR_external_fence_capabilities
  • VK_EXT_debug_report
  • VK_EXT_debug_utils
  • VK_EXT_swapchain_colorspace

What extension I’m missing? And how could I get it?


#6

It’s a C++ issue. Pointer to method is different type than pointer to function. GLFW takes pointer to function. The callback has to either be static member function, or global.

Try to run with VK_LAYER_LUNARG_api_dump to see what the driver actually sees.

Check that vs the instance extension list from vulkaninfo.


#7

Okay, the problem with with error callback of glfw seems to be solved.

About the problem with the surface creation:
I’ve tried to run the programm with following Validation-Layers:

const std::vector<const char*> validationLayers = {
			"VK_LAYER_LUNARG_standard_validation"
			"VK_LAYER_LUNARG_api_dump"
		};

In the cmd Output has been changed nothing. But now Visual Studio creates a Breakpoint at the line where I create the Surface:

result = glfwCreateWindowSurface(instance, window, NULL, &surface);

The error-discription is: access to injury while reading in vulkan-1.dll…

The Extensions from running vulkaninfo is following:
The Instance Extension count is 11 like in my application.
VK_EXT_debug_report : extension revision 9
VK_EXT_debug_utils : extension revision
VK_EXT_swapchain_colorspace : extension revision 3
VK_KHR_device_group_creation : extension revision 1
VK_KHR_external_fence_capabilities : extension revision 1
VK_KHR_external_memory_capabilities : extension revision 1
VK_KHR_external_semaphore_capabilities: extension revision 1
VK_KHR_get_physical_device_properties2: extension revision 1
VK_KHR_get_surface_capabilities2 : extension revision 1
VK_KHR_surface : extension revision 25
VK_KHR_win32_surface : extension revision 6


#8

Oh, and you do not enable VK_EXT_debug_utils extension, so your validation layers are as good as defunct.

Set environment variable VK_INSTANCE_LAYERS to VK_LAYER_LUNARG_api_dump:VK_LAYER_KHRONOS_validation. (In VS you can do so conveniently for your project in the props for the Debug config). That takes care of everything for you.

Otherwisely, you need to enable the VK_EXT_debug_utils extension as well, and define your own callback, and provide it to VkCreateInstanceInfo as well as later load extension commands and create permanent messenger. E.g. see my init code here.


#9

Sry for my Question, but I doesn’t have work so much with Visual Studio.
When I set the environment variable VK_INSTANCE_LAYERS to VK_LAYER_LUNARG_api_dump:VK_LAYER_KHRONOS_validation
I does not need to enable the extension VK_EXT_debug_utils?
How can I set the environment variable? Project ->Properties ->Debugging->Environment?
How is the syntax for this step? VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump:VK_LAYER_KHRONOS_validation?


#10

Yeah, that way is meant as ez mode to enable the validation. By default it will report warnings+ to stderr. (Or otherwisely do whatever the vk_layer_config.txt says, if present.)

Yea.

VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump;VK_LAYER_KHRONOS_validation

That is equivalent to set in Windows command line, minus the “set”. Apparently with “;” as separator on Windows.


#11

Thanks for your help :slight_smile:

I removed the layer VK_LAYER_LUNARG_api_dump from my validationlayers vector, because this layer isn’t available on my system (output of vulkaninfo)

Now I can run my code without any breakboints - thats a good step in the right direction.
So after the I set the VK_INSTANCE_LAYERS I get an more detailed error about what Extension is missing.
GLFW need two extensions: VK_KHR_surface and VK_KHR_win32_surface
And there is the error: The last extension is not persent on my system. Any idea how to fix that?


#12

VK_LAYER_LUNARG_api_dump is available assuming you have properly installed SDK.

Above you listed that it is supported.


#13

With vulkaninfo I get all Extensions (11), there is also the VK_KHR_win32_surface.
But in the cmd is written:
Error: Win32: Vulkan instance missing VK_KHR_win32_surface extension.
A short time before I write all supported extensions into the cmd. Here the extension is listen up, too.

Is the mistake maybe that I compile in x64 and not x84?


#14

Hm, weird. I am pretty sure you are passing something weird to vkCreateInstance. Just try the VK_LAYER_LUNARG_api_dump to be certain. Either enabledExtensionCount or ppEnabledExtensionNames will be corrupt in some way. If VK_LAYER_LUNARG_api_dump is not available that in of itself is suspicious; reinstall your SDK.


#15

After I reinstalled the vulkan-sdk there are 11 Extensions like before, but 17 layers. So now I have the layer VK_LAYER_LUNARG_api_dump

const std::vector<const char*> validationLayers = {
			"VK_LAYER_LUNARG_standard_validation",
			"VK_LAYER_LUNARG_api_dump"
		};

		uint32_t amountOfGLFWExtensions = 0;
		auto glfwExtensions = glfwGetRequiredInstanceExtensions(&amountOfExtensions);
		std::cout << "Amount of GLFW-Extension: " << amountOfExtensions << std::endl;

This is the used code to define layers and extensions. With validationlayer "VK_LAYER_LUNARG_api_dump" I get a more detailed error-printing in cmd. The Layers are initialized correct, but there is a problem with extensions:
enabledExtensionCount: uint32_t = 0
ppEnabledExtensionNames: const char* const* = 00007FF611C05100

This is a little bit confusing because the extensionCount is not 0 - it was two. I’ve printed it to the cmd, too.
This code is used to create the instanceCreateInfo:

VkInstanceCreateInfo instanceCreateInfo;
		instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
		instanceCreateInfo.pNext = NULL;
		instanceCreateInfo.flags = 0;
		instanceCreateInfo.pApplicationInfo = &appInfo;
		instanceCreateInfo.enabledLayerCount = validationLayers.size();
		instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
		instanceCreateInfo.enabledExtensionCount = amountOfGLFWExtensions;
		instanceCreateInfo.ppEnabledExtensionNames = glfwExtensions;

Is there a mistake in the code? I don’t have an idea, what I am doing wrong…
*Edit: I’ve change the amountOfGLFWExtensions to 2:

instanceCreateInfo.enabledExtensionCount = 2;

Now, there is no error anymore. So it seems like something changed the value stored in
uint32_t amountOfGLFWExtensions because I printed the stored value of amountOfGLFWExtensions to console.

But I do not have an idea why the stored value is changed.

*Edit2: I found the solution: when set the amount of used extension I set amountOfExtensions and not amountOfGLFWExtensions…