8#include <QtCore/qvariant.h>
9#include <QtCore/qmap.h>
10#include <QtCore/qdebug.h>
11#include <QtCore/qtextstream.h>
12#include <QtCore/qcoreapplication.h>
13#include <QtCore/qfile.h>
14#include <QtCore/qfileinfo.h>
15#include <QtCore/qstandardpaths.h>
16#include <QtCore/qlibraryinfo.h>
17#include <QtCore/qhash.h>
18#include <private/qsystemlibrary_p.h>
19#include <QtGui/qtgui-config.h>
22#include <private/qopengl_p.h>
25#include <QtCore/qt_windows.h>
35 result.vendorId = adapterIdentifier.VendorId;
36 result.deviceId = adapterIdentifier.DeviceId;
37 result.revision = adapterIdentifier.Revision;
38 result.subSysId = adapterIdentifier.SubSysId;
39 QList<
int> version(4, 0);
40 version[0] = HIWORD(adapterIdentifier.DriverVersion.HighPart);
41 version[1] = LOWORD(adapterIdentifier.DriverVersion.HighPart);
42 version[2] = HIWORD(adapterIdentifier.DriverVersion.LowPart);
43 version[3] = LOWORD(adapterIdentifier.DriverVersion.LowPart);
44 result.driverVersion = QVersionNumber(version);
45 result.driverName = adapterIdentifier.Driver;
46 result.description = adapterIdentifier.Description;
58 bool isValid()
const {
return m_direct3D9 !=
nullptr; }
60 UINT adapterCount()
const {
return m_direct3D9 ? m_direct3D9->GetAdapterCount() : 0u; }
64 IDirect3D9 *m_direct3D9 =
nullptr;
70 m_direct3D9 = Direct3DCreate9(D3D_SDK_VERSION);
77 m_direct3D9->Release();
83 && SUCCEEDED(m_direct3D9->GetAdapterIdentifier(n, 0, adapterIdentifier));
93 D3DADAPTER_IDENTIFIER9 adapterIdentifier;
101 if (direct3D9.retrieveAdapterIdentifier(0, &adapterIdentifier)) {
102 result = adapterIdentifierToGpuDescription(adapterIdentifier);
103 isAMD = result.vendorId == VENDOR_ID_AMD;
110 const UINT adapterCount = direct3D9.adapterCount();
111 for (UINT adp = 1; adp < adapterCount; ++adp) {
112 if (direct3D9.retrieveAdapterIdentifier(adp, &adapterIdentifier)
113 && adapterIdentifier.VendorId != VENDOR_ID_AMD) {
116 memset(&dd, 0,
sizeof(dd));
118 for (
int dev = 0; EnumDisplayDevices(
nullptr, dev, &dd, 0); ++dev) {
119 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
122 result.gpuSuitableScreen = QString::fromWCharArray(dd.DeviceName);
136 QList<GpuDescription> result;
138 if (
const UINT adapterCount = direct3D9.adapterCount()) {
139 for (UINT adp = 0; adp < adapterCount; ++adp) {
140 D3DADAPTER_IDENTIFIER9 adapterIdentifier;
141 if (direct3D9.retrieveAdapterIdentifier(adp, &adapterIdentifier))
142 result.append(adapterIdentifierToGpuDescription(adapterIdentifier));
148#ifndef QT_NO_DEBUG_STREAM
151 QDebugStateSaver s(d);
153 d << Qt::hex << Qt::showbase <<
"GpuDescription(vendorId=" << gd.vendorId
154 <<
", deviceId=" << gd.deviceId <<
", subSysId=" << gd.subSysId
155 << Qt::dec << Qt::noshowbase <<
", revision=" << gd.revision
156 <<
", driver: " << gd.driverName
157 <<
", version=" << gd.driverVersion <<
", " << gd.description
158 << gd.gpuSuitableScreen <<
')';
167 QTextStream str(&result);
168 str <<
" Card name : " << description
169 <<
"\n Driver Name : " << driverName
170 <<
"\n Driver Version : " << driverVersion.toString()
171 <<
"\n Vendor ID : 0x" << qSetPadChar(u'0')
172 << Qt::uppercasedigits << Qt::hex << qSetFieldWidth(4) << vendorId
173 <<
"\n Device ID : 0x" << qSetFieldWidth(4) << deviceId
174 <<
"\n SubSys ID : 0x" << qSetFieldWidth(8) << subSysId
175 <<
"\n Revision ID : 0x" << qSetFieldWidth(4) << revision
177 if (!gpuSuitableScreen.isEmpty())
178 str <<
"\nGL windows forced to screen: " << gpuSuitableScreen;
185 result.insert(QStringLiteral(
"vendorId"), QVariant(vendorId));
186 result.insert(QStringLiteral(
"deviceId"), QVariant(deviceId));
187 result.insert(QStringLiteral(
"subSysId"),QVariant(subSysId));
188 result.insert(QStringLiteral(
"revision"), QVariant(revision));
189 result.insert(QStringLiteral(
"driver"), QVariant(QLatin1StringView(driverName)));
190 result.insert(QStringLiteral(
"driverProduct"), QVariant(driverVersion.segmentAt(0)));
191 result.insert(QStringLiteral(
"driverVersion"), QVariant(driverVersion.segmentAt(1)));
192 result.insert(QStringLiteral(
"driverSubVersion"), QVariant(driverVersion.segmentAt(2)));
193 result.insert(QStringLiteral(
"driverBuild"), QVariant(driverVersion.segmentAt(3)));
194 result.insert(QStringLiteral(
"driverVersionString"), driverVersion.toString());
195 result.insert(QStringLiteral(
"description"), QVariant(QLatin1StringView(description)));
196 result.insert(QStringLiteral(
"printable"), QVariant(toString()));
202 const char openGlVar[] =
"QT_OPENGL";
203 if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES))
204 qWarning(
"Qt::AA_UseOpenGLES is no longer supported in Qt 6");
205 if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL))
207 if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL))
209 if (qEnvironmentVariableIsSet(openGlVar)) {
210 const QByteArray requested = qgetenv(openGlVar);
211 if (requested ==
"angle")
212 qWarning(
"QT_OPENGL=angle is no longer supported in Qt 6");
213 if (requested ==
"desktop")
215 if (requested ==
"software")
217 qCWarning(lcQpaGl) <<
"Invalid value set for " << openGlVar <<
": " << requested;
224 if (QFileInfo(fileName).isAbsolute())
228 const QString settingsPath = QLibraryInfo::path(QLibraryInfo::SettingsPath);
229 if (!settingsPath.isEmpty()) {
230 const QFileInfo fi(settingsPath + u'/' + fileName);
232 return fi.absoluteFilePath();
234 return QStandardPaths::locate(QStandardPaths::ConfigLocation, fileName);
239Q_GLOBAL_STATIC(SupportedRenderersCache, supportedRenderersCache)
242QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(
const GpuDescription &gpu,
245#if defined(QT_NO_OPENGL)
250 QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.vendorId, gpu.deviceId, gpu.driverVersion, gpu.description);
251 SupportedRenderersCache *srCache = supportedRenderersCache();
252 SupportedRenderersCache::const_iterator it = srCache->constFind(qgpu);
253 if (it != srCache->cend())
256 QWindowsOpenGLTester::Renderers result(QWindowsOpenGLTester::SoftwareRasterizer);
259 if (requested == DesktopGl || testDesktopGL())
260 result |= QWindowsOpenGLTester::DesktopGl;
262 QSet<QString> features;
263 if (!qEnvironmentVariableIsSet(
"QT_NO_OPENGL_BUGLIST")) {
264 const char bugListFileVar[] =
"QT_OPENGL_BUGLIST";
265 QString buglistFileName = QStringLiteral(
":/qt-project.org/windows/openglblacklists/default.json");
266 if (qEnvironmentVariableIsSet(bugListFileVar)) {
267 const QString fileName = resolveBugListFile(QFile::decodeName(qgetenv(bugListFileVar)));
268 if (!fileName.isEmpty())
269 buglistFileName = fileName;
271 features = QOpenGLConfig::gpuFeatures(qgpu, buglistFileName);
273 qCDebug(lcQpaGl) <<
"GPU features:" << features;
275 if (features.contains(QStringLiteral(
"disable_desktopgl"))) {
276 qCDebug(lcQpaGl) <<
"Disabling Desktop GL: " << gpu;
277 result &= ~QWindowsOpenGLTester::DesktopGl;
279 if (features.contains(QStringLiteral(
"disable_rotation"))) {
280 qCDebug(lcQpaGl) <<
"Disabling rotation: " << gpu;
281 result |= DisableRotationFlag;
283 if (features.contains(QStringLiteral(
"disable_program_cache"))) {
284 qCDebug(lcQpaGl) <<
"Disabling program cache: " << gpu;
285 result |= DisableProgramCacheFlag;
287 srCache->insert(qgpu, result);
292QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers(Renderer requested)
294 const GpuDescription gpu = GpuDescription::detect();
295 const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, requested);
296 qCDebug(lcQpaGl) <<
__FUNCTION__ << gpu << requested <<
"renderer: " << result;
300bool QWindowsOpenGLTester::testDesktopGL()
302#if !defined(QT_NO_OPENGL)
303 typedef HGLRC (WINAPI *CreateContextType)(HDC);
304 typedef BOOL (WINAPI *DeleteContextType)(HGLRC);
305 typedef BOOL (WINAPI *MakeCurrentType)(HDC, HGLRC);
306 typedef PROC (WINAPI *WglGetProcAddressType)(LPCSTR);
308 HMODULE lib =
nullptr;
311 HGLRC context =
nullptr;
312 LPCTSTR className = L"qtopengltest";
314 CreateContextType CreateContext =
nullptr;
315 DeleteContextType DeleteContext =
nullptr;
316 MakeCurrentType MakeCurrent =
nullptr;
317 WglGetProcAddressType WGL_GetProcAddress =
nullptr;
323 lib = QSystemLibrary::load(L"opengl32");
325 CreateContext =
reinterpret_cast<CreateContextType>(
326 reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib,
"wglCreateContext")));
329 DeleteContext =
reinterpret_cast<DeleteContextType>(
330 reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib,
"wglDeleteContext")));
333 MakeCurrent =
reinterpret_cast<MakeCurrentType>(
334 reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib,
"wglMakeCurrent")));
337 WGL_GetProcAddress =
reinterpret_cast<WglGetProcAddressType>(
338 reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib,
"wglGetProcAddress")));
339 if (!WGL_GetProcAddress)
343 wclass.cbClsExtra = 0;
344 wclass.cbWndExtra = 0;
345 wclass.hInstance =
static_cast<HINSTANCE>(GetModuleHandle(
nullptr));
346 wclass.hIcon =
nullptr;
347 wclass.hCursor =
nullptr;
348 wclass.hbrBackground = HBRUSH(COLOR_BACKGROUND);
349 wclass.lpszMenuName =
nullptr;
350 wclass.lpfnWndProc = DefWindowProc;
351 wclass.lpszClassName = className;
352 wclass.style = CS_OWNDC;
353 if (!RegisterClass(&wclass))
355 wnd = CreateWindow(className, L"qtopenglproxytest", WS_OVERLAPPED,
356 0, 0, 640, 480,
nullptr,
nullptr, wclass.hInstance,
nullptr);
363 PIXELFORMATDESCRIPTOR pfd;
364 memset(&pfd, 0,
sizeof(PIXELFORMATDESCRIPTOR));
365 pfd.nSize =
sizeof(PIXELFORMATDESCRIPTOR);
367 pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT;
368 pfd.iPixelType = PFD_TYPE_RGBA;
370 int pixelFormat = ChoosePixelFormat(dc, &pfd);
373 if (!SetPixelFormat(dc, pixelFormat, &pfd))
375 context = CreateContext(dc);
378 if (!MakeCurrent(dc, context))
384 typedef const GLubyte * (APIENTRY * GetString_t)(GLenum name);
385 auto GetString =
reinterpret_cast<GetString_t>(
386 reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib,
"glGetString")));
388 if (
const char *versionStr =
reinterpret_cast<
const char *>(GetString(GL_VERSION))) {
389 const QByteArray version(versionStr);
390 const int majorDot = version.indexOf(
'.');
391 if (majorDot != -1) {
392 int minorDot = version.indexOf(
'.', majorDot + 1);
394 minorDot = version.size();
395 const int major = version.mid(0, majorDot).toInt();
396 const int minor = version.mid(majorDot + 1, minorDot - majorDot - 1).toInt();
397 qCDebug(lcQpaGl,
"Basic wglCreateContext gives version %d.%d", major, minor);
403 qCDebug(lcQpaGl,
"OpenGL version too low");
409 qCDebug(lcQpaGl,
"OpenGL 1.x entry points not found");
413 if (WGL_GetProcAddress(
"glCreateShader") && WGL_GetProcAddress(
"glBindFramebuffer")) {
415 qCDebug(lcQpaGl,
"OpenGL 2.0 entry points available");
417 qCDebug(lcQpaGl,
"OpenGL 2.0 entry points not found");
420 qCDebug(lcQpaGl,
"Failed to load opengl32.dll");
425 MakeCurrent(
nullptr,
nullptr);
427 DeleteContext(context);
432 UnregisterClass(className, GetModuleHandle(
nullptr));
UINT adapterCount() const
bool retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const
Combined button and popup list for selecting options.
static GpuDescription adapterIdentifierToGpuDescription(const D3DADAPTER_IDENTIFIER9 &adapterIdentifier)
static QT_BEGIN_NAMESPACE const DWORD VENDOR_ID_AMD
static QString resolveBugListFile(const QString &fileName)
QHash< QOpenGLConfig::Gpu, QWindowsOpenGLTester::Renderers > SupportedRenderersCache
static GpuDescription detect()
QVariant toVariant() const