Skip to content

Latest commit

 

History

History
158 lines (122 loc) · 7.11 KB

README.adoc

File metadata and controls

158 lines (122 loc) · 7.11 KB

Using Vulkan profiles

This sample demonstrates the usage of the Vulkan Profiles Library. Profiles define a common requirement baseline of properties, features, extensions, etc. to make Vulkan applications more portable. Instead of having to check all of these in your app one by one at runtime, you use the profiles library to check if the selected device supports all the requirements of that given profile. If that’s the case, you then use the same library to create the device and/or instance. The library then takes care of enabling all the required features, extensions, etc. saving a lot of the otherwise common boilerplate.

We’ll show this in a sample that makes use of descriptor indexing.

The sample uses the VP_KHR_roadmap_2022 profile that enables a baseline of features and extensions for "newer mid-to-high-end devices shipping in 2022 or shortly thereafter across mainstream smartphone, tablet, laptops, console and desktop devices.". Details on what this profile contains can be found here.

Without profiles

Without using the profiles library, and with an api version that doesn’t have this as a core feature, one would have to manually enable features and extensions at device and/or instance creation. This could look something like this:

VkPhysicalDeviceFeatures enabled_features{};
VkPhysicalDeviceVulkan11Features enabled_features_11{};
VkPhysicalDeviceVulkan12Features enabled_features_12{};

enabled_features.fullDrawIndexUint32 = VK_TRUE;
enabled_features.imageCubeArray = VK_TRUE;
enabled_features.independentBlend = VK_TRUE;
enabled_features.ampleRateShading = VK_TRUE;
enabled_features.rawIndirectFirstInstance = VK_TRUE;
enabled_features.depthClamp = VK_TRUE;
enabled_features.depthBiasClamp = VK_TRUE;
enabled_features.samplerAnisotropy = VK_TRUE;
enabled_features.occlusionQueryPrecise = VK_TRUE;
enabled_features.fragmentStoresAndAtomics = VK_TRUE;
enabled_features.shaderStorageImageExtendedFormats = VK_TRUE;
enabled_features.shaderUniformBufferArrayDynamicIndexing = VK_TRUE;
enabled_features.shaderSampledImageArrayDynamicIndexing = VK_TRUE;
enabled_features.shaderStorageBufferArrayDynamicIndexing = VK_TRUE;
enabled_features.shaderStorageImageArrayDynamicIndexing = VK_TRUE;
...

enabled_features_11.samplerYcbcrConversion = VK_TRUE;
enabled_features_11.pNext = &enabled_features_12;
...

enabled_features_12.samplerMirrorClampToEdge = VK_TRUE;
enabled_features_12.descriptorIndexing = VK_TRUE;
enabled_features_12.shaderUniformTexelBufferArrayDynamicIndexing = VK_TRUE;
...

VkDeviceCreateInfo device_create_info = {};
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_create_info.pNext = &enabled_features_11;

VkResult result = vkCreateDevice(...);
if (!result) {
    app_terminate('Could not create device, reason:' + vk_result_str(result));
}

With each additional device feature this code would get longer and longer, as physical device features need to be chained via the pNext member.

With profiles

Using the profile library and a profile that requires all the above features and extension this can be simplified a lot:

// Profile to enable
const VpProfileProperties profile_properties = {VP_KHR_ROADMAP_2022_NAME, VP_KHR_ROADMAP_2022_SPEC_VERSION};

// Instance creation

VkBool32 profile_supported;
vpGetInstanceProfileSupport(nullptr, &profile_properties, &profile_supported);
if (!profile_supported) {
    app_terminate("The selected profile is not supported!");
}

VkInstanceCreateInfo create_info{};
create_info.sType                   = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.ppEnabledExtensionNames = enabled_extensions.data();
create_info.enabledExtensionCount   = static_cast<uint32_t>(enabled_extensions.size());

VpInstanceCreateInfo instance_create_info{};
instance_create_info.pEnabledFullProfiles    = &profile_properties;
instance_create_info.enabledFullProfileCount = 1;
instance_create_info.pCreateInfo             = &create_info;
result = vpCreateInstance(&instance_create_info, nullptr, &vulkan_instance);

// Device creation

std::vector<const char *> enabled_extensions;
enabled_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);

VkDeviceCreateInfo create_info{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
create_info.pNext                   = gpu.get_extension_feature_chain();
create_info.pQueueCreateInfos       = &queue_create_info;
create_info.queueCreateInfoCount    = 1;
create_info.enabledExtensionCount   = static_cast<uint32_t>(enabled_extensions.size());
create_info.ppEnabledExtensionNames = enabled_extensions.data();

VkBool32 profile_supported;
vpGetPhysicalDeviceProfileSupport(instance->get_handle(), gpu.get_handle(), &profile_properties, &profile_supported);
if (!profile_supported) {
    app_terminate("The selected profile is not supported (error at creating the device)!");
}

VpDeviceCreateInfo deviceCreateInfo{};
deviceCreateInfo.pCreateInfo             = &create_info;
deviceCreateInfo.pEnabledFullProfiles    = &profile_properties;
deviceCreateInfo.enabledFullProfileCount = 1;
VkResult result = vpCreateDevice(gpu.get_handle(), &deviceCreateInfo, nullptr, &vulkan_device);

This will enable all features and extensions defined in the selected profile, including descriptor indexing. By passing pCreateInfo of the instance and/or device you can also enable additional extensions not part of the profile.

Inspecting the device created using a profile in a graphics debugger like RenderDoc we can see that the profile library did the following based on the profile we selected:

Set the appropriate Vulkan version at instance creation:

RenderDoc instance Api version

Enabled device features and setup the pNext chain:

RenderDoc device pNext

And also enabled all required extensions (incl. explicitly requested ones):

RenderDoc device extensions

Conclusion

Using profiles makes setting up a baseline of extensions and features a lot easier. It also saves lots of code as you no longer have to worry about enabling extensions, setting up their feature structs and properly chaining the pNext structures.