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