1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "qtdiag.h"
30
31#include <QtGui/QGuiApplication>
32#include <QtGui/QStyleHints>
33#include <QtGui/QScreen>
34#include <QtGui/QFont>
35#include <QtGui/QFontDatabase>
36#include <QtGui/QPalette>
37#ifndef QT_NO_OPENGL
38# include <QtGui/QOpenGLContext>
39# include <QtGui/QOpenGLFunctions>
40# include <QtGui/QOpenGLVersionProfile>
41#endif // QT_NO_OPENGL
42#if QT_CONFIG(vulkan)
43# include <QtGui/QVulkanInstance>
44# include <QtGui/QVulkanWindow>
45#endif // vulkan
46#include <QtGui/QWindow>
47#include <QtGui/QTouchDevice>
48
49#ifdef NETWORK_DIAG
50# include <QSslSocket>
51#endif
52
53#include <QtCore/QLibraryInfo>
54#include <QtCore/QStringList>
55#include <QtCore/QVariant>
56#include <QtCore/QSysInfo>
57#include <QtCore/QLibraryInfo>
58#if QT_CONFIG(processenvironment)
59# include <QtCore/QProcessEnvironment>
60#endif
61#include <QtCore/QTextStream>
62#include <QtCore/QStandardPaths>
63#include <QtCore/QDir>
64#include <QtCore/QFileSelector>
65#include <QtCore/QDebug>
66#include <QtCore/QVersionNumber>
67
68#include <private/qsimd_p.h>
69#include <private/qguiapplication_p.h>
70#include <qpa/qplatformintegration.h>
71#include <qpa/qplatformscreen.h>
72#include <qpa/qplatformtheme.h>
73#include <qpa/qplatformthemefactory_p.h>
74#include <qpa/qplatformnativeinterface.h>
75#include <private/qhighdpiscaling_p.h>
76
77#include <QtGui/private/qrhi_p.h>
78#include <QtGui/QOffscreenSurface>
79#if QT_CONFIG(opengl)
80# include <QtGui/private/qrhigles2_p.h>
81#endif
82#if QT_CONFIG(vulkan)
83# include <QtGui/private/qrhivulkan_p.h>
84#endif
85#ifdef Q_OS_WIN
86#include <QtGui/private/qrhid3d11_p.h>
87#endif
88#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
89# include <QtGui/private/qrhimetal_p.h>
90#endif
91
92#ifdef QT_WIDGETS_LIB
93# include <QtWidgets/QStyleFactory>
94#endif
95
96#include <algorithm>
97
98QT_BEGIN_NAMESPACE
99
100QTextStream &operator<<(QTextStream &str, const QSize &s)
101{
102 str << s.width() << 'x' << s.height();
103 return str;
104}
105
106QTextStream &operator<<(QTextStream &str, const QSizeF &s)
107{
108 str << s.width() << 'x' << s.height();
109 return str;
110}
111
112QTextStream &operator<<(QTextStream &str, const QDpi &d)
113{
114 str << d.first << ',' << d.second;
115 return str;
116}
117
118QTextStream &operator<<(QTextStream &str, const QRect &r)
119{
120 str << r.size() << Qt::forcesign << r.x() << r.y() << Qt::noforcesign;
121 return str;
122}
123
124QTextStream &operator<<(QTextStream &str, const QStringList &l)
125{
126 for (int i = 0; i < l.size(); ++i) {
127 if (i)
128 str << ',';
129 str << l.at(i);
130 }
131 return str;
132}
133
134QTextStream &operator<<(QTextStream &str, const QFont &f)
135{
136 str << '"' << f.family() << "\" " << f.pointSize();
137 return str;
138}
139
140QTextStream &operator<<(QTextStream &str, QPlatformScreen::SubpixelAntialiasingType st)
141{
142 static const char *enumValues[] = {
143 "Subpixel_None", "Subpixel_RGB", "Subpixel_BGR", "Subpixel_VRGB", "Subpixel_VBGR"
144 };
145 str << (size_t(st) < sizeof(enumValues) / sizeof(enumValues[0])
146 ? enumValues[st] : "<Unknown>");
147 return str;
148}
149
150#ifndef QT_NO_OPENGL
151
152QTextStream &operator<<(QTextStream &str, const QSurfaceFormat &format)
153{
154 str << "Version: " << format.majorVersion() << '.'
155 << format.minorVersion() << " Profile: " << format.profile()
156 << " Swap behavior: " << format.swapBehavior()
157 << " Buffer size (RGB";
158 if (format.hasAlpha())
159 str << 'A';
160 str << "): " << format.redBufferSize() << ',' << format.greenBufferSize()
161 << ',' << format.blueBufferSize();
162 if (format.hasAlpha())
163 str << ',' << format.alphaBufferSize();
164 if (const int dbs = format.depthBufferSize())
165 str << " Depth buffer: " << dbs;
166 if (const int sbs = format.stencilBufferSize())
167 str << " Stencil buffer: " << sbs;
168 const int samples = format.samples();
169 if (samples > 0)
170 str << " Samples: " << samples;
171 return str;
172}
173
174void dumpGlInfo(QTextStream &str, bool listExtensions)
175{
176 QOpenGLContext context;
177 if (context.create()) {
178# ifdef QT_OPENGL_DYNAMIC
179 str << "Dynamic GL ";
180# endif
181 switch (context.openGLModuleType()) {
182 case QOpenGLContext::LibGL:
183 str << "LibGL";
184 break;
185 case QOpenGLContext::LibGLES:
186 str << "LibGLES";
187 break;
188 }
189 QWindow window;
190 window.setSurfaceType(QSurface::OpenGLSurface);
191 window.create();
192 context.makeCurrent(surface: &window);
193 QOpenGLFunctions functions(&context);
194
195 str << " Vendor: " << reinterpret_cast<const char *>(functions.glGetString(GL_VENDOR))
196 << "\nRenderer: " << reinterpret_cast<const char *>(functions.glGetString(GL_RENDERER))
197 << "\nVersion: " << reinterpret_cast<const char *>(functions.glGetString(GL_VERSION))
198 << "\nShading language: " << reinterpret_cast<const char *>(functions.glGetString(GL_SHADING_LANGUAGE_VERSION))
199 << "\nFormat: " << context.format();
200# ifndef QT_OPENGL_ES_2
201 GLint majorVersion;
202 functions.glGetIntegerv(GL_MAJOR_VERSION, params: &majorVersion);
203 GLint minorVersion;
204 functions.glGetIntegerv(GL_MINOR_VERSION, params: &minorVersion);
205 const QByteArray openGlVersionFunctionsName = "QOpenGLFunctions_"
206 + QByteArray::number(majorVersion) + '_' + QByteArray::number(minorVersion);
207 str << "\nProfile: None (" << openGlVersionFunctionsName << ')';
208 if (majorVersion > 3 || (majorVersion == 3 && minorVersion >= 1)) {
209 QOpenGLVersionProfile profile;
210 profile.setVersion(majorVersion, minorVersion);
211 profile.setProfile(QSurfaceFormat::CoreProfile);
212 if (QAbstractOpenGLFunctions *f = context.versionFunctions(versionProfile: profile)) {
213 if (f->initializeOpenGLFunctions())
214 str << ", Core (" << openGlVersionFunctionsName << "_Core)";
215 }
216 profile.setProfile(QSurfaceFormat::CompatibilityProfile);
217 if (QAbstractOpenGLFunctions *f = context.versionFunctions(versionProfile: profile)) {
218 if (f->initializeOpenGLFunctions())
219 str << ", Compatibility (" << openGlVersionFunctionsName << "_Compatibility)";
220 }
221 }
222 str << '\n';
223# endif // !QT_OPENGL_ES_2
224 if (listExtensions) {
225 QByteArrayList extensionList = context.extensions().values();
226 std::sort(first: extensionList.begin(), last: extensionList.end());
227 str << " \nFound " << extensionList.size() << " extensions:\n";
228 for (const QByteArray &extension : qAsConst(t&: extensionList))
229 str << " " << extension << '\n';
230 }
231 } else {
232 str << "Unable to create an Open GL context.\n";
233 }
234}
235
236#endif // !QT_NO_OPENGL
237
238#if QT_CONFIG(vulkan)
239QVersionNumber vulkanVersion(uint32_t v)
240{
241 return QVersionNumber(VK_VERSION_MAJOR(v), VK_VERSION_MINOR(v), VK_VERSION_PATCH(v));
242}
243
244void dumpVkInfo(QTextStream &str)
245{
246 QVulkanInstance inst;
247 if (inst.create()) {
248 str << "Vulkan instance available\n";
249 str << "Supported instance extensions:\n";
250 for (const QVulkanExtension &ext : inst.supportedExtensions())
251 str << " " << ext.name << ", version " << ext.version << "\n";
252 str << "Supported layers:\n";
253 for (const QVulkanLayer &layer : inst.supportedLayers())
254 str << " " << layer.name << ", version " << layer.version
255 << ", spec version " << layer.specVersion.toString()
256 << ", " << layer.description << "\n";
257 // Show at least the available physical devices. Anything additional
258 // needs lots of initialization, or, if done through QVulkanWindow, an
259 // exposed window. None of these are very tempting right now.
260 str << "Available physical devices:\n";
261 QVulkanWindow window;
262 window.setVulkanInstance(&inst);
263 for (const VkPhysicalDeviceProperties &props : window.availablePhysicalDevices()) {
264 str << " API version " << vulkanVersion(v: props.apiVersion).toString()
265 << Qt::hex << ", vendor 0x" << props.vendorID
266 << ", device 0x" << props.deviceID << ", " << props.deviceName
267 << Qt::dec << ", type " << props.deviceType
268 << ", driver version " << vulkanVersion(v: props.driverVersion).toString();
269 }
270 } else {
271 str << "Unable to create a Vulkan instance, error code is" << inst.errorCode() << "\n";
272 }
273}
274#endif // vulkan
275
276void dumpRhiBackendInfo(QTextStream &str, const char *name, QRhi::Implementation impl, QRhiInitParams *initParams)
277{
278 struct RhiFeature {
279 const char *name;
280 QRhi::Feature val;
281 };
282 const RhiFeature features[] = {
283 { .name: "MultisampleTexture", .val: QRhi::MultisampleTexture },
284 { .name: "MultisampleRenderBuffer", .val: QRhi::MultisampleRenderBuffer },
285 { .name: "DebugMarkers", .val: QRhi::DebugMarkers },
286 { .name: "Timestamps", .val: QRhi::Timestamps },
287 { .name: "Instancing", .val: QRhi::Instancing },
288 { .name: "CustomInstanceStepRate", .val: QRhi::CustomInstanceStepRate },
289 { .name: "PrimitiveRestart", .val: QRhi::PrimitiveRestart },
290 { .name: "NonDynamicUniformBuffers", .val: QRhi::NonDynamicUniformBuffers },
291 { .name: "NonFourAlignedEffectiveIndexBufferOffset", .val: QRhi::NonFourAlignedEffectiveIndexBufferOffset },
292 { .name: "NPOTTextureRepeat", .val: QRhi::NPOTTextureRepeat },
293 { .name: "RedOrAlpha8IsRed", .val: QRhi::RedOrAlpha8IsRed },
294 { .name: "ElementIndexUint", .val: QRhi::ElementIndexUint },
295 { .name: "Compute", .val: QRhi::Compute },
296 { .name: "WideLines", .val: QRhi::WideLines },
297 { .name: "VertexShaderPointSize", .val: QRhi::VertexShaderPointSize },
298 { .name: "BaseVertex", .val: QRhi::BaseVertex },
299 { .name: "BaseInstance", .val: QRhi::BaseInstance },
300 { .name: "TriangleFanTopology", .val: QRhi::TriangleFanTopology },
301 { .name: "ReadBackNonUniformBuffer", .val: QRhi::ReadBackNonUniformBuffer },
302 { .name: "ReadBackNonBaseMipLevel", .val: QRhi::ReadBackNonBaseMipLevel },
303 { .name: nullptr, .val: QRhi::Feature(0) }
304 };
305 struct RhiTextureFormat {
306 const char *name;
307 QRhiTexture::Format val;
308 };
309 const RhiTextureFormat textureFormats[] = {
310 { .name: "RGBA8", .val: QRhiTexture::RGBA8 },
311 { .name: "BGRA8", .val: QRhiTexture::BGRA8 },
312 { .name: "R8", .val: QRhiTexture::R8 },
313 { .name: "R16", .val: QRhiTexture::R16 },
314 { .name: "RED_OR_ALPHA8", .val: QRhiTexture::RED_OR_ALPHA8 },
315 { .name: "RGBA16F", .val: QRhiTexture::RGBA16F },
316 { .name: "RGBA32F", .val: QRhiTexture::RGBA32F },
317 { .name: "R16F", .val: QRhiTexture::R16F },
318 { .name: "R32F", .val: QRhiTexture::R32F },
319 { .name: "D16", .val: QRhiTexture::D16 },
320 { .name: "D32F", .val: QRhiTexture::D32F },
321 { .name: "BC1", .val: QRhiTexture::BC1 },
322 { .name: "BC2", .val: QRhiTexture::BC2 },
323 { .name: "BC3", .val: QRhiTexture::BC3 },
324 { .name: "BC4", .val: QRhiTexture::BC4 },
325 { .name: "BC5", .val: QRhiTexture::BC5 },
326 { .name: "BC6H", .val: QRhiTexture::BC6H },
327 { .name: "BC7", .val: QRhiTexture::BC7 },
328 { .name: "ETC2_RGB8", .val: QRhiTexture::ETC2_RGB8 },
329 { .name: "ETC2_RGB8A1", .val: QRhiTexture::ETC2_RGB8A1 },
330 { .name: "ETC2_RGBA8", .val: QRhiTexture::ETC2_RGBA8 },
331 { .name: "ASTC_4x4", .val: QRhiTexture::ASTC_4x4 },
332 { .name: "ASTC_5x4", .val: QRhiTexture::ASTC_5x4 },
333 { .name: "ASTC_5x5", .val: QRhiTexture::ASTC_5x5 },
334 { .name: "ASTC_6x5", .val: QRhiTexture::ASTC_6x5 },
335 { .name: "ASTC_6x6", .val: QRhiTexture::ASTC_6x6 },
336 { .name: "ASTC_8x5", .val: QRhiTexture::ASTC_8x5 },
337 { .name: "ASTC_8x6", .val: QRhiTexture::ASTC_8x6 },
338 { .name: "ASTC_8x8", .val: QRhiTexture::ASTC_8x8 },
339 { .name: "ASTC_10x5", .val: QRhiTexture::ASTC_10x5 },
340 { .name: "ASTC_10x6", .val: QRhiTexture::ASTC_10x6 },
341 { .name: "ASTC_10x8", .val: QRhiTexture::ASTC_10x8 },
342 { .name: "ASTC_10x10", .val: QRhiTexture::ASTC_10x10 },
343 { .name: "ASTC_12x10", .val: QRhiTexture::ASTC_12x10 },
344 { .name: "ASTC_12x12", .val: QRhiTexture::ASTC_12x12 },
345 { .name: nullptr, .val: QRhiTexture::UnknownFormat }
346 };
347
348 QScopedPointer<QRhi> rhi(QRhi::create(impl, params: initParams, flags: QRhi::Flags(), importDevice: nullptr));
349 if (rhi) {
350 str << name << ":\n";
351 str << " Min Texture Size: " << rhi->resourceLimit(limit: QRhi::TextureSizeMin) << "\n";
352 str << " Max Texture Size: " << rhi->resourceLimit(limit: QRhi::TextureSizeMax) << "\n";
353 str << " Max Color Attachments: " << rhi->resourceLimit(limit: QRhi::MaxColorAttachments) << "\n";
354 str << " Frames in Flight: " << rhi->resourceLimit(limit: QRhi::FramesInFlight) << "\n";
355 str << " Uniform Buffer Alignment: " << rhi->ubufAlignment() << "\n";
356 QByteArrayList supportedSampleCounts;
357 for (int s : rhi->supportedSampleCounts())
358 supportedSampleCounts << QByteArray::number(s);
359 str << " Supported MSAA sample counts: " << supportedSampleCounts.join(sep: ',') << "\n";
360 str << " Features:\n";
361 for (int i = 0; features[i].name; i++) {
362 str << " " << (rhi->isFeatureSupported(feature: features[i].val) ? "v" : "-") << " " << features[i].name << "\n";
363 }
364 str << " Texture formats:";
365 for (int i = 0; textureFormats[i].name; i++) {
366 if (rhi->isTextureFormatSupported(format: textureFormats[i].val))
367 str << " " << textureFormats[i].name;
368 }
369 str << "\n";
370 }
371}
372
373void dumpRhiInfo(QTextStream &str)
374{
375 str << "Qt Rendering Hardware Interface supported backends:\n";
376
377#if QT_CONFIG(opengl)
378 {
379 QRhiGles2InitParams params;
380 params.fallbackSurface = QRhiGles2InitParams::newFallbackSurface();
381 dumpRhiBackendInfo(str, name: "OpenGL (with default QSurfaceFormat)", impl: QRhi::OpenGLES2, initParams: &params);
382 delete params.fallbackSurface;
383 }
384#endif
385
386#if QT_CONFIG(vulkan)
387 {
388 QVulkanInstance vulkanInstance;
389 vulkanInstance.create();
390 QRhiVulkanInitParams params;
391 params.inst = &vulkanInstance;
392 dumpRhiBackendInfo(str, name: "Vulkan", impl: QRhi::Vulkan, initParams: &params);
393 vulkanInstance.destroy();
394 }
395#endif
396
397#ifdef Q_OS_WIN
398 {
399 QRhiD3D11InitParams params;
400 dumpRhiBackendInfo(str, "Direct3D 11", QRhi::D3D11, &params);
401 }
402#endif
403
404#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
405 {
406 QRhiMetalInitParams params;
407 dumpRhiBackendInfo(str, "Metal", QRhi::Metal, &params);
408 }
409#endif
410}
411
412#define DUMP_CAPABILITY(str, integration, capability) \
413 if (platformIntegration->hasCapability(QPlatformIntegration::capability)) \
414 str << ' ' << #capability;
415
416// Dump values of QStandardPaths, indicate writable locations by asterisk.
417static void dumpStandardLocation(QTextStream &str, QStandardPaths::StandardLocation location)
418{
419 str << '"' << QStandardPaths::displayName(type: location) << '"';
420 const QStringList directories = QStandardPaths::standardLocations(type: location);
421 const QString writableDirectory = QStandardPaths::writableLocation(type: location);
422 const int writableIndex = writableDirectory.isEmpty() ? -1 : directories.indexOf(t: writableDirectory);
423 for (int i = 0; i < directories.size(); ++i) {
424 str << ' ';
425 if (i == writableIndex)
426 str << '*';
427 str << QDir::toNativeSeparators(pathName: directories.at(i));
428 if (i == writableIndex)
429 str << '*';
430 }
431 if (!writableDirectory.isEmpty() && writableIndex < 0)
432 str << " *" << QDir::toNativeSeparators(pathName: writableDirectory) << '*';
433}
434
435#define DUMP_CPU_FEATURE(feature, name) \
436 if (qCpuHasFeature(feature)) \
437 str << " " name;
438
439#define DUMP_STANDARDPATH(str, location) \
440 str << " " << #location << ": "; \
441 dumpStandardLocation(str, QStandardPaths::location); \
442 str << '\n';
443
444#define DUMP_LIBRARYPATH(str, loc) \
445 str << " " << #loc << ": " << QDir::toNativeSeparators(QLibraryInfo::location(QLibraryInfo::loc)) << '\n';
446
447// Helper to format a type via QDebug to be used for QFlags/Q_ENUM.
448template <class T>
449static QString formatQDebug(T t)
450{
451 QString result;
452 QDebug(&result) << t;
453 return result;
454}
455
456// Helper to format a type via QDebug, stripping the class name.
457template <class T>
458static QString formatValueQDebug(T t)
459{
460 QString result = formatQDebug(t).trimmed();
461 if (result.endsWith(c: QLatin1Char(')'))) {
462 result.chop(n: 1);
463 result.remove(i: 0, len: result.indexOf(c: QLatin1Char('(')) + 1);
464 }
465 return result;
466}
467
468QTextStream &operator<<(QTextStream &str, const QPalette &palette)
469{
470 for (int r = 0; r < int(QPalette::NColorRoles); ++r) {
471 const QPalette::ColorRole role = static_cast< QPalette::ColorRole>(r);
472 const QColor color = palette.color(cg: QPalette::Active, cr: role);
473 if (color.isValid())
474 str << " " << formatValueQDebug(t: role) << ": " << color.name(format: QColor::HexArgb) << '\n';
475 }
476 return str;
477}
478
479static inline QByteArrayList qtFeatures()
480{
481 QByteArrayList result;
482#ifdef QT_NO_CLIPBOARD
483 result.append("QT_NO_CLIPBOARD");
484#endif
485#ifdef QT_NO_CONTEXTMENU
486 result.append("QT_NO_CONTEXTMENU");
487#endif
488#ifdef QT_NO_CURSOR
489 result.append("QT_NO_CURSOR");
490#endif
491#ifdef QT_NO_DRAGANDDROP
492 result.append("QT_NO_DRAGANDDROP");
493#endif
494#ifdef QT_NO_EXCEPTIONS
495 result.append(t: "QT_NO_EXCEPTIONS");
496#endif
497#ifdef QT_NO_LIBRARY
498 result.append("QT_NO_LIBRARY");
499#endif
500#ifdef QT_NO_NETWORK
501 result.append("QT_NO_NETWORK");
502#endif
503#ifdef QT_NO_OPENGL
504 result.append("QT_NO_OPENGL");
505#endif
506#ifdef QT_NO_OPENSSL
507 result.append("QT_NO_OPENSSL");
508#endif
509#ifdef QT_NO_PROCESS
510 result.append("QT_NO_PROCESS");
511#endif
512#ifdef QT_NO_PRINTER
513 result.append("QT_NO_PRINTER");
514#endif
515#ifdef QT_NO_SESSIONMANAGER
516 result.append("QT_NO_SESSIONMANAGER");
517#endif
518#ifdef QT_NO_SETTINGS
519 result.append("QT_NO_SETTINGS");
520#endif
521#ifdef QT_NO_SHORTCUT
522 result.append("QT_NO_SHORTCUT");
523#endif
524#ifdef QT_NO_SYSTEMTRAYICON
525 result.append("QT_NO_SYSTEMTRAYICON");
526#endif
527#ifdef QT_NO_QTHREAD
528 result.append("QT_NO_QTHREAD");
529#endif
530#ifdef QT_NO_WHATSTHIS
531 result.append("QT_NO_WHATSTHIS");
532#endif
533#ifdef QT_NO_WIDGETS
534 result.append("QT_NO_WIDGETS");
535#endif
536#ifdef QT_NO_ZLIB
537 result.append("QT_NO_ZLIB");
538#endif
539 return result;
540}
541
542QString qtDiag(unsigned flags)
543{
544 QString result;
545 QTextStream str(&result);
546
547 const QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
548 str << QLibraryInfo::build() << " on \"" << QGuiApplication::platformName() << "\" "
549 << '\n'
550 << "OS: " << QSysInfo::prettyProductName()
551 << " [" << QSysInfo::kernelType() << " version " << QSysInfo::kernelVersion() << "]\n";
552
553 str << "\nArchitecture: " << QSysInfo::currentCpuArchitecture() << "; features:";
554#if defined(Q_PROCESSOR_X86)
555 DUMP_CPU_FEATURE(SSE2, "SSE2");
556 DUMP_CPU_FEATURE(SSE3, "SSE3");
557 DUMP_CPU_FEATURE(SSSE3, "SSSE3");
558 DUMP_CPU_FEATURE(SSE4_1, "SSE4.1");
559 DUMP_CPU_FEATURE(SSE4_2, "SSE4.2");
560 DUMP_CPU_FEATURE(AVX, "AVX");
561 DUMP_CPU_FEATURE(AVX2, "AVX2");
562 DUMP_CPU_FEATURE(RTM, "RTM");
563 DUMP_CPU_FEATURE(HLE, "HLE");
564#elif defined(Q_PROCESSOR_ARM)
565 DUMP_CPU_FEATURE(ARM_NEON, "Neon");
566#elif defined(Q_PROCESSOR_MIPS)
567 DUMP_CPU_FEATURE(DSP, "DSP");
568 DUMP_CPU_FEATURE(DSPR2, "DSPR2");
569#endif
570 str << '\n';
571
572#if QT_CONFIG(process)
573 const QProcessEnvironment systemEnvironment = QProcessEnvironment::systemEnvironment();
574 str << "\nEnvironment:\n";
575 const QStringList keys = systemEnvironment.keys();
576 for (const QString &key : keys) {
577 if (key.startsWith(c: QLatin1Char('Q')))
578 str << " " << key << "=\"" << systemEnvironment.value(name: key) << "\"\n";
579 }
580#endif // QT_CONFIG(process)
581
582 const QByteArrayList features = qtFeatures();
583 if (!features.isEmpty())
584 str << "\nFeatures: " << features.join(sep: ' ') << '\n';
585
586 str << "\nLibrary info:\n";
587 DUMP_LIBRARYPATH(str, PrefixPath)
588 DUMP_LIBRARYPATH(str, DocumentationPath)
589 DUMP_LIBRARYPATH(str, HeadersPath)
590 DUMP_LIBRARYPATH(str, LibrariesPath)
591 DUMP_LIBRARYPATH(str, LibraryExecutablesPath)
592 DUMP_LIBRARYPATH(str, BinariesPath)
593 DUMP_LIBRARYPATH(str, PluginsPath)
594 DUMP_LIBRARYPATH(str, ImportsPath)
595 DUMP_LIBRARYPATH(str, Qml2ImportsPath)
596 DUMP_LIBRARYPATH(str, ArchDataPath)
597 DUMP_LIBRARYPATH(str, DataPath)
598 DUMP_LIBRARYPATH(str, TranslationsPath)
599 DUMP_LIBRARYPATH(str, ExamplesPath)
600 DUMP_LIBRARYPATH(str, TestsPath)
601 DUMP_LIBRARYPATH(str, SettingsPath)
602
603 str << "\nStandard paths [*...* denote writable entry]:\n";
604 DUMP_STANDARDPATH(str, DesktopLocation)
605 DUMP_STANDARDPATH(str, DocumentsLocation)
606 DUMP_STANDARDPATH(str, FontsLocation)
607 DUMP_STANDARDPATH(str, ApplicationsLocation)
608 DUMP_STANDARDPATH(str, MusicLocation)
609 DUMP_STANDARDPATH(str, MoviesLocation)
610 DUMP_STANDARDPATH(str, PicturesLocation)
611 DUMP_STANDARDPATH(str, TempLocation)
612 DUMP_STANDARDPATH(str, HomeLocation)
613 DUMP_STANDARDPATH(str, AppLocalDataLocation)
614 DUMP_STANDARDPATH(str, CacheLocation)
615 DUMP_STANDARDPATH(str, GenericDataLocation)
616 DUMP_STANDARDPATH(str, RuntimeLocation)
617 DUMP_STANDARDPATH(str, ConfigLocation)
618 DUMP_STANDARDPATH(str, DownloadLocation)
619 DUMP_STANDARDPATH(str, GenericCacheLocation)
620 DUMP_STANDARDPATH(str, GenericConfigLocation)
621 DUMP_STANDARDPATH(str, AppDataLocation)
622 DUMP_STANDARDPATH(str, AppConfigLocation)
623
624 str << "\nFile selectors (increasing order of precedence):\n ";
625 const QStringList allSelectors = QFileSelector().allSelectors();
626 for (const QString &s : allSelectors)
627 str << ' ' << s;
628
629 str << "\n\nNetwork:\n ";
630#ifdef NETWORK_DIAG
631# ifndef QT_NO_SSL
632 if (QSslSocket::supportsSsl()) {
633 str << "Using \"" << QSslSocket::sslLibraryVersionString() << "\", version: 0x"
634 << Qt::hex << QSslSocket::sslLibraryVersionNumber() << Qt::dec;
635 } else {
636 str << "\nSSL is not supported.";
637 }
638# else // !QT_NO_SSL
639 str << "SSL is not available.";
640# endif // QT_NO_SSL
641#else
642 str << "Qt Network module is not available.";
643#endif // NETWORK_DIAG
644
645 str << "\n\nPlatform capabilities:";
646 DUMP_CAPABILITY(str, platformIntegration, ThreadedPixmaps)
647 DUMP_CAPABILITY(str, platformIntegration, OpenGL)
648 DUMP_CAPABILITY(str, platformIntegration, ThreadedOpenGL)
649 DUMP_CAPABILITY(str, platformIntegration, SharedGraphicsCache)
650 DUMP_CAPABILITY(str, platformIntegration, BufferQueueingOpenGL)
651 DUMP_CAPABILITY(str, platformIntegration, WindowMasks)
652 DUMP_CAPABILITY(str, platformIntegration, MultipleWindows)
653 DUMP_CAPABILITY(str, platformIntegration, ApplicationState)
654 DUMP_CAPABILITY(str, platformIntegration, ForeignWindows)
655 DUMP_CAPABILITY(str, platformIntegration, NonFullScreenWindows)
656 DUMP_CAPABILITY(str, platformIntegration, NativeWidgets)
657 DUMP_CAPABILITY(str, platformIntegration, WindowManagement)
658 DUMP_CAPABILITY(str, platformIntegration, SyncState)
659 DUMP_CAPABILITY(str, platformIntegration, RasterGLSurface)
660 DUMP_CAPABILITY(str, platformIntegration, AllGLFunctionsQueryable)
661 DUMP_CAPABILITY(str, platformIntegration, ApplicationIcon)
662 DUMP_CAPABILITY(str, platformIntegration, SwitchableWidgetComposition)
663 str << '\n';
664
665 const QStyleHints *styleHints = QGuiApplication::styleHints();
666 const QChar passwordMaskCharacter = styleHints->passwordMaskCharacter();
667 str << "\nStyle hints:\n mouseDoubleClickInterval: " << styleHints->mouseDoubleClickInterval() << '\n'
668 << " mousePressAndHoldInterval: " << styleHints->mousePressAndHoldInterval() << '\n'
669 << " startDragDistance: " << styleHints->startDragDistance() << '\n'
670 << " startDragTime: " << styleHints->startDragTime() << '\n'
671 << " startDragVelocity: " << styleHints->startDragVelocity() << '\n'
672 << " keyboardInputInterval: " << styleHints->keyboardInputInterval() << '\n'
673 << " keyboardAutoRepeatRate: " << styleHints->keyboardAutoRepeatRate() << '\n'
674 << " cursorFlashTime: " << styleHints->cursorFlashTime() << '\n'
675 << " showIsFullScreen: " << styleHints->showIsFullScreen() << '\n'
676 << " showIsMaximized: " << styleHints->showIsMaximized() << '\n'
677 << " passwordMaskDelay: " << styleHints->passwordMaskDelay() << '\n'
678 << " passwordMaskCharacter: ";
679 if (passwordMaskCharacter.unicode() >= 32 && passwordMaskCharacter.unicode() < 128)
680 str << '\'' << passwordMaskCharacter << '\'';
681 else
682 str << "U+" << qSetFieldWidth(width: 4) << qSetPadChar(ch: '0') << Qt::uppercasedigits << Qt::hex << passwordMaskCharacter.unicode() << Qt::dec << qSetFieldWidth(width: 0);
683 str << '\n'
684 << " fontSmoothingGamma: " << styleHints->fontSmoothingGamma() << '\n'
685 << " useRtlExtensions: " << styleHints->useRtlExtensions() << '\n'
686 << " setFocusOnTouchRelease: " << styleHints->setFocusOnTouchRelease() << '\n'
687 << " tabFocusBehavior: " << formatQDebug(t: styleHints->tabFocusBehavior()) << '\n'
688 << " singleClickActivation: " << styleHints->singleClickActivation() << '\n';
689 str << "\nAdditional style hints (QPlatformIntegration):\n"
690 << " ReplayMousePressOutsidePopup: "
691 << platformIntegration->styleHint(hint: QPlatformIntegration::ReplayMousePressOutsidePopup).toBool() << '\n';
692
693 const QPlatformTheme *platformTheme = QGuiApplicationPrivate::platformTheme();
694 str << "\nTheme:"
695 "\n Platforms requested : " << platformIntegration->themeNames()
696 << "\n available : " << QPlatformThemeFactory::keys()
697#ifdef QT_WIDGETS_LIB
698 << "\n Styles requested : " << platformTheme->themeHint(hint: QPlatformTheme::StyleNames).toStringList()
699 << "\n available : " << QStyleFactory::keys()
700#endif
701 ;
702 const QString iconTheme = platformTheme->themeHint(hint: QPlatformTheme::SystemIconThemeName).toString();
703 if (!iconTheme.isEmpty()) {
704 str << "\n Icon theme : " << iconTheme
705 << ", " << platformTheme->themeHint(hint: QPlatformTheme::SystemIconFallbackThemeName).toString()
706 << " from " << platformTheme->themeHint(hint: QPlatformTheme::IconThemeSearchPaths).toStringList();
707 }
708 if (const QFont *systemFont = platformTheme->font())
709 str << "\n System font : " << *systemFont<< '\n';
710
711 if (platformTheme->usePlatformNativeDialog(type: QPlatformTheme::FileDialog))
712 str << " Native file dialog\n";
713 if (platformTheme->usePlatformNativeDialog(type: QPlatformTheme::ColorDialog))
714 str << " Native color dialog\n";
715 if (platformTheme->usePlatformNativeDialog(type: QPlatformTheme::FontDialog))
716 str << " Native font dialog\n";
717 if (platformTheme->usePlatformNativeDialog(type: QPlatformTheme::MessageDialog))
718 str << " Native message dialog\n";
719
720 str << "\nFonts:\n General font : " << QFontDatabase::systemFont(type: QFontDatabase::GeneralFont) << '\n'
721 << " Fixed font : " << QFontDatabase::systemFont(type: QFontDatabase::FixedFont) << '\n'
722 << " Title font : " << QFontDatabase::systemFont(type: QFontDatabase::TitleFont) << '\n'
723 << " Smallest font: " << QFontDatabase::systemFont(type: QFontDatabase::SmallestReadableFont) << '\n';
724 if (flags & QtDiagFonts) {
725 QFontDatabase fontDatabase;
726 const QStringList families = fontDatabase.families();
727 str << "\n Families (" << families.size() << "):\n";
728 for (int i = 0, count = families.size(); i < count; ++i)
729 str << " " << families.at(i) << '\n';
730
731 const QList<int> standardSizes = QFontDatabase::standardSizes();
732 str << "\n Standard Sizes:";
733 for (int i = 0, count = standardSizes.size(); i < count; ++i)
734 str << ' ' << standardSizes.at(i);
735 QList<QFontDatabase::WritingSystem> writingSystems = fontDatabase.writingSystems();
736 str << "\n\n Writing systems:\n";
737 for (int i = 0, count = writingSystems.size(); i < count; ++i)
738 str << " " << formatValueQDebug(t: writingSystems.at(i)) << '\n';
739 }
740
741 str << "\nPalette:\n" << QGuiApplication::palette();
742
743 const QList<QScreen*> screens = QGuiApplication::screens();
744 const int screenCount = screens.size();
745 str << "\nScreens: " << screenCount << ", High DPI scaling: "
746 << (QHighDpiScaling::isActive() ? "active" : "inactive") << '\n';
747 for (int s = 0; s < screenCount; ++s) {
748 const QScreen *screen = screens.at(i: s);
749 const QPlatformScreen *platformScreen = screen->handle();
750 const QRect geometry = screen->geometry();
751 const QDpi dpi(screen->logicalDotsPerInchX(), screen->logicalDotsPerInchY());
752 const QDpi nativeDpi = platformScreen->logicalDpi();
753 const QRect nativeGeometry = platformScreen->geometry();
754 str << '#' << ' ' << s << " \"" << screen->name() << '"'
755 << " Depth: " << screen->depth()
756 << " Primary: " << (screen == QGuiApplication::primaryScreen() ? "yes" : "no")
757 << "\n Manufacturer: " << screen->manufacturer()
758 << "\n Model: " << screen->model()
759 << "\n Serial number: " << screen->serialNumber()
760 << "\n Geometry: " << geometry;
761 if (geometry != nativeGeometry)
762 str << " (native: " << nativeGeometry << ')';
763 str << " Available: " << screen->availableGeometry();
764 if (geometry != screen->virtualGeometry())
765 str << "\n Virtual geometry: " << screen->virtualGeometry() << " Available: " << screen->availableVirtualGeometry();
766 if (screen->virtualSiblings().size() > 1)
767 str << "\n " << screen->virtualSiblings().size() << " virtual siblings";
768 str << "\n Physical size: " << screen->physicalSize() << " mm"
769 << " Refresh: " << screen->refreshRate() << " Hz"
770 << " Power state: " << platformScreen->powerState();
771 str << "\n Physical DPI: " << screen->physicalDotsPerInchX()
772 << ',' << screen->physicalDotsPerInchY()
773 << " Logical DPI: " << dpi;
774 if (dpi != nativeDpi)
775 str << " (native: " << nativeDpi << ')';
776 str << ' ' << platformScreen->subpixelAntialiasingTypeHint() << "\n ";
777 if (QHighDpiScaling::isActive())
778 str << "High DPI scaling factor: " << QHighDpiScaling::factor(context: screen) << ' ';
779 str << "DevicePixelRatio: " << screen->devicePixelRatio()
780 << " Pixel density: " << platformScreen->pixelDensity();
781 str << "\n Primary orientation: " << screen->primaryOrientation()
782 << " Orientation: " << screen->orientation()
783 << " Native orientation: " << screen->nativeOrientation()
784 << " OrientationUpdateMask: " << screen->orientationUpdateMask()
785 << "\n\n";
786 }
787
788 const QList<const QTouchDevice *> touchDevices = QTouchDevice::devices();
789 if (!touchDevices.isEmpty()) {
790 str << "Touch devices: " << touchDevices.size() << '\n';
791 for (const QTouchDevice *device : touchDevices) {
792 str << " " << (device->type() == QTouchDevice::TouchScreen ? "TouchScreen" : "TouchPad")
793 << " \"" << device->name() << "\", max " << device->maximumTouchPoints()
794 << " touch points, capabilities:";
795 const QTouchDevice::Capabilities capabilities = device->capabilities();
796 if (capabilities & QTouchDevice::Position)
797 str << " Position";
798 if (capabilities & QTouchDevice::Area)
799 str << " Area";
800 if (capabilities & QTouchDevice::Pressure)
801 str << " Pressure";
802 if (capabilities & QTouchDevice::Velocity)
803 str << " Velocity";
804 if (capabilities & QTouchDevice::RawPositions)
805 str << " RawPositions";
806 if (capabilities & QTouchDevice::NormalizedPosition)
807 str << " NormalizedPosition";
808 if (capabilities & QTouchDevice::MouseEmulation)
809 str << " MouseEmulation";
810 str << '\n';
811 }
812 str << "\n\n";
813 }
814
815#ifndef QT_NO_OPENGL
816 if (flags & QtDiagGl) {
817 dumpGlInfo(str, listExtensions: flags & QtDiagGlExtensions);
818 str << "\n";
819 }
820#else
821 Q_UNUSED(flags);
822#endif // !QT_NO_OPENGL
823
824#if QT_CONFIG(vulkan)
825 if (flags & QtDiagVk) {
826 dumpVkInfo(str);
827 str << "\n\n";
828 }
829#endif // vulkan
830
831 // On Windows, this will provide addition GPU info similar to the output of dxdiag.
832 if (const QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface()) {
833 const QVariant gpuInfoV = ni->property(name: "gpuList");
834 if (gpuInfoV.type() == QVariant::List) {
835 const auto gpuList = gpuInfoV.toList();
836 for (int i = 0; i < gpuList.size(); ++i) {
837 const QString description =
838 gpuList.at(i).toMap().value(QStringLiteral("printable")).toString();
839 if (!description.isEmpty())
840 str << "\nGPU #" << (i + 1) << ":\n" << description << '\n';
841 }
842 str << "\n";
843 }
844 }
845
846 if (flags & QtDiagRhi) {
847 dumpRhiInfo(str);
848 str << "\n";
849 }
850
851 return result;
852}
853
854QT_END_NAMESPACE
855

source code of qttools/src/qtdiag/qtdiag.cpp