必须调用DisplayConfigGetDeviceInfo获取DISPLAYCONFIG_HDR_METADATA_TYPE和DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY字段,确认hdrMetadataType非NONE且videoOutputTechnology为HDRTV或INTERNAL;需管理员权限、遍历所有targetId,并结合EDID解析或QueryVideoCapability交叉验证。

Windows平台用IDisplayConfigProvider查HDR状态
Windows 10/11 的 HDR 开启状态不能靠读注册表或WMI直接判断,必须走Display Configuration API。核心是调用DisplayConfigGetDeviceInfo配合DISPLAYCONFIG_TARGET_PREFERRED_MODE获取目标设备的DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY和DISPLAYCONFIG_HDR_METADATA_TYPE字段。
常见错误是只检查DXGI_OUTPUT_DESC里的ColorSpace——它反映的是当前输出格式,不是系统级HDR开关状态。实际需确认两点:hdrMetadataType != DISPLAYCONFIG_HDR_METADATA_TYPE_NONE且videoOutputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDRTV(或_INTERNAL)。
- 必须以管理员权限运行,否则
DisplayConfigGetDeviceInfo可能返回ERROR_ACCESS_DENIED - 多显示器场景下,
targetId需遍历所有DISPLAYCONFIG_PATH_INFO中的targetInfo.id,不能只查主屏 - 即使HDR已开启,某些OLED笔记本在电池模式下会强制关闭HDR,此时API仍返回启用状态但实际无效
GetDeviceGammaRamp无法用于HDR亮度范围检测
很多开发者尝试用SetDeviceGammaRamp/GetDeviceGammaRamp读取gamma表来反推亮度范围,这是错误路径。HDR模式下gamma ramp被忽略,显卡驱动直接使用scRGB或PQ传递线性光值,gamma表内容与实际亮度无对应关系。
真正可用的是IDXGIOutput6::QueryVideoCapability(需要DXGI 1.6+),传入DXGI_FORMAT_R10G10B10A2_UNORM或DXGI_FORMAT_R16G16B16A16_FLOAT,返回DXGI_VIDEO_CAPABILITY结构体中的MaxLuminanceInNits和MinLuminanceInNits字段。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 必须先调用
dxgiFactory->EnumAdapters1(0, &adapter)再adapter->EnumOutputs(0, &output)拿到IDXGIOutput6* - 部分集成显卡(如Intel UHD 630)虽支持HDR,但
QueryVideoCapability返回DXGI_ERROR_NOT_SUPPORTED,需降级 fallback 到读取EDID中的hdr_static_metadata_type_1数据块 -
MaxLuminanceInNits通常为1000(SDR显示器则恒为300),但实际峰值亮度受电源策略限制,需结合PowerSettingGuid中GUID_VIDEO_POWERDOWN_TIMEOUT状态交叉验证
EDID解析是跨平台兼容的兜底方案
当API不可用或权限受限时,直接读取显示器EDID是最可靠方式。Windows下通过SetupDiGetClassDevs枚举GUID_DEVCLASS_MONITOR设备,再用CM_Get_Device_Interface_Property获取DEVPKEY_Device_InstanceId,最后调用WmiMonitorID WMI类或直接读取\.DISPLAY1monitor设备文件(需FILE_SHARE_READ和GENERIC_READ权限)。
EDID Block 0x83(HDR Static Metadata Data Block)包含max_cll(最大内容亮度)和max_fall(最大帧平均亮度),单位为cd/m²。注意:该值是显示器物理能力上限,不等于当前系统设置的HDR亮度目标值。
- EDID读取失败常见原因为:显示器未通电、USB-C转接器丢弃EDID、Windows“连接到此显示器”选项设为“断开”
- 部分HDR显示器(如LG UltraFine 5K)EDID中
max_cll = 0,需额外检查Block 0x7E(Extended Display Identification Data)中的display_transfer_characteristic字段是否为SMPTE ST 2084 - Linux/macOS下需改用
ddcutil或I2C总线直接读取,Windows上无标准替代命令
亮度范围数值容易被误解的三个点
所谓“亮度范围”在HDR语境下不是单一数值,而是三组独立指标:系统当前HDR模式下的TargetLuminance(由SetThreadDpiAwarenessContext触发的DPI感知上下文隐含)、显示器硬件支持的MaxLuminanceInNits、以及Windows设置中用户手动调节的HDR brightness slider(存储在HKEY_CURRENT_USERSOFTWAREMicrosoftDirectXGraphicsSettingsHdrBrightness,值域0–100,映射到约300–1000 nits)。
-
HdrBrightness注册表值不是线性映射,0对应约300 nits(SDR基准),100对应显示器标称峰值亮度,中间段按PQ曲线非线性压缩 - 调用
SetThreadDpiAwarenessContext后需等待至少500ms再查询亮度,否则QueryVideoCapability可能返回旧缓存值 - 游戏全屏独占模式下,DirectX会覆盖系统HDR亮度设置,此时应监听
DXGI_OUTPUT_DESC::ColorSpace变化而非依赖系统API
最易被忽略的是:即使所有API都返回HDR已启用且亮度范围正常,若应用程序未声明SCENERY或MOVIE色彩空间(通过DXGI_SWAP_CHAIN_DESC1::ColorSpace),GPU驱动仍会以SDR路径渲染——状态存在,但无效。

















