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