V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dant
V2EX  ›  分享发现

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

  •  4
     
  •   dant · 2022-04-14 01:59:51 +08:00 · 4018 次点击
    这是一个创建于 986 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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:

    • 覆盖 EDID ,删除其中的 HDR static metadata
      • 通过注册表设置 EDID_OVERRIDE(具体效果与驱动有关,可能无法覆盖 HDR 信息)
      • 通过专业显卡的控制面板设置(极高的溢价)
      • 通过可以更改 EDID 的转换盒子(如 3DLUT loader )
      • 自己打板子,拦截 EDID 传输

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

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

    第 1 条附言  ·  2022-10-13 23:49:53 +08:00
    5 条回复    2022-05-01 15:26:26 +08:00
    4c5577c0ff3f496b
        1
    4c5577c0ff3f496b  
       2022-04-14 02:04:35 +08:00
    这样好.jpg
    qazplkm
        2
    qazplkm  
       2022-04-14 03:04:43 +08:00
    苹果那玩意不适合 Windows 。用 LG OLED 电视或者 EP950 显示器
    carlist
        3
    carlist  
       2022-04-14 08:24:27 +08:00
    从显示器厂商的角度说说
    最恶心人的就是 HDR 标定 - 锁死所有调整参数只能那么用
    所以这个 HDR 就是垃圾

    色彩偏移是硬件转换标定的锅
    叫电脑老老实实的输出 SRGB 信号就行了
    没必要故意偏移或者加载色彩参数
    叫显示器自己的硬件调节做好该做的
    做不好的垃圾玩意直接砸换新就好
    TrembleBeforeMe
        4
    TrembleBeforeMe  
       2022-04-14 10:01:38 +08:00
    目前的低价 HDR 显示器体验实在是不能说好
    mmdsun
        5
    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 框架,网上根本找不到类似资料,有问题直接去问,微软基本都秒回。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4185 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 10:13 · PVG 18:13 · LAX 02:13 · JFK 05:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.