From 82d6518696cdfeec88b7bdbffccc5b1521c18785 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 26 Oct 2011 16:09:37 +0200 Subject: Windows: Fix Open GL formats. - Add swapInterval as additional format - Query context format correctly and store in separate struct (default vs requested/obtained) - Cosmetics, rename enumerations, structs. Change-Id: I381cf8e1bde33e6624feb549437c7b95dd85e93c Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowsglcontext.cpp | 197 ++++++++++++--------- src/plugins/platforms/windows/qwindowsglcontext.h | 28 ++- src/plugins/platforms/windows/qwindowswindow.cpp | 12 +- src/plugins/platforms/windows/qwindowswindow.h | 10 +- 4 files changed, 156 insertions(+), 91 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 27669da392..1685adccec 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -545,49 +545,6 @@ static QSurfaceFormat if (iValues[11]) additionalIn->formatFlags |= QWindowsGLOverlay; } - // Check version. Known to fail for some drivers - if (staticContext.majorVersion > 1) { - i = 0; - iAttributes[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB; // 0 - iAttributes[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; // 1 - if (staticContext.wglGetPixelFormatAttribIVARB(hdc, pixelFormat, 0, i, - iAttributes, iValues)) { - result.setMajorVersion(iValues[0]); - result.setMinorVersion(iValues[1]); - } else { - qErrnoWarning("%s: wglGetPixelFormatAttribIVARB() failed for version.", __FUNCTION__); - } - } - // Query flags from 3.2 onwards - if (staticContext.majorVersion > 3) { - i = 0; - iAttributes[i++] = WGL_CONTEXT_FLAGS_ARB; // 0 - if (staticContext.wglGetPixelFormatAttribIVARB(hdc, pixelFormat, 0, i, - iAttributes, iValues)) { - if (iValues[0] & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) - result.setOption(QSurfaceFormat::DeprecatedFunctions); - if (iValues[0] & WGL_CONTEXT_DEBUG_BIT_ARB) - result.setOption(QSurfaceFormat::DebugContext); - } else { - qErrnoWarning("%s: wglGetPixelFormatAttribIVARB() failed for context flags.", __FUNCTION__); - } - } - // Query profile from 3.2 onwards. Known to fail for some drivers - if ((staticContext.majorVersion == 3 && staticContext.minorVersion >= 2) - || staticContext.majorVersion > 3) { - i = 0; - iAttributes[i++] = WGL_CONTEXT_PROFILE_MASK_ARB; // 0 - if (staticContext.wglGetPixelFormatAttribIVARB(hdc, pixelFormat, 0, i, - iAttributes, iValues)) { - if (iValues[0] & WGL_CONTEXT_CORE_PROFILE_BIT_ARB) { - result.setProfile(QSurfaceFormat::CoreProfile); - } else if (iValues[0] & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) { - result.setProfile(QSurfaceFormat::CompatibilityProfile); - } - } else { - qErrnoWarning("%s: wglGetPixelFormatAttribIVARB() failed for profile mask.", __FUNCTION__); - } - } return result; } @@ -604,22 +561,14 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, int attributes[attribSize]; int attribIndex = 0; qFill(attributes, attributes + attribSize, int(0)); - - const int formatMajorVersion = format.majorVersion(); - const int formatMinorVersion = format.minorVersion(); - const bool versionRequested = formatMajorVersion != 1 || formatMinorVersion != 1; - const int majorVersion = versionRequested ? - formatMajorVersion : staticContext.majorVersion; - const int minorVersion = versionRequested ? - formatMinorVersion : staticContext.minorVersion; - - if (majorVersion > 1) { + const int requestedVersion = (format.majorVersion() << 8) + format.minorVersion(); + if (requestedVersion > 0x0101) { attributes[attribIndex++] = WGL_CONTEXT_MAJOR_VERSION_ARB; - attributes[attribIndex++] = majorVersion; + attributes[attribIndex++] = format.majorVersion(); attributes[attribIndex++] = WGL_CONTEXT_MINOR_VERSION_ARB; - attributes[attribIndex++] = minorVersion; + attributes[attribIndex++] = format.minorVersion(); } - if (majorVersion >= 3) { + if (requestedVersion >= 0x0300) { attributes[attribIndex++] = WGL_CONTEXT_FLAGS_ARB; attributes[attribIndex] = 0; if (format.testOption(QSurfaceFormat::DeprecatedFunctions)) @@ -628,8 +577,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, attributes[attribIndex++] |= WGL_CONTEXT_DEBUG_BIT_ARB; attribIndex++; } - if ((majorVersion == 3 && minorVersion >= 2) - || majorVersion > 3) { + if (requestedVersion >= 0x0302) { switch (format.profile()) { case QSurfaceFormat::NoProfile: break; @@ -645,7 +593,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, } if (QWindowsContext::verboseGL) qDebug("%s: Creating context version %d.%d with %d attributes", - __FUNCTION__, majorVersion, minorVersion, attribIndex / 2); + __FUNCTION__, format.majorVersion(), format.minorVersion(), attribIndex / 2); const HGLRC result = staticContext.wglCreateContextAttribsARB(hdc, shared, attributes); @@ -707,6 +655,85 @@ static inline QOpenGLContextData createDummyWindowOpenGLContextData() return result; } +/*! + \class QOpenGLContextFormat + \brief Format options that are related to the context (not pixelformats) + + Provides utility function to retrieve from currently active + context and to apply to a QSurfaceFormat. + + \ingroup qt-lighthouse-win +*/ + +QWindowsOpenGLContextFormat::QWindowsOpenGLContextFormat() : + profile(QSurfaceFormat::NoProfile), + version(0), + options(0) +{ +} + +QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() +{ + QWindowsOpenGLContextFormat result; + const QByteArray version = QOpenGLStaticContext::getGlString(GL_VERSION); + const int majorDot = version.indexOf('.'); + if (majorDot != -1) { + int minorDot = version.indexOf('.', majorDot + 1); + if (minorDot == -1) + minorDot = version.size(); + result.version = (version.mid(0, majorDot).toInt() << 8) + + version.mid(majorDot + 1, minorDot - majorDot - 1).toInt(); + } + if (result.version < 0x0300) { + result.profile = QSurfaceFormat::NoProfile; + result.options |= QSurfaceFormat::DeprecatedFunctions; + return result; + } + // v3 onwards + GLint value = 0; + glGetIntegerv(GL_CONTEXT_FLAGS, &value); + if (value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) + result.options |= QSurfaceFormat::DeprecatedFunctions; + if (value & WGL_CONTEXT_DEBUG_BIT_ARB) + result.options |= QSurfaceFormat::DebugContext; + if (result.version < 0x0302) + return result; + // v3.2 onwards: Profiles + value = 0; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); + switch (value) { + case WGL_CONTEXT_CORE_PROFILE_BIT_ARB: + result.profile = QSurfaceFormat::CoreProfile; + break; + case WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: + result.profile = QSurfaceFormat::CompatibilityProfile; + break; + default: + result.profile = QSurfaceFormat::NoProfile; + break; + } + return result; +} + +void QWindowsOpenGLContextFormat::apply(QSurfaceFormat *format) const +{ + format->setMajorVersion(version >> 8); + format->setMinorVersion(version & 0xFF); + format->setProfile(profile); + if (options & QSurfaceFormat::DebugContext) + format->setOption(QSurfaceFormat::DebugContext); + if (options & QSurfaceFormat::DeprecatedFunctions) + format->setOption(QSurfaceFormat::DeprecatedFunctions); +} + +QDebug operator<<(QDebug d, const QWindowsOpenGLContextFormat &f) +{ + d.nospace() << "ContextFormat: v" << (f.version >> 8) << '.' + << (f.version & 0xFF) << " profile: " << f.profile + << " options: " << f.options; + return d; +} + /*! \class QOpenGLTemporaryContext \brief A temporary context that can be instantiated on the stack. @@ -768,29 +795,17 @@ QOpenGLStaticContext::QOpenGLStaticContext() : vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)), renderer(QOpenGLStaticContext::getGlString(GL_RENDERER)), extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)), - majorVersion(0), minorVersion(0), extensions(0), + defaultFormat(QWindowsOpenGLContextFormat::current()), wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)wglGetProcAddress("wglGetPixelFormatAttribivARB")), wglChoosePixelFormatARB((WglChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB")), - wglCreateContextAttribsARB((WglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB")) + wglCreateContextAttribsARB((WglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB")), + wglSwapInternalExt((WglSwapInternalExt)wglGetProcAddress("wglSwapIntervalEXT")), + wglGetSwapInternalExt((WglGetSwapInternalExt)wglGetProcAddress("wglGetSwapIntervalEXT")) { if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION" ") || extensionNames.indexOf(" "SAMPLE_BUFFER_EXTENSION" ") != -1) extensions |= SampleBuffers; - // Get version - do { - const QByteArray version = QOpenGLStaticContext::getGlString(GL_VERSION); - if (version.isEmpty()) - break; - const int majorDot = version.indexOf('.'); - if (majorDot == -1) - break; - int minorDot = version.indexOf('.', majorDot + 1); - if (minorDot == -1) - minorDot = version.size(); - majorVersion = version.mid(0, majorDot).toInt(); - minorVersion = version.mid(majorDot + 1, minorDot - majorDot - 1).toInt(); - } while (false); } QByteArray QOpenGLStaticContext::getGlString(unsigned int which) @@ -815,13 +830,15 @@ QOpenGLStaticContext *QOpenGLStaticContext::create() QDebug operator<<(QDebug d, const QOpenGLStaticContext &s) { QDebug nsp = d.nospace(); - nsp << "OpenGL: " << s.vendor << ',' << s.renderer << ",v" - << s.majorVersion << '.' << s.minorVersion; + nsp << "OpenGL: " << s.vendor << ',' << s.renderer << " default " + << s.defaultFormat; if (s.extensions & QOpenGLStaticContext::SampleBuffers) nsp << ",SampleBuffers"; if (s.hasExtensions()) nsp << ", Extension-API present"; - nsp << "\nExtensions: " << s.extensionNames; + nsp << "\nExtensions: " << (s.extensionNames.count(' ') + 1); + if (QWindowsContext::verboseGL > 1) + nsp << s.extensionNames; return d; } @@ -872,6 +889,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex HWND dummyWindow = 0; HDC hdc = 0; bool tryExtensions = false; + int obtainedSwapInternal = -1; do { dummyWindow = createDummyGLWindow(); if (!dummyWindow) @@ -934,6 +952,21 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex qWarning("Unable to create a GL Context."); break; } + + // Query obtained parameters and apply swap interval. + if (!wglMakeCurrent(hdc, m_renderingContext)) { + qWarning("Failed to make context current."); + break; + } + + QWindowsOpenGLContextFormat::current().apply(&m_obtainedFormat); + + if (requestedAdditional.swapInterval != -1 && m_staticContext->wglSwapInternalExt) { + m_staticContext->wglSwapInternalExt(requestedAdditional.swapInterval); + if (m_staticContext->wglGetSwapInternalExt) + obtainedSwapInternal = m_staticContext->wglGetSwapInternalExt(); + } + wglMakeCurrent(0, 0); } while (false); if (hdc) ReleaseDC(dummyWindow, hdc); @@ -945,6 +978,8 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex << " requested: " << context->format() << "\n obtained #" << m_pixelFormat << (m_extensionsUsed ? "ARB" : "GDI") << m_obtainedFormat << "\n " << m_obtainedPixelFormatDescriptor + << " swap interval: " << obtainedSwapInternal + << "\n default: " << m_staticContext->defaultFormat << "\n HGLRC=" << m_renderingContext; } @@ -1012,13 +1047,15 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) return false; // Initialize pixel format first time. This will apply to // the HWND as well and must be done only once. - if (!window->testFlag(QWindowsWindow::PixelFormatInitialized)) { + if (!window->testFlag(QWindowsWindow::OpenGlPixelFormatInitialized)) { if (!SetPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { qErrnoWarning("%s: SetPixelFormat() failed", __FUNCTION__); ReleaseDC(newContext.hwnd, newContext.hdc); return false; } - window->setFlag(QWindowsWindow::PixelFormatInitialized); + window->setFlag(QWindowsWindow::OpenGlPixelFormatInitialized); + if (m_obtainedFormat.swapBehavior() == QSurfaceFormat::DoubleBuffer) + window->setFlag(QWindowsWindow::OpenGLDoubleBuffered); } m_windowContexts.append(newContext); return wglMakeCurrent(newContext.hdc, newContext.renderingContext); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index aa839d1fcd..f2784f3d9b 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -64,10 +64,11 @@ enum QWindowsGLFormatFlags // Additional format information for Windows. struct QWindowsOpenGLAdditionalFormat { - QWindowsOpenGLAdditionalFormat(unsigned formatFlagsIn = 0, unsigned pixmapDepthIn = 0) : - formatFlags(formatFlagsIn), pixmapDepth(pixmapDepthIn) {} + QWindowsOpenGLAdditionalFormat(unsigned formatFlagsIn = 0, unsigned pixmapDepthIn = 0, unsigned swapIntervalIn = -1) : + formatFlags(formatFlagsIn), pixmapDepth(pixmapDepthIn), swapInterval(swapIntervalIn) {} unsigned formatFlags; // QWindowsGLFormatFlags. unsigned pixmapDepth; // for QWindowsGLRenderToPixmap + int swapInterval; }; // Per-window data for active OpenGL contexts. @@ -81,6 +82,19 @@ struct QOpenGLContextData HDC hdc; }; +struct QWindowsOpenGLContextFormat +{ + QWindowsOpenGLContextFormat(); + static QWindowsOpenGLContextFormat current(); + void apply(QSurfaceFormat *format) const; + + QSurfaceFormat::OpenGLContextProfile profile; + int version; //! majorVersion<<8 + minorVersion + QSurfaceFormat::FormatOptions options; +}; + +QDebug operator<<(QDebug d, const QWindowsOpenGLContextFormat &); + class QOpenGLStaticContext { Q_DISABLE_COPY(QOpenGLStaticContext) @@ -104,6 +118,11 @@ public: typedef HGLRC (APIENTRY *WglCreateContextAttribsARB)(HDC, HGLRC, const int *); + typedef BOOL + (APIENTRY *WglSwapInternalExt)(int interval); + typedef int + (APIENTRY *WglGetSwapInternalExt)(void); + bool hasExtensions() const { return wglGetPixelFormatAttribIVARB && wglChoosePixelFormatARB && wglCreateContextAttribsARB; } @@ -113,13 +132,14 @@ public: const QByteArray vendor; const QByteArray renderer; const QByteArray extensionNames; - int majorVersion; - int minorVersion; unsigned extensions; + const QWindowsOpenGLContextFormat defaultFormat; WglGetPixelFormatAttribIVARB wglGetPixelFormatAttribIVARB; WglChoosePixelFormatARB wglChoosePixelFormatARB; WglCreateContextAttribsARB wglCreateContextAttribsARB; + WglSwapInternalExt wglSwapInternalExt; + WglGetSwapInternalExt wglGetSwapInternalExt; }; QDebug operator<<(QDebug d, const QOpenGLStaticContext &); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 4b03fe6c9e..ef5c2ae246 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -617,7 +617,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : m_dropTarget(0) { if (aWindow->surfaceType() == QWindow::OpenGLSurface) - setFlag(OpenGL_Surface); + setFlag(OpenGLSurface); QWindowsContext::instance()->addWindow(m_data.hwnd, this); if (aWindow->isTopLevel()) { switch (aWindow->windowType()) { @@ -779,9 +779,14 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const parentHWND = parentW->handle(); } + const bool wasTopLevel = window()->isTopLevel(); const bool isTopLevel = parentHWND == 0; + + setFlag(WithinSetParent); SetParent(m_data.hwnd, parentHWND); + clearFlag(WithinSetParent); + // WS_CHILD/WS_POPUP must be manually set/cleared in addition // to dialog frames, etc (see SetParent() ) if the top level state changes. if (wasTopLevel != isTopLevel) { @@ -841,7 +846,8 @@ void QWindowsWindow::setGeometry(const QRect &rect) void QWindowsWindow::handleMoved() { - if (!IsIconic(m_data.hwnd)) // Minimize can send nonsensical move events. + // Minimize/Set parent can send nonsensical move events. + if (!IsIconic(m_data.hwnd) && !testFlag(WithinSetParent)) handleGeometryChange(); } @@ -940,7 +946,7 @@ void QWindowsWindow::handleWmPaint(HWND hwnd, UINT, WPARAM, LPARAM) { PAINTSTRUCT ps; - if (testFlag(OpenGL_Surface)) { + if (testFlag(OpenGLSurface)) { BeginPaint(hwnd, &ps); // WM_ERASEBKGND needs to be handled. EndPaint(hwnd, &ps); } else { diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 42fff8b362..2aaf722277 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -95,10 +95,12 @@ class QWindowsWindow : public QPlatformWindow public: enum Flags { - OpenGL_Surface = 0x1, - WithinWmPaint = 0x2, - PixelFormatInitialized = 0x4, - FrameDirty = 0x8 //! Frame outdated by setStyle, recalculate in next query. + WithinWmPaint = 0x1, + WithinSetParent = 0x2, + FrameDirty = 0x4, //! Frame outdated by setStyle, recalculate in next query. + OpenGLSurface = 0x10, + OpenGLDoubleBuffered = 0x20, + OpenGlPixelFormatInitialized = 0x40 }; struct WindowData -- cgit v1.2.3