qtbase/src/plugins/platforms/windows/qwindowsopengltester.cpp

425 lines
17 KiB
C++
Raw Normal View History

Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qwindowsopengltester.h"
#include "qwindowscontext.h"
#include <QtCore/QVariantMap>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QStandardPaths>
#include <QtCore/QLibraryInfo>
#include <QtCore/QHash>
#ifndef QT_NO_OPENGL
#include <private/qopengl_p.h>
#endif
#ifndef Q_OS_WINCE
# include <QtCore/qt_windows.h>
# include <private/qsystemlibrary_p.h>
# include <d3d9.h>
#endif
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
QT_BEGIN_NAMESPACE
GpuDescription GpuDescription::detect()
{
#ifndef Q_OS_WINCE
typedef IDirect3D9 * (WINAPI *PtrDirect3DCreate9)(UINT);
GpuDescription result;
QSystemLibrary d3d9lib(QStringLiteral("d3d9"));
if (!d3d9lib.load())
return result;
PtrDirect3DCreate9 direct3DCreate9 = (PtrDirect3DCreate9)d3d9lib.resolve("Direct3DCreate9");
if (!direct3DCreate9)
return result;
IDirect3D9 *direct3D9 = direct3DCreate9(D3D_SDK_VERSION);
if (!direct3D9)
return result;
D3DADAPTER_IDENTIFIER9 adapterIdentifier;
const HRESULT hr = direct3D9->GetAdapterIdentifier(0, 0, &adapterIdentifier);
direct3D9->Release();
if (SUCCEEDED(hr)) {
result.vendorId = int(adapterIdentifier.VendorId);
result.deviceId = int(adapterIdentifier.DeviceId);
result.revision = int(adapterIdentifier.Revision);
result.subSysId = int(adapterIdentifier.SubSysId);
QVector<int> version(4, 0);
version[0] = HIWORD(adapterIdentifier.DriverVersion.HighPart); // Product
version[1] = LOWORD(adapterIdentifier.DriverVersion.HighPart); // Version
version[2] = HIWORD(adapterIdentifier.DriverVersion.LowPart); // Sub version
version[3] = LOWORD(adapterIdentifier.DriverVersion.LowPart); // build
result.driverVersion = QVersionNumber(version);
result.driverName = adapterIdentifier.Driver;
result.description = adapterIdentifier.Description;
}
return result;
#else // !Q_OS_WINCE
GpuDescription result;
result.vendorId = result.deviceId = result.revision =1;
result.driverVersion = QVersionNumber(1, 1, 1);
result.driverName = result.description = QByteArrayLiteral("Generic");
return result;
#endif
}
QDebug operator<<(QDebug d, const GpuDescription &gd)
{
QDebugStateSaver s(d);
d.nospace();
d << hex << showbase << "GpuDescription(vendorId=" << gd.vendorId
<< ", deviceId=" << gd.deviceId << ", subSysId=" << gd.subSysId
<< dec << noshowbase << ", revision=" << gd.revision
<< ", driver: " << gd.driverName
<< ", version=" << gd.driverVersion << ", " << gd.description << ')';
return d;
}
// Return printable string formatted like the output of the dxdiag tool.
QString GpuDescription::toString() const
{
QString result;
QTextStream str(&result);
str << " Card name: " << description
<< "\n Driver Name: " << driverName
<< "\n Driver Version: " << driverVersion.toString()
<< "\n Vendor ID: 0x" << qSetPadChar(QLatin1Char('0'))
<< uppercasedigits << hex << qSetFieldWidth(4) << vendorId
<< "\n Device ID: 0x" << qSetFieldWidth(4) << deviceId
<< "\n SubSys ID: 0x" << qSetFieldWidth(8) << subSysId
<< "\n Revision ID: 0x" << qSetFieldWidth(4) << revision
<< dec;
return result;
}
QVariant GpuDescription::toVariant() const
{
QVariantMap result;
result.insert(QStringLiteral("vendorId"), QVariant(vendorId));
result.insert(QStringLiteral("deviceId"), QVariant(deviceId));
result.insert(QStringLiteral("subSysId"),QVariant(subSysId));
result.insert(QStringLiteral("revision"), QVariant(revision));
result.insert(QStringLiteral("driver"), QVariant(QLatin1String(driverName)));
result.insert(QStringLiteral("driverProduct"), QVariant(driverVersion.segmentAt(0)));
result.insert(QStringLiteral("driverVersion"), QVariant(driverVersion.segmentAt(1)));
result.insert(QStringLiteral("driverSubVersion"), QVariant(driverVersion.segmentAt(2)));
result.insert(QStringLiteral("driverBuild"), QVariant(driverVersion.segmentAt(3)));
result.insert(QStringLiteral("driverVersionString"), driverVersion.toString());
result.insert(QStringLiteral("description"), QVariant(QLatin1String(description)));
result.insert(QStringLiteral("printable"), QVariant(toString()));
return result;
}
QWindowsOpenGLTester::Renderer QWindowsOpenGLTester::requestedGlesRenderer()
{
#ifndef Q_OS_WINCE
const char platformVar[] = "QT_ANGLE_PLATFORM";
if (qEnvironmentVariableIsSet(platformVar)) {
const QByteArray anglePlatform = qgetenv(platformVar);
if (anglePlatform == "d3d11")
return QWindowsOpenGLTester::AngleRendererD3d11;
if (anglePlatform == "d3d9")
return QWindowsOpenGLTester::AngleRendererD3d9;
if (anglePlatform == "warp")
return QWindowsOpenGLTester::AngleRendererD3d11Warp;
qCWarning(lcQpaGl) << "Invalid value set for " << platformVar << ": " << anglePlatform;
}
#endif // !Q_OS_WINCE
return QWindowsOpenGLTester::InvalidRenderer;
}
QWindowsOpenGLTester::Renderer QWindowsOpenGLTester::requestedRenderer()
{
#ifndef Q_OS_WINCE
const char openGlVar[] = "QT_OPENGL";
if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES)) {
const Renderer glesRenderer = QWindowsOpenGLTester::requestedGlesRenderer();
return glesRenderer != InvalidRenderer ? glesRenderer : Gles;
}
if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL))
return QWindowsOpenGLTester::DesktopGl;
if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL))
return QWindowsOpenGLTester::SoftwareRasterizer;
if (qEnvironmentVariableIsSet(openGlVar)) {
const QByteArray requested = qgetenv(openGlVar);
if (requested == "angle") {
const Renderer glesRenderer = QWindowsOpenGLTester::requestedGlesRenderer();
return glesRenderer != InvalidRenderer ? glesRenderer : Gles;
}
if (requested == "desktop")
return QWindowsOpenGLTester::DesktopGl;
if (requested == "software")
return QWindowsOpenGLTester::SoftwareRasterizer;
qCWarning(lcQpaGl) << "Invalid value set for " << openGlVar << ": " << requested;
}
#endif // !Q_OS_WINCE
return QWindowsOpenGLTester::InvalidRenderer;
}
#ifndef Q_OS_WINCE
static inline QString resolveBugListFile(const QString &fileName)
{
if (QFileInfo(fileName).isAbsolute())
return fileName;
// Try QLibraryInfo::SettingsPath which is typically empty unless specified in qt.conf,
// then resolve via QStandardPaths::ConfigLocation.
const QString settingsPath = QLibraryInfo::location(QLibraryInfo::SettingsPath);
if (!settingsPath.isEmpty()) { // SettingsPath is empty unless specified in qt.conf.
const QFileInfo fi(settingsPath + QLatin1Char('/') + fileName);
if (fi.isFile())
return fi.absoluteFilePath();
}
return QStandardPaths::locate(QStandardPaths::ConfigLocation, fileName);
}
# ifndef QT_NO_OPENGL
typedef QHash<QOpenGLConfig::Gpu, QWindowsOpenGLTester::Renderers> SupportedRenderersCache;
Q_GLOBAL_STATIC(SupportedRenderersCache, supportedRenderersCache)
# endif
#endif // !Q_OS_WINCE
QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(const GpuDescription &gpu, bool glesOnly)
{
Q_UNUSED(gpu)
Q_UNUSED(glesOnly)
#if defined(QT_NO_OPENGL)
return 0;
#elif defined(Q_OS_WINCE)
return QWindowsOpenGLTester::Gles;
#else
QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.deviceId, gpu.vendorId, gpu.driverVersion, gpu.description);
SupportedRenderersCache *srCache = supportedRenderersCache();
SupportedRenderersCache::const_iterator it = srCache->find(qgpu);
if (it != srCache->cend())
return *it;
QWindowsOpenGLTester::Renderers result(QWindowsOpenGLTester::AngleRendererD3d11
| QWindowsOpenGLTester::AngleRendererD3d9
| QWindowsOpenGLTester::AngleRendererD3d11Warp
| QWindowsOpenGLTester::SoftwareRasterizer);
if (!glesOnly && testDesktopGL())
result |= QWindowsOpenGLTester::DesktopGl;
QSet<QString> features;
const char bugListFileVar[] = "QT_OPENGL_BUGLIST";
if (qEnvironmentVariableIsSet(bugListFileVar)) {
const QString fileName = resolveBugListFile(QFile::decodeName(qgetenv(bugListFileVar)));
if (!fileName.isEmpty())
features = QOpenGLConfig::gpuFeatures(qgpu, fileName);
} else {
features = QOpenGLConfig::gpuFeatures(qgpu, QStringLiteral(":/qt-project.org/windows/openglblacklists/default.json"));
}
qCDebug(lcQpaGl) << "GPU features:" << features;
if (features.contains(QStringLiteral("disable_desktopgl"))) { // Qt-specific
qCDebug(lcQpaGl) << "Disabling Desktop GL: " << gpu;
result &= ~QWindowsOpenGLTester::DesktopGl;
}
if (features.contains(QStringLiteral("disable_angle"))) { // Qt-specific keyword
qCDebug(lcQpaGl) << "Disabling ANGLE: " << gpu;
result &= ~QWindowsOpenGLTester::GlesMask;
} else {
if (features.contains(QStringLiteral("disable_d3d11"))) { // standard keyword
qCDebug(lcQpaGl) << "Disabling D3D11: " << gpu;
result &= ~QWindowsOpenGLTester::AngleRendererD3d11;
}
if (features.contains(QStringLiteral("disable_d3d9"))) { // Qt-specific
qCDebug(lcQpaGl) << "Disabling D3D9: " << gpu;
result &= ~QWindowsOpenGLTester::AngleRendererD3d9;
}
}
srCache->insert(qgpu, result);
return result;
#endif // !Q_OS_WINCE && !QT_NO_OPENGL
}
QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedGlesRenderers()
{
const GpuDescription gpu = GpuDescription::detect();
const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, true);
qDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result;
return result;
}
QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers()
{
const GpuDescription gpu = GpuDescription::detect();
const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, false);
qDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result;
return result;
}
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
bool QWindowsOpenGLTester::testDesktopGL()
{
#if !defined(QT_NO_OPENGL) && !defined(Q_OS_WINCE)
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
HMODULE lib = 0;
HWND wnd = 0;
HDC dc = 0;
HGLRC context = 0;
LPCTSTR className = L"qtopengltest";
HGLRC (WINAPI * CreateContext)(HDC dc) = 0;
BOOL (WINAPI * DeleteContext)(HGLRC context) = 0;
BOOL (WINAPI * MakeCurrent)(HDC dc, HGLRC context) = 0;
PROC (WINAPI * WGL_GetProcAddress)(LPCSTR name) = 0;
bool result = false;
// Test #1: Load opengl32.dll and try to resolve an OpenGL 2 function.
// This will typically fail on systems that do not have a real OpenGL driver.
lib = LoadLibraryA("opengl32.dll");
if (lib) {
CreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(::GetProcAddress(lib, "wglCreateContext"));
if (!CreateContext)
goto cleanup;
DeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(::GetProcAddress(lib, "wglDeleteContext"));
if (!DeleteContext)
goto cleanup;
MakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(::GetProcAddress(lib, "wglMakeCurrent"));
if (!MakeCurrent)
goto cleanup;
WGL_GetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(::GetProcAddress(lib, "wglGetProcAddress"));
if (!WGL_GetProcAddress)
goto cleanup;
WNDCLASS wclass;
wclass.cbClsExtra = 0;
wclass.cbWndExtra = 0;
wclass.hInstance = (HINSTANCE) GetModuleHandle(0);
wclass.hIcon = 0;
wclass.hCursor = 0;
wclass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND);
wclass.lpszMenuName = 0;
wclass.lpfnWndProc = DefWindowProc;
wclass.lpszClassName = className;
wclass.style = CS_OWNDC;
if (!RegisterClass(&wclass))
goto cleanup;
wnd = CreateWindow(className, L"qtopenglproxytest", WS_OVERLAPPED,
0, 0, 640, 480, 0, 0, wclass.hInstance, 0);
if (!wnd)
goto cleanup;
dc = GetDC(wnd);
if (!dc)
goto cleanup;
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT;
pfd.iPixelType = PFD_TYPE_RGBA;
// Use the GDI functions. Under the hood this will call the wgl variants in opengl32.dll.
int pixelFormat = ChoosePixelFormat(dc, &pfd);
if (!pixelFormat)
goto cleanup;
if (!SetPixelFormat(dc, pixelFormat, &pfd))
goto cleanup;
context = CreateContext(dc);
if (!context)
goto cleanup;
if (!MakeCurrent(dc, context))
goto cleanup;
// Now that there is finally a context current, try doing something useful.
// Check the version. If we got 1.x then it's all hopeless and we can stop right here.
typedef const GLubyte * (APIENTRY * GetString_t)(GLenum name);
GetString_t GetString = reinterpret_cast<GetString_t>(::GetProcAddress(lib, "glGetString"));
if (GetString) {
const char *versionStr = (const char *) GetString(GL_VERSION);
if (versionStr) {
const QByteArray version(versionStr);
const int majorDot = version.indexOf('.');
if (majorDot != -1) {
int minorDot = version.indexOf('.', majorDot + 1);
if (minorDot == -1)
minorDot = version.size();
const int major = version.mid(0, majorDot).toInt();
const int minor = version.mid(majorDot + 1, minorDot - majorDot - 1).toInt();
qCDebug(lcQpaGl, "Basic wglCreateContext gives version %d.%d", major, minor);
// Try to be as lenient as possible. Missing version, bogus values and
// such are all accepted. The driver may still be functional. Only
// check for known-bad cases, like versions "1.4.0 ...".
if (major == 1) {
result = false;
qCDebug(lcQpaGl, "OpenGL version too low");
}
}
}
} else {
result = false;
qCDebug(lcQpaGl, "OpenGL 1.x entry points not found");
}
// Check for a shader-specific function.
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
if (WGL_GetProcAddress("glCreateShader")) {
result = true;
qCDebug(lcQpaGl, "OpenGL 2.0 entry points available");
} else {
qCDebug(lcQpaGl, "OpenGL 2.0 entry points not found");
}
} else {
qCDebug(lcQpaGl, "Failed to load opengl32.dll");
}
cleanup:
if (MakeCurrent)
MakeCurrent(0, 0);
if (context)
DeleteContext(context);
if (dc && wnd)
ReleaseDC(wnd, dc);
if (wnd) {
DestroyWindow(wnd);
UnregisterClass(className, GetModuleHandle(0));
}
// No FreeLibrary. Some implementations, Mesa in particular, deadlock when trying to unload.
return result;
#else
return false;
#endif // !QT_NO_OPENGL && !Q_OS_WINCE
Load winsys and gl dynamically in the windows plugin The dynamic builds (-opengl dynamic) are now functional on Windows. In such a build no components in Qt link to any OpenGL libraries directly and qmake will not automatically add any such libraries to the applications' makefiles. Instead, the libraries are chosen and loaded during runtime and applications are expected to use QOpenGLFunctions instead of direct OpenGLfunction calls. Set the environment variable QT_OPENGL to desktop or angle to skip testing and force the given implementation. The application attributes (AA_UseOpenGLES and such) are also taken into account. The testing logic is same as before: We try to load opengl32 and resolve a shader related function. If this fails, ANGLE is chosen. This allows utilizing full desktop OpenGL on systems that have proper drivers, while a transparent fallback to ANGLE will be done automatically for systems that don't. The latter includes also remote desktop connections. Software rendering via Mesa llvmpipe is supported too. The fallback is automatic on systems where the desktop test fails and ANGLE fails to load or initialize (e.g. due to missing libs like d3dcompiler), as long as a suitable patched build of Mesa is available. [ChangeLog][QtGui] Dynamic OpenGL implementation loading is now supported on Windows. This requires Qt to be configured with -opengl dynamic. Task-number: QTBUG-36483 Change-Id: Ie8bb25a6d55b3a1609b00150aeccd909aec27313 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
2014-04-24 12:36:49 +00:00
}
QT_END_NAMESPACE