22constexpr const char* kEnvRhiDebug =
"QGC_RHI_DEBUG";
23constexpr const char* kEnvRhiPipelineCache =
"QGC_RHI_PIPELINE_CACHE";
24constexpr const char* kEnvHdrOutput =
"QGC_HDR_OUTPUT";
25constexpr const char* kEnvForceVideoGpu =
"QGC_FORCE_VIDEO_GPU";
27bool envFlag(
const char* name)
29 return qEnvironmentVariableIsSet(name) && (qEnvironmentVariable(name) != QLatin1String(
"0"));
32bool envEnabledByDefault(
const char* name)
34 return !qEnvironmentVariableIsSet(name) || (qEnvironmentVariable(name) != QLatin1String(
"0"));
37void configurePipelineCache(QQuickGraphicsConfiguration&
config)
39 if (!envEnabledByDefault(kEnvRhiPipelineCache)) {
43 const QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
44 if (cacheDir.isEmpty()) {
45 qCWarning(GraphicsSetupLog) <<
"RHI pipeline cache disabled: no writable cache location";
50 if (!dir.mkpath(cacheDir)) {
51 qCWarning(GraphicsSetupLog) <<
"RHI pipeline cache disabled: failed to create" << cacheDir;
55 const QString cacheFile = cacheDir + QStringLiteral(
"/qgc_rhi_pipeline.cache");
56 config.setPipelineCacheLoadFile(cacheFile);
57 config.setPipelineCacheSaveFile(cacheFile);
58 qCDebug(GraphicsSetupLog) <<
"RHI pipeline cache:" << cacheFile;
62bool parseHex32(
const QString& spec, quint32& value)
64 QString token = spec.trimmed();
65 if (token.startsWith(QLatin1String(
"0x"), Qt::CaseInsensitive)) {
69 if (token.isEmpty()) {
74 value = token.toUInt(&ok, 16);
78qint32 signExtend32(quint32 value)
80 const qint64 signedValue =
81 (value <= 0x7FFFFFFFU) ? static_cast<qint64>(value) : (
static_cast<qint64
>(value) - 0x100000000LL);
82 return static_cast<qint32
>(signedValue);
85bool parseLuid(
const QString& spec, quint32& low, qint32& high)
87 const QStringList parts = spec.split(QLatin1Char(
':'));
88 if (parts.size() != 2) {
93 if (!parseHex32(parts.at(0), low) || !parseHex32(parts.at(1), highRaw)) {
97 high = signExtend32(highRaw);
101void configureForcedD3DAdapter(QQuickWindow* window)
103 if (!qEnvironmentVariableIsSet(kEnvForceVideoGpu)) {
107 const QString spec = qEnvironmentVariable(kEnvForceVideoGpu);
110 if (!parseLuid(spec, luidLow, luidHigh)) {
111 qCWarning(GraphicsSetupLog) <<
"QGC_FORCE_VIDEO_GPU malformed (expected hex 'low:high'):" << spec;
116 window->setGraphicsDevice(QQuickGraphicsDevice::fromAdapter(luidLow, luidHigh));
117 qCWarning(GraphicsSetupLog).nospace()
118 <<
"QGC_FORCE_VIDEO_GPU: forcing adapter LUID low=0x" << QString::number(luidLow, 16) <<
" high=0x"
119 << QString::number(
static_cast<quint32
>(luidHigh), 16);
122void warnForcedGpuUnsupported()
124 if (qEnvironmentVariableIsSet(kEnvForceVideoGpu)) {
125 qCWarning(GraphicsSetupLog)
126 <<
"QGC_FORCE_VIDEO_GPU is Windows/D3D-only; ignoring LUID" << qEnvironmentVariable(kEnvForceVideoGpu);
131const char* hdrFormatName(QRhiSwapChain::Format f)
134 case QRhiSwapChain::SDR:
136 case QRhiSwapChain::HDRExtendedSrgbLinear:
137 return "HDRExtendedSrgbLinear";
138 case QRhiSwapChain::HDR10:
140 case QRhiSwapChain::HDRExtendedDisplayP3Linear:
141 return "HDRExtendedDisplayP3Linear";
146void probeHdr(QQuickWindow* window)
148 QRhi* rhi = window->rhi();
150 qCWarning(GraphicsSetupLog) <<
"HDR probe: no QRhi on render thread";
154 std::unique_ptr<QRhiSwapChain> sc(rhi->newSwapChain());
156 qCWarning(GraphicsSetupLog) <<
"HDR probe: backend has no swapchain support";
159 sc->setWindow(window);
161 const QRhiSwapChainHdrInfo info = sc->hdrInfo();
162 qCDebug(GraphicsSetupLog).nospace()
163 <<
"HDR display info: limitsType=" <<
static_cast<int>(info.limitsType)
164 <<
" luminanceBehavior=" <<
static_cast<int>(info.luminanceBehavior) <<
" sdrWhiteLevel=" << info.sdrWhiteLevel;
166 for (
const QRhiSwapChain::Format f :
167 {QRhiSwapChain::HDRExtendedSrgbLinear, QRhiSwapChain::HDR10, QRhiSwapChain::HDRExtendedDisplayP3Linear}) {
168 qCDebug(GraphicsSetupLog) <<
"HDR format" << hdrFormatName(f) <<
"supported:" << sc->isFormatSupported(f);
171 if (envFlag(kEnvHdrOutput)) {
172 qCWarning(GraphicsSetupLog)
173 <<
"QGC_HDR_OUTPUT set but Qt Quick exposes no public swapchain-format setter in this"
174 <<
"Qt version; staying on SDR. (Diagnostic only.)";
183 qCWarning(GraphicsSetupLog) <<
"configureMainWindow: null window";
187 if (window->isSceneGraphInitialized()) {
188 qCWarning(GraphicsSetupLog)
189 <<
"Scene graph already initialized before configureMainWindow; skipping RHI config";
191 QQuickGraphicsConfiguration
config = window->graphicsConfiguration();
193 if (envFlag(kEnvRhiDebug)) {
194 config.setDebugLayer(
true);
195 config.setDebugMarkers(
true);
196 config.setTimestamps(
true);
197 qCDebug(GraphicsSetupLog) <<
"RHI debug layer/markers/timestamps enabled";
200 configurePipelineCache(
config);
201 window->setGraphicsConfiguration(
config);
204 configureForcedD3DAdapter(window);
206 warnForcedGpuUnsupported();
210 if (!envFlag(kEnvRhiDebug) && !envFlag(kEnvHdrOutput)) {
213 QQuickWindow* win = window;
214 if (win->isSceneGraphInitialized()) {
215 win->scheduleRenderJob(QRunnable::create([win]() { probeHdr(win); }), QQuickWindow::BeforeSynchronizingStage);
219 win, &QQuickWindow::sceneGraphInitialized, win, [win]() { probeHdr(win); }, Qt::DirectConnection);