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 
47 QT_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 
248 class QVulkanInstancePrivate
249 {
250 public:
QVulkanInstancePrivate(QVulkanInstance * q)251     QVulkanInstancePrivate(QVulkanInstance *q)
252         : q_ptr(q),
253           vkInst(VK_NULL_HANDLE),
254           errorCode(VK_SUCCESS)
255     { }
~QVulkanInstancePrivate()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     QVector<QVulkanInstance::DebugFilter> debugFilters;
272 };
273 
ensureVulkan()274 bool 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 
reset()286 void 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  */
QVulkanInstance()301 QVulkanInstance::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  */
~QVulkanInstance()311 QVulkanInstance::~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 uint qHash(const QVulkanLayer &key, uint 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 uint qHash(const QVulkanExtension &key, uint 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 QVector 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 vector 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 vector 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  */
supportedLayers()435 QVulkanInfoVector<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  */
supportedExtensions()445 QVulkanInfoVector<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  */
setVkInstance(VkInstance existingVkInstance)462 void 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  */
setFlags(Flags flags)478 void 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  */
setLayers(const QByteArrayList & layers)496 void 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  */
setExtensions(const QByteArrayList & extensions)516 void 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  */
setApiVersion(const QVersionNumber & vulkanVersion)535 void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion)
536 {
537     if (isValid()) {
538         qWarning("QVulkanInstance already created; setApiVersion() has no effect");
539         return;
540     }
541 
542     d_ptr->apiVersion = vulkanVersion;
543 }
544 
545 /*!
546     Initializes the Vulkan library and creates a new or adopts and existing
547     Vulkan instance.
548 
549     \return true if successful, false on error or when Vulkan is not supported.
550 
551     When successful, the pointer to this QVulkanInstance is retrievable via the
552     static function current().
553 
554     The Vulkan instance and library is available as long as this
555     QVulkanInstance exists, or until destroy() is called.
556  */
create()557 bool QVulkanInstance::create()
558 {
559     if (isValid())
560         destroy();
561 
562     if (!d_ptr->ensureVulkan())
563         return false;
564 
565     d_ptr->platformInst->createOrAdoptInstance();
566 
567     if (d_ptr->platformInst->isValid()) {
568         d_ptr->vkInst = d_ptr->platformInst->vkInstance();
569         d_ptr->layers = d_ptr->platformInst->enabledLayers();
570         d_ptr->extensions = d_ptr->platformInst->enabledExtensions();
571         d_ptr->errorCode = VK_SUCCESS;
572         d_ptr->funcs.reset(new QVulkanFunctions(this));
573         d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
574         return true;
575     }
576 
577     qWarning("Failed to create platform Vulkan instance");
578     if (d_ptr->platformInst) {
579         d_ptr->errorCode = d_ptr->platformInst->errorCode();
580         d_ptr->platformInst.reset();
581     } else {
582         d_ptr->errorCode = VK_NOT_READY;
583     }
584     return false;
585 }
586 
587 /*!
588     Destroys the underlying platform instance, thus destroying the VkInstance
589     (when owned). The QVulkanInstance object is still reusable by calling
590     create() again.
591  */
destroy()592 void QVulkanInstance::destroy()
593 {
594     d_ptr->reset();
595 }
596 
597 /*!
598     \return true if create() was successful and the instance is valid.
599  */
isValid() const600 bool QVulkanInstance::isValid() const
601 {
602     return d_ptr->platformInst && d_ptr->platformInst->isValid();
603 }
604 
605 /*!
606     \return the Vulkan error code after an unsuccessful create(), \c VK_SUCCESS otherwise.
607 
608     The value is typically the return value from vkCreateInstance() (when
609     creating a new Vulkan instance instead of adopting an existing one), but
610     may also be \c VK_NOT_READY if the platform plugin does not support Vulkan.
611  */
errorCode() const612 VkResult QVulkanInstance::errorCode() const
613 {
614     return d_ptr->errorCode;
615 }
616 
617 /*!
618     \return the VkInstance handle this QVulkanInstance wraps, or \nullptr if
619     create() has not yet been successfully called and no existing instance has
620     been provided via setVkInstance().
621  */
vkInstance() const622 VkInstance QVulkanInstance::vkInstance() const
623 {
624     return d_ptr->vkInst;
625 }
626 
627 /*!
628     \return the requested flags.
629  */
flags() const630 QVulkanInstance::Flags QVulkanInstance::flags() const
631 {
632     return d_ptr->flags;
633 }
634 
635 /*!
636     \return the enabled instance layers, if create() was called and was successful. The
637     requested layers otherwise.
638  */
layers() const639 QByteArrayList QVulkanInstance::layers() const
640 {
641     return d_ptr->layers;
642 }
643 
644 /*!
645     \return the enabled instance extensions, if create() was called and was
646     successful. The requested extensions otherwise.
647  */
extensions() const648 QByteArrayList QVulkanInstance::extensions() const
649 {
650     return d_ptr->extensions;
651 }
652 
653 /*!
654     \return the requested Vulkan API version against which the application
655     expects to run, or a null version number if setApiVersion() was not called
656     before create().
657  */
apiVersion() const658 QVersionNumber QVulkanInstance::apiVersion() const
659 {
660     return d_ptr->apiVersion;
661 }
662 
663 /*!
664     Resolves the Vulkan function with the given \a name.
665 
666     For core Vulkan commands prefer using the function wrappers retrievable from
667     functions() and deviceFunctions() instead.
668  */
getInstanceProcAddr(const char * name)669 PFN_vkVoidFunction QVulkanInstance::getInstanceProcAddr(const char *name)
670 {
671     // The return value is PFN_vkVoidFunction instead of QFunctionPointer or
672     // similar because on some platforms honoring VKAPI_PTR is important.
673     return d_ptr->platformInst->getInstanceProcAddr(name);
674 }
675 
676 /*!
677     \return the platform Vulkan instance corresponding to this QVulkanInstance.
678 
679     \internal
680  */
handle() const681 QPlatformVulkanInstance *QVulkanInstance::handle() const
682 {
683     return d_ptr->platformInst.data();
684 }
685 
686 /*!
687     \return the corresponding QVulkanFunctions object that exposes the core
688     Vulkan command set, excluding device level functions, and is guaranteed to
689     be functional cross-platform.
690 
691     \note The returned object is owned and managed by the QVulkanInstance. Do
692     not destroy or alter it.
693 
694     \sa deviceFunctions()
695  */
functions() const696 QVulkanFunctions *QVulkanInstance::functions() const
697 {
698     return d_ptr->funcs.data();
699 }
700 
701 /*!
702     \return the QVulkanDeviceFunctions object that exposes the device level
703     core Vulkan command set and is guaranteed to be functional cross-platform.
704 
705     \note The Vulkan functions in the returned object must only be called with
706     \a device or a child object (VkQueue, VkCommandBuffer) of \a device as
707     their first parameter. This is because these functions are resolved via
708     \l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetDeviceProcAddr.html}{vkGetDeviceProcAddr}
709     in order to avoid the potential overhead of internal dispatching.
710 
711     \note The returned object is owned and managed by the QVulkanInstance. Do
712     not destroy or alter it.
713 
714     \note The object is cached so calling this function with the same \a device
715     again is a cheap operation. However, when the device gets destroyed, it is up
716     to the application to notify the QVulkanInstance by calling
717     resetDeviceFunctions().
718 
719     \sa functions(), resetDeviceFunctions()
720  */
deviceFunctions(VkDevice device)721 QVulkanDeviceFunctions *QVulkanInstance::deviceFunctions(VkDevice device)
722 {
723     QVulkanDeviceFunctions *&f = d_ptr->deviceFuncs[device];
724     if (!f)
725         f = new QVulkanDeviceFunctions(this, device);
726     return f;
727 }
728 
729 /*!
730     Invalidates and destroys the QVulkanDeviceFunctions object for the given
731     \a device.
732 
733     This function must be called when a VkDevice, for which deviceFunctions()
734     was called, gets destroyed while the application intends to continue
735     running, possibly creating a new logical Vulkan device later on.
736 
737     There is no need to call this before destroying the QVulkanInstance since
738     clean up is then performed automatically.
739 
740     \sa deviceFunctions()
741  */
resetDeviceFunctions(VkDevice device)742 void QVulkanInstance::resetDeviceFunctions(VkDevice device)
743 {
744     QVulkanDeviceFunctions *&f = d_ptr->deviceFuncs[device];
745     delete f;
746     f = nullptr;
747 }
748 
749 /*!
750     Creates or retrieves the already existing \c{VkSurfaceKHR} handle for the
751     given \a window.
752 
753     \return the Vulkan surface handle or 0 when failed.
754  */
surfaceForWindow(QWindow * window)755 VkSurfaceKHR QVulkanInstance::surfaceForWindow(QWindow *window)
756 {
757     QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
758     // VkSurfaceKHR is non-dispatchable and maps to a pointer on x64 and a uint64 on x86.
759     // Therefore a pointer is returned from the platform plugin, not the value itself.
760     void *p = nativeInterface->nativeResourceForWindow(QByteArrayLiteral("vkSurface"), window);
761     return p ? *static_cast<VkSurfaceKHR *>(p) : VK_NULL_HANDLE;
762 }
763 
764 /*!
765     \return true if the queue family with \a queueFamilyIndex within the
766     \a physicalDevice supports presenting to \a window.
767 
768     Call this function when examining the queues of a given Vulkan device, in
769     order to decide which queue can be used for performing presentation.
770  */
supportsPresent(VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex,QWindow * window)771 bool QVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window)
772 {
773     return d_ptr->platformInst->supportsPresent(physicalDevice, queueFamilyIndex, window);
774 }
775 
776 /*!
777     This function should be called by the application's renderer before queuing
778     a present operation for \a window.
779 
780     While on some platforms this will be a no-op, some may perform windowing
781     system dependent synchronization. For example, on Wayland this will
782     add send a wl_surface.frame request in order to prevent the driver from
783     blocking for minimized windows.
784 
785     \since 5.15
786  */
presentAboutToBeQueued(QWindow * window)787 void QVulkanInstance::presentAboutToBeQueued(QWindow *window)
788 {
789     d_ptr->platformInst->presentAboutToBeQueued(window);
790 }
791 
792 /*!
793     This function should be called by the application's renderer after queuing
794     a present operation for \a window.
795 
796     While on some platforms this will be a no-op, some may perform windowing
797     system dependent synchronization. For example, on X11 this will update
798     \c{_NET_WM_SYNC_REQUEST_COUNTER}.
799  */
presentQueued(QWindow * window)800 void QVulkanInstance::presentQueued(QWindow *window)
801 {
802     d_ptr->platformInst->presentQueued(window);
803 }
804 
805 /*!
806     \typedef QVulkanInstance::DebugFilter
807 
808     Typedef for debug filtering callback functions.
809 
810     \sa installDebugOutputFilter(), removeDebugOutputFilter()
811  */
812 
813 /*!
814     Installs a \a filter function that is called for every Vulkan debug
815     message. When the callback returns \c true, the message is stopped (filtered
816     out) and will not appear on the debug output.
817 
818     \note Filtering is only effective when NoDebugOutputRedirect is not
819     \l{setFlags()}{set}. Installing filters has no effect otherwise.
820 
821     \note This function can be called before create().
822 
823     \sa removeDebugOutputFilter()
824  */
installDebugOutputFilter(DebugFilter filter)825 void QVulkanInstance::installDebugOutputFilter(DebugFilter filter)
826 {
827     if (!d_ptr->debugFilters.contains(filter)) {
828         d_ptr->debugFilters.append(filter);
829         if (d_ptr->platformInst)
830             d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
831     }
832 }
833 
834 /*!
835     Removes a \a filter function previously installed by
836     installDebugOutputFilter().
837 
838     \note This function can be called before create().
839 
840     \sa installDebugOutputFilter()
841  */
removeDebugOutputFilter(DebugFilter filter)842 void QVulkanInstance::removeDebugOutputFilter(DebugFilter filter)
843 {
844     d_ptr->debugFilters.removeOne(filter);
845     if (d_ptr->platformInst)
846         d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
847 }
848 
849 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug dbg,const QVulkanLayer & layer)850 QDebug operator<<(QDebug dbg, const QVulkanLayer &layer)
851 {
852     QDebugStateSaver saver(dbg);
853     dbg.nospace() << "QVulkanLayer(" << layer.name << " " << layer.version
854                   << " " << layer.specVersion << " " << layer.description << ")";
855     return dbg;
856 }
857 
operator <<(QDebug dbg,const QVulkanExtension & extension)858 QDebug operator<<(QDebug dbg, const QVulkanExtension &extension)
859 {
860     QDebugStateSaver saver(dbg);
861     dbg.nospace() << "QVulkanExtension(" << extension.name << " " << extension.version << ")";
862     return dbg;
863 }
864 #endif
865 
866 QT_END_NAMESPACE
867