diff options
Diffstat (limited to 'src/plugins/platforms/windows/qwindowsglcontext.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowsglcontext.cpp | 191 |
1 files changed, 71 insertions, 120 deletions
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index d9521e7e08..5ca52c2c19 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qwindowsglcontext.h" #include "qwindowscontext.h" @@ -44,10 +8,10 @@ #include <QtCore/qdebug.h> #include <QtCore/qsysinfo.h> +#include <QtGui/qcolorspace.h> #include <QtGui/qguiapplication.h> #include <qpa/qplatformnativeinterface.h> -#include <QtPlatformHeaders/qwglnativecontext.h> - +#include <private/qsystemlibrary_p.h> #include <algorithm> #include <wingdi.h> @@ -162,19 +126,25 @@ QFunctionPointer QWindowsOpengl32DLL::resolve(const char *name) bool QWindowsOpengl32DLL::init(bool softwareRendering) { - const QByteArray opengl32 = QByteArrayLiteral("opengl32.dll"); - const QByteArray swopengl = QByteArrayLiteral("opengl32sw.dll"); + const QByteArray opengl32 = QByteArrayLiteral("opengl32"); + const QByteArray swopengl = QByteArrayLiteral("opengl32sw"); + bool useSystemLib = false; QByteArray openglDll = qgetenv("QT_OPENGL_DLL"); - if (openglDll.isEmpty()) + if (openglDll.isEmpty()) { openglDll = softwareRendering ? swopengl : opengl32; + useSystemLib = !softwareRendering; + } openglDll = openglDll.toLower(); m_nonOpengl32 = openglDll != opengl32; qCDebug(lcQpaGl) << "Qt: Using WGL and OpenGL from" << openglDll; - m_lib = ::LoadLibraryA(openglDll.constData()); + if (useSystemLib) + m_lib = QSystemLibrary::load((wchar_t*)(QString::fromLatin1(openglDll).utf16())); + else + m_lib = LoadLibraryA(openglDll.constData()); if (!m_lib) { qErrnoWarning(::GetLastError(), "Failed to load %s", openglDll.constData()); return false; @@ -184,7 +154,7 @@ bool QWindowsOpengl32DLL::init(bool softwareRendering) // Load opengl32.dll always. GDI functions like ChoosePixelFormat do // GetModuleHandle for opengl32.dll and behave differently (and call back into // opengl32) when the module is present. This is fine for dummy contexts and windows. - ::LoadLibraryA("opengl32.dll"); + QSystemLibrary::load(L"opengl32"); } wglCreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(resolve("wglCreateContext")); @@ -225,6 +195,11 @@ QWindowsOpenGLContext *QOpenGLStaticContext::createContext(QOpenGLContext *conte return new QWindowsGLContext(this, context); } +QWindowsOpenGLContext *QOpenGLStaticContext::createContext(HGLRC context, HWND window) +{ + return new QWindowsGLContext(this, context, window); +} + template <class MaskType, class FlagType> inline bool testFlag(MaskType mask, FlagType flag) { return (mask & MaskType(flag)) != 0; @@ -569,11 +544,14 @@ static int choosePixelFormat(HDC hdc, iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB; iAttributes[i++] = 1; } + // must be the one before the last one const int samples = format.samples(); const bool sampleBuffersRequested = samples > 1 && testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers); + int sampleBuffersKeyPosition = 0; int samplesValuePosition = 0; if (sampleBuffersRequested) { + sampleBuffersKeyPosition = i; iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; iAttributes[i++] = TRUE; iAttributes[i++] = WGL_SAMPLES_ARB; @@ -584,10 +562,10 @@ static int choosePixelFormat(HDC hdc, iAttributes[i++] = FALSE; } // must be the last - bool srgbRequested = format.colorSpace() == QSurfaceFormat::sRGBColorSpace; - int srgbValuePosition = 0; + bool srgbRequested = format.colorSpace() == QColorSpace::SRgb; + int srgbCapableKeyPosition = 0; if (srgbRequested) { - srgbValuePosition = i; + srgbCapableKeyPosition = i; iAttributes[i++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT; iAttributes[i++] = TRUE; } @@ -601,8 +579,9 @@ static int choosePixelFormat(HDC hdc, && numFormats >= 1; if (valid || (!sampleBuffersRequested && !srgbRequested)) break; + // NB reductions must be done in reverse order (disable the last first, then move on to the one before that, etc.) if (srgbRequested) { - iAttributes[srgbValuePosition] = 0; + iAttributes[srgbCapableKeyPosition] = 0; srgbRequested = false; } else if (sampleBuffersRequested) { if (iAttributes[samplesValuePosition] > 1) { @@ -610,11 +589,8 @@ static int choosePixelFormat(HDC hdc, } else if (iAttributes[samplesValuePosition] == 1) { // Fallback in case it is unable to initialize with any // samples to avoid falling back to the GDI path - // NB: The sample attributes needs to be at the end for this - // to work correctly - iAttributes[samplesValuePosition - 1] = FALSE; + iAttributes[sampleBuffersKeyPosition] = 0; iAttributes[samplesValuePosition] = 0; - iAttributes[samplesValuePosition + 1] = 0; } else { break; } @@ -706,10 +682,10 @@ static QSurfaceFormat if (hasSampleBuffers) { result.setSamples(iValues[13]); if (hasSrgbSupport && iValues[14]) - result.setColorSpace(QSurfaceFormat::sRGBColorSpace); + result.setColorSpace(QColorSpace::SRgb); } else { if (hasSrgbSupport && iValues[12]) - result.setColorSpace(QSurfaceFormat::sRGBColorSpace); + result.setColorSpace(QColorSpace::SRgb); } if (additionalIn) { if (iValues[7]) @@ -802,7 +778,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, static inline HWND createDummyGLWindow() { return QWindowsContext::instance()-> - createDummyWindow(QStringLiteral("QtOpenGLDummyWindow"), + createDummyWindow(QStringLiteral("OpenGLDummyWindow"), L"OpenGLDummyWindow", nullptr, WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); } @@ -858,7 +834,6 @@ static inline QOpenGLContextData createDummyWindowOpenGLContextData() context and to apply to a QSurfaceFormat. \internal - \ingroup qt-lighthouse-win */ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() @@ -913,7 +888,6 @@ void QWindowsOpenGLContextFormat::apply(QSurfaceFormat *format) const is a current GL context. \internal - \ingroup qt-lighthouse-win */ class QOpenGLTemporaryContext @@ -946,7 +920,6 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext() /*! \class QWindowsOpenGLAdditionalFormat \brief Additional format information that is not in QSurfaceFormat - \ingroup qt-lighthouse-win */ /*! @@ -964,7 +937,6 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext() \sa QWindowsGLContext \internal - \ingroup qt-lighthouse-win */ #define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample" @@ -1051,66 +1023,15 @@ QOpenGLStaticContext *QOpenGLStaticContext::create(bool softwareRendering) QOpenGLContextData and are released in doneCurrent(). \internal - \ingroup qt-lighthouse-win */ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context) : - m_staticContext(staticContext), - m_context(context), - m_renderingContext(nullptr), - m_pixelFormat(0), - m_extensionsUsed(false), - m_swapInterval(-1), - m_ownsContext(true), - m_getGraphicsResetStatus(nullptr), - m_lost(false) + m_staticContext(staticContext) { if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false. return; - QVariant nativeHandle = context->nativeHandle(); - if (!nativeHandle.isNull()) { - // Adopt and existing context. - if (!nativeHandle.canConvert<QWGLNativeContext>()) { - qWarning("QWindowsGLContext: Requires a QWGLNativeContext"); - return; - } - auto handle = nativeHandle.value<QWGLNativeContext>(); - HGLRC wglcontext = handle.context(); - HWND wnd = handle.window(); - if (!wglcontext || !wnd) { - qWarning("QWindowsGLContext: No context and window given"); - return; - } - - HDC dc = GetDC(wnd); - // A window with an associated pixel format is mandatory. - // When no SetPixelFormat() call has been made, the following will fail. - m_pixelFormat = GetPixelFormat(dc); - bool ok = m_pixelFormat != 0; - if (!ok) - qWarning("QWindowsGLContext: Failed to get pixel format"); - ok = DescribePixelFormat(dc, m_pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &m_obtainedPixelFormatDescriptor); - if (!ok) { - qWarning("QWindowsGLContext: Failed to describe pixel format"); - } else { - QWindowsOpenGLAdditionalFormat obtainedAdditional; - m_obtainedFormat = GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor, &obtainedAdditional); - m_renderingContext = wglcontext; - ok = updateObtainedParams(dc); - } - - ReleaseDC(wnd, dc); - - if (ok) - m_ownsContext = false; - else - m_renderingContext = nullptr; - - return; - } - QSurfaceFormat format = context->format(); if (format.renderableType() == QSurfaceFormat::DefaultRenderableType) format.setRenderableType(QSurfaceFormat::OpenGL); @@ -1212,11 +1133,6 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, } while (false); - // Make the HGLRC retrievable via QOpenGLContext::nativeHandle(). - // Do not provide the window since it is the dummy one and it is about to disappear. - if (m_renderingContext) - context->setNativeHandle(QVariant::fromValue<QWGLNativeContext>(QWGLNativeContext(m_renderingContext, nullptr))); - if (hdc) ReleaseDC(dummyWindow, hdc); if (dummyWindow) @@ -1230,6 +1146,37 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, << "\n HGLRC=" << m_renderingContext; } +QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, HGLRC wglcontext, HWND wnd) + : m_staticContext(staticContext) +{ + if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false. + return; + + HDC dc = GetDC(wnd); + // A window with an associated pixel format is mandatory. + // When no SetPixelFormat() call has been made, the following will fail. + m_pixelFormat = GetPixelFormat(dc); + bool ok = m_pixelFormat != 0; + if (!ok) + qWarning("QWindowsGLContext: Failed to get pixel format"); + ok = DescribePixelFormat(dc, m_pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &m_obtainedPixelFormatDescriptor); + if (!ok) { + qWarning("QWindowsGLContext: Failed to describe pixel format"); + } else { + QWindowsOpenGLAdditionalFormat obtainedAdditional; + m_obtainedFormat = GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor, &obtainedAdditional); + m_renderingContext = wglcontext; + ok = updateObtainedParams(dc); + } + + ReleaseDC(wnd, dc); + + if (ok) + m_ownsContext = false; + else + m_renderingContext = nullptr; +} + QWindowsGLContext::~QWindowsGLContext() { if (m_renderingContext && m_ownsContext) @@ -1315,17 +1262,19 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) // Do we already have a DC entry for that window? auto *window = static_cast<QWindowsWindow *>(surface); - window->aboutToMakeCurrent(); const HWND hwnd = window->handle(); if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, hwnd)) { // Repeated calls to wglMakeCurrent when vsync is enabled in the driver will // often result in 100% cpuload. This check is cheap and avoids the problem. - // This is reproducable on NVidia cards and Intel onboard chips. + // This is reproducible on NVidia cards and Intel onboard chips. if (QOpenGLStaticContext::opengl32.wglGetCurrentContext() == contextData->renderingContext && QOpenGLStaticContext::opengl32.wglGetCurrentDC() == contextData->hdc) { return true; } - return QOpenGLStaticContext::opengl32.wglMakeCurrent(contextData->hdc, contextData->renderingContext); + const bool success = QOpenGLStaticContext::opengl32.wglMakeCurrent(contextData->hdc, contextData->renderingContext); + if (!success) + qErrnoWarning("%s: wglMakeCurrent() failed for existing context data", __FUNCTION__); + return success; } // Create a new entry. const QOpenGLContextData newContext(m_renderingContext, hwnd, GetDC(hwnd)); @@ -1353,6 +1302,8 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) qCDebug(lcQpaGl) << "makeCurrent(): context loss detected" << this; // Drop the surface. Will recreate on the next makeCurrent. window->invalidateSurface(); + } else { + qErrnoWarning("%s: wglMakeCurrent() failed", __FUNCTION__); } } |