Magnum::Vk::Instance class new in Git master

Instance.

Wraps a VkInstance and stores instance-specific Vulkan function pointers. An instance provides device enumeration and management of Vulkan layers that enable additional functionality such as command validation or tracing / debugging.

Instance creation

While an Instance can be default-constructed without much fuss, it's recommended to pass a InstanceCreateInfo with at least the argc / argv pair, which allows you to use various --magnum-* command-line options:

#include <Magnum/Vk/InstanceCreateInfo.h>



Vk::Instance instance{{argc, argv}};

In addition to command-line arguments, setting application info isn't strictly required either, but may be beneficial for the driver:

using namespace Containers::Literals;

Vk::Instance instance{Vk::InstanceCreateInfo{argc, argv}
    .setApplicationInfo("My Vulkan Application"_s, Vk::version(1, 2, 3))
};

The above won't enable any additional layers or extensions except for what the engine itself needs or what's supplied on the command line. Use InstanceCreateInfo::addEnabledLayers() and InstanceCreateInfo::addEnabledExtensions() to enable them, you can use both string names as well as predefined instance extensions from the Extensions namespace. Later on, presence of predefined extensions can be checked with isExtensionEnabled().

Vk::Instance instance{Vk::InstanceCreateInfo{argc, argv}
    
    .addEnabledLayers({"VK_LAYER_KHRONOS_validation"_s})
    .addEnabledExtensions<                          // predefined extensions
        Vk::Extensions::EXT::debug_report,
        Vk::Extensions::KHR::external_fence_capabilities>()
    .addEnabledExtensions({"VK_KHR_xcb_surface"_s}) // can be plain strings too
};

However, with the above approach, if any layer or extension isn't available, the instance creation will abort. The recommended workflow is thus first checking layer and extension availability using enumerateLayerProperties() and enumerateInstanceExtensionProperties():

/* Query layer and extension support */
Vk::LayerProperties layers = Vk::enumerateLayerProperties();
Vk::InstanceExtensionProperties extensions =
    /* ... including extensions exposed only by the extra layers */
    Vk::enumerateInstanceExtensionProperties(layers.names());

/* Enable only those that are supported */
Vk::InstanceCreateInfo info{argc, argv};
if(layers.isSupported("VK_LAYER_KHRONOS_validation"_s))
    info.addEnabledLayers({"VK_LAYER_KHRONOS_validation"_s});
if(extensions.isSupported<Vk::Extensions::EXT::debug_report>())
    info.addEnabledExtensions<Vk::Extensions::EXT::debug_report>();


Vk::Instance instance{info};

Next step after creating a Vulkan instance is picking and creating a Device.

Command-line options

The Instance is configurable through command-line options that are passed through the InstanceCreateInfo argc / argv parameters. If those are not passed, only the environment variables are used. A subset of these options is reused by a subsequently created Device as well.

<application> [--magnum-help]
    [--magnum-disable-workarounds LIST]
    [--magnum-disable-layers LIST]
    [--magnum-disable-extensions LIST]
    [--magnum-enable-layers LIST]
    [--magnum-enable-instance-extensions LIST]
    [--magnum-enable-extensions LIST]
    [--magnum-vulkan-version X.Y]
    [--magnum-log default|quiet|verbose]
    [--magnum-device ID|integrated|discrete|virtual|cpu] ...

Arguments:

  • ... — main application arguments (see -h or --help for details)
  • --magnum-help — display this help message and exit
  • --magnum-disable-workarounds LIST — Vulkan driver workarounds to disable (see Driver workarounds for detailed info) (environment: MAGNUM_DISABLE_WORKAROUNDS)
  • --magnum-disable-layers LIST — Vulkan layers to disable, meaning InstanceCreateInfo::addEnabledLayers() will skip them (environment: MAGNUM_DISABLE_LAYERS)
  • --magnum-disable-extensions LIST — Vulkan instance or device extensions to disable, meaning InstanceCreateInfo::addEnabledExtensions() and DeviceCreateInfo::addEnabledExtensions() will skip them (environment: MAGNUM_DISABLE_EXTENSIONS)
  • --magnum-enable-layers LIST — Vulkan layers to enable in addition to InstanceCreateInfo defaults and what the application requests (environment: MAGNUM_ENABLE_LAYERS)
  • --magnum-enable-instance-extensions LIST — Vulkan instance extensions to enable in addition to InstanceCreateInfo defaults and what the application requests (environment: MAGNUM_ENABLE_INSTANCE_EXTENSIONS)
  • --magnum-enable-extensions LIST — Vulkan device extensions to enable in addition to DeviceCreateInfo defaults and what the application requests (environment: MAGNUM_ENABLE_EXTENSIONS)
  • --magnum-vulkan-version X.Y — force Instance and Device Vulkan version instead of using what the instance / device reports as supported, affecting what entrypoints and extensions get used (environment: MAGNUM_VULKAN_VERSION)
  • --magnum-log default|quiet|verbose — console logging (environment: MAGNUM_LOG) (default: default)
  • --magnum-device ID|integrated|discrete|virtual|cpu — device ID or kind to pick in pickDevice(); if a device is selected through enumerateDevices() or any other way, this option has no effect (environment: MAGNUM_DEVICE)

Interaction with raw Vulkan code

In addition to the common properties explained in Common interfaces for interaction with raw Vulkan code, the Instance contains instance-level Vulkan function pointers, accessible through operator->():

Vk::Instance instance{};

VkPhysicalDeviceGroupPropertiesKHR properties[10];
UnsignedInt count = Containers::arraySize(properties);
instance->EnumeratePhysicalDeviceGroupsKHR(instance, &count, properties);

These functions are by default not accessible globally (and neither there is a global "current instance"), which is done in order to avoid multiple independent instances affecting each other. Sometimes it is however desirable to have global function pointers — for example when a 3rd party code needs to operate on the same instance, or when writing quick prototype code — and then it's possible to populate those using populateGlobalFunctionPointers(). Compared to the above, the same custom code would then look like this:

#include <MagnumExternal/Vulkan/flextVkGlobal.h>



instance.populateGlobalFunctionPointers();

VkPhysicalDeviceGroupPropertiesKHR properties[10];
UnsignedInt count = Containers::arraySize(properties);
vkEnumeratePhysicalDeviceGroupsKHR(instance, &count, properties);

Similarly you can use Device::populateGlobalFunctionPointers() to populate device-level global function pointers.

Disabled move and delayed instance creation

Similarly to Device, for safety reasons as all instance-dependent objects internally have to keep a pointer to the originating Instance to access Vulkan function pointers, the Instance class is not movable. This leads to a difference compared to other Vulkan object wrappers, where you can use the NoCreate tag to construct an empty instance (for example as a class member) and do a delayed creation by moving a new instance over the empty one. Here you have to use the create() function instead:

class MyApplication {
    public:
        explicit MyApplication();

    private:
        Vk::Instance _instance{NoCreate};
};

MyApplication::MyApplication() {
    // decide on layers, extensions, ...

    _instance.create(Vk::InstanceCreateInfo{}
        
    );
}

Similar case is with wrap() — instead of being static, you have to call it on a NoCreate'd instance.

Constructors, destructors, conversion operators

Instance(const InstanceCreateInfo& info = InstanceCreateInfo{}) explicit
Constructor.
Instance(NoCreateT) explicit
Construct without creating the instance.
Instance(const Instance&) deleted
Copying is not allowed.
Instance(Instance&&) deleted
Moving is not allowed.
~Instance()
Destructor.
operator VkInstance()

Public functions

void wrap(VkInstance handle, Version version, Containers::ArrayView<const Containers::StringView> enabledExtensions, HandleFlags flags = {})
Wrap existing Vulkan handle.
void wrap(VkInstance handle, Version version, std::initializer_list<Containers::StringView> enabledExtensions, HandleFlags flags = {})
auto operator=(const Instance&) -> Instance& deleted
Copying is not allowed.
auto operator=(Instance&&) -> Instance& deleted
Moving is not allowed.
auto handle() -> VkInstance
Underlying VkInstance handle.
auto handleFlags() const -> HandleFlags
Handle flags.
void create(const InstanceCreateInfo& info = InstanceCreateInfo{})
Create an instance.
auto tryCreate(const InstanceCreateInfo& info = InstanceCreateInfo{}) -> Result
Try to create an instance.
auto version() const -> Version
Version supported by the instance.
auto isVersionSupported(Version version) const -> bool
Whether given version is supported on the instance.
template<class E>
auto isExtensionEnabled() const -> bool
Whether given extension is enabled.
auto isExtensionEnabled(const InstanceExtension& extension) const -> bool
auto operator*() const -> const FlextVkInstance&
Instance-specific Vulkan function pointers.
auto operator->() const -> const FlextVkInstance*
auto release() -> VkInstance
Release the underlying Vulkan instance.
void populateGlobalFunctionPointers()
Populate global instance-level function pointers to be used with third-party code.

Function documentation

Magnum::Vk::Instance::Instance(const InstanceCreateInfo& info = InstanceCreateInfo{}) explicit

Constructor.

Equivalent to calling Instance(NoCreateT) followed by create(const InstanceCreateInfo&).

Magnum::Vk::Instance::Instance(NoCreateT) explicit

Construct without creating the instance.

The constructed instance is equivalent to moved-from state. Useful in cases where you will overwrite the instance later anyway. Move another object over it to make it useful.

Magnum::Vk::Instance::Instance(Instance&&) deleted

Moving is not allowed.

See Disabled move and delayed instance creation for more information.

Magnum::Vk::Instance::~Instance()

Destructor.

Destroys associated VkInstance handle, unless the instance was created using wrap() without HandleFlag::DestroyOnDestruction specified.

Magnum::Vk::Instance::operator VkInstance()

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void Magnum::Vk::Instance::wrap(VkInstance handle, Version version, Containers::ArrayView<const Containers::StringView> enabledExtensions, HandleFlags flags = {})

Wrap existing Vulkan handle.

Parameters
handle The VkInstance handle
version Vulkan version that's assumed to be used on the instance
enabledExtensions Extensions that are assumed to be enabled on the instance
flags Handle flags

The handle is expected to be of an existing Vulkan instance. The version and enabledExtensions parameters populate internal info about supported version and extensions and will be reflected in isVersionSupported() and isExtensionEnabled(), among other things. If enabledExtensions empty, the instance will behave as if no extensions were enabled.

Note that this function retrieves all instance-specific Vulkan function pointers, which is a relatively costly operation. It's thus not recommended to call this function repeatedly for creating short-lived instances, even though it's technically correct.

Unlike an instance created using a constructor, the Vulkan instance is by default not deleted on destruction, use flags for different behavior.

void Magnum::Vk::Instance::wrap(VkInstance handle, Version version, std::initializer_list<Containers::StringView> enabledExtensions, HandleFlags flags = {})

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Instance& Magnum::Vk::Instance::operator=(Instance&&) deleted

Moving is not allowed.

See Disabled move and delayed instance creation for more information.

void Magnum::Vk::Instance::create(const InstanceCreateInfo& info = InstanceCreateInfo{})

Create an instance.

Parameters
info Instance creation info

Meant to be called on a NoCreate'd instance. After creating the instance, populates instance-level function pointers and runtime information about enabled extensions based on info.

If instance creation fails, a message is printed to error output and the application exits — if you need a different behavior, use tryCreate() instead.

Result Magnum::Vk::Instance::tryCreate(const InstanceCreateInfo& info = InstanceCreateInfo{})

Try to create an instance.

Unlike create(), instead of exiting on error, prints a message to error output and returns a corresponding result value. On success returns Result::Success.

Version Magnum::Vk::Instance::version() const

Version supported by the instance.

Unless overriden using --magnum-vulkan-version on the command line, corresponds to enumerateInstanceVersion().

bool Magnum::Vk::Instance::isVersionSupported(Version version) const

Whether given version is supported on the instance.

Compares version against version().

template<class E>
bool Magnum::Vk::Instance::isExtensionEnabled() const

Whether given extension is enabled.

Accepts instance extensions from the Extensions namespace, listed also in the Vulkan support tables. Search complexity is $ \mathcal{O}(1) $ . Example usage:

if(instance.isExtensionEnabled<Vk::Extensions::EXT::debug_utils>()) {
    // use the fancy debugging APIs
} else if(instance.isExtensionEnabled<Vk::Extensions::EXT::debug_report>()) {
    // use the non-fancy and deprecated debugging APIs
} else {
    // well, tough luck
}

Note that this returns true only if given extension is supported by the driver and it was enabled via InstanceCreateInfo::addEnabledExtensions(). For querying extension support before creating an instance use InstanceExtensionProperties::isSupported().

bool Magnum::Vk::Instance::isExtensionEnabled(const InstanceExtension& extension) const

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

const FlextVkInstance& Magnum::Vk::Instance::operator*() const

Instance-specific Vulkan function pointers.

Function pointers are implicitly stored per-instance, use populateGlobalFunctionPointers() to populate the global vk* functions.

const FlextVkInstance* Magnum::Vk::Instance::operator->() const

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

VkInstance Magnum::Vk::Instance::release()

Release the underlying Vulkan instance.

Releases ownership of the Vulkan instance and returns its handle so vkDestroyInstance() is not called on destruction. The internal state is then equivalent to moved-from state.

void Magnum::Vk::Instance::populateGlobalFunctionPointers()

Populate global instance-level function pointers to be used with third-party code.

Populates instance-level global function pointers so third-party code is able to call global instance-level vk* functions. See Interaction with raw Vulkan code for more information.