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;
}
// 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;
m_vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
if (layerCount) {
@ -180,6 +199,11 @@ QVulkanInfoVector<QVulkanExtension> QBasicPlatformVulkanInstance::supportedExten
return m_supportedExtensions;
}
QVersionNumber QBasicPlatformVulkanInstance::supportedApiVersion() const
{
return m_supportedApiVersion;
}
void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const QByteArrayList &extraExts)
{
if (!m_vkGetInstanceProcAddr) {

View File

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

View File

@ -69,6 +69,7 @@ public:
virtual QVulkanInfoVector<QVulkanLayer> supportedLayers() const = 0;
virtual QVulkanInfoVector<QVulkanExtension> supportedExtensions() const = 0;
virtual QVersionNumber supportedApiVersion() const = 0;
virtual void createOrAdoptInstance() = 0;
virtual bool isValid() 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 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
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
during Vulkan instance creation.
By default \a vulkanVersion is 0, which maps to Vulkan 1.0.
\note This function can only be called before create() and has no effect if
called afterwards.
@ -538,6 +559,13 @@ void QVulkanInstance::setExtensions(const QByteArrayList &extensions)
as was mandated by the specification. Starting with Vulkan 1.1, the
specification disallows this, the driver must accept any version without
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)
{

View File

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

View File

@ -86,8 +86,8 @@ void tst_QVulkan::vulkanInstance()
void tst_QVulkan::vulkanCheckSupported()
{
// Test the early calls to supportedLayers/extensions that need the library
// and some basics, but do not initialize the instance.
// Test the early calls to supportedLayers/extensions/apiVersion that need
// the library and some basics, but do not initialize the instance.
QVulkanInstance inst;
QVERIFY(!inst.isValid());
@ -103,6 +103,9 @@ void tst_QVulkan::vulkanCheckSupported()
QVERIFY(!ve.isEmpty());
QVERIFY(ve == inst.supportedExtensions());
}
qDebug() << inst.supportedApiVersion();
QVERIFY(inst.supportedApiVersion().majorVersion() >= 1);
}
void tst_QVulkan::vulkanPlainWindow()
@ -162,6 +165,15 @@ void tst_QVulkan::vulkanVersionRequest()
// succeed for any bogus api version).
if (!result)
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)