关于 Windows 10/11 的全系统色彩管理

2022-04-14 01:59:51 +08:00
 dant

Windows 的色彩管理一直是一个非常令人诟病的问题,甚至已经把人逼到去 hook dwm。在当前版本的 Windows 10/11 中,微软静悄悄地加入了两个色彩管理有关的功能:

一.硬件矩阵变换

硬件实现的色彩空间转换其实已经不是新鲜事,当前的 GPU 硬件基本都支持在 RGB 通道间进行线性变换,更有甚者提供了 3DLUT ,驱动也提供了对应的用户态 API ,或进一步包装成色彩空间转换 API 。( API 参考:NVIDIAAMDIntel

而在 Linux drm 框架下,硬件矩阵变换功能对应统一的 drm_color_ctm API ,可以从用户态直接访问,或通过 XRandR CTM API 访问。

后来 WDDM 规范中加入了矩阵变换作为可选功能,但是并没有说明如何从用户态调用这个功能。

在 Windows 11 SDK 中,微软提供了一个没有文档、甚至没有对应导出函数的 API:

// C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\Icm.h:1481
#if NTDDI_VERSION >= NTDDI_WIN10_CO

struct WCS_DEVICE_VCGT_CAPABILITIES
{
    UINT Size;              //  Size of structure in bytes
    BOOL SupportsVcgt;      //  Indicates if display supports VCGT 
};

struct WCS_DEVICE_MHC2_CAPABILITIES
{
    UINT Size;                      //  Size of structure in bytes
    BOOL SupportsMhc2;              //  Indicates if display supports MHC2

    UINT RegammaLutEntryCount;      //  Max number of entries in the regamma lut

    // Color space transform (CSC) matrix (row-major)
    UINT CscXyzMatrixRows;          //  Number of rows in the color transform matrix
    UINT CscXyzMatrixColumns;       //  Number of columns in the color transform matrix
};

typedef enum 
{
    VideoCardGammaTable = 1,
    MicrosoftHardwareColorV2 = 2,
} WCS_DEVICE_CAPABILITIES_TYPE;

/*
 * Gets the selected display color correction capabilities
 *
 * Parameters:
 *    scope                 specifies the association as system-wide or user-specific
 *    targetAdapterID       the target adapter of the display
 *    sourceID              the source identifier of the display  
 *    capsType              the type of capabilities to retrieve (VCGT, MHC2)
 *    outputCapabilities    the color correction capabilities to return
 */
HRESULT WINAPI ColorProfileGetDeviceCapabilities(
    _In_ WCS_PROFILE_MANAGEMENT_SCOPE scope,
    _In_ LUID                         targetAdapterID,
    _In_ UINT32                       sourceID,
    _In_ WCS_DEVICE_CAPABILITIES_TYPE capsType,
    _Out_ PVOID                outputCapabilities
);

#endif //NTDDI_VERSION >= NTDDI_WIN10_CO

与此同时,新上市的广色域(指超出 sRGB )笔记本 /显示器附带的 ICC 文件中还包含了一个叫做 MHC2 的神秘 tag ,合理怀疑是与上面的 MicrosoftHardwareColorV2 有关。通过横向对比多个 ICC 文件中的 MHC2 tag 以及一些简单的逆向分析,再结合 SDK 中提供的信息,得出这个 tag 中存放的是屏幕的最高 /最低亮度,以及用于色彩空间转换的矩阵( 4x3 ,猜测是多了一列 offset )和 regamma LUT 。

鉴于 Windows 应用默认 sRGB 色彩空间,我们可以求得一个矩阵将 sRGB 的三通道亮度转换到设备色彩空间的三通道亮度,然后通过 gamma 曲线和色调响应曲线求出亮度对应的输入信号,从而将屏幕校准为 sRGB 。

通过校色 ICC 和校准目标 ICC 生成 MHC2 ICC 的工具已发布在 GitHub 上: https://github.com/dantmnf/MHC2

小插曲

一开始我的直觉告诉我这个矩阵的输入是 RGB ,于是填了一个 [[0,1,0,0],[1,0,0,0],[0,0,1,0]] 试图交换红色分量和绿色分量,结果发现白点向紫色方向偏移了。后来看到 SDK 里那个 CscXyzMatrixRows,又尝试在 XYZ 空间的白点中交换了 XY ,转换回 RGB 空间后,发现绿色分量变少了。

后来我在两边各乘了一个 XYZ/RGB 转换矩阵,成功互换了红色分量与绿色分量。但是我依然不能理解为什么一个声称 color space transform/conversion 的矩阵要应用在 XYZ 空间,尤其是变换结果依然当作 XYZ 解释。对此我直呼大脑升级

此处应有发光大脑 meme 图.jpg

二、带色彩管理的桌面混成

在上面的方法中,Windows 依然认为设备色彩空间是 sRGB ,并且通过 GPU 的 display engine 将 framebuffer 中的 sRGB 信号转换为真正的设备色彩空间信号。这种做法不会占用额外的通用计算资源,但同时系统也无法输出在 sRGB 空间外,却在设备色彩空间内的颜色。

Windows 在引入 HDR 桌面的同时也带来了桌面混成的色彩管理(内部名称 advanced color):支持 advanced color 的应用输出 scRGB 信号,不支持 advanced color 的应用输出被认为是 sRGB 信号,各个应用的输出经混成器( dwm.exe )在 scRGB 空间进行混成后,最终转换为设备色彩空间信号传送到显示器。

这一过程对 HDR 桌面而言是必须的,但通过逆向分析 dxgkrnl.sys ,发现在特定条件下也可以在 SDR 桌面中强行启用,详见 https://github.com/dantmnf/MHC2#advanced-color-for-sdr 。通过对比多个版本的 dxgkrnl.sys,推断这一功能可能会在 Windows 11 的下一个大版本更新中正式发布。

(Credit: @imbushuo)

如果显示器声称支持 HDR ,advanced color 将使用 Rec. 2020 (存疑) + PQ 作为设备色彩空间,由显示器内部转换为合适的面板信号。但对于消费级电子垃圾显示器而言,这个转换过程很可能是不准确且无法校准的。

不幸的是,在假 HDR* 显示器大行其道的今天,我们很难找到一台广色域但不支持 HDR 的显示器。如果你的显示器声明了假 HDR ,你可以尝试以下方法让 Windows 认为它不支持 HDR:

很可惜我是属于那种不能覆盖 HDR 信息并且没有专业显卡的,但是已经有两个有钱的群友在多个版本的 Windows 10/11 上测试成功了。

* 假 HDR ,又称 HDRn’t 、ScamHDR 400

4000 次点击
所在节点    分享发现
5 条回复
4c5577c0ff3f496b
2022-04-14 02:04:35 +08:00
这样好.jpg
qazplkm
2022-04-14 03:04:43 +08:00
苹果那玩意不适合 Windows 。用 LG OLED 电视或者 EP950 显示器
carlist
2022-04-14 08:24:27 +08:00
从显示器厂商的角度说说
最恶心人的就是 HDR 标定 - 锁死所有调整参数只能那么用
所以这个 HDR 就是垃圾

色彩偏移是硬件转换标定的锅
叫电脑老老实实的输出 SRGB 信号就行了
没必要故意偏移或者加载色彩参数
叫显示器自己的硬件调节做好该做的
做不好的垃圾玩意直接砸换新就好
TrembleBeforeMe
2022-04-14 10:01:38 +08:00
目前的低价 HDR 显示器体验实在是不能说好
mmdsun
2022-05-01 15:26:26 +08:00
后来 WDDM 规范中加入了[矩阵变换作为可选功能]( https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/d3dkmddi/ns-d3dkmddi-_dxgk_colortransformcaps),但是并没有说明如何从用户态调用这个功能。在 Windows 11 SDK 中,微软提供了一个没有文档、甚至没有对应导出函数的 API 。

这个文档 doc ,往最下面有个 github 连接,你去提 question 问就好了或者要求补充更详细文档。我之前调 WinUI3 框架,网上根本找不到类似资料,有问题直接去问,微软基本都秒回。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/846850

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX