2022-05-10 10:06:48 +00:00
|
|
|
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
#include "codegenerator.h"
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QTextStream>
|
|
|
|
|
|
|
|
static const QString extensionRegistryFileName = QStringLiteral("qopengl-extension-registry.ini");
|
|
|
|
static const QString extensionIdGroupName = QStringLiteral("ExtensionIds");
|
|
|
|
|
|
|
|
CodeGenerator::CodeGenerator()
|
|
|
|
: m_parser(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::generateCoreClasses(const QString &baseFileName) const
|
|
|
|
{
|
|
|
|
// Output header and implementation files for the backend and base class
|
|
|
|
writeCoreHelperClasses(baseFileName + QStringLiteral(".h"), Declaration);
|
|
|
|
writeCoreHelperClasses(baseFileName + QStringLiteral(".cpp"), Definition);
|
|
|
|
|
|
|
|
// Output the per-version and profile public classes
|
|
|
|
writeCoreClasses(baseFileName);
|
|
|
|
|
|
|
|
// We also need to generate a factory class that can be used by
|
|
|
|
// QOpenGLContext to actually create version function objects
|
|
|
|
writeCoreFactoryHeader(baseFileName + QStringLiteral("factory_p.h"));
|
|
|
|
writeCoreFactoryImplementation(baseFileName + QStringLiteral("factory.cpp"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::generateExtensionClasses(const QString &baseFileName) const
|
|
|
|
{
|
|
|
|
writeExtensionHeader(baseFileName + QStringLiteral(".h"));
|
|
|
|
writeExtensionImplementation(baseFileName + QStringLiteral(".cpp"));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CodeGenerator::isLegacyVersion(Version v) const
|
|
|
|
{
|
|
|
|
return (v.major < 3 || (v.major == 3 && v.minor == 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CodeGenerator::versionHasProfiles(Version v) const
|
|
|
|
{
|
|
|
|
VersionProfile vp;
|
|
|
|
vp.version = v;
|
|
|
|
return vp.hasProfiles();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeCoreHelperClasses(const QString &fileName, ClassComponent component) const
|
|
|
|
{
|
|
|
|
if (!m_parser)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QFile file(fileName);
|
|
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|
|
|
return;
|
|
|
|
QTextStream stream(&file);
|
|
|
|
|
|
|
|
// Write the preamble
|
|
|
|
writePreamble(fileName, stream);
|
|
|
|
|
|
|
|
// Iterate over each OpenGL version. For each version output a private class for
|
|
|
|
// core functions and a private class for deprecated functions.
|
|
|
|
const QString privateRootClass = QStringLiteral("QOpenGLVersionFunctionsBackend");
|
|
|
|
Q_FOREACH (const VersionProfile &versionProfile, m_parser->versionProfiles()) {
|
|
|
|
switch (component) {
|
|
|
|
case Declaration:
|
|
|
|
writeBackendClassDeclaration(stream, versionProfile, privateRootClass);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Definition:
|
|
|
|
writeBackendClassImplementation(stream, versionProfile, privateRootClass);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the postamble
|
|
|
|
writePostamble(fileName, stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeCoreClasses(const QString &baseFileName) const
|
|
|
|
{
|
|
|
|
// Iterate over each OpenGL version. For each version output a public class (for legacy
|
|
|
|
// versions or two public classes (for modern versions with profiles). Each public class
|
|
|
|
// is given pointers to private classes containing the actual entry points. For example,
|
|
|
|
// the class for OpenGL 1.1 will have pointers to the private classes for 1.0 core, 1.1
|
|
|
|
// core, 1.0 deprecated and 1.1 deprecated. Whereas the class for OpenGL 3.2 Core profile
|
|
|
|
// will have pointers to the private classes for 1.0 core, 1.1 core, ..., 3.2 core but
|
|
|
|
// not to any of the deprecated private classes
|
|
|
|
QList<ClassComponent> components = (QList<ClassComponent>() << Declaration << Definition);
|
|
|
|
Q_FOREACH (const ClassComponent &component, components) {
|
|
|
|
const QString rootClass = QStringLiteral("QAbstractOpenGLFunctions");
|
|
|
|
Q_FOREACH (const Version &classVersion, m_parser->versions()) {
|
|
|
|
VersionProfile v;
|
|
|
|
v.version = classVersion;
|
|
|
|
v.profile = VersionProfile::CompatibilityProfile;
|
|
|
|
|
|
|
|
if (isLegacyVersion(classVersion)) {
|
|
|
|
switch (component) {
|
|
|
|
case Declaration:
|
|
|
|
writePublicClassDeclaration(baseFileName, v, rootClass);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Definition:
|
|
|
|
writePublicClassImplementation(baseFileName, v, rootClass);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (component) {
|
|
|
|
case Declaration:
|
|
|
|
writePublicClassDeclaration(baseFileName, v, rootClass);
|
|
|
|
v.profile = VersionProfile::CoreProfile;
|
|
|
|
writePublicClassDeclaration(baseFileName, v, rootClass);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Definition:
|
|
|
|
writePublicClassImplementation(baseFileName, v, rootClass);
|
|
|
|
v.profile = VersionProfile::CoreProfile;
|
|
|
|
writePublicClassImplementation(baseFileName, v, rootClass);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeCoreFactoryHeader(const QString &fileName) const
|
|
|
|
{
|
|
|
|
if (!m_parser)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QFile file(fileName);
|
|
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|
|
|
return;
|
|
|
|
QTextStream stream(&file);
|
|
|
|
|
|
|
|
// Write the preamble
|
|
|
|
writePreamble(fileName, stream);
|
|
|
|
|
|
|
|
// Write the postamble
|
|
|
|
writePostamble(fileName, stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeCoreFactoryImplementation(const QString &fileName) const
|
|
|
|
{
|
|
|
|
if (!m_parser)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QFile file(fileName);
|
|
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|
|
|
return;
|
|
|
|
QTextStream stream(&file);
|
|
|
|
|
|
|
|
// Write the preamble
|
|
|
|
writePreamble(fileName, stream);
|
|
|
|
|
|
|
|
// Get the set of version functions classes we need to create
|
|
|
|
QList<Version> versions = m_parser->versions();
|
2020-01-28 14:47:48 +00:00
|
|
|
std::sort(versions.begin(), versions.end(), std::greater<Version>());
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Outout the #include statements
|
2020-04-14 11:48:28 +00:00
|
|
|
stream << QStringLiteral("#if !QT_CONFIG(opengles2)") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
Q_FOREACH (const Version &classVersion, versions) {
|
|
|
|
if (!versionHasProfiles(classVersion)) {
|
|
|
|
stream << QString(QStringLiteral("#include \"qopenglfunctions_%1_%2.h\""))
|
|
|
|
.arg(classVersion.major)
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(classVersion.minor) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
} else {
|
|
|
|
const QList<VersionProfile::OpenGLProfile> profiles = (QList<VersionProfile::OpenGLProfile>()
|
|
|
|
<< VersionProfile::CoreProfile << VersionProfile::CompatibilityProfile);
|
|
|
|
|
|
|
|
Q_FOREACH (const VersionProfile::OpenGLProfile profile, profiles) {
|
|
|
|
const QString profileSuffix = profile == VersionProfile::CoreProfile
|
|
|
|
? QStringLiteral("core")
|
|
|
|
: QStringLiteral("compatibility");
|
|
|
|
stream << QString(QStringLiteral("#include \"qopenglfunctions_%1_%2_%3.h\""))
|
|
|
|
.arg(classVersion.major)
|
|
|
|
.arg(classVersion.minor)
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(profileSuffix) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("#else") << Qt::endl;
|
|
|
|
stream << QStringLiteral("#include \"qopenglfunctions_es2.h\"") << Qt::endl;
|
|
|
|
stream << QStringLiteral("#endif") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("QT_BEGIN_NAMESPACE") << Qt::endl << Qt::endl;
|
|
|
|
stream << QStringLiteral("QAbstractOpenGLFunctions *QOpenGLVersionFunctionsFactory::create(const QOpenGLVersionProfile &versionProfile)") << Qt::endl;
|
|
|
|
stream << QStringLiteral("{") << Qt::endl;
|
2020-04-14 11:48:28 +00:00
|
|
|
stream << QStringLiteral("#if !QT_CONFIG(opengles2)") << Qt::endl;
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" const int major = versionProfile.version().first;") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" const int minor = versionProfile.version().second;") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Iterate over classes with profiles
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" if (versionProfile.hasProfiles()) {") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" switch (versionProfile.profile()) {") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
const QList<VersionProfile::OpenGLProfile> profiles = (QList<VersionProfile::OpenGLProfile>()
|
|
|
|
<< VersionProfile::CoreProfile << VersionProfile::CompatibilityProfile);
|
|
|
|
Q_FOREACH (const VersionProfile::OpenGLProfile profile, profiles) {
|
|
|
|
const QString caseLabel = profile == VersionProfile::CoreProfile
|
|
|
|
? QStringLiteral("QSurfaceFormat::CoreProfile")
|
|
|
|
: QStringLiteral("QSurfaceFormat::CompatibilityProfile");
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral(" case %1:")).arg(caseLabel) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
Q_FOREACH (const Version &classVersion, versions) {
|
|
|
|
if (!versionHasProfiles(classVersion))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const QString ifString = (i++ == 0) ? QStringLiteral("if") : QStringLiteral("else if");
|
|
|
|
stream << QString(QStringLiteral(" %1 (major == %2 && minor == %3)"))
|
|
|
|
.arg(ifString)
|
|
|
|
.arg(classVersion.major)
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(classVersion.minor) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
VersionProfile v;
|
|
|
|
v.version = classVersion;
|
|
|
|
v.profile = profile;
|
|
|
|
stream << QString(QStringLiteral(" return new %1;"))
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(generateClassName(v)) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" break;") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" case QSurfaceFormat::NoProfile:") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" default:") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" break;") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" };") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" } else {") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Iterate over the legacy classes (no profiles)
|
|
|
|
int i = 0;
|
|
|
|
Q_FOREACH (const Version &classVersion, versions) {
|
|
|
|
if (versionHasProfiles(classVersion))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const QString ifString = (i++ == 0) ? QStringLiteral("if") : QStringLiteral("else if");
|
|
|
|
stream << QString(QStringLiteral(" %1 (major == %2 && minor == %3)"))
|
|
|
|
.arg(ifString)
|
|
|
|
.arg(classVersion.major)
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(classVersion.minor) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
VersionProfile v;
|
|
|
|
v.version = classVersion;
|
|
|
|
stream << QString(QStringLiteral(" return new %1;"))
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(generateClassName(v)) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" }") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" return 0;") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("#else") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" Q_UNUSED(versionProfile);") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" return new QOpenGLFunctions_ES2;") << Qt::endl;
|
|
|
|
stream << QStringLiteral("#endif") << Qt::endl;
|
|
|
|
stream << QStringLiteral("}") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Write the postamble
|
|
|
|
writePostamble(fileName, stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\returns all functions to be included in the class defined by \a classVersionProfile
|
|
|
|
*/
|
|
|
|
FunctionCollection CodeGenerator::functionCollection( const VersionProfile& classVersionProfile ) const
|
|
|
|
{
|
|
|
|
const Version classVersion = classVersionProfile.version;
|
|
|
|
FunctionCollection functionSet;
|
|
|
|
QList<Version> versions = m_parser->versions();
|
|
|
|
|
|
|
|
// Populate these based upon the class version and profile
|
|
|
|
Version minVersion;
|
|
|
|
minVersion.major = 1;
|
|
|
|
minVersion.minor = 0;
|
|
|
|
Version maxVersion = classVersion;
|
|
|
|
QList<VersionProfile::OpenGLProfile> profiles;
|
|
|
|
profiles << VersionProfile::CoreProfile; // Always need core functions
|
|
|
|
|
|
|
|
if (isLegacyVersion(classVersion)
|
|
|
|
|| (classVersionProfile.hasProfiles()
|
|
|
|
&& classVersionProfile.profile == VersionProfile::CompatibilityProfile)) {
|
|
|
|
// For versions < 3.1 and Compatibility profile we include both core and deprecated functions
|
|
|
|
profiles << VersionProfile::CompatibilityProfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_FOREACH (const Version &v, versions) {
|
|
|
|
// Only include functions from versions in the range
|
|
|
|
if (v < minVersion)
|
|
|
|
continue;
|
|
|
|
if (v > maxVersion)
|
|
|
|
break;
|
|
|
|
|
|
|
|
Q_FOREACH (VersionProfile::OpenGLProfile profile, profiles) {
|
|
|
|
// Combine version and profile for this subset of functions
|
|
|
|
VersionProfile version;
|
|
|
|
version.version = v;
|
|
|
|
version.profile = profile;
|
|
|
|
|
|
|
|
// Fetch the functions and add to collection for this class
|
|
|
|
QList<Function> functions = m_parser->functionsForVersion(version);
|
|
|
|
functionSet.insert(version, functions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return functionSet;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writePreamble(const QString &baseFileName, QTextStream &stream, const QString replacement) const
|
|
|
|
{
|
|
|
|
const QString fileName = baseFileName + QStringLiteral(".header");
|
|
|
|
if (!QFile::exists(fileName))
|
|
|
|
return;
|
|
|
|
|
|
|
|
QFile file(fileName);
|
|
|
|
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
|
|
QTextStream preambleStream(&file);
|
|
|
|
QString preamble = preambleStream.readAll();
|
|
|
|
if (!replacement.isEmpty())
|
|
|
|
preamble.replace(QStringLiteral("__VERSION__"), replacement, Qt::CaseSensitive);
|
|
|
|
stream << preamble;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writePostamble(const QString &baseFileName, QTextStream &stream) const
|
|
|
|
{
|
|
|
|
const QString fileName = baseFileName + QStringLiteral(".footer");
|
|
|
|
if (!QFile::exists(fileName))
|
|
|
|
return;
|
|
|
|
|
|
|
|
QFile file(fileName);
|
|
|
|
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
|
|
QTextStream postambleStream(&file);
|
|
|
|
QString postamble = postambleStream.readAll();
|
|
|
|
stream << postamble;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString CodeGenerator::passByType(const Argument &arg) const
|
|
|
|
{
|
|
|
|
QString passBy;
|
|
|
|
switch (arg.mode) {
|
|
|
|
case Argument::Reference:
|
|
|
|
case Argument::Array:
|
|
|
|
passBy = QStringLiteral("*");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
case Argument::Value:
|
|
|
|
passBy = QString();
|
|
|
|
}
|
|
|
|
return passBy;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString CodeGenerator::safeArgumentName(const QString& arg) const
|
|
|
|
{
|
Don't use QStringLiteral in comparisons
For QLatin1String, operator== is overloaded, so comparing to a latin-1
(C) string literal is efficient, since strlen() is comparatively fast.
OTOH, QStringLiteral, when not using RVO, litters the code with
QString dtor calls, which are not inline. Worse, absent lambdas,
it even allocates memory.
So, just compare using QLatin1String instead.
Change-Id: I761b2b26ab5b416bc695f524a9ee607dacf0a7b2
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
2016-01-19 08:49:37 +00:00
|
|
|
if (arg == QLatin1String("near")) // MS Windows defines near and far
|
2012-08-08 15:43:48 +00:00
|
|
|
return QStringLiteral("nearVal");
|
Don't use QStringLiteral in comparisons
For QLatin1String, operator== is overloaded, so comparing to a latin-1
(C) string literal is efficient, since strlen() is comparatively fast.
OTOH, QStringLiteral, when not using RVO, litters the code with
QString dtor calls, which are not inline. Worse, absent lambdas,
it even allocates memory.
So, just compare using QLatin1String instead.
Change-Id: I761b2b26ab5b416bc695f524a9ee607dacf0a7b2
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
2016-01-19 08:49:37 +00:00
|
|
|
else if (arg == QLatin1String("far"))
|
2012-08-08 15:43:48 +00:00
|
|
|
return QStringLiteral("farVal");
|
Don't use QStringLiteral in comparisons
For QLatin1String, operator== is overloaded, so comparing to a latin-1
(C) string literal is efficient, since strlen() is comparatively fast.
OTOH, QStringLiteral, when not using RVO, litters the code with
QString dtor calls, which are not inline. Worse, absent lambdas,
it even allocates memory.
So, just compare using QLatin1String instead.
Change-Id: I761b2b26ab5b416bc695f524a9ee607dacf0a7b2
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
2016-01-19 08:49:37 +00:00
|
|
|
else if (arg == QLatin1String("d"))
|
2012-08-08 15:43:48 +00:00
|
|
|
return QStringLiteral("dd"); // Don't shadow d pointer
|
|
|
|
else
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString CodeGenerator::generateClassName(const VersionProfile &classVersion, ClassVisibility visibility) const
|
|
|
|
{
|
|
|
|
QString className;
|
|
|
|
switch ( visibility ) {
|
|
|
|
case Public: {
|
|
|
|
// Class name and base class
|
|
|
|
QString profileSuffix;
|
|
|
|
if (classVersion.hasProfiles())
|
|
|
|
profileSuffix = (classVersion.profile == VersionProfile::CoreProfile ? QStringLiteral("_Core") : QStringLiteral("_Compatibility"));
|
|
|
|
|
|
|
|
className = QString(QStringLiteral("QOpenGLFunctions_%1_%2%3"))
|
|
|
|
.arg(classVersion.version.major)
|
|
|
|
.arg(classVersion.version.minor)
|
|
|
|
.arg(profileSuffix);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Private: {
|
|
|
|
QString statusSuffix = (classVersion.profile == VersionProfile::CoreProfile ? QStringLiteral("_Core") : QStringLiteral("_Deprecated"));
|
|
|
|
|
|
|
|
className = QString(QStringLiteral("QOpenGLFunctions_%1_%2%3Private"))
|
|
|
|
.arg(classVersion.version.major)
|
|
|
|
.arg(classVersion.version.minor)
|
|
|
|
.arg(statusSuffix);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return className;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeBackendClassDeclaration(QTextStream &stream,
|
|
|
|
const VersionProfile &versionProfile,
|
|
|
|
const QString &baseClass) const
|
|
|
|
{
|
|
|
|
const QString className = backendClassName(versionProfile);
|
|
|
|
stream << QString(QStringLiteral("class %1 : public %2"))
|
|
|
|
.arg(className)
|
|
|
|
.arg(baseClass)
|
2020-01-28 14:50:13 +00:00
|
|
|
<< Qt::endl;
|
|
|
|
stream << QStringLiteral("{") << Qt::endl;
|
|
|
|
stream << QStringLiteral("public:") << Qt::endl;
|
|
|
|
stream << QString( QStringLiteral(" %1(QOpenGLContext *context);") ).arg(className) << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output function used for generating key used in QOpenGLContextPrivate
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" static QOpenGLVersionStatus versionStatus();") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Get the functions needed for this class
|
|
|
|
FunctionList functions = m_parser->functionsForVersion(versionProfile);
|
|
|
|
FunctionCollection functionSet;
|
|
|
|
functionSet.insert(versionProfile, functions);
|
|
|
|
|
|
|
|
// Declare the functions
|
|
|
|
writeClassFunctionDeclarations(stream, functionSet, Private);
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("};") << Qt::endl;
|
|
|
|
stream << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeBackendClassImplementation(QTextStream &stream,
|
|
|
|
const VersionProfile &versionProfile,
|
|
|
|
const QString &baseClass) const
|
|
|
|
{
|
|
|
|
const QString className = backendClassName(versionProfile);
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral("%1::%1(QOpenGLContext *context)")).arg(className) << Qt::endl;
|
|
|
|
stream << QString(QStringLiteral(" : %1(context)")).arg(baseClass) << Qt::endl
|
|
|
|
<< QStringLiteral("{") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Resolve the entry points for this set of functions
|
|
|
|
// Get the functions needed for this class
|
|
|
|
FunctionList functions = m_parser->functionsForVersion(versionProfile);
|
|
|
|
FunctionCollection functionSet;
|
|
|
|
functionSet.insert(versionProfile, functions);
|
|
|
|
writeEntryPointResolutionCode(stream, functionSet);
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral("QOpenGLVersionStatus %1::versionStatus()")).arg(className) << Qt::endl;
|
|
|
|
stream << QStringLiteral("{") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
const QString status = versionProfile.profile == VersionProfile::CoreProfile
|
|
|
|
? QStringLiteral("QOpenGLVersionStatus::CoreStatus")
|
|
|
|
: QStringLiteral("QOpenGLVersionStatus::DeprecatedStatus");
|
|
|
|
stream << QString(QStringLiteral(" return QOpenGLVersionStatus(%1, %2, %3);"))
|
|
|
|
.arg(versionProfile.version.major)
|
|
|
|
.arg(versionProfile.version.minor)
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(status) << Qt::endl;
|
|
|
|
stream << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString CodeGenerator::coreClassFileName(const VersionProfile &versionProfile,
|
|
|
|
const QString& fileExtension) const
|
|
|
|
{
|
|
|
|
QString profileSuffix;
|
|
|
|
if (versionProfile.hasProfiles())
|
|
|
|
profileSuffix = (versionProfile.profile == VersionProfile::CoreProfile ? QStringLiteral("_core") : QStringLiteral("_compatibility"));
|
|
|
|
|
|
|
|
const QString fileName = QString(QStringLiteral("qopenglfunctions_%1_%2%3.%4"))
|
|
|
|
.arg(versionProfile.version.major)
|
|
|
|
.arg(versionProfile.version.minor)
|
|
|
|
.arg(profileSuffix)
|
|
|
|
.arg(fileExtension);
|
|
|
|
return fileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writePublicClassDeclaration(const QString &baseFileName,
|
|
|
|
const VersionProfile &versionProfile,
|
|
|
|
const QString &baseClass) const
|
|
|
|
{
|
|
|
|
const QString fileName = coreClassFileName(versionProfile, QStringLiteral("h"));
|
|
|
|
QFile file(fileName);
|
|
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|
|
|
return;
|
|
|
|
QTextStream stream(&file);
|
|
|
|
|
|
|
|
// Write the preamble
|
|
|
|
const QString templateFileName = QString(QStringLiteral("%1__VERSION__.h"))
|
|
|
|
.arg(baseFileName);
|
|
|
|
QString profileSuffix;
|
|
|
|
if (versionProfile.hasProfiles())
|
|
|
|
profileSuffix = (versionProfile.profile == VersionProfile::CoreProfile ? QStringLiteral("_CORE") : QStringLiteral("_COMPATIBILITY"));
|
|
|
|
|
|
|
|
const QString versionProfileString = QString(QStringLiteral("_%1_%2%3"))
|
|
|
|
.arg(versionProfile.version.major)
|
|
|
|
.arg(versionProfile.version.minor)
|
|
|
|
.arg(profileSuffix);
|
|
|
|
writePreamble(templateFileName, stream, versionProfileString);
|
|
|
|
|
|
|
|
// Ctor, dtor, and initialize function;
|
|
|
|
const QString className = generateClassName(versionProfile, Public);
|
|
|
|
stream << QString(QStringLiteral("class Q_GUI_EXPORT %1 : public %2"))
|
|
|
|
.arg(className)
|
|
|
|
.arg(baseClass)
|
2020-01-28 14:50:13 +00:00
|
|
|
<< Qt::endl;
|
|
|
|
stream << QStringLiteral("{") << Qt::endl;
|
|
|
|
stream << QStringLiteral("public:") << Qt::endl;
|
|
|
|
stream << QString(QStringLiteral(" %1();")).arg(className) << Qt::endl;
|
|
|
|
stream << QString(QStringLiteral(" ~%1();")).arg(className) << Qt::endl << Qt::endl;
|
|
|
|
stream << QStringLiteral(" bool initializeOpenGLFunctions() override;") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Get the functions needed for this class and declare them
|
|
|
|
FunctionCollection functionSet = functionCollection(versionProfile);
|
|
|
|
writeClassFunctionDeclarations(stream, functionSet, Public);
|
|
|
|
|
|
|
|
// isCompatible function and backend variables
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("private:") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" friend class QOpenGLContext;") << Qt::endl << Qt::endl;
|
|
|
|
stream << QStringLiteral(" static bool isContextCompatible(QOpenGLContext *context);") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" static QOpenGLVersionProfile versionProfile();") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
writeBackendVariableDeclarations(stream, backendsForFunctionCollection(functionSet));
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("};") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output the inline functions that forward OpenGL calls to the backends' entry points
|
|
|
|
writeClassInlineFunctions(stream, className, functionSet);
|
|
|
|
|
|
|
|
// Write the postamble
|
|
|
|
writePostamble(templateFileName, stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writePublicClassImplementation(const QString &baseFileName,
|
|
|
|
const VersionProfile &versionProfile,
|
|
|
|
const QString& baseClass) const
|
|
|
|
{
|
|
|
|
const QString fileName = coreClassFileName(versionProfile, QStringLiteral("cpp"));
|
|
|
|
QFile file(fileName);
|
|
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|
|
|
return;
|
|
|
|
QTextStream stream(&file);
|
|
|
|
|
|
|
|
// Write the preamble
|
|
|
|
const QString templateFileName = QString(QStringLiteral("%1__VERSION__.cpp"))
|
|
|
|
.arg(baseFileName);
|
|
|
|
QString profileSuffix;
|
|
|
|
if (versionProfile.hasProfiles())
|
|
|
|
profileSuffix = (versionProfile.profile == VersionProfile::CoreProfile ? QStringLiteral("_core") : QStringLiteral("_compatibility"));
|
|
|
|
|
|
|
|
const QString versionProfileString = QString(QStringLiteral("_%1_%2%3"))
|
|
|
|
.arg(versionProfile.version.major)
|
|
|
|
.arg(versionProfile.version.minor)
|
|
|
|
.arg(profileSuffix);
|
|
|
|
writePreamble(templateFileName, stream, versionProfileString);
|
|
|
|
|
|
|
|
const QString className = generateClassName(versionProfile, Public);
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("/*!") << Qt::endl
|
|
|
|
<< QStringLiteral(" \\class ") << className << Qt::endl
|
|
|
|
<< QStringLiteral(" \\inmodule QtGui") << Qt::endl
|
|
|
|
<< QStringLiteral(" \\since 5.1") << Qt::endl
|
|
|
|
<< QStringLiteral(" \\wrapper") << Qt::endl
|
2012-08-08 15:43:48 +00:00
|
|
|
<< QStringLiteral(" \\brief The ") << className
|
2013-09-03 12:38:45 +00:00
|
|
|
<< QString(QStringLiteral(" class provides all functions for OpenGL %1.%2 "))
|
|
|
|
.arg(versionProfile.version.major)
|
|
|
|
.arg(versionProfile.version.minor);
|
|
|
|
|
|
|
|
if (!profileSuffix.isEmpty()) {
|
|
|
|
profileSuffix.remove(0, 1);
|
|
|
|
profileSuffix.append(QStringLiteral(" profile"));
|
|
|
|
} else {
|
|
|
|
profileSuffix = "specification";
|
|
|
|
}
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << profileSuffix << QStringLiteral(".") << Qt::endl << Qt::endl
|
2013-09-03 12:38:45 +00:00
|
|
|
<< QStringLiteral(" This class is a wrapper for functions from ")
|
|
|
|
<< QString(QStringLiteral("OpenGL %1.%2 "))
|
|
|
|
.arg(versionProfile.version.major)
|
|
|
|
.arg(versionProfile.version.minor)
|
2020-01-28 14:50:13 +00:00
|
|
|
<< profileSuffix << QStringLiteral(".") << Qt::endl
|
|
|
|
<< QStringLiteral(" See reference pages on \\l {http://www.opengl.org/sdk/docs/}{opengl.org}") << Qt::endl
|
|
|
|
<< QStringLiteral(" for function documentation.") << Qt::endl << Qt::endl
|
|
|
|
<< QStringLiteral(" \\sa QAbstractOpenGLFunctions") << Qt::endl
|
|
|
|
<< QStringLiteral("*/") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Get the data we'll need for this class implementation
|
|
|
|
FunctionCollection functionSet = functionCollection(versionProfile);
|
|
|
|
QList<VersionProfile> backends = backendsForFunctionCollection(functionSet);
|
|
|
|
|
|
|
|
// Output default constructor
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << className << QStringLiteral("::") << className << QStringLiteral("()") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
stream << QStringLiteral(" : ") << baseClass << QStringLiteral("()");
|
|
|
|
Q_FOREACH (const VersionProfile &v, backends)
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << Qt::endl << QString(QStringLiteral(" , %1(0)")).arg(backendVariableName(v));
|
|
|
|
stream << Qt::endl << QStringLiteral("{") << Qt::endl << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output the destructor
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << className << QStringLiteral("::~") << className << QStringLiteral("()") << Qt::endl;
|
|
|
|
stream << QStringLiteral("{") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
Q_FOREACH (const VersionProfile &v, backends) {
|
|
|
|
const QString backendVar = backendVariableName(v);
|
|
|
|
const QString backendClass = backendClassName(v);
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral(" if (%1 && !%1->refs.deref()) {")).arg(backendVar) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
stream << QString(QStringLiteral(" QAbstractOpenGLFunctionsPrivate::removeFunctionsBackend(%1->context, %2::versionStatus());"))
|
|
|
|
.arg(backendVar)
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(backendClass) << Qt::endl;
|
|
|
|
stream << QString(QStringLiteral(" delete %1;")).arg(backendVar) << Qt::endl;
|
|
|
|
stream << QStringLiteral(" }") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output the initialize function that creates the backend objects
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral("bool %1::initializeOpenGLFunctions()")).arg(className) << Qt::endl;
|
|
|
|
stream << QStringLiteral("{") << Qt::endl;
|
|
|
|
|
|
|
|
stream << QStringLiteral(" if ( isInitialized() )") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" return true;") << Qt::endl << Qt::endl;
|
|
|
|
stream << QStringLiteral(" QOpenGLContext* context = QOpenGLContext::currentContext();") << Qt::endl << Qt::endl;
|
|
|
|
stream << QStringLiteral(" // If owned by a context object make sure it is current.") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" // Also check that current context is capable of resolving all needed functions") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" if (((owningContext() && owningContext() == context) || !owningContext())") << Qt::endl;
|
|
|
|
stream << QString(QStringLiteral(" && %1::isContextCompatible(context))")).arg(className) << Qt::endl;
|
|
|
|
stream << QStringLiteral(" {") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" // Associate with private implementation, creating if necessary") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" // Function pointers in the backends are resolved at creation time") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" QOpenGLVersionFunctionsBackend* d = 0;") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
Q_FOREACH (const VersionProfile &v, backends) {
|
|
|
|
const QString backendClass = backendClassName(v);
|
|
|
|
const QString backendVar = backendVariableName(v);
|
|
|
|
stream << QString(QStringLiteral(" d = QAbstractOpenGLFunctionsPrivate::functionsBackend(context, %1::versionStatus());"))
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(backendClass) << Qt::endl;
|
|
|
|
stream << QStringLiteral(" if (!d) {") << Qt::endl;
|
|
|
|
stream << QString(QStringLiteral(" d = new %1(context);")).arg(backendClass) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
stream << QString(QStringLiteral(" QAbstractOpenGLFunctionsPrivate::insertFunctionsBackend(context, %1::versionStatus(), d);"))
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(backendClass) << Qt::endl;
|
|
|
|
stream << QStringLiteral(" }") << Qt::endl;
|
|
|
|
stream << QString(QStringLiteral(" %1 = static_cast<%2*>(d);")).arg(backendVar).arg(backendClass) << Qt::endl;
|
|
|
|
stream << QStringLiteral(" d->refs.ref();") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" QAbstractOpenGLFunctions::initializeOpenGLFunctions();") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" }") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" return isInitialized();") << Qt::endl;
|
|
|
|
stream << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output the context compatibility check function
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral("bool %1::isContextCompatible(QOpenGLContext *context)")).arg(className) << Qt::endl;
|
|
|
|
stream << QStringLiteral("{") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" Q_ASSERT(context);") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" QSurfaceFormat f = context->format();") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" const QPair<int, int> v = qMakePair(f.majorVersion(), f.minorVersion());") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
stream << QString(QStringLiteral(" if (v < qMakePair(%1, %2))"))
|
|
|
|
.arg(versionProfile.version.major)
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(versionProfile.version.minor) << Qt::endl;
|
|
|
|
stream << QStringLiteral(" return false;") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// If generating a legacy or compatibility profile class we need to ensure that
|
|
|
|
// the context does not expose only core functions
|
|
|
|
if (versionProfile.profile != VersionProfile::CoreProfile) {
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" if (f.profile() == QSurfaceFormat::CoreProfile)") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" return false;") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" return true;") << Qt::endl;
|
|
|
|
stream << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output static function used as helper in template versionFunctions() function
|
|
|
|
// in QOpenGLContext
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral("QOpenGLVersionProfile %1::versionProfile()")).arg(className) << Qt::endl;
|
|
|
|
stream << QStringLiteral("{") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" QOpenGLVersionProfile v;") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
stream << QString(QStringLiteral(" v.setVersion(%1, %2);"))
|
|
|
|
.arg(versionProfile.version.major)
|
2020-01-28 14:50:13 +00:00
|
|
|
.arg(versionProfile.version.minor) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
if (versionProfile.hasProfiles()) {
|
|
|
|
const QString profileName = versionProfile.profile == VersionProfile::CoreProfile
|
|
|
|
? QStringLiteral("QSurfaceFormat::CoreProfile")
|
|
|
|
: QStringLiteral("QSurfaceFormat::CompatibilityProfile");
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral(" v.setProfile(%1);")).arg(profileName) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" return v;") << Qt::endl;
|
|
|
|
stream << QStringLiteral("}") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Write the postamble
|
|
|
|
writePostamble(templateFileName, stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeClassFunctionDeclarations(QTextStream &stream,
|
|
|
|
const FunctionCollection &functionSet,
|
|
|
|
ClassVisibility visibility) const
|
|
|
|
{
|
|
|
|
Q_FOREACH (const VersionProfile &version, functionSet.keys()) {
|
|
|
|
// Add a comment to the header
|
|
|
|
stream << QString(QStringLiteral(" // OpenGL %1.%2 %3 functions"))
|
|
|
|
.arg(version.version.major)
|
|
|
|
.arg(version.version.minor)
|
|
|
|
.arg((version.profile == VersionProfile::CoreProfile) ? QStringLiteral("core") : QStringLiteral("deprecated"))
|
2020-01-28 14:50:13 +00:00
|
|
|
<< Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output function declarations
|
|
|
|
FunctionList functions = functionSet.value(version);
|
|
|
|
Q_FOREACH (const Function &f, functions)
|
|
|
|
writeFunctionDeclaration(stream, f, visibility);
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
} // version and profile
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeFunctionDeclaration(QTextStream &stream, const Function &f, ClassVisibility visibility) const
|
|
|
|
{
|
|
|
|
QStringList argList;
|
|
|
|
Q_FOREACH (const Argument &arg, f.arguments) {
|
|
|
|
QString a = QString(QStringLiteral("%1%2 %3%4"))
|
|
|
|
.arg((arg.direction == Argument::In && arg.mode != Argument::Value) ? QStringLiteral("const ") : QString())
|
|
|
|
.arg(arg.type)
|
|
|
|
.arg(passByType(arg))
|
|
|
|
.arg(safeArgumentName(arg.name));
|
|
|
|
argList.append(a);
|
|
|
|
}
|
|
|
|
QString args = argList.join(QStringLiteral(", "));
|
|
|
|
|
|
|
|
QString signature;
|
|
|
|
switch (visibility) {
|
|
|
|
case Public:
|
|
|
|
signature = QString(QStringLiteral(" %1 gl%2(%3);")).arg(f.returnType).arg(f.name).arg(args);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Private:
|
|
|
|
default:
|
|
|
|
signature = QString(QStringLiteral(" %1 (QOPENGLF_APIENTRYP %2)(%3);")).arg(f.returnType).arg(f.name).arg(args);
|
|
|
|
}
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << signature << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeClassInlineFunctions(QTextStream &stream,
|
|
|
|
const QString &className,
|
|
|
|
const FunctionCollection &functionSet) const
|
|
|
|
{
|
|
|
|
Q_FOREACH (const VersionProfile &version, functionSet.keys()) {
|
|
|
|
|
|
|
|
// Add a comment to the header
|
|
|
|
stream << QString(QStringLiteral("// OpenGL %1.%2 %3 functions"))
|
|
|
|
.arg(version.version.major)
|
|
|
|
.arg(version.version.minor)
|
|
|
|
.arg((version.profile == VersionProfile::CoreProfile) ? QStringLiteral("core") : QStringLiteral("deprecated"))
|
2020-01-28 14:50:13 +00:00
|
|
|
<< Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output function declarations
|
|
|
|
const QString backendVar = backendVariableName(version);
|
|
|
|
FunctionList functions = functionSet.value(version);
|
|
|
|
Q_FOREACH (const Function &f, functions)
|
|
|
|
writeInlineFunction(stream, className, backendVar, f);
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
} // version and profile
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeInlineFunction(QTextStream &stream, const QString &className,
|
|
|
|
const QString &backendVar, const Function &f) const
|
|
|
|
{
|
|
|
|
QStringList argList;
|
|
|
|
Q_FOREACH (const Argument &arg, f.arguments) {
|
|
|
|
QString a = QString(QStringLiteral("%1%2 %3%4"))
|
|
|
|
.arg((arg.direction == Argument::In && arg.mode != Argument::Value) ? QStringLiteral("const ") : QString())
|
|
|
|
.arg(arg.type)
|
|
|
|
.arg(passByType(arg))
|
|
|
|
.arg(safeArgumentName(arg.name));
|
|
|
|
argList.append(a);
|
|
|
|
}
|
|
|
|
QString args = argList.join(", ");
|
|
|
|
|
|
|
|
|
|
|
|
QString signature = QString(QStringLiteral("inline %1 %2::gl%3(%4)"))
|
|
|
|
.arg(f.returnType)
|
|
|
|
.arg(className)
|
|
|
|
.arg(f.name)
|
|
|
|
.arg(args);
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << signature << Qt::endl << QStringLiteral("{") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
QStringList argumentNames;
|
|
|
|
Q_FOREACH (const Argument &arg, f.arguments)
|
|
|
|
argumentNames.append(safeArgumentName(arg.name));
|
|
|
|
QString argNames = argumentNames.join(", ");
|
|
|
|
|
Don't use QStringLiteral in comparisons
For QLatin1String, operator== is overloaded, so comparing to a latin-1
(C) string literal is efficient, since strlen() is comparatively fast.
OTOH, QStringLiteral, when not using RVO, litters the code with
QString dtor calls, which are not inline. Worse, absent lambdas,
it even allocates memory.
So, just compare using QLatin1String instead.
Change-Id: I761b2b26ab5b416bc695f524a9ee607dacf0a7b2
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
2016-01-19 08:49:37 +00:00
|
|
|
if (f.returnType == QLatin1String("void"))
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral(" %1->%2(%3);")).arg(backendVar).arg(f.name).arg(argNames) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
else
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral(" return %1->%2(%3);")).arg(backendVar).arg(f.name).arg(argNames) << Qt::endl;
|
|
|
|
stream << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeEntryPointResolutionCode(QTextStream &stream,
|
|
|
|
const FunctionCollection &functionSet) const
|
|
|
|
{
|
|
|
|
bool hasModuleHandle = false;
|
|
|
|
Q_FOREACH (const VersionProfile &version, functionSet.keys()) {
|
|
|
|
|
|
|
|
// Add a comment to the header
|
|
|
|
stream << QString(QStringLiteral(" // OpenGL %1.%2 %3 functions"))
|
|
|
|
.arg(version.version.major)
|
|
|
|
.arg(version.version.minor)
|
|
|
|
.arg((version.profile == VersionProfile::CoreProfile) ? QStringLiteral("core") : QStringLiteral("deprecated"))
|
2020-01-28 14:50:13 +00:00
|
|
|
<< Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output function declarations
|
|
|
|
FunctionList functions = functionSet.value(version);
|
|
|
|
|
|
|
|
bool useGetProcAddress = (version.version.major == 1 && (version.version.minor == 0 || version.version.minor == 1));
|
|
|
|
if (useGetProcAddress) {
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << "#if defined(Q_OS_WIN)" << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
if (!hasModuleHandle) {
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << " HMODULE handle = GetModuleHandleA(\"opengl32.dll\");" << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
hasModuleHandle = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_FOREACH (const Function &f, functions)
|
|
|
|
writeEntryPointResolutionStatement(stream, f, QString(), useGetProcAddress);
|
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << "#else" << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Q_FOREACH (const Function &f, functions)
|
|
|
|
writeEntryPointResolutionStatement(stream, f);
|
|
|
|
|
|
|
|
if (useGetProcAddress)
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << "#endif" << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
} // version and profile
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeEntryPointResolutionStatement(QTextStream &stream, const Function &f,
|
|
|
|
const QString &prefix, bool useGetProcAddress) const
|
|
|
|
{
|
|
|
|
QStringList argList;
|
|
|
|
Q_FOREACH (const Argument &arg, f.arguments) {
|
|
|
|
QString a = QString("%1%2 %3")
|
|
|
|
.arg((arg.direction == Argument::In && arg.mode != Argument::Value) ? QStringLiteral("const ") : QString())
|
|
|
|
.arg(arg.type)
|
|
|
|
.arg(passByType(arg));
|
|
|
|
argList.append(a);
|
|
|
|
}
|
|
|
|
QString args = argList.join(QStringLiteral(", "));
|
|
|
|
|
|
|
|
QString signature;
|
|
|
|
if (!useGetProcAddress) {
|
|
|
|
signature = QString(QStringLiteral(" %4%3 = reinterpret_cast<%1 (QOPENGLF_APIENTRYP)(%2)>(context->getProcAddress(\"gl%3\"));"))
|
|
|
|
.arg(f.returnType)
|
|
|
|
.arg(args)
|
|
|
|
.arg(f.name)
|
|
|
|
.arg(prefix);
|
|
|
|
} else {
|
|
|
|
signature = QString(QStringLiteral(" %4%3 = reinterpret_cast<%1 (QOPENGLF_APIENTRYP)(%2)>(GetProcAddress(handle, \"gl%3\"));"))
|
|
|
|
.arg(f.returnType)
|
|
|
|
.arg(args)
|
|
|
|
.arg(f.name)
|
|
|
|
.arg(prefix);
|
|
|
|
}
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << signature << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QList<VersionProfile> CodeGenerator::backendsForFunctionCollection(const FunctionCollection &functionSet) const
|
|
|
|
{
|
|
|
|
QList<VersionProfile> backends;
|
|
|
|
Q_FOREACH (const VersionProfile &versionProfile, functionSet.keys()) {
|
|
|
|
if (m_parser->versionProfiles().contains(versionProfile))
|
|
|
|
backends.append(versionProfile);
|
|
|
|
}
|
|
|
|
return backends;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString CodeGenerator::backendClassName(const VersionProfile &v) const
|
|
|
|
{
|
|
|
|
QString statusSuffix = v.profile == VersionProfile::CoreProfile
|
|
|
|
? QStringLiteral("_Core")
|
|
|
|
: QStringLiteral("_Deprecated");
|
|
|
|
const QString className = QString(QStringLiteral("QOpenGLFunctions_%1_%2%3Backend"))
|
|
|
|
.arg(v.version.major)
|
|
|
|
.arg(v.version.minor)
|
|
|
|
.arg(statusSuffix);
|
|
|
|
return className;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString CodeGenerator::backendVariableName(const VersionProfile &v) const
|
|
|
|
{
|
|
|
|
const QString status = (v.profile == VersionProfile::CoreProfile)
|
|
|
|
? QStringLiteral("Core")
|
|
|
|
: QStringLiteral("Deprecated");
|
|
|
|
const QString varName = QString(QStringLiteral("d_%1_%2_%3"))
|
|
|
|
.arg(v.version.major)
|
|
|
|
.arg(v.version.minor)
|
|
|
|
.arg(status);
|
|
|
|
return varName;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeBackendVariableDeclarations(QTextStream &stream, const QList<VersionProfile> &backends) const
|
|
|
|
{
|
|
|
|
// We need a private class for each version and profile (status: core or deprecated)
|
|
|
|
Q_FOREACH (const VersionProfile &v, backends) {
|
|
|
|
const QString className = backendClassName(v);
|
|
|
|
const QString varName = backendVariableName(v);
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral(" %1* %2;")).arg(className).arg(varName) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeExtensionHeader(const QString &fileName) const
|
|
|
|
{
|
|
|
|
if (!m_parser)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QFile file(fileName);
|
|
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|
|
|
return;
|
|
|
|
QTextStream stream(&file);
|
|
|
|
|
|
|
|
// Write the preamble
|
|
|
|
writePreamble(fileName, stream);
|
|
|
|
|
|
|
|
// Iterate through the list of extensions and create one class per extension
|
|
|
|
QStringList extensions = m_parser->extensions();
|
|
|
|
Q_FOREACH (const QString &extension, extensions) {
|
|
|
|
writeExtensionClassDeclaration(stream, extension, Private);
|
|
|
|
writeExtensionClassDeclaration(stream, extension, Public);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the postamble
|
|
|
|
writePostamble(fileName, stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeExtensionImplementation(const QString &fileName) const
|
|
|
|
{
|
|
|
|
if (!m_parser)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QFile file(fileName);
|
|
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|
|
|
return;
|
|
|
|
QTextStream stream(&file);
|
|
|
|
|
|
|
|
// Write the preamble
|
|
|
|
writePreamble(fileName, stream);
|
|
|
|
|
|
|
|
// Iterate through the list of extensions and create one class per extension
|
|
|
|
QStringList extensions = m_parser->extensions();
|
|
|
|
Q_FOREACH (const QString &extension, extensions)
|
|
|
|
writeExtensionClassImplementation(stream, extension);
|
|
|
|
|
|
|
|
// Write the postamble
|
|
|
|
writePostamble(fileName, stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeExtensionClassDeclaration(QTextStream &stream, const QString &extension, ClassVisibility visibility) const
|
|
|
|
{
|
|
|
|
const QString className = generateExtensionClassName(extension, visibility);
|
|
|
|
|
|
|
|
QString baseClass = (visibility == Public) ? QStringLiteral("QAbstractOpenGLExtension") : QStringLiteral("QAbstractOpenGLExtensionPrivate");
|
|
|
|
|
|
|
|
stream << QString(QStringLiteral("class %2 : public %3"))
|
|
|
|
.arg(className)
|
|
|
|
.arg(baseClass)
|
2020-01-28 14:50:13 +00:00
|
|
|
<< Qt::endl << "{" << Qt::endl << "public:" << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
if (visibility == Public) {
|
|
|
|
// Default constructor
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" ") << className << QStringLiteral("();") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Base class virtual function(s)
|
2017-09-21 15:01:03 +00:00
|
|
|
QString resolveFunction = QStringLiteral(" bool initializeOpenGLFunctions() final;");
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << resolveFunction << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Output the functions provided by this extension
|
|
|
|
QList<Function> functions = m_parser->functionsForExtension(extension);
|
|
|
|
Q_FOREACH (const Function &f, functions)
|
|
|
|
writeFunctionDeclaration(stream, f, visibility);
|
|
|
|
|
|
|
|
if (visibility == Public) {
|
|
|
|
// Write out the protected ctor
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << Qt::endl << QStringLiteral("protected:") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" Q_DECLARE_PRIVATE(") << className << QStringLiteral(")") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// End the class declaration
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral("};") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output the inline functions for public class
|
|
|
|
if (visibility == Public) {
|
|
|
|
Q_FOREACH (const Function &f, functions)
|
|
|
|
writeExtensionInlineFunction(stream, className, f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeExtensionInlineFunction(QTextStream &stream, const QString &className, const Function &f) const
|
|
|
|
{
|
|
|
|
QStringList argList;
|
|
|
|
Q_FOREACH (const Argument &arg, f.arguments) {
|
|
|
|
QString a = QString(QStringLiteral("%1%2 %3%4"))
|
|
|
|
.arg((arg.direction == Argument::In && arg.mode != Argument::Value) ? QStringLiteral("const ") : QString())
|
|
|
|
.arg(arg.type)
|
|
|
|
.arg(passByType(arg))
|
|
|
|
.arg(safeArgumentName(arg.name));
|
|
|
|
argList.append(a);
|
|
|
|
}
|
|
|
|
QString args = argList.join(", ");
|
|
|
|
|
|
|
|
|
|
|
|
QString signature = QString(QStringLiteral("inline %1 %2::gl%3(%4)"))
|
|
|
|
.arg(f.returnType)
|
|
|
|
.arg(className)
|
|
|
|
.arg(f.name)
|
|
|
|
.arg(args);
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << signature << Qt::endl << QStringLiteral("{") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral(" Q_D(%1);")).arg(className) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
QStringList argumentNames;
|
|
|
|
Q_FOREACH (const Argument &arg, f.arguments)
|
|
|
|
argumentNames.append(safeArgumentName(arg.name));
|
|
|
|
QString argNames = argumentNames.join(", ");
|
|
|
|
|
|
|
|
if (f.returnType == QStringLiteral("void"))
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral(" d->%1(%2);")).arg(f.name).arg(argNames) << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
else
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QString(QStringLiteral(" return d->%1(%2);")).arg(f.name).arg(argNames) << Qt::endl;
|
|
|
|
stream << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CodeGenerator::writeExtensionClassImplementation(QTextStream &stream, const QString &extension) const
|
|
|
|
{
|
|
|
|
const QString className = generateExtensionClassName(extension);
|
|
|
|
const QString privateClassName = generateExtensionClassName(extension, Private);
|
|
|
|
|
|
|
|
// Output default constructor
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << className << QStringLiteral("::") << className << QStringLiteral("()") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" : QAbstractOpenGLExtension(*(new ") << privateClassName << QStringLiteral("))") << Qt::endl;
|
|
|
|
stream << QStringLiteral("{") << Qt::endl << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Output function to initialize this class
|
|
|
|
stream << QStringLiteral("bool ") << className
|
2020-01-28 14:50:13 +00:00
|
|
|
<< QStringLiteral("::initializeOpenGLFunctions()") << Qt::endl
|
|
|
|
<< QStringLiteral("{") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" if (isInitialized())") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" return true;") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" QOpenGLContext *context = QOpenGLContext::currentContext();") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" if (!context) {") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
stream << QStringLiteral(" qWarning(\"A current OpenGL context is required to resolve OpenGL extension functions\");")
|
2020-01-28 14:50:13 +00:00
|
|
|
<< Qt::endl;
|
|
|
|
stream << QStringLiteral(" return false;") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" }") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output code to resolve entry points for this class
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" // Resolve the functions") << Qt::endl;
|
|
|
|
stream << QStringLiteral(" Q_D(") << className << QStringLiteral(");") << Qt::endl;
|
|
|
|
stream << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Output function declarations
|
|
|
|
QList<Function> functions = m_parser->functionsForExtension(extension);
|
|
|
|
Q_FOREACH (const Function &f, functions)
|
|
|
|
writeEntryPointResolutionStatement(stream, f, QStringLiteral("d->"));
|
|
|
|
|
|
|
|
// Call the base class implementation
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" QAbstractOpenGLExtension::initializeOpenGLFunctions();") << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
|
|
|
|
// Finish off
|
2020-01-28 14:50:13 +00:00
|
|
|
stream << QStringLiteral(" return true;") << Qt::endl;
|
|
|
|
stream << QStringLiteral("}") << Qt::endl << Qt::endl;
|
2012-08-08 15:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString CodeGenerator::generateExtensionClassName(const QString &extension, ClassVisibility visibility) const
|
|
|
|
{
|
|
|
|
QString visibilitySuffix;
|
|
|
|
if (visibility == Private)
|
|
|
|
visibilitySuffix = QStringLiteral("Private");
|
|
|
|
|
|
|
|
return QString(QStringLiteral("QOpenGLExtension_%1%2"))
|
|
|
|
.arg(extension)
|
|
|
|
.arg(visibilitySuffix);
|
|
|
|
}
|