Jump to content

Getting Started with Vulkan


Josh

3,517 views

 Share

The latest design of my OpenGL renderer using bindless textures has some problems, and although these can be resolved, I think I have hit the limit on how useful an initial OpenGL implementation will be for the new engine. I decided it was time to dive into the Vulkan API. This is sort of scary, because I feel like it sets me back quite a lot, but at the same time the work I do with this will carry forward much better. A Vulkan-based renderer can run on Windows, Linux, Mac, iOS, Android, PS4, and Nintendo Switch.

So far my impressions of the API are pretty good. Although it is very verbose, it gives you a lot of control over things that were previously undefined or vendor-specific hacks. Below is code that initializes Vulkan and chooses a rendering device, with a preference for discrete GPUs over integrated graphics.

VkInstance inst;
VkResult res;
VkDevice device;

VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "MyGame";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "TurboEngine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;

// Get extensions
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, availableExtensions.data());
std::vector<const char*> extensions;

VkInstanceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledExtensionCount = (uint32_t)extensions.size();
createInfo.ppEnabledExtensionNames = extensions.data();

#ifdef DEBUG
createInfo.enabledLayerCount = 1;
const char* DEBUG_LAYER = "VK_LAYER_LUNARG_standard_validation";
createInfo.ppEnabledLayerNames = &DEBUG_LAYER;
#endif

res = vkCreateInstance(&createInfo, NULL, &inst);
if (res == VK_ERROR_INCOMPATIBLE_DRIVER)
{
	std::cout << "cannot find a compatible Vulkan ICD\n";
	exit(-1);
}
else if (res)
{
	std::cout << "unknown error\n";
	exit(-1);
}

//Enumerate devices
uint32_t gpu_count = 1;
std::vector<VkPhysicalDevice> devices;
res = vkEnumeratePhysicalDevices(inst, &gpu_count, NULL);
if (gpu_count > 0)
{			
	devices.resize(gpu_count);
	res = vkEnumeratePhysicalDevices(inst, &gpu_count, &devices[0]);
	assert(!res && gpu_count >= 1);
}

//Sort list with discrete GPUs at the beginning
std::vector<VkPhysicalDevice> sorteddevices;
for (int n = 0; n < devices.size(); n++)
{
	VkPhysicalDeviceProperties deviceprops = VkPhysicalDeviceProperties{};
	vkGetPhysicalDeviceProperties(devices[n], &deviceprops);
	if (deviceprops.deviceType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
	{
		sorteddevices.insert(sorteddevices.begin(),devices[n]);
	}
	else
	{
		sorteddevices.push_back(devices[n]);
	}
}
devices = sorteddevices;

VkDeviceQueueCreateInfo queue_info = {};
unsigned int queue_family_count;

for (int n = 0; n < devices.size(); ++n)
{
	vkGetPhysicalDeviceQueueFamilyProperties(devices[n], &queue_family_count, NULL);
	if (queue_family_count >= 1)
	{
		std::vector<VkQueueFamilyProperties> queue_props;
		queue_props.resize(queue_family_count);
		vkGetPhysicalDeviceQueueFamilyProperties(devices[n], &queue_family_count, queue_props.data());

		if (queue_family_count >= 1)
		{
			bool found = false;
			for (int i = 0; i < queue_family_count; i++)
			{
				if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
				{
					queue_info.queueFamilyIndex = i;
					found = true;
					break;
				}
			}
			if (!found) continue;

			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;

			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.enabledExtensionCount = 0;
			device_info.ppEnabledExtensionNames = NULL;
			device_info.enabledLayerCount = 0;
			device_info.ppEnabledLayerNames = NULL;
			device_info.pEnabledFeatures = NULL;

			res = vkCreateDevice(devices[n], &device_info, NULL, &device);
			if (res == VK_SUCCESS)
			{
				VkPhysicalDeviceProperties deviceprops = VkPhysicalDeviceProperties{};
				vkGetPhysicalDeviceProperties(devices[n], &deviceprops);
						
				std::cout << deviceprops.deviceName;

				vkDestroyDevice(device, NULL);
				break;
			}
		}
	}
}

vkDestroyInstance(inst, NULL);

 

  • Like 3
  • Upvote 1
 Share

9 Comments


Recommended Comments

5 hours ago, gamecreator said:

Do you already know if it will be faster than OpenGL and if so, by how much?  Or is that subject to testing?

Our new engine makes speed gains in a different way and I don't think Vulkan will make anything faster at all, honestly, over what the engine could do with OpenGL 4.3. We already have zero driver overhead, but Vulkan is more widely supported and the brand is synonymous with speed in the customer's mind. I know this because when I talk to people in person the first thing they say is "does it use Vulkan?"

It will be a lot faster than Leadwerks 4 but so was the OpenGL implementation.

Using Vulkan does not automatically make anything faster. No one will listen to me if I try to argue with that, which is fine, because I am just going to let everyone else mess up and I will make the fastest engine.

  • Confused 1
Link to comment

The best wishes in this project will surely be very pleasant results for users like us who are not real programmers.  :)

Link to comment

No, I don't consider myself a real programmer, that is to say the magic is done by the engine, I have no idea how to create a light, I have no idea how that light casts shadows on a static or dynamic mesh, I think that in this era of globalization we are made to believe that we are programmers when we use powerful tools such as Leadwerks, where the greatest work is already done, on the other hand we are users, creators of possible games, but the programmer in all this riddle is really you, the one who has the necessary tools for people like us to think we are programmers and create something fun.  


Translated with www.DeepL.com/Translator

Link to comment
1 hour ago, Josh said:

Using Vulkan does not automatically make anything faster.

This could be true.  I did some searches and one response said that it depends on if you can put it to use for your engine or game.  Wiki says something similar:

Quote

Vulkan is intended to offer higher performance and more balanced CPU/GPU usage ... Vulkan is said to induce anywhere from a marginal to polynomial speedup in run time relative to other APIs if implemented properly on the same hardware

 

  • Upvote 1
Link to comment

This is really complicated stuff, for really no good reason. I'm 600 lines into it and still can't even make a blue screen. :blink:

  • Confused 1
Link to comment

That confirms my suspicions, you are a programmer, I play to believe that I am, I know that you will succeed. 

Link to comment
Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...