显示核心下一代 (DCN)

为了让读者掌握 AMD 显示核心下一代 (DCN) 的基本工作原理,我们需要从硬件管道的概述开始。下面你可以看到一张提供 DCN 概述的图片,请记住这是一个通用图,每个 ASIC 都有不同的变体。

../../../_images/dc_pipeline_overview.svg

基于此图,我们可以逐个遍历每个模块并简要描述它们

  • 显示控制器中心 (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 的责任是为每个特定场景驱动最佳配置。将所有这些组件协调在一起需要一个复杂的通信接口,该接口在图中通过连接每个模块的边缘突出显示;从图表中可以看出,这些模块之间的每个连接都表示

  1. 像素数据接口(红色):表示像素数据流;

  2. 全局同步信号(绿色):它是由 VStartup、VUpdate 和 VReady 组成的一组同步信号;

  3. 配置接口:负责配置模块;

  4. 边带信号:所有不适合前一个信号的其他信号。

这些信号至关重要,并在 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 的工作是将通用像素流帧化为特定显示器的像素流。

数据流

最初,数据以原生像素格式从 VRAM 通过数据结构 (DF) 传入。这种数据格式一直保留到 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,它可以根据需要任意分配。我们使用这种管道概念来尝试优化带宽利用率。

../../../_images/pipeline_4k_no_split.svg

此外,让我们看一下 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 是灵活的,我们可以以不同的方式拆分这个单管道,如下面的图所示

../../../_images/pipeline_4k_split.svg

现在,如果我们再次检查 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 管道供电,而不会发生下溢或挂起。全局同步信号始终在垂直空白期间发生,独立于垂直同步信号,并且彼此不重叠。

VUPDATE 是驱动程序堆栈或用户空间客户端唯一感兴趣的信号,因为它标志着硬件锁存到原子编程(即双缓冲)寄存器的时刻。尽管它独立于 VSync 信号,但我们使用 VUPDATE 来表示 VSync 事件,因为它能够最好地指示原子提交和硬件之间的交互方式。

由于 DCN 硬件是双缓冲的,因此 DC 驱动程序能够在帧期间的任何时间编程硬件。

下图说明了全局同步信号

../../../_images/global_sync_vblank.svg

这些信号会影响 DCN 的核心行为。错误地编程它们会导致许多负面后果,其中大多数都是灾难性的。

下图显示了全局同步如何实现邮箱式的更新,即它允许在 VUpdate 事件之间进行多次重新配置,其中只有在 VUpdate 信号之前编程的最后一个配置才会生效。

../../../_images/config_example.svg