8 月末, macOS 外接显示器自动亮度工具 Lunar 的开发者 Alin Panaitiu 在自己的一篇博客中提到了这样一个现象:

You know how people get two identical monitors and place them side by side for a neat ultrawide-like look.

Well a lot of those people experience a very annoying behavior: After standby or restart, the monitors get swapped by the OS, so moving the cursor to the left monitor will actually appear on the right monitor, and vice-versa.

If the monitors also had some of the settings different, like resolution or color profile, those also get swapped.

简而言之,在电脑上连接了两块同型号的显示器之后,一旦显示器进入待机或重启,两块显示器上面的内容就有概率会被互换(比如分割好的壁纸),与之相伴的还有一些在分辨率、色彩档案上有差别的设置也会一并发生对调——尽管你并没有调整任何东西。

boxcnrkg1wcANebpgtz3GwbqC5g
图|Alin Panaitiu

发生类似问题的原因,便出在显示器传输给电脑的识别信息中。

在人类用户之外,那个硅基的世界里,你的显示器是怎样与你的输出设备交流、让它输出适当的显示内容的呢?这答案便是 EDID ——扩展显示器标识数据(Extended Display Identification Data)。

EDID 的功能

与我们手动连接显示器,屏幕画面「啪就转过去了,很快啊」的观感不同,画面数据的传输是需要经过画面的源端(Host Device,比如显卡、机顶盒)与终端(Display Device,比如显示器、电视、投影仪)进行一次握手和数据交换,由终端设备主动将自己支持的分辨率、刷新率、色域、Gamma 值等等信息告知源端,从而避免输出设备为了保持最大兼容性而仅仅输出最低规格的画面或者遍历所有支持的格式,导致浪费性能或浪费时间。

boxcnWdeg5DjGM07FL0E0MN8VIc
EDID 工作方式的本质:吆喝

这些由画面接收端主动通报给输出端的数据,就是这台显示设备的 EDID ,由显示数据通道(Display Data Channel, DDC)负责传输——所以有时也会被不太规范的称为 DDC 数据。因此,显示设备的 EDID 负责解决的,就是展示这台显示器「我是谁,我能做什么,我能怎么做」的「灵魂三问」的答案。

作为一项上世纪九十年代被 VESA 协会(Video Electronics Standards Association,视频电子标准协会)提出的标准数据格式, EDID 的应用范围横跨了从模拟信号到数字信号的各类主流传输协议,从 1994 到 2006 年间共经历了五个版本。以 2000 年推出的 v1.3 版本为界, v1.3 和 v1.4 的 EDID 被称为 E-EDID ,即 Enhanced Extended Display Identification Data ——增强扩展显示器标识数据,相比更早版本的 EDID 规范进行了数据量的扩充。

而随着技术的进步和普及, VESA 协会于 2007 年进一步推出了新的格式标准 DisplayID ,被视为是第二代的 EDID 。 DisplayID 在向下兼容 EDID 标准的同时增加了对于 3D 显示、广色域及 HDR 之类比较新的内容标准的支持。并且相比 EDID , DisplayID 对于数据格式的灵活性放宽了许多,让显示设备厂商可以根据自己的需求增减所需的数据块。

但相比规格更高的 DisplayID ,目前最主流的显示设别识别协议仍然是 E-EDID 。本文基于 HDMI 协议下 E-EDID v1.4 进行介绍。

寻找 EDID

EDID 相比显示设备的分辨率、色彩空间等等参数而言,是一个更加底层的数据,绝大多数的显示设备都不会预置查看方式,我们需要通过在显示信号的源端——比如电脑上——通过一些第三方的程序进行查询。 Windows 平台可以使用 Monitor Asset Manager , macOS 上则有包含在 Xcode 工具中的 IORegistryExplorer ,可以单独下载并独立使用。

以 IORegistryExplorer 为例,打开程序后在搜索框内输入「display」,在左侧的目录中找到 display0 下面的 AppleBacklightDisplay 与 AppleDisplay ,对应的分别是 MacBook 的内置屏幕与外接的显示器,选择其中任意一个之后右侧 IODisplayEDID 下便是显示器的 EDID 数据。

boxcnA3zqJPrZPjlPwC1HfgMXyf

除了下载专用的程序之外,你也可以直接使用

ioreg -lw0 | grep IODisplayEDID

指令在 Terminal 中获取所有正在使用中的显示设备的 EDID ,展示顺序依然是内置 - 外接显示器。

boxcnjipoqeyj4AMqJiVpOrK6qc

解读 EDID

在绝大多数情况下,这些由显示器回报上来的 EDID 数据是无需用户劳神费力去解读的,对于 EDID 信息的编写和固件刷入也主要是显示器厂商的工作,但是这仍然不妨碍我们以分段的形式简单了解一下 EDID 数据的构成。

以 MacBook 内置屏幕的 EDID 信息为例,其中包含了 256 个字节( Byte )的 16 进制数据,分为两个各 128 字节的数据块 block0 和 block1 。

boxcnzlwrIhmt4meYbiBLskWL0f

其中 block0 包含了 EDID 规定的基础数据,也被称为 Base Block ;而后的 block1 、block2 等等可以根据 EDID 协议的版本和设备的支持规格最多延伸出 255 个 Extension Block (只限 E-EDID v1.4 ,v1.3 需要将 Block 255 留出来作为 Block Map ),组成由 256 个 Block 构成的 EDID 数据。

头信息(Header Information)

boxcnr9Bk7u8et1AXGc5MSHJ4Of

Base Block 的前 20 个字节的信息被称为整段 EDID 的头信息,其中包含了 8 个字节的固定字符、10 个字节的生产厂商信息与 2 个字节的 EDID 版本信息。

基本显示参数(Basic Display Parameters and Features)

boxcngK5e4bklRekmZjZ3CQwE9f

在 EDID 头信息之后的 5 个字节则包含了设备的基本显示参数,负责描述显示器支持的输入格式——比如模拟信号或数字信号、屏幕的尺寸以及 Gamma 值,以及 1 字节的功能支持信息(比如是否是使用模拟信号的单色显示器、是否支持 DPMS ——显示器的节能待机模式——等等)。

色度信息(Color Characteristics)

boxcnVz0HATerWmsanOZzKyXvvg

基本显示参数之后的 10 个字节分别以红色/绿色、蓝色/白色的最低坐标、红绿蓝白分别在 X 与 Y 轴上的最高坐标数描述了显示设备显示颜色的能力——比如对于单色显示器来说,《VESA-EEDID-A2》规范文档中就建议将白色之外的三种颜色的 XY 轴坐标均设置为 00hex 。

既定时序与标准时序(Established Timings, Standard Timings)

boxcno8EHWeONeOu6Fs2iZyTQMh

色度信息后的 19 个字节的信息展示了显示设备的分辨率信息,分为 3 个字节的 Established Timings 与 16 个字节的 Standard Timings 。其中 Established Timings 3 个字节分别对应了一些早期显示器的格式,比如 Apple Mac II 的 640 x 480 @ 67Hz ,以及 IBM XGA2 的 720 x 400 @ 88Hz 等等;后面 16 字节的 Standard Timings 则用来容纳显示设备支持的更多预设分辨率。

在 E-EDID v1.4 中这两处分辨率数据对于不使用 VESA Plug & Play 接口的显示设备都是选填的,因此可以看到苹果在这两处填写的都是默认的填充符。

详细时序信息(Detailed Timing Descriptor Block)

在既定与标准时序之后的 72 个字节被用来描述显示设备支持的更多分辨率信息,分为四个各 18 字节的 Descriptor ,依次为:

  • 1st Detailed Timing Descriptor
  • 2nd Detailed Timing Descriptor
  • 1st Monitor Descriptor
  • 2nd Monitor Descriptor

其中 1st Detailed Timing Descriptor 会包含显示设备制造商决定的 Preferred Timing Mode (PTM) ,即由显示面板决定的可以显示最佳画质的那个分辨率,对应的通常就是显示设备的默认分辨率。同时得益于 18 字节可以承载的信息量比前面既定时序与标准时序更多,这里也可以填写更多 CEA-861 文件之外的非标准的分辨率数据。

boxcnpPS5Qq32ES47XtAml5iH3b

1st Detailed Timing Descriptor

而在 HDMI 协议下,后续的三组 Descriptor 中则会包含一部分 Monitor Range Descriptor,用来描述显示设备的水平与垂直刷新率,以及 Monitor Name Descriptor 用来包含产品名称。

扩展数量与校验码(Extension Flag & Checksum)

boxcn8yF4gkofYoEvQRs1lDqDtg

在 Base Block 的最后两个字节中,前一字节被称为 Extension Flag ,标记了这台显示设备的 EDID 数据中包含了几个 Extension Block 。最后一字节则是 Base Block 前面 127 字节数据的校验码,由源端在连接时对 Base Block 进行模除(modulo)后加总,计算结果为 00hex 即 EDID 数据无误。

Extension Block

在格式基本固定的 Base Block 之后,显示设备的生产厂商可以根据自己的需要和设备的规格自行添加 Extension Block 对显示设备的更多功能进行描述,比如更加细分的分辨率种类、 HDR 和 3D 支持等等。如果显示设备自带扬声器的话,关于内建扬声器的支持格式、分布方式之类的信息也会被保存在 Extension Block 中。

EDID 的问题

回到开头 Alin Panaitiu 博客里提到的那个问题上。

每当电脑连接到显示器时,电脑会将用户针对这台显示器的各项设置——比如布局、分辨率、色彩文件等等,根据显示器的 EDID 生成一份 UUID (识别码)将对应的配置储存下来。而显示器在进入待机模式后,会完全断开与电脑的连接、从电脑的 I/O 注册表中消失。

然而在 E-EDID v1.4 中, VESA 协会并没有强制要求显示设备厂商在 EDID 中记录产品的序列号——无论是在头信息中纯数字格式的序列号还是 Monitor Descriptor 中 ASCII 编码的序列号——这样就导致一些显示器厂商会将相同的 EDID 数据刷写到同一批次相同型号的显示器产品中。

boxcno3dAWCWAPD5lGdvQRq1xad

《VESA-EEDID-A2》

而电脑正是根据显示器的 EDID 来生成对应的配置文件的,如果你用来组多屏幕的几台显示器不巧是来自同一生产批次的同型号产品的话,它们固件中相同的 EDID 会让电脑为它们生成相同的 UUID ,哪怕这些 UUID 对应的是你分别设置过的不同的显示设置。

boxcn2jcCG8TytjRCdXr4IokEie

因此,当显示器被重新唤醒后,这些显示器在电脑的眼中是完全相同的,电脑只能随机将 UUID 对应的配置文件分配给它们,最终呈现的结果便是你的电脑有时候会把你已经分别设置好的多显示器配置搞混。

修改 EDID ?

很不幸的是,对于这些由于 EDID 导致的问题,目前仍然很难找到特别好的解决方案, Alin Panaitiu 最终也是通过写了一个对调显示器的脚本来处理,并没有从 EDID 本身入手。

尽管 EDID 通常储存在显示设备的 EEPROM 上,是可以通过一些工具进行修改的。但是修改 EDID 不仅需要专用的软件,还需要对 EDID 协议本身的编写方式有足够的了解,有时甚至还得手动计算一些参数(比如像素频率 Pix Clk 以确定某个分辨率对应的刷新率)。因此目前需要触碰到 EDID 的场景中,反而是提取原有 EDID 信息后注入 Hackintosh 以解决显示问题反而占了大多数。

但如果重新编写 EDID 的确是你的需要,那么这篇微软为 Windows 硬件开发者提供的通过 INF 文件覆写 EDID 的技术文档或许是最专业稳妥的方式:Manufacturer override of monitor EDIDs ,也可以参阅中国电子技术标准化研究院出版的 EDID 规范详解

> 下载 少数派 2.0 客户端、关注 少数派公众号,解锁全新阅读体验 📰

> 实用、好用的 正版软件,少数派为你呈现 🚀