aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgrhisupport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/qsgrhisupport.cpp')
-rw-r--r--src/quick/scenegraph/qsgrhisupport.cpp209
1 files changed, 155 insertions, 54 deletions
diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp
index f18d6a7d00..45c183a5f8 100644
--- a/src/quick/scenegraph/qsgrhisupport.cpp
+++ b/src/quick/scenegraph/qsgrhisupport.cpp
@@ -50,19 +50,22 @@ void QSGRhiSupport::applySettings()
if (m_requested.valid) {
// explicit rhi backend request from C++ (e.g. via QQuickWindow)
switch (m_requested.api) {
- case QSGRendererInterface::OpenGLRhi:
+ case QSGRendererInterface::OpenGL:
m_rhiBackend = QRhi::OpenGLES2;
break;
- case QSGRendererInterface::Direct3D11Rhi:
+ case QSGRendererInterface::Direct3D11:
m_rhiBackend = QRhi::D3D11;
break;
- case QSGRendererInterface::VulkanRhi:
+ case QSGRendererInterface::Direct3D12:
+ m_rhiBackend = QRhi::D3D12;
+ break;
+ case QSGRendererInterface::Vulkan:
m_rhiBackend = QRhi::Vulkan;
break;
- case QSGRendererInterface::MetalRhi:
+ case QSGRendererInterface::Metal:
m_rhiBackend = QRhi::Metal;
break;
- case QSGRendererInterface::NullRhi:
+ case QSGRendererInterface::Null:
m_rhiBackend = QRhi::Null;
break;
default:
@@ -79,6 +82,8 @@ void QSGRhiSupport::applySettings()
m_rhiBackend = QRhi::OpenGLES2;
} else if (rhiBackend == QByteArrayLiteral("d3d11") || rhiBackend == QByteArrayLiteral("d3d")) {
m_rhiBackend = QRhi::D3D11;
+ } else if (rhiBackend == QByteArrayLiteral("d3d12")) {
+ m_rhiBackend = QRhi::D3D12;
} else if (rhiBackend == QByteArrayLiteral("vulkan")) {
m_rhiBackend = QRhi::Vulkan;
} else if (rhiBackend == QByteArrayLiteral("metal")) {
@@ -92,7 +97,7 @@ void QSGRhiSupport::applySettings()
}
#if defined(Q_OS_WIN)
m_rhiBackend = QRhi::D3D11;
-#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#elif QT_CONFIG(metal)
m_rhiBackend = QRhi::Metal;
#elif QT_CONFIG(opengl)
m_rhiBackend = QRhi::OpenGLES2;
@@ -111,26 +116,11 @@ void QSGRhiSupport::applySettings()
// (QQuickWindow) may depend on the graphics API as well (surfaceType
// f.ex.), and all that is based on what we report from here. So further
// adjustments are not possible (or, at minimum, not safe and portable).
-
- m_killDeviceFrameCount = qEnvironmentVariableIntValue("QSG_RHI_SIMULATE_DEVICE_LOSS");
- if (m_killDeviceFrameCount > 0 && m_rhiBackend == QRhi::D3D11)
- qDebug("Graphics device will be reset every %d frames", m_killDeviceFrameCount);
-
- QByteArray hdrRequest = qgetenv("QSG_RHI_HDR");
- if (!hdrRequest.isEmpty()) {
- hdrRequest = hdrRequest.toLower();
- if (hdrRequest == QByteArrayLiteral("scrgb") || hdrRequest == QByteArrayLiteral("extendedsrgblinear"))
- m_swapChainFormat = QRhiSwapChain::HDRExtendedSrgbLinear;
- else if (hdrRequest == QByteArrayLiteral("hdr10"))
- m_swapChainFormat = QRhiSwapChain::HDR10;
- else
- qWarning("Unknown HDR mode '%s'", hdrRequest.constData());
- }
}
void QSGRhiSupport::adjustToPlatformQuirks()
{
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
// A macOS VM may not have Metal support at all. We have to decide at this
// point, it will be too late afterwards, and the only way is to see if
// MTLCreateSystemDefaultDevice succeeds.
@@ -225,12 +215,24 @@ void QSGRhiSupport::checkEnvQSgInfo()
#define GL_RGB10_A2 0x8059
#endif
-QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromGL(uint format)
+#ifndef GL_SRGB_ALPHA
+#define GL_SRGB_ALPHA 0x8C42
+#endif
+
+#ifndef GL_SRGB8_ALPHA8
+#define GL_SRGB8_ALPHA8 0x8C43
+#endif
+
+QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromGL(uint format, QRhiTexture::Flags *flags)
{
+ bool sRGB = false;
auto rhiFormat = QRhiTexture::UnknownFormat;
switch (format) {
- case GL_RGBA:
+ case GL_SRGB_ALPHA:
+ case GL_SRGB8_ALPHA8:
+ sRGB = true;
Q_FALLTHROUGH();
+ case GL_RGBA:
case GL_RGBA8:
case 0:
rhiFormat = QRhiTexture::RGBA8;
@@ -292,6 +294,8 @@ QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromGL(uint format)
qWarning("GL format %d is not supported", format);
break;
}
+ if (sRGB)
+ (*flags) |=(QRhiTexture::sRGB);
return rhiFormat;
}
#endif
@@ -508,7 +512,7 @@ QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromVulkan(uint format, QRh
#endif
#ifdef Q_OS_WIN
-QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromD3D11(uint format, QRhiTexture::Flags *flags)
+QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromDXGI(uint format, QRhiTexture::Flags *flags)
{
auto rhiFormat = QRhiTexture::UnknownFormat;
bool sRGB = false;
@@ -608,7 +612,7 @@ QRhiTexture::Format QSGRhiSupport::toRhiTextureFormatFromD3D11(uint format, QRhi
}
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
namespace QSGRhiSupportMac {
QRhiTexture::Format toRhiTextureFormatFromMetal(uint format, QRhiTexture::Flags *flags);
}
@@ -655,15 +659,17 @@ QSGRendererInterface::GraphicsApi QSGRhiSupport::graphicsApi() const
{
switch (m_rhiBackend) {
case QRhi::Null:
- return QSGRendererInterface::NullRhi;
+ return QSGRendererInterface::Null;
case QRhi::Vulkan:
- return QSGRendererInterface::VulkanRhi;
+ return QSGRendererInterface::Vulkan;
case QRhi::OpenGLES2:
- return QSGRendererInterface::OpenGLRhi;
+ return QSGRendererInterface::OpenGL;
case QRhi::D3D11:
- return QSGRendererInterface::Direct3D11Rhi;
+ return QSGRendererInterface::Direct3D11;
+ case QRhi::D3D12:
+ return QSGRendererInterface::Direct3D12;
case QRhi::Metal:
- return QSGRendererInterface::MetalRhi;
+ return QSGRendererInterface::Metal;
default:
return QSGRendererInterface::Unknown;
}
@@ -677,6 +683,7 @@ QSurface::SurfaceType QSGRhiSupport::windowSurfaceType() const
case QRhi::OpenGLES2:
return QSurface::OpenGLSurface;
case QRhi::D3D11:
+ case QRhi::D3D12:
return QSurface::Direct3DSurface;
case QRhi::Metal:
return QSurface::MetalSurface;
@@ -714,6 +721,10 @@ static const void *qsgrhi_vk_rifResource(QSGRendererInterface::Resource res,
return &maybeVkRpNat->renderPass;
else
return nullptr;
+ case QSGRendererInterface::GraphicsQueueFamilyIndexResource:
+ return &vknat->gfxQueueFamilyIdx;
+ case QSGRendererInterface::GraphicsQueueIndexResource:
+ return &vknat->gfxQueueIdx;
default:
return nullptr;
}
@@ -746,9 +757,22 @@ static const void *qsgrhi_d3d11_rifResource(QSGRendererInterface::Resource res,
return nullptr;
}
}
+
+static const void *qsgrhi_d3d12_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat)
+{
+ const QRhiD3D12NativeHandles *d3dnat = static_cast<const QRhiD3D12NativeHandles *>(nat);
+ switch (res) {
+ case QSGRendererInterface::DeviceResource:
+ return d3dnat->dev;
+ case QSGRendererInterface::CommandQueueResource:
+ return d3dnat->commandQueue;
+ default:
+ return nullptr;
+ }
+}
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
static const void *qsgrhi_mtl_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat,
const QRhiNativeHandles *cbNat)
{
@@ -795,7 +819,7 @@ const void *QSGRhiSupport::rifResource(QSGRendererInterface::Resource res,
case QSGRendererInterface::RhiRedirectCommandBuffer:
return QQuickWindowPrivate::get(w)->redirect.commandBuffer;
case QSGRendererInterface::RhiRedirectRenderTarget:
- return QQuickWindowPrivate::get(w)->redirect.rt.renderTarget;
+ return QQuickWindowPrivate::get(w)->redirect.rt.rt.renderTarget;
default:
break;
}
@@ -822,8 +846,10 @@ const void *QSGRhiSupport::rifResource(QSGRendererInterface::Resource res,
#ifdef Q_OS_WIN
case QRhi::D3D11:
return qsgrhi_d3d11_rifResource(res, nat);
+ case QRhi::D3D12:
+ return qsgrhi_d3d12_rifResource(res, nat);
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
case QRhi::Metal:
{
QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
@@ -1026,8 +1052,18 @@ void QSGRhiSupport::finalizePipelineCache(QRhi *rhi, const QQuickGraphicsConfigu
// If empty, do nothing. This is exactly what will happen if the rhi was
// created without QRhi::EnablePipelineCacheDataSave set.
- if (buf.isEmpty())
+ if (buf.isEmpty()) {
+ if (isAutomatic) {
+ // Attempt to remove the file. If it does not exist or this fails,
+ // that's fine. The goal is just to prevent warnings from
+ // setPipelineCacheData in future runs, e.g. if the Qt or driver
+ // version does not match _and_ we do not generate any data at run
+ // time, then not writing the file out also means the warning would
+ // appear again and again on every run. Prevent that.
+ QDir().remove(pipelineCacheSave);
+ }
return;
+ }
QLockFile lock(pipelineCacheLockFileName(pipelineCacheSave));
if (!lock.lock()) {
@@ -1068,7 +1104,7 @@ void QSGRhiSupport::finalizePipelineCache(QRhi *rhi, const QQuickGraphicsConfigu
}
// must be called on the render thread
-QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QSurface *offscreenSurface)
+QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QSurface *offscreenSurface, bool forcePreferSwRenderer)
{
QRhi *rhi = nullptr;
QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
@@ -1083,7 +1119,8 @@ QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QS
const bool debugLayer = wd->graphicsConfig.isDebugLayerEnabled();
const bool debugMarkers = wd->graphicsConfig.isDebugMarkersEnabled();
- const bool preferSoftware = wd->graphicsConfig.prefersSoftwareDevice();
+ const bool timestamps = wd->graphicsConfig.timestampsEnabled();
+ const bool preferSoftware = wd->graphicsConfig.prefersSoftwareDevice() || forcePreferSwRenderer;
const bool pipelineCacheSave = !wd->graphicsConfig.pipelineCacheSaveFile().isEmpty()
|| (wd->graphicsConfig.isAutomaticPipelineCacheEnabled()
&& !isAutomaticPipelineCacheSaveSkippedForWindow(window->flags()));
@@ -1093,13 +1130,18 @@ QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QS
"Creating QRhi with backend %s for window %p (wflags 0x%X)\n"
" Graphics API debug/validation layers: %d\n"
" Debug markers: %d\n"
- " Prefer software device: %d\n"
+ " Timestamps: %d\n"
+ " Prefer software device: %d%s\n"
" Shader/pipeline cache collection: %d",
- qPrintable(backendName), window, int(window->flags()), debugLayer, debugMarkers, preferSoftware, pipelineCacheSave);
+ qPrintable(backendName), window, int(window->flags()), debugLayer,
+ debugMarkers, timestamps, preferSoftware, forcePreferSwRenderer ? " [FORCED]" : "", pipelineCacheSave);
QRhi::Flags flags;
+ flags |= QRhi::SuppressSmokeTestWarnings;
if (debugMarkers)
flags |= QRhi::EnableDebugMarkers;
+ if (timestamps)
+ flags |= QRhi::EnableTimestamps;
if (preferSoftware)
flags |= QRhi::PreferSoftwareRenderer;
if (pipelineCacheSave)
@@ -1169,10 +1211,6 @@ QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QS
if (backend == QRhi::D3D11) {
QRhiD3D11InitParams rhiParams;
rhiParams.enableDebugLayer = debugLayer;
- if (m_killDeviceFrameCount > 0) {
- rhiParams.framesUntilKillingDeviceViaTdr = m_killDeviceFrameCount;
- rhiParams.repeatDeviceKill = true;
- }
if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndContext) {
QRhiD3D11NativeHandles importDev;
importDev.dev = customDevD->u.deviceAndContext.device;
@@ -1190,7 +1228,32 @@ QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QS
rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
} else {
rhi = QRhi::create(backend, &rhiParams, flags);
- if (!rhi && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
+ if (!rhi && attemptReinitWithSwRastUponFail() && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
+ qCDebug(QSG_LOG_INFO, "Failed to create a D3D device with default settings; "
+ "attempting to get a software rasterizer backed device instead");
+ flags |= QRhi::PreferSoftwareRenderer;
+ rhi = QRhi::create(backend, &rhiParams, flags);
+ }
+ }
+ } else if (backend == QRhi::D3D12) {
+ QRhiD3D12InitParams rhiParams;
+ rhiParams.enableDebugLayer = debugLayer;
+ if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndContext) {
+ QRhiD3D12NativeHandles importDev;
+ importDev.dev = customDevD->u.deviceAndContext.device;
+ qCDebug(QSG_LOG_INFO, "Using existing native D3D12 device %p", importDev.dev);
+ rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
+ } else if (customDevD->type == QQuickGraphicsDevicePrivate::Type::Adapter) {
+ QRhiD3D12NativeHandles importDev;
+ importDev.adapterLuidLow = customDevD->u.adapter.luidLow;
+ importDev.adapterLuidHigh = customDevD->u.adapter.luidHigh;
+ importDev.minimumFeatureLevel = customDevD->u.adapter.featureLevel;
+ qCDebug(QSG_LOG_INFO, "Using D3D12 adapter LUID %u, %d and minimum feature level %d",
+ importDev.adapterLuidLow, importDev.adapterLuidHigh, importDev.minimumFeatureLevel);
+ rhi = QRhi::create(backend, &rhiParams, flags, &importDev);
+ } else {
+ rhi = QRhi::create(backend, &rhiParams, flags);
+ if (!rhi && attemptReinitWithSwRastUponFail() && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
qCDebug(QSG_LOG_INFO, "Failed to create a D3D device with default settings; "
"attempting to get a software rasterizer backed device instead");
flags |= QRhi::PreferSoftwareRenderer;
@@ -1199,7 +1262,7 @@ QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QS
}
}
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
if (backend == QRhi::Metal) {
QRhiMetalInitParams rhiParams;
if (customDevD->type == QQuickGraphicsDevicePrivate::Type::DeviceAndCommandQueue) {
@@ -1460,10 +1523,28 @@ QImage QSGRhiSupport::grabOffscreenForProtectedContent(QQuickWindow *window)
}
#endif
-void QSGRhiSupport::applySwapChainFormat(QRhiSwapChain *scWithWindowSet)
+void QSGRhiSupport::applySwapChainFormat(QRhiSwapChain *scWithWindowSet, QQuickWindow *window)
{
+ Q_ASSERT(scWithWindowSet->window() == window);
+
+ QRhiSwapChain::Format swapChainFormat = QRhiSwapChain::SDR;
+
+ QByteArray hdrRequest = qgetenv("QSG_RHI_HDR");
+ if (hdrRequest.isEmpty())
+ hdrRequest = window->property("_qt_sg_hdr_format").toByteArray();
+
+ if (!hdrRequest.isEmpty()) {
+ hdrRequest = hdrRequest.toLower();
+ if (hdrRequest == QByteArrayLiteral("scrgb") || hdrRequest == QByteArrayLiteral("extendedsrgblinear"))
+ swapChainFormat = QRhiSwapChain::HDRExtendedSrgbLinear;
+ else if (hdrRequest == QByteArrayLiteral("hdr10"))
+ swapChainFormat = QRhiSwapChain::HDR10;
+ else if (hdrRequest == QByteArrayLiteral("p3"))
+ swapChainFormat = QRhiSwapChain::HDRExtendedDisplayP3Linear;
+ }
+
const char *fmtStr = "unknown";
- switch (m_swapChainFormat) {
+ switch (swapChainFormat) {
case QRhiSwapChain::SDR:
fmtStr = "SDR";
break;
@@ -1473,12 +1554,15 @@ void QSGRhiSupport::applySwapChainFormat(QRhiSwapChain *scWithWindowSet)
case QRhiSwapChain::HDR10:
fmtStr = "HDR10";
break;
+ case QRhiSwapChain::HDRExtendedDisplayP3Linear:
+ fmtStr = "Extended Linear Display P3";
+ break;
default:
break;
}
- if (!scWithWindowSet->isFormatSupported(m_swapChainFormat)) {
- if (m_swapChainFormat != QRhiSwapChain::SDR) {
+ if (!scWithWindowSet->isFormatSupported(swapChainFormat)) {
+ if (swapChainFormat != QRhiSwapChain::SDR) {
qCDebug(QSG_LOG_INFO, "Requested a %s swapchain but it is reported to be unsupported with the current display(s). "
"In multi-screen configurations make sure the window is located on a HDR-enabled screen. "
"Request ignored, using SDR swapchain.", fmtStr);
@@ -1486,9 +1570,9 @@ void QSGRhiSupport::applySwapChainFormat(QRhiSwapChain *scWithWindowSet)
return;
}
- scWithWindowSet->setFormat(m_swapChainFormat);
+ scWithWindowSet->setFormat(swapChainFormat);
- if (m_swapChainFormat != QRhiSwapChain::SDR) {
+ if (swapChainFormat != QRhiSwapChain::SDR) {
qCDebug(QSG_LOG_INFO, "Creating %s swapchain", fmtStr);
qCDebug(QSG_LOG_INFO) << "HDR output info:" << scWithWindowSet->hdrInfo();
}
@@ -1504,19 +1588,36 @@ QRhiTexture::Format QSGRhiSupport::toRhiTextureFormat(uint nativeFormat, QRhiTex
#if QT_CONFIG(opengl)
case QRhi::OpenGLES2:
Q_UNUSED(flags);
- return toRhiTextureFormatFromGL(nativeFormat);
+ return toRhiTextureFormatFromGL(nativeFormat, flags);
#endif
#ifdef Q_OS_WIN
case QRhi::D3D11:
- return toRhiTextureFormatFromD3D11(nativeFormat, flags);
+ case QRhi::D3D12:
+ return toRhiTextureFormatFromDXGI(nativeFormat, flags);
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
case QRhi::Metal:
return toRhiTextureFormatFromMetal(nativeFormat, flags);
#endif
default:
return QRhiTexture::UnknownFormat;
}
+ Q_UNUSED(nativeFormat)
+ Q_UNUSED(flags)
+}
+
+bool QSGRhiSupport::attemptReinitWithSwRastUponFail() const
+{
+ const QRhi::Implementation backend = rhiBackend();
+
+ // On Windows it makes sense to retry using a software adapter whenever
+ // device creation or swapchain creation fails, as WARP is usually available
+ // (built in to the OS) and is good quality. This helps a lot in particular
+ // when running in a VM that cripples proper 3D graphics.
+ if (backend == QRhi::D3D11 || backend == QRhi::D3D12)
+ return true;
+
+ return false;
}
QT_END_NAMESPACE