rhi: Add a flag to indicate preferring a software adapter

...if there is one and the concept is applicable in the first place.

Change-Id: Iab202c1c1cdd229f4910159de4cae7ce30805ea9
Reviewed-by: Christian Strømme <christian.stromme@qt.io>
This commit is contained in:
Laszlo Agocs 2019-09-11 11:09:05 +02:00
parent 8fef0ffc16
commit ef78a2e8f9
5 changed files with 67 additions and 4 deletions

View File

@ -439,6 +439,18 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
visible in external GPU debugging tools will not be available and functions
like QRhiCommandBuffer::debugMarkBegin() will become a no-op. Avoid
enabling in production builds as it may involve a performance penalty.
\value PreferSoftwareRenderer Indicates that backends should prefer
choosing an adapter or physical device that renders in software on the CPU.
For example, with Direct3D there is typically a "Basic Render Driver"
adapter available with \c{DXGI_ADAPTER_FLAG_SOFTWARE}. Setting this flag
requests the backend to choose that adapter over any other, as long as no
specific adapter was forced by other backend-specific means. With Vulkan
this maps to preferring physical devices with
\c{VK_PHYSICAL_DEVICE_TYPE_CPU}. When not available, or when it is not
possible to decide if an adapter/device is software-based, this flag is
ignored. It may also be ignored with graphics APIs that have no concept and
means of enumerating adapters/devices.
*/
/*!

View File

@ -1294,7 +1294,8 @@ public:
enum Flag {
EnableProfiling = 1 << 0,
EnableDebugMarkers = 1 << 1
EnableDebugMarkers = 1 << 1,
PreferSoftwareRenderer = 1 << 2
};
Q_DECLARE_FLAGS(Flags, Flag)

View File

@ -119,6 +119,11 @@ QT_BEGIN_NAMESPACE
\c{ID3D11Texture2D *}.
*/
// help mingw with its ancient sdk headers
#ifndef DXGI_ADAPTER_FLAG_SOFTWARE
#define DXGI_ADAPTER_FLAG_SOFTWARE 2
#endif
QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice)
: ofr(this),
deviceCurse(this)
@ -227,11 +232,29 @@ bool QRhiD3D11::create(QRhi::Flags flags)
int requestedAdapterIndex = -1;
if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX"))
requestedAdapterIndex = qEnvironmentVariableIntValue("QT_D3D_ADAPTER_INDEX");
if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
adapter->Release();
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
requestedAdapterIndex = adapterIndex;
break;
}
}
}
for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
const QString name = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description));
qCDebug(QRHI_LOG_INFO, "Adapter %d: '%s' (flags 0x%x)", adapterIndex, qPrintable(name), desc.Flags);
qCDebug(QRHI_LOG_INFO, "Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
adapterIndex,
qPrintable(name),
desc.VendorId,
desc.DeviceId,
desc.Flags);
if (!adapterToUse && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
adapterToUse = adapter;
qCDebug(QRHI_LOG_INFO, " using this adapter");

View File

@ -388,22 +388,42 @@ bool QRhiVulkan::create(QRhi::Flags flags)
qWarning("Failed to enumerate physical devices: %d", err);
return false;
}
int physDevIndex = -1;
int requestedPhysDevIndex = -1;
if (qEnvironmentVariableIsSet("QT_VK_PHYSICAL_DEVICE_INDEX"))
requestedPhysDevIndex = qEnvironmentVariableIntValue("QT_VK_PHYSICAL_DEVICE_INDEX");
if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
for (int i = 0; i < int(physDevCount); ++i) {
f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
requestedPhysDevIndex = i;
break;
}
}
}
for (int i = 0; i < int(physDevCount); ++i) {
f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
qCDebug(QRHI_LOG_INFO, "Physical device %d: '%s' %d.%d.%d", i,
qCDebug(QRHI_LOG_INFO, "Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
i,
physDevProperties.deviceName,
VK_VERSION_MAJOR(physDevProperties.driverVersion),
VK_VERSION_MINOR(physDevProperties.driverVersion),
VK_VERSION_PATCH(physDevProperties.driverVersion));
VK_VERSION_PATCH(physDevProperties.driverVersion),
VK_VERSION_MAJOR(physDevProperties.apiVersion),
VK_VERSION_MINOR(physDevProperties.apiVersion),
VK_VERSION_PATCH(physDevProperties.apiVersion),
physDevProperties.vendorID,
physDevProperties.deviceID,
physDevProperties.deviceType);
if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex == int(i))) {
physDevIndex = i;
qCDebug(QRHI_LOG_INFO, " using this physical device");
}
}
if (physDevIndex < 0) {
qWarning("No matching physical device");
return false;

View File

@ -473,6 +473,10 @@ int main(int argc, char **argv)
"(generate a device reset every <count> frames when on D3D11)"),
QLatin1String("count"));
cmdLineParser.addOption(tdrOption);
// Allow testing preferring the software adapter (D3D).
QCommandLineOption swOption(QLatin1String("software"), QLatin1String("Prefer a software renderer when choosing the adapter. "
"Only applicable with some APIs and platforms."));
cmdLineParser.addOption(swOption);
cmdLineParser.process(app);
if (cmdLineParser.isSet(nullOption))
@ -534,6 +538,9 @@ int main(int argc, char **argv)
if (cmdLineParser.isSet(tdrOption))
framesUntilTdr = cmdLineParser.value(tdrOption).toInt();
if (cmdLineParser.isSet(swOption))
rhiFlags |= QRhi::PreferSoftwareRenderer;
// Create and show the window.
Window w;
#if QT_CONFIG(vulkan)