vulkan: Add instance-level version getter

...as described in the Vulkan >= 1.1 spec. One can now call
supportedApiVersion() (before create(), similarly to the other
supported* functions) to determine the available Vulkan
(instance-level) version.

Fixes: QTBUG-90333
Change-Id: Ibe8482402b7f07e4abc48c88252ff0365e4e2faa
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2021-01-14 17:42:47 +01:00
parent 9573441236
commit 7d378bd780
6 changed files with 73 additions and 5 deletions

View File

@ -135,6 +135,25 @@ void QBasicPlatformVulkanInstance::init(QLibrary *lib)
return; return;
} }
// Do not rely on non-1.0 header typedefs here.
typedef VkResult (VKAPI_PTR *T_enumerateInstanceVersion)(uint32_t* pApiVersion);
// Determine instance-level version as described in the Vulkan 1.2 spec.
T_enumerateInstanceVersion enumerateInstanceVersion = reinterpret_cast<T_enumerateInstanceVersion>(
m_vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceVersion"));
if (enumerateInstanceVersion) {
uint32_t ver = 0;
if (enumerateInstanceVersion(&ver) == VK_SUCCESS) {
m_supportedApiVersion = QVersionNumber(VK_VERSION_MAJOR(ver),
VK_VERSION_MINOR(ver),
VK_VERSION_PATCH(ver));
} else {
m_supportedApiVersion = QVersionNumber(1, 0, 0);
}
} else {
// Vulkan 1.0
m_supportedApiVersion = QVersionNumber(1, 0, 0);
}
uint32_t layerCount = 0; uint32_t layerCount = 0;
m_vkEnumerateInstanceLayerProperties(&layerCount, nullptr); m_vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
if (layerCount) { if (layerCount) {
@ -180,6 +199,11 @@ QVulkanInfoVector<QVulkanExtension> QBasicPlatformVulkanInstance::supportedExten
return m_supportedExtensions; return m_supportedExtensions;
} }
QVersionNumber QBasicPlatformVulkanInstance::supportedApiVersion() const
{
return m_supportedApiVersion;
}
void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const QByteArrayList &extraExts) void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const QByteArrayList &extraExts)
{ {
if (!m_vkGetInstanceProcAddr) { if (!m_vkGetInstanceProcAddr) {

View File

@ -68,6 +68,7 @@ public:
QVulkanInfoVector<QVulkanLayer> supportedLayers() const override; QVulkanInfoVector<QVulkanLayer> supportedLayers() const override;
QVulkanInfoVector<QVulkanExtension> supportedExtensions() const override; QVulkanInfoVector<QVulkanExtension> supportedExtensions() const override;
QVersionNumber supportedApiVersion() const override;
bool isValid() const override; bool isValid() const override;
VkResult errorCode() const override; VkResult errorCode() const override;
VkInstance vkInstance() const override; VkInstance vkInstance() const override;
@ -99,6 +100,7 @@ private:
VkResult m_errorCode; VkResult m_errorCode;
QVulkanInfoVector<QVulkanLayer> m_supportedLayers; QVulkanInfoVector<QVulkanLayer> m_supportedLayers;
QVulkanInfoVector<QVulkanExtension> m_supportedExtensions; QVulkanInfoVector<QVulkanExtension> m_supportedExtensions;
QVersionNumber m_supportedApiVersion;
QByteArrayList m_enabledLayers; QByteArrayList m_enabledLayers;
QByteArrayList m_enabledExtensions; QByteArrayList m_enabledExtensions;

View File

@ -69,6 +69,7 @@ public:
virtual QVulkanInfoVector<QVulkanLayer> supportedLayers() const = 0; virtual QVulkanInfoVector<QVulkanLayer> supportedLayers() const = 0;
virtual QVulkanInfoVector<QVulkanExtension> supportedExtensions() const = 0; virtual QVulkanInfoVector<QVulkanExtension> supportedExtensions() const = 0;
virtual QVersionNumber supportedApiVersion() const = 0;
virtual void createOrAdoptInstance() = 0; virtual void createOrAdoptInstance() = 0;
virtual bool isValid() const = 0; virtual bool isValid() const = 0;
virtual VkResult errorCode() const = 0; virtual VkResult errorCode() const = 0;

View File

@ -447,6 +447,28 @@ QVulkanInfoVector<QVulkanExtension> QVulkanInstance::supportedExtensions()
return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedExtensions() : QVulkanInfoVector<QVulkanExtension>(); return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedExtensions() : QVulkanInfoVector<QVulkanExtension>();
} }
/*!
\return the version of instance-level functionality supported by the Vulkan
implementation.
In practice this is either the value returned from
vkEnumerateInstanceVersion, if that function is available (with Vulkan 1.1
and newer), or 1.0.
Applications that want to branch in their Vulkan feature and API usage
based on what Vulkan version is available at run time, can use this function
to determine what version to pass in to setApiVersion() before calling
create().
\note This function can be called before create().
\sa setApiVersion()
*/
QVersionNumber QVulkanInstance::supportedApiVersion()
{
return d_ptr->ensureVulkan() ? d_ptr->platformInst->supportedApiVersion() : QVersionNumber();
}
/*! /*!
Makes QVulkanInstance adopt an existing VkInstance handle instead of Makes QVulkanInstance adopt an existing VkInstance handle instead of
creating a new one. creating a new one.
@ -524,10 +546,9 @@ void QVulkanInstance::setExtensions(const QByteArrayList &extensions)
} }
/*! /*!
Specifies the Vulkan API against which the application expects to run. Specifies the highest Vulkan API version the application is designed to use.
By default no \a vulkanVersion is specified, and so no version check is performed By default \a vulkanVersion is 0, which maps to Vulkan 1.0.
during Vulkan instance creation.
\note This function can only be called before create() and has no effect if \note This function can only be called before create() and has no effect if
called afterwards. called afterwards.
@ -538,6 +559,13 @@ void QVulkanInstance::setExtensions(const QByteArrayList &extensions)
as was mandated by the specification. Starting with Vulkan 1.1, the as was mandated by the specification. Starting with Vulkan 1.1, the
specification disallows this, the driver must accept any version without specification disallows this, the driver must accept any version without
failing the instance creation. failing the instance creation.
Application developers are advised to familiarize themselves with the \c
apiVersion notes in
\l{https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html}{the
Vulkan specification}.
\sa supportedApiVersion()
*/ */
void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion) void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion)
{ {

View File

@ -176,6 +176,7 @@ public:
QVulkanInfoVector<QVulkanLayer> supportedLayers(); QVulkanInfoVector<QVulkanLayer> supportedLayers();
QVulkanInfoVector<QVulkanExtension> supportedExtensions(); QVulkanInfoVector<QVulkanExtension> supportedExtensions();
QVersionNumber supportedApiVersion();
void setVkInstance(VkInstance existingVkInstance); void setVkInstance(VkInstance existingVkInstance);

View File

@ -86,8 +86,8 @@ void tst_QVulkan::vulkanInstance()
void tst_QVulkan::vulkanCheckSupported() void tst_QVulkan::vulkanCheckSupported()
{ {
// Test the early calls to supportedLayers/extensions that need the library // Test the early calls to supportedLayers/extensions/apiVersion that need
// and some basics, but do not initialize the instance. // the library and some basics, but do not initialize the instance.
QVulkanInstance inst; QVulkanInstance inst;
QVERIFY(!inst.isValid()); QVERIFY(!inst.isValid());
@ -103,6 +103,9 @@ void tst_QVulkan::vulkanCheckSupported()
QVERIFY(!ve.isEmpty()); QVERIFY(!ve.isEmpty());
QVERIFY(ve == inst.supportedExtensions()); QVERIFY(ve == inst.supportedExtensions());
} }
qDebug() << inst.supportedApiVersion();
QVERIFY(inst.supportedApiVersion().majorVersion() >= 1);
} }
void tst_QVulkan::vulkanPlainWindow() void tst_QVulkan::vulkanPlainWindow()
@ -162,6 +165,15 @@ void tst_QVulkan::vulkanVersionRequest()
// succeed for any bogus api version). // succeed for any bogus api version).
if (!result) if (!result)
QCOMPARE(inst.errorCode(), VK_ERROR_INCOMPATIBLE_DRIVER); QCOMPARE(inst.errorCode(), VK_ERROR_INCOMPATIBLE_DRIVER);
inst.destroy();
// Verify that specifying the version returned from supportedApiVersion
// (either 1.0.0 or what vkEnumerateInstanceVersion returns in Vulkan 1.1+)
// leads to successful instance creation.
inst.setApiVersion(inst.supportedApiVersion());
result = inst.create();
QVERIFY(result);
} }
static void waitForUnexposed(QWindow *w) static void waitForUnexposed(QWindow *w)