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