diff options
author | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2009-12-29 13:06:18 (GMT) |
---|---|---|
committer | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2009-12-30 15:23:29 (GMT) |
commit | 592dc5978e5109c6c7c378623817938779c869a0 (patch) | |
tree | e9acdb025fc82e52d3e03738fa14b273c2d579c6 | |
parent | e5c52134bdd24a19f2aa5c29b654ab5e6b39ec89 (diff) | |
download | Qt-592dc5978e5109c6c7c378623817938779c869a0.zip Qt-592dc5978e5109c6c7c378623817938779c869a0.tar.gz Qt-592dc5978e5109c6c7c378623817938779c869a0.tar.bz2 |
Added support for OpenGL up to version 3.2 on Windows.
Task-number: QTBUG-4438, QT-2662, QT-2663
Reviewed-by: Tom
-rw-r--r-- | src/opengl/qgl.cpp | 101 | ||||
-rw-r--r-- | src/opengl/qgl.h | 23 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 18 | ||||
-rw-r--r-- | src/opengl/qgl_win.cpp | 158 |
4 files changed, 275 insertions, 25 deletions
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index eb14c6c..ffce551 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -227,6 +227,9 @@ bool qt_gl_preferGL2Engine() \value DirectRendering Specifies that the context is used for direct rendering to a display. \value HasOverlay Enables the use of an overlay. \value SampleBuffers Enables the use of sample buffers. + \value DeprecatedFunctions Enables the use of deprecated functionality for OpenGL 3.x + contexts. A context with deprecated functionality enabled is + called a full context in the OpenGL specification. \value SingleBuffer Specifies the use of a single buffer, as opposed to double buffers. \value NoDepthBuffer Disables the use of a depth buffer. \value ColorIndex Specifies that the context should use a color index as its pixel format. @@ -237,6 +240,9 @@ bool qt_gl_preferGL2Engine() \value IndirectRendering Specifies that the context is used for indirect rendering to a buffer. \value NoOverlay Disables the use of an overlay. \value NoSampleBuffers Disables the use of sample buffers. + \value NoDeprecatedFunctions Disables the use of deprecated functionality for OpenGL 3.x + contexts. A context with deprecated functionality disabled is + called a forward compatible context in the OpenGL specification. \sa {Sample Buffers Example} */ @@ -1082,6 +1088,84 @@ int QGLFormat::stencilBufferSize() const } /*! + \since 4.7 + + Set the OpenGL version. If a context compatible with the requested OpenGL version + cannot be created, a context compatible with version 1.x is created instead. + + \sa majorVersion(), minorVersion() +*/ +void QGLFormat::setVersion(int major, int minor) +{ + detach(); + d->majorVersion = major; + d->minorVersion = minor; +} + +/*! + \since 4.7 + + Returns the OpenGL major version. + + \sa setVersion(), minorVersion() +*/ +int QGLFormat::majorVersion() const +{ + return d->majorVersion; +} + +/*! + \since 4.7 + + Returns the OpenGL minor version. + + \sa setVersion(), majorVersion() +*/ +int QGLFormat::minorVersion() const +{ + return d->minorVersion; +} + +/*! + \enum QGLFormat::OpenGLContextProfile + \since 4.7 + + This enum describes the OpenGL context profiles that can be specified for contexts implementing + OpenGL version 3.2 or higher. These profiles are different from OpenGL ES profiles. + + \value NoProfile OpenGL version is lower than 3.2. + \value CoreProfile Functionality deprecated in OpenGL version 3.0 is not available. + \value CompatibilityProfile Functionality from earlier OpenGL versions is available. +*/ + +/*! + \since 4.7 + + Set the OpenGL context profile. The profile is ignored if the requested OpenGL + version is less than 3.2. + + \sa profile() +*/ +void QGLFormat::setProfile(OpenGLContextProfile profile) +{ + detach(); + d->profile = profile; +} + +/*! + \since 4.7 + + Returns the OpenGL context profile. + + \sa setProfile() +*/ +QGLFormat::OpenGLContextProfile QGLFormat::profile() const +{ + return d->profile; +} + + +/*! \fn bool QGLFormat::hasOpenGL() Returns true if the window system has any OpenGL support; @@ -1155,8 +1239,7 @@ QGLFormat::OpenGLVersionFlags Q_AUTOTEST_EXPORT qOpenGLVersionFlagsFromString(co QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_2_0; - QString minorVersion = versionString.section(QLatin1Char(' '), 0, 0).section(QLatin1Char('.'), 1, 1); - if (minorVersion == QChar(QLatin1Char('1'))) + if (versionString[2].toAscii() == '1') versionFlags |= QGLFormat::OpenGL_Version_2_1; } else if (versionString.startsWith(QLatin1String("3."))) { versionFlags |= QGLFormat::OpenGL_Version_1_1 | @@ -1167,6 +1250,14 @@ QGLFormat::OpenGLVersionFlags Q_AUTOTEST_EXPORT qOpenGLVersionFlagsFromString(co QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_3_0; + switch (versionString[2].toAscii()) { + case '2': + versionFlags |= QGLFormat::OpenGL_Version_3_2; + case '1': + versionFlags |= QGLFormat::OpenGL_Version_3_1; + default: + break; + } } else { qWarning("Unrecognised OpenGL version"); } @@ -1201,6 +1292,12 @@ QGLFormat::OpenGLVersionFlags Q_AUTOTEST_EXPORT qOpenGLVersionFlagsFromString(co \value OpenGL_Version_3_0 OpenGL version 3.0 or higher is present. + \value OpenGL_Version_3_1 OpenGL version 3.1 or higher is present. + Note that OpenGL version 3.1 or higher does not necessarily support all the features of + version 3.0 and lower. + + \value OpenGL_Version_3_2 OpenGL version 3.2 or higher is present. + \value OpenGL_ES_CommonLite_Version_1_0 OpenGL ES version 1.0 Common Lite or higher is present. \value OpenGL_ES_Common_Version_1_0 OpenGL ES version 1.0 Common or higher is present. diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 2076c46..d2fe5fb 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -144,6 +144,7 @@ namespace QGL DirectRendering = 0x0080, HasOverlay = 0x0100, SampleBuffers = 0x0200, + DeprecatedFunctions = 0x0400, SingleBuffer = DoubleBuffer << 16, NoDepthBuffer = DepthBuffer << 16, ColorIndex = Rgba << 16, @@ -153,7 +154,8 @@ namespace QGL NoStereoBuffers = StereoBuffers << 16, IndirectRendering = DirectRendering << 16, NoOverlay = HasOverlay << 16, - NoSampleBuffers = SampleBuffers << 16 + NoSampleBuffers = SampleBuffers << 16, + NoDeprecatedFunctions = DeprecatedFunctions << 16 }; Q_DECLARE_FLAGS(FormatOptions, FormatOption) } @@ -235,7 +237,20 @@ public: static bool hasOpenGL(); static bool hasOpenGLOverlays(); - enum OpenGLVersionFlag { + void setVersion(int major, int minor); + int majorVersion() const; + int minorVersion() const; + + enum OpenGLContextProfile { + NoProfile, + CoreProfile, + CompatibilityProfile + }; + + void setProfile(OpenGLContextProfile profile); + OpenGLContextProfile profile() const; + + enum OpenGLVersionFlag { OpenGL_Version_None = 0x00000000, OpenGL_Version_1_1 = 0x00000001, OpenGL_Version_1_2 = 0x00000002, @@ -249,7 +264,9 @@ public: OpenGL_ES_Common_Version_1_1 = 0x00000200, OpenGL_ES_CommonLite_Version_1_1 = 0x00000400, OpenGL_ES_Version_2_0 = 0x00000800, - OpenGL_Version_3_0 = 0x00001000 + OpenGL_Version_3_0 = 0x00001000, + OpenGL_Version_3_1 = 0x00002000, + OpenGL_Version_3_2 = 0x00004000 }; Q_DECLARE_FLAGS(OpenGLVersionFlags, OpenGLVersionFlag) diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 99c0f33..a075a31 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -132,11 +132,15 @@ public: QGLFormatPrivate() : ref(1) { - opts = QGL::DoubleBuffer | QGL::DepthBuffer | QGL::Rgba | QGL::DirectRendering | QGL::StencilBuffer; + opts = QGL::DoubleBuffer | QGL::DepthBuffer | QGL::Rgba | QGL::DirectRendering + | QGL::StencilBuffer | QGL::DeprecatedFunctions; pln = 0; depthSize = accumSize = stencilSize = redSize = greenSize = blueSize = alphaSize = -1; numSamples = -1; swapInterval = -1; + majorVersion = 1; + minorVersion = 0; + profile = QGLFormat::NoProfile; } QGLFormatPrivate(const QGLFormatPrivate *other) : ref(1), @@ -150,7 +154,10 @@ public: blueSize(other->blueSize), alphaSize(other->alphaSize), numSamples(other->numSamples), - swapInterval(other->swapInterval) + swapInterval(other->swapInterval), + majorVersion(other->majorVersion), + minorVersion(other->minorVersion), + profile(other->profile) { } QAtomicInt ref; @@ -165,6 +172,9 @@ public: int alphaSize; int numSamples; int swapInterval; + int majorVersion; + int minorVersion; + QGLFormat::OpenGLContextProfile profile; }; class QGLWidgetPrivate : public QWidgetPrivate @@ -277,6 +287,10 @@ public: void cleanup(); #if defined(Q_WS_WIN) + void updateFormatVersion(); +#endif + +#if defined(Q_WS_WIN) HGLRC rc; HDC dc; WId win; diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp index 5b5820a..c2170e0 100644 --- a/src/opengl/qgl_win.cpp +++ b/src/opengl/qgl_win.cpp @@ -122,6 +122,30 @@ typedef bool (APIENTRY *PFNWGLCHOOSEPIXELFORMATARB)(HDC hdc, #define WGL_TYPE_COLORINDEX_ARB 0x202C #endif +#ifndef WGL_ARB_create_context +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x0001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x0002 +// Error codes returned by GetLastError(). +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif + +#ifndef GL_VERSION_3_2 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 +#endif + QT_BEGIN_NAMESPACE class QGLCmapPrivate @@ -681,8 +705,118 @@ public: WId dmy_id; }; +static bool qgl_create_context(HDC hdc, QGLContextPrivate *d, QGLContextPrivate *shareContext) +{ + d->rc = 0; + + typedef HGLRC (APIENTRYP PFNWGLCREATECONTEXTATTRIBSARB)(HDC, HGLRC, const int *); + PFNWGLCREATECONTEXTATTRIBSARB wglCreateContextAttribsARB = + (PFNWGLCREATECONTEXTATTRIBSARB) wglGetProcAddress("wglCreateContextAttribsARB"); + if (wglCreateContextAttribsARB) { + int attributes[11]; + int attribIndex = 0; + const int major = d->reqFormat.majorVersion(); + const int minor = d->reqFormat.minorVersion(); + attributes[attribIndex++] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attributes[attribIndex++] = major; + attributes[attribIndex++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attributes[attribIndex++] = minor; + + if (major >= 3 && !d->reqFormat.testOption(QGL::DeprecatedFunctions)) { + attributes[attribIndex++] = WGL_CONTEXT_FLAGS_ARB; + attributes[attribIndex++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + } + + if ((major == 3 && minor >= 2) || major > 3) { + switch (d->reqFormat.profile()) { + case QGLFormat::NoProfile: + break; + case QGLFormat::CoreProfile: + attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB; + attributes[attribIndex++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + break; + case QGLFormat::CompatibilityProfile: + attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB; + attributes[attribIndex++] = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + break; + default: + qWarning("QGLContext::chooseContext(): Context profile not supported."); + return false; + } + } + + if (d->reqFormat.plane() != 0) { + attributes[attribIndex++] = WGL_CONTEXT_LAYER_PLANE_ARB; + attributes[attribIndex++] = d->reqFormat.plane(); + } + + attributes[attribIndex++] = 0; // Terminate list. + d->rc = wglCreateContextAttribsARB(hdc, shareContext && shareContext->valid + ? shareContext->rc : 0, attributes); + if (d->rc) { + if (shareContext) + shareContext->sharing = d->sharing = true; + return true; + } + } + + d->rc = wglCreateLayerContext(hdc, d->reqFormat.plane()); + if (d->rc && shareContext && shareContext->valid) + shareContext->sharing = d->sharing = wglShareLists(shareContext->rc, d->rc); + return d->rc != 0; +} + +void QGLContextPrivate::updateFormatVersion() +{ + const GLubyte *s = glGetString(GL_VERSION); + + if (!(s && s[0] >= '0' && s[0] <= '9' && s[1] == '.' && s[2] >= '0' && s[2] <= '9')) { + if (!s) + qWarning("QGLContext::chooseContext(): OpenGL version string is null."); + else + qWarning("QGLContext::chooseContext(): Unexpected OpenGL version string format."); + glFormat.setVersion(0, 0); + glFormat.setProfile(QGLFormat::NoProfile); + glFormat.setOption(QGL::DeprecatedFunctions); + return; + } + + int major = s[0] - '0'; + int minor = s[2] - '0'; + glFormat.setVersion(major, minor); + + if (major < 3) { + glFormat.setProfile(QGLFormat::NoProfile); + glFormat.setOption(QGL::DeprecatedFunctions); + } else { + GLint value = 0; + if (major > 3 || minor >= 2) + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); + + switch (value) { + case WGL_CONTEXT_CORE_PROFILE_BIT_ARB: + glFormat.setProfile(QGLFormat::CoreProfile); + break; + case WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: + glFormat.setProfile(QGLFormat::CompatibilityProfile); + break; + default: + glFormat.setProfile(QGLFormat::NoProfile); + break; + } + + glGetIntegerv(GL_CONTEXT_FLAGS, &value); + if (value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) + glFormat.setOption(QGL::NoDeprecatedFunctions); + else + glFormat.setOption(QGL::DeprecatedFunctions); + } +} + bool QGLContext::chooseContext(const QGLContext* shareContext) { + QGLContextPrivate *share = shareContext ? const_cast<QGLContext *>(shareContext)->d_func() : 0; + Q_D(QGLContext); // workaround for matrox driver: // make a cheap call to opengl to force loading of DLL @@ -740,8 +874,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) goto end; } - d->rc = wglCreateLayerContext(myDc, d->glFormat.plane()); - if (!d->rc) { + if (!qgl_create_context(myDc, d, share)) { qwglError("QGLContext::chooseContext()", "CreateLayerContext"); result = false; goto end; @@ -791,16 +924,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) d->cmap = new QGLCmap(1 << lpfd.cColorBits); d->cmap->setEntry(lpfd.crTransparent, qRgb(1, 2, 3));//, QGLCmap::Reserved); } - - if (shareContext && shareContext->isValid()) { - QGLContext *share = const_cast<QGLContext *>(shareContext); - d->sharing = (wglShareLists(shareContext->d_func()->rc, d->rc) != 0); - share->d_func()->sharing = d->sharing; - } - - goto end; - } - { + } else { PIXELFORMATDESCRIPTOR pfd; PIXELFORMATDESCRIPTOR realPfd; d->pixelFormatId = choosePixelFormat(&pfd, myDc); @@ -839,17 +963,12 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) goto end; } - if (!(d->rc = wglCreateLayerContext(myDc, 0))) { + if (!qgl_create_context(myDc, d, share)) { qwglError("QGLContext::chooseContext()", "wglCreateContext"); result = false; goto end; } - if (shareContext && shareContext->isValid()) { - d->sharing = (wglShareLists(shareContext->d_func()->rc, d->rc) != 0); - const_cast<QGLContext *>(shareContext)->d_func()->sharing = d->sharing; - } - if(!deviceIsPixmap()) { QRgb* pal = qgl_create_rgb_palette(&realPfd); if (pal) { @@ -864,6 +983,9 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) end: // vblanking wglMakeCurrent(myDc, d->rc); + if (d->rc) + d->updateFormatVersion(); + typedef BOOL (APIENTRYP PFNWGLSWAPINTERVALEXT) (int interval); typedef int (APIENTRYP PFNWGLGETSWAPINTERVALEXT) (void); PFNWGLSWAPINTERVALEXT wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXT) wglGetProcAddress("wglSwapIntervalEXT"); |