DC 编程模型

Display Core Next (DCN)DCN 块 页面中,您了解了硬件组件以及它们如何相互交互。 在此页面上,重点转移到显示代码架构。 因此,提醒读者 DC 中的代码与其他操作系统共享是合理的。 因此,DC 提供了一组抽象和操作,用于将不同的 API 与硬件配置连接起来。 将 DC 视为显示管理器 (amdgpu_dm) 可用于访问和配置 DCN/DCE 硬件的服务(DCE 也是 DC 的一部分,但为了简单起见,本文档仅检查 DCN)。

注意

对于本页,我们将使用术语 GPU 来指代 dGPU 和 APU。

概述

从显示硬件的角度来看,可以合理地预期,如果一个问题被很好地定义,它可能会在硬件层面实现。 另一方面,当有多种方法可以在没有非常明确定义范围的情况下实现某些目标时,解决方案通常作为 DC 级别的策略来实现。 换句话说,一些策略在 DC 核心中定义(资源管理、电源优化、图像质量等),而硬件中实现的其他策略通过 DC 配置启用。

在硬件管理方面,DCN 具有相同块的多个实例(例如,HUBP、DPP、MPC 等),并且在驱动程序执行期间,可能需要使用其中一些实例。 核心具有处理这些实例的策略。 关于资源管理,DC 的目标非常简单:当驱动程序执行某些操作时,最大限度地减少硬件 shuffle。 当状态从 A 变为 B 时,如果硬件资源仍用于同一组驱动程序对象,则该转换被认为更容易操作。 通常,向 pipe_ctx(更多细节如下)添加和删除资源不是问题; 但是,应避免将资源从一个 pipe_ctx 移动到另一个 pipe_ctx

DC 的另一个影响领域是电源优化,它有无数种排列可能性。 在某种程度上,仅通过 DCN 显示图像应该相对简单; 但是,以最佳功耗显示它更受欢迎,但它有许多相关的挑战。 不幸的是,由于与此问题相关的变量种类繁多(例如,许多不同的 DCN/DCE 硬件版本、不同的显示配置等),没有直接的分析方法来确定配置是否最适合上下文,因此 DC 实现了一个专用库来尝试一些配置并验证是否可以支持它。 这种类型的策略的创建和维护非常复杂,并且 amdgpu 驱动程序依赖于显示模式库 (DML) 来生成最佳决策。

总而言之,DC 必须处理处理多个场景的复杂性,并确定管理它们的策略。 传达上述所有信息是为了让读者了解从驱动程序的角度驱动显示器的复杂性。 此页面希望使读者能够更好地浏览 amdgpu 显示代码。

显示驱动程序架构概述

下图提供了显示驱动程序架构的概述; 请注意,它说明了 DC 采用的软件层

../../../_images/dc-components.svg

该图的第一层是由 dc.h 文件表示的高级 DC API; 在它下面是由 Core 和 Link 表示的两个大块。 接下来是硬件配置块; 描述它的主要文件是 `hw_sequencer.h`,其中回调的实现可以在硬件序列器文件夹中找到。 几乎在最后,您可以看到块级别 API (dc/inc/hw),它表示每个 DCN 底层块,例如 HUBP、DPP、MPC、OPTC 等。 请注意在图的左侧,我们有一组不同的层代表与 DMUB 微控制器的交互。

基本对象

下图概述了基本的显示对象。 特别是,请注意框中的名称,因为它们代表驱动程序中的数据结构

../../../_images/dc-arch-overview.svg

让我们从图像的中心块 dc 开始。 dc 结构体是每个 GPU 初始化一次; 例如,一个 GPU 有一个 dc 实例,两个 GPU 有两个 dc 实例,依此类推。 换句话说,每个“amdgpu”实例都有一个“dc”。 在某些方面,此对象类似于 Singleton 模式。

在图中的 dc 块之后,您可以看到 dc_link 组件,它是连接器的底层抽象。 图像的一个有趣方面是连接器不是 DCN 块的一部分; 它们由平台/板定义,而不是由 SoC 定义。 dc_link 结构体是高级数据容器,包含连接的 sink、连接状态、信号类型等信息。在 dc_link 之后,是 dc_sink,它是表示连接的显示器的对象。

注意

由于历史原因,我们使用了名称 dc_link,这给人一种错误的印象,即这种抽象只处理开发人员可以轻松操作的物理连接。 但是,这也涵盖了像 eDP 这样的连接,或者输出连接到其他设备的情况。

有两个结构体没有在图中表示,因为它们在 DCN 概述页面中进行了详细说明(查看 DCN 块图 Display Core Next (DCN)); 尽管如此,仍然值得带回来进行此概述,即 dc_streamdc_statedc_stream 存储与数据传输相关的许多属性,但最重要的是,它代表从连接器到显示器的数据流。 接下来是 dc_state,它表示硬件在当前时刻的逻辑状态; dc_statedc_streamdc_plane 组成。dc_streamdrm_crtc 的 DC 版本,代表后混合流水线。

说到 dc_plane 数据结构(图的第一部分),您可以将其视为类似于 drm_plane 的抽象,它代表流水线的预混合部分。 此图像可能已由 GFX 处理,并且已准备好在 dc_stream 下进行合成。 通常,驱动程序可能有一个或多个 dc_plane 连接到同一个 dc_stream,这定义了 DC 级别的合成。

基本操作

现在我们已经介绍了基本对象,现在是时候检查一些基本的硬件/软件操作了。 让我们从 dc_create() 函数开始,它直接处理 dc 数据结构; 此函数的作用类似于构造函数,负责基本的软件初始化并为启用 API 的其他部分做准备。 重要的是要强调此操作不会触及任何硬件配置; 它只是一个软件初始化。

接下来,我们有 dc_hardware_init(),它也依赖于 dc 数据结构。 它的主要功能是将硬件置于有效状态。 值得强调的是,硬件可能会在未知状态下初始化,并且需要将其置于有效状态; 此函数具有多个特定于硬件初始化的回调,而 dc_hardware_init 执行硬件初始化,并且是我们接触硬件的第一个点。

dc_get_link_at_index 是一个依赖于 dc_link 数据结构的操作。 此函数检索并枚举设备上所有可用的 dc_links; 这是必需的,因为此信息不是 SoC 定义的一部分,而是取决于板配置。 一旦 dc_link 被初始化,就可以使用 dc_link_detect() 函数来判断它们中是否有任何一个已经连接到显示器。 在驱动程序确定是否有任何显示器连接到设备后,具有挑战性的阶段就开始了:配置监视器以显示某些内容。 尽管如此,处理理想配置不是 DC 的任务,因为这是显示管理器 (amdgpu_dm) 的职责,后者又负责处理原子提交。 DC 提供给配置阶段的唯一接口是函数 dc_validate_with_context,它接收配置信息,并在此基础上验证硬件是否可以支持它。 重要的是要补充一点,即使显示器支持某些特定配置,也并不意味着 DCN 硬件可以支持它。

在 DM 和 DC 就配置达成一致后,流配置阶段开始。 此任务在此阶段激活一个或多个 dc_stream,并且在最佳情况下,您或许可以打开显示器并显示黑屏(它还没有显示任何内容,因为它没有任何与之关联的 plane)。 最后一步是调用 dc_update_planes_and_stream,它将添加或删除 plane。