From 6d4f2e50f64cf068c9bd2dd926dc675ee4dde7aa Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 20:51:18 +0200 Subject: [PATCH 01/16] fix: Adjust HDR detection logic for better reliability --- src/Features/HDRDisplay.cpp | 118 ++++++++---------------------------- 1 file changed, 25 insertions(+), 93 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index a7b086329f..7ba0495449 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -90,114 +90,46 @@ namespace return false; } - bool GetAdvancedColorInfo(HWND hwnd, DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO& outColorInfo) - { - DISPLAYCONFIG_PATH_INFO pathInfo{}; - if (GetDisplayConfigPathInfo(hwnd, pathInfo)) { - DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO colorInfo{}; - colorInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO; - colorInfo.header.size = sizeof(colorInfo); - colorInfo.header.adapterId = pathInfo.targetInfo.adapterId; - colorInfo.header.id = pathInfo.targetInfo.id; - if (ERROR_SUCCESS == DisplayConfigGetDeviceInfo(&colorInfo.header)) { - outColorInfo = colorInfo; - return true; - } - } - return false; - } - - // Win11 24H2+ API - uses runtime detection, will fail gracefully on older Windows - bool GetAdvancedColorInfo2(HWND hwnd, DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2& outColorInfo2) - { - DISPLAYCONFIG_PATH_INFO pathInfo{}; - if (GetDisplayConfigPathInfo(hwnd, pathInfo)) { - DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 colorInfo2{}; - colorInfo2.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2; - colorInfo2.header.size = sizeof(colorInfo2); - colorInfo2.header.adapterId = pathInfo.targetInfo.adapterId; - colorInfo2.header.id = pathInfo.targetInfo.id; - // This will fail on older Windows versions that don't support the API - if (ERROR_SUCCESS == DisplayConfigGetDeviceInfo(&colorInfo2.header)) { - outColorInfo2 = colorInfo2; - return true; - } - } - return false; - } - - bool CheckSwapChainHDRSupport(IDXGISwapChain* swapChain, bool& supported, bool& enabled) - { - winrt::com_ptr output; - if (SUCCEEDED(swapChain->GetContainingOutput(output.put()))) { - winrt::com_ptr output6; - if (SUCCEEDED(output->QueryInterface(IID_PPV_ARGS(output6.put())))) { - DXGI_OUTPUT_DESC1 desc1; - if (SUCCEEDED(output6->GetDesc1(&desc1))) { - enabled = desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 || - desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; - supported |= enabled; - logger::debug("[HDR] DXGI output detection: colorSpace={}, maxLuminance={}", static_cast(desc1.ColorSpace), desc1.MaxLuminance); - } - } - } - - winrt::com_ptr swapChain3; - if (SUCCEEDED(swapChain->QueryInterface(IID_PPV_ARGS(swapChain3.put())))) { - UINT colorSpaceSupported = 0; - if (SUCCEEDED(swapChain3->CheckColorSpaceSupport(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, &colorSpaceSupported))) { - supported |= (colorSpaceSupported & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) != 0; - } - if (SUCCEEDED(swapChain3->CheckColorSpaceSupport(DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, &colorSpaceSupported))) { - supported |= (colorSpaceSupported & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) != 0; - } - } - return true; - } - - bool IsHDRSupportedAndEnabled(HWND hwnd, bool& supported, bool& enabled, IDXGISwapChain* swapChain = nullptr) + bool IsHDRSupportedAndEnabled(HWND hwnd, bool& supported, bool& enabled) { supported = false; enabled = false; - // Try Windows 11 24H2+ API first - distinguishes HDR from WCG + DISPLAYCONFIG_PATH_INFO pathInfo{}; + if (!GetDisplayConfigPathInfo(hwnd, pathInfo)) + return false; + + // Try Windows 11 24H2+ API first - directly reports HDR hardware capability + // Credits: renodx by clshortfuse (MIT License) DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 colorInfo2{}; - if (GetAdvancedColorInfo2(hwnd, colorInfo2)) { - // WCG (Wide Color Gamut) allows wider color range without higher brightness peak - // We only consider true HDR mode, not WCG + colorInfo2.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2; + colorInfo2.header.size = sizeof(colorInfo2); + colorInfo2.header.adapterId = pathInfo.targetInfo.adapterId; + colorInfo2.header.id = pathInfo.targetInfo.id; + if (DisplayConfigGetDeviceInfo(&colorInfo2.header) == ERROR_SUCCESS) { + supported = colorInfo2.highDynamicRangeSupported != 0; enabled = colorInfo2.activeColorMode == DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR; - supported = enabled || (colorInfo2.highDynamicRangeSupported && !colorInfo2.advancedColorLimitedByPolicy); - // Copy bitfield members to avoid non-const reference binding issues UINT32 hdrSupported = colorInfo2.highDynamicRangeSupported; - UINT32 limitedByPolicy = colorInfo2.advancedColorLimitedByPolicy; - logger::debug("[HDR] Win11 24H2 detection: activeColorMode={}, hdrSupported={}, limitedByPolicy={}", - static_cast(colorInfo2.activeColorMode), hdrSupported, limitedByPolicy); + UINT32 activeMode = static_cast(colorInfo2.activeColorMode); + logger::debug("[HDR] Win11 24H2 detection: highDynamicRangeSupported={}, activeColorMode={}", hdrSupported, activeMode); return true; } // Fallback for older Windows versions DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO colorInfo{}; - if (GetAdvancedColorInfo(hwnd, colorInfo)) { - enabled = colorInfo.advancedColorEnabled; - supported = enabled || (colorInfo.advancedColorSupported && !colorInfo.advancedColorForceDisabled); - // Copy bitfield members to avoid non-const reference binding issues - UINT32 advancedEnabled = colorInfo.advancedColorEnabled; + colorInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO; + colorInfo.header.size = sizeof(colorInfo); + colorInfo.header.adapterId = pathInfo.targetInfo.adapterId; + colorInfo.header.id = pathInfo.targetInfo.id; + if (DisplayConfigGetDeviceInfo(&colorInfo.header) == ERROR_SUCCESS) { + supported = colorInfo.advancedColorSupported != 0; + enabled = colorInfo.advancedColorEnabled != 0; UINT32 advancedSupported = colorInfo.advancedColorSupported; - UINT32 forceDisabled = colorInfo.advancedColorForceDisabled; - logger::debug("[HDR] Legacy detection: advancedColorEnabled={}, advancedColorSupported={}, forceDisabled={}", - advancedEnabled, advancedSupported, forceDisabled); + UINT32 advancedEnabled = colorInfo.advancedColorEnabled; + logger::debug("[HDR] Legacy detection: advancedColorSupported={}, advancedColorEnabled={}", advancedSupported, advancedEnabled); return true; } - // Last resort: check swap chain color space support - if (swapChain) { - __try { - CheckSwapChainHDRSupport(swapChain, supported, enabled); - } __except (EXCEPTION_EXECUTE_HANDLER) { - logger::warn("[HDR] Exception during swap chain HDR detection (possibly due to Streamline interposer), skipping swap chain queries"); - } - } - return false; } @@ -255,7 +187,7 @@ bool HDRDisplay::DetectHDR() bool hdrEnabled = false; HWND hwnd = reinterpret_cast(RE::BSGraphics::Renderer::GetSingleton()->GetCurrentRenderWindow()); - IsHDRSupportedAndEnabled(hwnd, hdrSupported, hdrEnabled, globals::d3d::swapChain); + IsHDRSupportedAndEnabled(hwnd, hdrSupported, hdrEnabled); isHDRMonitor = hdrSupported; logger::info("[HDR] HDR display detection: supported={}, enabled={}", hdrSupported, hdrEnabled); From 06d4407f420096e4853b2d69b0a6e10052416dff Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 21:29:05 +0200 Subject: [PATCH 02/16] fix: works now --- src/Features/HDRDisplay.cpp | 59 +++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 7ba0495449..fea095f9fa 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -11,6 +11,7 @@ #include "Util.h" #include #include +#include #include #ifndef NTDDI_WIN11_GE @@ -57,47 +58,62 @@ typedef struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 // https://github.com/Filoppi/Luma-Framework/blob/f1fbc2a36f2d24fd551721ce90f26821a8e754c1/Source/Core/utils/display.hpp namespace { - bool GetDisplayConfigPathInfo(HWND hwnd, DISPLAYCONFIG_PATH_INFO& outPathInfo) + bool GetDisplayConfigPathInfo(IDXGISwapChain* swapChain, DISPLAYCONFIG_PATH_INFO& outPathInfo) { + // Get the GDI device name from the swap chain's containing output. + // This is more reliable than HWND-based monitor lookup because GetCurrentRenderWindow() + // may return an offscreen handle that MonitorFromWindow can't resolve. + winrt::com_ptr output; + if (FAILED(swapChain->GetContainingOutput(output.put()))) { + logger::debug("[HDR] GetContainingOutput failed"); + return false; + } + DXGI_OUTPUT_DESC outputDesc{}; + if (FAILED(output->GetDesc(&outputDesc))) { + logger::debug("[HDR] IDXGIOutput::GetDesc failed"); + return false; + } + logger::debug("[HDR] Swap chain output device: {}", std::filesystem::path(outputDesc.DeviceName).string()); + uint32_t pathCount, modeCount; - if (ERROR_SUCCESS != GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount)) + if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount) != ERROR_SUCCESS) return false; std::vector paths(pathCount); std::vector modes(modeCount); - if (ERROR_SUCCESS != QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths.data(), &modeCount, modes.data(), nullptr)) + if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths.data(), &modeCount, modes.data(), nullptr) != ERROR_SUCCESS) return false; - const HMONITOR monitorFromWindow = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL); for (auto& pathInfo : paths) { - if (pathInfo.flags & DISPLAYCONFIG_PATH_ACTIVE && pathInfo.sourceInfo.statusFlags & DISPLAYCONFIG_SOURCE_IN_USE) { - const bool bVirtual = pathInfo.flags & DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE; - const uint32_t modeIndex = bVirtual ? pathInfo.sourceInfo.sourceModeInfoIdx : pathInfo.sourceInfo.modeInfoIdx; - if (modeIndex == DISPLAYCONFIG_PATH_MODE_IDX_INVALID || modeIndex >= modeCount) - continue; - const DISPLAYCONFIG_SOURCE_MODE& sourceMode = modes[modeIndex].sourceMode; - - RECT rect{ sourceMode.position.x, sourceMode.position.y, sourceMode.position.x + (LONG)sourceMode.width, sourceMode.position.y + (LONG)sourceMode.height }; - if (!IsRectEmpty(&rect)) { - const HMONITOR monitorFromMode = MonitorFromRect(&rect, MONITOR_DEFAULTTONULL); - if (monitorFromMode != nullptr && monitorFromMode == monitorFromWindow) { - outPathInfo = pathInfo; - return true; - } + if (!(pathInfo.flags & DISPLAYCONFIG_PATH_ACTIVE)) + continue; + + DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName{}; + sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + sourceName.header.size = sizeof(sourceName); + sourceName.header.adapterId = pathInfo.sourceInfo.adapterId; + sourceName.header.id = pathInfo.sourceInfo.id; + if (DisplayConfigGetDeviceInfo(&sourceName.header) == ERROR_SUCCESS) { + if (wcscmp(sourceName.viewGdiDeviceName, outputDesc.DeviceName) == 0) { + outPathInfo = pathInfo; + return true; } } } + logger::debug("[HDR] No DisplayConfig path matched output device name"); return false; } - bool IsHDRSupportedAndEnabled(HWND hwnd, bool& supported, bool& enabled) + bool IsHDRSupportedAndEnabled(IDXGISwapChain* swapChain, bool& supported, bool& enabled) { supported = false; enabled = false; DISPLAYCONFIG_PATH_INFO pathInfo{}; - if (!GetDisplayConfigPathInfo(hwnd, pathInfo)) + if (!GetDisplayConfigPathInfo(swapChain, pathInfo)) { + logger::debug("[HDR] GetDisplayConfigPathInfo failed - no matching monitor path found"); return false; + } // Try Windows 11 24H2+ API first - directly reports HDR hardware capability // Credits: renodx by clshortfuse (MIT License) @@ -186,8 +202,7 @@ bool HDRDisplay::DetectHDR() bool hdrSupported = false; bool hdrEnabled = false; - HWND hwnd = reinterpret_cast(RE::BSGraphics::Renderer::GetSingleton()->GetCurrentRenderWindow()); - IsHDRSupportedAndEnabled(hwnd, hdrSupported, hdrEnabled); + IsHDRSupportedAndEnabled(globals::d3d::swapChain, hdrSupported, hdrEnabled); isHDRMonitor = hdrSupported; logger::info("[HDR] HDR display detection: supported={}, enabled={}", hdrSupported, hdrEnabled); From b72ec5e3e93029382f3a5aa2f098785d83ddefbf Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 21:37:21 +0200 Subject: [PATCH 03/16] add more info --- src/Features/HDRDisplay.cpp | 12 ++++++++++-- src/Features/HDRDisplay.h | 3 ++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index fea095f9fa..8e1ea9b3fe 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -196,6 +196,7 @@ namespace } bool HDRDisplay::isHDRMonitor = false; +bool HDRDisplay::isHDRCapableMonitor = false; bool HDRDisplay::DetectHDR() { @@ -204,9 +205,10 @@ bool HDRDisplay::DetectHDR() IsHDRSupportedAndEnabled(globals::d3d::swapChain, hdrSupported, hdrEnabled); - isHDRMonitor = hdrSupported; + isHDRMonitor = hdrEnabled; + isHDRCapableMonitor = hdrSupported; logger::info("[HDR] HDR display detection: supported={}, enabled={}", hdrSupported, hdrEnabled); - return hdrSupported; + return hdrEnabled; } NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( @@ -222,6 +224,12 @@ void HDRDisplay::DrawSettings() { if (isHDRMonitor) { ImGui::TextColored(Util::Colors::GetSuccess(), "HDR Display Detected"); + } else if (isHDRCapableMonitor) { + ImGui::TextColored(Util::Colors::GetWarning(), "HDR Capable Display (Windows HDR is off)"); + if (auto _tt = Util::HoverTooltipWrapper()) { + ImGui::Text("Your monitor supports HDR, but Windows HDR is currently disabled."); + ImGui::Text("Enable HDR in Windows Display Settings to allow auto-detection."); + } } else { ImGui::TextColored(Util::Colors::GetWarning(), "SDR Display (HDR not detected)"); } diff --git a/src/Features/HDRDisplay.h b/src/Features/HDRDisplay.h index e2f25508b8..50b227fc5b 100644 --- a/src/Features/HDRDisplay.h +++ b/src/Features/HDRDisplay.h @@ -113,7 +113,8 @@ struct HDRDisplay : public Feature ID3D11ComputeShader* GetUIBrightnessCS(); static bool DetectHDR(); - static bool isHDRMonitor; + static bool isHDRMonitor; // Windows HDR is active (enabled in OS settings) + static bool isHDRCapableMonitor; // Monitor supports HDR but Windows HDR may be off bool pendingAutoDetect = false; float GetDisplayMaxLuminance() const; From f40e2419bcff2937504e15b815a98ebc074e2cd9 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 21:44:44 +0200 Subject: [PATCH 04/16] chore: cleanup --- src/Features/HDRDisplay.cpp | 74 +++++++++++++++++++++++++++---------- src/Features/HDRDisplay.h | 6 +-- 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 8e1ea9b3fe..8e11b89531 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -11,7 +11,6 @@ #include "Util.h" #include #include -#include #include #ifndef NTDDI_WIN11_GE @@ -58,22 +57,31 @@ typedef struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 // https://github.com/Filoppi/Luma-Framework/blob/f1fbc2a36f2d24fd551721ce90f26821a8e754c1/Source/Core/utils/display.hpp namespace { - bool GetDisplayConfigPathInfo(IDXGISwapChain* swapChain, DISPLAYCONFIG_PATH_INFO& outPathInfo) + // Returns the GDI device name for the output the swap chain is presenting to. + // Uses GetContainingOutput which works for both windowed and borderless-fullscreen. + // Returns false if the swap chain's output cannot be determined (e.g. Streamline + // replaces the swap chain with a wrapper that does not implement GetContainingOutput). + bool GetSwapChainOutputDeviceName(IDXGISwapChain* swapChain, WCHAR (&outDeviceName)[32]) { - // Get the GDI device name from the swap chain's containing output. - // This is more reliable than HWND-based monitor lookup because GetCurrentRenderWindow() - // may return an offscreen handle that MonitorFromWindow can't resolve. winrt::com_ptr output; - if (FAILED(swapChain->GetContainingOutput(output.put()))) { - logger::debug("[HDR] GetContainingOutput failed"); + if (FAILED(swapChain->GetContainingOutput(output.put()))) return false; - } - DXGI_OUTPUT_DESC outputDesc{}; - if (FAILED(output->GetDesc(&outputDesc))) { - logger::debug("[HDR] IDXGIOutput::GetDesc failed"); + DXGI_OUTPUT_DESC desc{}; + if (FAILED(output->GetDesc(&desc))) + return false; + wcsncpy_s(outDeviceName, desc.DeviceName, _TRUNCATE); + // DeviceName is ASCII (e.g. "\\.\DISPLAY1") — safe to log as narrow string + logger::debug("[HDR] Swap chain output device: {}", std::string(desc.DeviceName, desc.DeviceName + wcslen(desc.DeviceName))); + return true; + } + + bool GetDisplayConfigPathInfo(IDXGISwapChain* swapChain, DISPLAYCONFIG_PATH_INFO& outPathInfo) + { + WCHAR deviceName[32]{}; + if (!GetSwapChainOutputDeviceName(swapChain, deviceName)) { + logger::warn("[HDR] GetContainingOutput failed - cannot determine monitor for HDR detection (Streamline/frame-gen?)"); return false; } - logger::debug("[HDR] Swap chain output device: {}", std::filesystem::path(outputDesc.DeviceName).string()); uint32_t pathCount, modeCount; if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount) != ERROR_SUCCESS) @@ -85,22 +93,27 @@ namespace return false; for (auto& pathInfo : paths) { - if (!(pathInfo.flags & DISPLAYCONFIG_PATH_ACTIVE)) + // DISPLAYCONFIG_SOURCE_IN_USE guards against inactive sources on multi-monitor + // setups where a disconnected display may still appear in the path table + if (!(pathInfo.flags & DISPLAYCONFIG_PATH_ACTIVE) || + !(pathInfo.sourceInfo.statusFlags & DISPLAYCONFIG_SOURCE_IN_USE)) continue; + // QDC_ONLY_ACTIVE_PATHS never returns virtual-mode paths, so no + // DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE index selection is needed here DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName{}; sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; sourceName.header.size = sizeof(sourceName); sourceName.header.adapterId = pathInfo.sourceInfo.adapterId; sourceName.header.id = pathInfo.sourceInfo.id; if (DisplayConfigGetDeviceInfo(&sourceName.header) == ERROR_SUCCESS) { - if (wcscmp(sourceName.viewGdiDeviceName, outputDesc.DeviceName) == 0) { + if (wcscmp(sourceName.viewGdiDeviceName, deviceName) == 0) { outPathInfo = pathInfo; return true; } } } - logger::debug("[HDR] No DisplayConfig path matched output device name"); + logger::warn("[HDR] No DisplayConfig path matched output device name"); return false; } @@ -111,7 +124,22 @@ namespace DISPLAYCONFIG_PATH_INFO pathInfo{}; if (!GetDisplayConfigPathInfo(swapChain, pathInfo)) { - logger::debug("[HDR] GetDisplayConfigPathInfo failed - no matching monitor path found"); + // GetContainingOutput can fail under Streamline/frame-gen wrappers. Fall back to + // IDXGIOutput6::GetDesc1 which reads the output's current color space directly. + // This only detects whether HDR is currently active, not whether the monitor + // supports it while Windows HDR is off, but is better than reporting nothing. + winrt::com_ptr output; + if (SUCCEEDED(swapChain->GetContainingOutput(output.put()))) { + winrt::com_ptr output6; + if (SUCCEEDED(output->QueryInterface(IID_PPV_ARGS(output6.put())))) { + DXGI_OUTPUT_DESC1 desc1{}; + if (SUCCEEDED(output6->GetDesc1(&desc1))) { + enabled = desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + supported = enabled; + logger::debug("[HDR] DXGI fallback detection: colorSpace={}", static_cast(desc1.ColorSpace)); + } + } + } return false; } @@ -273,12 +301,14 @@ void HDRDisplay::DrawSettings() if (auto _tt = Util::HoverTooltipWrapper()) { if (isHDRMonitor) { ImGui::Text("Enable HDR output. Matches vanilla visuals with extended dynamic range."); + } else if (isHDRCapableMonitor) { + ImGui::Text("Monitor supports HDR but Windows HDR is off. Enable HDR in Windows Display Settings, then restart the game."); } else { ImGui::Text("HDR display not detected. Use Advanced button to override."); } } - // Advanced override button for SDR monitors + // Advanced override button — shown when HDR is neither active nor auto-detected if (!isHDRMonitor && !oldEnableHDR) { ImGui::SameLine(); if (ImGui::Button("Advanced")) { @@ -303,7 +333,11 @@ void HDRDisplay::DrawSettings() } } if (auto _tt = Util::HoverTooltipWrapper()) { - ImGui::Text("Force enable HDR even without detection (not recommended)."); + if (isHDRCapableMonitor) { + ImGui::Text("Enable Windows HDR instead of forcing it here."); + } else { + ImGui::Text("Force enable HDR even without detection (not recommended)."); + } } } @@ -483,8 +517,8 @@ void HDRDisplay::LoadSettings(json& o_json) settings = o_json; - // Defer auto-detection to SetupResources where the renderer is available. - // DetectHDR() needs a valid HWND which doesn't exist during early plugin init. + // Defer auto-detection to SetupResources where the swap chain is available. + // DetectHDR() needs globals::d3d::swapChain which isn't valid during early plugin init. // hdrAutoDetected starts false in defaults and is only set true after auto-detect // completes in SetupResources, so this correctly triggers on first launch even // when the default config was auto-generated with enableHDR: false. diff --git a/src/Features/HDRDisplay.h b/src/Features/HDRDisplay.h index 50b227fc5b..483c9177de 100644 --- a/src/Features/HDRDisplay.h +++ b/src/Features/HDRDisplay.h @@ -112,9 +112,9 @@ struct HDRDisplay : public Feature ID3D11ComputeShader* uiBrightnessCS = nullptr; ID3D11ComputeShader* GetUIBrightnessCS(); - static bool DetectHDR(); - static bool isHDRMonitor; // Windows HDR is active (enabled in OS settings) - static bool isHDRCapableMonitor; // Monitor supports HDR but Windows HDR may be off + static bool DetectHDR(); // Returns true if Windows HDR is currently active (enabled in OS settings) + static bool isHDRMonitor; // Windows HDR is active (enabled in OS settings) + static bool isHDRCapableMonitor; // Monitor supports HDR but Windows HDR may be off bool pendingAutoDetect = false; float GetDisplayMaxLuminance() const; From d63a4cb4dd7b054869f3bf2ee314c8fa2d3ff6e3 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 21:45:20 +0200 Subject: [PATCH 05/16] fix: compile --- src/Features/HDRDisplay.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 8e11b89531..986fbfa166 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -71,7 +71,9 @@ namespace return false; wcsncpy_s(outDeviceName, desc.DeviceName, _TRUNCATE); // DeviceName is ASCII (e.g. "\\.\DISPLAY1") — safe to log as narrow string - logger::debug("[HDR] Swap chain output device: {}", std::string(desc.DeviceName, desc.DeviceName + wcslen(desc.DeviceName))); + char narrowName[32]{}; + WideCharToMultiByte(CP_UTF8, 0, desc.DeviceName, -1, narrowName, sizeof(narrowName), nullptr, nullptr); + logger::debug("[HDR] Swap chain output device: {}", narrowName); return true; } From 0764e77241d1d5f0fa30f1388341bba5a20d2248 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 20:16:47 +0000 Subject: [PATCH 06/16] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/Features/HDRDisplay.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Features/HDRDisplay.h b/src/Features/HDRDisplay.h index 483c9177de..b0babb5acf 100644 --- a/src/Features/HDRDisplay.h +++ b/src/Features/HDRDisplay.h @@ -112,9 +112,9 @@ struct HDRDisplay : public Feature ID3D11ComputeShader* uiBrightnessCS = nullptr; ID3D11ComputeShader* GetUIBrightnessCS(); - static bool DetectHDR(); // Returns true if Windows HDR is currently active (enabled in OS settings) - static bool isHDRMonitor; // Windows HDR is active (enabled in OS settings) - static bool isHDRCapableMonitor; // Monitor supports HDR but Windows HDR may be off + static bool DetectHDR(); // Returns true if Windows HDR is currently active (enabled in OS settings) + static bool isHDRMonitor; // Windows HDR is active (enabled in OS settings) + static bool isHDRCapableMonitor; // Monitor supports HDR but Windows HDR may be off bool pendingAutoDetect = false; float GetDisplayMaxLuminance() const; From eaf7f0299dc8d4e7404433f33b88be0b3dad1927 Mon Sep 17 00:00:00 2001 From: Skrubby Skrub In A Shrub <87662196+SkrubbySkrubInAShrub@users.noreply.github.com> Date: Wed, 22 Apr 2026 22:43:38 +0200 Subject: [PATCH 07/16] fix: address AI comment --- src/Features/HDRDisplay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 986fbfa166..79f2f0876e 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -139,6 +139,7 @@ namespace enabled = desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; supported = enabled; logger::debug("[HDR] DXGI fallback detection: colorSpace={}", static_cast(desc1.ColorSpace)); + return true; } } } From a7b637de578197db611d8ee8e017715fde49dad6 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 22:51:01 +0200 Subject: [PATCH 08/16] fix: address AI comments --- src/Features/HDRDisplay.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 79f2f0876e..c06b10c7f3 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -80,10 +80,8 @@ namespace bool GetDisplayConfigPathInfo(IDXGISwapChain* swapChain, DISPLAYCONFIG_PATH_INFO& outPathInfo) { WCHAR deviceName[32]{}; - if (!GetSwapChainOutputDeviceName(swapChain, deviceName)) { - logger::warn("[HDR] GetContainingOutput failed - cannot determine monitor for HDR detection (Streamline/frame-gen?)"); + if (!GetSwapChainOutputDeviceName(swapChain, deviceName)) return false; - } uint32_t pathCount, modeCount; if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount) != ERROR_SUCCESS) @@ -115,7 +113,6 @@ namespace } } } - logger::warn("[HDR] No DisplayConfig path matched output device name"); return false; } @@ -143,6 +140,7 @@ namespace } } } + logger::warn("[HDR] HDR detection failed - cannot determine monitor (Streamline/frame-gen?)"); return false; } @@ -231,6 +229,12 @@ bool HDRDisplay::isHDRCapableMonitor = false; bool HDRDisplay::DetectHDR() { + if (!globals::d3d::swapChain) { + isHDRMonitor = false; + isHDRCapableMonitor = false; + return false; + } + bool hdrSupported = false; bool hdrEnabled = false; From 2918fed599d9fefcb4f3e9aed099085ca51cc2fa Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 23:06:09 +0200 Subject: [PATCH 09/16] fix: more AI comments --- src/Features/HDRDisplay.cpp | 70 ++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index c06b10c7f3..29b4a25413 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -19,7 +19,7 @@ // Win11 24H2 structures - define if SDK doesn't have them #ifndef DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2 -# define DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2 ((DISPLAYCONFIG_DEVICE_INFO_TYPE)13) +# define DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2 ((DISPLAYCONFIG_DEVICE_INFO_TYPE)15) typedef enum { @@ -41,8 +41,9 @@ typedef struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 UINT32 advancedColorLimitedByPolicy: 1; UINT32 highDynamicRangeSupported: 1; UINT32 highDynamicRangeUserEnabled: 1; - UINT32 wideColorEnforced: 1; - UINT32 reserved: 25; + UINT32 wideColorSupported: 1; + UINT32 wideColorUserEnabled: 1; + UINT32 reserved: 24; }; UINT32 value; }; @@ -123,20 +124,55 @@ namespace DISPLAYCONFIG_PATH_INFO pathInfo{}; if (!GetDisplayConfigPathInfo(swapChain, pathInfo)) { - // GetContainingOutput can fail under Streamline/frame-gen wrappers. Fall back to - // IDXGIOutput6::GetDesc1 which reads the output's current color space directly. - // This only detects whether HDR is currently active, not whether the monitor - // supports it while Windows HDR is off, but is better than reporting nothing. - winrt::com_ptr output; - if (SUCCEEDED(swapChain->GetContainingOutput(output.put()))) { - winrt::com_ptr output6; - if (SUCCEEDED(output->QueryInterface(IID_PPV_ARGS(output6.put())))) { - DXGI_OUTPUT_DESC1 desc1{}; - if (SUCCEEDED(output6->GetDesc1(&desc1))) { - enabled = desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; - supported = enabled; - logger::debug("[HDR] DXGI fallback detection: colorSpace={}", static_cast(desc1.ColorSpace)); - return true; + // GetContainingOutput fails under Streamline/frame-gen wrappers. Fall back by + // finding the monitor via the swap chain's OutputWindow, then enumerating all + // DXGI outputs to locate the matching IDXGIOutput6 without relying on + // GetContainingOutput. This only detects whether HDR is currently active (not + // whether the monitor supports HDR while Windows HDR is off), but is better + // than reporting nothing. + HWND outputWindow = nullptr; + DXGI_SWAP_CHAIN_DESC scDescFull{}; + if (SUCCEEDED(swapChain->GetDesc(&scDescFull))) + outputWindow = scDescFull.OutputWindow; + + HMONITOR hMonitor = nullptr; + if (outputWindow) + hMonitor = MonitorFromWindow(outputWindow, MONITOR_DEFAULTTONEAREST); + if (!hMonitor) { + RECT r{ 0, 0, 1, 1 }; + hMonitor = MonitorFromRect(&r, MONITOR_DEFAULTTOPRIMARY); + } + + // Walk all adapters/outputs to find the one matching hMonitor + winrt::com_ptr dxgiDevice; + winrt::com_ptr adapter; + winrt::com_ptr factory; + if (SUCCEEDED(globals::d3d::device->QueryInterface(IID_PPV_ARGS(dxgiDevice.put()))) && + SUCCEEDED(dxgiDevice->GetAdapter(adapter.put())) && + SUCCEEDED(adapter->GetParent(IID_PPV_ARGS(factory.put())))) { + for (UINT ai = 0;; ++ai) { + winrt::com_ptr adap; + if (factory->EnumAdapters1(ai, adap.put()) == DXGI_ERROR_NOT_FOUND) + break; + for (UINT oi = 0;; ++oi) { + winrt::com_ptr out; + if (adap->EnumOutputs(oi, out.put()) == DXGI_ERROR_NOT_FOUND) + break; + DXGI_OUTPUT_DESC outDesc{}; + if (FAILED(out->GetDesc(&outDesc))) + continue; + if (outDesc.Monitor != hMonitor) + continue; + winrt::com_ptr out6; + if (SUCCEEDED(out->QueryInterface(IID_PPV_ARGS(out6.put())))) { + DXGI_OUTPUT_DESC1 desc1{}; + if (SUCCEEDED(out6->GetDesc1(&desc1))) { + enabled = desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + supported = enabled; + logger::debug("[HDR] DXGI fallback detection: colorSpace={}", static_cast(desc1.ColorSpace)); + return true; + } + } } } } From 8ddf61a66dd4289c103f80266bea092d520b9051 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 23:25:45 +0200 Subject: [PATCH 10/16] fix: AI comments --- src/Features/HDRDisplay.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 29b4a25413..9faf9bf47e 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -135,19 +135,18 @@ namespace if (SUCCEEDED(swapChain->GetDesc(&scDescFull))) outputWindow = scDescFull.OutputWindow; - HMONITOR hMonitor = nullptr; - if (outputWindow) - hMonitor = MonitorFromWindow(outputWindow, MONITOR_DEFAULTTONEAREST); + HMONITOR hMonitor = outputWindow ? MonitorFromWindow(outputWindow, MONITOR_DEFAULTTONEAREST) : nullptr; if (!hMonitor) { - RECT r{ 0, 0, 1, 1 }; - hMonitor = MonitorFromRect(&r, MONITOR_DEFAULTTOPRIMARY); + logger::warn("[HDR] HDR detection failed - cannot determine monitor from swap chain OutputWindow"); + return false; } // Walk all adapters/outputs to find the one matching hMonitor winrt::com_ptr dxgiDevice; winrt::com_ptr adapter; winrt::com_ptr factory; - if (SUCCEEDED(globals::d3d::device->QueryInterface(IID_PPV_ARGS(dxgiDevice.put()))) && + if (globals::d3d::device && + SUCCEEDED(globals::d3d::device->QueryInterface(IID_PPV_ARGS(dxgiDevice.put()))) && SUCCEEDED(dxgiDevice->GetAdapter(adapter.put())) && SUCCEEDED(adapter->GetParent(IID_PPV_ARGS(factory.put())))) { for (UINT ai = 0;; ++ai) { From 83e49dc9594ba2c53c0e80fc670c1015171e95f1 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 23:33:25 +0200 Subject: [PATCH 11/16] fix: AI --- src/Features/HDRDisplay.cpp | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 9faf9bf47e..e37755cb03 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -17,18 +17,24 @@ # define NTDDI_WIN11_GE 0x0A000010 #endif -// Win11 24H2 structures - define if SDK doesn't have them -#ifndef DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2 -# define DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2 ((DISPLAYCONFIG_DEVICE_INFO_TYPE)15) - +// Win11 24H2 display config types. +// DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2 is an enum member on newer SDKs, +// not a macro, so #ifndef cannot guard against redeclaration. Use Compat_ prefixed +// names and alias to the SDK types when they exist. +#if defined(NTDDI_WIN11_GE) && WDK_NTDDI_VERSION >= NTDDI_WIN11_GE +using Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE = DISPLAYCONFIG_ADVANCED_COLOR_MODE; +using Compat_DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 = DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2; +static constexpr DISPLAYCONFIG_DEVICE_INFO_TYPE kDisplayConfigGetAdvancedColorInfo2 = + DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2; +#else typedef enum { - DISPLAYCONFIG_ADVANCED_COLOR_MODE_SDR = 0, - DISPLAYCONFIG_ADVANCED_COLOR_MODE_WCG = 1, - DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR = 2 -} DISPLAYCONFIG_ADVANCED_COLOR_MODE; + Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_SDR = 0, + Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_WCG = 1, + Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR = 2 +} Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE; -typedef struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 +typedef struct Compat_DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 { DISPLAYCONFIG_DEVICE_INFO_HEADER header; union @@ -49,8 +55,11 @@ typedef struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 }; DISPLAYCONFIG_COLOR_ENCODING colorEncoding; UINT32 bitsPerColorChannel; - DISPLAYCONFIG_ADVANCED_COLOR_MODE activeColorMode; -} DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2; + Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE activeColorMode; +} Compat_DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2; + +static constexpr DISPLAYCONFIG_DEVICE_INFO_TYPE kDisplayConfigGetAdvancedColorInfo2 = + static_cast(15); #endif // HDR display detection @@ -181,14 +190,14 @@ namespace // Try Windows 11 24H2+ API first - directly reports HDR hardware capability // Credits: renodx by clshortfuse (MIT License) - DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 colorInfo2{}; - colorInfo2.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2; + Compat_DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 colorInfo2{}; + colorInfo2.header.type = kDisplayConfigGetAdvancedColorInfo2; colorInfo2.header.size = sizeof(colorInfo2); colorInfo2.header.adapterId = pathInfo.targetInfo.adapterId; colorInfo2.header.id = pathInfo.targetInfo.id; if (DisplayConfigGetDeviceInfo(&colorInfo2.header) == ERROR_SUCCESS) { supported = colorInfo2.highDynamicRangeSupported != 0; - enabled = colorInfo2.activeColorMode == DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR; + enabled = colorInfo2.activeColorMode == Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR; UINT32 hdrSupported = colorInfo2.highDynamicRangeSupported; UINT32 activeMode = static_cast(colorInfo2.activeColorMode); logger::debug("[HDR] Win11 24H2 detection: highDynamicRangeSupported={}, activeColorMode={}", hdrSupported, activeMode); From 869486d06e7ed7642b9d0c6583d4ce052b0c0f88 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Wed, 22 Apr 2026 23:52:53 +0200 Subject: [PATCH 12/16] fix: AI --- src/Features/HDRDisplay.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index e37755cb03..74c1ad924b 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -26,6 +26,9 @@ using Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE = DISPLAYCONFIG_ADVANCED_COLOR_MO using Compat_DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 = DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2; static constexpr DISPLAYCONFIG_DEVICE_INFO_TYPE kDisplayConfigGetAdvancedColorInfo2 = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2; +static constexpr Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_SDR = DISPLAYCONFIG_ADVANCED_COLOR_MODE_SDR; +static constexpr Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_WCG = DISPLAYCONFIG_ADVANCED_COLOR_MODE_WCG; +static constexpr Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR = DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR; #else typedef enum { From 692c3deac9a3c8dd694f71dba01d215df59db909 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Thu, 23 Apr 2026 00:04:32 +0200 Subject: [PATCH 13/16] fix: nitpick, compile and comments --- src/Features/HDRDisplay.cpp | 80 +++++++++++-------------------------- 1 file changed, 23 insertions(+), 57 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 74c1ad924b..7151c51a0e 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -13,23 +13,7 @@ #include #include -#ifndef NTDDI_WIN11_GE -# define NTDDI_WIN11_GE 0x0A000010 -#endif - -// Win11 24H2 display config types. -// DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2 is an enum member on newer SDKs, -// not a macro, so #ifndef cannot guard against redeclaration. Use Compat_ prefixed -// names and alias to the SDK types when they exist. -#if defined(NTDDI_WIN11_GE) && WDK_NTDDI_VERSION >= NTDDI_WIN11_GE -using Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE = DISPLAYCONFIG_ADVANCED_COLOR_MODE; -using Compat_DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 = DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2; -static constexpr DISPLAYCONFIG_DEVICE_INFO_TYPE kDisplayConfigGetAdvancedColorInfo2 = - DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2; -static constexpr Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_SDR = DISPLAYCONFIG_ADVANCED_COLOR_MODE_SDR; -static constexpr Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_WCG = DISPLAYCONFIG_ADVANCED_COLOR_MODE_WCG; -static constexpr Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR = DISPLAYCONFIG_ADVANCED_COLOR_MODE_HDR; -#else +// Win11 24H2 display config types. Compat_ prefix avoids collision with SDK enum members. typedef enum { Compat_DISPLAYCONFIG_ADVANCED_COLOR_MODE_SDR = 0, @@ -63,17 +47,14 @@ typedef struct Compat_DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 static constexpr DISPLAYCONFIG_DEVICE_INFO_TYPE kDisplayConfigGetAdvancedColorInfo2 = static_cast(15); -#endif // HDR display detection // Credits: Luma Framework by Filippo Tarpini (MIT License) // https://github.com/Filoppi/Luma-Framework/blob/f1fbc2a36f2d24fd551721ce90f26821a8e754c1/Source/Core/utils/display.hpp namespace { - // Returns the GDI device name for the output the swap chain is presenting to. - // Uses GetContainingOutput which works for both windowed and borderless-fullscreen. - // Returns false if the swap chain's output cannot be determined (e.g. Streamline - // replaces the swap chain with a wrapper that does not implement GetContainingOutput). + // Returns the GDI device name for the swap chain's output via GetContainingOutput. + // Returns false if the output cannot be determined (e.g. Streamline wraps the swap chain). bool GetSwapChainOutputDeviceName(IDXGISwapChain* swapChain, WCHAR (&outDeviceName)[32]) { winrt::com_ptr output; @@ -106,14 +87,12 @@ namespace return false; for (auto& pathInfo : paths) { - // DISPLAYCONFIG_SOURCE_IN_USE guards against inactive sources on multi-monitor - // setups where a disconnected display may still appear in the path table + // DISPLAYCONFIG_SOURCE_IN_USE skips inactive sources (disconnected displays) if (!(pathInfo.flags & DISPLAYCONFIG_PATH_ACTIVE) || !(pathInfo.sourceInfo.statusFlags & DISPLAYCONFIG_SOURCE_IN_USE)) continue; - // QDC_ONLY_ACTIVE_PATHS never returns virtual-mode paths, so no - // DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE index selection is needed here + // QDC_ONLY_ACTIVE_PATHS excludes virtual-mode paths; no index selection needed DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName{}; sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; sourceName.header.size = sizeof(sourceName); @@ -136,12 +115,8 @@ namespace DISPLAYCONFIG_PATH_INFO pathInfo{}; if (!GetDisplayConfigPathInfo(swapChain, pathInfo)) { - // GetContainingOutput fails under Streamline/frame-gen wrappers. Fall back by - // finding the monitor via the swap chain's OutputWindow, then enumerating all - // DXGI outputs to locate the matching IDXGIOutput6 without relying on - // GetContainingOutput. This only detects whether HDR is currently active (not - // whether the monitor supports HDR while Windows HDR is off), but is better - // than reporting nothing. + // GetContainingOutput fails under frame-gen wrappers. Fall back to enumerating + // the device adapter's outputs by HMONITOR. Only detects active HDR, not capable. HWND outputWindow = nullptr; DXGI_SWAP_CHAIN_DESC scDescFull{}; if (SUCCEEDED(swapChain->GetDesc(&scDescFull))) @@ -153,36 +128,27 @@ namespace return false; } - // Walk all adapters/outputs to find the one matching hMonitor + // Enumerate outputs on the device's own adapter; avoids touching other GPUs. winrt::com_ptr dxgiDevice; winrt::com_ptr adapter; - winrt::com_ptr factory; if (globals::d3d::device && SUCCEEDED(globals::d3d::device->QueryInterface(IID_PPV_ARGS(dxgiDevice.put()))) && - SUCCEEDED(dxgiDevice->GetAdapter(adapter.put())) && - SUCCEEDED(adapter->GetParent(IID_PPV_ARGS(factory.put())))) { - for (UINT ai = 0;; ++ai) { - winrt::com_ptr adap; - if (factory->EnumAdapters1(ai, adap.put()) == DXGI_ERROR_NOT_FOUND) + SUCCEEDED(dxgiDevice->GetAdapter(adapter.put()))) { + for (UINT oi = 0;; ++oi) { + winrt::com_ptr out; + if (adapter->EnumOutputs(oi, out.put()) == DXGI_ERROR_NOT_FOUND) break; - for (UINT oi = 0;; ++oi) { - winrt::com_ptr out; - if (adap->EnumOutputs(oi, out.put()) == DXGI_ERROR_NOT_FOUND) - break; - DXGI_OUTPUT_DESC outDesc{}; - if (FAILED(out->GetDesc(&outDesc))) - continue; - if (outDesc.Monitor != hMonitor) - continue; - winrt::com_ptr out6; - if (SUCCEEDED(out->QueryInterface(IID_PPV_ARGS(out6.put())))) { - DXGI_OUTPUT_DESC1 desc1{}; - if (SUCCEEDED(out6->GetDesc1(&desc1))) { - enabled = desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; - supported = enabled; - logger::debug("[HDR] DXGI fallback detection: colorSpace={}", static_cast(desc1.ColorSpace)); - return true; - } + DXGI_OUTPUT_DESC outDesc{}; + if (FAILED(out->GetDesc(&outDesc)) || outDesc.Monitor != hMonitor) + continue; + winrt::com_ptr out6; + if (SUCCEEDED(out->QueryInterface(IID_PPV_ARGS(out6.put())))) { + DXGI_OUTPUT_DESC1 desc1{}; + if (SUCCEEDED(out6->GetDesc1(&desc1))) { + enabled = desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + supported = enabled; + logger::debug("[HDR] DXGI fallback detection: colorSpace={}", static_cast(desc1.ColorSpace)); + return true; } } } From 25a8fd822679de0036e4038ecbd132d787f02877 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Thu, 23 Apr 2026 00:17:37 +0200 Subject: [PATCH 14/16] fix: AI comment --- src/Features/HDRDisplay.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 7151c51a0e..22ddd53cb1 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -136,8 +136,11 @@ namespace SUCCEEDED(dxgiDevice->GetAdapter(adapter.put()))) { for (UINT oi = 0;; ++oi) { winrt::com_ptr out; - if (adapter->EnumOutputs(oi, out.put()) == DXGI_ERROR_NOT_FOUND) + HRESULT hr = adapter->EnumOutputs(oi, out.put()); + if (hr == DXGI_ERROR_NOT_FOUND) break; + if (FAILED(hr)) + continue; DXGI_OUTPUT_DESC outDesc{}; if (FAILED(out->GetDesc(&outDesc)) || outDesc.Monitor != hMonitor) continue; @@ -159,6 +162,7 @@ namespace // Try Windows 11 24H2+ API first - directly reports HDR hardware capability // Credits: renodx by clshortfuse (MIT License) + // https://github.com/clshortfuse/renodx/blob/01f3739685ba8f850d82fb1a11a5ec1104e6b1b8/src/games/hollowknight-silksong/addon.cpp#L545 Compat_DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 colorInfo2{}; colorInfo2.header.type = kDisplayConfigGetAdvancedColorInfo2; colorInfo2.header.size = sizeof(colorInfo2); From f6c0eeaedb74d70c0f31330b009ee47ca2677dea Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Thu, 23 Apr 2026 21:54:54 +0200 Subject: [PATCH 15/16] fix: AI --- src/Features/HDRDisplay.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Features/HDRDisplay.cpp b/src/Features/HDRDisplay.cpp index 22ddd53cb1..1649c263fb 100644 --- a/src/Features/HDRDisplay.cpp +++ b/src/Features/HDRDisplay.cpp @@ -139,8 +139,10 @@ namespace HRESULT hr = adapter->EnumOutputs(oi, out.put()); if (hr == DXGI_ERROR_NOT_FOUND) break; - if (FAILED(hr)) - continue; + if (FAILED(hr)) { + logger::debug("[HDR] EnumOutputs failed: hr=0x{:08X}", static_cast(hr)); + break; + } DXGI_OUTPUT_DESC outDesc{}; if (FAILED(out->GetDesc(&outDesc)) || outDesc.Monitor != hMonitor) continue; @@ -185,10 +187,26 @@ namespace colorInfo.header.id = pathInfo.targetInfo.id; if (DisplayConfigGetDeviceInfo(&colorInfo.header) == ERROR_SUCCESS) { supported = colorInfo.advancedColorSupported != 0; - enabled = colorInfo.advancedColorEnabled != 0; + + DXGI_COLOR_SPACE_TYPE swapChainOutputColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + { + winrt::com_ptr containingOutput; + if (SUCCEEDED(swapChain->GetContainingOutput(containingOutput.put()))) { + winrt::com_ptr out6; + if (SUCCEEDED(containingOutput->QueryInterface(IID_PPV_ARGS(out6.put())))) { + DXGI_OUTPUT_DESC1 desc1{}; + if (SUCCEEDED(out6->GetDesc1(&desc1))) + swapChainOutputColorSpace = desc1.ColorSpace; + } + } + } + + enabled = (colorInfo.advancedColorEnabled != 0) && (swapChainOutputColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); UINT32 advancedSupported = colorInfo.advancedColorSupported; UINT32 advancedEnabled = colorInfo.advancedColorEnabled; - logger::debug("[HDR] Legacy detection: advancedColorSupported={}, advancedColorEnabled={}", advancedSupported, advancedEnabled); + int colorSpaceInt = static_cast(swapChainOutputColorSpace); + logger::debug("[HDR] Legacy detection: advancedColorSupported={}, advancedColorEnabled={}, swapChainColorSpace={}, enabled={}", + advancedSupported, advancedEnabled, colorSpaceInt, enabled); return true; } From 288651e83788641969c6732eb3d9cc384e341722 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 19:57:28 +0000 Subject: [PATCH 16/16] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/Features/HDRDisplay.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Features/HDRDisplay.h b/src/Features/HDRDisplay.h index 4a1145fb5e..12351caeaa 100644 --- a/src/Features/HDRDisplay.h +++ b/src/Features/HDRDisplay.h @@ -112,9 +112,9 @@ struct HDRDisplay : public Feature ID3D11ComputeShader* uiBrightnessCS = nullptr; ID3D11ComputeShader* GetUIBrightnessCS(); - static bool DetectHDR(); // Returns true if Windows HDR is currently active (enabled in OS settings) - static bool isHDRMonitor; // Windows HDR is active (enabled in OS settings) - static bool isHDRCapableMonitor; // Monitor supports HDR but Windows HDR may be off + static bool DetectHDR(); // Returns true if Windows HDR is currently active (enabled in OS settings) + static bool isHDRMonitor; // Windows HDR is active (enabled in OS settings) + static bool isHDRCapableMonitor; // Monitor supports HDR but Windows HDR may be off static bool wasExclusiveFullscreen; // EFS detected at swapchain creation; incompatible with HDR bool pendingAutoDetect = false;