Vulkan instance
The concept
The instance is the first step in initializing the Vulkan library. It establishes the connection between our application and the Vulkan library — it is the first piece of our Graphics context.
To create an instance, we need a few components. The first one is a struct
called VkApplicationInfo.
vk::ApplicationInfo appInfo{};
appInfo.pApplicationName = "Hello Triangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "Gamegine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = vk::ApiVersion14;This structure is optional, as the driver does not really need it to run the
basic graphics pipeline. If we assign nullptr to pApplicationInfo in the
instance creation structure (we will come back to this a little later), Vulkan
will use the default values. It will consider that:
- The application has no specific name or version.
- The targeted API version is the oldest supported (usually Vulkan 1.0).
However, omitting it is generally considered bad practice for real-world applications.
First, fields like applicationName and engineName act as hints to the
driver. GPU vendors (like NVIDIA or AMD) can detect these names to apply
specific driver-level optimizations or workarounds tailored to our engine. These
fields are also invaluable for debugging tools (like RenderDoc) to properly
identify our application.
Second, and most importantly, defining the apiVersion is critical. If we rely
on the default (Vulkan 1.0), we may be locked out of modern core features
introduced in later versions (such as Vulkan 1.2 or 1.3), even if the hardware
supports them.
What the instance enables
Two more things are configured at instance creation, each with its own note:
- Vulkan validation layers — debugging help attached to the instance during development.
- Vulkan extensions — the capabilities Vulkan needs to talk to the platform (window manager, debug utils, MoltenVK on macOS).
Create the instance
When all of this is set, we can create our instance by providing all the
elements we prepared to another struct, VkInstanceCreateInfo:
vk::InstanceCreateInfo createInfo{};
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledLayerCount = static_cast<uint32_t>(layers.size());
createInfo.ppEnabledLayerNames = layers.data();
#if defined(__APPLE__)
// Required for MoltenVK portability enumeration
createInfo.flags = vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
#endif
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
createInfo.ppEnabledExtensionNames = extensions.data();And then we can initialize our instance:
d_instance = vk::raii::Instance(d_context, createInfo);