CopperSpice API  1.9.1
QVulkanInstance Class Reference

Provides functionality to create a Vulkan instance. More...

Public Typedefs

using DebugFilter = std::function< bool (VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *)>
 
using InstanceFlags = QFlags< InstanceOptions >
 

Public Types

enum  InstanceOptions : uint32_t
 

Public Methods

 QVulkanInstance ()
 
 ~QVulkanInstance ()
 
QVersionNumber apiVersion () const
 
bool create ()
 
void destroy ()
 
QVulkanDeviceFunctionsdeviceFunctions (VkDevice device)
 
VkResult errorCode () const
 
QStringList extensions () const
 
InstanceFlags flags () const
 
QVulkanFunctionsfunctions () const
 
PFN_vkVoidFunction getInstanceProcAddr (const char *name)
 
uint32_t installDebugOutputFilter (QVulkanInstance::DebugFilter filter)
 
bool isValid () const
 
QStringList layers () const
 
void presentAboutToBeQueued (QWindow *window)
 
void presentQueued (QWindow *window)
 
void removeDebugOutputFilter (uint32_t filter)
 
void resetDeviceFunctions (VkDevice device)
 
void setApiVersion (const QVersionNumber &vulkanVersion)
 
void setExtensions (const QStringList &extensions)
 
void setFlags (InstanceFlags flags)
 
void setLayers (const QStringList &layers)
 
void setVkInstance (VkInstance existingVkInstance)
 
QVersionNumber supportedApiVersion () const
 
QVector< QVulkanExtensionPropertiessupportedExtensions () const
 
QVector< QVulkanLayerPropertiessupportedLayers () const
 
VkInstance vkInstance () const
 

Static Public Methods

static VkSurfaceKHR surfaceForWindow (QWindow *window)
 

Detailed Description

The QVulkanInstance class is used to load the Vulkan library by creating an instance. An instance is the connection between your CopperSpice application and the Vulkan library.

For more information about a Vulkan instance refer to the following tutorial. Creating an Instance

Platform specific support for Vulkan instances and windows with Vulkan capable surfaces is provided by the various platform plugins. Not all platforms support Vulkan and when running on an unsupported platform calling create() will fail and always return false.

Vulkan API Versions

The functions from Vulkan 1.1 will always be available. For newer versions like 1.3, the QVulkanDeviceFunctions or QVulkanFuntions objects will attempt to resolve the API calls. If the Vulkan physical device does not support a particular function then calling making this call can cause unspecified behavior.

To enable support for Vulkan versions higher than 1.1 an appropriate instance API version may need to be set by calling setApiVersion() before calling create(). Applications are expected to check the physical device apiVersion in the VkPhysicalDeviceProperties structure.

To query the Vulkan implementation version, call supportedApiVersion().

Initialization

Like QOpenGLContext, the Vulkan instance creation does not happen until create() is called. Calling the methods supportedLayers() and supportedExtensions() will return the supported instance level layers and extensions. These two methods are safe to call before calling create(). The create() method connects to the Vulkan library and constructs a VkInstance object which is required for almost every other method in CsVulkan. Normally there is only on VkInstance per user application.

In order to render graphics using Vulkan and have the result be displayed as part of your application user interface you must create a QWindow or QVulkanWinow and pass the QVulkanInstance by calling QWindow::setVulkanInstance(). The following code is a very basic example of these steps.

int main(int argc, char **argv)
{
QApplication app(argc, argv);
QVulkanInstance instance;
if (! instance.create()) {
return EXIT_FAILURE;
}
QVulkanWindow *window = new QVulkanWindow();
window->setVulkanInstance(&instance);
window->show();
return app.exec();
}

Configuration

QVulkanInstance automatically enables the minimum set of extensions it needs on the newly created instance. In practice this means the "VK_KHR_<OS>_surface" family of extensions.

By default Vulkan debug output, for example messages from the validation layers, is routed to qDebug(). This can be disabled by passing the flag NoDebugOutputRedirect to setFlags() before invoking create().

To enable additional layers and extensions, provide the list via setLayers() and setExtensions() before invoking create(). When a given layer or extension is not reported as available from the instance, the request is ignored. After a successful call to create(), the values returned from functions like layers() and extensions() reflect the actual enabled layers and extensions. When necessary, for example to avoid requesting extensions that conflict and thus would fail the Vulkan instance creation, the list of actually supported layers and extensions can be examined via supportedLayers() and supportedExtensions() before calling create().

For example, to enable the standard validation layers, one could do the following.

// enable validation layer if supported. Messages go to qDebug by default.
inst.setLayers(QStringList() << "VK_LAYER_LUNARG_standard_validation");
bool ok = inst.create();
if (! ok) {
// Vulkan not available
}
if (! inst.layers().contains("VK_LAYER_LUNARG_standard_validation")) {
// validation layer not available
}

Alternatively, to make decisions before attempting to create a Vulkan instance use the following code.

if (inst.supportedLayers().contains("VK_LAYER_LUNARG_standard_validation")) {
// validation layer is supported
}
bool ok = inst.create();

Adopting an Existing Instance

By default QVulkanInstance creates a new Vulkan instance. When working with external engines and renderers, this may sometimes not be desirable. When there is a VkInstance handle already available, call setVkInstance() before invoking create(). This way no additional instances will get created, and QVulkanInstance will not own the handle.

Note
It is up to the component creating the external instance to ensure the necessary extensions are enabled on it. These are: "VK_KHR_surface", the WSI specific "VK_KHR_<OS>_surface" that is appropriate for the platform in question, and "VK_EXT_debug_report" in case QVulkanInstance's debug output redirection is desired.

Accessing Core Vulkan Commands

To access the VkInstance handle the QVulkanInstance wraps, call vkInstance(). To resolve Vulkan functions call getInstanceProcAddr(). For core Vulkan commands manual resolving is not necessary as they are provided via the QVulkanFunctions and QVulkanDeviceFunctions objects accessible via functions() and deviceFunctions().

Getting a Native Vulkan Surface for a Window

The two common windowing system specific operations are getting a surface (a VkSurfaceKHR handle) for a window, and querying if a given queue family supports presenting to a given surface. To avoid WSI-specific bits in the applications, these are abstracted by QVulkanInstance and the underlying QPA layers.

To create a Vulkan surface for a window, or retrieve an existing one, call surfaceForWindow(). Most platforms will only create the surface via "VK_KHR_<OS>_surface" when first calling surfaceForWindow(), but there may be platform-specific variations in the internal behavior. Once created, subsequent calls to surfaceForWindow() just return the same handle. This fits the structure of typical Vulkan enabled QWindow subclasses well.

Troubleshooting

Besides returning false from create() or nullptr from surfaceForWindow(), critical errors will also be sent to the debug output via qWarning(). The actual Vulkan error code from instance creation can be retrieved by calling errorCode() after calling create() fails.

Example

The following is the basic outline of creating a Vulkan capable QWindow.

class VulkanWindow : public QWindow
{
public:
VulkanWindow() {
setSurfaceType(VulkanSurface);
}
void exposeEvent(QExposeEvent *) {
if (isExposed()) {
if (! m_initialized) {
m_initialized = true;
// initialize device, swapchain, etc.
QVulkanInstance *inst = vulkanInstance();
uint32_t devCount = 0;
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, nullptr);
// build the first frame
render();
}
}
}
bool event(QEvent *e) {
if (e->type() == QEvent::UpdateRequest) {
render();
}
return QWindow::event(e);
}
void render() {
requestUpdate(); // render continuously
}
private:
bool m_initialized = false;
};
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
if (! inst.create()) {
qWarning("Vulkan not available");
return 1;
}
VulkanWindow window;
window.showMaximized();
return app.exec();
}
Note
In addition to expose, a well-behaving window implementation will also have to take care of additional events like resize and QPlatformSurfaceEvent in order to ensure proper management of the swap chain. Additionally, some platforms may require releasing resources when not being exposed anymore.

Using Vulkan third party Libraries

The CsVulkan library is responsible for destroying the VkInstance, VkSurfaceKHR, and VkDevice objects. If you are using other third party Vulkan libraries or need to access these objects directly, the ownership of these objects must remain with CsVulkan.

Some third party libraries call Vulkan functions directly. To use one of these libraries your application will need to link with CsVulkan and the Vulkan API.

See also
QVulkanFunctions, QSurface::SurfaceType

Member Typedef Documentation

Typedef for debug filtering callback functions.

See also
installDebugOutputFilter(), removeDebugOutputFilter()

Member Enumeration Documentation

This enum describes the flags which can be passed to setFlags(). They control the behavior of create().

Constant Value Description
QVulkanInstance::NoDebugOutputRedirect 0x01 Disables Vulkan debug output (VK_EXT_debug_report) redirection to qDebug.

Constructor & Destructor Documentation

QVulkanInstance::QVulkanInstance ( )
deprecated

Constructs a new instance. No Vulkan initialization is performed in the constructor.

QVulkanInstance::~QVulkanInstance ( )

Destroys the QVulkanInstance. Calling the current() method will return a nullptr once the instance is destroyed.

Method Documentation

QVersionNumber QVulkanInstance::apiVersion ( ) const

Returns the requested Vulkan API version against which the application expects to run, or a null version number if setApiVersion() was not called before create().

bool QVulkanInstance::create ( )

Initializes the Vulkan library and creates a new or adopts and existing Vulkan instance. Returns true if successful, false on error or when Vulkan is not supported. When successful, the pointer to this QVulkanInstance is retrievable via the static function current().

The Vulkan instance and library is available as long as this QVulkanInstance exists or until destroy() is called.

void QVulkanInstance::destroy ( )

Destroys the underlying platform instance, thus destroying the VkInstance (when owned). The QVulkanInstance object is still reusable by calling create() again.

QVulkanDeviceFunctions * QVulkanInstance::deviceFunctions ( VkDevice  device)

Returns the QVulkanDeviceFunctions object that exposes the device level core Vulkan command set and is guaranteed to be functional cross platform.

The Vulkan functions in the returned object must only be called with device or a child object (VkQueue, VkCommandBuffer) of device as their first parameter. This is because these functions are resolved via vkGetDeviceProcAddr in order to avoid the potential overhead of internal dispatching.

Note
The returned object is owned and managed by the QVulkanInstance. Do not destroy or alter it.
The object is cached so calling this function with the same device again is a cheap operation. However, when the device gets destroyed, it is up to the application to notify the QVulkanInstance by calling resetDeviceFunctions().
See also
functions(), resetDeviceFunctions()
VkResult QVulkanInstance::errorCode ( ) const

Returns the Vulkan error code after an unsuccessful call to create(), otherwise return VK_SUCCESS. The value is typically the return value from vkCreateInstance() (when creating a new Vulkan instance instead of adopting an existing one), but may also be VK_NOT_READY if the platform plugin does not support Vulkan.

QStringList QVulkanInstance::extensions ( ) const

Returns the enabled instance extensions if create() was called and was successful. The requested extensions otherwise.

QVulkanInstance::InstanceFlags QVulkanInstance::flags ( ) const

Returns the requested flags.

QVulkanFunctions * QVulkanInstance::functions ( ) const

Returns the corresponding QVulkanFunctions object that exposes the core Vulkan command set, excluding device level functions, and is guaranteed to be functional cross-platform.

Note
The returned object is owned and managed by the QVulkanInstance. Do not destroy or alter it.
See also
deviceFunctions(), supportedApiVersion()
PFN_vkVoidFunction QVulkanInstance::getInstanceProcAddr ( const char *  name)

Resolves the Vulkan function with the given name.

For core Vulkan commands prefer using the function wrappers retrievable from functions() and deviceFunctions() instead.

uint32_t QVulkanInstance::installDebugOutputFilter ( QVulkanInstance::DebugFilter  filter)

Installs a filter function that is called for every Vulkan debug message. When the callback returns true, the message is stopped (filtered out) and will not appear on the debug output. Filtering is only effective when NoDebugOutputRedirect is not set. Installing filters has no effect otherwise.

This method can be called before create().

See also
removeDebugOutputFilter()
bool QVulkanInstance::isValid ( ) const

Returns true if create() was successful and the instance is valid.

QStringList QVulkanInstance::layers ( ) const

Returns the enabled instance layers, if create() was called and was successful. The requested layers otherwise.

void QVulkanInstance::presentAboutToBeQueued ( QWindow window)

This method should be called by the application's renderer before queuing a present operation for window.

While on some platforms this will be a no-op, some may perform windowing system dependent synchronization. For example, on Wayland this will add send a wl_surface.frame request in order to prevent the driver from blocking for minimized windows.

void QVulkanInstance::presentQueued ( QWindow window)

This method should be called by the application's renderer after queuing a present operation for window.

While on some platforms this will be a no-op, some may perform windowing system dependent synchronization. For example, on X11 this will update _NET_WM_SYNC_REQUEST_COUNTER.

void QVulkanInstance::removeDebugOutputFilter ( uint32_t  filter)

Removes a filter function previously installed by installDebugOutputFilter().

This method can be called before create().

See also
installDebugOutputFilter()
void QVulkanInstance::resetDeviceFunctions ( VkDevice  device)

Invalidates and destroys the QVulkanDeviceFunctions object for the given device. This method must be called when a VkDevice, for which deviceFunctions() was called, gets destroyed while the application intends to continue running, possibly creating a new logical Vulkan device later on.

There is no need to call this before destroying the QVulkanInstance since clean up is performed automatically.

See also
deviceFunctions()
void QVulkanInstance::setApiVersion ( const QVersionNumber vulkanVersion)

Specifies the highest Vulkan API version the application is designed to use. By default the vulkanVersion is 0 which maps to Vulkan 1.1.

This method can only be called before create() and has no effect when called afterwards.

See also
supportedApiVersion()
void QVulkanInstance::setExtensions ( const QStringList extensions)

Specifies the list of additional instance extensions to enable. It is safe to specify unsupported extensions as well because these get ignored when not supported at run time. The surface extensions required by CsVulkan will be added automatically.

This method can only be called before create() and has no effect when called afterwards

void QVulkanInstance::setFlags ( QVulkanInstance::InstanceFlags  flags)

Configures the behavior of create() based on the provided flags.

This method should be called before create() and has no effect if called afterwards.

void QVulkanInstance::setLayers ( const QStringList layers)

Specifies the list of instance layers to enable. It is safe to specify unsupported layers as well because these get ignored when not supported at run time.

This method should be called before create() and has no effect if called afterwards.

void QVulkanInstance::setVkInstance ( VkInstance  existingVkInstance)

Makes QVulkanInstance adopt an existing VkInstance handle instead of creating a new one. The given existingVkInstance must have at least "VK_KHR_surface" and the appropriate WSI specific "VK_KHR_<OS>_surface" extensions enabled. To ensure debug output redirection is functional "VK_EXT_debug_report" is needed as well.

This method should be called before create() and has no effect if called afterwards.

QVersionNumber QVulkanInstance::supportedApiVersion ( ) const

Returns the version of instance level functionality supported by the Vulkan implementation. This is the value returned from vkEnumerateInstanceVersion() if that function is available.

Applications which want to adjust the usage of the Vulkan API based on the Vulkan version available on the target system should use this method to determine what version to pass to setApiVersion() before calling create().

This method can be called before create().

See also
setApiVersion()
QVector< QVulkanExtensionProperties > QVulkanInstance::supportedExtensions ( ) const

Returns the list of supported instance-level extensions.

This method can be called before create().

QVector< QVulkanLayerProperties > QVulkanInstance::supportedLayers ( ) const

Returns the list of supported instance level layers.

This method can be called before create().

VkSurfaceKHR QVulkanInstance::surfaceForWindow ( QWindow window)
static

Creates or retrieves the already existing VkSurfaceKHR handle for the given window. Returns the Vulkan surface handle or a nullptr if this fails.

VkInstance QVulkanInstance::vkInstance ( ) const

Return the VkInstance handle this QVulkanInstance wraps or nullptr if create() has not yet been successfully called and no existing instance has been provided via setVkInstance().