src/opengl/qgl_p.h
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
     8 **
     8 **
    78 #define vt2f(x)     X2FLOAT(x)
    78 #define vt2f(x)     X2FLOAT(x)
    79 #define q_vertexType GLfixed
    79 #define q_vertexType GLfixed
    80 #define q_vertexTypeEnum GL_FIXED
    80 #define q_vertexTypeEnum GL_FIXED
    81 #endif //QT_OPENGL_ES_1_CL
    81 #endif //QT_OPENGL_ES_1_CL
    82 
    82 
    83 #ifdef QT_OPENGL_ES
    83 #if defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2)
    84 QT_BEGIN_INCLUDE_NAMESPACE
    84 QT_BEGIN_INCLUDE_NAMESPACE
       
    85 
    85 #if defined(QT_OPENGL_ES_2)
    86 #if defined(QT_OPENGL_ES_2)
    86 #include <EGL/egl.h>
    87 #   include <GLES2/gl2.h>
       
    88 #endif
       
    89 
       
    90 #if defined(QT_GLES_EGL)
       
    91 #   include <GLES/egl.h>
    87 #else
    92 #else
    88 #include <GLES/egl.h>
    93 #   include <EGL/egl.h>
    89 #endif
    94 #endif
       
    95 
    90 QT_END_INCLUDE_NAMESPACE
    96 QT_END_INCLUDE_NAMESPACE
    91 #endif
    97 #endif
    92 
    98 
    93 QT_BEGIN_NAMESPACE
    99 QT_BEGIN_NAMESPACE
    94 
   100 
   177                        , wsurf(0)
   183                        , wsurf(0)
   178 #endif
   184 #endif
   179 #if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
   185 #if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
   180                        , eglSurfaceWindowId(0)
   186                        , eglSurfaceWindowId(0)
   181 #endif
   187 #endif
   182         {}
   188     {
       
   189         isGLWidget = 1;
       
   190     }
   183 
   191 
   184     ~QGLWidgetPrivate() {}
   192     ~QGLWidgetPrivate() {}
   185 
   193 
   186     void init(QGLContext *context, const QGLWidget* shareWidget);
   194     void init(QGLContext *context, const QGLWidget* shareWidget);
   187     void initContext(QGLContext *context, const QGLWidget* shareWidget);
   195     void initContext(QGLContext *context, const QGLWidget* shareWidget);
   220 class QGLSharedResourceGuard;
   228 class QGLSharedResourceGuard;
   221 
   229 
   222 typedef QHash<QString, GLuint> QGLDDSCache;
   230 typedef QHash<QString, GLuint> QGLDDSCache;
   223 
   231 
   224 // QGLContextPrivate has the responsibility of creating context groups.
   232 // QGLContextPrivate has the responsibility of creating context groups.
   225 // QGLContextPrivate and QGLShareRegister will both maintain the reference counter and destroy
   233 // QGLContextPrivate maintains the reference counter and destroys
   226 // context groups when needed.
   234 // context groups when needed.
   227 // QGLShareRegister has the responsibility of keeping the context pointer up to date.
       
   228 class QGLContextGroup
   235 class QGLContextGroup
   229 {
   236 {
   230 public:
   237 public:
   231     ~QGLContextGroup();
   238     ~QGLContextGroup();
   232 
   239 
   233     QGLExtensionFuncs &extensionFuncs() {return m_extensionFuncs;}
   240     QGLExtensionFuncs &extensionFuncs() {return m_extensionFuncs;}
   234     const QGLContext *context() const {return m_context;}
   241     const QGLContext *context() const {return m_context;}
   235     bool isSharing() const { return m_shares.size() >= 2; }
   242     bool isSharing() const { return m_shares.size() >= 2; }
       
   243     QList<const QGLContext *> shares() const { return m_shares; }
   236 
   244 
   237     void addGuard(QGLSharedResourceGuard *guard);
   245     void addGuard(QGLSharedResourceGuard *guard);
   238     void removeGuard(QGLSharedResourceGuard *guard);
   246     void removeGuard(QGLSharedResourceGuard *guard);
       
   247 
       
   248     static void addShare(const QGLContext *context, const QGLContext *share);
       
   249     static void removeShare(const QGLContext *context);
   239 private:
   250 private:
   240     QGLContextGroup(const QGLContext *context) : m_context(context), m_guards(0), m_refs(1) { }
   251     QGLContextGroup(const QGLContext *context) : m_context(context), m_guards(0), m_refs(1) { }
   241 
   252 
   242     QGLExtensionFuncs m_extensionFuncs;
   253     QGLExtensionFuncs m_extensionFuncs;
   243     const QGLContext *m_context; // context group's representative
   254     const QGLContext *m_context; // context group's representative
   247     QAtomicInt m_refs;
   258     QAtomicInt m_refs;
   248     QGLDDSCache m_dds_cache;
   259     QGLDDSCache m_dds_cache;
   249 
   260 
   250     void cleanupResources(const QGLContext *ctx);
   261     void cleanupResources(const QGLContext *ctx);
   251 
   262 
   252     friend class QGLShareRegister;
       
   253     friend class QGLContext;
   263     friend class QGLContext;
   254     friend class QGLContextPrivate;
   264     friend class QGLContextPrivate;
   255     friend class QGLContextResource;
   265     friend class QGLContextResource;
   256 };
   266 };
   257 
   267 
   258 class QGLTexture;
   268 // Get the context that resources for "ctx" will transfer to once
   259 
   269 // "ctx" is destroyed.  Returns null if nothing is sharing with ctx.
   260 class QGLContextPrivate
   270 Q_OPENGL_EXPORT const QGLContext *qt_gl_transfer_context(const QGLContext *);
   261 {
       
   262     Q_DECLARE_PUBLIC(QGLContext)
       
   263 public:
       
   264     explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {group = new QGLContextGroup(context);}
       
   265     ~QGLContextPrivate();
       
   266     QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format,
       
   267                             QGLContext::BindOptions options);
       
   268     QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
       
   269                             QGLContext::BindOptions options);
       
   270     QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
       
   271                             QGLContext::BindOptions options);
       
   272     QGLTexture *textureCacheLookup(const qint64 key, GLenum target);
       
   273     void init(QPaintDevice *dev, const QGLFormat &format);
       
   274     QImage convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format);
       
   275     int maxTextureSize();
       
   276 
       
   277     void cleanup();
       
   278 
       
   279 #if defined(Q_WS_WIN)
       
   280     HGLRC rc;
       
   281     HDC dc;
       
   282     WId        win;
       
   283     int pixelFormatId;
       
   284     QGLCmap* cmap;
       
   285     HBITMAP hbitmap;
       
   286     HDC hbitmap_hdc;
       
   287 #endif
       
   288 #if defined(QT_OPENGL_ES)
       
   289     QEglContext *eglContext;
       
   290     EGLSurface eglSurface;
       
   291     void destroyEglSurfaceForDevice();
       
   292 #elif defined(Q_WS_X11) || defined(Q_WS_MAC)
       
   293     void* cx;
       
   294 #endif
       
   295 #if defined(Q_WS_X11) || defined(Q_WS_MAC)
       
   296     void* vi;
       
   297 #endif
       
   298 #if defined(Q_WS_X11)
       
   299     void* pbuf;
       
   300     quint32 gpm;
       
   301     int screen;
       
   302     QHash<QPixmapData*, QPixmap> boundPixmaps;
       
   303     QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key,
       
   304                                             QGLContext::BindOptions options);
       
   305     static void destroyGlSurfaceForPixmap(QPixmapData*);
       
   306     static void unbindPixmapFromTexture(QPixmapData*);
       
   307 #endif
       
   308 #if defined(Q_WS_MAC)
       
   309     bool update;
       
   310     void *tryFormat(const QGLFormat &format);
       
   311     void clearDrawable();
       
   312 #endif
       
   313     QGLFormat glFormat;
       
   314     QGLFormat reqFormat;
       
   315     GLuint fbo;
       
   316 
       
   317     uint valid : 1;
       
   318     uint sharing : 1;
       
   319     uint initDone : 1;
       
   320     uint crWin : 1;
       
   321     uint internal_context : 1;
       
   322     uint version_flags_cached : 1;
       
   323     QPaintDevice *paintDevice;
       
   324     QColor transpColor;
       
   325     QGLContext *q_ptr;
       
   326     QGLFormat::OpenGLVersionFlags version_flags;
       
   327 
       
   328     QGLContextGroup *group;
       
   329     GLint max_texture_size;
       
   330 
       
   331     GLuint current_fbo;
       
   332     GLuint default_fbo;
       
   333     QPaintEngine *active_engine;
       
   334 
       
   335     static inline QGLContextGroup *contextGroup(const QGLContext *ctx) { return ctx->d_ptr->group; }
       
   336 
       
   337 #ifdef Q_WS_WIN
       
   338     static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *ctx) { return ctx->d_ptr->group->extensionFuncs(); }
       
   339 #endif
       
   340 
       
   341 #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
       
   342     static QGLExtensionFuncs qt_extensionFuncs;
       
   343     static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *) { return qt_extensionFuncs; }
       
   344 #endif
       
   345 
       
   346     static void setCurrentContext(QGLContext *context);
       
   347 };
       
   348 
       
   349 // ### make QGLContext a QObject in 5.0 and remove the proxy stuff
       
   350 class Q_OPENGL_EXPORT QGLSignalProxy : public QObject
       
   351 {
       
   352     Q_OBJECT
       
   353 public:
       
   354     QGLSignalProxy() : QObject() {}
       
   355     void emitAboutToDestroyContext(const QGLContext *context) {
       
   356         emit aboutToDestroyContext(context);
       
   357     }
       
   358     static QGLSignalProxy *instance();
       
   359 Q_SIGNALS:
       
   360     void aboutToDestroyContext(const QGLContext *context);
       
   361 };
       
   362 
   271 
   363 // GL extension definitions
   272 // GL extension definitions
   364 class QGLExtensions {
   273 class QGLExtensions {
   365 public:
   274 public:
   366     enum Extension {
   275     enum Extension {
   384         PVRTCTextureCompression = 0x00020000,
   293         PVRTCTextureCompression = 0x00020000,
   385         FragmentShader          = 0x00040000
   294         FragmentShader          = 0x00040000
   386     };
   295     };
   387     Q_DECLARE_FLAGS(Extensions, Extension)
   296     Q_DECLARE_FLAGS(Extensions, Extension)
   388 
   297 
   389     static Extensions glExtensions;
   298     static Extensions glExtensions();
   390     static bool nvidiaFboNeedsFinish;
   299 
   391     static void init(); // sys dependent
   300 private:
   392     static void init_extensions(); // general: called by init()
   301     static Extensions currentContextExtensions();
       
   302 };
       
   303 
       
   304 /*
       
   305     QGLTemporaryContext - the main objective of this class is to have a way of
       
   306     creating a GL context and making it current, without going via QGLWidget
       
   307     and friends. At certain points during GL initialization we need a current
       
   308     context in order decide what GL features are available, and to resolve GL
       
   309     extensions. Having a light-weight way of creating such a context saves
       
   310     initial application startup time, and it doesn't wind up creating recursive
       
   311     conflicts.
       
   312     The class currently uses a private d pointer to hide the platform specific
       
   313     types. This could possibly been done inline with #ifdef'ery, but it causes
       
   314     major headaches on e.g. X11 due to namespace pollution.
       
   315 */
       
   316 class QGLTemporaryContextPrivate;
       
   317 class QGLTemporaryContext {
       
   318 public:
       
   319     QGLTemporaryContext(bool directRendering = true, QWidget *parent = 0);
       
   320     ~QGLTemporaryContext();
       
   321 
       
   322 private:
       
   323     QScopedPointer<QGLTemporaryContextPrivate> d;
       
   324 };
       
   325 
       
   326 class QGLTexture;
       
   327 
       
   328 // This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's
       
   329 // all the GL2 engine uses:
       
   330 #define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3
       
   331 
       
   332 class QGLContextPrivate
       
   333 {
       
   334     Q_DECLARE_PUBLIC(QGLContext)
       
   335 public:
       
   336     explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {group = new QGLContextGroup(context);}
       
   337     ~QGLContextPrivate();
       
   338     QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format,
       
   339                             QGLContext::BindOptions options);
       
   340     QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
       
   341                             QGLContext::BindOptions options);
       
   342     QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
       
   343                             QGLContext::BindOptions options);
       
   344     QGLTexture *textureCacheLookup(const qint64 key, GLenum target);
       
   345     void init(QPaintDevice *dev, const QGLFormat &format);
       
   346     QImage convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format);
       
   347     int maxTextureSize();
       
   348 
       
   349     void cleanup();
       
   350 
       
   351     void setVertexAttribArrayEnabled(int arrayIndex, bool enabled = true);
       
   352     void syncGlState(); // Makes sure the GL context's state is what we think it is
       
   353 
       
   354 #if defined(Q_WS_WIN)
       
   355     HGLRC rc;
       
   356     HDC dc;
       
   357     WId        win;
       
   358     int pixelFormatId;
       
   359     QGLCmap* cmap;
       
   360     HBITMAP hbitmap;
       
   361     HDC hbitmap_hdc;
       
   362 #endif
       
   363 #if defined(QT_OPENGL_ES)
       
   364     QEglContext *eglContext;
       
   365     EGLSurface eglSurface;
       
   366     void destroyEglSurfaceForDevice();
       
   367 #elif defined(Q_WS_X11) || defined(Q_WS_MAC)
       
   368     void* cx;
       
   369 #endif
       
   370 #if defined(Q_WS_X11) || defined(Q_WS_MAC)
       
   371     void* vi;
       
   372 #endif
       
   373 #if defined(Q_WS_X11)
       
   374     void* pbuf;
       
   375     quint32 gpm;
       
   376     int screen;
       
   377     QHash<QPixmapData*, QPixmap> boundPixmaps;
       
   378     QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key,
       
   379                                             QGLContext::BindOptions options);
       
   380     static void destroyGlSurfaceForPixmap(QPixmapData*);
       
   381     static void unbindPixmapFromTexture(QPixmapData*);
       
   382 #endif
       
   383 #if defined(Q_WS_MAC)
       
   384     bool update;
       
   385     void *tryFormat(const QGLFormat &format);
       
   386     void clearDrawable();
       
   387 #endif
       
   388     QGLFormat glFormat;
       
   389     QGLFormat reqFormat;
       
   390     GLuint fbo;
       
   391 
       
   392     uint valid : 1;
       
   393     uint sharing : 1;
       
   394     uint initDone : 1;
       
   395     uint crWin : 1;
       
   396     uint internal_context : 1;
       
   397     uint version_flags_cached : 1;
       
   398     uint extension_flags_cached : 1;
       
   399     QPaintDevice *paintDevice;
       
   400     QColor transpColor;
       
   401     QGLContext *q_ptr;
       
   402     QGLFormat::OpenGLVersionFlags version_flags;
       
   403     QGLExtensions::Extensions extension_flags;
       
   404 
       
   405     QGLContextGroup *group;
       
   406     GLint max_texture_size;
       
   407 
       
   408     GLuint current_fbo;
       
   409     GLuint default_fbo;
       
   410     QPaintEngine *active_engine;
       
   411 
       
   412     bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT];
       
   413 
       
   414     static inline QGLContextGroup *contextGroup(const QGLContext *ctx) { return ctx->d_ptr->group; }
       
   415 
       
   416 #ifdef Q_WS_WIN
       
   417     static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *ctx) { return ctx->d_ptr->group->extensionFuncs(); }
       
   418 #endif
       
   419 
       
   420 #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
       
   421     static QGLExtensionFuncs qt_extensionFuncs;
       
   422     static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *) { return qt_extensionFuncs; }
       
   423 #endif
       
   424 
       
   425     static void setCurrentContext(QGLContext *context);
       
   426 };
       
   427 
       
   428 // ### make QGLContext a QObject in 5.0 and remove the proxy stuff
       
   429 class Q_OPENGL_EXPORT QGLSignalProxy : public QObject
       
   430 {
       
   431     Q_OBJECT
       
   432 public:
       
   433     QGLSignalProxy() : QObject() {}
       
   434     void emitAboutToDestroyContext(const QGLContext *context) {
       
   435         emit aboutToDestroyContext(context);
       
   436     }
       
   437     static QGLSignalProxy *instance();
       
   438 Q_SIGNALS:
       
   439     void aboutToDestroyContext(const QGLContext *context);
   393 };
   440 };
   394 
   441 
   395 Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions)
   442 Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions)
   396 
       
   397 
       
   398 class Q_OPENGL_EXPORT QGLShareRegister
       
   399 {
       
   400 public:
       
   401     QGLShareRegister() {}
       
   402     ~QGLShareRegister() {}
       
   403 
       
   404     void addShare(const QGLContext *context, const QGLContext *share);
       
   405     QList<const QGLContext *> shares(const QGLContext *context);
       
   406     void removeShare(const QGLContext *context);
       
   407 };
       
   408 
       
   409 extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg();
       
   410 
   443 
   411 // Temporarily make a context current if not already current or
   444 // Temporarily make a context current if not already current or
   412 // shared with the current contex.  The previous context is made
   445 // shared with the current contex.  The previous context is made
   413 // current when the object goes out of scope.
   446 // current when the object goes out of scope.
   414 class Q_OPENGL_EXPORT QGLShareContextScope
   447 class Q_OPENGL_EXPORT QGLShareContextScope
   495         (const char *buf, int len, const char *format = 0);
   528         (const char *buf, int len, const char *format = 0);
   496     QSize bindCompressedTextureDDS(const char *buf, int len);
   529     QSize bindCompressedTextureDDS(const char *buf, int len);
   497     QSize bindCompressedTexturePVR(const char *buf, int len);
   530     QSize bindCompressedTexturePVR(const char *buf, int len);
   498 };
   531 };
   499 
   532 
   500 class QGLTextureCache {
   533 class Q_AUTOTEST_EXPORT QGLTextureCache {
   501 public:
   534 public:
   502     QGLTextureCache();
   535     QGLTextureCache();
   503     ~QGLTextureCache();
   536     ~QGLTextureCache();
   504 
   537 
   505     void insert(QGLContext *ctx, qint64 key, QGLTexture *texture, int cost);
   538     void insert(QGLContext *ctx, qint64 key, QGLTexture *texture, int cost);
   511     int maxCost() {return m_cache.maxCost(); }
   544     int maxCost() {return m_cache.maxCost(); }
   512     QGLTexture* getTexture(quint64 key) { return m_cache.object(key); }
   545     QGLTexture* getTexture(quint64 key) { return m_cache.object(key); }
   513 
   546 
   514     static QGLTextureCache *instance();
   547     static QGLTextureCache *instance();
   515     static void deleteIfEmpty();
   548     static void deleteIfEmpty();
   516     static void imageCleanupHook(qint64 cacheKey);
   549     static void cleanupTexturesForCacheKey(qint64 cacheKey);
   517     static void cleanupTextures(QPixmap* pixmap);
   550     static void cleanupTexturesForPixampData(QPixmapData* pixmap);
   518 #ifdef Q_WS_X11
   551     static void cleanupBeforePixmapDestruction(QPixmapData* pixmap);
   519     // X11 needs to catch pixmap data destruction to delete EGL/GLX pixmap surfaces
       
   520     static void cleanupPixmapSurfaces(QPixmap* pixmap);
       
   521 #endif
       
   522 
   552 
   523 private:
   553 private:
   524     QCache<qint64, QGLTexture> m_cache;
   554     QCache<qint64, QGLTexture> m_cache;
   525 };
   555 };
   526 
   556 
   529 
   559 
   530 bool qt_gl_preferGL2Engine();
   560 bool qt_gl_preferGL2Engine();
   531 
   561 
   532 inline GLenum qt_gl_preferredTextureFormat()
   562 inline GLenum qt_gl_preferredTextureFormat()
   533 {
   563 {
   534     return (QGLExtensions::glExtensions & QGLExtensions::BGRATextureFormat) && QSysInfo::ByteOrder == QSysInfo::LittleEndian
   564     return (QGLExtensions::glExtensions() & QGLExtensions::BGRATextureFormat) && QSysInfo::ByteOrder == QSysInfo::LittleEndian
   535         ? GL_BGRA : GL_RGBA;
   565         ? GL_BGRA : GL_RGBA;
   536 }
   566 }
   537 
   567 
   538 inline GLenum qt_gl_preferredTextureTarget()
   568 inline GLenum qt_gl_preferredTextureTarget()
   539 {
   569 {
   540 #if defined(QT_OPENGL_ES_2)
   570 #if defined(QT_OPENGL_ES_2)
   541     return GL_TEXTURE_2D;
   571     return GL_TEXTURE_2D;
   542 #else
   572 #else
   543     return (QGLExtensions::glExtensions & QGLExtensions::TextureRectangle)
   573     return (QGLExtensions::glExtensions() & QGLExtensions::TextureRectangle)
   544            && !qt_gl_preferGL2Engine()
   574            && !qt_gl_preferGL2Engine()
   545            ? GL_TEXTURE_RECTANGLE_NV
   575            ? GL_TEXTURE_RECTANGLE_NV
   546            : GL_TEXTURE_2D;
   576            : GL_TEXTURE_2D;
   547 #endif
   577 #endif
   548 }
   578 }
   549 
   579 
   550 // One resource per group of shared contexts.
   580 // One resource per group of shared contexts.
   551 class Q_AUTOTEST_EXPORT QGLContextResource
   581 class Q_OPENGL_EXPORT QGLContextResource
   552 {
   582 {
   553 public:
   583 public:
   554     typedef void (*FreeFunc)(void *);
   584     typedef void (*FreeFunc)(void *);
   555     QGLContextResource(FreeFunc f);
   585     QGLContextResource(FreeFunc f);
   556     ~QGLContextResource();
   586     ~QGLContextResource();
   610 
   640 
   611     friend class QGLContextGroup;
   641     friend class QGLContextGroup;
   612 };
   642 };
   613 
   643 
   614 
   644 
   615 // This class can be used to match GL extensions with doing any mallocs. The
   645 // This class can be used to match GL extensions without doing any mallocs. The
   616 // class assumes that the GL extension string ends with a space character,
   646 // class assumes that the GL extension string ends with a space character,
   617 // which it should do on all conformant platforms. Create the object and pass
   647 // which it should do on all conformant platforms. Create the object and pass
   618 // in a pointer to the extension string, then call match() on each extension
   648 // in a pointer to the extension string, then call match() on each extension
   619 // that should be matched. The match() function takes the extension name
   649 // that should be matched. The match() function takes the extension name
   620 // *without* the terminating space character as input.
   650 // *without* the terminating space character as input.