23constexpr const char* kEnvRhiDebug =
"QGC_RHI_DEBUG";
24constexpr const char* kEnvRhiPipelineCache =
"QGC_RHI_PIPELINE_CACHE";
25constexpr const char* kEnvHdrOutput =
"QGC_HDR_OUTPUT";
26constexpr const char* kEnvForceVideoGpu =
"QGC_FORCE_VIDEO_GPU";
28bool envFlag(
const char* name)
30 return qEnvironmentVariableIsSet(name) && (qEnvironmentVariable(name) != QLatin1String(
"0"));
33bool envEnabledByDefault(
const char* name)
35 return !qEnvironmentVariableIsSet(name) || (qEnvironmentVariable(name) != QLatin1String(
"0"));
38void configurePipelineCache(QQuickGraphicsConfiguration&
config)
40 if (!envEnabledByDefault(kEnvRhiPipelineCache)) {
44 const QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
45 if (cacheDir.isEmpty()) {
46 qCWarning(GraphicsSetupLog) <<
"RHI pipeline cache disabled: no writable cache location";
51 if (!dir.mkpath(cacheDir)) {
52 qCWarning(GraphicsSetupLog) <<
"RHI pipeline cache disabled: failed to create" << cacheDir;
56 const QString cacheFile = cacheDir + QStringLiteral(
"/qgc_rhi_pipeline.cache");
60 if (QFileInfo::exists(cacheFile)) {
61 config.setPipelineCacheLoadFile(cacheFile);
63 config.setPipelineCacheSaveFile(cacheFile);
64 qCDebug(GraphicsSetupLog) <<
"RHI pipeline cache:" << cacheFile;
68bool parseHex32(
const QString& spec, quint32& value)
70 QString token = spec.trimmed();
71 if (token.startsWith(QLatin1String(
"0x"), Qt::CaseInsensitive)) {
75 if (token.isEmpty()) {
80 value = token.toUInt(&ok, 16);
84qint32 signExtend32(quint32 value)
86 const qint64 signedValue =
87 (value <= 0x7FFFFFFFU) ? static_cast<qint64>(value) : (
static_cast<qint64
>(value) - 0x100000000LL);
88 return static_cast<qint32
>(signedValue);
91bool parseLuid(
const QString& spec, quint32& low, qint32& high)
93 const QStringList parts = spec.split(QLatin1Char(
':'));
94 if (parts.size() != 2) {
99 if (!parseHex32(parts.at(0), low) || !parseHex32(parts.at(1), highRaw)) {
103 high = signExtend32(highRaw);
107void configureForcedD3DAdapter(QQuickWindow* window)
109 if (!qEnvironmentVariableIsSet(kEnvForceVideoGpu)) {
113 const QString spec = qEnvironmentVariable(kEnvForceVideoGpu);
116 if (!parseLuid(spec, luidLow, luidHigh)) {
117 qCWarning(GraphicsSetupLog) <<
"QGC_FORCE_VIDEO_GPU malformed (expected hex 'low:high'):" << spec;
122 window->setGraphicsDevice(QQuickGraphicsDevice::fromAdapter(luidLow, luidHigh));
123 qCWarning(GraphicsSetupLog).nospace()
124 <<
"QGC_FORCE_VIDEO_GPU: forcing adapter LUID low=0x" << QString::number(luidLow, 16) <<
" high=0x"
125 << QString::number(
static_cast<quint32
>(luidHigh), 16);
128void warnForcedGpuUnsupported()
130 if (qEnvironmentVariableIsSet(kEnvForceVideoGpu)) {
131 qCWarning(GraphicsSetupLog)
132 <<
"QGC_FORCE_VIDEO_GPU is Windows/D3D-only; ignoring LUID" << qEnvironmentVariable(kEnvForceVideoGpu);
137const char* hdrFormatName(QRhiSwapChain::Format f)
140 case QRhiSwapChain::SDR:
142 case QRhiSwapChain::HDRExtendedSrgbLinear:
143 return "HDRExtendedSrgbLinear";
144 case QRhiSwapChain::HDR10:
146 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
147 return "HDRExtendedDisplayP3Linear";
152void probeHdr(QQuickWindow* window)
154 QRhi* rhi = window->rhi();
156 qCWarning(GraphicsSetupLog) <<
"HDR probe: no QRhi on render thread";
160 std::unique_ptr<QRhiSwapChain> sc(rhi->newSwapChain());
162 qCWarning(GraphicsSetupLog) <<
"HDR probe: backend has no swapchain support";
165 sc->setWindow(window);
167 const QRhiSwapChainHdrInfo info = sc->hdrInfo();
168 qCDebug(GraphicsSetupLog).nospace()
169 <<
"HDR display info: limitsType=" <<
static_cast<int>(info.limitsType)
170 <<
" luminanceBehavior=" <<
static_cast<int>(info.luminanceBehavior) <<
" sdrWhiteLevel=" << info.sdrWhiteLevel;
172 for (
const QRhiSwapChain::Format f :
173 {QRhiSwapChain::HDRExtendedSrgbLinear, QRhiSwapChain::HDR10, QRhiSwapChain::HDRExtendedDisplayP3Linear}) {
174 qCDebug(GraphicsSetupLog) <<
"HDR format" << hdrFormatName(f) <<
"supported:" << sc->isFormatSupported(f);
177 if (envFlag(kEnvHdrOutput)) {
178 qCWarning(GraphicsSetupLog)
179 <<
"QGC_HDR_OUTPUT set but Qt Quick exposes no public swapchain-format setter in this"
180 <<
"Qt version; staying on SDR. (Diagnostic only.)";
189 qCWarning(GraphicsSetupLog) <<
"configureMainWindow: null window";
193 if (window->isSceneGraphInitialized()) {
194 qCWarning(GraphicsSetupLog)
195 <<
"Scene graph already initialized before configureMainWindow; skipping RHI config";
197 QQuickGraphicsConfiguration
config = window->graphicsConfiguration();
199 if (envFlag(kEnvRhiDebug)) {
200 config.setDebugLayer(
true);
201 config.setDebugMarkers(
true);
202 config.setTimestamps(
true);
203 qCDebug(GraphicsSetupLog) <<
"RHI debug layer/markers/timestamps enabled";
206 configurePipelineCache(
config);
207 window->setGraphicsConfiguration(
config);
210 configureForcedD3DAdapter(window);
212 warnForcedGpuUnsupported();
216 if (!envFlag(kEnvRhiDebug) && !envFlag(kEnvHdrOutput)) {
219 QQuickWindow* win = window;
220 if (win->isSceneGraphInitialized()) {
221 win->scheduleRenderJob(QRunnable::create([win]() { probeHdr(win); }), QQuickWindow::BeforeSynchronizingStage);
225 win, &QQuickWindow::sceneGraphInitialized, win, [win]() { probeHdr(win); }, Qt::DirectConnection);