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