Windows: Fix Open GL formats.
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>
Wed, 26 Oct 2011 14:09:37 +0000 (16:09 +0200)
committerQt by Nokia <qt-info@nokia.com>
Wed, 26 Oct 2011 16:06:39 +0000 (18:06 +0200)
- 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 <Friedemann.Kleint@nokia.com>
src/plugins/platforms/windows/qwindowsglcontext.cpp
src/plugins/platforms/windows/qwindowsglcontext.h
src/plugins/platforms/windows/qwindowswindow.cpp
src/plugins/platforms/windows/qwindowswindow.h

index 27669da..1685adc 100644 (file)
@@ -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);
@@ -708,6 +656,85 @@ static inline QOpenGLContextData createDummyWindowOpenGLContextData()
 }
 
 /*!
+    \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);
index aa839d1..f2784f3 100644 (file)
@@ -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 &);
index 4b03fe6..ef5c2ae 100644 (file)
@@ -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 {
index 42fff8b..2aaf722 100644 (file)
@@ -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