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 
98 QT_BEGIN_NAMESPACE
99 
operator <<(QTextStream & str,const QSize & s)100 QTextStream &operator<<(QTextStream &str, const QSize &s)
101 {
102     str << s.width() << 'x' << s.height();
103     return str;
104 }
105 
operator <<(QTextStream & str,const QSizeF & s)106 QTextStream &operator<<(QTextStream &str, const QSizeF &s)
107 {
108     str << s.width() << 'x' << s.height();
109     return str;
110 }
111 
operator <<(QTextStream & str,const QDpi & d)112 QTextStream &operator<<(QTextStream &str, const QDpi &d)
113 {
114     str << d.first << ',' << d.second;
115     return str;
116 }
117 
operator <<(QTextStream & str,const QRect & r)118 QTextStream &operator<<(QTextStream &str, const QRect &r)
119 {
120     str << r.size() << Qt::forcesign << r.x() << r.y() << Qt::noforcesign;
121     return str;
122 }
123 
operator <<(QTextStream & str,const QStringList & l)124 QTextStream &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 
operator <<(QTextStream & str,const QFont & f)134 QTextStream &operator<<(QTextStream &str, const QFont &f)
135 {
136     str << '"' << f.family() << "\" "  << f.pointSize();
137     return str;
138 }
139 
operator <<(QTextStream & str,QPlatformScreen::SubpixelAntialiasingType st)140 QTextStream &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 
operator <<(QTextStream & str,const QSurfaceFormat & format)152 QTextStream &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 
dumpGlInfo(QTextStream & str,bool listExtensions)174 void 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(&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, &majorVersion);
203         GLint minorVersion;
204         functions.glGetIntegerv(GL_MINOR_VERSION, &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(profile)) {
213                 if (f->initializeOpenGLFunctions())
214                     str << ", Core (" << openGlVersionFunctionsName << "_Core)";
215             }
216             profile.setProfile(QSurfaceFormat::CompatibilityProfile);
217             if (QAbstractOpenGLFunctions *f = context.versionFunctions(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(extensionList.begin(), extensionList.end());
227             str << " \nFound " << extensionList.size() << " extensions:\n";
228             for (const QByteArray &extension : qAsConst(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)
vulkanVersion(uint32_t v)239 QVersionNumber vulkanVersion(uint32_t v)
240 {
241     return QVersionNumber(VK_VERSION_MAJOR(v), VK_VERSION_MINOR(v), VK_VERSION_PATCH(v));
242 }
243 
dumpVkInfo(QTextStream & str)244 void 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(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(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 
dumpRhiBackendInfo(QTextStream & str,const char * name,QRhi::Implementation impl,QRhiInitParams * initParams)276 void 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         { "MultisampleTexture", QRhi::MultisampleTexture },
284         { "MultisampleRenderBuffer", QRhi::MultisampleRenderBuffer },
285         { "DebugMarkers", QRhi::DebugMarkers },
286         { "Timestamps", QRhi::Timestamps },
287         { "Instancing", QRhi::Instancing },
288         { "CustomInstanceStepRate", QRhi::CustomInstanceStepRate },
289         { "PrimitiveRestart", QRhi::PrimitiveRestart },
290         { "NonDynamicUniformBuffers", QRhi::NonDynamicUniformBuffers },
291         { "NonFourAlignedEffectiveIndexBufferOffset", QRhi::NonFourAlignedEffectiveIndexBufferOffset },
292         { "NPOTTextureRepeat", QRhi::NPOTTextureRepeat },
293         { "RedOrAlpha8IsRed", QRhi::RedOrAlpha8IsRed },
294         { "ElementIndexUint", QRhi::ElementIndexUint },
295         { "Compute", QRhi::Compute },
296         { "WideLines", QRhi::WideLines },
297         { "VertexShaderPointSize", QRhi::VertexShaderPointSize },
298         { "BaseVertex", QRhi::BaseVertex },
299         { "BaseInstance", QRhi::BaseInstance },
300         { "TriangleFanTopology", QRhi::TriangleFanTopology },
301         { "ReadBackNonUniformBuffer", QRhi::ReadBackNonUniformBuffer },
302         { "ReadBackNonBaseMipLevel", QRhi::ReadBackNonBaseMipLevel },
303         { nullptr, QRhi::Feature(0) }
304     };
305     struct RhiTextureFormat {
306         const char *name;
307         QRhiTexture::Format val;
308     };
309     const RhiTextureFormat textureFormats[] = {
310         { "RGBA8", QRhiTexture::RGBA8 },
311         { "BGRA8", QRhiTexture::BGRA8 },
312         { "R8", QRhiTexture::R8 },
313         { "R16", QRhiTexture::R16 },
314         { "RED_OR_ALPHA8", QRhiTexture::RED_OR_ALPHA8 },
315         { "RGBA16F", QRhiTexture::RGBA16F },
316         { "RGBA32F", QRhiTexture::RGBA32F },
317         { "R16F", QRhiTexture::R16F },
318         { "R32F", QRhiTexture::R32F },
319         { "D16", QRhiTexture::D16 },
320         { "D32F", QRhiTexture::D32F },
321         { "BC1", QRhiTexture::BC1 },
322         { "BC2", QRhiTexture::BC2 },
323         { "BC3", QRhiTexture::BC3 },
324         { "BC4", QRhiTexture::BC4 },
325         { "BC5", QRhiTexture::BC5 },
326         { "BC6H", QRhiTexture::BC6H },
327         { "BC7", QRhiTexture::BC7 },
328         { "ETC2_RGB8", QRhiTexture::ETC2_RGB8 },
329         { "ETC2_RGB8A1", QRhiTexture::ETC2_RGB8A1 },
330         { "ETC2_RGBA8", QRhiTexture::ETC2_RGBA8 },
331         { "ASTC_4x4", QRhiTexture::ASTC_4x4 },
332         { "ASTC_5x4", QRhiTexture::ASTC_5x4 },
333         { "ASTC_5x5", QRhiTexture::ASTC_5x5 },
334         { "ASTC_6x5", QRhiTexture::ASTC_6x5 },
335         { "ASTC_6x6", QRhiTexture::ASTC_6x6 },
336         { "ASTC_8x5", QRhiTexture::ASTC_8x5 },
337         { "ASTC_8x6", QRhiTexture::ASTC_8x6 },
338         { "ASTC_8x8", QRhiTexture::ASTC_8x8 },
339         { "ASTC_10x5", QRhiTexture::ASTC_10x5 },
340         { "ASTC_10x6", QRhiTexture::ASTC_10x6 },
341         { "ASTC_10x8", QRhiTexture::ASTC_10x8 },
342         { "ASTC_10x10", QRhiTexture::ASTC_10x10 },
343         { "ASTC_12x10", QRhiTexture::ASTC_12x10 },
344         { "ASTC_12x12", QRhiTexture::ASTC_12x12 },
345         { nullptr, QRhiTexture::UnknownFormat }
346     };
347 
348     QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr));
349     if (rhi) {
350         str << name << ":\n";
351         str << "  Min Texture Size: " << rhi->resourceLimit(QRhi::TextureSizeMin) << "\n";
352         str << "  Max Texture Size: " << rhi->resourceLimit(QRhi::TextureSizeMax) << "\n";
353         str << "  Max Color Attachments: " << rhi->resourceLimit(QRhi::MaxColorAttachments) << "\n";
354         str << "  Frames in Flight: " << rhi->resourceLimit(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(',') << "\n";
360         str << "  Features:\n";
361         for (int i = 0; features[i].name; i++) {
362             str << "    " << (rhi->isFeatureSupported(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(textureFormats[i].val))
367                 str << " " << textureFormats[i].name;
368         }
369         str << "\n";
370     }
371 }
372 
dumpRhiInfo(QTextStream & str)373 void 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, "OpenGL (with default QSurfaceFormat)", QRhi::OpenGLES2, &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, "Vulkan", QRhi::Vulkan, &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.
dumpStandardLocation(QTextStream & str,QStandardPaths::StandardLocation location)417 static void dumpStandardLocation(QTextStream &str, QStandardPaths::StandardLocation location)
418 {
419     str << '"' << QStandardPaths::displayName(location) << '"';
420     const QStringList directories = QStandardPaths::standardLocations(location);
421     const QString writableDirectory = QStandardPaths::writableLocation(location);
422     const int writableIndex = writableDirectory.isEmpty() ? -1 : directories.indexOf(writableDirectory);
423     for (int i = 0; i < directories.size(); ++i) {
424         str << ' ';
425         if (i == writableIndex)
426             str << '*';
427         str << QDir::toNativeSeparators(directories.at(i));
428         if (i == writableIndex)
429             str << '*';
430     }
431     if (!writableDirectory.isEmpty() && writableIndex < 0)
432         str << " *" << QDir::toNativeSeparators(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.
448 template <class T>
formatQDebug(T t)449 static 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.
457 template <class T>
formatValueQDebug(T t)458 static QString formatValueQDebug(T t)
459 {
460     QString result = formatQDebug(t).trimmed();
461     if (result.endsWith(QLatin1Char(')'))) {
462         result.chop(1);
463         result.remove(0, result.indexOf(QLatin1Char('(')) + 1);
464     }
465     return result;
466 }
467 
operator <<(QTextStream & str,const QPalette & palette)468 QTextStream &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(QPalette::Active, role);
473         if (color.isValid())
474             str << "  " << formatValueQDebug(role) << ": " << color.name(QColor::HexArgb) << '\n';
475     }
476     return str;
477 }
478 
qtFeatures()479 static 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("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 
qtDiag(unsigned flags)542 QString 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(QLatin1Char('Q')))
578            str << "  " << key << "=\"" << systemEnvironment.value(key) << "\"\n";
579     }
580 #endif // QT_CONFIG(process)
581 
582     const QByteArrayList features = qtFeatures();
583     if (!features.isEmpty())
584         str << "\nFeatures: " << features.join(' ') << '\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(4) << qSetPadChar('0') << Qt::uppercasedigits << Qt::hex << passwordMaskCharacter.unicode() << Qt::dec << qSetFieldWidth(0);
683     str << '\n'
684         << "  fontSmoothingGamma: " << styleHints->fontSmoothingGamma() << '\n'
685         << "  useRtlExtensions: " << styleHints->useRtlExtensions() << '\n'
686         << "  setFocusOnTouchRelease: " << styleHints->setFocusOnTouchRelease() << '\n'
687         << "  tabFocusBehavior: " << formatQDebug(styleHints->tabFocusBehavior()) << '\n'
688         << "  singleClickActivation: " << styleHints->singleClickActivation() << '\n';
689     str << "\nAdditional style hints (QPlatformIntegration):\n"
690         << "  ReplayMousePressOutsidePopup: "
691         << platformIntegration->styleHint(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(QPlatformTheme::StyleNames).toStringList()
699         << "\n         available    : " << QStyleFactory::keys()
700 #endif
701            ;
702     const QString iconTheme = platformTheme->themeHint(QPlatformTheme::SystemIconThemeName).toString();
703     if (!iconTheme.isEmpty()) {
704         str << "\n  Icon theme          : " << iconTheme
705             << ", " << platformTheme->themeHint(QPlatformTheme::SystemIconFallbackThemeName).toString()
706             << " from " << platformTheme->themeHint(QPlatformTheme::IconThemeSearchPaths).toStringList();
707     }
708     if (const QFont *systemFont = platformTheme->font())
709         str << "\n  System font         : " << *systemFont<< '\n';
710 
711     if (platformTheme->usePlatformNativeDialog(QPlatformTheme::FileDialog))
712         str << "  Native file dialog\n";
713     if (platformTheme->usePlatformNativeDialog(QPlatformTheme::ColorDialog))
714         str << "  Native color dialog\n";
715     if (platformTheme->usePlatformNativeDialog(QPlatformTheme::FontDialog))
716         str << "  Native font dialog\n";
717     if (platformTheme->usePlatformNativeDialog(QPlatformTheme::MessageDialog))
718         str << "  Native message dialog\n";
719 
720     str << "\nFonts:\n  General font : " << QFontDatabase::systemFont(QFontDatabase::GeneralFont) << '\n'
721               << "  Fixed font   : " << QFontDatabase::systemFont(QFontDatabase::FixedFont) << '\n'
722               << "  Title font   : " << QFontDatabase::systemFont(QFontDatabase::TitleFont) << '\n'
723               << "  Smallest font: " << QFontDatabase::systemFont(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(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(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(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, 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("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 
854 QT_END_NAMESPACE
855