Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qvulkaninstance.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6#include <qpa/qplatformvulkaninstance.h>
7#include <qpa/qplatformintegration.h>
8#include <qpa/qplatformnativeinterface.h>
9#include <QtGui/private/qguiapplication_p.h>
10
11QT_BEGIN_NAMESPACE
12
13/*!
14 \class QVulkanInstance
15 \since 5.10
16 \ingroup painting-3D
17 \inmodule QtGui
18
19 \brief The QVulkanInstance class represents a native Vulkan instance, enabling
20 Vulkan rendering onto a QSurface.
21
22 \l{https://www.khronos.org/vulkan/}{Vulkan} is a cross-platform, explicit
23 graphics and compute API. This class provides support for loading a Vulkan
24 library and creating an \c instance in a cross-platform manner. For an
25 introduction on Vulkan instances, refer
26 \l{https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#initialization-instances}{to
27 section 3.2 of the specification}.
28
29 \note Platform-specific support for Vulkan instances and windows with
30 Vulkan-capable surfaces is provided by the various platform plugins. Not
31 all of them will support Vulkan, however. When running on such a platform,
32 create() will fail and always return \c false.
33
34 \note Vulkan support may get automatically disabled for a given Qt build due
35 to not having the necessary Vulkan headers available at build time. When
36 this is the case, and the output of \c configure indicates Vulkan support is
37 disabled, the QVulkan* classes will be unavailable.
38
39 \note Some functions changed their signature between the various Vulkan
40 header revisions. When building Qt and only headers with the old,
41 conflicting signatures are present in a system, Vulkan support will get
42 disabled. It is recommended to use headers from Vulkan 1.0.39 or newer.
43
44 \section1 Initialization
45
46 Similarly to QOpenGLContext, any actual Vulkan instance creation happens
47 only when calling create(). This allows using QVulkanInstance as a plain
48 member variable while retaining control over when to perform
49 initialization.
50
51 Querying the supported instance-level layers and extensions is possible by
52 calling supportedLayers() and supportedExtensions(). These ensure the
53 Vulkan library is loaded, and can therefore be called safely before
54 create() as well.
55
56 Instances store per-application Vulkan state and creating a \c VkInstance
57 object initializes the Vulkan library. In practice there will typically be
58 a single instance constructed early on in main(). The object then stays
59 alive until exiting the application.
60
61 Every Vulkan-based QWindow must be associated with a QVulkanInstance by
62 calling QWindow::setVulkanInstance(). Thus a typical application pattern is
63 the following:
64
65 \snippet code/src_gui_vulkan_qvulkaninstance.cpp 0
66
67 \section1 Configuration
68
69 QVulkanInstance automatically enables the minimum set of extensions it
70 needs on the newly created instance. In practice this means the
71 \c{VK_KHR_*_surface} family of extensions.
72
73 By default Vulkan debug output, for example messages from the validation
74 layers, is routed to qDebug(). This can be disabled by passing the flag
75 \c NoDebugOutputRedirect to setFlags() \e before invoking create().
76
77 To enable additional layers and extensions, provide the list via
78 setLayers() and setExtensions() \e before invoking create(). When a
79 given layer or extension is not reported as available from the instance,
80 the request is ignored. After a successful call to create(), the values
81 returned from functions like layers() and extensions() reflect the actual
82 enabled layers and extensions. When necessary, for example to avoid
83 requesting extensions that conflict and thus would fail the Vulkan instance
84 creation, the list of actually supported layers and extensions can be
85 examined via supportedLayers() and supportedExtensions() before calling
86 create().
87
88 For example, to enable the standard validation layers, one could do the
89 following:
90
91 \snippet code/src_gui_vulkan_qvulkaninstance.cpp 1
92
93 Or, alternatively, to make decisions before attempting to create a Vulkan
94 instance:
95
96 \snippet code/src_gui_vulkan_qvulkaninstance.cpp 2
97
98 \section1 Adopting an Existing Instance
99
100 By default QVulkanInstance creates a new Vulkan instance. When working with
101 external engines and renderers, this may sometimes not be desirable. When
102 there is a \c VkInstance handle already available, call setVkInstance()
103 before invoking create(). This way no additional instances will get
104 created, and QVulkanInstance will not own the handle.
105
106 \note It is up to the component creating the external instance to ensure
107 the necessary extensions are enabled on it. These are: \c{VK_KHR_surface},
108 the WSI-specific \c{VK_KHR_*_surface} that is appropriate for the platform
109 in question, and \c{VK_EXT_debug_utils} in case QVulkanInstance's debug
110 output redirection is desired.
111
112 \section1 Accessing Core Vulkan Commands
113
114 To access the \c VkInstance handle the QVulkanInstance wraps, call
115 vkInstance(). To resolve Vulkan functions, call getInstanceProcAddr(). For
116 core Vulkan commands manual resolving is not necessary as they are provided
117 via the QVulkanFunctions and QVulkanDeviceFunctions objects accessible via
118 functions() and deviceFunctions().
119
120 \note QVulkanFunctions and QVulkanDeviceFunctions are generated from the
121 Vulkan API XML specifications when building the Qt libraries. Therefore no
122 documentation is provided for them. They contain the Vulkan 1.2 functions
123 with the same signatures as described in the
124 \l{https://www.khronos.org/registry/vulkan/specs/1.2/html/}{Vulkan API
125 documentation}.
126
127 \section1 Getting a Native Vulkan Surface for a Window
128
129 The two common windowing system specific operations are getting a surface
130 (a \c{VkSurfaceKHR} handle) for a window, and querying if a given queue
131 family supports presenting to a given surface. To avoid WSI-specific bits
132 in the applications, these are abstracted by QVulkanInstance and the
133 underlying QPA layers.
134
135 To create a Vulkan surface for a window, or retrieve an existing one,
136 call surfaceForWindow(). Most platforms will only create the surface via
137 \c{VK_KHR_*_surface} when first calling surfaceForWindow(), but there may be
138 platform-specific variations in the internal behavior. Once created,
139 subsequent calls to surfaceForWindow() just return the same handle. This
140 fits the structure of typical Vulkan-enabled QWindow subclasses well.
141
142 To query if a given queue family within a physical device can be used to
143 perform presentation to a given surface, call supportsPresent(). This
144 encapsulates both the generic \c vkGetPhysicalDeviceSurfaceSupportKHR and
145 the WSI-specific \c{vkGetPhysicalDevice*PresentationSupportKHR} checks.
146
147 \section1 Troubleshooting
148
149 Besides returning \c false from create() or \c 0 from surfaceForWindow(),
150 critical errors will also get printed to the debug output via qWarning().
151 Additional logging can be requested by enabling debug output for the
152 logging category \c{qt.vulkan}. The actual Vulkan error code from instance
153 creation can be retrieved by calling errorCode() after a failing create().
154
155 In some special cases it may be necessary to override the Vulkan
156 library name. This can be achieved by setting the \c{QT_VULKAN_LIB}
157 environment variable.
158
159 \section1 Example
160
161 The following is the basic outline of creating a Vulkan-capable QWindow:
162
163 \snippet code/src_gui_vulkan_qvulkaninstance.cpp 3
164
165 \note In addition to expose, a well-behaving window implementation will
166 also have to take care of additional events like resize and
167 QPlatformSurfaceEvent in order to ensure proper management of the
168 swap chain. Additionally, some platforms may require releasing resources
169 when not being exposed anymore.
170
171 \section1 Using C++ Bindings for Vulkan
172
173 Combining Qt's Vulkan enablers with a C++ Vulkan wrapper, for example
174 \l{https://github.com/KhronosGroup/Vulkan-Hpp}{Vulkan-Hpp}, is possible as
175 well. The pre-requisite here is that the C++ layer must be able to adopt
176 native handles (VkInstance, VkSurfaceKHR) in its classes without taking
177 ownership (since the ownership stays with QVulkanInstance and QWindow).
178 Consider also the following:
179
180 \list
181
182 \li Some wrappers require exception support to be enabled. Qt does not use
183 exceptions. To enable exceptions for the application, add \c{CONFIG += exceptions}
184 to the \c{.pro} file.
185
186 \li Some wrappers call Vulkan functions directly, assuming \c{vulkan.h}
187 provides prototypes and the application links to a Vulkan library exporting
188 all necessary symbols. Qt may not directly link to a Vulkan library.
189 Therefore, on some platforms it may be necessary to add
190 \c{LIBS += -lvulkan} or similar in the application's \c{.pro} file.
191
192 \li The headers for the QVulkan classes may include \c{vulkan.h} with
193 \c{VK_NO_PROTOTYPES} enabled. This can cause issues in C++ wrapper headers
194 that rely on the prototypes. Hence in application code it may be
195 necessary to include \c{vulkan.hpp} or similar before any of the QVulkan
196 headers.
197
198 \endlist
199
200 \sa QVulkanFunctions, QSurface::SurfaceType
201*/
202
203/*!
204 \enum QVulkanInstance::Flag
205 \since 5.10
206
207 This enum describes the flags that can be passed to setFlags(). These control
208 the behavior of create().
209
210 \value NoDebugOutputRedirect Disables Vulkan debug output (\c{VK_EXT_debug_utils}) redirection to qDebug.
211 \value [since 6.5] NoPortabilityDrivers Disables enumerating physical devices marked as Vulkan Portability.
212*/
213
214bool QVulkanInstancePrivate::ensureVulkan()
215{
216 if (!platformInst) {
217 platformInst.reset(QGuiApplicationPrivate::platformIntegration()->createPlatformVulkanInstance(q_ptr));
218 if (!platformInst) {
219 qWarning("QVulkanInstance: Failed to initialize Vulkan");
220 return false;
221 }
222 }
223 return true;
224}
225
226void QVulkanInstancePrivate::reset()
227{
228 qDeleteAll(deviceFuncs);
229 deviceFuncs.clear();
230 funcs.reset();
231 platformInst.reset();
232 vkInst = VK_NULL_HANDLE;
233 errorCode = VK_SUCCESS;
234}
235
236/*!
237 Constructs a new instance.
238
239 \note No Vulkan initialization is performed in the constructor.
240 */
241QVulkanInstance::QVulkanInstance()
242 : d_ptr(new QVulkanInstancePrivate(this))
243{
244}
245
246/*!
247 Destructor.
248
249 \note \l {QVulkanInstance::}{vkInstance()} will return \nullptr once the
250 instance is destroyed.
251 */
252QVulkanInstance::~QVulkanInstance()
253{
254 destroy();
255}
256
257/*!
258 \class QVulkanLayer
259 \inmodule QtGui
260 \brief Represents information about a Vulkan layer.
261 */
262
263/*!
264 \variable QVulkanLayer::name
265 \brief The name of the layer.
266 */
267
268/*!
269 \variable QVulkanLayer::version
270 \brief The version of the layer. This is an integer, increasing with each backward
271 compatible change.
272 */
273
274/*!
275 \variable QVulkanLayer::specVersion
276 \brief The Vulkan version the layer was written against.
277 */
278
279/*!
280 \variable QVulkanLayer::description
281 \brief The description of the layer.
282 */
283
284/*!
285 \fn bool operator==(const QVulkanLayer &lhs, const QVulkanLayer &rhs)
286 \since 5.10
287 \relates QVulkanLayer
288
289 Returns \c true if Vulkan layers \a lhs and \a rhs have
290 the same name, version, and spec version.
291*/
292
293/*!
294 \fn bool operator!=(const QVulkanLayer &lhs, const QVulkanLayer &rhs)
295 \since 5.10
296 \relates QVulkanLayer
297
298 Returns \c true if Vulkan layers \a lhs and \a rhs have
299 different name, version, or spec version.
300*/
301
302/*!
303 \fn size_t qHash(const QVulkanLayer &key, size_t seed = 0)
304 \since 5.10
305 \qhashold{QVulkanLayer}
306*/
307
308/*!
309 \class QVulkanExtension
310 \inmodule QtGui
311 \brief Represents information about a Vulkan extension.
312 */
313
314/*!
315 \variable QVulkanExtension::name
316 \brief The name of the extension.
317 */
318
319/*!
320 \variable QVulkanExtension::version
321 \brief The version of the extension. This is an integer, increasing with each backward
322 compatible change.
323 */
324
325/*!
326 \fn bool operator==(const QVulkanExtension &lhs, const QVulkanExtension &rhs)
327 \since 5.10
328 \relates QVulkanExtension
329
330 Returns \c true if Vulkan extensions \a lhs and \a rhs are have the
331 same name and version.
332*/
333
334/*!
335 \fn bool operator!=(const QVulkanExtension &lhs, const QVulkanExtension &rhs)
336 \since 5.10
337 \relates QVulkanExtension
338
339 Returns \c true if Vulkan extensions \a lhs and \a rhs are have different
340 name or version.
341*/
342
343/*!
344 \fn size_t qHash(const QVulkanExtension &key, size_t seed = 0)
345 \since 5.10
346 \qhashold{QVulkanExtension}
347*/
348
349/*!
350 \class QVulkanInfoVector
351 \inmodule QtGui
352 \brief A specialized QList for QVulkanLayer and QVulkanExtension.
353
354 QVulkanInfoVector<T> is a template class where \a T is either
355 QVulkanLayer or QVulkanExtension.
356 */
357
358/*!
359 \fn template<typename T> bool QVulkanInfoVector<T>::contains(const QByteArray &name) const
360
361 \return true if the list contains a layer or extension with the given \a name.
362 */
363
364/*!
365 \fn template<typename T> bool QVulkanInfoVector<T>::contains(const QByteArray &name, int minVersion) const
366
367 \return true if the list contains a layer or extension with the given
368 \a name and a version same as or newer than \a minVersion.
369 */
370
371/*!
372 \fn QVulkanInfoVector<QVulkanLayer> QVulkanInstance::supportedLayers() const
373 \return the list of supported instance-level layers.
374
375 \note This function can be called before create().
376 */
377
378/*!
379 \internal
380 */
381QVulkanInfoVector<QVulkanLayer> QVulkanInstance::supportedLayers()
382{
383 return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedLayers() : QVulkanInfoVector<QVulkanLayer>();
384}
385
386/*!
387 \fn QVulkanInfoVector<QVulkanExtension> QVulkanInstance::supportedExtensions() const
388 \return the list of supported instance-level extensions.
389
390 \note This function can be called before create().
391 */
392
393/*!
394 \internal
395 */
396QVulkanInfoVector<QVulkanExtension> QVulkanInstance::supportedExtensions()
397{
398 return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedExtensions() : QVulkanInfoVector<QVulkanExtension>();
399}
400
401/*!
402 \return the version of instance-level functionality supported by the Vulkan
403 implementation.
404
405 In practice this is either the value returned from
406 vkEnumerateInstanceVersion, if that function is available (with Vulkan 1.1
407 and newer), or 1.0.
408
409 Applications that want to branch in their Vulkan feature and API usage
410 based on what Vulkan version is available at run time, can use this function
411 to determine what version to pass in to setApiVersion() before calling
412 create().
413
414 \note This function can be called before create().
415
416 \sa setApiVersion()
417 */
418QVersionNumber QVulkanInstance::supportedApiVersion() const
419{
420 return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedApiVersion() : QVersionNumber();
421}
422
423/*!
424 Makes QVulkanInstance adopt an existing VkInstance handle instead of
425 creating a new one.
426
427 \note \a existingVkInstance must have at least \c{VK_KHR_surface} and the
428 appropriate WSI-specific \c{VK_KHR_*_surface} extensions enabled. To ensure
429 debug output redirection is functional, \c{VK_EXT_debug_utils} is needed as
430 well.
431
432 \note This function can only be called before create() and has no effect if
433 called afterwards.
434 */
435void QVulkanInstance::setVkInstance(VkInstance existingVkInstance)
436{
437 if (isValid()) {
438 qWarning("QVulkanInstance already created; setVkInstance() has no effect");
439 return;
440 }
441
442 d_ptr->vkInst = existingVkInstance;
443}
444
445/*!
446 Configures the behavior of create() based on the provided \a flags.
447
448 \note This function can only be called before create() and has no effect if
449 called afterwards.
450 */
451void QVulkanInstance::setFlags(Flags flags)
452{
453 if (isValid()) {
454 qWarning("QVulkanInstance already created; setFlags() has no effect");
455 return;
456 }
457
458 d_ptr->flags = flags;
459}
460
461/*!
462 Specifies the list of instance \a layers to enable. It is safe to specify
463 unsupported layers as well because these get ignored when not supported at
464 run time.
465
466 \note This function can only be called before create() and has no effect if
467 called afterwards.
468 */
469void QVulkanInstance::setLayers(const QByteArrayList &layers)
470{
471 if (isValid()) {
472 qWarning("QVulkanInstance already created; setLayers() has no effect");
473 return;
474 }
475
476 d_ptr->layers = layers;
477}
478
479/*!
480 Specifies the list of additional instance \a extensions to enable. It is
481 safe to specify unsupported extensions as well because these get ignored
482 when not supported at run time.
483
484 \note The surface-related extensions required by Qt (for example, \c
485 VK_KHR_win32_surface) will always be added automatically, no need to
486 include them in this list.
487
488 \note \c VK_KHR_portability_enumeration is added automatically unless the
489 NoPortabilityDrivers flag is set. This value was introduced in Qt 6.5.
490
491 \note This function can only be called before create() and has no effect if
492 called afterwards.
493 */
494void QVulkanInstance::setExtensions(const QByteArrayList &extensions)
495{
496 if (isValid()) {
497 qWarning("QVulkanInstance already created; setExtensions() has no effect");
498 return;
499 }
500
501 d_ptr->extensions = extensions;
502}
503
504/*!
505 Specifies the highest Vulkan API version the application is designed to use.
506
507 By default \a vulkanVersion is 0, which maps to Vulkan 1.0.
508
509 \note This function can only be called before create() and has no effect if
510 called afterwards.
511
512 \note Be aware that Vulkan 1.1 changes the behavior with regards to the
513 Vulkan API version field. In Vulkan 1.0 specifying an unsupported \a
514 vulkanVersion led to failing create() with \c VK_ERROR_INCOMPATIBLE_DRIVER,
515 as was mandated by the specification. Starting with Vulkan 1.1, the
516 specification disallows this, the driver must accept any version without
517 failing the instance creation.
518
519 Application developers are advised to familiarize themselves with the \c
520 apiVersion notes in
521 \l{https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html}{the
522 Vulkan specification}.
523
524 \sa supportedApiVersion()
525 */
526void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion)
527{
528 if (isValid()) {
529 qWarning("QVulkanInstance already created; setApiVersion() has no effect");
530 return;
531 }
532
533 d_ptr->apiVersion = vulkanVersion;
534}
535
536/*!
537 Initializes the Vulkan library and creates a new or adopts and existing
538 Vulkan instance.
539
540 \return true if successful, false on error or when Vulkan is not supported.
541
542 When successful, the pointer to this QVulkanInstance is retrievable via
543 \l {QVulkanInstance::}{vkInstance()}.
544
545 The Vulkan instance and library is available as long as this
546 QVulkanInstance exists, or until destroy() is called.
547
548 By default the VkInstance is created with the flag
549 \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateFlagBits.html}{VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR}
550 set. This means that Vulkan Portability physical devices get enumerated as
551 well. If this is not desired, set the NoPortabilityDrivers flag.
552 */
553bool QVulkanInstance::create()
554{
555 if (isValid())
556 destroy();
557
558 if (!d_ptr->ensureVulkan())
559 return false;
560
561 d_ptr->platformInst->createOrAdoptInstance();
562
563 if (d_ptr->platformInst->isValid()) {
564 d_ptr->vkInst = d_ptr->platformInst->vkInstance();
565 d_ptr->layers = d_ptr->platformInst->enabledLayers();
566 d_ptr->extensions = d_ptr->platformInst->enabledExtensions();
567 d_ptr->errorCode = VK_SUCCESS;
568 d_ptr->funcs.reset(new QVulkanFunctions(this));
569 d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
570 d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
571 return true;
572 }
573
574 qWarning("Failed to create platform Vulkan instance");
575 if (d_ptr->platformInst) {
576 d_ptr->errorCode = d_ptr->platformInst->errorCode();
577 d_ptr->platformInst.reset();
578 } else {
579 d_ptr->errorCode = VK_NOT_READY;
580 }
581 return false;
582}
583
584/*!
585 Destroys the underlying platform instance, thus destroying the VkInstance
586 (when owned). The QVulkanInstance object is still reusable by calling
587 create() again.
588 */
589void QVulkanInstance::destroy()
590{
591 d_ptr->reset();
592}
593
594/*!
595 \return true if create() was successful and the instance is valid.
596 */
597bool QVulkanInstance::isValid() const
598{
599 return d_ptr->platformInst && d_ptr->platformInst->isValid();
600}
601
602/*!
603 \return the Vulkan error code after an unsuccessful create(), \c VK_SUCCESS otherwise.
604
605 The value is typically the return value from vkCreateInstance() (when
606 creating a new Vulkan instance instead of adopting an existing one), but
607 may also be \c VK_NOT_READY if the platform plugin does not support Vulkan.
608 */
609VkResult QVulkanInstance::errorCode() const
610{
611 return d_ptr->errorCode;
612}
613
614/*!
615 \return the VkInstance handle this QVulkanInstance wraps, or \nullptr if
616 create() has not yet been successfully called and no existing instance has
617 been provided via setVkInstance().
618 */
619VkInstance QVulkanInstance::vkInstance() const
620{
621 return d_ptr->vkInst;
622}
623
624/*!
625 \return the requested flags.
626 */
627QVulkanInstance::Flags QVulkanInstance::flags() const
628{
629 return d_ptr->flags;
630}
631
632/*!
633 \return the enabled instance layers, if create() was called and was successful. The
634 requested layers otherwise.
635 */
636QByteArrayList QVulkanInstance::layers() const
637{
638 return d_ptr->layers;
639}
640
641/*!
642 \return the enabled instance extensions, if create() was called and was
643 successful. The requested extensions otherwise.
644 */
645QByteArrayList QVulkanInstance::extensions() const
646{
647 return d_ptr->extensions;
648}
649
650/*!
651 \return the requested Vulkan API version against which the application
652 expects to run, or a null version number if setApiVersion() was not called
653 before create().
654 */
655QVersionNumber QVulkanInstance::apiVersion() const
656{
657 return d_ptr->apiVersion;
658}
659
660/*!
661 Resolves the Vulkan function with the given \a name.
662
663 For core Vulkan commands prefer using the function wrappers retrievable from
664 functions() and deviceFunctions() instead.
665 */
666PFN_vkVoidFunction QVulkanInstance::getInstanceProcAddr(const char *name)
667{
668 // The return value is PFN_vkVoidFunction instead of QFunctionPointer or
669 // similar because on some platforms honoring VKAPI_PTR is important.
670 return d_ptr->platformInst->getInstanceProcAddr(name);
671}
672
673/*!
674 \return the platform Vulkan instance corresponding to this QVulkanInstance.
675
676 \internal
677 */
678QPlatformVulkanInstance *QVulkanInstance::handle() const
679{
680 return d_ptr->platformInst.data();
681}
682
683/*!
684 \return the corresponding QVulkanFunctions object that exposes the core
685 Vulkan command set, excluding device level functions, and is guaranteed to
686 be functional cross-platform.
687
688 \note The returned object is owned and managed by the QVulkanInstance. Do
689 not destroy or alter it.
690
691 The functions from the core Vulkan 1.0 API will be available always. When it
692 comes to higher Vulkan versions, such as, 1.1 and 1.2, the QVulkanFunctions
693 object will try to resolve the core API functions for those as well, but if
694 the Vulkan instance implementation at run time has no support for those,
695 calling any such unsupported function will lead to unspecified behavior. In
696 addition, to properly enable support for Vulkan versions higher than 1.0, an
697 appropriate instance API version may need to be set by calling
698 setApiVersion() before create(). To query the Vulkan implementation's
699 instance-level version, call supportedApiVersion().
700
701 \sa deviceFunctions(), supportedApiVersion()
702 */
703QVulkanFunctions *QVulkanInstance::functions() const
704{
705 return d_ptr->funcs.data();
706}
707
708/*!
709 \return the QVulkanDeviceFunctions object that exposes the device level
710 core Vulkan command set and is guaranteed to be functional cross-platform.
711
712 \note The Vulkan functions in the returned object must only be called with
713 \a device or a child object (VkQueue, VkCommandBuffer) of \a device as
714 their first parameter. This is because these functions are resolved via
715 \l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetDeviceProcAddr.html}{vkGetDeviceProcAddr}
716 in order to avoid the potential overhead of internal dispatching.
717
718 \note The returned object is owned and managed by the QVulkanInstance. Do
719 not destroy or alter it.
720
721 \note The object is cached so calling this function with the same \a device
722 again is a cheap operation. However, when the device gets destroyed, it is up
723 to the application to notify the QVulkanInstance by calling
724 resetDeviceFunctions().
725
726 The functions from the core Vulkan 1.0 API will be available always. When
727 it comes to higher Vulkan versions, such as, 1.1 and 1.2, the
728 QVulkanDeviceFunctions object will try to resolve the core API functions
729 for those as well, but if the Vulkan physical device at run time has no
730 support for those, calling any such unsupported function will lead to
731 unspecified behavior. To properly enable support for Vulkan versions higher
732 than 1.0, an appropriate instance API version may need to be set by calling
733 setApiVersion() before create(). In addition, applications are expected to
734 check the physical device's apiVersion in VkPhysicalDeviceProperties.
735
736 \sa functions(), resetDeviceFunctions()
737 */
738QVulkanDeviceFunctions *QVulkanInstance::deviceFunctions(VkDevice device)
739{
740 QVulkanDeviceFunctions *&f = d_ptr->deviceFuncs[device];
741 if (!f)
742 f = new QVulkanDeviceFunctions(this, device);
743 return f;
744}
745
746/*!
747 Invalidates and destroys the QVulkanDeviceFunctions object for the given
748 \a device.
749
750 This function must be called when a VkDevice, for which deviceFunctions()
751 was called, gets destroyed while the application intends to continue
752 running, possibly creating a new logical Vulkan device later on.
753
754 There is no need to call this before destroying the QVulkanInstance since
755 clean up is then performed automatically.
756
757 \sa deviceFunctions()
758 */
759void QVulkanInstance::resetDeviceFunctions(VkDevice device)
760{
761 QVulkanDeviceFunctions *&f = d_ptr->deviceFuncs[device];
762 delete f;
763 f = nullptr;
764}
765
766/*!
767 Creates or retrieves the already existing \c{VkSurfaceKHR} handle for the
768 given \a window.
769
770 \return the Vulkan surface handle or 0 when failed.
771 */
772VkSurfaceKHR QVulkanInstance::surfaceForWindow(QWindow *window)
773{
774 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
775 // VkSurfaceKHR is non-dispatchable and maps to a pointer on x64 and a uint64 on x86.
776 // Therefore a pointer is returned from the platform plugin, not the value itself.
777 void *p = nativeInterface->nativeResourceForWindow(QByteArrayLiteral("vkSurface"), window);
778 return p ? *static_cast<VkSurfaceKHR *>(p) : VK_NULL_HANDLE;
779}
780
781/*!
782 \return true if the queue family with \a queueFamilyIndex within the
783 \a physicalDevice supports presenting to \a window.
784
785 Call this function when examining the queues of a given Vulkan device, in
786 order to decide which queue can be used for performing presentation.
787 */
788bool QVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window)
789{
790 return d_ptr->platformInst->supportsPresent(physicalDevice, queueFamilyIndex, window);
791}
792
793/*!
794 This function should be called by the application's renderer before queuing
795 a present operation for \a window.
796
797 While on some platforms this will be a no-op, some may perform windowing
798 system dependent synchronization. For example, on Wayland this will
799 add send a wl_surface.frame request in order to prevent the driver from
800 blocking for minimized windows.
801
802 \since 5.15
803 */
804void QVulkanInstance::presentAboutToBeQueued(QWindow *window)
805{
806 d_ptr->platformInst->presentAboutToBeQueued(window);
807}
808
809/*!
810 This function should be called by the application's renderer after queuing
811 a present operation for \a window.
812
813 While on some platforms this will be a no-op, some may perform windowing
814 system dependent synchronization. For example, on X11 this will update
815 \c{_NET_WM_SYNC_REQUEST_COUNTER}.
816 */
817void QVulkanInstance::presentQueued(QWindow *window)
818{
819 d_ptr->platformInst->presentQueued(window);
820}
821
822/*!
823 \typedef QVulkanInstance::DebugFilter
824
825 Typedef for debug filtering callback functions, with the following signature:
826
827 \code
828 bool myDebugFilter(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object,
829 size_t location, int32_t messageCode, const char *pLayerPrefix, const char *pMessage)
830 \endcode
831
832 Returning \c true suppresses the printing of the message.
833
834 \note Starting with Qt 6.5 \c{VK_EXT_debug_utils} is used instead of the
835 deprecated \c{VK_EXT_debug_report}. The callback signature is based on
836 VK_EXT_debug_report. Therefore, not all arguments can be expected to be
837 valid anymore. Avoid relying on arguments other than \c pMessage, \c
838 messageCode, and \c object. Applications wishing to access all the callback
839 data as specified in VK_EXT_debug_utils should migrate to DebugUtilsFilter.
840
841 \sa installDebugOutputFilter(), removeDebugOutputFilter()
842 */
843
844/*!
845 \overload
846
847 Installs a \a filter function that is called for every Vulkan debug
848 message. When the callback returns \c true, the message is stopped (filtered
849 out) and will not appear on the debug output.
850
851 \note Filtering is only effective when NoDebugOutputRedirect is not
852 \l{setFlags()}{set}. Installing filters has no effect otherwise.
853
854 \note This function can be called before create().
855
856 \sa removeDebugOutputFilter()
857 */
858void QVulkanInstance::installDebugOutputFilter(DebugFilter filter)
859{
860 if (!d_ptr->debugFilters.contains(filter)) {
861 d_ptr->debugFilters.append(filter);
862 if (d_ptr->platformInst)
863 d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
864 }
865}
866
867/*!
868 \overload
869
870 Removes a \a filter function previously installed by
871 installDebugOutputFilter().
872
873 \note This function can be called before create().
874
875 \sa installDebugOutputFilter()
876 */
877void QVulkanInstance::removeDebugOutputFilter(DebugFilter filter)
878{
879 d_ptr->debugFilters.removeOne(filter);
880 if (d_ptr->platformInst)
881 d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
882}
883
884/*!
885 \typedef QVulkanInstance::DebugUtilsFilter
886
887 Typedef for debug filtering callback functions, with the following signature:
888
889 \code
890 std::function<bool(DebugMessageSeverityFlags severity, DebugMessageTypeFlags type, const void *message)>;
891 \endcode
892
893 The \c message argument is a pointer to the
894 VkDebugUtilsMessengerCallbackDataEXT structure. Refer to the documentation
895 of \c{VK_EXT_debug_utils} for details. The Qt headers do not use the real
896 type in order to avoid introducing a dependency on post-1.0 Vulkan headers.
897
898 Returning \c true suppresses the printing of the message.
899
900 \sa installDebugOutputFilter(), removeDebugOutputFilter()
901 \since 6.5
902 */
903
904/*!
905 \enum QVulkanInstance::DebugMessageSeverityFlag
906 \since 6.5
907
908 \value VerboseSeverity
909 \value InfoSeverity
910 \value WarningSeverity
911 \value ErrorSeverity
912 */
913
914/*!
915 \enum QVulkanInstance::DebugMessageTypeFlag
916 \since 6.5
917
918 \value GeneralMessage
919 \value ValidationMessage
920 \value PerformanceMessage
921 */
922
923/*!
924 Installs a \a filter function that is called for every Vulkan debug
925 message. When the callback returns \c true, the message is stopped (filtered
926 out) and will not appear on the debug output.
927
928 \note Filtering is only effective when NoDebugOutputRedirect is not
929 \l{setFlags()}{set}. Installing filters has no effect otherwise.
930
931 \note This function can be called before create().
932
933 \sa clearDebugOutputFilters()
934 \since 6.5
935 */
936void QVulkanInstance::installDebugOutputFilter(DebugUtilsFilter filter)
937{
938 d_ptr->debugUtilsFilters.append(filter);
939 if (d_ptr->platformInst)
940 d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
941}
942
943/*!
944 Removes all filter functions installed previously by
945 installDebugOutputFilter().
946
947 \note This function can be called before create().
948
949 \sa installDebugOutputFilter()
950 \since 6.5
951 */
952void QVulkanInstance::clearDebugOutputFilters()
953{
954 d_ptr->debugFilters.clear();
955 d_ptr->debugUtilsFilters.clear();
956 if (d_ptr->platformInst) {
957 d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
958 d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
959 }
960}
961
962#ifndef QT_NO_DEBUG_STREAM
963QDebug operator<<(QDebug dbg, const QVulkanLayer &layer)
964{
965 QDebugStateSaver saver(dbg);
966 dbg.nospace() << "QVulkanLayer(" << layer.name << " " << layer.version
967 << " " << layer.specVersion << " " << layer.description << ")";
968 return dbg;
969}
970
971QDebug operator<<(QDebug dbg, const QVulkanExtension &extension)
972{
973 QDebugStateSaver saver(dbg);
974 dbg.nospace() << "QVulkanExtension(" << extension.name << " " << extension.version << ")";
975 return dbg;
976}
977#endif
978
979QT_END_NAMESPACE
QDebug operator<<(QDebug dbg, const QFileInfo &fi)