Feature management

Extensions

As mentioned in the previous step about Core creation, you need to specify the Vulkan extensions and features which are required by the application or potentially useful for optimization but optional. For now we only focus on requirements though.

In case our application only requires some specific extensions. You can provide a list of those extension identifiers to the function creating the Core instance. The extension identifiers are just string constants in that case. For example:

{
  VK_KHR_SWAPCHAIN_EXTENSION_NAME,           // "VK_KHR_swapchain"
  VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, // "VK_KHR_shader_float16_int8"
  VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME  // "VK_EXT_descriptor_indexing"
}

Those string constants come directly from the Vulkan headers as macros. But you can also use the exact literals of course.


Features

However in most cases you don't just enable required extensions in Vulkan. You also need to specify the exact features to be used from this extension because even if an extension is available on your device, not all of its features might be available. So how can you do this with the framework?

vkcv::Features features;

// 1.) Require an extension by identifier as before via the list of strings:
features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);

// 2.) Require an extension by identifier but with certain required features:
//
// The type `vk::PhysicalDeviceDescriptorIndexingFeatures` specifies the features 
// class of the selected extension via a template parameter. The lambda expression 
// or function you provide additionally needs to use that type as well.
//
// All of those features classes for the Vulkan extensions are defined in the 
// Vulkan-hpp headers and the VkCV tries to support most of them.
//
features.requireExtensionFeature<vk::PhysicalDeviceDescriptorIndexingFeatures>(
  // extension identifier
  VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,                   
  
  // lambda expression to select certain features
  [](vk::PhysicalDeviceDescriptorIndexingFeatures& features) {
    features.setDescriptorBindingPartiallyBound(true);
  }
);

// 3.) Optionally enable an extension by identifier with certain features:
//
// This works equivalent to the previous call but it does not flag the extension 
// or its features as required. So the application won't fail if anything is 
// unsupported.
//
features.tryExtensionFeature<vk::PhysicalDevice16BitStorageFeatures>(
  VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME,
  [](vk::PhysicalDevice16BitStorageFeatures& features) {
    features.setStorageBuffer16BitAccess(true);
  }
);

In this example code lambda expressions and function templates (as member templates from the vkcv::Features class) are used.

Those three example use cases with the features object can be used for most extensions and the framework will automatically compare all the features, selected by setting their boolean value to true, with your device's capabilities. You can also query whether optional features have been enabled for your application in case they were supported. But that's not really necessary for the current guide. For our goal to draw a triangle it should be enough to require the "VK_KHR_swapchain" extension which is necessary to render in a window surface.


Core integration

As last part of using the features object from the VkCV framework, this is how you can pass it to the Core creation from the last step:

vkcv::Core core = vkcv::Core::create(
  applicationName,
  VK_MAKE_VERSION(0, 0, 1),
  {
    vk::QueueFlagBits::eTransfer,
    vk::QueueFlagBits::eGraphics,
    vk::QueueFlagBits::eCompute
  },
  
  // Just replace the list of extension identifiers with the features instance:
  features
);

Previous

Next

Popular posts from this blog

Introduction

Application development

First setup