DC 编程模型

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

注意

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

概述

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

在硬件管理方面,DCN 具有相同模块的多个实例(例如,HUBP、DPP、MPC 等),在驱动程序执行期间,可能需要使用其中一些实例。核心制定了处理这些实例的策略。关于资源管理,DC 的目标非常简单:当驱动程序执行某些操作时,尽量减少硬件的改组。当状态从 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;在它下面是由核心和链接表示的两个大模块。接下来是硬件配置模块;描述它的主要文件是 `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 结构是高级数据容器,包含诸如连接的接收器、连接状态、信号类型等信息。在 dc_link 之后,是 dc_sink,它是表示连接的显示器的对象。

注意

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

该图中没有表示两个结构,因为它们在 DCN 概述页面中进行了详细说明(请查看 DCN 模块图 显示核心下一代 (DCN));不过,为了概述起见,值得再回顾一下 dc_streamdc_statedc_stream 存储了许多与数据传输相关的属性,但最重要的是,它表示从连接器到显示器的数据流。接下来是 dc_state,它表示当前硬件中的逻辑状态;dc_statedc_streamdc_plane 组成。dc_streamdrm_crtc 的 DC 版本,表示混合后的管道。

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

基本操作

现在我们已经介绍了基本对象,接下来就该研究一些基本的硬件/软件操作了。让我们从直接与 dc 数据结构配合使用的 dc_create() 函数开始;此函数的行为类似于构造函数,负责基本的软件初始化,并为启用 API 的其他部分做准备。必须强调的是,此操作不会触及任何硬件配置;它只是一个软件初始化。

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

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

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