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
4#include "qvulkaninstance_p.h"
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(other: QGuiApplicationPrivate::platformIntegration()->createPlatformVulkanInstance(instance: q_ptr));
217 if (!platformInst) {
218 qWarning(msg: "QVulkanInstance: Failed to initialize Vulkan");
219 return false;
220 }
221 }
222 return true;
223}
224
225void QVulkanInstancePrivate::reset()
226{
227 qDeleteAll(c: 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 \relates QVulkanLayer
305
306 Returns the hash value for the \a key, using \a seed to seed the
307 calculation.
308*/
309
310/*!
311 \class QVulkanExtension
312 \inmodule QtGui
313 \brief Represents information about a Vulkan extension.
314 */
315
316/*!
317 \variable QVulkanExtension::name
318 \brief The name of the extension.
319 */
320
321/*!
322 \variable QVulkanExtension::version
323 \brief The version of the extension. This is an integer, increasing with each backward
324 compatible change.
325 */
326
327/*!
328 \fn bool operator==(const QVulkanExtension &lhs, const QVulkanExtension &rhs)
329 \since 5.10
330 \relates QVulkanExtension
331
332 Returns \c true if Vulkan extensions \a lhs and \a rhs are have the
333 same name and version.
334*/
335
336/*!
337 \fn bool operator!=(const QVulkanExtension &lhs, const QVulkanExtension &rhs)
338 \since 5.10
339 \relates QVulkanExtension
340
341 Returns \c true if Vulkan extensions \a lhs and \a rhs are have different
342 name or version.
343*/
344
345/*!
346 \fn size_t qHash(const QVulkanExtension &key, size_t seed = 0)
347 \since 5.10
348 \relates QVulkanExtension
349
350 Returns the hash value for the \a key, using \a seed to seed the
351 calculation.
352*/
353
354/*!
355 \class QVulkanInfoVector
356 \inmodule QtGui
357 \brief A specialized QList for QVulkanLayer and QVulkanExtension.
358 */
359
360/*!
361 \fn template<typename T> bool QVulkanInfoVector<T>::contains(const QByteArray &name) const
362
363 \return true if the list contains a layer or extension with the given \a name.
364 */
365
366/*!
367 \fn template<typename T> bool QVulkanInfoVector<T>::contains(const QByteArray &name, int minVersion) const
368
369 \return true if the list contains a layer or extension with the given
370 \a name and a version same as or newer than \a minVersion.
371 */
372
373/*!
374 \fn QVulkanInfoVector<QVulkanLayer> QVulkanInstance::supportedLayers() const
375 \return the list of supported instance-level layers.
376
377 \note This function can be called before create().
378 */
379
380/*!
381 \internal
382 */
383QVulkanInfoVector<QVulkanLayer> QVulkanInstance::supportedLayers()
384{
385 return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedLayers() : QVulkanInfoVector<QVulkanLayer>();
386}
387
388/*!
389 \fn QVulkanInfoVector<QVulkanExtension> QVulkanInstance::supportedExtensions() const
390 \return the list of supported instance-level extensions.
391
392 \note This function can be called before create().
393 */
394
395/*!
396 \internal
397 */
398QVulkanInfoVector<QVulkanExtension> QVulkanInstance::supportedExtensions()
399{
400 return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedExtensions() : QVulkanInfoVector<QVulkanExtension>();
401}
402
403/*!
404 \return the version of instance-level functionality supported by the Vulkan
405 implementation.
406
407 In practice this is either the value returned from
408 vkEnumerateInstanceVersion, if that function is available (with Vulkan 1.1
409 and newer), or 1.0.
410
411 Applications that want to branch in their Vulkan feature and API usage
412 based on what Vulkan version is available at run time, can use this function
413 to determine what version to pass in to setApiVersion() before calling
414 create().
415
416 \note This function can be called before create().
417
418 \sa setApiVersion()
419 */
420QVersionNumber QVulkanInstance::supportedApiVersion() const
421{
422 return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedApiVersion() : QVersionNumber();
423}
424
425/*!
426 Makes QVulkanInstance adopt an existing VkInstance handle instead of
427 creating a new one.
428
429 \note \a existingVkInstance must have at least \c{VK_KHR_surface} and the
430 appropriate WSI-specific \c{VK_KHR_*_surface} extensions enabled. To ensure
431 debug output redirection is functional, \c{VK_EXT_debug_utils} is needed as
432 well.
433
434 \note This function can only be called before create() and has no effect if
435 called afterwards.
436 */
437void QVulkanInstance::setVkInstance(VkInstance existingVkInstance)
438{
439 if (isValid()) {
440 qWarning(msg: "QVulkanInstance already created; setVkInstance() has no effect");
441 return;
442 }
443
444 d_ptr->vkInst = existingVkInstance;
445}
446
447/*!
448 Configures the behavior of create() based on the provided \a flags.
449
450 \note This function can only be called before create() and has no effect if
451 called afterwards.
452 */
453void QVulkanInstance::setFlags(Flags flags)
454{
455 if (isValid()) {
456 qWarning(msg: "QVulkanInstance already created; setFlags() has no effect");
457 return;
458 }
459
460 d_ptr->flags = flags;
461}
462
463/*!
464 Specifies the list of instance \a layers to enable. It is safe to specify
465 unsupported layers as well because these get ignored when not supported at
466 run time.
467
468 \note This function can only be called before create() and has no effect if
469 called afterwards.
470 */
471void QVulkanInstance::setLayers(const QByteArrayList &layers)
472{
473 if (isValid()) {
474 qWarning(msg: "QVulkanInstance already created; setLayers() has no effect");
475 return;
476 }
477
478 d_ptr->layers = layers;
479}
480
481/*!
482 Specifies the list of additional instance \a extensions to enable. It is
483 safe to specify unsupported extensions as well because these get ignored
484 when not supported at run time.
485
486 \note The surface-related extensions required by Qt (for example, \c
487 VK_KHR_win32_surface) will always be added automatically, no need to
488 include them in this list.
489
490 \note \c VK_KHR_portability_enumeration is added automatically unless the
491 NoPortabilityDrivers flag is set. This value was introduced in Qt 6.5.
492
493 \note This function can only be called before create() and has no effect if
494 called afterwards.
495 */
496void QVulkanInstance::setExtensions(const QByteArrayList &extensions)
497{
498 if (isValid()) {
499 qWarning(msg: "QVulkanInstance already created; setExtensions() has no effect");
500 return;
501 }
502
503 d_ptr->extensions = extensions;
504}
505
506/*!
507 Specifies the highest Vulkan API version the application is designed to use.
508
509 By default \a vulkanVersion is 0, which maps to Vulkan 1.0.
510
511 \note This function can only be called before create() and has no effect if
512 called afterwards.
513
514 \note Be aware that Vulkan 1.1 changes the behavior with regards to the
515 Vulkan API version field. In Vulkan 1.0 specifying an unsupported \a
516 vulkanVersion led to failing create() with \c VK_ERROR_INCOMPATIBLE_DRIVER,
517 as was mandated by the specification. Starting with Vulkan 1.1, the
518 specification disallows this, the driver must accept any version without
519 failing the instance creation.
520
521 Application developers are advised to familiarize themselves with the \c
522 apiVersion notes in
523 \l{https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html}{the
524 Vulkan specification}.
525
526 \sa supportedApiVersion()
527 */
528void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion)
529{
530 if (isValid()) {
531 qWarning(msg: "QVulkanInstance already created; setApiVersion() has no effect");
532 return;
533 }
534
535 d_ptr->apiVersion = vulkanVersion;
536}
537
538/*!
539 Initializes the Vulkan library and creates a new or adopts and existing
540 Vulkan instance.
541
542 \return true if successful, false on error or when Vulkan is not supported.
543
544 When successful, the pointer to this QVulkanInstance is retrievable via
545 \l {QVulkanInstance::}{vkInstance()}.
546
547 The Vulkan instance and library is available as long as this
548 QVulkanInstance exists, or until destroy() is called.
549
550 By default the VkInstance is created with the flag
551 \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateFlagBits.html}{VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR}
552 set. This means that Vulkan Portability physical devices get enumerated as
553 well. If this is not desired, set the NoPortabilityDrivers flag.
554 */
555bool QVulkanInstance::create()
556{
557 if (isValid())
558 destroy();
559
560 if (!d_ptr->ensureVulkan())
561 return false;
562
563 d_ptr->platformInst->createOrAdoptInstance();
564
565 if (d_ptr->platformInst->isValid()) {
566 d_ptr->vkInst = d_ptr->platformInst->vkInstance();
567 d_ptr->layers = d_ptr->platformInst->enabledLayers();
568 d_ptr->extensions = d_ptr->platformInst->enabledExtensions();
569 d_ptr->errorCode = VK_SUCCESS;
570 d_ptr->funcs.reset(new QVulkanFunctions(this));
571 d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
572 d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
573 return true;
574 }
575
576 qWarning(msg: "Failed to create platform Vulkan instance");
577 if (d_ptr->platformInst) {
578 d_ptr->errorCode = d_ptr->platformInst->errorCode();
579 d_ptr->platformInst.reset();
580 } else {
581 d_ptr->errorCode = VK_NOT_READY;
582 }
583 return false;
584}
585
586/*!
587 Destroys the underlying platform instance, thus destroying the VkInstance
588 (when owned). The QVulkanInstance object is still reusable by calling
589 create() again.
590 */
591void QVulkanInstance::destroy()
592{
593 d_ptr->reset();
594}
595
596/*!
597 \return true if create() was successful and the instance is valid.
598 */
599bool QVulkanInstance::isValid() const
600{
601 return d_ptr->platformInst && d_ptr->platformInst->isValid();
602}
603
604/*!
605 \return the Vulkan error code after an unsuccessful create(), \c VK_SUCCESS otherwise.
606
607 The value is typically the return value from vkCreateInstance() (when
608 creating a new Vulkan instance instead of adopting an existing one), but
609 may also be \c VK_NOT_READY if the platform plugin does not support Vulkan.
610 */
611VkResult QVulkanInstance::errorCode() const
612{
613 return d_ptr->errorCode;
614}
615
616/*!
617 \return the VkInstance handle this QVulkanInstance wraps, or \nullptr if
618 create() has not yet been successfully called and no existing instance has
619 been provided via setVkInstance().
620 */
621VkInstance QVulkanInstance::vkInstance() const
622{
623 return d_ptr->vkInst;
624}
625
626/*!
627 \return the requested flags.
628 */
629QVulkanInstance::Flags QVulkanInstance::flags() const
630{
631 return d_ptr->flags;
632}
633
634/*!
635 \return the enabled instance layers, if create() was called and was successful. The
636 requested layers otherwise.
637 */
638QByteArrayList QVulkanInstance::layers() const
639{
640 return d_ptr->layers;
641}
642
643/*!
644 \return the enabled instance extensions, if create() was called and was
645 successful. The requested extensions otherwise.
646 */
647QByteArrayList QVulkanInstance::extensions() const
648{
649 return d_ptr->extensions;
650}
651
652/*!
653 \return the requested Vulkan API version against which the application
654 expects to run, or a null version number if setApiVersion() was not called
655 before create().
656 */
657QVersionNumber QVulkanInstance::apiVersion() const
658{
659 return d_ptr->apiVersion;
660}
661
662/*!
663 Resolves the Vulkan function with the given \a name.
664
665 For core Vulkan commands prefer using the function wrappers retrievable from
666 functions() and deviceFunctions() instead.
667 */
668PFN_vkVoidFunction QVulkanInstance::getInstanceProcAddr(const char *name)
669{
670 // The return value is PFN_vkVoidFunction instead of QFunctionPointer or
671 // similar because on some platforms honoring VKAPI_PTR is important.
672 return d_ptr->platformInst->getInstanceProcAddr(name);
673}
674
675/*!
676 \return the platform Vulkan instance corresponding to this QVulkanInstance.
677
678 \internal
679 */
680QPlatformVulkanInstance *QVulkanInstance::handle() const
681{
682 return d_ptr->platformInst.data();
683}
684
685/*!
686 \return the corresponding QVulkanFunctions object that exposes the core
687 Vulkan command set, excluding device level functions, and is guaranteed to
688 be functional cross-platform.
689
690 \note The returned object is owned and managed by the QVulkanInstance. Do
691 not destroy or alter it.
692
693 The functions from the core Vulkan 1.0 API will be available always. When it
694 comes to higher Vulkan versions, such as, 1.1 and 1.2, the QVulkanFunctions
695 object will try to resolve the core API functions for those as well, but if
696 the Vulkan instance implementation at run time has no support for those,
697 calling any such unsupported function will lead to unspecified behavior. In
698 addition, to properly enable support for Vulkan versions higher than 1.0, an
699 appropriate instance API version may need to be set by calling
700 setApiVersion() before create(). To query the Vulkan implementation's
701 instance-level version, call supportedApiVersion().
702
703 \sa deviceFunctions(), supportedApiVersion()
704 */
705QVulkanFunctions *QVulkanInstance::functions() const
706{
707 return d_ptr->funcs.data();
708}
709
710/*!
711 \return the QVulkanDeviceFunctions object that exposes the device level
712 core Vulkan command set and is guaranteed to be functional cross-platform.
713
714 \note The Vulkan functions in the returned object must only be called with
715 \a device or a child object (VkQueue, VkCommandBuffer) of \a device as
716 their first parameter. This is because these functions are resolved via
717 \l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetDeviceProcAddr.html}{vkGetDeviceProcAddr}
718 in order to avoid the potential overhead of internal dispatching.
719
720 \note The returned object is owned and managed by the QVulkanInstance. Do
721 not destroy or alter it.
722
723 \note The object is cached so calling this function with the same \a device
724 again is a cheap operation. However, when the device gets destroyed, it is up
725 to the application to notify the QVulkanInstance by calling
726 resetDeviceFunctions().
727
728 The functions from the core Vulkan 1.0 API will be available always. When
729 it comes to higher Vulkan versions, such as, 1.1 and 1.2, the
730 QVulkanDeviceFunctions object will try to resolve the core API functions
731 for those as well, but if the Vulkan physical device at run time has no
732 support for those, calling any such unsupported function will lead to
733 unspecified behavior. To properly enable support for Vulkan versions higher
734 than 1.0, an appropriate instance API version may need to be set by calling
735 setApiVersion() before create(). In addition, applications are expected to
736 check the physical device's apiVersion in VkPhysicalDeviceProperties.
737
738 \sa functions(), resetDeviceFunctions()
739 */
740QVulkanDeviceFunctions *QVulkanInstance::deviceFunctions(VkDevice device)
741{
742 QVulkanDeviceFunctions *&f = d_ptr->deviceFuncs[device];
743 if (!f)
744 f = new QVulkanDeviceFunctions(this, device);
745 return f;
746}
747
748/*!
749 Invalidates and destroys the QVulkanDeviceFunctions object for the given
750 \a device.
751
752 This function must be called when a VkDevice, for which deviceFunctions()
753 was called, gets destroyed while the application intends to continue
754 running, possibly creating a new logical Vulkan device later on.
755
756 There is no need to call this before destroying the QVulkanInstance since
757 clean up is then performed automatically.
758
759 \sa deviceFunctions()
760 */
761void QVulkanInstance::resetDeviceFunctions(VkDevice device)
762{
763 QVulkanDeviceFunctions *&f = d_ptr->deviceFuncs[device];
764 delete f;
765 f = nullptr;
766}
767
768/*!
769 Creates or retrieves the already existing \c{VkSurfaceKHR} handle for the
770 given \a window.
771
772 \return the Vulkan surface handle or 0 when failed.
773 */
774VkSurfaceKHR QVulkanInstance::surfaceForWindow(QWindow *window)
775{
776 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
777 // VkSurfaceKHR is non-dispatchable and maps to a pointer on x64 and a uint64 on x86.
778 // Therefore a pointer is returned from the platform plugin, not the value itself.
779 void *p = nativeInterface->nativeResourceForWindow(QByteArrayLiteral("vkSurface"), window);
780 return p ? *static_cast<VkSurfaceKHR *>(p) : VK_NULL_HANDLE;
781}
782
783/*!
784 \return true if the queue family with \a queueFamilyIndex within the
785 \a physicalDevice supports presenting to \a window.
786
787 Call this function when examining the queues of a given Vulkan device, in
788 order to decide which queue can be used for performing presentation.
789 */
790bool QVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window)
791{
792 return d_ptr->platformInst->supportsPresent(physicalDevice, queueFamilyIndex, window);
793}
794
795/*!
796 This function should be called by the application's renderer before queuing
797 a present operation for \a window.
798
799 While on some platforms this will be a no-op, some may perform windowing
800 system dependent synchronization. For example, on Wayland this will
801 add send a wl_surface.frame request in order to prevent the driver from
802 blocking for minimized windows.
803
804 \since 5.15
805 */
806void QVulkanInstance::presentAboutToBeQueued(QWindow *window)
807{
808 d_ptr->platformInst->presentAboutToBeQueued(window);
809}
810
811/*!
812 This function should be called by the application's renderer after queuing
813 a present operation for \a window.
814
815 While on some platforms this will be a no-op, some may perform windowing
816 system dependent synchronization. For example, on X11 this will update
817 \c{_NET_WM_SYNC_REQUEST_COUNTER}.
818 */
819void QVulkanInstance::presentQueued(QWindow *window)
820{
821 d_ptr->platformInst->presentQueued(window);
822}
823
824/*!
825 \typedef QVulkanInstance::DebugFilter
826
827 Typedef for debug filtering callback functions, with the following signature:
828
829 \code
830 bool myDebugFilter(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object,
831 size_t location, int32_t messageCode, const char *pLayerPrefix, const char *pMessage)
832 \endcode
833
834 Returning \c true suppresses the printing of the message.
835
836 \note Starting with Qt 6.5 \c{VK_EXT_debug_utils} is used instead of the
837 deprecated \c{VK_EXT_debug_report}. The callback signature is based on
838 VK_EXT_debug_report. Therefore, not all arguments can be expected to be
839 valid anymore. Avoid relying on arguments other than \c pMessage, \c
840 messageCode, and \c object. Applications wishing to access all the callback
841 data as specified in VK_EXT_debug_utils should migrate to DebugUtilsFilter.
842
843 \sa installDebugOutputFilter(), removeDebugOutputFilter()
844 */
845
846/*!
847 \overload
848
849 Installs a \a filter function that is called for every Vulkan debug
850 message. When the callback returns \c true, the message is stopped (filtered
851 out) and will not appear on the debug output.
852
853 \note Filtering is only effective when NoDebugOutputRedirect is not
854 \l{setFlags()}{set}. Installing filters has no effect otherwise.
855
856 \note This function can be called before create().
857
858 \sa removeDebugOutputFilter()
859 */
860void QVulkanInstance::installDebugOutputFilter(DebugFilter filter)
861{
862 if (!d_ptr->debugFilters.contains(t: filter)) {
863 d_ptr->debugFilters.append(t: filter);
864 if (d_ptr->platformInst)
865 d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
866 }
867}
868
869/*!
870 \overload
871
872 Removes a \a filter function previously installed by
873 installDebugOutputFilter().
874
875 \note This function can be called before create().
876
877 \sa installDebugOutputFilter()
878 */
879void QVulkanInstance::removeDebugOutputFilter(DebugFilter filter)
880{
881 d_ptr->debugFilters.removeOne(t: filter);
882 if (d_ptr->platformInst)
883 d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
884}
885
886/*!
887 \typedef QVulkanInstance::DebugUtilsFilter
888
889 Typedef for debug filtering callback functions, with the following signature:
890
891 \code
892 std::function<bool(DebugMessageSeverityFlags severity, DebugMessageTypeFlags type, const void *message)>;
893 \endcode
894
895 The \c message argument is a pointer to the
896 VkDebugUtilsMessengerCallbackDataEXT structure. Refer to the documentation
897 of \c{VK_EXT_debug_utils} for details. The Qt headers do not use the real
898 type in order to avoid introducing a dependency on post-1.0 Vulkan headers.
899
900 Returning \c true suppresses the printing of the message.
901
902 \sa installDebugOutputFilter(), removeDebugOutputFilter()
903 \since 6.5
904 */
905
906/*!
907 \enum QVulkanInstance::DebugMessageSeverityFlag
908 \since 6.5
909
910 \value VerboseSeverity
911 \value InfoSeverity
912 \value WarningSeverity
913 \value ErrorSeverity
914 */
915
916/*!
917 \enum QVulkanInstance::DebugMessageTypeFlag
918 \since 6.5
919
920 \value GeneralMessage
921 \value ValidationMessage
922 \value PerformanceMessage
923 */
924
925/*!
926 Installs a \a filter function that is called for every Vulkan debug
927 message. When the callback returns \c true, the message is stopped (filtered
928 out) and will not appear on the debug output.
929
930 \note Filtering is only effective when NoDebugOutputRedirect is not
931 \l{setFlags()}{set}. Installing filters has no effect otherwise.
932
933 \note This function can be called before create().
934
935 \sa clearDebugOutputFilters()
936 \since 6.5
937 */
938void QVulkanInstance::installDebugOutputFilter(DebugUtilsFilter filter)
939{
940 d_ptr->debugUtilsFilters.append(t: filter);
941 if (d_ptr->platformInst)
942 d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
943}
944
945/*!
946 Removes all filter functions installed previously by
947 installDebugOutputFilter().
948
949 \note This function can be called before create().
950
951 \sa installDebugOutputFilter()
952 \since 6.5
953 */
954void QVulkanInstance::clearDebugOutputFilters()
955{
956 d_ptr->debugFilters.clear();
957 d_ptr->debugUtilsFilters.clear();
958 if (d_ptr->platformInst) {
959 d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
960 d_ptr->platformInst->setDebugUtilsFilters(d_ptr->debugUtilsFilters);
961 }
962}
963
964#ifndef QT_NO_DEBUG_STREAM
965QDebug operator<<(QDebug dbg, const QVulkanLayer &layer)
966{
967 QDebugStateSaver saver(dbg);
968 dbg.nospace() << "QVulkanLayer(" << layer.name << " " << layer.version
969 << " " << layer.specVersion << " " << layer.description << ")";
970 return dbg;
971}
972
973QDebug operator<<(QDebug dbg, const QVulkanExtension &extension)
974{
975 QDebugStateSaver saver(dbg);
976 dbg.nospace() << "QVulkanExtension(" << extension.name << " " << extension.version << ")";
977 return dbg;
978}
979#endif
980
981QT_END_NAMESPACE
982

source code of qtbase/src/gui/vulkan/qvulkaninstance.cpp