Update QVulkan(Device)Functions to Vulkan 1.2
This also needs improvements to qvkgen. What we get with this patch are the Vulkan 1.1 and 1.2 core API's additional 11 instance-level and 30 device-level commands present in QVulkanFunctions and QVulkanDeviceFunctions. All of these are attempted to be resolved upon construction. When the implementation does not return a valid function pointer for some of them (e.g. because it is a Vulkan 1.0 instance or physical device), calling the corresponding wrapper functions will lead to unspecified behavior. This is in line with how QOpenGLExtraFunctions works. The simple autotest added to exercise some Vulkan 1.1 APIs demonstrates this in action. The member functions in the generated qvulkan(device)functions header and source files are ifdefed by VK_VERSION_1_{0,1,2}. This is essential because otherwise a Qt build made on a system with Vulkan 1.2 headers would cause compilation breaks in application build environments with Vulkan 1.0/1.1 headers when including qvulkanfunctions.h (due to missing the 1.1/1.2 types and constants, some of which are used in the function prototypes). In practice this should be alright - the only caveat to keep in mind is that the Qt builds meant to be distributed to a wide variety of systems need to be made with a sufficiently new version of the Vulkan headers installed, just to ensure that the 1.1 and 1.2 wrapper functions are compiled into the Qt libraries. Task-number: QTBUG-90219 Change-Id: I48360a8a2e915d2709fe82993f65e99b2ccd5d53 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
parent
12d8bb0709
commit
c6d6029909
@ -1,20 +0,0 @@
|
||||
Copyright (c) 2015-2017 The Khronos Group Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and/or associated documentation files (the
|
||||
"Materials"), to deal in the Materials without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
permit persons to whom the Materials are furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Materials.
|
||||
|
||||
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
19
src/gui/vulkan/LICENSE.txt
Normal file
19
src/gui/vulkan/LICENSE.txt
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2015-2020 The Khronos Group Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
@ -8,10 +8,10 @@
|
||||
"Path": "vk.xml",
|
||||
|
||||
"Homepage": "https://www.khronos.org/",
|
||||
"Version": "1.0.39",
|
||||
"Version": "1.2.166",
|
||||
"License": "MIT License",
|
||||
"LicenseId": "MIT",
|
||||
"LicenseFile": "KHRONOS_LICENSE.txt",
|
||||
"Copyright": "Copyright (c) 2015-2017 The Khronos Group Inc."
|
||||
"LicenseId": "Apache-2.0 OR MIT",
|
||||
"LicenseFile": "LICENSE.txt",
|
||||
"Copyright": "Copyright (c) 2015-2020 The Khronos Group Inc."
|
||||
}
|
||||
]
|
||||
|
@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
|
||||
\wrapper
|
||||
|
||||
\brief The QVulkanFunctions class provides cross-platform access to the
|
||||
instance level core Vulkan 1.0 API.
|
||||
instance level core Vulkan 1.2 API.
|
||||
|
||||
Qt and Qt applications do not link to any Vulkan libraries by default.
|
||||
Instead, all functions are resolved dynamically at run time. Each
|
||||
@ -81,6 +81,18 @@ QT_BEGIN_NAMESPACE
|
||||
\l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetInstanceProcAddr.html}{the
|
||||
man page for vkGetInstanceProcAddr} for more information.
|
||||
|
||||
\note The member function prototypes for Vulkan 1.1 and 1.2 commands are
|
||||
ifdefed with the appropriate \c{VK_VERSION_1_x} that is defined by the
|
||||
Vulkan headers. Therefore these functions will only be callable by an
|
||||
application when the system's (on which the application is built) Vulkan
|
||||
header is new enough and it contains 1.1 and 1.2 Vulkan API definitions.
|
||||
When building Qt from source, this has an additional consequence: the
|
||||
Vulkan headers on the build environment must also be 1.1 and 1.2 capable in
|
||||
order to get a Qt build that supports resolving the 1.1 and 1.2 API
|
||||
commands. If either of these conditions is not met, applications will only
|
||||
be able to call the Vulkan 1.0 commands through QVulkanFunctions and
|
||||
QVulkanDeviceFunctions.
|
||||
|
||||
\sa QVulkanInstance, QVulkanDeviceFunctions, QWindow::setVulkanInstance(), QWindow::setSurfaceType()
|
||||
*/
|
||||
|
||||
@ -92,7 +104,7 @@ QT_BEGIN_NAMESPACE
|
||||
\wrapper
|
||||
|
||||
\brief The QVulkanDeviceFunctions class provides cross-platform access to
|
||||
the device level core Vulkan 1.0 API.
|
||||
the device level core Vulkan 1.2 API.
|
||||
|
||||
Qt and Qt applications do not link to any Vulkan libraries by default.
|
||||
Instead, all functions are resolved dynamically at run time. Each
|
||||
|
@ -154,9 +154,9 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
\note QVulkanFunctions and QVulkanDeviceFunctions are generated from the
|
||||
Vulkan API XML specifications when building the Qt libraries. Therefore no
|
||||
documentation is provided for them. They contain the Vulkan 1.0 functions
|
||||
documentation is provided for them. They contain the Vulkan 1.2 functions
|
||||
with the same signatures as described in the
|
||||
\l{https://www.khronos.org/registry/vulkan/specs/1.0/html/}{Vulkan API
|
||||
\l{https://www.khronos.org/registry/vulkan/specs/1.2/html/}{Vulkan API
|
||||
documentation}.
|
||||
|
||||
\section1 Getting a Native Vulkan Surface for a Window
|
||||
@ -726,7 +726,17 @@ QPlatformVulkanInstance *QVulkanInstance::handle() const
|
||||
\note The returned object is owned and managed by the QVulkanInstance. Do
|
||||
not destroy or alter it.
|
||||
|
||||
\sa deviceFunctions()
|
||||
The functions from the core Vulkan 1.0 API will be available always. When it
|
||||
comes to higher Vulkan versions, such as, 1.1 and 1.2, the QVulkanFunctions
|
||||
object will try to resolve the core API functions for those as well, but if
|
||||
the Vulkan instance implementation at run time has no support for those,
|
||||
calling any such unsupported function will lead to unspecified behavior. In
|
||||
addition, to properly enable support for Vulkan versions higher than 1.0, an
|
||||
appropriate instance API version may need to be set by calling
|
||||
setApiVersion() before create(). To query the Vulkan implementation's
|
||||
instance-level version, call supportedApiVersion().
|
||||
|
||||
\sa deviceFunctions(), supportedApiVersion()
|
||||
*/
|
||||
QVulkanFunctions *QVulkanInstance::functions() const
|
||||
{
|
||||
@ -751,6 +761,16 @@ QVulkanFunctions *QVulkanInstance::functions() const
|
||||
to the application to notify the QVulkanInstance by calling
|
||||
resetDeviceFunctions().
|
||||
|
||||
The functions from the core Vulkan 1.0 API will be available always. When
|
||||
it comes to higher Vulkan versions, such as, 1.1 and 1.2, the
|
||||
QVulkanDeviceFunctions object will try to resolve the core API functions
|
||||
for those as well, but if the Vulkan physical device at run time has no
|
||||
support for those, calling any such unsupported function will lead to
|
||||
unspecified behavior. To properly enable support for Vulkan versions higher
|
||||
than 1.0, an appropriate instance API version may need to be set by calling
|
||||
setApiVersion() before create(). In addition, applications are expected to
|
||||
check the physical device's apiVersion in VkPhysicalDeviceProperties.
|
||||
|
||||
\sa functions(), resetDeviceFunctions()
|
||||
*/
|
||||
QVulkanDeviceFunctions *QVulkanInstance::deviceFunctions(VkDevice device)
|
||||
|
13500
src/gui/vulkan/vk.xml
13500
src/gui/vulkan/vk.xml
File diff suppressed because it is too large
Load Diff
@ -32,6 +32,13 @@
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qxmlstream.h>
|
||||
|
||||
// generate wrappers for core functions from the following versions
|
||||
static const QStringList VERSIONS = {
|
||||
QStringLiteral("VK_VERSION_1_0"), // must be the first and always present
|
||||
QStringLiteral("VK_VERSION_1_1"),
|
||||
QStringLiteral("VK_VERSION_1_2")
|
||||
};
|
||||
|
||||
class VkSpecParser
|
||||
{
|
||||
public:
|
||||
@ -50,11 +57,14 @@ public:
|
||||
};
|
||||
|
||||
QList<Command> commands() const { return m_commands; }
|
||||
QMap<QString, QStringList> versionCommandMapping() const { return m_versionCommandMapping; }
|
||||
|
||||
void setFileName(const QString &fn) { m_fn = fn; }
|
||||
|
||||
private:
|
||||
void skip();
|
||||
void parseFeature();
|
||||
void parseFeatureRequire(const QString &versionDefine);
|
||||
void parseCommands();
|
||||
Command parseCommand();
|
||||
TypedName parseParamOrProto(const QString &tag);
|
||||
@ -63,6 +73,7 @@ private:
|
||||
QFile m_file;
|
||||
QXmlStreamReader m_reader;
|
||||
QList<Command> m_commands;
|
||||
QMap<QString, QStringList> m_versionCommandMapping; // "1.0" -> ["vkGetPhysicalDeviceProperties", ...]
|
||||
QString m_fn;
|
||||
};
|
||||
|
||||
@ -73,13 +84,18 @@ bool VkSpecParser::parse()
|
||||
qWarning("Failed to open %s", qPrintable(m_file.fileName()));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_reader.setDevice(&m_file);
|
||||
|
||||
m_commands.clear();
|
||||
m_versionCommandMapping.clear();
|
||||
|
||||
while (!m_reader.atEnd()) {
|
||||
m_reader.readNext();
|
||||
if (m_reader.isStartElement()) {
|
||||
if (m_reader.name() == QStringLiteral("commands"))
|
||||
parseCommands();
|
||||
else if (m_reader.name() == QStringLiteral("feature"))
|
||||
parseFeature();
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,15 +112,60 @@ void VkSpecParser::skip()
|
||||
}
|
||||
}
|
||||
|
||||
void VkSpecParser::parseFeature()
|
||||
{
|
||||
// <feature api="vulkan" name="VK_VERSION_1_0" number="1.0" comment="Vulkan core API interface definitions">
|
||||
// <require comment="Device initialization">
|
||||
|
||||
QString api;
|
||||
QString versionName;
|
||||
for (const QXmlStreamAttribute &attr : m_reader.attributes()) {
|
||||
if (attr.name() == QStringLiteral("api"))
|
||||
api = attr.value().toString().trimmed();
|
||||
else if (attr.name() == QStringLiteral("name"))
|
||||
versionName = attr.value().toString().trimmed();
|
||||
}
|
||||
const bool isVulkan = api == QStringLiteral("vulkan");
|
||||
|
||||
while (!m_reader.atEnd()) {
|
||||
m_reader.readNext();
|
||||
if (m_reader.isEndElement() && m_reader.name() == QStringLiteral("feature"))
|
||||
return;
|
||||
if (m_reader.isStartElement() && m_reader.name() == QStringLiteral("require")) {
|
||||
if (isVulkan)
|
||||
parseFeatureRequire(versionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VkSpecParser::parseFeatureRequire(const QString &versionDefine)
|
||||
{
|
||||
// <require comment="Device initialization">
|
||||
// <command name="vkCreateInstance"/>
|
||||
|
||||
while (!m_reader.atEnd()) {
|
||||
m_reader.readNext();
|
||||
if (m_reader.isEndElement() && m_reader.name() == QStringLiteral("require"))
|
||||
return;
|
||||
if (m_reader.isStartElement() && m_reader.name() == QStringLiteral("command")) {
|
||||
for (const QXmlStreamAttribute &attr : m_reader.attributes()) {
|
||||
if (attr.name() == QStringLiteral("name"))
|
||||
m_versionCommandMapping[versionDefine].append(attr.value().toString().trimmed());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VkSpecParser::parseCommands()
|
||||
{
|
||||
m_commands.clear();
|
||||
// <commands comment="Vulkan command definitions">
|
||||
// <command successcodes="VK_SUCCESS" ...>
|
||||
|
||||
while (!m_reader.atEnd()) {
|
||||
m_reader.readNext();
|
||||
if (m_reader.isEndElement() && m_reader.name() == QStringLiteral("commands"))
|
||||
return;
|
||||
if (m_reader.isStartElement() && m_reader.name() == u"command") {
|
||||
if (m_reader.isStartElement() && m_reader.name() == QStringLiteral("command")) {
|
||||
const Command c = parseCommand();
|
||||
if (!c.cmd.name.isEmpty()) // skip aliases
|
||||
m_commands.append(c);
|
||||
@ -116,6 +177,12 @@ VkSpecParser::Command VkSpecParser::parseCommand()
|
||||
{
|
||||
Command c;
|
||||
|
||||
// <command successcodes="VK_SUCCESS" ...>
|
||||
// <proto><type>VkResult</type> <name>vkCreateInstance</name></proto>
|
||||
// <param>const <type>VkInstanceCreateInfo</type>* <name>pCreateInfo</name></param>
|
||||
// <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
|
||||
// <param><type>VkInstance</type>* <name>pInstance</name></param>
|
||||
|
||||
while (!m_reader.atEnd()) {
|
||||
m_reader.readNext();
|
||||
if (m_reader.isEndElement() && m_reader.name() == QStringLiteral("command"))
|
||||
@ -265,7 +332,9 @@ QByteArray Preamble::get(const QString &fn)
|
||||
return m_str;
|
||||
}
|
||||
|
||||
bool genVulkanFunctionsH(const QList<VkSpecParser::Command> &commands, const QString &licHeaderFn,
|
||||
bool genVulkanFunctionsH(const QList<VkSpecParser::Command> &commands,
|
||||
const QMap<QString, QStringList> &versionCommandMapping,
|
||||
const QString &licHeaderFn,
|
||||
const QString &outputBase)
|
||||
{
|
||||
QFile f(outputBase + QStringLiteral(".h"));
|
||||
@ -332,11 +401,21 @@ bool genVulkanFunctionsH(const QList<VkSpecParser::Command> &commands, const QSt
|
||||
|
||||
QString instCmdStr;
|
||||
QString devCmdStr;
|
||||
for (const VkSpecParser::Command &c : commands) {
|
||||
QString *dst = c.deviceLevel ? &devCmdStr : &instCmdStr;
|
||||
*dst += QStringLiteral(" ");
|
||||
*dst += funcSig(c);
|
||||
*dst += QStringLiteral(";\n");
|
||||
for (const QString &version : VERSIONS) {
|
||||
const QStringList &coreFunctionsInVersion = versionCommandMapping[version];
|
||||
instCmdStr += "#if " + version + "\n";
|
||||
devCmdStr += "#if " + version + "\n";
|
||||
for (const VkSpecParser::Command &c : commands) {
|
||||
if (!coreFunctionsInVersion.contains(c.cmd.name))
|
||||
continue;
|
||||
|
||||
QString *dst = c.deviceLevel ? &devCmdStr : &instCmdStr;
|
||||
*dst += QStringLiteral(" ");
|
||||
*dst += funcSig(c);
|
||||
*dst += QStringLiteral(";\n");
|
||||
}
|
||||
instCmdStr += "#endif\n";
|
||||
devCmdStr += "#endif\n";
|
||||
}
|
||||
|
||||
f.write(QString::asprintf(s, preamble.get(licHeaderFn).constData(),
|
||||
@ -346,7 +425,9 @@ bool genVulkanFunctionsH(const QList<VkSpecParser::Command> &commands, const QSt
|
||||
return true;
|
||||
}
|
||||
|
||||
bool genVulkanFunctionsPH(const QList<VkSpecParser::Command> &commands, const QString &licHeaderFn,
|
||||
bool genVulkanFunctionsPH(const QList<VkSpecParser::Command> &commands,
|
||||
const QMap<QString, QStringList> &versionCommandMapping,
|
||||
const QString &licHeaderFn,
|
||||
const QString &outputBase)
|
||||
{
|
||||
QFile f(outputBase + QStringLiteral("_p.h"));
|
||||
@ -397,16 +478,29 @@ bool genVulkanFunctionsPH(const QList<VkSpecParser::Command> &commands, const QS
|
||||
"\n"
|
||||
"#endif // QVULKANFUNCTIONS_P_H\n";
|
||||
|
||||
const int devLevelCount = std::count_if(commands.cbegin(), commands.cend(),
|
||||
[](const VkSpecParser::Command &c) { return c.deviceLevel; });
|
||||
const int instLevelCount = commands.count() - devLevelCount;
|
||||
int devLevelCount = 0;
|
||||
int instLevelCount = 0;
|
||||
for (const QString &version : VERSIONS) {
|
||||
const QStringList &coreFunctionsInVersion = versionCommandMapping[version];
|
||||
for (const VkSpecParser::Command &c : commands) {
|
||||
if (!coreFunctionsInVersion.contains(c.cmd.name))
|
||||
continue;
|
||||
|
||||
if (c.deviceLevel)
|
||||
devLevelCount += 1;
|
||||
else
|
||||
instLevelCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
f.write(QString::asprintf(s, preamble.get(licHeaderFn).constData(), instLevelCount, devLevelCount).toUtf8());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool genVulkanFunctionsPC(const QList<VkSpecParser::Command> &commands, const QString &licHeaderFn,
|
||||
bool genVulkanFunctionsPC(const QList<VkSpecParser::Command> &commands,
|
||||
const QMap<QString, QStringList> &versionCommandMapping,
|
||||
const QString &licHeaderFn,
|
||||
const QString &outputBase)
|
||||
{
|
||||
QFile f(outputBase + QStringLiteral("_p.cpp"));
|
||||
@ -429,7 +523,7 @@ bool genVulkanFunctionsPC(const QList<VkSpecParser::Command> &commands, const QS
|
||||
" };\n"
|
||||
" for (int i = 0; i < %d; ++i) {\n"
|
||||
" m_funcs[i] = inst->getInstanceProcAddr(funcNames[i]);\n"
|
||||
" if (!m_funcs[i])\n"
|
||||
" if (i < %d && !m_funcs[i])\n"
|
||||
" qWarning(\"QVulkanFunctions: Failed to resolve %%s\", funcNames[i]);\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
@ -443,7 +537,7 @@ bool genVulkanFunctionsPC(const QList<VkSpecParser::Command> &commands, const QS
|
||||
" };\n"
|
||||
" for (int i = 0; i < %d; ++i) {\n"
|
||||
" m_funcs[i] = f->vkGetDeviceProcAddr(device, funcNames[i]);\n"
|
||||
" if (!m_funcs[i])\n"
|
||||
" if (i < %d && !m_funcs[i])\n"
|
||||
" qWarning(\"QVulkanDeviceFunctions: Failed to resolve %%s\", funcNames[i]);\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
@ -453,23 +547,46 @@ bool genVulkanFunctionsPC(const QList<VkSpecParser::Command> &commands, const QS
|
||||
QString devCmdWrapperStr;
|
||||
QString instCmdWrapperStr;
|
||||
int devIdx = 0;
|
||||
int devCount = 0;
|
||||
int instIdx = 0;
|
||||
int instCount = 0;
|
||||
QString devCmdNamesStr;
|
||||
QString instCmdNamesStr;
|
||||
int vulkan10DevCount = 0;
|
||||
int vulkan10InstCount = 0;
|
||||
|
||||
for (int i = 0; i < commands.count(); ++i) {
|
||||
QString *dst = commands[i].deviceLevel ? &devCmdWrapperStr : &instCmdWrapperStr;
|
||||
int *idx = commands[i].deviceLevel ? &devIdx : &instIdx;
|
||||
*dst += funcSig(commands[i], commands[i].deviceLevel ? "QVulkanDeviceFunctions" : "QVulkanFunctions");
|
||||
*dst += QString(QStringLiteral("\n{\n Q_ASSERT(d_ptr->m_funcs[%1]);\n ")).arg(*idx);
|
||||
*dst += funcCall(commands[i], *idx);
|
||||
*dst += QStringLiteral(";\n}\n\n");
|
||||
++*idx;
|
||||
for (const QString &version : VERSIONS) {
|
||||
const QStringList &coreFunctionsInVersion = versionCommandMapping[version];
|
||||
instCmdWrapperStr += "\n#if " + version + "\n";
|
||||
devCmdWrapperStr += "\n#if " + version + "\n";
|
||||
for (const VkSpecParser::Command &c : commands) {
|
||||
if (!coreFunctionsInVersion.contains(c.cmd.name))
|
||||
continue;
|
||||
|
||||
dst = commands[i].deviceLevel ? &devCmdNamesStr : &instCmdNamesStr;
|
||||
*dst += QStringLiteral(" \"");
|
||||
*dst += commands[i].cmd.name;
|
||||
*dst += QStringLiteral("\",\n");
|
||||
QString *dst = c.deviceLevel ? &devCmdWrapperStr : &instCmdWrapperStr;
|
||||
int *idx = c.deviceLevel ? &devIdx : &instIdx;
|
||||
*dst += funcSig(c, c.deviceLevel ? "QVulkanDeviceFunctions" : "QVulkanFunctions");
|
||||
*dst += QString(QStringLiteral("\n{\n Q_ASSERT(d_ptr->m_funcs[%1]);\n ")).arg(*idx);
|
||||
*dst += funcCall(c, *idx);
|
||||
*dst += QStringLiteral(";\n}\n\n");
|
||||
*idx += 1;
|
||||
|
||||
dst = c.deviceLevel ? &devCmdNamesStr : &instCmdNamesStr;
|
||||
*dst += QStringLiteral(" \"");
|
||||
*dst += c.cmd.name;
|
||||
*dst += QStringLiteral("\",\n");
|
||||
|
||||
if (c.deviceLevel)
|
||||
devCount += 1;
|
||||
else
|
||||
instCount += 1;
|
||||
}
|
||||
if (version == QStringLiteral("VK_VERSION_1_0")) {
|
||||
vulkan10InstCount = instIdx;
|
||||
vulkan10DevCount = devIdx;
|
||||
}
|
||||
instCmdWrapperStr += "#endif\n\n";
|
||||
devCmdWrapperStr += "#endif\n\n";
|
||||
}
|
||||
|
||||
if (devCmdNamesStr.count() > 2)
|
||||
@ -480,9 +597,9 @@ bool genVulkanFunctionsPC(const QList<VkSpecParser::Command> &commands, const QS
|
||||
const QString str =
|
||||
QString::asprintf(s, preamble.get(licHeaderFn).constData(),
|
||||
instCmdWrapperStr.toUtf8().constData(),
|
||||
instCmdNamesStr.toUtf8().constData(), instIdx,
|
||||
instCmdNamesStr.toUtf8().constData(), instCount, vulkan10InstCount,
|
||||
devCmdWrapperStr.toUtf8().constData(),
|
||||
devCmdNamesStr.toUtf8().constData(), commands.count() - instIdx);
|
||||
devCmdNamesStr.toUtf8().constData(), devCount, vulkan10DevCount);
|
||||
|
||||
f.write(str.toUtf8());
|
||||
|
||||
@ -505,27 +622,27 @@ int main(int argc, char **argv)
|
||||
if (!parser.parse())
|
||||
return 1;
|
||||
|
||||
// Now we have a list of functions (commands), including extensions, and a
|
||||
// table of Version (1.0, 1.1, 1.2) -> Core functions in that version.
|
||||
QList<VkSpecParser::Command> commands = parser.commands();
|
||||
QMap<QString, QStringList> versionCommandMapping = parser.versionCommandMapping();
|
||||
|
||||
QStringList ignoredFuncs {
|
||||
QStringLiteral("vkCreateInstance"),
|
||||
QStringLiteral("vkDestroyInstance"),
|
||||
QStringLiteral("vkGetInstanceProcAddr")
|
||||
QStringLiteral("vkGetInstanceProcAddr"),
|
||||
QStringLiteral("vkEnumerateInstanceVersion")
|
||||
};
|
||||
|
||||
// Filter out extensions and unwanted functions.
|
||||
// The check for the former is rather simplistic for now: skip if the last letter is uppercase...
|
||||
for (int i = 0; i < commands.count(); ++i) {
|
||||
QString name = commands[i].cmd.name;
|
||||
QChar c = name[name.count() - 1];
|
||||
if (c.isUpper() || ignoredFuncs.contains(name))
|
||||
if (ignoredFuncs.contains(commands[i].cmd.name))
|
||||
commands.remove(i--);
|
||||
}
|
||||
|
||||
QString licenseHeaderFileName = QString::fromUtf8(argv[2]);
|
||||
QString outputBase = QString::fromUtf8(argv[3]);
|
||||
genVulkanFunctionsH(commands, licenseHeaderFileName, outputBase);
|
||||
genVulkanFunctionsPH(commands, licenseHeaderFileName, outputBase);
|
||||
genVulkanFunctionsPC(commands, licenseHeaderFileName, outputBase);
|
||||
genVulkanFunctionsH(commands, versionCommandMapping, licenseHeaderFileName, outputBase);
|
||||
genVulkanFunctionsPH(commands, versionCommandMapping, licenseHeaderFileName, outputBase);
|
||||
genVulkanFunctionsPC(commands, versionCommandMapping, licenseHeaderFileName, outputBase);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ private slots:
|
||||
void vulkanCheckSupported();
|
||||
void vulkanPlainWindow();
|
||||
void vulkanVersionRequest();
|
||||
void vulkan11();
|
||||
void vulkanWindow();
|
||||
void vulkanWindowRenderer();
|
||||
void vulkanWindowGrab();
|
||||
@ -108,6 +109,78 @@ void tst_QVulkan::vulkanCheckSupported()
|
||||
QVERIFY(inst.supportedApiVersion().majorVersion() >= 1);
|
||||
}
|
||||
|
||||
void tst_QVulkan::vulkan11()
|
||||
{
|
||||
#if VK_VERSION_1_1
|
||||
QVulkanInstance inst;
|
||||
if (inst.supportedApiVersion() < QVersionNumber(1, 1))
|
||||
QSKIP("Vulkan 1.1 is not supported by the VkInstance; skip");
|
||||
|
||||
inst.setApiVersion(QVersionNumber(1, 1));
|
||||
if (!inst.create())
|
||||
QSKIP("Vulkan 1.1 instance creation failed; skip");
|
||||
|
||||
QCOMPARE(inst.errorCode(), VK_SUCCESS);
|
||||
|
||||
// exercise some 1.1 commands
|
||||
QVulkanFunctions *f = inst.functions();
|
||||
QVERIFY(f);
|
||||
uint32_t count = 0;
|
||||
VkResult err = f->vkEnumeratePhysicalDeviceGroups(inst.vkInstance(), &count, nullptr);
|
||||
if (err != VK_SUCCESS)
|
||||
QSKIP("No physical devices; skip");
|
||||
|
||||
if (count) {
|
||||
QVarLengthArray<VkPhysicalDeviceGroupProperties, 4> groupProperties;
|
||||
groupProperties.resize(count);
|
||||
err = f->vkEnumeratePhysicalDeviceGroups(inst.vkInstance(), &count, groupProperties.data()); // 1.1 API
|
||||
QCOMPARE(err, VK_SUCCESS);
|
||||
for (const VkPhysicalDeviceGroupProperties &gp : groupProperties) {
|
||||
QCOMPARE(gp.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES);
|
||||
for (uint32_t i = 0; i != gp.physicalDeviceCount; ++i) {
|
||||
VkPhysicalDevice physDev = gp.physicalDevices[i];
|
||||
|
||||
// Instance and physical device apiVersion are two different things.
|
||||
VkPhysicalDeviceProperties props;
|
||||
f->vkGetPhysicalDeviceProperties(physDev, &props);
|
||||
QVersionNumber physDevVer(VK_VERSION_MAJOR(props.apiVersion),
|
||||
VK_VERSION_MINOR(props.apiVersion),
|
||||
VK_VERSION_PATCH(props.apiVersion));
|
||||
qDebug() << "Physical device" << physDev << "apiVersion" << physDevVer;
|
||||
|
||||
if (physDevVer >= QVersionNumber(1, 1)) {
|
||||
// Now that we ensured that we have an 1.1 capable instance and physical device,
|
||||
// query something that was not in 1.0.
|
||||
VkPhysicalDeviceIDProperties deviceIdProps = {}; // new in 1.1
|
||||
deviceIdProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
|
||||
VkPhysicalDeviceProperties2 props2 = {};
|
||||
props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
props2.pNext = &deviceIdProps;
|
||||
f->vkGetPhysicalDeviceProperties2(physDev, &props2); // 1.1 API
|
||||
QByteArray deviceUuid = QByteArray::fromRawData((const char *) deviceIdProps.deviceUUID, VK_UUID_SIZE).toHex();
|
||||
QByteArray driverUuid = QByteArray::fromRawData((const char *) deviceIdProps.driverUUID, VK_UUID_SIZE).toHex();
|
||||
qDebug() << "deviceUUID" << deviceUuid << "driverUUID" << driverUuid;
|
||||
// deviceUUID cannot be all zero as per spec
|
||||
bool seenNonZero = false;
|
||||
for (int i = 0; i < VK_UUID_SIZE; ++i) {
|
||||
if (deviceIdProps.deviceUUID[i]) {
|
||||
seenNonZero = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
QVERIFY(seenNonZero);
|
||||
} else {
|
||||
qDebug("Physical device is not Vulkan 1.1 capable");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
QSKIP("Vulkan header is not 1.1 capable; skip");
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QVulkan::vulkanPlainWindow()
|
||||
{
|
||||
QVulkanInstance inst;
|
||||
|
Loading…
x
Reference in New Issue
Block a user