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

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