显示核心下一代 (DCN)¶
为了让读者掌握 AMD 显示核心下一代 (DCN) 的基本工作原理,我们需要从硬件流水线的概述开始。 下面您可以看到一张提供 DCN 概述的图片,请记住,这是一个通用图,每个 ASIC 都有变体。
基于这张图,我们可以遍历每个块并简要描述它们
显示控制器集线器 (DCHUB):这是可扩展数据端口 (SDP) 和 DCN 之间的网关。 此组件具有多种功能,例如内存仲裁、旋转和光标操作。
显示管道和平面 (DPP):此块提供预混合像素处理,例如颜色空间转换、像素数据线性化、色调映射和色域映射。
多管道/平面组合 (MPC):此组件使用全局或每像素 alpha 执行多个平面的混合。
输出像素处理 (OPP):处理和格式化像素以发送到显示器。
输出管道时序组合器 (OPTC):它生成时间输出以组合流或划分能力。 CRC 值在此块中生成。
显示输出 (DIO):将输出编码到连接到我们 GPU 的显示器。
显示回写 (DWB):它提供将显示管道的输出作为视频帧写回内存的能力。
多媒体集线器 (MMHUBBUB):用于 DMCUB 和 DWB 的内存控制器接口(请注意,DWB 尚未连接)。
DCN 管理单元 (DMU):它提供带有访问控制的寄存器,并将控制器中断到 SOC 主机中断单元。 此块包括显示微控制器单元 - B 版本 (DMCUB),它通过固件处理。
DCN 时钟发生器块 (DCCG):它为所有显示控制器时钟域提供时钟和复位。
Azalia (AZ):音频引擎。
上面的图是 DCN 的架构概括,这意味着每个 ASIC 都有围绕这个基本模型的变体。 请注意,显示管道通过 DCHUB 连接到可扩展数据端口 (SDP); 您可以将 SDP 视为我们数据结构中为显示管道提供数据的元素。
始终将 DCN 架构视为可以以多种方式配置和重新配置的灵活事物; 换句话说,可以根据用户空间的需求相应地设置或忽略每个块。 例如,如果我们想驱动一个启用 DSC 的 8k@60Hz,我们的 DCN 可能需要 4 个 DPP 和 2 个 OPP。 DC 的职责是为每个特定场景驱动最佳配置。 将所有这些组件协调在一起需要一个复杂的通信接口,该接口在图中由连接每个块的边突出显示; 从图表中可以看出,这些块之间的每个连接代表
像素数据接口(红色):表示像素数据流;
全局同步信号(绿色):它是由 VStartup、VUpdate 和 VReady 组成的一组同步信号;
配置接口:负责配置块;
边带信号:所有不符合前一个的信号。
这些信号至关重要,并在 DCN 中发挥重要作用。 然而,全局同步值得在下一节中详细描述。
所有这些组件都由一个名为 dc_state 的数据结构表示。 从 DCHUB 到 MPC,我们有一个名为 dc_plane 的表示; 从 MPC 到 OPTC,我们有 dc_stream,输出 (DIO) 由 dc_link 处理。 请记住,HUBP 使用从内存读取的特定格式访问表面,并且我们的 dc_plane 应该努力将平面中的所有像素转换为可以通过 dc_stream 和 dc_link 发送到显示器的东西。
前端和后端¶
显示管道可以分解为通常称为前端 (FE) 和后端 (BE) 的两个组件,其中 FE 包括
DCHUB(主要指名为 HUBP 的子组件)
DPP
MPC
另一方面,BE 包括
OPP
OPTC
DIO (DP/HDMI 流编码器和链路编码器)
OPP 和 OPTC 是 FE 和 BE 之间的两个连接块。 顺便说一句,这是链路编码器到 PHY 的一对一映射,但我们可以配置 DCN 以选择将哪个链路编码器连接到哪个 PHY。 FE 的主要职责是更改、混合和组合像素数据,而 BE 的工作是将通用像素流构架为特定显示的像素流。
数据流¶
最初,数据以原生像素格式通过数据结构 (DF) 从 VRAM 传入。 这种数据格式一直保持到 DCHUB 中的 HUBP,HUBP 在这里解压缩不同的像素格式,并通过 4 个通道(1 个用于 alpha + 3 个用于颜色)以统一的流将它们输出到 DPP。
DPP 中的转换器和光标 (CNVC) 然后将规范化数据表示形式,并将它们转换为 DCN 特定的浮点格式(即,不同于 IEEE 浮点格式)。 在此过程中,CNVC 还应用一个反伽玛函数,将数据从非线性空间转换为线性空间,以放松后续的浮点计算。 数据将以这种浮点格式从 DPP 保持到 OPP。
从 OPP 开始,因为颜色转换和混合已经完成(即,可以删除 alpha),并且最终接收器不需要浮点提供的精度和动态范围(即,所有显示器都是整数深度格式),因此位深度减少/抖动会启动。 在 OPP 中,我们还将应用一个反伽玛函数,以将先前删除的伽玛重新引入。 最终,我们以整数格式在 DIO 输出数据。
AMD 硬件流水线¶
在讨论 Linux 上的图形时,流水线术语有时可能被过度使用,具有多种含义,因此重要的是定义我们所说的流水线的含义。 在 DCN 驱动程序中,我们使用术语硬件流水线或流水线或仅管道作为一种抽象,以指示实例化的一系列 DCN 块,以解决某些特定配置。 DC 核心将 DCN 块视为单个资源,这意味着我们可以通过获取所有单个硬件块的资源来构建一个管道来组成一个管道。 实际上,我们无法将一个管道中的任意块连接到另一个管道中的块; 它们是线性路由的,除了 DSC,它可以根据需要任意分配。 我们有这个流水线概念是为了尝试优化带宽利用率。
此外,让我们看一下 DTN 日志的一部分(有关更多信息,请参见“显示核心调试工具”),因为此日志可以帮助我们实时查看此流水线行为的一部分
HUBP: format addr_hi width height ...
[ 0]: 8h 81h 3840 2160
[ 1]: 0h 0h 0 0
[ 2]: 0h 0h 0 0
[ 3]: 0h 0h 0 0
[ 4]: 0h 0h 0 0
...
MPCC: OPP DPP ...
[ 0]: 0h 0h ...
从图和 DTN 日志中首先要注意的是,我们 DCN 块的每个部分都有不同的时钟域。 在此示例中,我们只有一个流水线,其中数据从 DCHUB 流向 DIO,正如我们凭直觉所期望的那样。 尽管如此,如前所述,DCN 是灵活的,我们可以以不同的方式拆分这单个管道,如下面的图所示
现在,如果我们再次检查 DTN 日志,我们可以看到一些有趣的变化
HUBP: format addr_hi width height ...
[ 0]: 8h 81h 1920 2160 ...
...
[ 4]: 0h 0h 0 0 ...
[ 5]: 8h 81h 1920 2160 ...
...
MPCC: OPP DPP ...
[ 0]: 0h 0h ...
[ 5]: 0h 5h ...
从上面的示例中,我们现在将显示管道分成两个 1920x2160 的垂直部分(即 3440x2160),因此,我们可以降低 DPP 部分中的时钟频率。 这不仅对于节省功耗很有用,而且对于更好地处理所需的吞吐量也很有用。 这里要记住的是,管道配置可能会根据显示配置而变化很大,并且 DML 的职责是为我们的硬件支持的多种场景设置所有必需的配置参数。
全局同步¶
许多 DCN 寄存器都是双缓冲的,最重要的是表面地址。 这使我们能够以原子方式更新 DCN 硬件以进行页面翻转,以及大多数其他不需要启用或禁用新管道的更新。
(注意:在许多情况下,DC 会决定保留额外的管道,以支持需要非常高的像素时钟的输出,或出于省电的目的。)
这些原子寄存器更新由 DCN 中的全局同步信号驱动。 为了了解原子更新如何与 DCN 硬件交互,以及 DCN 如何发出页面翻转和垂直消隐事件的信号,了解全局同步的编程方式很有帮助。
全局同步由三个信号组成:VSTARTUP、VUPDATE 和 VREADY。 这些信号由显示模式库 - DML (drivers/gpu/drm/amd/display/dc/dml) 基于大量参数计算得出,并确保我们的硬件能够在任何给定的系统配置中为 DCN 管道提供数据,而不会出现下溢或挂起。 全局同步信号始终发生在垂直消隐期间,独立于 VSync 信号,并且彼此不重叠。
VUPDATE 是驱动程序堆栈或用户空间客户端唯一感兴趣的信号,因为它表示硬件锁定到原子编程的(即双缓冲)寄存器的点。 即使它独立于 VSync 信号,我们也使用 VUPDATE 来发出 VSync 事件的信号,因为它提供了有关原子提交和硬件如何交互的最佳指示。
由于 DCN 硬件是双缓冲的,因此 DC 驱动程序能够在帧的任何时间点对硬件进行编程。
下图说明了全局同步信号
这些信号会影响核心 DCN 行为。 如果编程不正确,将导致许多负面后果,其中大多数是灾难性的。
下图显示了全局同步如何允许邮箱样式的更新,即它允许在 VUpdate 事件之间进行多次重新配置,其中只有在 VUpdate 信号之前编程的最后一个配置才生效。