diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 786479fccd..718835ad8f 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -4735,6 +4735,100 @@ QRhi::Implementation QRhi::backend() const return d->implType; } +/*! + \return the backend type as string for this QRhi. + */ +const char *QRhi::backendName() const +{ + switch (d->implType) { + case QRhi::Null: + return "Null"; + case QRhi::Vulkan: + return "Vulkan"; + case QRhi::OpenGLES2: + return "OpenGL"; + case QRhi::D3D11: + return "D3D11"; + case QRhi::Metal: + return "Metal"; + default: + return "Unknown"; + } +} + +/*! + \enum QRhiDriverInfo::DeviceType + Specifies the graphics device's type, when the information is available. In + practice this is only applicable with Vulkan and Metal. With others the + value will always be UnknownDevice. + + \value UnknownDevice + \value IntegratedDevice + \value DiscreteDevice + \value ExternalDevice + \value VirtualDevice + \value CpuDevice +*/ + +/*! + \struct QRhiDriverInfo + \internal + \inmodule QtGui + \since 6.1 + + \brief Describes the physical device, adapter, or graphics API + implementation that is used by an initialized QRhi. + + Graphics APIs offer different levels and kinds of information. The only + value that is available across all APIs is the deviceName, which is a + freetext description of the physical device, adapter, or is a combination + of the strings reported for \c{GL_VENDOR} + \c{GL_RENDERER} + + \c{GL_VERSION}. The deviceId is always 0 for OpenGL. vendorId is always 0 + for OpenGL and Metal. deviceType is always UnknownDevice for OpenGL and + Direct 3D. + */ + +#ifndef QT_NO_DEBUG_STREAM +static inline const char *deviceTypeStr(QRhiDriverInfo::DeviceType type) +{ + switch (type) { + case QRhiDriverInfo::UnknownDevice: + return "Unknown"; + case QRhiDriverInfo::IntegratedDevice: + return "Integrated"; + case QRhiDriverInfo::DiscreteDevice: + return "Discrete"; + case QRhiDriverInfo::ExternalDevice: + return "External"; + case QRhiDriverInfo::VirtualDevice: + return "Virtual"; + case QRhiDriverInfo::CpuDevice: + return "Cpu"; + default: + return ""; + } +} +QDebug operator<<(QDebug dbg, const QRhiDriverInfo &info) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "QRhiDriverInfo(deviceName=" << info.deviceName + << " deviceId=0x" << Qt::hex << info.deviceId + << " vendorId=0x" << info.vendorId + << " deviceType=" << deviceTypeStr(info.deviceType) + << ')'; + return dbg; +} +#endif + +/*! + \return metadata for the graphics device used by this successfully + initialized QRhi instance. + */ +QRhiDriverInfo QRhi::driverInfo() const +{ + return d->driverInfo(); +} + /*! \return the thread on which the QRhi was \l{QRhi::create()}{initialized}. */ diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 14ea81abec..fc65587408 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -1443,6 +1443,29 @@ private: friend class QRhi; }; +struct Q_GUI_EXPORT QRhiDriverInfo +{ + enum DeviceType { + UnknownDevice, + IntegratedDevice, + DiscreteDevice, + ExternalDevice, + VirtualDevice, + CpuDevice + }; + + QByteArray deviceName; + quint64 deviceId = 0; + quint64 vendorId = 0; + DeviceType deviceType = UnknownDevice; +}; + +Q_DECLARE_TYPEINFO(QRhiDriverInfo, Q_RELOCATABLE_TYPE); + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiDriverInfo &); +#endif + struct Q_GUI_EXPORT QRhiInitParams { }; @@ -1530,6 +1553,8 @@ public: QRhiNativeHandles *importDevice = nullptr); Implementation backend() const; + const char *backendName() const; + QRhiDriverInfo driverInfo() const; QThread *thread() const; using CleanupCallback = std::function; diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index 538df66868..af974b69d0 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -162,6 +162,7 @@ public: virtual bool isFeatureSupported(QRhi::Feature feature) const = 0; virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0; virtual const QRhiNativeHandles *nativeHandles() = 0; + virtual QRhiDriverInfo driverInfo() const = 0; virtual void sendVMemStatsToProfiler() = 0; virtual bool makeThreadLocalNativeContextCurrent() = 0; virtual void releaseCachedResources() = 0; diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 0db32e794f..247d51ecc8 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -220,7 +220,6 @@ bool QRhiD3D11::create(QRhi::Flags flags) hasDxgi2 ? "true" : "false", supportsFlipDiscardSwapchain ? "true" : "false"); if (!importedDeviceAndContext) { - IDXGIAdapter1 *adapterToUse = nullptr; IDXGIAdapter1 *adapter; int requestedAdapterIndex = -1; if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX")) @@ -253,6 +252,7 @@ bool QRhiD3D11::create(QRhi::Flags flags) } } + IDXGIAdapter1 *adapterToUse = nullptr; for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) { DXGI_ADAPTER_DESC1 desc; adapter->GetDesc1(&desc); @@ -266,6 +266,9 @@ bool QRhiD3D11::create(QRhi::Flags flags) if (!adapterToUse && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) { adapterToUse = adapter; adapterLuid = desc.AdapterLuid; + driverInfoStruct.deviceName = name.toUtf8(); + driverInfoStruct.deviceId = desc.DeviceId; + driverInfoStruct.vendorId = desc.VendorId; qCDebug(QRHI_LOG_INFO, " using this adapter"); } else { adapter->Release(); @@ -323,6 +326,9 @@ bool QRhiD3D11::create(QRhi::Flags flags) DXGI_ADAPTER_DESC desc; adapter->GetDesc(&desc); adapterLuid = desc.AdapterLuid; + driverInfoStruct.deviceName = QString::fromUtf16(reinterpret_cast(desc.Description)).toUtf8(); + driverInfoStruct.deviceId = desc.DeviceId; + driverInfoStruct.vendorId = desc.VendorId; adapter->Release(); } dxgiDev->Release(); @@ -575,6 +581,11 @@ const QRhiNativeHandles *QRhiD3D11::nativeHandles() return &nativeHandlesStruct; } +QRhiDriverInfo QRhiD3D11::driverInfo() const +{ + return driverInfoStruct; +} + void QRhiD3D11::sendVMemStatsToProfiler() { // nothing to do here diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 3b56393900..80e5ee10ae 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -671,6 +671,7 @@ public: bool isFeatureSupported(QRhi::Feature feature) const override; int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; + QRhiDriverInfo driverInfo() const override; void sendVMemStatsToProfiler() override; bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; @@ -704,6 +705,7 @@ public: bool supportsFlipDiscardSwapchain = false; bool deviceLost = false; QRhiD3D11NativeHandles nativeHandlesStruct; + QRhiDriverInfo driverInfoStruct; struct { int vsHighestActiveVertexBufferBinding = -1; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 00477b0716..014d603724 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -461,6 +461,17 @@ bool QRhiGles2::create(QRhi::Flags flags) if (vendor && renderer && version) qCDebug(QRHI_LOG_INFO, "OpenGL VENDOR: %s RENDERER: %s VERSION: %s", vendor, renderer, version); + if (vendor) { + driverInfoStruct.deviceName += QByteArray(vendor); + driverInfoStruct.deviceName += ' '; + } + if (renderer) { + driverInfoStruct.deviceName += QByteArray(renderer); + driverInfoStruct.deviceName += ' '; + } + if (version) + driverInfoStruct.deviceName += QByteArray(version); + const QSurfaceFormat actualFormat = ctx->format(); caps.ctxMajor = actualFormat.majorVersion(); @@ -990,6 +1001,11 @@ const QRhiNativeHandles *QRhiGles2::nativeHandles() return &nativeHandlesStruct; } +QRhiDriverInfo QRhiGles2::driverInfo() const +{ + return driverInfoStruct; +} + void QRhiGles2::sendVMemStatsToProfiler() { // nothing to do here diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index a336497b63..4f4e0f8491 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -807,6 +807,7 @@ public: bool isFeatureSupported(QRhi::Feature feature) const override; int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; + QRhiDriverInfo driverInfo() const override; void sendVMemStatsToProfiler() override; bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; @@ -957,6 +958,7 @@ public: QList supportedCompressedFormats; mutable QList supportedSampleCountList; QRhiGles2NativeHandles nativeHandlesStruct; + QRhiDriverInfo driverInfoStruct; mutable bool contextLost = false; struct DeferredReleaseEntry { diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 9e0655ef06..5a1183b8ef 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -372,7 +372,30 @@ bool QRhiMetal::create(QRhi::Flags flags) return false; } - qCDebug(QRHI_LOG_INFO, "Metal device: %s", qPrintable(QString::fromNSString([d->dev name]))); + const QString deviceName = QString::fromNSString([d->dev name]); + qCDebug(QRHI_LOG_INFO, "Metal device: %s", qPrintable(deviceName)); + driverInfoStruct.deviceName = deviceName.toUtf8(); + driverInfoStruct.deviceId = [d->dev registryID]; +#ifdef Q_OS_IOS + driverInfoStruct.deviceType = QRhiDriverInfo::IntegratedDevice; +#else + if (@available(macOS 10.15, *)) { + const MTLDeviceLocation deviceLocation = [d->dev location]; + switch (deviceLocation) { + case MTLDeviceLocationBuiltIn: + driverInfoStruct.deviceType = QRhiDriverInfo::IntegratedDevice; + break; + case MTLDeviceLocationSlot: + driverInfoStruct.deviceType = QRhiDriverInfo::DiscreteDevice; + break; + case MTLDeviceLocationExternal: + driverInfoStruct.deviceType = QRhiDriverInfo::ExternalDevice; + break; + default: + break; + } + } +#endif if (importedCmdQueue) [d->cmdQueue retain]; @@ -615,6 +638,11 @@ const QRhiNativeHandles *QRhiMetal::nativeHandles() return &nativeHandlesStruct; } +QRhiDriverInfo QRhiMetal::driverInfo() const +{ + return driverInfoStruct; +} + void QRhiMetal::sendVMemStatsToProfiler() { // nothing to do here diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index d2082d04b6..3d1c0f8aa0 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -435,6 +435,7 @@ public: bool isFeatureSupported(QRhi::Feature feature) const override; int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; + QRhiDriverInfo driverInfo() const override; void sendVMemStatsToProfiler() override; bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; @@ -463,6 +464,7 @@ public: QMetalSwapChain *currentSwapChain = nullptr; QSet swapchains; QRhiMetalNativeHandles nativeHandlesStruct; + QRhiDriverInfo driverInfoStruct; struct { int maxTextureSize = 4096; diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index 9666f4c688..dbcf8673fd 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -170,6 +170,13 @@ const QRhiNativeHandles *QRhiNull::nativeHandles() return &nativeHandlesStruct; } +QRhiDriverInfo QRhiNull::driverInfo() const +{ + QRhiDriverInfo info; + info.deviceName = QByteArrayLiteral("Null"); + return info; +} + void QRhiNull::sendVMemStatsToProfiler() { // nothing to do here diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h index eda30614a0..cc8becc5a8 100644 --- a/src/gui/rhi/qrhinull_p_p.h +++ b/src/gui/rhi/qrhinull_p_p.h @@ -292,6 +292,7 @@ public: bool isFeatureSupported(QRhi::Feature feature) const override; int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; + QRhiDriverInfo driverInfo() const override; void sendVMemStatsToProfiler() override; bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index aa287ce1b9..cb76851d1e 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -361,6 +361,24 @@ static bool qvk_debug_filter(VkDebugReportFlagsEXT flags, VkDebugReportObjectTyp return false; } +static inline QRhiDriverInfo::DeviceType toRhiDeviceType(VkPhysicalDeviceType type) +{ + switch (type) { + case VK_PHYSICAL_DEVICE_TYPE_OTHER: + return QRhiDriverInfo::UnknownDevice; + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + return QRhiDriverInfo::IntegratedDevice; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + return QRhiDriverInfo::DiscreteDevice; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: + return QRhiDriverInfo::VirtualDevice; + case VK_PHYSICAL_DEVICE_TYPE_CPU: + return QRhiDriverInfo::CpuDevice; + default: + return QRhiDriverInfo::UnknownDevice; + } +} + bool QRhiVulkan::create(QRhi::Flags flags) { Q_UNUSED(flags); @@ -454,6 +472,11 @@ bool QRhiVulkan::create(QRhi::Flags flags) physDevProperties.deviceType); } + driverInfoStruct.deviceName = QByteArray(physDevProperties.deviceName); + driverInfoStruct.deviceId = physDevProperties.deviceID; + driverInfoStruct.vendorId = physDevProperties.vendorID; + driverInfoStruct.deviceType = toRhiDeviceType(physDevProperties.deviceType); + f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures); // Choose queue and create device, unless the device was specified in importParams. @@ -4224,6 +4247,11 @@ const QRhiNativeHandles *QRhiVulkan::nativeHandles() return &nativeHandlesStruct; } +QRhiDriverInfo QRhiVulkan::driverInfo() const +{ + return driverInfoStruct; +} + void QRhiVulkan::sendVMemStatsToProfiler() { QRhiProfilerPrivate *rhiP = profilerPrivateOrNull(); diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 31edcc6924..a4b306d5c0 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -750,6 +750,7 @@ public: bool isFeatureSupported(QRhi::Feature feature) const override; int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; + QRhiDriverInfo driverInfo() const override; void sendVMemStatsToProfiler() override; bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; @@ -889,6 +890,7 @@ public: QVkSwapChain *currentSwapChain = nullptr; QSet swapchains; QRhiVulkanNativeHandles nativeHandlesStruct; + QRhiDriverInfo driverInfoStruct; struct OffscreenFrame { OffscreenFrame(QRhiImplementation *rhi) diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index 6dbd0599e4..db83f7955f 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -228,7 +228,11 @@ void tst_QRhi::create() QScopedPointer rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); if (rhi) { + qDebug() << rhi->driverInfo(); + QCOMPARE(rhi->backend(), impl); + QVERIFY(strcmp(rhi->backendName(), "")); + QVERIFY(!rhi->driverInfo().deviceName.isEmpty()); QCOMPARE(rhi->thread(), QThread::currentThread()); // do a basic smoke test for the apis that do not directly render anything