1 /***************************************************************************
2 **
3 ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the utilities of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28
29 #include "codegenerator.h"
30
31 #include <QDebug>
32 #include <QFile>
33 #include <QSettings>
34 #include <QTextStream>
35
36 static const QString extensionRegistryFileName = QStringLiteral("qopengl-extension-registry.ini");
37 static const QString extensionIdGroupName = QStringLiteral("ExtensionIds");
38
CodeGenerator()39 CodeGenerator::CodeGenerator()
40 : m_parser(0)
41 {
42 }
43
generateCoreClasses(const QString & baseFileName) const44 void CodeGenerator::generateCoreClasses(const QString &baseFileName) const
45 {
46 // Output header and implementation files for the backend and base class
47 writeCoreHelperClasses(baseFileName + QStringLiteral(".h"), Declaration);
48 writeCoreHelperClasses(baseFileName + QStringLiteral(".cpp"), Definition);
49
50 // Output the per-version and profile public classes
51 writeCoreClasses(baseFileName);
52
53 // We also need to generate a factory class that can be used by
54 // QOpenGLContext to actually create version function objects
55 writeCoreFactoryHeader(baseFileName + QStringLiteral("factory_p.h"));
56 writeCoreFactoryImplementation(baseFileName + QStringLiteral("factory.cpp"));
57 }
58
generateExtensionClasses(const QString & baseFileName) const59 void CodeGenerator::generateExtensionClasses(const QString &baseFileName) const
60 {
61 writeExtensionHeader(baseFileName + QStringLiteral(".h"));
62 writeExtensionImplementation(baseFileName + QStringLiteral(".cpp"));
63 }
64
isLegacyVersion(Version v) const65 bool CodeGenerator::isLegacyVersion(Version v) const
66 {
67 return (v.major < 3 || (v.major == 3 && v.minor == 0));
68 }
69
versionHasProfiles(Version v) const70 bool CodeGenerator::versionHasProfiles(Version v) const
71 {
72 VersionProfile vp;
73 vp.version = v;
74 return vp.hasProfiles();
75 }
76
writeCoreHelperClasses(const QString & fileName,ClassComponent component) const77 void CodeGenerator::writeCoreHelperClasses(const QString &fileName, ClassComponent component) const
78 {
79 if (!m_parser)
80 return;
81
82 QFile file(fileName);
83 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
84 return;
85 QTextStream stream(&file);
86
87 // Write the preamble
88 writePreamble(fileName, stream);
89
90 // Iterate over each OpenGL version. For each version output a private class for
91 // core functions and a private class for deprecated functions.
92 const QString privateRootClass = QStringLiteral("QOpenGLVersionFunctionsBackend");
93 Q_FOREACH (const VersionProfile &versionProfile, m_parser->versionProfiles()) {
94 switch (component) {
95 case Declaration:
96 writeBackendClassDeclaration(stream, versionProfile, privateRootClass);
97 break;
98
99 case Definition:
100 writeBackendClassImplementation(stream, versionProfile, privateRootClass);
101 break;
102 }
103 }
104
105 // Write the postamble
106 writePostamble(fileName, stream);
107 }
108
writeCoreClasses(const QString & baseFileName) const109 void CodeGenerator::writeCoreClasses(const QString &baseFileName) const
110 {
111 // Iterate over each OpenGL version. For each version output a public class (for legacy
112 // versions or two public classes (for modern versions with profiles). Each public class
113 // is given pointers to private classes containing the actual entry points. For example,
114 // the class for OpenGL 1.1 will have pointers to the private classes for 1.0 core, 1.1
115 // core, 1.0 deprecated and 1.1 deprecated. Whereas the class for OpenGL 3.2 Core profile
116 // will have pointers to the private classes for 1.0 core, 1.1 core, ..., 3.2 core but
117 // not to any of the deprecated private classes
118 QList<ClassComponent> components = (QList<ClassComponent>() << Declaration << Definition);
119 Q_FOREACH (const ClassComponent &component, components) {
120 const QString rootClass = QStringLiteral("QAbstractOpenGLFunctions");
121 Q_FOREACH (const Version &classVersion, m_parser->versions()) {
122 VersionProfile v;
123 v.version = classVersion;
124 v.profile = VersionProfile::CompatibilityProfile;
125
126 if (isLegacyVersion(classVersion)) {
127 switch (component) {
128 case Declaration:
129 writePublicClassDeclaration(baseFileName, v, rootClass);
130 break;
131
132 case Definition:
133 writePublicClassImplementation(baseFileName, v, rootClass);
134 break;
135 }
136 } else {
137 switch (component) {
138 case Declaration:
139 writePublicClassDeclaration(baseFileName, v, rootClass);
140 v.profile = VersionProfile::CoreProfile;
141 writePublicClassDeclaration(baseFileName, v, rootClass);
142 break;
143
144 case Definition:
145 writePublicClassImplementation(baseFileName, v, rootClass);
146 v.profile = VersionProfile::CoreProfile;
147 writePublicClassImplementation(baseFileName, v, rootClass);
148 break;
149 }
150 }
151 }
152 }
153 }
154
writeCoreFactoryHeader(const QString & fileName) const155 void CodeGenerator::writeCoreFactoryHeader(const QString &fileName) const
156 {
157 if (!m_parser)
158 return;
159
160 QFile file(fileName);
161 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
162 return;
163 QTextStream stream(&file);
164
165 // Write the preamble
166 writePreamble(fileName, stream);
167
168 // Write the postamble
169 writePostamble(fileName, stream);
170 }
171
writeCoreFactoryImplementation(const QString & fileName) const172 void CodeGenerator::writeCoreFactoryImplementation(const QString &fileName) const
173 {
174 if (!m_parser)
175 return;
176
177 QFile file(fileName);
178 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
179 return;
180 QTextStream stream(&file);
181
182 // Write the preamble
183 writePreamble(fileName, stream);
184
185 // Get the set of version functions classes we need to create
186 QList<Version> versions = m_parser->versions();
187 std::sort(versions.begin(), versions.end(), std::greater<Version>());
188
189 // Outout the #include statements
190 stream << QStringLiteral("#if !defined(QT_OPENGL_ES_2)") << endl;
191 Q_FOREACH (const Version &classVersion, versions) {
192 if (!versionHasProfiles(classVersion)) {
193 stream << QString(QStringLiteral("#include \"qopenglfunctions_%1_%2.h\""))
194 .arg(classVersion.major)
195 .arg(classVersion.minor) << endl;
196 } else {
197 const QList<VersionProfile::OpenGLProfile> profiles = (QList<VersionProfile::OpenGLProfile>()
198 << VersionProfile::CoreProfile << VersionProfile::CompatibilityProfile);
199
200 Q_FOREACH (const VersionProfile::OpenGLProfile profile, profiles) {
201 const QString profileSuffix = profile == VersionProfile::CoreProfile
202 ? QStringLiteral("core")
203 : QStringLiteral("compatibility");
204 stream << QString(QStringLiteral("#include \"qopenglfunctions_%1_%2_%3.h\""))
205 .arg(classVersion.major)
206 .arg(classVersion.minor)
207 .arg(profileSuffix) << endl;
208 }
209 }
210 }
211 stream << QStringLiteral("#else") << endl;
212 stream << QStringLiteral("#include \"qopenglfunctions_es2.h\"") << endl;
213 stream << QStringLiteral("#endif") << endl;
214
215 stream << endl;
216
217 stream << QStringLiteral("QT_BEGIN_NAMESPACE") << endl << endl;
218 stream << QStringLiteral("QAbstractOpenGLFunctions *QOpenGLVersionFunctionsFactory::create(const QOpenGLVersionProfile &versionProfile)") << endl;
219 stream << QStringLiteral("{") << endl;
220 stream << QStringLiteral("#if !defined(QT_OPENGL_ES_2)") << endl;
221 stream << QStringLiteral(" const int major = versionProfile.version().first;") << endl;
222 stream << QStringLiteral(" const int minor = versionProfile.version().second;") << endl << endl;
223
224 // Iterate over classes with profiles
225 stream << QStringLiteral(" if (versionProfile.hasProfiles()) {") << endl;
226 stream << QStringLiteral(" switch (versionProfile.profile()) {") << endl;
227 const QList<VersionProfile::OpenGLProfile> profiles = (QList<VersionProfile::OpenGLProfile>()
228 << VersionProfile::CoreProfile << VersionProfile::CompatibilityProfile);
229 Q_FOREACH (const VersionProfile::OpenGLProfile profile, profiles) {
230 const QString caseLabel = profile == VersionProfile::CoreProfile
231 ? QStringLiteral("QSurfaceFormat::CoreProfile")
232 : QStringLiteral("QSurfaceFormat::CompatibilityProfile");
233 stream << QString(QStringLiteral(" case %1:")).arg(caseLabel) << endl;
234
235 int i = 0;
236 Q_FOREACH (const Version &classVersion, versions) {
237 if (!versionHasProfiles(classVersion))
238 continue;
239
240 const QString ifString = (i++ == 0) ? QStringLiteral("if") : QStringLiteral("else if");
241 stream << QString(QStringLiteral(" %1 (major == %2 && minor == %3)"))
242 .arg(ifString)
243 .arg(classVersion.major)
244 .arg(classVersion.minor) << endl;
245
246 VersionProfile v;
247 v.version = classVersion;
248 v.profile = profile;
249 stream << QString(QStringLiteral(" return new %1;"))
250 .arg(generateClassName(v)) << endl;
251 }
252
253 stream << QStringLiteral(" break;") << endl << endl;
254 }
255
256 stream << QStringLiteral(" case QSurfaceFormat::NoProfile:") << endl;
257 stream << QStringLiteral(" default:") << endl;
258 stream << QStringLiteral(" break;") << endl;
259 stream << QStringLiteral(" };") << endl;
260 stream << QStringLiteral(" } else {") << endl;
261
262 // Iterate over the legacy classes (no profiles)
263 int i = 0;
264 Q_FOREACH (const Version &classVersion, versions) {
265 if (versionHasProfiles(classVersion))
266 continue;
267
268 const QString ifString = (i++ == 0) ? QStringLiteral("if") : QStringLiteral("else if");
269 stream << QString(QStringLiteral(" %1 (major == %2 && minor == %3)"))
270 .arg(ifString)
271 .arg(classVersion.major)
272 .arg(classVersion.minor) << endl;
273
274 VersionProfile v;
275 v.version = classVersion;
276 stream << QString(QStringLiteral(" return new %1;"))
277 .arg(generateClassName(v)) << endl;
278 }
279
280 stream << QStringLiteral(" }") << endl;
281 stream << QStringLiteral(" return 0;") << endl;
282
283 stream << QStringLiteral("#else") << endl;
284 stream << QStringLiteral(" Q_UNUSED(versionProfile);") << endl;
285 stream << QStringLiteral(" return new QOpenGLFunctions_ES2;") << endl;
286 stream << QStringLiteral("#endif") << endl;
287 stream << QStringLiteral("}") << endl;
288
289 // Write the postamble
290 writePostamble(fileName, stream);
291 }
292
293 /**
294 \returns all functions to be included in the class defined by \a classVersionProfile
295 */
functionCollection(const VersionProfile & classVersionProfile) const296 FunctionCollection CodeGenerator::functionCollection( const VersionProfile& classVersionProfile ) const
297 {
298 const Version classVersion = classVersionProfile.version;
299 FunctionCollection functionSet;
300 QList<Version> versions = m_parser->versions();
301
302 // Populate these based upon the class version and profile
303 Version minVersion;
304 minVersion.major = 1;
305 minVersion.minor = 0;
306 Version maxVersion = classVersion;
307 QList<VersionProfile::OpenGLProfile> profiles;
308 profiles << VersionProfile::CoreProfile; // Always need core functions
309
310 if (isLegacyVersion(classVersion)
311 || (classVersionProfile.hasProfiles()
312 && classVersionProfile.profile == VersionProfile::CompatibilityProfile)) {
313 // For versions < 3.1 and Compatibility profile we include both core and deprecated functions
314 profiles << VersionProfile::CompatibilityProfile;
315 }
316
317 Q_FOREACH (const Version &v, versions) {
318 // Only include functions from versions in the range
319 if (v < minVersion)
320 continue;
321 if (v > maxVersion)
322 break;
323
324 Q_FOREACH (VersionProfile::OpenGLProfile profile, profiles) {
325 // Combine version and profile for this subset of functions
326 VersionProfile version;
327 version.version = v;
328 version.profile = profile;
329
330 // Fetch the functions and add to collection for this class
331 QList<Function> functions = m_parser->functionsForVersion(version);
332 functionSet.insert(version, functions);
333 }
334 }
335
336 return functionSet;
337 }
338
writePreamble(const QString & baseFileName,QTextStream & stream,const QString replacement) const339 void CodeGenerator::writePreamble(const QString &baseFileName, QTextStream &stream, const QString replacement) const
340 {
341 const QString fileName = baseFileName + QStringLiteral(".header");
342 if (!QFile::exists(fileName))
343 return;
344
345 QFile file(fileName);
346 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
347 QTextStream preambleStream(&file);
348 QString preamble = preambleStream.readAll();
349 if (!replacement.isEmpty())
350 preamble.replace(QStringLiteral("__VERSION__"), replacement, Qt::CaseSensitive);
351 stream << preamble;
352 }
353 }
354
writePostamble(const QString & baseFileName,QTextStream & stream) const355 void CodeGenerator::writePostamble(const QString &baseFileName, QTextStream &stream) const
356 {
357 const QString fileName = baseFileName + QStringLiteral(".footer");
358 if (!QFile::exists(fileName))
359 return;
360
361 QFile file(fileName);
362 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
363 QTextStream postambleStream(&file);
364 QString postamble = postambleStream.readAll();
365 stream << postamble;
366 }
367 }
368
passByType(const Argument & arg) const369 QString CodeGenerator::passByType(const Argument &arg) const
370 {
371 QString passBy;
372 switch (arg.mode) {
373 case Argument::Reference:
374 case Argument::Array:
375 passBy = QStringLiteral("*");
376 break;
377
378 default:
379 case Argument::Value:
380 passBy = QString();
381 }
382 return passBy;
383 }
384
safeArgumentName(const QString & arg) const385 QString CodeGenerator::safeArgumentName(const QString& arg) const
386 {
387 if (arg == QLatin1String("near")) // MS Windows defines near and far
388 return QStringLiteral("nearVal");
389 else if (arg == QLatin1String("far"))
390 return QStringLiteral("farVal");
391 else if (arg == QLatin1String("d"))
392 return QStringLiteral("dd"); // Don't shadow d pointer
393 else
394 return arg;
395 }
396
generateClassName(const VersionProfile & classVersion,ClassVisibility visibility) const397 QString CodeGenerator::generateClassName(const VersionProfile &classVersion, ClassVisibility visibility) const
398 {
399 QString className;
400 switch ( visibility ) {
401 case Public: {
402 // Class name and base class
403 QString profileSuffix;
404 if (classVersion.hasProfiles())
405 profileSuffix = (classVersion.profile == VersionProfile::CoreProfile ? QStringLiteral("_Core") : QStringLiteral("_Compatibility"));
406
407 className = QString(QStringLiteral("QOpenGLFunctions_%1_%2%3"))
408 .arg(classVersion.version.major)
409 .arg(classVersion.version.minor)
410 .arg(profileSuffix);
411 break;
412 }
413 case Private: {
414 QString statusSuffix = (classVersion.profile == VersionProfile::CoreProfile ? QStringLiteral("_Core") : QStringLiteral("_Deprecated"));
415
416 className = QString(QStringLiteral("QOpenGLFunctions_%1_%2%3Private"))
417 .arg(classVersion.version.major)
418 .arg(classVersion.version.minor)
419 .arg(statusSuffix);
420 break;
421 }
422 }
423
424 return className;
425 }
426
writeBackendClassDeclaration(QTextStream & stream,const VersionProfile & versionProfile,const QString & baseClass) const427 void CodeGenerator::writeBackendClassDeclaration(QTextStream &stream,
428 const VersionProfile &versionProfile,
429 const QString &baseClass) const
430 {
431 const QString className = backendClassName(versionProfile);
432 stream << QString(QStringLiteral("class %1 : public %2"))
433 .arg(className)
434 .arg(baseClass)
435 << endl;
436 stream << QStringLiteral("{") << endl;
437 stream << QStringLiteral("public:") << endl;
438 stream << QString( QStringLiteral(" %1(QOpenGLContext *context);") ).arg(className) << endl << endl;
439
440 // Output function used for generating key used in QOpenGLContextPrivate
441 stream << QStringLiteral(" static QOpenGLVersionStatus versionStatus();") << endl << endl;
442
443 // Get the functions needed for this class
444 FunctionList functions = m_parser->functionsForVersion(versionProfile);
445 FunctionCollection functionSet;
446 functionSet.insert(versionProfile, functions);
447
448 // Declare the functions
449 writeClassFunctionDeclarations(stream, functionSet, Private);
450
451 stream << QStringLiteral("};") << endl;
452 stream << endl;
453 }
454
writeBackendClassImplementation(QTextStream & stream,const VersionProfile & versionProfile,const QString & baseClass) const455 void CodeGenerator::writeBackendClassImplementation(QTextStream &stream,
456 const VersionProfile &versionProfile,
457 const QString &baseClass) const
458 {
459 const QString className = backendClassName(versionProfile);
460 stream << QString(QStringLiteral("%1::%1(QOpenGLContext *context)")).arg(className) << endl;
461 stream << QString(QStringLiteral(" : %1(context)")).arg(baseClass) << endl
462 << QStringLiteral("{") << endl;
463
464 // Resolve the entry points for this set of functions
465 // Get the functions needed for this class
466 FunctionList functions = m_parser->functionsForVersion(versionProfile);
467 FunctionCollection functionSet;
468 functionSet.insert(versionProfile, functions);
469 writeEntryPointResolutionCode(stream, functionSet);
470
471 stream << QStringLiteral("}") << endl << endl;
472
473 stream << QString(QStringLiteral("QOpenGLVersionStatus %1::versionStatus()")).arg(className) << endl;
474 stream << QStringLiteral("{") << endl;
475 const QString status = versionProfile.profile == VersionProfile::CoreProfile
476 ? QStringLiteral("QOpenGLVersionStatus::CoreStatus")
477 : QStringLiteral("QOpenGLVersionStatus::DeprecatedStatus");
478 stream << QString(QStringLiteral(" return QOpenGLVersionStatus(%1, %2, %3);"))
479 .arg(versionProfile.version.major)
480 .arg(versionProfile.version.minor)
481 .arg(status) << endl;
482 stream << QStringLiteral("}") << endl << endl;
483 }
484
coreClassFileName(const VersionProfile & versionProfile,const QString & fileExtension) const485 QString CodeGenerator::coreClassFileName(const VersionProfile &versionProfile,
486 const QString& fileExtension) const
487 {
488 QString profileSuffix;
489 if (versionProfile.hasProfiles())
490 profileSuffix = (versionProfile.profile == VersionProfile::CoreProfile ? QStringLiteral("_core") : QStringLiteral("_compatibility"));
491
492 const QString fileName = QString(QStringLiteral("qopenglfunctions_%1_%2%3.%4"))
493 .arg(versionProfile.version.major)
494 .arg(versionProfile.version.minor)
495 .arg(profileSuffix)
496 .arg(fileExtension);
497 return fileName;
498 }
499
writePublicClassDeclaration(const QString & baseFileName,const VersionProfile & versionProfile,const QString & baseClass) const500 void CodeGenerator::writePublicClassDeclaration(const QString &baseFileName,
501 const VersionProfile &versionProfile,
502 const QString &baseClass) const
503 {
504 const QString fileName = coreClassFileName(versionProfile, QStringLiteral("h"));
505 QFile file(fileName);
506 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
507 return;
508 QTextStream stream(&file);
509
510 // Write the preamble
511 const QString templateFileName = QString(QStringLiteral("%1__VERSION__.h"))
512 .arg(baseFileName);
513 QString profileSuffix;
514 if (versionProfile.hasProfiles())
515 profileSuffix = (versionProfile.profile == VersionProfile::CoreProfile ? QStringLiteral("_CORE") : QStringLiteral("_COMPATIBILITY"));
516
517 const QString versionProfileString = QString(QStringLiteral("_%1_%2%3"))
518 .arg(versionProfile.version.major)
519 .arg(versionProfile.version.minor)
520 .arg(profileSuffix);
521 writePreamble(templateFileName, stream, versionProfileString);
522
523 // Ctor, dtor, and initialize function;
524 const QString className = generateClassName(versionProfile, Public);
525 stream << QString(QStringLiteral("class Q_GUI_EXPORT %1 : public %2"))
526 .arg(className)
527 .arg(baseClass)
528 << endl;
529 stream << QStringLiteral("{") << endl;
530 stream << QStringLiteral("public:") << endl;
531 stream << QString(QStringLiteral(" %1();")).arg(className) << endl;
532 stream << QString(QStringLiteral(" ~%1();")).arg(className) << endl << endl;
533 stream << QStringLiteral(" bool initializeOpenGLFunctions() override;") << endl << endl;
534
535 // Get the functions needed for this class and declare them
536 FunctionCollection functionSet = functionCollection(versionProfile);
537 writeClassFunctionDeclarations(stream, functionSet, Public);
538
539 // isCompatible function and backend variables
540 stream << QStringLiteral("private:") << endl;
541 stream << QStringLiteral(" friend class QOpenGLContext;") << endl << endl;
542 stream << QStringLiteral(" static bool isContextCompatible(QOpenGLContext *context);") << endl;
543 stream << QStringLiteral(" static QOpenGLVersionProfile versionProfile();") << endl << endl;
544 writeBackendVariableDeclarations(stream, backendsForFunctionCollection(functionSet));
545
546 stream << QStringLiteral("};") << endl << endl;
547
548 // Output the inline functions that forward OpenGL calls to the backends' entry points
549 writeClassInlineFunctions(stream, className, functionSet);
550
551 // Write the postamble
552 writePostamble(templateFileName, stream);
553 }
554
writePublicClassImplementation(const QString & baseFileName,const VersionProfile & versionProfile,const QString & baseClass) const555 void CodeGenerator::writePublicClassImplementation(const QString &baseFileName,
556 const VersionProfile &versionProfile,
557 const QString& baseClass) const
558 {
559 const QString fileName = coreClassFileName(versionProfile, QStringLiteral("cpp"));
560 QFile file(fileName);
561 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
562 return;
563 QTextStream stream(&file);
564
565 // Write the preamble
566 const QString templateFileName = QString(QStringLiteral("%1__VERSION__.cpp"))
567 .arg(baseFileName);
568 QString profileSuffix;
569 if (versionProfile.hasProfiles())
570 profileSuffix = (versionProfile.profile == VersionProfile::CoreProfile ? QStringLiteral("_core") : QStringLiteral("_compatibility"));
571
572 const QString versionProfileString = QString(QStringLiteral("_%1_%2%3"))
573 .arg(versionProfile.version.major)
574 .arg(versionProfile.version.minor)
575 .arg(profileSuffix);
576 writePreamble(templateFileName, stream, versionProfileString);
577
578 const QString className = generateClassName(versionProfile, Public);
579 stream << QStringLiteral("/*!") << endl
580 << QStringLiteral(" \\class ") << className << endl
581 << QStringLiteral(" \\inmodule QtGui") << endl
582 << QStringLiteral(" \\since 5.1") << endl
583 << QStringLiteral(" \\wrapper") << endl
584 << QStringLiteral(" \\brief The ") << className
585 << QString(QStringLiteral(" class provides all functions for OpenGL %1.%2 "))
586 .arg(versionProfile.version.major)
587 .arg(versionProfile.version.minor);
588
589 if (!profileSuffix.isEmpty()) {
590 profileSuffix.remove(0, 1);
591 profileSuffix.append(QStringLiteral(" profile"));
592 } else {
593 profileSuffix = "specification";
594 }
595
596 stream << profileSuffix << QStringLiteral(".") << endl << endl
597 << QStringLiteral(" This class is a wrapper for functions from ")
598 << QString(QStringLiteral("OpenGL %1.%2 "))
599 .arg(versionProfile.version.major)
600 .arg(versionProfile.version.minor)
601 << profileSuffix << QStringLiteral(".") << endl
602 << QStringLiteral(" See reference pages on \\l {http://www.opengl.org/sdk/docs/}{opengl.org}") << endl
603 << QStringLiteral(" for function documentation.") << endl << endl
604 << QStringLiteral(" \\sa QAbstractOpenGLFunctions") << endl
605 << QStringLiteral("*/") << endl << endl;
606
607 // Get the data we'll need for this class implementation
608 FunctionCollection functionSet = functionCollection(versionProfile);
609 QList<VersionProfile> backends = backendsForFunctionCollection(functionSet);
610
611 // Output default constructor
612 stream << className << QStringLiteral("::") << className << QStringLiteral("()") << endl;
613 stream << QStringLiteral(" : ") << baseClass << QStringLiteral("()");
614 Q_FOREACH (const VersionProfile &v, backends)
615 stream << endl << QString(QStringLiteral(" , %1(0)")).arg(backendVariableName(v));
616 stream << endl << QStringLiteral("{") << endl << QStringLiteral("}") << endl << endl;
617
618 // Output the destructor
619 stream << className << QStringLiteral("::~") << className << QStringLiteral("()") << endl;
620 stream << QStringLiteral("{") << endl;
621 Q_FOREACH (const VersionProfile &v, backends) {
622 const QString backendVar = backendVariableName(v);
623 const QString backendClass = backendClassName(v);
624 stream << QString(QStringLiteral(" if (%1 && !%1->refs.deref()) {")).arg(backendVar) << endl;
625 stream << QString(QStringLiteral(" QAbstractOpenGLFunctionsPrivate::removeFunctionsBackend(%1->context, %2::versionStatus());"))
626 .arg(backendVar)
627 .arg(backendClass) << endl;
628 stream << QString(QStringLiteral(" delete %1;")).arg(backendVar) << endl;
629 stream << QStringLiteral(" }") << endl;
630 }
631 stream << QStringLiteral("}") << endl << endl;
632
633 // Output the initialize function that creates the backend objects
634 stream << QString(QStringLiteral("bool %1::initializeOpenGLFunctions()")).arg(className) << endl;
635 stream << QStringLiteral("{") << endl;
636
637 stream << QStringLiteral(" if ( isInitialized() )") << endl;
638 stream << QStringLiteral(" return true;") << endl << endl;
639 stream << QStringLiteral(" QOpenGLContext* context = QOpenGLContext::currentContext();") << endl << endl;
640 stream << QStringLiteral(" // If owned by a context object make sure it is current.") << endl;
641 stream << QStringLiteral(" // Also check that current context is capable of resolving all needed functions") << endl;
642 stream << QStringLiteral(" if (((owningContext() && owningContext() == context) || !owningContext())") << endl;
643 stream << QString(QStringLiteral(" && %1::isContextCompatible(context))")).arg(className) << endl;
644 stream << QStringLiteral(" {") << endl;
645 stream << QStringLiteral(" // Associate with private implementation, creating if necessary") << endl;
646 stream << QStringLiteral(" // Function pointers in the backends are resolved at creation time") << endl;
647 stream << QStringLiteral(" QOpenGLVersionFunctionsBackend* d = 0;") << endl;
648
649 Q_FOREACH (const VersionProfile &v, backends) {
650 const QString backendClass = backendClassName(v);
651 const QString backendVar = backendVariableName(v);
652 stream << QString(QStringLiteral(" d = QAbstractOpenGLFunctionsPrivate::functionsBackend(context, %1::versionStatus());"))
653 .arg(backendClass) << endl;
654 stream << QStringLiteral(" if (!d) {") << endl;
655 stream << QString(QStringLiteral(" d = new %1(context);")).arg(backendClass) << endl;
656 stream << QString(QStringLiteral(" QAbstractOpenGLFunctionsPrivate::insertFunctionsBackend(context, %1::versionStatus(), d);"))
657 .arg(backendClass) << endl;
658 stream << QStringLiteral(" }") << endl;
659 stream << QString(QStringLiteral(" %1 = static_cast<%2*>(d);")).arg(backendVar).arg(backendClass) << endl;
660 stream << QStringLiteral(" d->refs.ref();") << endl << endl;
661 }
662
663 stream << QStringLiteral(" QAbstractOpenGLFunctions::initializeOpenGLFunctions();") << endl;
664 stream << QStringLiteral(" }") << endl;
665
666 stream << QStringLiteral(" return isInitialized();") << endl;
667 stream << QStringLiteral("}") << endl << endl;
668
669 // Output the context compatibility check function
670 stream << QString(QStringLiteral("bool %1::isContextCompatible(QOpenGLContext *context)")).arg(className) << endl;
671 stream << QStringLiteral("{") << endl;
672 stream << QStringLiteral(" Q_ASSERT(context);") << endl;
673 stream << QStringLiteral(" QSurfaceFormat f = context->format();") << endl;
674 stream << QStringLiteral(" const QPair<int, int> v = qMakePair(f.majorVersion(), f.minorVersion());") << endl;
675 stream << QString(QStringLiteral(" if (v < qMakePair(%1, %2))"))
676 .arg(versionProfile.version.major)
677 .arg(versionProfile.version.minor) << endl;
678 stream << QStringLiteral(" return false;") << endl << endl;
679
680 // If generating a legacy or compatibility profile class we need to ensure that
681 // the context does not expose only core functions
682 if (versionProfile.profile != VersionProfile::CoreProfile) {
683 stream << QStringLiteral(" if (f.profile() == QSurfaceFormat::CoreProfile)") << endl;
684 stream << QStringLiteral(" return false;") << endl << endl;
685 }
686
687 stream << QStringLiteral(" return true;") << endl;
688 stream << QStringLiteral("}") << endl << endl;
689
690 // Output static function used as helper in template versionFunctions() function
691 // in QOpenGLContext
692 stream << QString(QStringLiteral("QOpenGLVersionProfile %1::versionProfile()")).arg(className) << endl;
693 stream << QStringLiteral("{") << endl;
694 stream << QStringLiteral(" QOpenGLVersionProfile v;") << endl;
695 stream << QString(QStringLiteral(" v.setVersion(%1, %2);"))
696 .arg(versionProfile.version.major)
697 .arg(versionProfile.version.minor) << endl;
698 if (versionProfile.hasProfiles()) {
699 const QString profileName = versionProfile.profile == VersionProfile::CoreProfile
700 ? QStringLiteral("QSurfaceFormat::CoreProfile")
701 : QStringLiteral("QSurfaceFormat::CompatibilityProfile");
702 stream << QString(QStringLiteral(" v.setProfile(%1);")).arg(profileName) << endl;
703 }
704 stream << QStringLiteral(" return v;") << endl;
705 stream << QStringLiteral("}") << endl;
706
707 // Write the postamble
708 writePostamble(templateFileName, stream);
709 }
710
writeClassFunctionDeclarations(QTextStream & stream,const FunctionCollection & functionSet,ClassVisibility visibility) const711 void CodeGenerator::writeClassFunctionDeclarations(QTextStream &stream,
712 const FunctionCollection &functionSet,
713 ClassVisibility visibility) const
714 {
715 Q_FOREACH (const VersionProfile &version, functionSet.keys()) {
716 // Add a comment to the header
717 stream << QString(QStringLiteral(" // OpenGL %1.%2 %3 functions"))
718 .arg(version.version.major)
719 .arg(version.version.minor)
720 .arg((version.profile == VersionProfile::CoreProfile) ? QStringLiteral("core") : QStringLiteral("deprecated"))
721 << endl;
722
723 // Output function declarations
724 FunctionList functions = functionSet.value(version);
725 Q_FOREACH (const Function &f, functions)
726 writeFunctionDeclaration(stream, f, visibility);
727 stream << endl;
728 } // version and profile
729 }
730
writeFunctionDeclaration(QTextStream & stream,const Function & f,ClassVisibility visibility) const731 void CodeGenerator::writeFunctionDeclaration(QTextStream &stream, const Function &f, ClassVisibility visibility) const
732 {
733 QStringList argList;
734 Q_FOREACH (const Argument &arg, f.arguments) {
735 QString a = QString(QStringLiteral("%1%2 %3%4"))
736 .arg((arg.direction == Argument::In && arg.mode != Argument::Value) ? QStringLiteral("const ") : QString())
737 .arg(arg.type)
738 .arg(passByType(arg))
739 .arg(safeArgumentName(arg.name));
740 argList.append(a);
741 }
742 QString args = argList.join(QStringLiteral(", "));
743
744 QString signature;
745 switch (visibility) {
746 case Public:
747 signature = QString(QStringLiteral(" %1 gl%2(%3);")).arg(f.returnType).arg(f.name).arg(args);
748 break;
749
750 case Private:
751 default:
752 signature = QString(QStringLiteral(" %1 (QOPENGLF_APIENTRYP %2)(%3);")).arg(f.returnType).arg(f.name).arg(args);
753 }
754 stream << signature << endl;
755 }
756
writeClassInlineFunctions(QTextStream & stream,const QString & className,const FunctionCollection & functionSet) const757 void CodeGenerator::writeClassInlineFunctions(QTextStream &stream,
758 const QString &className,
759 const FunctionCollection &functionSet) const
760 {
761 Q_FOREACH (const VersionProfile &version, functionSet.keys()) {
762
763 // Add a comment to the header
764 stream << QString(QStringLiteral("// OpenGL %1.%2 %3 functions"))
765 .arg(version.version.major)
766 .arg(version.version.minor)
767 .arg((version.profile == VersionProfile::CoreProfile) ? QStringLiteral("core") : QStringLiteral("deprecated"))
768 << endl;
769
770 // Output function declarations
771 const QString backendVar = backendVariableName(version);
772 FunctionList functions = functionSet.value(version);
773 Q_FOREACH (const Function &f, functions)
774 writeInlineFunction(stream, className, backendVar, f);
775
776 stream << endl;
777
778 } // version and profile
779 }
780
writeInlineFunction(QTextStream & stream,const QString & className,const QString & backendVar,const Function & f) const781 void CodeGenerator::writeInlineFunction(QTextStream &stream, const QString &className,
782 const QString &backendVar, const Function &f) const
783 {
784 QStringList argList;
785 Q_FOREACH (const Argument &arg, f.arguments) {
786 QString a = QString(QStringLiteral("%1%2 %3%4"))
787 .arg((arg.direction == Argument::In && arg.mode != Argument::Value) ? QStringLiteral("const ") : QString())
788 .arg(arg.type)
789 .arg(passByType(arg))
790 .arg(safeArgumentName(arg.name));
791 argList.append(a);
792 }
793 QString args = argList.join(", ");
794
795
796 QString signature = QString(QStringLiteral("inline %1 %2::gl%3(%4)"))
797 .arg(f.returnType)
798 .arg(className)
799 .arg(f.name)
800 .arg(args);
801 stream << signature << endl << QStringLiteral("{") << endl;
802
803 QStringList argumentNames;
804 Q_FOREACH (const Argument &arg, f.arguments)
805 argumentNames.append(safeArgumentName(arg.name));
806 QString argNames = argumentNames.join(", ");
807
808 if (f.returnType == QLatin1String("void"))
809 stream << QString(QStringLiteral(" %1->%2(%3);")).arg(backendVar).arg(f.name).arg(argNames) << endl;
810 else
811 stream << QString(QStringLiteral(" return %1->%2(%3);")).arg(backendVar).arg(f.name).arg(argNames) << endl;
812 stream << QStringLiteral("}") << endl << endl;
813 }
814
writeEntryPointResolutionCode(QTextStream & stream,const FunctionCollection & functionSet) const815 void CodeGenerator::writeEntryPointResolutionCode(QTextStream &stream,
816 const FunctionCollection &functionSet) const
817 {
818 bool hasModuleHandle = false;
819 Q_FOREACH (const VersionProfile &version, functionSet.keys()) {
820
821 // Add a comment to the header
822 stream << QString(QStringLiteral(" // OpenGL %1.%2 %3 functions"))
823 .arg(version.version.major)
824 .arg(version.version.minor)
825 .arg((version.profile == VersionProfile::CoreProfile) ? QStringLiteral("core") : QStringLiteral("deprecated"))
826 << endl;
827
828 // Output function declarations
829 FunctionList functions = functionSet.value(version);
830
831 bool useGetProcAddress = (version.version.major == 1 && (version.version.minor == 0 || version.version.minor == 1));
832 if (useGetProcAddress) {
833 stream << "#if defined(Q_OS_WIN)" << endl;
834 if (!hasModuleHandle) {
835 stream << " HMODULE handle = GetModuleHandleA(\"opengl32.dll\");" << endl;
836 hasModuleHandle = true;
837 }
838
839 Q_FOREACH (const Function &f, functions)
840 writeEntryPointResolutionStatement(stream, f, QString(), useGetProcAddress);
841
842 stream << "#else" << endl;
843 }
844
845 Q_FOREACH (const Function &f, functions)
846 writeEntryPointResolutionStatement(stream, f);
847
848 if (useGetProcAddress)
849 stream << "#endif" << endl;
850
851 stream << endl;
852
853 } // version and profile
854 }
855
writeEntryPointResolutionStatement(QTextStream & stream,const Function & f,const QString & prefix,bool useGetProcAddress) const856 void CodeGenerator::writeEntryPointResolutionStatement(QTextStream &stream, const Function &f,
857 const QString &prefix, bool useGetProcAddress) const
858 {
859 QStringList argList;
860 Q_FOREACH (const Argument &arg, f.arguments) {
861 QString a = QString("%1%2 %3")
862 .arg((arg.direction == Argument::In && arg.mode != Argument::Value) ? QStringLiteral("const ") : QString())
863 .arg(arg.type)
864 .arg(passByType(arg));
865 argList.append(a);
866 }
867 QString args = argList.join(QStringLiteral(", "));
868
869 QString signature;
870 if (!useGetProcAddress) {
871 signature = QString(QStringLiteral(" %4%3 = reinterpret_cast<%1 (QOPENGLF_APIENTRYP)(%2)>(context->getProcAddress(\"gl%3\"));"))
872 .arg(f.returnType)
873 .arg(args)
874 .arg(f.name)
875 .arg(prefix);
876 } else {
877 signature = QString(QStringLiteral(" %4%3 = reinterpret_cast<%1 (QOPENGLF_APIENTRYP)(%2)>(GetProcAddress(handle, \"gl%3\"));"))
878 .arg(f.returnType)
879 .arg(args)
880 .arg(f.name)
881 .arg(prefix);
882 }
883 stream << signature << endl;
884 }
885
backendsForFunctionCollection(const FunctionCollection & functionSet) const886 QList<VersionProfile> CodeGenerator::backendsForFunctionCollection(const FunctionCollection &functionSet) const
887 {
888 QList<VersionProfile> backends;
889 Q_FOREACH (const VersionProfile &versionProfile, functionSet.keys()) {
890 if (m_parser->versionProfiles().contains(versionProfile))
891 backends.append(versionProfile);
892 }
893 return backends;
894 }
895
backendClassName(const VersionProfile & v) const896 QString CodeGenerator::backendClassName(const VersionProfile &v) const
897 {
898 QString statusSuffix = v.profile == VersionProfile::CoreProfile
899 ? QStringLiteral("_Core")
900 : QStringLiteral("_Deprecated");
901 const QString className = QString(QStringLiteral("QOpenGLFunctions_%1_%2%3Backend"))
902 .arg(v.version.major)
903 .arg(v.version.minor)
904 .arg(statusSuffix);
905 return className;
906 }
907
backendVariableName(const VersionProfile & v) const908 QString CodeGenerator::backendVariableName(const VersionProfile &v) const
909 {
910 const QString status = (v.profile == VersionProfile::CoreProfile)
911 ? QStringLiteral("Core")
912 : QStringLiteral("Deprecated");
913 const QString varName = QString(QStringLiteral("d_%1_%2_%3"))
914 .arg(v.version.major)
915 .arg(v.version.minor)
916 .arg(status);
917 return varName;
918 }
919
writeBackendVariableDeclarations(QTextStream & stream,const QList<VersionProfile> & backends) const920 void CodeGenerator::writeBackendVariableDeclarations(QTextStream &stream, const QList<VersionProfile> &backends) const
921 {
922 // We need a private class for each version and profile (status: core or deprecated)
923 Q_FOREACH (const VersionProfile &v, backends) {
924 const QString className = backendClassName(v);
925 const QString varName = backendVariableName(v);
926 stream << QString(QStringLiteral(" %1* %2;")).arg(className).arg(varName) << endl;
927 }
928 }
929
writeExtensionHeader(const QString & fileName) const930 void CodeGenerator::writeExtensionHeader(const QString &fileName) const
931 {
932 if (!m_parser)
933 return;
934
935 QFile file(fileName);
936 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
937 return;
938 QTextStream stream(&file);
939
940 // Write the preamble
941 writePreamble(fileName, stream);
942
943 // Iterate through the list of extensions and create one class per extension
944 QStringList extensions = m_parser->extensions();
945 Q_FOREACH (const QString &extension, extensions) {
946 writeExtensionClassDeclaration(stream, extension, Private);
947 writeExtensionClassDeclaration(stream, extension, Public);
948 }
949
950 // Write the postamble
951 writePostamble(fileName, stream);
952 }
953
writeExtensionImplementation(const QString & fileName) const954 void CodeGenerator::writeExtensionImplementation(const QString &fileName) const
955 {
956 if (!m_parser)
957 return;
958
959 QFile file(fileName);
960 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
961 return;
962 QTextStream stream(&file);
963
964 // Write the preamble
965 writePreamble(fileName, stream);
966
967 // Iterate through the list of extensions and create one class per extension
968 QStringList extensions = m_parser->extensions();
969 Q_FOREACH (const QString &extension, extensions)
970 writeExtensionClassImplementation(stream, extension);
971
972 // Write the postamble
973 writePostamble(fileName, stream);
974 }
975
writeExtensionClassDeclaration(QTextStream & stream,const QString & extension,ClassVisibility visibility) const976 void CodeGenerator::writeExtensionClassDeclaration(QTextStream &stream, const QString &extension, ClassVisibility visibility) const
977 {
978 const QString className = generateExtensionClassName(extension, visibility);
979
980 QString baseClass = (visibility == Public) ? QStringLiteral("QAbstractOpenGLExtension") : QStringLiteral("QAbstractOpenGLExtensionPrivate");
981
982 stream << QString(QStringLiteral("class %2 : public %3"))
983 .arg(className)
984 .arg(baseClass)
985 << endl << "{" << endl << "public:" << endl;
986
987 if (visibility == Public) {
988 // Default constructor
989 stream << QStringLiteral(" ") << className << QStringLiteral("();") << endl << endl;
990
991 // Base class virtual function(s)
992 QString resolveFunction = QStringLiteral(" bool initializeOpenGLFunctions() final;");
993 stream << resolveFunction << endl << endl;
994 }
995
996 // Output the functions provided by this extension
997 QList<Function> functions = m_parser->functionsForExtension(extension);
998 Q_FOREACH (const Function &f, functions)
999 writeFunctionDeclaration(stream, f, visibility);
1000
1001 if (visibility == Public) {
1002 // Write out the protected ctor
1003 stream << endl << QStringLiteral("protected:") << endl;
1004 stream << QStringLiteral(" Q_DECLARE_PRIVATE(") << className << QStringLiteral(")") << endl;
1005 }
1006
1007 // End the class declaration
1008 stream << QStringLiteral("};") << endl << endl;
1009
1010 // Output the inline functions for public class
1011 if (visibility == Public) {
1012 Q_FOREACH (const Function &f, functions)
1013 writeExtensionInlineFunction(stream, className, f);
1014 }
1015 }
1016
writeExtensionInlineFunction(QTextStream & stream,const QString & className,const Function & f) const1017 void CodeGenerator::writeExtensionInlineFunction(QTextStream &stream, const QString &className, const Function &f) const
1018 {
1019 QStringList argList;
1020 Q_FOREACH (const Argument &arg, f.arguments) {
1021 QString a = QString(QStringLiteral("%1%2 %3%4"))
1022 .arg((arg.direction == Argument::In && arg.mode != Argument::Value) ? QStringLiteral("const ") : QString())
1023 .arg(arg.type)
1024 .arg(passByType(arg))
1025 .arg(safeArgumentName(arg.name));
1026 argList.append(a);
1027 }
1028 QString args = argList.join(", ");
1029
1030
1031 QString signature = QString(QStringLiteral("inline %1 %2::gl%3(%4)"))
1032 .arg(f.returnType)
1033 .arg(className)
1034 .arg(f.name)
1035 .arg(args);
1036 stream << signature << endl << QStringLiteral("{") << endl;
1037
1038 stream << QString(QStringLiteral(" Q_D(%1);")).arg(className) << endl;
1039
1040 QStringList argumentNames;
1041 Q_FOREACH (const Argument &arg, f.arguments)
1042 argumentNames.append(safeArgumentName(arg.name));
1043 QString argNames = argumentNames.join(", ");
1044
1045 if (f.returnType == QStringLiteral("void"))
1046 stream << QString(QStringLiteral(" d->%1(%2);")).arg(f.name).arg(argNames) << endl;
1047 else
1048 stream << QString(QStringLiteral(" return d->%1(%2);")).arg(f.name).arg(argNames) << endl;
1049 stream << QStringLiteral("}") << endl << endl;
1050 }
1051
writeExtensionClassImplementation(QTextStream & stream,const QString & extension) const1052 void CodeGenerator::writeExtensionClassImplementation(QTextStream &stream, const QString &extension) const
1053 {
1054 const QString className = generateExtensionClassName(extension);
1055 const QString privateClassName = generateExtensionClassName(extension, Private);
1056
1057 // Output default constructor
1058 stream << className << QStringLiteral("::") << className << QStringLiteral("()") << endl;
1059 stream << QStringLiteral(" : QAbstractOpenGLExtension(*(new ") << privateClassName << QStringLiteral("))") << endl;
1060 stream << QStringLiteral("{") << endl << QStringLiteral("}") << endl << endl;
1061
1062
1063 // Output function to initialize this class
1064 stream << QStringLiteral("bool ") << className
1065 << QStringLiteral("::initializeOpenGLFunctions()") << endl
1066 << QStringLiteral("{") << endl;
1067
1068 stream << QStringLiteral(" if (isInitialized())") << endl;
1069 stream << QStringLiteral(" return true;") << endl << endl;
1070
1071 stream << QStringLiteral(" QOpenGLContext *context = QOpenGLContext::currentContext();") << endl;
1072 stream << QStringLiteral(" if (!context) {") << endl;
1073 stream << QStringLiteral(" qWarning(\"A current OpenGL context is required to resolve OpenGL extension functions\");")
1074 << endl;
1075 stream << QStringLiteral(" return false;") << endl;
1076 stream << QStringLiteral(" }") << endl << endl;
1077
1078 // Output code to resolve entry points for this class
1079 stream << QStringLiteral(" // Resolve the functions") << endl;
1080 stream << QStringLiteral(" Q_D(") << className << QStringLiteral(");") << endl;
1081 stream << endl;
1082
1083 // Output function declarations
1084 QList<Function> functions = m_parser->functionsForExtension(extension);
1085 Q_FOREACH (const Function &f, functions)
1086 writeEntryPointResolutionStatement(stream, f, QStringLiteral("d->"));
1087
1088 // Call the base class implementation
1089 stream << QStringLiteral(" QAbstractOpenGLExtension::initializeOpenGLFunctions();") << endl;
1090
1091 // Finish off
1092 stream << QStringLiteral(" return true;") << endl;
1093 stream << QStringLiteral("}") << endl << endl;
1094 }
1095
generateExtensionClassName(const QString & extension,ClassVisibility visibility) const1096 QString CodeGenerator::generateExtensionClassName(const QString &extension, ClassVisibility visibility) const
1097 {
1098 QString visibilitySuffix;
1099 if (visibility == Private)
1100 visibilitySuffix = QStringLiteral("Private");
1101
1102 return QString(QStringLiteral("QOpenGLExtension_%1%2"))
1103 .arg(extension)
1104 .arg(visibilitySuffix);
1105 }
1106