Windows QPA: Output all adapters in diagnostics used by qtdiag

Split up the code detecting the GPUs into small helpers. Add a
QDirect3D9Handle class providing Direct3D9 functionality, add
GpuDescription::detectAll() and add a QVariantList "gpuList" property to the
native interface.

Task-number: QTBUG-50371
Task-number: QTBUG-65882
Change-Id: I8673542d327837babc2ad8f507da76e8ff5524ea
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
Friedemann Kleint 2019-03-13 13:32:34 +01:00
parent 036fe49580
commit 15f88a7c01
4 changed files with 104 additions and 41 deletions

View File

@ -289,4 +289,13 @@ QVariant QWindowsNativeInterface::gpu() const
return GpuDescription::detect().toVariant();
}
QVariant QWindowsNativeInterface::gpuList() const
{
QVariantList result;
const auto gpus = GpuDescription::detectAll();
for (const auto &gpu : gpus)
result.append(gpu.toVariant());
return result;
}
QT_END_NAMESPACE

View File

@ -66,6 +66,7 @@ class QWindowsNativeInterface : public QPlatformNativeInterface
Q_OBJECT
Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose)
Q_PROPERTY(QVariant gpu READ gpu STORED false)
Q_PROPERTY(QVariant gpuList READ gpuList STORED false)
public:
void *nativeResourceForIntegration(const QByteArray &resource) override;
@ -91,6 +92,7 @@ public:
void setAsyncExpose(bool value);
QVariant gpu() const;
QVariant gpuList() const;
QVariantMap windowProperties(QPlatformWindow *window) const override;
QVariant windowProperty(QPlatformWindow *window, const QString &name) const override;

View File

@ -62,19 +62,70 @@ QT_BEGIN_NAMESPACE
static const DWORD VENDOR_ID_AMD = 0x1002;
static GpuDescription adapterIdentifierToGpuDescription(const D3DADAPTER_IDENTIFIER9 &adapterIdentifier)
{
GpuDescription result;
result.vendorId = adapterIdentifier.VendorId;
result.deviceId = adapterIdentifier.DeviceId;
result.revision = adapterIdentifier.Revision;
result.subSysId = 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;
}
class QDirect3D9Handle
{
public:
Q_DISABLE_COPY(QDirect3D9Handle)
QDirect3D9Handle();
~QDirect3D9Handle();
bool isValid() const { return m_direct3D9 != nullptr; }
UINT adapterCount() const { return m_direct3D9 ? m_direct3D9->GetAdapterCount() : 0u; }
bool retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const;
private:
QSystemLibrary m_d3d9lib;
IDirect3D9 *m_direct3D9 = nullptr;
};
QDirect3D9Handle::QDirect3D9Handle() :
m_d3d9lib(QStringLiteral("d3d9"))
{
using PtrDirect3DCreate9 = IDirect3D9 *(WINAPI *)(UINT);
if (m_d3d9lib.load()) {
if (auto direct3DCreate9 = (PtrDirect3DCreate9)m_d3d9lib.resolve("Direct3DCreate9"))
m_direct3D9 = direct3DCreate9(D3D_SDK_VERSION);
}
}
QDirect3D9Handle::~QDirect3D9Handle()
{
if (m_direct3D9)
m_direct3D9->Release();
}
bool QDirect3D9Handle::retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const
{
return m_direct3D9
&& SUCCEEDED(m_direct3D9->GetAdapterIdentifier(n, 0, adapterIdentifier));
}
GpuDescription GpuDescription::detect()
{
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)
QDirect3D9Handle direct3D9;
if (!direct3D9.isValid())
return result;
D3DADAPTER_IDENTIFIER9 adapterIdentifier;
@ -85,20 +136,8 @@ GpuDescription GpuDescription::detect()
// and D3D uses by default. Therefore querying any additional adapters is
// futile and not useful for our purposes in general, except for
// identifying a few special cases later on.
HRESULT hr = direct3D9->GetAdapterIdentifier(0, 0, &adapterIdentifier);
if (SUCCEEDED(hr)) {
result.vendorId = adapterIdentifier.VendorId;
result.deviceId = adapterIdentifier.DeviceId;
result.revision = adapterIdentifier.Revision;
result.subSysId = 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;
if (direct3D9.retrieveAdapterIdentifier(0, &adapterIdentifier)) {
result = adapterIdentifierToGpuDescription(adapterIdentifier);
isAMD = result.vendorId == VENDOR_ID_AMD;
}
@ -106,30 +145,41 @@ GpuDescription GpuDescription::detect()
// when starting apps on a screen connected to the Intel card) by looking
// for a default AMD adapter and an additional non-AMD one.
if (isAMD) {
const UINT adapterCount = direct3D9->GetAdapterCount();
const UINT adapterCount = direct3D9.adapterCount();
for (UINT adp = 1; adp < adapterCount; ++adp) {
hr = direct3D9->GetAdapterIdentifier(adp, 0, &adapterIdentifier);
if (SUCCEEDED(hr)) {
if (adapterIdentifier.VendorId != VENDOR_ID_AMD) {
// Bingo. Now figure out the display for the AMD card.
DISPLAY_DEVICE dd;
memset(&dd, 0, sizeof(dd));
dd.cb = sizeof(dd);
for (int dev = 0; EnumDisplayDevices(nullptr, dev, &dd, 0); ++dev) {
if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
// DeviceName is something like \\.\DISPLAY1 which can be used to
// match with the MONITORINFOEX::szDevice queried by QWindowsScreen.
result.gpuSuitableScreen = QString::fromWCharArray(dd.DeviceName);
break;
}
if (direct3D9.retrieveAdapterIdentifier(adp, &adapterIdentifier)
&& adapterIdentifier.VendorId != VENDOR_ID_AMD) {
// Bingo. Now figure out the display for the AMD card.
DISPLAY_DEVICE dd;
memset(&dd, 0, sizeof(dd));
dd.cb = sizeof(dd);
for (int dev = 0; EnumDisplayDevices(nullptr, dev, &dd, 0); ++dev) {
if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
// DeviceName is something like \\.\DISPLAY1 which can be used to
// match with the MONITORINFOEX::szDevice queried by QWindowsScreen.
result.gpuSuitableScreen = QString::fromWCharArray(dd.DeviceName);
break;
}
break;
}
break;
}
}
}
direct3D9->Release();
return result;
}
QVector<GpuDescription> GpuDescription::detectAll()
{
QVector<GpuDescription> result;
QDirect3D9Handle direct3D9;
if (const UINT adapterCount = direct3D9.adapterCount()) {
for (UINT adp = 0; adp < adapterCount; ++adp) {
D3DADAPTER_IDENTIFIER9 adapterIdentifier;
if (direct3D9.retrieveAdapterIdentifier(adp, &adapterIdentifier))
result.append(adapterIdentifierToGpuDescription(adapterIdentifier));
}
}
return result;
}

View File

@ -42,6 +42,7 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qflags.h>
#include <QtCore/qvector.h>
#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
@ -52,6 +53,7 @@ class QVariant;
struct GpuDescription
{
static GpuDescription detect();
static QVector<GpuDescription> detectAll();
QString toString() const;
QVariant toVariant() const;