内核模式设置 (KMS)

驱动程序必须通过在 DRM 设备上调用 drmm_mode_config_init() 来初始化模式设置核心。该函数初始化 struct drm_device 的 mode_config 字段,并且永远不会失败。完成后,必须通过初始化以下字段来设置模式配置。

  • int min_width, min_height; int max_width, max_height; 帧缓冲区以像素为单位的最小和最大宽度和高度。

  • struct drm_mode_config_funcs *funcs; 模式设置函数。

概述

KMS Display Pipeline

KMS 显示管道概述

KMS 向用户空间呈现的基本对象结构相当简单。帧缓冲区(由 struct drm_framebuffer 表示,请参阅 帧缓冲区抽象)馈送到平面。平面由 struct drm_plane 表示,有关更多详细信息,请参阅 平面抽象。一个或多个(甚至没有)平面将其像素数据馈送到 CRTC(由 struct drm_crtc 表示,请参阅 CRTC 抽象)进行混合。在 平面合成属性 和相关章节中更详细地解释了精确的混合步骤。

对于输出路由,第一步是编码器(由 struct drm_encoder 表示,请参阅 编码器抽象)。这些实际上只是用于实现 KMS 驱动程序的辅助库的内部产物。除此之外,它们使用户空间不必要地更难以弄清楚 CRTC 和连接器之间的哪些连接是可能的,以及支持哪种克隆,它们在用户空间 API 中没有任何用途。不幸的是,编码器已暴露给用户空间,因此此时无法删除它们。此外,暴露的限制通常由驱动程序错误地设置,并且在许多情况下不足以表达实际的限制。一个 CRTC 可以连接到多个编码器,并且对于一个活动的 CRTC,必须至少有一个编码器。

显示链中的最终也是真正的端点是连接器(由 struct drm_connector 表示,请参阅 连接器抽象)。连接器可以有不同的可能编码器,但内核驱动程序会为每个连接器选择要使用的编码器。用例是 DVI,它可以在模拟和数字编码器之间切换。编码器还可以驱动多个不同的连接器。每个活动编码器都有一个活动的连接器。

在内部,输出管道稍微复杂一些,并且更接近当今的硬件

KMS Output Pipeline

KMS 输出管道

在内部,另外两个辅助对象会发挥作用。首先,为了能够共享编码器的代码(有时在同一 SoC 上,有时在片外),可以将一个或多个 桥接器(由 struct drm_bridge 表示)链接到编码器。此链接是静态的,无法更改,这意味着需要在 CRTC 和任何编码器之间映射交叉开关(如果有)。通常,对于具有桥接器的驱动程序,编码器级别没有剩余的代码。原子驱动程序可以忽略所有编码器回调,基本上只留下一个虚拟路由对象,这是向后兼容所必需的,因为编码器已暴露给用户空间。

第二个对象用于面板,由 struct drm_panel 表示,请参阅 面板帮助器参考。面板没有固定的绑定点,但通常链接到嵌入 struct drm_connector 的驱动程序私有结构。

请注意,目前桥接链和与连接器和面板的交互仍在不断变化,尚未完全理清。

KMS 核心结构和函数

struct drm_mode_config_funcs

基本驱动程序提供的模式设置函数

定义:

struct drm_mode_config_funcs {
    struct drm_framebuffer *(*fb_create)(struct drm_device *dev,struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd);
    const struct drm_format_info *(*get_format_info)(const struct drm_mode_fb_cmd2 *mode_cmd);
    enum drm_mode_status (*mode_valid)(struct drm_device *dev, const struct drm_display_mode *mode);
    int (*atomic_check)(struct drm_device *dev, struct drm_atomic_state *state);
    int (*atomic_commit)(struct drm_device *dev,struct drm_atomic_state *state, bool nonblock);
    struct drm_atomic_state *(*atomic_state_alloc)(struct drm_device *dev);
    void (*atomic_state_clear)(struct drm_atomic_state *state);
    void (*atomic_state_free)(struct drm_atomic_state *state);
};

成员

fb_create

创建一个新的帧缓冲区对象。核心对请求的元数据进行基本检查,但大部分留给驱动程序。有关详细信息,请参阅 struct drm_mode_fb_cmd2

要验证像素格式和修饰符,驱动程序可以使用 drm_any_plane_has_format() 来确保至少有一个平面支持请求的值。请注意,如果请求未指定修饰符,即当 (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) == 0 时,驱动程序必须首先确定实际使用的修饰符。

重要提示:这些用于旧版用户空间的隐含修饰符必须存储在 struct drm_framebuffer 中,包括所有相关元数据,如 drm_framebuffer.pitchesdrm_framebuffer.offsets,如果修饰符启用超出 fourcc 像素格式代码的其他平面。这是 GETFB2 ioctl 所必需的。

如果参数被认为是有效的,并且底层内存管理器中的后备存储对象都存在,那么驱动程序会分配一个新的 drm_framebuffer 结构,该结构被子类化以包含特定于驱动程序的信息(如内部本机缓冲区对象引用)。它还需要填写所有相关元数据,这应该通过调用 drm_helper_mode_fill_fb_struct() 来完成。

初始化通过调用 drm_framebuffer_init() 完成,该函数注册帧缓冲区并使其可供其他线程访问。

返回

具有初始引用计数 1 的新帧缓冲区或使用 ERR_PTR() 编码的负错误代码。

get_format_info

允许驱动程序为特殊的 fb 布局(例如,具有辅助压缩控制平面的布局)返回自定义格式信息。

返回

特定于给定 fb 元数据的格式信息,如果未找到,则返回 NULL。

mode_valid

设备特定显示模式验证。可用于拒绝永远无法支持的模式。此处只能检查设备范围的约束。crtc/encoder/bridge/connector 的特定约束应在每个特定对象的 .mode_valid() 钩子中检查。

atomic_check

这是验证原子模式设置更新的唯一钩子。此函数必须拒绝硬件或驱动程序不支持的任何模式设置和状态更改。这包括但不限于:

  • 检查模式、帧缓冲区、缩放和放置要求等是否在硬件的限制范围内。

  • 检查任何隐藏的共享资源是否未被过度订阅。这可以是共享 PLL、共享通道、总体内存带宽、显示 FIFO 空间(在平面或甚至 CRTC 之间共享)。

  • 检查导出到用户空间的虚拟资源是否未被过度订阅。出于各种原因,暴露比物理上存在的更多平面、crtc 或编码器可能是有意义的。一个示例是双管道操作(如果硬件以锁定方式步进,则通常应隐藏在用户空间中,否则会暴露),其中一个平面可能需要 1 个硬件平面(如果它仅在一个管道上),2 个硬件平面(当它跨越两个管道时)或者甚至与第二个平面共享一个硬件平面(如果另一个管道处理的区域上请求了兼容的平面)。

  • 检查任何过渡状态是否可能,以及如果请求,更新是否确实可以在垂直消隐期内完成,而不会临时禁用某些功能。

  • 检查驱动程序或硬件可能存在的任何其他约束。

  • 此回调还需要正确填充此更新中的 drm_crtc_state,以确保 drm_atomic_crtc_needs_modeset() 反映可能更新的性质,并且当且仅当更新无法在单个垂直消隐期间在 CRTC 上无撕裂地应用时才返回 true。如果用户空间在其请求中禁止了需要完全模式设置(即,使屏幕空白,或至少暂停更新相当长的时间),则核心会使用该信息来拒绝此类更新。

  • 驱动程序也不需要重复执行与相应传统入口点相同的基本输入验证。核心会在调用此钩子之前执行此操作。

有关无需在此回调中检查的错误条件的详尽列表,请参阅 atomic_commit 的文档。

有关原子模式设置更新的确切描述方式,请参阅 struct drm_atomic_state 的文档。

使用原子辅助函数的驱动程序可以使用 drm_atomic_helper_check() 或其导出的子函数之一来实现此钩子。

返回

成功时返回 0,或返回以下负错误代码之一

  • -EINVAL,如果违反了上述任何约束。

  • -EDEADLK,当尝试通过 drm_modeset_lock() 获取额外的 drm_modeset_lock 时返回。

  • -ENOMEM,如果由于内存不足而导致分配额外的状态子结构失败。

  • -EINTR、-EAGAIN 或 -ERESTARTSYS,如果应重新启动 IOCTL。这可能是由于存在挂起的信号,或者由于驱动程序需要完全退出以从诸如 GPU 挂起之类的异常情况中恢复。从用户空间的角度来看,所有错误的处理方式都相同。

atomic_commit

这是提交原子模式设置更新的唯一钩子。核心保证在调用此函数之前已成功调用 atomic_check,并且在此期间没有任何更改。

有关原子模式设置更新的确切描述方式,请参阅 struct drm_atomic_state 的文档。

使用原子辅助函数的驱动程序可以使用 drm_atomic_helper_commit() 或其导出的子函数之一来实现此钩子。

非阻塞提交(如 nonblock 参数所示)必须在此回调的上下文中完成任何可能导致提交失败的准备工作。唯一的例外是导致 -EIO 的硬件错误。但即便如此,驱动程序也必须确保显示管道至少正在运行,以避免在页面翻转不起作用时合成器崩溃。任何其他事情,特别是将更新提交到硬件,都应在不阻塞调用者的情况下完成。对于不需要模式设置的更新,必须保证这一点。

驱动程序必须等待任何对新帧缓冲区的挂起渲染完成,然后才能执行翻转。如果底层缓冲区是共享的 dma-buf,则还应等待来自其他驱动程序的任何挂起渲染。非阻塞提交不得在此回调的上下文中等待渲染。

应用程序可以请求在原子提交完成时收到通知。这些事件是按 CRTC 分组的,可以通过提供给用户空间的 drm_event 中提供的 CRTC 索引来区分。

drm 核心将在每个 CRTC 的 drm_crtc_state.event 中提供 struct drm_event。有关此事件的精确语义的更多详细信息,请参阅 drm_crtc_state.event 的文档。

注意

不允许驱动程序自行关闭通过原子提交成功启用的任何显示管道。这样做会导致合成器崩溃,如果由于管道关闭而突然拒绝页面翻转。

返回

成功时返回 0,或返回以下负错误代码之一

  • -EBUSY,如果请求了非阻塞更新,并且存在较早的挂起更新。允许驱动程序支持未完成更新的队列,但目前没有驱动程序支持此功能。请注意,如果请求同步更新,则驱动程序必须等待先前的更新完成,在这种情况下不允许提交失败。

  • -ENOMEM,如果驱动程序未能分配内存。具体来说,当尝试固定帧缓冲区时可能会发生这种情况,这种情况必须仅在提交状态时完成。

  • -ENOSPC,作为更通用的 -ENOMEM 的细化,指示驱动程序已用完 vram、iommu 空间或类似的 GPU 地址空间(帧缓冲区需要)。

  • -EIO,如果硬件完全失效。

  • -EINTR、-EAGAIN 或 -ERESTARTSYS,如果应重新启动 IOCTL。这可能是由于存在挂起的信号,或者由于驱动程序需要完全退出以从诸如 GPU 挂起之类的异常情况中恢复。从用户空间的角度来看,所有错误的处理方式都相同。

此列表是详尽的。具体来说,不允许此钩子返回 -EINVAL(任何无效请求都应在 atomic_check 中捕获)或 -EDEADLK(此函数不得获取额外的模式设置锁)。

atomic_state_alloc

希望对结构 drm_atomic_state 进行子类化,以便能够轻松跟踪其自己的驱动程序私有全局状态的驱动程序可以使用此可选钩子。如果实现了此钩子,则驱动程序还必须实现 atomic_state_clearatomic_state_free

不建议使用 drm_atomic_state 的子类化,建议使用 drm_private_statedrm_private_obj

返回

成功时返回新的 drm_atomic_state,失败时返回 NULL。

atomic_state_clear

此钩子必须清除重复到传入的 drm_atomic_state 中的任何驱动程序私有状态。当调用方遇到 drm_modeset_lock 死锁,并且需要删除作为 drm_modeset_backoff() 中实现的死锁避免机制的一部分而获取的所有锁时,将调用此钩子。

任何重复的状态都必须失效,因为并发的原子更新可能会更改它,并且 drm 原子接口始终将更新应用为相对于当前状态的更改。

实现此功能的驱动程序必须调用 drm_atomic_state_default_clear() 以清除公共状态。

不建议使用 drm_atomic_state 的子类化,建议使用 drm_private_statedrm_private_obj

atomic_state_free

此钩子需要驱动程序私有资源和 drm_atomic_state 本身。请注意,核心首先调用 drm_atomic_state_clear(),以避免在清除和释放钩子之间重复代码。

实现此功能的驱动程序必须调用 drm_atomic_state_default_release() 以释放公共资源。

不建议使用 drm_atomic_state 的子类化,建议使用 drm_private_statedrm_private_obj

描述

某些涉及驱动程序的全局(即,不是每个 CRTC、连接器等)模式设置功能。

struct drm_mode_config

模式配置控制结构

定义:

struct drm_mode_config {
    struct mutex mutex;
    struct drm_modeset_lock connection_mutex;
    struct drm_modeset_acquire_ctx *acquire_ctx;
    struct mutex idr_mutex;
    struct idr object_idr;
    struct idr tile_idr;
    struct mutex fb_lock;
    int num_fb;
    struct list_head fb_list;
    spinlock_t connector_list_lock;
    int num_connector;
    struct ida connector_ida;
    struct list_head connector_list;
    struct llist_head connector_free_list;
    struct work_struct connector_free_work;
    int num_encoder;
    struct list_head encoder_list;
    int num_total_plane;
    struct list_head plane_list;
    struct raw_spinlock panic_lock;
    int num_crtc;
    struct list_head crtc_list;
    struct list_head property_list;
    struct list_head privobj_list;
    int min_width, min_height;
    int max_width, max_height;
    const struct drm_mode_config_funcs *funcs;
    bool poll_enabled;
    bool poll_running;
    bool delayed_event;
    struct delayed_work output_poll_work;
    struct mutex blob_lock;
    struct list_head property_blob_list;
    struct drm_property *edid_property;
    struct drm_property *dpms_property;
    struct drm_property *path_property;
    struct drm_property *tile_property;
    struct drm_property *link_status_property;
    struct drm_property *plane_type_property;
    struct drm_property *prop_src_x;
    struct drm_property *prop_src_y;
    struct drm_property *prop_src_w;
    struct drm_property *prop_src_h;
    struct drm_property *prop_crtc_x;
    struct drm_property *prop_crtc_y;
    struct drm_property *prop_crtc_w;
    struct drm_property *prop_crtc_h;
    struct drm_property *prop_fb_id;
    struct drm_property *prop_in_fence_fd;
    struct drm_property *prop_out_fence_ptr;
    struct drm_property *prop_crtc_id;
    struct drm_property *prop_fb_damage_clips;
    struct drm_property *prop_active;
    struct drm_property *prop_mode_id;
    struct drm_property *prop_vrr_enabled;
    struct drm_property *dvi_i_subconnector_property;
    struct drm_property *dvi_i_select_subconnector_property;
    struct drm_property *dp_subconnector_property;
    struct drm_property *tv_subconnector_property;
    struct drm_property *tv_select_subconnector_property;
    struct drm_property *legacy_tv_mode_property;
    struct drm_property *tv_mode_property;
    struct drm_property *tv_left_margin_property;
    struct drm_property *tv_right_margin_property;
    struct drm_property *tv_top_margin_property;
    struct drm_property *tv_bottom_margin_property;
    struct drm_property *tv_brightness_property;
    struct drm_property *tv_contrast_property;
    struct drm_property *tv_flicker_reduction_property;
    struct drm_property *tv_overscan_property;
    struct drm_property *tv_saturation_property;
    struct drm_property *tv_hue_property;
    struct drm_property *scaling_mode_property;
    struct drm_property *aspect_ratio_property;
    struct drm_property *content_type_property;
    struct drm_property *degamma_lut_property;
    struct drm_property *degamma_lut_size_property;
    struct drm_property *ctm_property;
    struct drm_property *gamma_lut_property;
    struct drm_property *gamma_lut_size_property;
    struct drm_property *suggested_x_property;
    struct drm_property *suggested_y_property;
    struct drm_property *non_desktop_property;
    struct drm_property *panel_orientation_property;
    struct drm_property *writeback_fb_id_property;
    struct drm_property *writeback_pixel_formats_property;
    struct drm_property *writeback_out_fence_ptr_property;
    struct drm_property *hdr_output_metadata_property;
    struct drm_property *content_protection_property;
    struct drm_property *hdcp_content_type_property;
    uint32_t preferred_depth, prefer_shadow;
    bool quirk_addfb_prefer_xbgr_30bpp;
    bool quirk_addfb_prefer_host_byte_order;
    bool async_page_flip;
    bool fb_modifiers_not_supported;
    bool normalize_zpos;
    struct drm_property *modifiers_property;
    struct drm_property *size_hints_property;
    uint32_t cursor_width, cursor_height;
    struct drm_atomic_state *suspend_state;
    const struct drm_mode_config_helper_funcs *helper_private;
};

成员

mutex

这是一个巨大的可怕模式设置 BKL,它可以保护所有未受其他保护的事物。范围不明确且模糊,请尝试从其保护下删除任何内容,并将其移动到范围更明确的锁中。

它保护的一个重要事项是 acquire_ctx 的使用。

connection_mutex

这可以保护连接器状态以及连接器到编码器到 CRTC 的路由链。

对于原子驱动程序,这可以特别保护 drm_connector.state

acquire_ctx

原子驱动程序用于传统 IOCTL 的全局隐式获取上下文。已弃用,因为隐式锁定上下文使得不可能使用驱动程序私有的 struct drm_modeset_lock。此项的使用者必须持有 mutex

idr_mutex

用于 KMS ID 分配和管理的互斥锁。可以同时保护 object_idrtile_idr

object_idr

主要的 KMS ID 跟踪对象。将此 idr 用于所有 ID、fb、crtc、连接器、模式 - 仅使用一个就可以更轻松地生活。

tile_idr

使用此 idr 为诸如某些高分辨率 DP MST 屏幕中使用的平铺接收器分配新 ID。

fb_lock

用于保护 fb 全局 fb_listnum_fb 的互斥锁。

num_fb

fb_list 上的条目数。

fb_list

所有 struct drm_framebuffer 的列表。

connector_list_lock

保护 num_connectorconnector_list 以及 connector_free_list

num_connector

此设备上的连接器数。受 connector_list_lock 保护。

connector_ida

用于连接器索引的 ID 分配器。

connector_list

drm_connector.head链接的连接器对象列表。受 connector_list_lock 保护。只能使用drm_for_each_connector_iter()struct drm_connector_list_iter 来遍历此列表。

connector_free_list

drm_connector.free_head链接的连接器对象列表。受 connector_list_lock 保护。 drm_for_each_connector_iter()struct drm_connector_list_iter 使用此列表来安全地使用 connector_free_work 释放连接器。

connector_free_work

清理 connector_free_list 的工作。

num_encoder

此设备上的编码器数量。这在设备的生命周期内是不变的,因此不需要任何锁。

encoder_list

drm_encoder.head链接的编码器对象列表。这在设备的生命周期内是不变的,因此不需要任何锁。

num_total_plane

此设备上的通用(即带有主/光标)平面数量。这在设备的生命周期内是不变的,因此不需要任何锁。

plane_list

drm_plane.head链接的平面对象列表。这在设备的生命周期内是不变的,因此不需要任何锁。

panic_lock

原始自旋锁,用于保护访问显示硬件或模式设置软件状态的关键代码段,必须防止 panic 打印代码访问这些代码段。请参阅drm_panic_trylock()drm_panic_lock()drm_panic_unlock()

num_crtc

此设备上与drm_crtc.head链接的 CRTC 数量。这在设备的生命周期内是不变的,因此不需要任何锁。

crtc_list

drm_crtc.head链接的 CRTC 对象列表。这在设备的生命周期内是不变的,因此不需要任何锁。

property_list

drm_property.head链接的属性类型对象列表。这在设备的生命周期内是不变的,因此不需要任何锁。

privobj_list

drm_private_obj.head链接的私有对象列表。这在设备的生命周期内是不变的,因此不需要任何锁。

min_width

此设备上的最小帧缓冲像素宽度

min_height

此设备上的最小帧缓冲像素高度

max_width

此设备上的最大帧缓冲像素宽度

max_height

此设备上的最大帧缓冲像素高度

funcs

核心驱动程序提供的模式设置函数

poll_enabled

跟踪此设备的轮询支持

poll_running

跟踪此设备的轮询状态

delayed_event

跟踪此设备的延迟轮询 uevent 传递

output_poll_work

用于在进程上下文中进行轮询的延迟工作

blob_lock

用于 blob 属性分配和管理的互斥锁,保护 property_blob_listdrm_file.blobs

property_blob_list

drm_property_blob.head链接的所有 blob 属性对象的列表。受 blob_lock 保护。

edid_property

默认的连接器属性,用于保存当前连接的接收器的 EDID(如果有)。

dpms_property

默认的连接器属性,用于控制连接器的 DPMS 状态。

path_property

默认的连接器属性,用于保存端口的 DP MST 路径。

tile_property

默认的连接器属性,用于存储平铺屏幕的平铺位置,用于需要多个 CRTC 驱动的接收器。

link_status_property

连接器链路状态的默认连接器属性

plane_type_property

默认的平面属性,用于区分平面 CURSOR、PRIMARY 和 OVERLAY 的旧用法。

prop_src_x

默认的原子平面属性,用于表示连接的 drm_framebuffer 中的平面源位置。

prop_src_y

默认的原子平面属性,用于表示连接的 drm_framebuffer 中的平面源位置。

prop_src_w

默认的原子平面属性,用于表示连接的 drm_framebuffer 中的平面源位置。

prop_src_h

默认的原子平面属性,用于表示连接的 drm_framebuffer 中的平面源位置。

prop_crtc_x

默认的原子平面属性,用于表示要在其上显示的 drm_crtc 中的平面目标位置。

prop_crtc_y

默认的原子平面属性,用于表示要在其上显示的 drm_crtc 中的平面目标位置。

prop_crtc_w

默认的原子平面属性,用于表示要在其上显示的 drm_crtc 中的平面目标位置。

prop_crtc_h

默认的原子平面属性,用于表示要在其上显示的 drm_crtc 中的平面目标位置。

prop_fb_id

默认的原子平面属性,用于指定 drm_framebuffer

prop_in_fence_fd

表示平面传入栅栏的同步文件 fd。

prop_out_fence_ptr

表示 CRTC 传出栅栏的同步文件 fd 指针。用户空间应提供指向 s32 类型的值的指针,然后将该指针强制转换为 u64。

prop_crtc_id

默认的原子平面属性,用于指定 drm_crtc

prop_fb_damage_clips

可选的平面属性,用于标记附加到平面的帧缓冲区的帧缓冲区坐标中平面上的损坏区域。

blob 数据的布局只是一个 drm_mode_rect 的数组。与平面源坐标不同,损坏剪辑不是 16.16 定点格式。

prop_active

默认的原子 CRTC 属性,用于控制活动状态,这是原子驱动程序中 DPMS 的简化实现。

prop_mode_id

默认的原子 CRTC 属性,用于设置 CRTC 的模式。模式为 0 表示 CRTC 完全禁用 - 所有连接器都必须关闭,并且 active 也必须设置为禁用。

prop_vrr_enabled

默认的原子 CRTC 属性,用于指示是否应在 CRTC 上启用可变刷新率。

dvi_i_subconnector_property

可选的 DVI-I 属性,用于区分模拟模式或数字模式。

dvi_i_select_subconnector_property

可选的 DVI-I 属性,用于在模拟模式或数字模式之间选择。

dp_subconnector_property

可选的 DP 属性,用于区分不同的 DP 下游端口类型。

tv_subconnector_property

可选的 TV 属性,用于区分不同的 TV 连接器类型。

tv_select_subconnector_property

可选的 TV 属性,用于在不同的 TV 连接器类型之间选择。

legacy_tv_mode_property

可选的 TV 属性,用于选择输出 TV 模式。

已由 tv_mode_property 取代

tv_mode_property

可选的 TV 属性,用于选择连接器上的 TV 标准输出。

tv_left_margin_property

可选的 TV 属性,用于设置左边距(以像素表示)。

tv_right_margin_property

可选的 TV 属性,用于设置右边距(以像素表示)。

tv_top_margin_property

可选的 TV 属性,用于设置右边距(以像素表示)。

tv_bottom_margin_property

可选的 TV 属性,用于设置右边距(以像素表示)。

tv_brightness_property

可选的 TV 属性,用于设置亮度。

tv_contrast_property

可选的 TV 属性,用于设置对比度。

tv_flicker_reduction_property

可选的 TV 属性,用于控制闪烁减少模式。

tv_overscan_property

可选的 TV 属性,用于控制过扫描设置。

tv_saturation_property

可选的 TV 属性,用于设置饱和度。

tv_hue_property

可选的 TV 属性,用于设置色调。

scaling_mode_property

可选的连接器属性,用于控制放大,主要用于内置面板。

aspect_ratio_property

可选的连接器属性,用于控制 HDMI 信息帧宽高比设置。

content_type_property

可选的连接器属性,用于控制 HDMI 信息帧内容类型设置。

degamma_lut_property

可选的 CRTC 属性,用于设置将帧缓冲区的颜色转换为线性伽马的 LUT。

degamma_lut_size_property

可选的 CRTC 属性,用于表示驱动程序支持的去伽玛 LUT 的大小(只读)。

ctm_property

可选的 CRTC 属性,用于设置在去伽玛 LUT 中查找后用于转换颜色的矩阵。

gamma_lut_property

可选的 CRTC 属性,用于设置在 CTM 矩阵之后将颜色转换为连接的屏幕的伽马空间的 LUT。

gamma_lut_size_property

可选的 CRTC 属性,用于表示驱动程序支持的伽玛 LUT 的大小(只读)。

suggested_x_property

可选的连接器属性,其中包含有关输出在主机屏幕上的位置的提示。

suggested_y_property

可选的连接器属性,其中包含有关输出在主机屏幕上的位置的提示。

non_desktop_property

可选的连接器属性,其中包含有关设备不是标准显示器的提示,并且控制台/桌面不应在其上显示。

panel_orientation_property

可选的连接器属性,指示 LCD 面板在机壳内的安装方式(例如,正常或倒置)。

writeback_fb_id_property

用于回写连接器的属性,用于存储输出帧缓冲区的 ID。另请参阅:drm_writeback_connector_init()

writeback_pixel_formats_property

用于回写连接器的属性,用于存储回写引擎支持的像素格式数组(只读)。另请参阅:drm_writeback_connector_init()

writeback_out_fence_ptr_property

用于回写连接器的属性,fd 指针表示回写连接器的传出栅栏。用户空间应提供指向 s32 类型的值的指针,然后将该指针强制转换为 u64。另请参阅:drm_writeback_connector_init()

hdr_output_metadata_property

包含 hdr 元数据的连接器属性。这将由用户空间合成器基于 HDR 内容提供

content_protection_property

用于内容保护的 DRM ENUM 属性。请参阅drm_connector_attach_content_protection_property()

hdcp_content_type_property

用于受保护内容的类型的 DRM 枚举属性。

preferred_depth

首选的 RGB 像素深度,供 fb 辅助函数使用

prefer_shadow

提示用户空间首选使用 shadow-fb 渲染

quirk_addfb_prefer_xbgr_30bpp

为保持旧版 ADDFB 与 nouveau 用户空间兼容而进行的特殊 hack。 仅应由 nouveau 内核驱动程序设置。

quirk_addfb_prefer_host_byte_order

如果设置为 true,则 drm_mode_addfb() 在调用 drm_mode_addfb2() 时会选择主机字节序像素格式。这本应是 drm_mode_addfb() 的工作方式。但实际上并非如此,所以我们最终在内核和用户空间驱动程序中都使用了 quirk 来处理这种错误行为。简单地无条件修复 drm_mode_addfb() 会破坏这些驱动程序,因此在此处添加一个 quirk 位以允许驱动程序选择加入。

async_page_flip

此设备是否支持主平面上的异步翻转?

fb_modifiers_not_supported

设置此标志后,DRM 设备不会向用户空间公开修改器支持。这仅由通过启发式方法推断缓冲区布局而不使用修改器的旧版驱动程序使用。新驱动程序不应设置此标志。

normalize_zpos

如果为 true,drm 核心将从 drm_atomic_helper_check() 中调用 drm_atomic_normalize_zpos() 作为原子模式检查的一部分

modifiers_property

用于列出支持的修改器/格式组合的平面属性。

size_hints_property

平面 SIZE_HINTS 属性。

cursor_width

向用户空间提示最大光标宽度

cursor_height

向用户空间提示最大光标高度

suspend_state

挂起时的原子状态。由 drm_mode_config_helper_suspend() 设置,并由 drm_mode_config_helper_resume() 清除。

helper_private

中间层私有数据

描述

核心模式资源跟踪结构。驱动程序枚举的所有 CRTC、编码器和连接器都将添加到此处,全局属性也是如此。一些全局限制也在此处,例如维度限制。

帧缓冲区大小是指 CRTC 可以显示的虚拟屏幕。这可能与编程的物理分辨率不同。存储在 **min_width** 和 **min_height** 中的最小宽度和高度描述了帧缓冲区的最小大小。它与最小可编程分辨率相关。存储在 **max_width** 中的最大宽度通常受两个相邻扫描线之间的最大间距限制。存储在 **max_height** 中的最大高度通常仅受可寻址视频内存量的限制。对于没有实际最大值的硬件,驱动程序应选择合理的默认值。

另请参阅 **DRM_SHADOW_PLANE_MAX_WIDTH** 和 **DRM_SHADOW_PLANE_MAX_HEIGHT**。

int drm_mode_config_init(struct drm_device *dev)

DRM mode_configuration 结构初始化

参数

struct drm_device *dev

DRM 设备

描述

这是 drmm_mode_config_init() 的非托管版本,适用于仍显式调用 drm_mode_config_cleanup() 的驱动程序。

FIXME:此函数已弃用,应将驱动程序转换为使用 drmm_mode_config_init()

void drm_mode_config_reset(struct drm_device *dev)

调用 ->reset 回调

参数

struct drm_device *dev

drm 设备

描述

此函数调用所有 crtc、编码器和连接器的 ->reset 回调。驱动程序可以在其驱动程序加载或恢复代码中使用它来重置硬件和软件状态。

int drmm_mode_config_init(struct drm_device *dev)

托管的 DRM mode_configuration 结构初始化

参数

struct drm_device *dev

DRM 设备

描述

初始化 **dev** 的 mode_config 结构,用于跟踪 **dev** 的图形配置。

由于此操作会初始化模式设置锁,因此无法进行锁定。这没有问题,因为这应该在初始化时以单线程方式进行。确保此保证是驱动程序的问题。

清理工作通过使用 drmm_add_action() 注册 drm_mode_config_cleanup 来自动处理。

返回

成功时返回 0,失败时返回负错误值。

void drm_mode_config_cleanup(struct drm_device *dev)

释放 DRM mode_config 信息

参数

struct drm_device *dev

DRM 设备

描述

释放与此 DRM 设备关联的所有连接器和 CRTC,然后释放帧缓冲区和关联的缓冲区对象。

请注意,由于此操作应该在驱动程序/设备拆卸时以单线程方式进行,因此不需要锁定。确保此保证实际成立是驱动程序的工作。

FIXME:使用托管的 drmm_mode_config_init() 后,驱动程序不再需要显式调用此函数。

模式设置基本对象抽象

Mode Objects and Properties

模式对象和属性

所有 KMS 对象的基本结构是 struct drm_mode_object。它提供的基本服务之一是跟踪属性,这对于原子 IOCTL 非常重要(请参阅原子模式设置)。这里有点令人惊讶的是,属性不是直接在每个对象上实例化的,而是独立的模式对象本身,由 struct drm_property 表示,它仅指定属性的类型和值范围。可以使用 drm_object_attach_property() 将任何给定属性多次附加到不同的对象。

struct drm_mode_object

模式设置对象的基本结构

定义:

struct drm_mode_object {
    uint32_t id;
    uint32_t type;
    struct drm_object_properties *properties;
    struct kref refcount;
    void (*free_cb)(struct kref *kref);
};

成员

id

用户空间可见标识符

type

对象的类型,为 DRM_MODE_OBJECT_* 之一

properties

附加到此对象的属性,包括值

refcount

具有动态生命周期的对象的引用计数

free_cb

释放函数回调,仅为具有动态生命周期的对象设置

描述

用户空间可见的模式设置对象的基本结构。可以使用 drm_mode_object_find() 查找对象。除了诸如 **id** 和 **type** 之类的基本 uapi 接口属性之外,它还提供两项服务

struct drm_object_properties

用于 drm_mode_object 的属性跟踪

定义:

struct drm_object_properties {
    int count;
    struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY];
    uint64_t values[DRM_OBJECT_MAX_PROPERTY];
};

成员

count

有效属性的数量,必须小于或等于 DRM_OBJECT_MAX_PROPERTY。

properties

指向 drm_property 的指针数组。

注意:如果我们开始动态销毁属性(即不在 drm_mode_config_cleanup() 时),那么我们将不得不更好地将属性从模式对象中分离出来,以避免悬空属性指针

values

用于存储属性值的数组,与 **properties** 匹配。请勿直接读取/写入值,而应使用 drm_object_property_get_value()drm_object_property_set_value()

请注意,原子驱动程序不会在此数组中存储可变属性,而只会存储相应状态结构中的解码值。解码是使用 drm_crtc.atomic_get_propertydrm_crtc.atomic_set_property hook 来完成的,用于 struct drm_crtc。对于 struct drm_plane,hook 是 drm_plane_funcs.atomic_get_propertydrm_plane_funcs.atomic_set_property。对于 struct drm_connector,hook 是 drm_connector_funcs.atomic_get_propertydrm_connector_funcs.atomic_set_property

因此,原子驱动程序不应在可变对象上使用 drm_object_property_set_value()drm_object_property_get_value(),即可变对象是指未设置 DRM_MODE_PROP_IMMUTABLE 标志的对象。

对于原子驱动程序,属性的默认值存储在此数组中,因此可以使用 drm_object_property_get_default_value 来检索它。

struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, struct drm_file *file_priv, uint32_t id, uint32_t type)

查找具有静态生存期的 drm 对象

参数

struct drm_device *dev

drm 设备

struct drm_file *file_priv

drm 文件

uint32_t id

模式对象的 ID

uint32_t type

模式对象的类型

描述

此函数用于查找模式设置对象。它将获取引用计数对象的引用。此引用必须通过调用 drm_mode_object_put() 再次删除。

void drm_mode_object_put(struct drm_mode_object *obj)

释放模式对象引用

参数

struct drm_mode_object *obj

DRM 模式对象

描述

如果对象是引用计数的模式设置对象,则此函数将递减对象的引用计数。它对任何其他对象都是空操作。这用于删除通过 drm_mode_object_get() 获取的引用。

void drm_mode_object_get(struct drm_mode_object *obj)

获取模式对象引用

参数

struct drm_mode_object *obj

DRM 模式对象

描述

如果对象是引用计数的模式设置对象,则此函数将递增对象的引用计数。它对任何其他对象都是空操作。应通过调用 drm_mode_object_put() 再次删除引用。

void drm_object_attach_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t init_val)

将属性附加到模式设置对象

参数

struct drm_mode_object *obj

drm 模式设置对象

struct drm_property *property

要附加的属性

uint64_t init_val

属性的初始值

描述

这会将给定的属性与给定的初始值附加到模式设置对象。目前,此函数不会失败,因为属性存储在静态大小的数组中。

请注意,所有属性必须在对象本身注册并可从用户空间访问之前附加。

int drm_object_property_set_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t val)

设置属性的值

参数

struct drm_mode_object *obj

要为其设置属性值的 drm 模式对象

struct drm_property *property

要设置的属性

uint64_t val

应将属性设置为的值

描述

此函数在给定对象上设置给定的属性。此函数仅更改属性的软件状态,它不会调用驱动程序的 ->set_property 回调。

请注意,原子驱动程序不应需要调用此函数,核心将通过适当的 ->atomic_get_property 回调确保报告给用户空间的值的一致性。只有旧版驱动程序才应调用此函数来更新跟踪值(在应用钳位和其他限制之后)。

返回

成功时为零,失败时为错误代码。

int drm_object_property_get_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val)

检索属性的值

参数

struct drm_mode_object *obj

要从中获取属性值的 drm 模式对象

struct drm_property *property

要检索的属性

uint64_t *val

属性值的存储

描述

此函数检索给定属性的软件状态。由于没有驱动程序回调来检索当前属性值,因此根据驱动程序和属性,这可能与硬件不同步。

原子驱动程序永远不应直接调用此函数,核心将通过各种 ->atomic_get_property 回调读取属性值。

返回

成功时为零,失败时为错误代码。

int drm_object_property_get_default_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val)

检索原子模式下属性的默认值。

参数

struct drm_mode_object *obj

要从中获取属性值的 drm 模式对象

struct drm_property *property

要检索的属性

uint64_t *val

属性值的存储

描述

此函数检索传递给 drm_object_attach_property 的给定属性的默认状态

只有原子驱动程序才应直接调用此函数,因为对于非原子驱动程序,它将返回当前值。

返回

成功时为零,失败时为错误代码。

原子模式设置

Mode Objects and Properties

模式对象和属性

原子提供了事务性的模式设置(包括平面)更新,但与通常的尝试提交和回滚的事务方法略有不同

  • 首先,当提交失败时,不允许进行任何硬件更改。这使我们可以实现 DRM_MODE_ATOMIC_TEST_ONLY 模式,该模式允许用户空间探索某些配置是否有效。

  • 这仍然允许只设置和回滚软件状态,从而简化现有驱动程序的转换。但是,要审计驱动程序中 atomic_check 代码的正确性就变得非常困难:回滚遍布各处的数据结构中的更改很难做到正确。

  • 最后,为了向后兼容并支持所有用例,原子更新需要是增量的并且能够并行执行。硬件并不总是允许这样做,但在可能的情况下,不同 CRTC 上的平面更新不应相互干扰,并且不会因为不同 CRTC 上输出路由的更改而停滞。

总而言之,原子设计有两个结果

  • 整体状态被拆分为每个对象的状态结构:平面的 struct drm_plane_state、CRTC 的 struct drm_crtc_state 和连接器的 struct drm_connector_state。这些是唯一具有用户可见和可设置状态的对象。对于内部状态,驱动程序可以通过嵌入来子类化这些结构,或者为其全局共享的硬件功能添加全新的状态结构,请参阅 struct drm_private_state

  • 原子更新在 drm_atomic_state 容器中组装和验证为一个完全独立的结构堆。驱动程序私有状态结构也在此结构中进行跟踪;请参阅下一章。仅当提交状态时,它才应用于驱动程序和模式设置对象。这样,回滚更新就归结为释放内存和取消引用帧缓冲区等对象。

原子状态结构的锁定在内部使用 struct drm_modeset_lock。通常,锁定不应暴露给驱动程序,相反,任何复制或窥视状态的函数(如 drm_atomic_get_crtc_state())应自动获取正确的锁。锁定仅保护软件数据结构,将状态更改提交到硬件的顺序是使用 struct drm_crtc_commit 来排序的。

请继续阅读本章,并在原子模式设置辅助函数参考中阅读有关特定主题的更详细信息。

处理驱动程序私有状态

通常,在原子模式设置 API 中暴露给用户空间的 DRM 对象(drm_connectordrm_crtcdrm_plane)并不能完全映射到底层硬件。特别是对于任何类型的共享资源(例如,在多个平面或 CRTC 组之间共享的共享时钟、缩放器单元、带宽和 FIFO 限制等),将这些建模为独立对象是有意义的。然后,驱动程序需要为这些私有对象(因为不暴露给用户空间)执行类似的状态跟踪和提交排序,就像原子核心和辅助函数已经为连接器、平面和 CRTC 提供的那样。

为了使驱动程序更容易,原子核心提供了一些支持,以使用结构 drm_private_obj 跟踪驱动程序私有状态对象,以及关联的状态结构 drm_private_state

与用户空间暴露的对象类似,可以通过调用 drm_atomic_get_private_obj_state() 来获取私有状态结构。这也会处理锁定,因此驱动程序不应需要直接调用 drm_modeset_lock()。实际硬件状态提交的顺序未处理,驱动程序可能需要在 drm_private_state 的子类化结构中跟踪 struct drm_crtc_commit,例如类似于 drm_plane_state.commit。另请参阅 drm_atomic_state.fake_commit

可以使用 for_each_oldnew_private_obj_in_state()for_each_new_private_obj_in_state()for_each_old_private_obj_in_state() 迭代 drm_atomic_state 更新中包含的所有私有状态结构。建议驱动程序为他们拥有的每种驱动程序私有状态对象包装这些迭代器,使用 for_each_if()drm_private_obj.funcs 上进行筛选,至少在它们想要迭代给定类型的所有对象时是这样。

处理驱动程序私有状态的早期方法是通过子类化结构 drm_atomic_state。但是,由于这鼓励了实现检查/提交拆分原子操作的非标准方法(例如,使用“检查和回滚或提交”而不是“复制状态,检查,然后提交或释放复制的状态”),因此不建议使用它,而建议使用 drm_private_state

原子模式设置函数参考

struct drm_crtc_commit

跟踪 CRTC 上的模式设置提交

定义:

struct drm_crtc_commit {
    struct drm_crtc *crtc;
    struct kref ref;
    struct completion flip_done;
    struct completion hw_done;
    struct completion cleanup_done;
    struct list_head commit_entry;
    struct drm_pending_vblank_event *event;
    bool abort_completion;
};

成员

crtc

此提交的 DRM CRTC。

ref

此结构的引用计数。需要它才能允许在完成时阻塞,而不会有完成同时消失的风险。

flip_done

当硬件翻转到新的缓冲区集时将发出信号。与此提交的 drm 事件发送到用户空间或发出 out-fence 信号时同时发出信号。请注意,对于大多数硬件,在大多数情况下,这发生在发出 hw_done 信号之后。

通过在 drm_crtc_state.event 上调用 drm_crtc_send_vblank_event() 来隐式地发出此阶段的完成信号。

hw_done

当此提交的所有硬件寄存器更改都已写入时将发出信号。特别是当禁用管道时,这可能会比 flip_done 晚得多,因为当屏幕变黑时它可能已经发出信号,而要完全关闭管道则需要更多的寄存器 I/O。

请注意,这不需要包括单独引用计数的资源,如后备存储缓冲区固定或运行时电源管理。

驱动程序应调用 drm_atomic_helper_commit_hw_done() 来发出此阶段完成的信号。

cleanup_done

在调用 drm_atomic_helper_cleanup_planes() 清理旧缓冲区后将发出信号。由于这只能在垂直消隐等待完成后发生,因此可能会晚一些。此完成对于限制更新并避免硬件更新过多地领先于缓冲区清理非常有用。

驱动程序应调用 drm_atomic_helper_commit_cleanup_done() 来发出此阶段完成的信号。

commit_entry

每个 CRTC 的 drm_crtc.commit_list 上的条目。受 $drm_crtc.commit_lock 保护。

event

drm_pending_vblank_event 指针,用于清理私有事件。

abort_completion

drm_atomic_helper_setup_commit() 为 $drm_crtc_state.event 的完成获取第二个引用后设置的标志。它被释放代码用来在提交失败时删除第二个引用。

描述

此结构用于跟踪每个 CRTC 上挂起的模式设置更改和原子提交。由于更新列表永远不应阻塞,因此此结构是引用计数的,以允许等待者安全地等待事件完成,而无需持有任何锁。

它总共有 3 个不同的事件,以允许在未完成的更新之间进行细粒度的同步

atomic commit thread                    hardware

write new state into hardware   ---->   ...
signal hw_done
                                        switch to new state on next
...                                     v/hblank

wait for buffers to show up             ...

...                                     send completion irq
                                        irq handler signals flip_done
cleanup old buffers

signal cleanup_done

wait for flip_done              <----
clean up atomic state

需要知道的重要一点是 cleanup_done 是终端事件,但 flip_donehw_done 之间的顺序完全取决于特定的驱动程序和模式设置状态更改。

有关如何使用此的实现,请查看原子辅助库中的 drm_atomic_helper_setup_commit()

另请参阅 drm_crtc_commit_wait()

struct drm_private_state_funcs

私有对象的原子状态函数

定义:

struct drm_private_state_funcs {
    struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj);
    void (*atomic_destroy_state)(struct drm_private_obj *obj, struct drm_private_state *state);
    void (*atomic_print_state)(struct drm_printer *p, const struct drm_private_state *state);
};

成员

atomic_duplicate_state

复制私有对象的当前状态并返回它。在 obj->state 初始化之前调用此函数是错误的。

返回

当 obj->state 未初始化或分配失败时,复制的原子状态或 NULL。

atomic_destroy_state

释放使用 atomic_duplicate_state 创建的私有对象状态。

atomic_print_state

如果驱动程序子类化 struct drm_private_state,则应实现此可选钩子以打印其他特定于驱动程序的状态。

不要直接调用此函数,请改用 drm_atomic_private_obj_print_state()。

描述

这些钩子由原子助手用来创建、交换和销毁私有对象的状态。该结构本身用作 vtable 来标识关联的私有对象类型。每个需要添加到原子状态的私有对象类型都应实现这些钩子,并将指向其 drm_private_state_funcs 结构的指针传递给 drm_atomic_get_private_obj_state()

struct drm_private_obj

驱动程序私有原子对象的基础结构

定义:

struct drm_private_obj {
    struct list_head head;
    struct drm_modeset_lock lock;
    struct drm_private_state *state;
    const struct drm_private_state_funcs *funcs;
};

成员

head

用于将私有对象附加到 drm_device 的列表条目(排队到 drm_mode_config.privobj_list)。

lock

用于保护状态对象的模式设置锁。

state

此驱动程序私有对象的当前原子状态。

funcs

用于操作此驱动程序私有对象状态的函数,请参阅 drm_private_state_funcs

描述

通过调用 drm_atomic_private_obj_init() 初始化驱动程序私有对象,并通过调用 drm_atomic_private_obj_fini() 清理驱动程序私有对象。

目前仅跟踪状态更新函数和不透明的驱动程序私有状态本身,但将来也可能跟踪需要哪个 drm_modeset_lock 来复制和更新此对象的状态。

所有私有对象都必须在它们附加到的 DRM 设备注册到 DRM 子系统之前进行初始化(调用 drm_dev_register()),并且应在注销此 DRM 设备之前一直存在(调用 drm_dev_unregister())。换句话说,私有对象的生命周期与 DRM 设备的生命周期相关。这意味着

1/ 对 drm_atomic_private_obj_init() 的所有调用都必须在调用之前完成

drm_dev_register()

2/ 对 drm_atomic_private_obj_fini() 的所有调用都必须在调用之后完成

drm_dev_unregister()

如果该私有对象用于存储多个 CRTC 共享的状态,则必须适当注意确保非阻塞提交正确排序,以避免发生释放后使用问题。

实际上,假设在两个不同的 drm_crtc 上使用不同的 drm_planedrm_connector 进行两次非阻塞 drm_atomic_commit 的序列,因此在没有共享资源的情况下,无法保证哪个提交将首先发生。但是,第二个 drm_atomic_commit 会将第一个 drm_private_obj 视为其旧状态,并将负责在第二个 drm_atomic_commit 完成时释放它。

如果第一个 drm_atomic_commit 在其之后发生,则会将其 drm_private_obj 视为新状态,并且可能会访问它,从而导致访问已释放的内存区域。驱动程序应在 drm_mode_config_helper_funcs.atomic_commit_setup 中将其 drm_crtc_commit 结构存储(并获取对它的引用)到我们的私有状态中,然后在 drm_mode_config_helper_funcs.atomic_commit_tail 的第一步中等待该提交完成,类似于 drm_atomic_helper_wait_for_dependencies()

drm_for_each_privobj

drm_for_each_privobj (privobj, dev)

私有对象迭代器

参数

privobj

指向当前私有对象的指针。每次迭代后更新

dev

我们要从中获取私有对象的 DRM 设备

描述

允许您迭代附加到 dev 的所有私有对象

struct drm_private_state

驱动程序私有对象状态的基础结构

定义:

struct drm_private_state {
    struct drm_atomic_state *state;
    struct drm_private_obj *obj;
};

成员

state

指向全局 drm_atomic_state 的后向指针

obj

指向私有对象的后向指针

描述

当前仅包含指向总体原子更新的后向指针和相关的私有对象,但将来也可能包含类似于 drm_crtc.commit 的同步信息。

struct drm_atomic_state

原子提交结构

定义:

struct drm_atomic_state {
    struct kref ref;
    struct drm_device *dev;
    bool allow_modeset : 1;
    bool legacy_cursor_update : 1;
    bool async_update : 1;
    bool duplicated : 1;
    struct __drm_planes_state *planes;
    struct __drm_crtcs_state *crtcs;
    int num_connector;
    struct __drm_connnectors_state *connectors;
    int num_private_objs;
    struct __drm_private_objs_state *private_objs;
    struct drm_modeset_acquire_ctx *acquire_ctx;
    struct drm_crtc_commit *fake_commit;
    struct work_struct commit_work;
};

成员

ref

对此更新的所有引用的计数(在计数为零之前不会释放)。

dev

父 DRM 设备。

allow_modeset

允许完全模式设置。ATOMIC IOCTL 处理程序使用此标志来实现 DRM_MODE_ATOMIC_ALLOW_MODESET 标志。驱动程序永远不应查阅此标志,而应查看 drm_atomic_crtc_needs_modeset() 的输出。

legacy_cursor_update

强制执行旧式光标 IOCTL 语义的提示。

警告:这完全损坏,并且几乎不可能正确实现。驱动程序必须忽略此项,而应实现 drm_plane_helper_funcs.atomic_async_checkdrm_plane_helper_funcs.atomic_async_commit 钩子。不允许此标志的新用户。

async_update

异步平面更新的提示

duplicated

指示此原子状态是否使用 drm_atomic_helper_duplicate_state() 复制。驱动程序和原子助手应使用它来修复复制状态中的正常不一致之处。

planes

指向此更新的 drm_planedrm_plane_state 数组的指针。

crtcs

指向此更新的 drm_crtcdrm_crtc_state 数组的指针。

num_connector

connectors 数组的大小

connectors

指向此更新的 drm_connectordrm_connector_state 数组的指针。

num_private_objs

private_objs 数组的大小

private_objs

指向此更新的 drm_private_objdrm_private_obj_state 数组的指针。

acquire_ctx

此原子模式设置状态更新的获取上下文

fake_commit

用于发出未绑定平面/连接器的信号。当连接器或平面未绑定到任何 CRTC 时,仍然需要保持线性,以防止过早释放原子状态。

如果设置了此提交,则此提交未绑定到任何 CRTC,但当调用 drm_atomic_helper_commit_hw_done() 时,将完成该提交。

commit_work

驱动程序或助手可以用来执行提交而不阻塞的工作项。

描述

此结构是 drm_mode_atomic 的内核对应项,表示从旧显示状态转换为新显示状态的原子提交。它包含受原子提交影响的所有对象,以及这些对象的新状态结构和指向旧状态结构的指针。

通过调用 drm_atomic_get_crtc_state()drm_atomic_get_plane_state()drm_atomic_get_connector_state() 或对于私有状态结构,drm_atomic_get_private_obj_state() 将状态添加到原子更新中。

struct drm_crtc_commit *drm_crtc_commit_get(struct drm_crtc_commit *commit)

获取对 CRTC 提交的引用

参数

struct drm_crtc_commit *commit

CRTC 提交

描述

增加 commit 的引用计数。

返回

指向 commit 的指针,引用计数已增加。

void drm_crtc_commit_put(struct drm_crtc_commit *commit)

释放对 CRTC 提交的引用

参数

struct drm_crtc_commit *commit

CRTC 提交

描述

这将释放对 commit 的引用,在移除最后一个引用后将其释放。无需锁定,并且可从任何上下文调用。

struct drm_atomic_state *drm_atomic_state_get(struct drm_atomic_state *state)

获取对原子状态的引用

参数

struct drm_atomic_state *state

原子状态

描述

返回 state 的新引用

void drm_atomic_state_put(struct drm_atomic_state *state)

释放对原子状态的引用

参数

struct drm_atomic_state *state

原子状态

描述

这将释放对 state 的引用,在移除最后一个引用后将其释放。无需锁定,并且可从任何上下文调用。

struct drm_crtc_state *drm_atomic_get_existing_crtc_state(const struct drm_atomic_state *state, struct drm_crtc *crtc)

获取 CRTC 状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_crtc *crtc

要获取的 CRTC

描述

此函数返回给定 CRTC 的 CRTC 状态,如果 CRTC 不是全局原子状态的一部分,则返回 NULL。

此函数已弃用,应改用 drm_atomic_get_old_crtc_statedrm_atomic_get_new_crtc_state

struct drm_crtc_state *drm_atomic_get_old_crtc_state(const struct drm_atomic_state *state, struct drm_crtc *crtc)

获取旧的 CRTC 状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_crtc *crtc

要获取的 CRTC

描述

此函数返回给定 CRTC 的旧 CRTC 状态,如果 CRTC 不是全局原子状态的一部分,则返回 NULL。

struct drm_crtc_state *drm_atomic_get_new_crtc_state(const struct drm_atomic_state *state, struct drm_crtc *crtc)

获取新的 CRTC 状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_crtc *crtc

要获取的 CRTC

描述

此函数返回给定 CRTC 的新 CRTC 状态,如果 CRTC 不是全局原子状态的一部分,则返回 NULL。

struct drm_plane_state *drm_atomic_get_existing_plane_state(const struct drm_atomic_state *state, struct drm_plane *plane)

获取平面状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_plane *plane

要获取的平面

描述

此函数返回给定平面的平面状态,如果平面不是全局原子状态的一部分,则返回 NULL。

此函数已弃用,应改用 drm_atomic_get_old_plane_statedrm_atomic_get_new_plane_state

struct drm_plane_state *drm_atomic_get_old_plane_state(const struct drm_atomic_state *state, struct drm_plane *plane)

获取平面状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_plane *plane

要获取的平面

描述

此函数返回给定平面的旧平面状态,如果平面不是全局原子状态的一部分,则返回 NULL。

struct drm_plane_state *drm_atomic_get_new_plane_state(const struct drm_atomic_state *state, struct drm_plane *plane)

获取平面状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_plane *plane

要获取的平面

描述

此函数返回给定平面的新平面状态,如果平面不是全局原子状态的一部分,则返回 NULL。

struct drm_connector_state *drm_atomic_get_existing_connector_state(const struct drm_atomic_state *state, struct drm_connector *connector)

获取连接器状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_connector *connector

要获取的连接器

描述

此函数返回给定连接器的连接器状态,如果连接器不是全局原子状态的一部分,则返回 NULL。

此函数已弃用,应改用 drm_atomic_get_old_connector_statedrm_atomic_get_new_connector_state

struct drm_connector_state *drm_atomic_get_old_connector_state(const struct drm_atomic_state *state, struct drm_connector *connector)

获取连接器状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_connector *connector

要获取的连接器

描述

此函数返回给定连接器的旧连接器状态,如果该连接器不属于全局原子状态,则返回 NULL。

struct drm_connector_state *drm_atomic_get_new_connector_state(const struct drm_atomic_state *state, struct drm_connector *connector)

获取连接器状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_connector *connector

要获取的连接器

描述

此函数返回给定连接器的新连接器状态,如果该连接器不属于全局原子状态,则返回 NULL。

const struct drm_plane_state *__drm_atomic_get_current_plane_state(const struct drm_atomic_state *state, struct drm_plane *plane)

获取当前平面状态

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_plane *plane

要获取的平面

描述

此函数返回给定平面的平面状态,要么来自 state,要么如果平面不属于原子状态更新,则来自 plane。这在原子检查回调中很有用,当驱动程序需要查看但不更改其他平面的状态时,因为它避免了将错误代码向上传递到调用链中。

警告

请注意,此函数通常是不安全的,因为它不检查访问状态结构所需的锁定。驱动程序必须确保通过其他方式访问返回的状态结构是安全的。一个常见的例子是,当平面固定到单个 CRTC 时,并且驱动程序知道 CRTC 锁已经持有。在这种情况下,持有 CRTC 锁可以对连接到该 CRTC 的所有平面进行读锁定。但是,如果可以重新分配平面,事情会变得更加棘手。在这种情况下,最好使用 drm_atomic_get_plane_state 并连接完整的错误处理。

指向当前平面状态的只读指针。

返回

for_each_oldnew_connector_in_state

for_each_oldnew_connector_in_state (__state, connector, old_connector_state, new_connector_state, __i)

在原子更新中迭代所有连接器

参数

__state

struct drm_atomic_state 指针

connector

struct drm_connector 迭代游标

old_connector_state

struct drm_connector_state 用于旧状态的迭代游标

new_connector_state

struct drm_connector_state 用于新状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

这将迭代原子更新中的所有连接器,跟踪旧状态和新状态。这在需要考虑状态增量的地方很有用,例如在原子检查函数中。

for_each_old_connector_in_state

for_each_old_connector_in_state (__state, connector, old_connector_state, __i)

在原子更新中迭代所有连接器

参数

__state

struct drm_atomic_state 指针

connector

struct drm_connector 迭代游标

old_connector_state

struct drm_connector_state 用于旧状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

这将迭代原子更新中的所有连接器,仅跟踪旧状态。这在禁用函数中很有用,在禁用函数中,我们需要硬件仍处于的旧状态。

for_each_new_connector_in_state

for_each_new_connector_in_state (__state, connector, new_connector_state, __i)

在原子更新中迭代所有连接器

参数

__state

struct drm_atomic_state 指针

connector

struct drm_connector 迭代游标

new_connector_state

struct drm_connector_state 用于新状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

这将迭代原子更新中的所有连接器,仅跟踪新状态。这在启用函数中很有用,在启用函数中,我们需要原子提交操作完成后硬件应处于的新状态。

for_each_oldnew_crtc_in_state

for_each_oldnew_crtc_in_state (__state, crtc, old_crtc_state, new_crtc_state, __i)

在原子更新中迭代所有 CRTC

参数

__state

struct drm_atomic_state 指针

crtc

struct drm_crtc 迭代游标

old_crtc_state

struct drm_crtc_state 用于旧状态的迭代游标

new_crtc_state

struct drm_crtc_state 用于新状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

这将迭代原子更新中的所有 CRTC,跟踪旧状态和新状态。这在需要考虑状态增量的地方很有用,例如在原子检查函数中。

for_each_old_crtc_in_state

for_each_old_crtc_in_state (__state, crtc, old_crtc_state, __i)

在原子更新中迭代所有 CRTC

参数

__state

struct drm_atomic_state 指针

crtc

struct drm_crtc 迭代游标

old_crtc_state

struct drm_crtc_state 用于旧状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

这将迭代原子更新中的所有 CRTC,仅跟踪旧状态。这在禁用函数中很有用,在禁用函数中,我们需要硬件仍处于的旧状态。

for_each_new_crtc_in_state

for_each_new_crtc_in_state (__state, crtc, new_crtc_state, __i)

在原子更新中迭代所有 CRTC

参数

__state

struct drm_atomic_state 指针

crtc

struct drm_crtc 迭代游标

new_crtc_state

struct drm_crtc_state 用于新状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

这将迭代原子更新中的所有 CRTC,仅跟踪新状态。这在启用函数中很有用,在启用函数中,我们需要原子提交操作完成后硬件应处于的新状态。

for_each_oldnew_plane_in_state

for_each_oldnew_plane_in_state (__state, plane, old_plane_state, new_plane_state, __i)

在原子更新中迭代所有平面

参数

__state

struct drm_atomic_state 指针

plane

struct drm_plane 迭代游标

old_plane_state

struct drm_plane_state 用于旧状态的迭代游标

new_plane_state

struct drm_plane_state 用于新状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

这将迭代原子更新中的所有平面,跟踪旧状态和新状态。这在需要考虑状态增量的地方很有用,例如在原子检查函数中。

for_each_oldnew_plane_in_state_reverse

for_each_oldnew_plane_in_state_reverse (__state, plane, old_plane_state, new_plane_state, __i)

以相反的顺序迭代原子更新中的所有平面

参数

__state

struct drm_atomic_state 指针

plane

struct drm_plane 迭代游标

old_plane_state

struct drm_plane_state 用于旧状态的迭代游标

new_plane_state

struct drm_plane_state 用于新状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

此函数以相反的顺序迭代原子更新中的所有平面,同时跟踪旧状态和新状态。这在需要考虑状态变化的地方很有用,例如在原子检查函数中。

for_each_new_plane_in_state_reverse

for_each_new_plane_in_state_reverse (__state, plane, new_plane_state, __i)

除了只跟踪新状态之外,它与 for_each_oldnew_plane_in_state_reverse 相同

参数

__state

struct drm_atomic_state 指针

plane

struct drm_plane 迭代游标

new_plane_state

struct drm_plane_state 用于新状态的迭代游标

__i

int 迭代游标,供宏内部使用

for_each_old_plane_in_state

for_each_old_plane_in_state (__state, plane, old_plane_state, __i)

在原子更新中迭代所有平面

参数

__state

struct drm_atomic_state 指针

plane

struct drm_plane 迭代游标

old_plane_state

struct drm_plane_state 用于旧状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

此函数迭代原子更新中的所有平面,仅跟踪旧状态。这在禁用函数中很有用,我们需要硬件仍然处于的旧状态。

for_each_new_plane_in_state

for_each_new_plane_in_state (__state, plane, new_plane_state, __i)

在原子更新中迭代所有平面

参数

__state

struct drm_atomic_state 指针

plane

struct drm_plane 迭代游标

new_plane_state

struct drm_plane_state 用于新状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

此函数迭代原子更新中的所有平面,仅跟踪新状态。这在启用函数中很有用,我们需要原子提交操作完成时硬件应处于的新状态。

for_each_oldnew_private_obj_in_state

for_each_oldnew_private_obj_in_state (__state, obj, old_obj_state, new_obj_state, __i)

迭代原子更新中的所有私有对象

参数

__state

struct drm_atomic_state 指针

obj

struct drm_private_obj 迭代游标

old_obj_state

struct drm_private_state 旧状态的迭代游标

new_obj_state

struct drm_private_state 新状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

此函数迭代原子更新中的所有私有对象,同时跟踪旧状态和新状态。这在需要考虑状态变化的地方很有用,例如在原子检查函数中。

for_each_old_private_obj_in_state

for_each_old_private_obj_in_state (__state, obj, old_obj_state, __i)

迭代原子更新中的所有私有对象

参数

__state

struct drm_atomic_state 指针

obj

struct drm_private_obj 迭代游标

old_obj_state

struct drm_private_state 旧状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

此函数迭代原子更新中的所有私有对象,仅跟踪旧状态。这在禁用函数中很有用,我们需要硬件仍然处于的旧状态。

for_each_new_private_obj_in_state

for_each_new_private_obj_in_state (__state, obj, new_obj_state, __i)

迭代原子更新中的所有私有对象

参数

__state

struct drm_atomic_state 指针

obj

struct drm_private_obj 迭代游标

new_obj_state

struct drm_private_state 新状态的迭代游标

__i

int 迭代游标,供宏内部使用

描述

此函数迭代原子更新中的所有私有对象,仅跟踪新状态。这在启用函数中很有用,我们需要原子提交操作完成时硬件应处于的新状态。

bool drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state)

计算组合的模式设置需求

参数

const struct drm_crtc_state *state

drm_crtc_state 用于 CRTC

描述

为了给驱动程序灵活性,struct drm_crtc_state 有 3 个布尔值来跟踪状态 CRTC 是否发生了足够的变化以需要完全的模式设置周期:mode_changed、active_changed 和 connectors_changed。此帮助函数只是将这三者结合起来,计算 **state** 的整体模式设置需求。

原子帮助函数代码设置这些布尔值,但驱动程序可以并且应该适当地更改它们,以准确表示是否真正需要模式设置。通常,驱动程序应尽可能避免完全模式设置。

例如,如果 CRTC 模式已更改,并且硬件能够在不经过完全模式设置的情况下实施请求的模式更改,则驱动程序应在其 drm_mode_config_funcs.atomic_check 实现中清除 mode_changed。

bool drm_atomic_crtc_effectively_active(const struct drm_crtc_state *state)

计算 CRTC 是否实际处于活动状态

参数

const struct drm_crtc_state *state

drm_crtc_state 用于 CRTC

描述

在自刷新模式下,crtc_state->active 值将为 false,因为 CRTC 已关闭。但是,在某些情况下,我们对 CRTC 是否处于活动状态或有效活动状态(即:它是否连接到活动显示器)感兴趣。在这些情况下,请使用此函数,而不仅仅是检查 active。

struct drm_bus_cfg

总线配置

定义:

struct drm_bus_cfg {
    u32 format;
    u32 flags;
};

成员

格式

此总线上使用的格式(MEDIA_BUS_FMT_* 格式之一)

驱动程序不应直接修改此字段(drm_atomic_bridge_chain_select_bus_fmts() 负责总线格式协商)。

标志

此总线上使用的 DRM_BUS_* 标志

描述

此结构存储输出管道中两个组件之间的物理总线的配置,通常在两个桥接器、编码器和桥接器或桥接器和连接器之间。

总线配置存储在 drm_bridge_state 中,对于每个桥接器的视角,分别存储输入和输出总线。桥接器输出的总线配置通常与下一个桥接器的输入配置相同,但如果信号在两个桥接器之间被修改,例如通过板上的反相器,则可能会有所不同。如果桥接器在内部修改信号(例如通过执行格式转换或修改信号极性),则桥接器的输入和输出配置可能会有所不同。

struct drm_bridge_state

原子桥接器状态对象

定义:

struct drm_bridge_state {
    struct drm_private_state base;
    struct drm_bridge *bridge;
    struct drm_bus_cfg input_bus_cfg;
    struct drm_bus_cfg output_bus_cfg;
};

成员

基础

继承自 drm_private_state

桥接器

此状态引用的桥接器

input_bus_cfg

输入总线配置

output_bus_cfg

输出总线配置

int drm_crtc_commit_wait(struct drm_crtc_commit *commit)

等待提交完成

参数

struct drm_crtc_commit *commit

drm_crtc_commit 要等待的提交

描述

等待给定的 drm_crtc_commit 被编程到硬件并翻转。

返回

成功时返回 0,否则返回负错误代码。

void drm_atomic_state_default_release(struct drm_atomic_state *state)

释放由 drm_atomic_state_init 初始化的内存

参数

struct drm_atomic_state *state

原子状态

描述

释放 drm_atomic_state_init 分配的所有内存。这应该仅由仍对 drm_atomic_state 进行子类化并且尚未切换到 drm_private_state 的驱动程序使用。

int drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)

初始化新的原子状态

参数

struct drm_device *dev

DRM 设备

struct drm_atomic_state *state

原子状态

描述

用于填充新的原子状态的默认实现。这应该只被仍然子类化 drm_atomic_state 且尚未切换到 drm_private_state 的驱动程序使用。

struct drm_atomic_state *drm_atomic_state_alloc(struct drm_device *dev)

分配原子状态

参数

struct drm_device *dev

DRM 设备

描述

这将分配一个空的原子状态来跟踪更新。

void drm_atomic_state_default_clear(struct drm_atomic_state *state)

清除基本原子状态

参数

struct drm_atomic_state *state

原子状态

描述

用于清除原子状态的默认实现。这应该只被仍然子类化 drm_atomic_state 且尚未切换到 drm_private_state 的驱动程序使用。

void drm_atomic_state_clear(struct drm_atomic_state *state)

清除状态对象

参数

struct drm_atomic_state *state

原子状态

描述

当 w/w 互斥算法检测到死锁时,我们需要回退并放弃所有锁。因此,其他人可能会偷偷进入并更改当前的模式设置配置。这意味着在 state 中组装的所有状态不再是对当前状态的原子更新,而是对某个任意的较早状态的原子更新。这可能会打破驱动程序的 drm_mode_config_funcs.atomic_check 可能依赖的假设。

因此,我们必须清除所有缓存的状态并完全重新开始,使用此函数。

void __drm_atomic_state_free(struct kref *ref)

释放原子状态的所有内存

参数

struct kref *ref

要释放的原子状态

描述

这将释放与原子状态关联的所有内存,包括平面、CRTC 和连接器的所有每个对象的状态。

struct drm_crtc_state *drm_atomic_get_crtc_state(struct drm_atomic_state *state, struct drm_crtc *crtc)

获取 CRTC 状态

参数

struct drm_atomic_state *state

全局原子状态对象

struct drm_crtc *crtc

要获取其状态对象的 CRTC

描述

此函数返回给定 CRTC 的 CRTC 状态,并在需要时分配它。它还将获取相关的 CRTC 锁以确保状态一致。

警告:只有当设置了 drm_atomic_state.allow_modeset 时,或者如果它是通过 IOCTL 调用而非用户空间创建的驱动程序内部提交时,驱动程序才能向 state 添加新的 CRTC 状态。

返回

分配的状态或编码到指针中的错误代码。当错误为 EDEADLK 时,w/w 互斥代码已检测到死锁,必须重新启动整个原子序列。所有其他错误都是致命的。

struct drm_plane_state *drm_atomic_get_plane_state(struct drm_atomic_state *state, struct drm_plane *plane)

获取平面状态

参数

struct drm_atomic_state *state

全局原子状态对象

struct drm_plane *plane

要获取其状态对象的平面

描述

此函数返回给定平面的平面状态,并在需要时分配它。它还将获取相关的平面锁以确保状态一致。

返回

分配的状态或编码到指针中的错误代码。当错误为 EDEADLK 时,w/w 互斥代码已检测到死锁,必须重新启动整个原子序列。所有其他错误都是致命的。

void drm_atomic_private_obj_init(struct drm_device *dev, struct drm_private_obj *obj, struct drm_private_state *state, const struct drm_private_state_funcs *funcs)

初始化私有对象

参数

struct drm_device *dev

此对象将附加到的 DRM 设备

struct drm_private_obj *obj

私有对象

struct drm_private_state *state

初始私有对象状态

const struct drm_private_state_funcs *funcs

指向标识对象类型的函数指针结构的指针

描述

初始化私有对象,该对象可以嵌入到任何需要自己的原子状态的驱动程序私有对象中。

void drm_atomic_private_obj_fini(struct drm_private_obj *obj)

完成私有对象

参数

struct drm_private_obj *obj

私有对象

描述

完成私有对象。

struct drm_private_state *drm_atomic_get_private_obj_state(struct drm_atomic_state *state, struct drm_private_obj *obj)

获取私有对象状态

参数

struct drm_atomic_state *state

全局原子状态

struct drm_private_obj *obj

要获取其状态的私有对象

描述

此函数返回给定私有对象的私有对象状态,并在需要时分配状态。它还将获取相关的私有对象锁以确保状态一致。

返回

分配的状态或编码到指针中的错误代码。

struct drm_private_state *drm_atomic_get_old_private_obj_state(const struct drm_atomic_state *state, struct drm_private_obj *obj)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_private_obj *obj

要获取的 private_obj

描述

此函数返回给定 private_obj 的旧私有对象状态,如果 private_obj 不属于全局原子状态,则返回 NULL。

struct drm_private_state *drm_atomic_get_new_private_obj_state(const struct drm_atomic_state *state, struct drm_private_obj *obj)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_private_obj *obj

要获取的 private_obj

描述

此函数返回给定 private_obj 的新私有对象状态,如果 private_obj 不属于全局原子状态,则返回 NULL。

struct drm_connector *drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state *state, struct drm_encoder *encoder)

获取编码器的旧连接器

参数

const struct drm_atomic_state *state

原子状态

struct drm_encoder *encoder

要获取连接器状态的编码器

描述

此函数查找并返回 **state** 指定的已连接到 **encoder** 的连接器。

如果 **state** 中没有先前连接到 **encoder** 的连接器,则此函数将返回 NULL。虽然这看起来像是无效的用例,但在启用挂钩中,区分没有先前连接到 **encoder** 的连接器与有先前连接器的提交(并检查其状态)有时很有用,因为管道已更改。

返回

连接到 **encoder** 的旧连接器,如果编码器未连接,则为 NULL。

struct drm_connector *drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state, struct drm_encoder *encoder)

获取编码器的新连接器

参数

const struct drm_atomic_state *state

原子状态

struct drm_encoder *encoder

要获取连接器状态的编码器

描述

此函数查找并返回 **state** 指定的将连接到 **encoder** 的连接器。

如果 **state** 中没有将连接到 **encoder** 的连接器,则此函数将返回 NULL。虽然这看起来像是无效的用例,但在禁用挂钩中,区分没有连接到 **encoder** 的连接器与有连接器的提交(并检查其状态)有时很有用,因为管道将发生更改。

返回

连接到 **encoder** 的新连接器,如果编码器未连接,则为 NULL。

struct drm_crtc *drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state, struct drm_encoder *encoder)

获取编码器的旧 crtc

参数

struct drm_atomic_state *state

原子状态

struct drm_encoder *encoder

要获取 crtc 状态的编码器

描述

此函数查找并返回 **state** 指定的已连接到 **encoder** 的 crtc。

返回

连接到 **encoder** 的旧 crtc,如果编码器未连接,则为 NULL。

struct drm_crtc *drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state, struct drm_encoder *encoder)

获取编码器的新 crtc

参数

struct drm_atomic_state *state

原子状态

struct drm_encoder *encoder

要获取 crtc 状态的编码器

描述

此函数查找并返回 **state** 指定的将连接到 **encoder** 的 crtc。

返回

连接到 **encoder** 的新 crtc,如果编码器未连接,则为 NULL。

struct drm_connector_state *drm_atomic_get_connector_state(struct drm_atomic_state *state, struct drm_connector *connector)

获取连接器状态

参数

struct drm_atomic_state *state

全局原子状态对象

struct drm_connector *connector

要获取状态对象的连接器

描述

此函数返回给定连接器的连接器状态,并在需要时分配它。它还会获取相关的连接器锁,以确保状态一致。

返回

分配的状态或编码到指针中的错误代码。当错误为 EDEADLK 时,w/w 互斥代码已检测到死锁,必须重新启动整个原子序列。所有其他错误都是致命的。

struct drm_bridge_state *drm_atomic_get_bridge_state(struct drm_atomic_state *state, struct drm_bridge *bridge)

获取桥接状态

参数

struct drm_atomic_state *state

全局原子状态对象

struct drm_bridge *bridge

要获取状态对象的桥接

描述

此函数返回给定桥接的桥接状态,并在需要时分配它。它还会获取相关的桥接锁,以确保状态一致。

返回

分配的状态或编码到指针中的错误代码。当错误为 EDEADLK 时,w/w 互斥代码已检测到死锁,必须重新启动整个原子序列。

struct drm_bridge_state *drm_atomic_get_old_bridge_state(const struct drm_atomic_state *state, struct drm_bridge *bridge)

获取旧桥接状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_bridge *bridge

要获取的桥接

描述

此函数返回给定桥接的旧桥接状态,如果桥接不属于全局原子状态,则返回 NULL。

struct drm_bridge_state *drm_atomic_get_new_bridge_state(const struct drm_atomic_state *state, struct drm_bridge *bridge)

获取新的桥接状态(如果存在)

参数

const struct drm_atomic_state *state

全局原子状态对象

struct drm_bridge *bridge

要获取的桥接

描述

此函数返回给定桥接的新桥接状态,如果桥接不属于全局原子状态,则返回 NULL。

int drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, struct drm_encoder *encoder)

添加附加到编码器的桥接

参数

struct drm_atomic_state *state

原子状态

struct drm_encoder *encoder

DRM 编码器

描述

此函数添加附加到 encoder 的所有桥接。需要在 state 中添加桥接状态,并在调用 drm_bridge_funcs.atomic_check()drm_bridge_funcs.atomic_pre_enable()drm_bridge_funcs.atomic_enable()drm_bridge_funcs.atomic_disable_post_disable() 时使它们可用。

返回

成功时返回 0,或失败时返回 -EDEADLK 或 -ENOMEM。如果错误为 EDEADLK,则表示 w/w 互斥代码检测到死锁,并且必须重新启动整个原子序列。所有其他错误都是致命的。

int drm_atomic_add_affected_connectors(struct drm_atomic_state *state, struct drm_crtc *crtc)

为 CRTC 添加连接器

参数

struct drm_atomic_state *state

原子状态

struct drm_crtc *crtc

DRM CRTC

描述

此函数遍历当前配置,并将当前使用 crtc 的所有连接器添加到原子配置 state。请注意,此函数必须获取连接互斥锁。如果更新仅针对一个 CRTC 上的平面,这可能会导致不必要的序列化。因此,驱动程序和助手应该只在真正需要时才调用此函数(例如,当由于某些更改而需要发生完整的模式设置时)。

返回

成功时返回 0,或失败时返回 -EDEADLK 或 -ENOMEM。如果错误为 EDEADLK,则表示 w/w 互斥代码检测到死锁,并且必须重新启动整个原子序列。所有其他错误都是致命的。

int drm_atomic_add_affected_planes(struct drm_atomic_state *state, struct drm_crtc *crtc)

为 CRTC 添加平面

参数

struct drm_atomic_state *state

原子状态

struct drm_crtc *crtc

DRM CRTC

描述

此函数遍历当前配置,并将 crtc 当前使用的所有平面添加到原子配置 state。当原子提交还需要检查 crtc 上当前启用的所有平面时(例如,当更改模式时),这很有用。当重新启用 CRTC 时,避免使用特殊代码来强制启用所有平面也很有用。

由于获取平面状态总是也会获取该平面当前 CRTC 的 w/w 互斥锁(如果有),因此为 CRTC 添加所有平面状态不会降低原子更新的并行性。

返回

成功时返回 0,或失败时返回 -EDEADLK 或 -ENOMEM。如果错误为 EDEADLK,则表示 w/w 互斥代码检测到死锁,并且必须重新启动整个原子序列。所有其他错误都是致命的。

int drm_atomic_check_only(struct drm_atomic_state *state)

检查给定的配置是否有效

参数

struct drm_atomic_state *state

要检查的原子配置

描述

请注意,如果驱动程序需要获取更多锁但遇到死锁,则此函数可以返回 -EDEADLK。调用者必须执行通常的 w/w 退避操作并重新启动。所有其他错误都是致命的。

返回

成功时返回 0,失败时返回负错误代码。

int drm_atomic_commit(struct drm_atomic_state *state)

以原子方式提交配置

参数

struct drm_atomic_state *state

要检查的原子配置

描述

请注意,如果驱动程序需要获取更多锁但遇到死锁,则此函数可以返回 -EDEADLK。调用者必须执行通常的 w/w 退避操作并重新启动。所有其他错误都是致命的。

此函数将对 state 采取自己的引用。调用者应始终使用 drm_atomic_state_put() 释放其引用。

返回

成功时返回 0,失败时返回负错误代码。

int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)

原子非阻塞提交

参数

struct drm_atomic_state *state

要检查的原子配置

描述

请注意,如果驱动程序需要获取更多锁但遇到死锁,则此函数可以返回 -EDEADLK。调用者必须执行通常的 w/w 退避操作并重新启动。所有其他错误都是致命的。

此函数将对 state 采取自己的引用。调用者应始终使用 drm_atomic_state_put() 释放其引用。

返回

成功时返回 0,失败时返回负错误代码。

void drm_atomic_print_new_state(const struct drm_atomic_state *state, struct drm_printer *p)

打印 drm 原子状态

参数

const struct drm_atomic_state *state

要检查的原子配置

struct drm_printer *p

drm 打印机

描述

此函数使用传递给它的 drm 打印机打印 drm 原子状态快照。此快照可用于调试目的。

请注意,此函数会查看新的状态对象,因此在调用 drm_atomic_helper_commit_hw_done() 之后使用此函数是不安全的。

void drm_state_dump(struct drm_device *dev, struct drm_printer *p)

转储整个设备原子状态

参数

struct drm_device *dev

drm 设备

struct drm_printer *p

将状态打印到何处

描述

仅用于调试。驱动程序可能需要在发生错误中断时选择将状态转储到 dmesg。(提示,您可能需要限制此操作!)

调用者必须包装此 drm_modeset_lock_all_ctx()drm_modeset_drop_locks()。如果这是从错误中断处理程序调用的,则默认情况下不应启用它 - 如果您正在调试错误,您可能不关心这是否是竞争性的,但是在没有保持所有模式设置锁的情况下调用此函数本质上是不安全的。

原子模式设置 IOCTL 和 UAPI 函数

此文件包含原子 UAPI 的编组和解组粘合代码,包括其所有形式:巨大的 ATOMIC IOCTL 本身,用于 GET_PROPERTY 和 SET_PROPERTY IOCTL 的代码。此外,还包括用于兼容性助手和驱动程序的接口函数,这些驱动程序有特殊的需求来构建自己的原子更新,例如用于负载检测或类似用途。

int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, const struct drm_display_mode *mode)

为 CRTC 设置模式

参数

struct drm_crtc_state *state

要更新其传入状态的 CRTC

const struct drm_display_mode *mode

用于 CRTC 的内核内部模式,如果禁用则为 NULL

描述

在所需的 CRTC 状态上设置一个模式(源自内核)并更新启用属性。

返回

成功时返回零,失败时返回错误代码。不能返回 -EDEADLK。

int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, struct drm_property_blob *blob)

为 CRTC 设置模式

参数

struct drm_crtc_state *state

要更新其传入状态的 CRTC

struct drm_property_blob *blob

指向用于模式的 blob 属性的指针

描述

在所需的 CRTC 状态上设置一个模式(源自 blob 属性)。此函数将获取 CRTC 状态上的 blob 属性的引用,并释放状态现有模式属性上持有的引用(如果已设置)。

返回

成功时返回零,失败时返回错误代码。不能返回 -EDEADLK。

int drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, struct drm_crtc *crtc)

为平面设置 CRTC

参数

struct drm_plane_state *plane_state

要更新其传入状态的平面

struct drm_crtc *crtc

用于平面的 CRTC

描述

更改平面的分配 CRTC 需要我们根据需要获取新 CRTC 的锁和状态。此函数处理所有这些细节,除了更新状态对象本身的指针。

返回

成功时返回 0,或失败时返回 -EDEADLK 或 -ENOMEM。如果错误为 EDEADLK,则表示 w/w 互斥代码检测到死锁,并且必须重新启动整个原子序列。所有其他错误都是致命的。

void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, struct drm_framebuffer *fb)

为平面设置帧缓冲区

参数

struct drm_plane_state *plane_state

平面的原子状态对象

struct drm_framebuffer *fb

用于平面的帧缓冲区

描述

更改平面的分配帧缓冲区需要我们获取新帧缓冲区的引用并删除旧帧缓冲区的引用(如果有)。此函数处理所有这些细节,除了更新状态对象本身的指针。

int drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, struct drm_crtc *crtc)

为连接器设置 CRTC

参数

struct drm_connector_state *conn_state

连接器的原子状态对象

struct drm_crtc *crtc

用于连接器的 CRTC

描述

更改连接器的分配 CRTC 需要我们根据需要获取新 CRTC 的锁和状态。此函数处理所有这些细节,除了更新状态对象本身的指针。

返回

成功时返回 0,或失败时返回 -EDEADLK 或 -ENOMEM。如果错误为 EDEADLK,则表示 w/w 互斥代码检测到死锁,并且必须重新启动整个原子序列。所有其他错误都是致命的。

CRTC 抽象

CRTC 代表整个显示管道。它从 drm_plane 接收像素数据并将它们混合在一起。drm_display_mode 也附加到 CRTC,指定显示时序。在输出端,数据被馈送到一个或多个 drm_encoder,然后每个 drm_encoder 都连接到一个 drm_connector

要创建 CRTC,KMS 驱动程序会分配并清零 struct drm_crtc 的实例(可能作为较大结构的一部分),并通过调用 drm_crtc_init_with_planes() 来注册它。

CRTC 也是传统模式设置操作的入口点(请参阅 drm_crtc_funcs.set_config)、传统平面操作(请参阅 drm_crtc_funcs.page_flipdrm_crtc_funcs.cursor_set2)以及其他传统操作,如 drm_crtc_funcs.gamma_set。对于原子驱动程序,所有这些功能都通过 drm_propertydrm_mode_config_funcs.atomic_check 进行控制。

CRTC 函数参考

struct drm_crtc_state

可变的 CRTC 状态

定义:

struct drm_crtc_state {
    struct drm_crtc *crtc;
    bool enable;
    bool active;
    bool planes_changed : 1;
    bool mode_changed : 1;
    bool active_changed : 1;
    bool connectors_changed : 1;
    bool zpos_changed : 1;
    bool color_mgmt_changed : 1;
    bool no_vblank : 1;
    u32 plane_mask;
    u32 connector_mask;
    u32 encoder_mask;
    struct drm_display_mode adjusted_mode;
    struct drm_display_mode mode;
    struct drm_property_blob *mode_blob;
    struct drm_property_blob *degamma_lut;
    struct drm_property_blob *ctm;
    struct drm_property_blob *gamma_lut;
    u32 target_vblank;
    bool async_flip;
    bool vrr_enabled;
    bool self_refresh_active;
    enum drm_scaling_filter scaling_filter;
    struct drm_pending_vblank_event *event;
    struct drm_crtc_commit *commit;
    struct drm_atomic_state *state;
};

成员

crtc

指向 CRTC 的反向指针

启用

是否应启用 CRTC,这会限制所有其他状态。这控制共享资源的预留。实际硬件状态由 active 控制。

活动

CRTC 是否正在主动显示(用于 DPMS)。这意味着设置了 enable。如果 active 设置为 false 但 enable 仍然为 true,则驱动程序不得释放任何共享资源,因为用户空间期望 DPMS ON 始终成功。

因此,驱动程序不得在其各种 drm_mode_config_funcs.atomic_check 回调中咨询 active 以拒绝原子提交。他们可以咨询它以帮助计算导出的硬件状态,因为即使在 DPMS OFF 状态下,显示硬件也应尽可能像通过将 enable 设置为 false 来完全禁用 CRTC 时一样关闭电源。

planes_changed

此 CRTC 上的平面已更新。由原子助手和驱动程序用于控制原子提交控制流。

mode_changed

modeenable 已更改。由原子助手和驱动程序用于控制原子提交控制流。另请参阅 drm_atomic_crtc_needs_modeset()

对于需要完全模式设置的任何 CRTC 状态更改,驱动程序都应设置此项。如果例如仅通过更改缩放器设置就可以在不进行完全模式设置的情况下完成 mode 更改,他们也可以将其重置为 false。

active_changed

active 已切换。由原子助手和驱动程序用于控制原子提交控制流。另请参阅 drm_atomic_crtc_needs_modeset()

connectors_changed

此 CRTC 的连接器已更新,无论是在其状态还是路由中。由原子助手和驱动程序用于控制原子提交控制流。另请参阅 drm_atomic_crtc_needs_modeset()

驱动程序应根据需要从他们自己的原子检查代码中设置此项,例如从 drm_encoder_helper_funcs.atomic_check

zpos_changed

此 CRTC 上平面的 zpos 值已更新。由原子助手和驱动程序用于控制原子提交控制流。

color_mgmt_changed

颜色管理属性已更改(gamma_lutdegamma_lutctm)。由原子助手和驱动程序用于控制原子提交控制流。

no_vblank

反映 CRTC 发送 VBLANK 事件的能力。此状态通常取决于管道配置。如果设置为 true,DRM 原子助手将在所有硬件更改都已提交后,在显示更新期间发送伪造的 VBLANK 事件。这在 drm_atomic_helper_fake_vblank() 中实现。

一种用法是针对不支持垂直消隐 (VBLANK) 中断的驱动程序和/或硬件。此类驱动程序通常不初始化垂直消隐(即,不使用 CRTC 数量调用 drm_vblank_init())。对于未初始化垂直消隐的 CRTC,此字段在 drm_atomic_helper_check_modeset() 中设置为 true,并且每次显示管道更新时,都会由 drm_atomic_helper_fake_vblank() 发送一个伪 VBLANK 事件。

另一种用法是用于以单次模式运行的回写连接器所馈送的 CRTC。在这种情况下,伪 VBLANK 事件仅在有作业排队到回写连接器时生成,并且当管道的这部分没有更改但其他部分已更改时,或者当 CRTC 和连接器被禁用时,我们希望核心模拟 VBLANK 事件。

__drm_atomic_helper_crtc_duplicate_state() 不会重置当前状态的值,因此 CRTC 驱动程序负责在需要时更新此字段。

请注意,drm_crtc_state.event == NULL 和 drm_crtc_state.no_blank == true 的组合是有效的,并且通常在连接到 CRTC 的回写连接器有新作业排队时使用。在这种情况下,驱动程序将在回写作业完成时自行发送 VBLANK 事件。

plane_mask

附加到此 CRTC 的平面 (plane) 的 drm_plane_mask(plane) 的位掩码。

connector_mask

附加到此 CRTC 的连接器 (connector) 的 drm_connector_mask(connector) 的位掩码。

encoder_mask

附加到此 CRTC 的编码器 (encoder) 的 drm_encoder_mask(encoder) 的位掩码。

adjusted_mode

内部显示时序,驱动程序可以使用它来处理用户空间在 mode 中请求的模式与实际编程到硬件中的模式之间的差异。

对于使用 drm_bridge 的驱动程序,此字段存储 CRTC 和第一个桥接器之间使用的硬件显示时序。对于其他驱动程序,adjusted_mode 字段的含义纯粹是驱动程序实现定义的信息,通常用于存储 CRTC 和编码器块之间使用的硬件显示时序。

mode

用户空间请求的显示时序。驱动程序应尝试尽可能地匹配刷新率(但请注意,究竟多接近才算足够是未定义的,例如,某些 HDMI 模式仅在刷新率上相差不到 1%)。用户空间用于定位平面的活动宽度和高度必须完全匹配。

对于接收器未固定的外部连接器(例如内置面板),此处的模式应与线上的物理模式在最后一个细节上匹配(即,包括同步极性和所有内容)。

mode_blob

用于 modedrm_property_blob,用于向原子用户空间公开模式。

degamma_lut

在应用颜色转换矩阵 ctm 之前转换帧缓冲区像素数据的查找表。请参阅 drm_crtc_enable_color_mgmt()。该 blob(如果不是 NULL)是 struct drm_color_lut 的数组。

ctm

颜色转换矩阵。请参阅 drm_crtc_enable_color_mgmt()。该 blob(如果不是 NULL)是一个 struct drm_color_ctm

gamma_lut

在颜色转换矩阵 ctm 之后转换像素数据的查找表。请参阅 drm_crtc_enable_color_mgmt()。该 blob(如果不是 NULL)是 struct drm_color_lut 的数组。

请注意,由于主要来自 Xorg 传统的历史原因,这也被用于存储索引格式(如 DRM_FORMAT_C8)的颜色映射(有时也称为颜色查找表、CLUT 或调色板)。

target_vblank

页面翻转应生效的目标垂直消隐周期。

async_flip

当在旧版 PAGE_FLIP IOCTL 中设置 DRM_MODE_PAGE_FLIP_ASYNC 时,将设置此项。它尚未连接到原子 IOCTL 本身。

vrr_enabled

指示是否应为 CRTC 启用可变刷新率。对所请求的 vrr 状态的支持将取决于驱动程序和硬件功能 - 缺乏支持不被视为失败。

self_refresh_active

自刷新辅助程序用于表示何时发生自刷新转换。当启用或禁用自刷新时,将在启用/禁用回调中设置此项。在某些情况下,可能不希望在自刷新期间完全关闭 crtc。CRTC 可以检查此标志并确定最佳操作方案。

scaling_filter

要应用的缩放滤镜

event

指向 DRM 事件的可选指针,用于在状态更新完成后发出信号。当原子提交操作完成时,驱动程序必须发送事件。有两种情况:

  • 该事件用于通过此原子提交禁用的 CRTC。在这种情况下,可以在硬件停止扫描输出当前帧缓冲区之后的任何时间发送事件。它应包含显示管道关闭之前最后一次垂直消隐的时间戳和计数器。实现此目的的最简单方法是在调用 drm_crtc_vblank_off() 之后的某个时间调用 drm_crtc_send_vblank_event()

  • 对于在提交结束时启用的 CRTC(即使它经历了完整的模式设置),垂直消隐时间戳和计数器必须是扫描输出新缓冲区集的第一帧之前的垂直消隐的时间戳和计数器。同样,只有在硬件停止扫描输出旧缓冲区之后才能发送事件。

  • 不允许禁用 CRTC 的事件,驱动程序可以忽略这种情况。

对于没有垂直消隐中断的非常简单的硬件,启用 struct drm_crtc_state.no_vblank 会使 DRM 的原子提交辅助程序在应用所有硬件更改后,在显示更新结束时发送一个伪 VBLANK 事件。请参阅 drm_atomic_helper_fake_vblank()

对于更复杂的硬件,可以通过 drm_crtc_send_vblank_event() 函数来处理,驱动程序应在原子提交完成后对提供的事件调用该函数。请注意,如果驱动程序支持垂直消隐信号和时间戳,则垂直消隐计数器和时间戳必须与页面翻转事件返回的计数器和时间戳一致。使用当前的垂直消隐辅助程序基础架构,可以通过在页面翻转挂起时保持垂直消隐引用来实现此目的,该引用通过 drm_crtc_vblank_get() 获取,并通过 drm_crtc_vblank_put() 释放。驱动程序可以自由地实现他们自己的垂直消隐计数器和时间戳跟踪,例如,如果它们在硬件中具有精确的时间戳寄存器。

对于支持某种方法将垂直消隐中断的传递与提交显示状态同步的硬件,还有 drm_crtc_arm_vblank_event()。有关安全使用它的约束的详细讨论,请参阅该函数的文档。

如果设备根本无法以无竞争方式通知翻转完成,则应在页面翻转提交后立即配置事件。在最坏的情况下,驱动程序会将事件发送到用户空间晚一帧。这不允许真正的原子更新,但应避免撕裂。

commit

此项跟踪此更新的提交如何通过各个阶段。除非我们销毁状态,否则它永远不会被清除,以便后续提交可以与之前的提交同步。

state

指向全局 drm_atomic_state 的后向指针

描述

请注意,enableactive 之间的区别相当微妙:在设置 enable 的同时翻转 active 而不更改任何其他内容可能永远不会在 drm_mode_config_funcs.atomic_check 回调中返回失败。用户空间假设 DPMS On 总是会成功。换句话说:enable 控制资源分配,active 控制实际硬件状态。

三个布尔值 active_changed、connectors_changed 和 mode_changed 旨在指示是否需要完整的模式设置,而不是严格描述提交中发生的变化。另请参阅:drm_atomic_crtc_needs_modeset()

struct drm_crtc_funcs

控制给定设备的 CRTC

定义:

struct drm_crtc_funcs {
    void (*reset)(struct drm_crtc *crtc);
    int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height);
    int (*cursor_set2)(struct drm_crtc *crtc, struct drm_file *file_priv,uint32_t handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y);
    int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
    int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,uint32_t size, struct drm_modeset_acquire_ctx *ctx);
    void (*destroy)(struct drm_crtc *crtc);
    int (*set_config)(struct drm_mode_set *set, struct drm_modeset_acquire_ctx *ctx);
    int (*page_flip)(struct drm_crtc *crtc,struct drm_framebuffer *fb,struct drm_pending_vblank_event *event,uint32_t flags, struct drm_modeset_acquire_ctx *ctx);
    int (*page_flip_target)(struct drm_crtc *crtc,struct drm_framebuffer *fb,struct drm_pending_vblank_event *event,uint32_t flags, uint32_t target, struct drm_modeset_acquire_ctx *ctx);
    int (*set_property)(struct drm_crtc *crtc, struct drm_property *property, uint64_t val);
    struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);
    void (*atomic_destroy_state)(struct drm_crtc *crtc, struct drm_crtc_state *state);
    int (*atomic_set_property)(struct drm_crtc *crtc,struct drm_crtc_state *state,struct drm_property *property, uint64_t val);
    int (*atomic_get_property)(struct drm_crtc *crtc,const struct drm_crtc_state *state,struct drm_property *property, uint64_t *val);
    int (*late_register)(struct drm_crtc *crtc);
    void (*early_unregister)(struct drm_crtc *crtc);
    int (*set_crc_source)(struct drm_crtc *crtc, const char *source);
    int (*verify_crc_source)(struct drm_crtc *crtc, const char *source, size_t *values_cnt);
    const char *const *(*get_crc_sources)(struct drm_crtc *crtc, size_t *count);
    void (*atomic_print_state)(struct drm_printer *p, const struct drm_crtc_state *state);
    u32 (*get_vblank_counter)(struct drm_crtc *crtc);
    int (*enable_vblank)(struct drm_crtc *crtc);
    void (*disable_vblank)(struct drm_crtc *crtc);
    bool (*get_vblank_timestamp)(struct drm_crtc *crtc,int *max_error,ktime_t *vblank_time, bool in_vblank_irq);
};

成员

reset

将 CRTC 硬件和软件状态重置为关闭状态。此函数不会由内核直接调用,仅通过 drm_mode_config_reset() 调用。它不是仅出于历史原因的辅助钩子。

原子驱动程序可以使用 drm_atomic_helper_crtc_reset() 来使用此钩子重置原子状态。

cursor_set

更新光标图像。光标位置相对于 CRTC,并且可以部分或完全在可见区域之外。

请注意,与所有其他 KMS 函数相反,传统光标入口点不接受帧缓冲对象,而是直接从驱动程序的缓冲区管理器(对于当前驱动程序,它是 GEM 或 TTM)获取原始缓冲区对象 ID。

此入口点已弃用,驱动程序应改为实现通用平面支持,并使用 drm_crtc_init_with_planes() 注册适当的光标平面。

此回调是可选的

返回

成功返回 0,失败返回负错误代码。

cursor_set2

更新光标图像,包括热点信息。热点不得影响 CRTC 坐标中的光标位置,而仅用于提示虚拟化显示硬件协调访客和主机光标位置。光标热点相对于光标图像。否则,它的工作方式与 cursor_set 完全相同。

此入口点已弃用,驱动程序应改为实现通用平面支持,并使用 drm_crtc_init_with_planes() 注册适当的光标平面。

此回调是可选的。

返回

成功返回 0,失败返回负错误代码。

cursor_move

更新光标位置。调用此钩子时,光标不需要可见。

此入口点已弃用,驱动程序应改为实现通用平面支持,并使用 drm_crtc_init_with_planes() 注册适当的光标平面。

此回调是可选的。

返回

成功返回 0,失败返回负错误代码。

gamma_set

在 CRTC 上设置 gamma。

此回调是可选的。

想要支持 gamma 表的原子驱动程序应实现原子颜色管理支持,通过调用 drm_crtc_enable_color_mgmt() 启用,然后通过 drm_atomic_helper_legacy_gamma_set() 兼容性实现支持传统 gamma 接口。

destroy

清理 CRTC 资源。这仅在驱动程序卸载时通过 drm_mode_config_cleanup() 调用,因为 CRTC 不能在 DRM 中热插拔。

set_config

这是更改 CRTC 上模式设置状态的主要传统入口点。所需配置的所有详细信息都通过 struct drm_mode_set 传递 - 有关详细信息,请参阅此处。

实现原子模式设置的驱动程序应使用 drm_atomic_helper_set_config() 来实现此钩子。

返回

成功返回 0,失败返回负错误代码。

page_flip

调度翻转到给定帧缓冲区的传统入口点。

页面翻转是一种同步机制,它在垂直消隐期间用新的帧缓冲区替换 CRTC 扫描输出的帧缓冲区,从而避免撕裂(除非通过 DRM_MODE_PAGE_FLIP_ASYNC 标志另行请求)。当应用程序请求页面翻转时,DRM 内核会验证新帧缓冲区是否足够大,以便在当前配置的模式下由 CRTC 扫描输出,然后使用指向新帧缓冲区的指针调用此钩子。

驱动程序必须等待对新帧缓冲区的任何挂起渲染完成后才能执行翻转。如果底层缓冲区是共享的 dma-buf,它还应该等待来自其他驱动程序的任何挂起渲染。

应用程序可以请求在页面翻转完成后收到通知。在这种情况下,drm 内核将在事件参数中提供一个 struct drm_event。这可以通过 drm_crtc_send_vblank_event() 函数处理,驱动程序应在翻转完成后在提供的事件上调用此函数。请注意,如果驱动程序支持垂直消隐信号和时间戳,则垂直消隐计数器和时间戳必须与页面翻转事件返回的计数器和时间戳一致。使用当前的垂直消隐辅助基础设施,可以通过在页面翻转挂起时保持垂直消隐引用来实现这一点,该引用通过 drm_crtc_vblank_get() 获取,并通过 drm_crtc_vblank_put() 释放。驱动程序可以自由实现自己的垂直消隐计数器和时间戳跟踪,例如,如果它们在硬件中有准确的时间戳寄存器。

此回调是可选的。

注意

KMS ABI 的早期版本规定,驱动程序必须阻止(但不拒绝)在翻转操作完成且旧帧缓冲区不再可见之前对旧帧缓冲区的任何渲染。此要求已被取消,而是期望用户空间请求交付事件并等待回收旧缓冲区,直到收到此类事件。

返回

成功返回 0,失败返回负错误代码。请注意,如果页面翻转操作已在挂起,则回调应返回 -EBUSY。在禁用 CRTC 上(通过设置 NULL 模式或仅通过 DPMS 或新的原子“ACTIVE”状态运行时禁用)的页面翻转应导致 -EINVAL 错误代码。请注意,drm_atomic_helper_page_flip() 已为原子驱动程序检查过这一点。

page_flip_target

page_flip 相同,但附加了一个参数,指定翻转应生效的绝对目标垂直消隐周期(如 drm_crtc_vblank_count() 报告)。

请注意,核心代码在此入口点之前调用 drm_crtc_vblank_get,如果此入口点返回任何非 0 错误代码,则将调用 drm_crtc_vblank_put。驱动程序负责在此入口点返回 0 后调用 drm_crtc_vblank_put,通常在翻转完成时。

set_property

这是更新附加到 CRTC 的属性的传统入口点。

如果驱动程序不支持任何传统驱动程序私有属性,则此回调是可选的。对于原子驱动程序,它不使用,因为属性处理完全在 DRM 内核中完成。

返回

成功返回 0,失败返回负错误代码。

atomic_duplicate_state

复制此 CRTC 的当前原子状态并返回它。核心和辅助程序保证使用此钩子复制的任何原子状态,并且仍然由调用方拥有(即,未通过调用 drm_mode_config_funcs.atomic_commit 转移到驱动程序)将通过调用此结构中的 atomic_destroy_state 钩子清理。

此回调对于原子驱动程序是强制性的。

不子类化 struct drm_crtc_state 的原子驱动程序应使用 drm_atomic_helper_crtc_duplicate_state()。子类化状态结构以使用驱动程序私有状态扩展它的驱动程序应使用 __drm_atomic_helper_crtc_duplicate_state() 以确保在驱动程序之间以一致的方式复制共享状态。

drm_crtc.state 正确初始化之前调用此钩子是错误的。

注意

如果重复的状态引用了引用计数的资源,则此钩子必须为每个资源获取引用。驱动程序必须在 atomic_destroy_state 中再次释放这些引用。

返回

当分配失败时,重复的原子状态或 NULL。

atomic_destroy_state

销毁使用 atomic_duplicate_state 复制的状态,并释放或取消引用其引用的所有资源

此回调对于原子驱动程序是强制性的。

atomic_set_property

解码驱动程序私有属性值,并将解码的值存储到传入的状态结构中。由于原子内核解码所有标准化的属性(即使对于核心属性集之外的扩展,这些扩展可能并非所有驱动程序都实现),因此这要求驱动程序子类化状态结构。

此类驱动程序私有属性实际上仅应针对真正的硬件/供应商特定状态实现。相反,最好标准化原子扩展,并在内核中解码用于公开此类扩展的属性。

不要直接调用此函数,请改用 drm_atomic_crtc_set_property()。

如果驱动程序不支持任何驱动程序私有原子属性,则此回调是可选的。

注意

此函数在原子模式设置的状态组装阶段调用,该阶段可能出于任何原因中止(包括在用户空间请求时仅检查配置是否可能)。驱动程序不得触及任何持久状态(硬件或软件)或数据结构,除了传入的 state 参数。

此外,由于用户空间控制属性的设置顺序,因此此函数不得进行任何输入验证(因为状态更新不完整,因此可能不一致)。相反,任何此类输入验证都必须在各种 atomic_check 回调中完成。

返回

如果找到该属性,则返回 0;如果驱动程序未实现该属性,则返回 -EINVAL(这永远不应该发生,内核仅要求附加到此 CRTC 的属性)。驱动程序不允许进行其他验证。内核已经检查属性值是否在驱动程序注册属性时设置的范围(整数、有效枚举值等)内。

atomic_get_property

读出解码后的驱动程序私有属性。这用于实现 GETCRTC IOCTL。

不要直接调用此函数,请改用 drm_atomic_crtc_get_property()。

如果驱动程序不支持任何驱动程序私有原子属性,则此回调是可选的。

返回

成功时返回 0,如果驱动程序未实现该属性则返回 -EINVAL(这不应该发生,核心只请求附加到此 CRTC 的属性)。

late_register

这个可选钩子可用于注册附加到 CRTC 的额外用户空间接口,例如 debugfs 接口。它在驱动程序加载序列的后期从 drm_dev_register() 调用。从这个回调中添加的所有内容都应该在 early_unregister 回调中取消注册。

返回值

成功时返回 0,失败时返回负错误代码。

early_unregister

这个可选钩子应该用于取消注册从 late_register 附加到 CRTC 的额外用户空间接口。它从 drm_dev_unregister() 调用,在驱动程序卸载序列的早期禁用用户空间访问,然后再销毁数据结构。

set_crc_source

应用户空间请求更改帧的 CRC 校验和的来源,通常用于测试目的。可用的来源是每个驱动程序特定的,NULL 值表示要关闭 CRC 生成。

启用 CRC 生成后,驱动程序应在每个帧调用 drm_crtc_add_crc_entry(),在 crcN 参数中提供任何表征帧内容的信息,如配置的来源所提供。驱动程序必须接受一个 “auto” 源名称,该名称将为此 CRTC 选择默认源。

如有必要,这可能会触发原子模式设置提交以启用 CRC 生成。

请注意,“auto” 可能取决于当前的模式设置配置,例如,它可以选择编码器或输出特定的 CRC 采样点。

如果驱动程序不支持任何 CRC 生成功能,则此回调是可选的。

返回

成功返回 0,失败返回负错误代码。

verify_crc_source

在设置 CRC 的源之前以及在 CRC 打开期间验证帧的 CRC 校验和的源。禁用 CRC 源时,Source 参数可以为 NULL。

如果驱动程序不支持任何 CRC 生成功能,则此回调是可选的。

返回

成功返回 0,失败返回负错误代码。

get_crc_sources

驱动程序回调,用于获取 CRC 生成的所有可用源的列表。此回调取决于 verify_crc_source,因此应先实现 verify_crc_source 回调,然后再实现此回调。驱动程序可以传递所有可用 CRC 源的完整列表,此回调在将每个 CRC 源传递给用户空间之前对其进行验证。

如果驱动程序不支持导出可能的 CRC 源列表,则此回调是可选的。

返回

一个指向所有可用 CRC 源列表的常量字符指针。失败时,驱动程序应返回 NULL。count 应该用列表中的源数量更新。如果为零,我们不处理列表中的任何源。

atomic_print_state

如果驱动程序子类化 struct drm_crtc_state,则它应该实现这个可选钩子来打印额外的驱动程序特定状态。

不要直接调用它,而是使用 drm_atomic_crtc_print_state()。

get_vblank_counter

驱动程序回调,用于获取 CRTC 的原始硬件垂直消隐计数器。它旨在被新驱动程序用作 drm_driver.get_vblank_counter 钩子的替代品。

此回调是可选的。如果设备没有硬件计数器,驱动程序可以简单地将钩子保留为 NULL。DRM 核心将在基于系统时间戳的禁用中断期间考虑错过的垂直消隐事件。

由于模式设置导致的事件回绕处理和丢失在 DRM 核心代码中处理,只要驱动程序在禁用或启用 CRTC 时调用 drm_crtc_vblank_off()drm_crtc_vblank_on()

另请参阅 drm_device.vblank_disable_immediatedrm_device.max_vblank_count

返回值

原始垂直消隐计数器值。

enable_vblank

启用 CRTC 的垂直消隐中断。它旨在被新驱动程序用作 drm_driver.enable_vblank 钩子的替代品。

返回值

成功时返回零,如果无法启用垂直消隐中断则返回适当的 errno。

disable_vblank

禁用 CRTC 的垂直消隐中断。它旨在被新驱动程序用作 drm_driver.disable_vblank 钩子的替代品。

get_vblank_timestamp

由 drm_get_last_vbltimestamp() 调用。应该返回最近的垂直消隐间隔结束或将要结束时的精确时间戳。

具体来说,vblank_time 中的时间戳应尽可能接近视频帧的第一个视频扫描线在垂直消隐结束后开始扫描输出的时间,即垂直消隐间隔结束后立即的时间。如果 crtc 当前在垂直消隐内,这将是未来的时间。如果 crtc 当前正在扫描输出一个帧,这将是当前扫描输出的过去开始时间。这旨在遵守 OpenML OML_sync_control 扩展规范。

参数

crtc

应返回时间戳的 CRTC。

max_error

允许的最大时间戳误差,以纳秒为单位。实现应努力提供时间戳,其误差最大为 max_error 纳秒。返回时间戳误差的真实上限。

vblank_time

返回的垂直消隐时间戳的目标位置。

in_vblank_irq

drm_crtc_handle_vblank() 调用时为 True。如果设置了标志,一些驱动程序需要为 GPU 特定的垂直消隐 irq 怪癖应用一些解决方法。

返回值

成功时为 True,失败时为 false,这意味着核心应该回退到 drm_crtc_handle_vblank() 中获取的简单时间戳。

描述

drm_crtc_funcs 结构是 DRM 中主要的 CRTC 管理结构。每个 CRTC 控制一个或多个连接器(请注意,CRTC 名称只是历史遗留问题,CRTC 可以控制 LVDS、VGA、DVI、TV 输出等连接器,而不仅仅是 CRT)。

每个驱动程序都负责在启动时填充此结构,此外还要提供其他模式设置功能,例如 i2c 和 DDC 总线访问器。

struct drm_crtc

主要的 CRTC 控制结构

定义:

struct drm_crtc {
    struct drm_device *dev;
    struct device_node *port;
    struct list_head head;
    char *name;
    struct drm_modeset_lock mutex;
    struct drm_mode_object base;
    struct drm_plane *primary;
    struct drm_plane *cursor;
    unsigned index;
    int cursor_x;
    int cursor_y;
    bool enabled;
    struct drm_display_mode mode;
    struct drm_display_mode hwmode;
    int x;
    int y;
    const struct drm_crtc_funcs *funcs;
    uint32_t gamma_size;
    uint16_t *gamma_store;
    const struct drm_crtc_helper_funcs *helper_private;
    struct drm_object_properties properties;
    struct drm_property *scaling_filter_property;
    struct drm_crtc_state *state;
    struct list_head commit_list;
    spinlock_t commit_lock;
    struct dentry *debugfs_entry;
    struct drm_crtc_crc crc;
    unsigned int fence_context;
    spinlock_t fence_lock;
    unsigned long fence_seqno;
    char timeline_name[32];
    struct drm_self_refresh_data *self_refresh_data;
};

成员

dev

父 DRM 设备

端口

drm_of_find_possible_crtcs() 使用的 OF 节点。

head

dev 上的所有 CRTC 的列表,从 drm_mode_config.crtc_list 链接。在 dev 的生命周期中保持不变,因此不需要锁定。

名称

人类可读的名称,可以被驱动程序覆盖

mutex

这为整体 CRTC 状态(模式、dpms 状态等)提供了一个读锁定,并为所有可以在不进行完整模式设置的情况下更新的内容(fb、光标数据、CRTC 属性等)提供了一个写锁定。完整的模式设置还需要获取 drm_mode_config.connection_mutex

特别是对于原子驱动程序,这保护了 state

基础

用于 ID 跟踪等的基 KMS 对象。

primary

此 CRTC 的主平面。请注意,这仅与旧版 IOCTL 相关,它指定了 SETCRTC 和 PAGE_FLIP IOCTL 隐式使用的平面。除此之外,它没有任何意义。

cursor

此 CRTC 的光标平面。请注意,这仅与旧版 IOCTL 相关,它指定了 SETCURSOR 和 SETCURSOR2 IOCTL 隐式使用的平面。除此之外,它没有任何意义。

index

在 mode_config.list 中的位置,可以用作数组索引。它在 CRTC 的生命周期中保持不变。

cursor_x

光标的当前 x 位置,用于通用光标平面,因为 SETCURSOR IOCTL 只能在不提供坐标的情况下更新帧缓冲区。驱动程序不应直接使用此值,原子驱动程序应查看光标平面的 drm_plane_state.crtc_x

cursor_y

光标的当前 y 位置,用于通用光标平面,因为 SETCURSOR IOCTL 只能在不提供坐标的情况下更新帧缓冲区。驱动程序不应直接使用此值,原子驱动程序应查看光标平面的 drm_plane_state.crtc_y

enabled

此 CRTC 是否启用?只应由旧版驱动程序使用,原子驱动程序应改为查阅 drm_crtc_state.enabledrm_crtc_state.active。原子驱动程序可以通过调用 drm_atomic_helper_update_legacy_modeset_state() 来更新此值。

mode

当前模式时序。只应由旧版驱动程序使用,原子驱动程序应改为查阅 drm_crtc_state.mode。原子驱动程序可以通过调用 drm_atomic_helper_update_legacy_modeset_state() 来更新此值。

hwmode

硬件中编程的模式,在对编码器、crtc、面板缩放等进行调整后。只应由旧版驱动程序使用,用于 drm_crtc_vblank_helper_get_vblank_timestamp() 中的高精度垂直消隐时间戳。

请注意,原子驱动程序不应使用此值,而应使用 drm_crtc_state.adjusted_mode。对于高精度时间戳,drm_crtc_vblank_helper_get_vblank_timestamp() 使用 drm_vblank_crtc.hwmode,该值通过调用 drm_calc_timestamping_constants() 填充。

x

屏幕上的 X 坐标。仅应由旧式驱动程序使用,原子驱动程序应查看主平面的 drm_plane_state.crtc_x。通过调用 drm_atomic_helper_update_legacy_modeset_state() 更新。

y

屏幕上的 Y 坐标。仅应由旧式驱动程序使用,原子驱动程序应查看主平面的 drm_plane_state.crtc_y。通过调用 drm_atomic_helper_update_legacy_modeset_state() 更新。

funcs

CRTC 控制函数

gamma_size

报告给用户空间的旧式 gamma 斜坡的大小。通过调用 drm_mode_crtc_set_gamma_size() 设置。

请注意,原子驱动程序需要改为使用 drm_crtc_state.gamma_lut。请参阅 drm_crtc_enable_color_mgmt()

gamma_store

旧式 SETGAMMA 和 GETGAMMA IOCTls 使用的 gamma 斜坡值。通过调用 drm_mode_crtc_set_gamma_size() 设置。

请注意,原子驱动程序需要改为使用 drm_crtc_state.gamma_lut。请参阅 drm_crtc_enable_color_mgmt()

helper_private

中间层私有数据

properties

此 CRTC 的属性跟踪

scaling_filter_property

用于在缩放时应用特定过滤器的属性。

state

此 CRTC 的当前原子状态。

mutex 保护。请注意,非阻塞原子提交在不获取锁的情况下访问当前 CRTC 状态。可以通过 struct drm_atomic_state 指针,请参阅 for_each_oldnew_crtc_in_state()for_each_old_crtc_in_state()for_each_new_crtc_in_state()。或通过原子助手实施的原子提交操作的仔细排序,请参阅 struct drm_crtc_commit

commit_list

跟踪挂起的提交的 drm_crtc_commit 结构列表。受 commit_lock 保护。此列表持有自己的完整引用,正在进行的提交也是如此。

“请注意,状态更改的提交也跟踪在 drm_crtc_state.commit 中。对于访问原子更新中紧随其后的提交,建议仅使用旧 CRTC 状态中的该指针,因为访问它不需要任何锁定或列表遍历。commit_list 仅应用于等待通过 drm_crtc_commit.cleanup_done 发出信号的帧缓冲清理。”

commit_lock

用于保护 commit_list 的自旋锁。

debugfs_entry

此 CRTC 的 Debugfs 目录。

crc

CRC 捕获的配置设置。

fence_context

用于栅栏操作的时间线上下文。

fence_lock

用于保护 fence_context 中栅栏的自旋锁。

fence_seqno

用作 CRTC 时间线上创建的栅栏的单调计数器的 Seqno 变量。

timeline_name

CRTC 的栅栏时间线的名称。

self_refresh_data

保存自刷新助手的状态

通过 drm_self_refresh_helper_init() 初始化。

描述

每个 CRTC 可以有一个或多个与之关联的连接器。此结构允许控制 CRTC。

struct drm_mode_set

CRTC 配置更改的新值

定义:

struct drm_mode_set {
    struct drm_framebuffer *fb;
    struct drm_crtc *crtc;
    struct drm_display_mode *mode;
    uint32_t x;
    uint32_t y;
    struct drm_connector **connectors;
    size_t num_connectors;
};

成员

fb

用于新配置的帧缓冲

crtc

我们将要更改其配置的 CRTC

mode

要使用的模式时序

x

此 CRTC 相对于 fb 的位置

y

此 CRTC 相对于 fb 的位置

connectors

如果可能,要使用此 CRTC 驱动的连接器数组

num_connectors

connectors 数组的大小

描述

这表示旧式 SETCRTC ioctl 的模式设置配置,也在内部使用。原子驱动程序改为使用 drm_atomic_state

drmm_crtc_alloc_with_planes

drmm_crtc_alloc_with_planes (dev, type, member, primary, cursor, funcs, name, ...)

分配并初始化具有指定主平面和光标平面的新 CRTC 对象。

参数

dev

DRM 设备

type

包含结构 drm_crtc 的结构的类型

member

type 中的 drm_crtc 的名称。

primary

CRTC 的主平面

cursor

CRTC 的光标平面

funcs

新 CRTC 的回调

名称

CRTC 名称的 printf 样式格式字符串,如果使用默认名称则为 NULL

...

可变参数

描述

分配并初始化一个新的 crtc 对象。通过使用 drmm_add_action() 注册 drmm_crtc_cleanup() 来自动处理清理。

drm_crtc_funcs.destroy 钩子必须为 NULL。

返回

指向新 crtc 的指针,失败时为 ERR_PTR。

unsigned int drm_crtc_index(const struct drm_crtc *crtc)

查找已注册 CRTC 的索引

参数

const struct drm_crtc *crtc

要查找索引的 CRTC

描述

给定已注册的 CRTC,返回该 CRTC 在 DRM 设备的 CRTC 列表中的索引。

uint32_t drm_crtc_mask(const struct drm_crtc *crtc)

查找已注册 CRTC 的掩码

参数

const struct drm_crtc *crtc

要查找掩码的 CRTC

描述

给定已注册的 CRTC,返回该 CRTC 的掩码位,用于 drm_encoder.possible_crtcsdrm_plane.possible_crtcs 字段。

struct drm_crtc *drm_crtc_find(struct drm_device *dev, struct drm_file *file_priv, uint32_t id)

从其 ID 查找 CRTC 对象

参数

struct drm_device *dev

DRM 设备

struct drm_file *file_priv

用于检查租约的 drm 文件。

uint32_t id

drm_mode_object ID

描述

这可用于从其用户空间 ID 查找 CRTC。仅由驱动程序用于旧式 IOCTL 和接口,如今 KMS 用户空间接口的扩展应使用 drm_property 完成。

drm_for_each_crtc

drm_for_each_crtc (crtc, dev)

迭代所有 CRTC

参数

crtc

作为循环光标的 struct drm_crtc

dev

struct drm_device

描述

迭代 dev 的所有 CRTC。

drm_for_each_crtc_reverse

drm_for_each_crtc_reverse (crtc, dev)

以相反的顺序迭代所有 CRTC

参数

crtc

作为循环光标的 struct drm_crtc

dev

struct drm_device

描述

迭代 dev 的所有 CRTC。

struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx)

查找指定索引的已注册 CRTC

参数

struct drm_device *dev

DRM 设备

int idx

要查找的已注册 CRTC 的索引

描述

给定一个 CRTC 索引,从 DRM 设备匹配索引的 CRTC 列表中返回已注册的 CRTC。这是 drm_crtc_index() 的逆操作。这在垂直同步回调中(例如 drm_driver.enable_vblankdrm_driver.disable_vblank)很有用,因为它们仍然处理索引而不是指向 struct drm_crtc 的指针。”

int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, struct drm_plane *primary, struct drm_plane *cursor, const struct drm_crtc_funcs *funcs, const char *name, ...)

使用指定的 primary 和 cursor 平面初始化新的 CRTC 对象。

参数

struct drm_device *dev

DRM 设备

struct drm_crtc *crtc

要初始化的 CRTC 对象

struct drm_plane *primary

CRTC 的主平面

struct drm_plane *cursor

CRTC 的光标平面

const struct drm_crtc_funcs *funcs

新 CRTC 的回调

const char *name

CRTC 名称的 printf 样式格式字符串,如果使用默认名称则为 NULL

...

可变参数

描述

初始化一个作为驱动程序 crtc 对象的基础部分创建的新对象。驱动程序应该使用此函数,而不是 drm_crtc_init(),它仅为向后兼容尚不支持通用平面的驱动程序提供。对于只有一个平面的非常简单的硬件,请查看 drm_simple_display_pipe_init()drm_crtc_funcs.destroy 钩子应该调用 drm_crtc_cleanup()kfree() crtc 结构。crtc 结构不应使用 devm_kzalloc() 分配。

primarycursor 平面仅与旧版 uAPI 相关,请参阅 drm_crtc.primarydrm_crtc.cursor

注意

考虑使用 drmm_crtc_alloc_with_planes()drmm_crtc_init_with_planes() 而不是 drm_crtc_init_with_planes(),以让 DRM 托管资源基础结构负责清理和释放。

返回

成功时为零,失败时为错误代码。

int drmm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, struct drm_plane *primary, struct drm_plane *cursor, const struct drm_crtc_funcs *funcs, const char *name, ...)

使用指定的 primary 和 cursor 平面初始化新的 CRTC 对象。

参数

struct drm_device *dev

DRM 设备

struct drm_crtc *crtc

要初始化的 CRTC 对象

struct drm_plane *primary

CRTC 的主平面

struct drm_plane *cursor

CRTC 的光标平面

const struct drm_crtc_funcs *funcs

新 CRTC 的回调

const char *name

CRTC 名称的 printf 样式格式字符串,如果使用默认名称则为 NULL

...

可变参数

描述

初始化一个作为驱动程序 crtc 对象的基础部分创建的新对象。驱动程序应该使用此函数,而不是 drm_crtc_init(),它仅为向后兼容尚不支持通用平面的驱动程序提供。对于只有一个平面的非常简单的硬件,请查看 drm_simple_display_pipe_init()

清理工作通过使用 drmm_add_action() 注册 drmm_crtc_cleanup() 自动处理。crtc 结构应使用 drmm_kzalloc() 分配。

drm_crtc_funcs.destroy 钩子必须为 NULL。

primarycursor 平面仅与旧版 uAPI 相关,请参阅 drm_crtc.primarydrm_crtc.cursor

返回

成功时为零,失败时为错误代码。

void drm_crtc_cleanup(struct drm_crtc *crtc)

清理核心 crtc 的使用

参数

struct drm_crtc *crtc

要清理的 CRTC

描述

此函数会清理 crtc 并将其从 DRM 模式设置核心中移除。请注意,该函数不会释放 crtc 结构本身,这是调用者的责任。

int drm_mode_set_config_internal(struct drm_mode_set *set)

调用 drm_mode_config_funcs.set_config 的辅助函数

参数

struct drm_mode_set *set

要设置的 modeset 配置

描述

这是一个小的辅助函数,用于包装对 drm_mode_config_funcs.set_config 驱动程序接口的内部调用。它唯一添加的是正确的引用计数方式。

这应该只由非原子遗留驱动程序使用。

返回

成功返回零,失败返回负 errno。

int drm_crtc_check_viewport(const struct drm_crtc *crtc, int x, int y, const struct drm_display_mode *mode, const struct drm_framebuffer *fb)

检查帧缓冲是否足够大,以满足 CRTC 视口的需求

参数

const struct drm_crtc *crtc

将显示帧缓冲的 CRTC

int x

x 方向的平移

int y

y 方向的平移

const struct drm_display_mode *mode

帧缓冲将在此模式下显示

const struct drm_framebuffer *fb

要检查大小的帧缓冲

int drm_crtc_create_scaling_filter_property(struct drm_crtc *crtc, unsigned int supported_filters)

创建一个新的缩放过滤器属性

参数

struct drm_crtc *crtc

drm CRTC

unsigned int supported_filters

支持的缩放过滤器位掩码,必须包括 BIT(DRM_SCALING_FILTER_DEFAULT)。

描述

此函数允许驱动程序在给定的 CRTC 上启用缩放过滤器属性。

返回

成功则返回零,失败则返回 -errno

颜色管理函数参考

u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n)

参数

u64 user_input

输入值

u32 m

整数位的数量,仅支持 m <= 32,包括符号位

u32 n

小数位的数量,仅支持 n <= 32

描述

将 S31.32 符号幅度转换为 Qm.n(有符号的 2 的补码)并进行钳位。符号位 BIT(m+n-1) 及以上对于正值是 0,对于负值是 1,值的范围是 [-2^(m-1), 2^(m-1) - 2^-n]

例如,一个 Q3.12 格式的数字:- 需要的位数:3 + 12 = 15 位 - 范围:[-2^2, 2^2 - 2^-15]

注意

如果所有位精度都用于表示小数,则 m 可以为零

例如 Q0.32 这样的位

void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, uint degamma_lut_size, bool has_ctm, uint gamma_lut_size)

启用颜色管理属性

参数

struct drm_crtc *crtc

DRM CRTC

uint degamma_lut_size

反伽玛查找表的大小(在 CSC 之前)

bool has_ctm

是否为 CSC 矩阵附加 ctm_property

uint gamma_lut_size

伽玛查找表的大小(在 CSC 之后)

描述

此函数允许驱动程序在 CRTC 上启用颜色校正属性。这包括用户空间可以设置的 3 个反伽玛、csc 和伽玛属性,以及 2 个大小属性以通知用户空间查找表的大小。每个属性都是可选的。只有当伽玛和反伽玛属性的大小不为 0 时才会附加它们,并且只有当 has_ctm 为 true 时才会附加 ctm_property。

int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size)

设置伽玛表大小

参数

struct drm_crtc *crtc

要设置伽玛表大小的 CRTC

int gamma_size

伽玛表的大小

描述

支持伽玛表的驱动程序应在初始化 CRTC 时将其设置为支持的伽玛表大小。目前,drm 内核仅支持固定的伽玛表大小。

返回

成功返回零,失败返回负 errno。

int drm_plane_create_color_properties(struct drm_plane *plane, u32 supported_encodings, u32 supported_ranges, enum drm_color_encoding default_encoding, enum drm_color_range default_range)

颜色编码相关的平面属性

参数

struct drm_plane *plane

平面对象

u32 supported_encodings

指示支持的颜色编码的位字段

u32 supported_ranges

指示支持的颜色范围的位字段

enum drm_color_encoding default_encoding

默认颜色编码

enum drm_color_range default_range

默认颜色范围

描述

创建并将特定于平面的 COLOR_ENCODING 和 COLOR_RANGE 属性附加到 plane。支持的编码和范围应在 supported_encodings 和 supported_ranges 位掩码中提供。位掩码中设置的每个位都表示其作为枚举值的数字被支持。

int drm_color_lut_check(const struct drm_property_blob *lut, u32 tests)

检查查找表的有效性

参数

const struct drm_property_blob *lut

包含要检查的 LUT 的属性 blob

u32 tests

要运行的测试的位掩码

描述

帮助程序检查用户空间提供的查找表是否有效并满足硬件要求。驱动程序传递一个位掩码,指示应执行 drm_color_lut_tests 中的哪些测试。

成功返回 0,失败返回 -EINVAL。

u32 drm_color_lut_extract(u32 user_input, int bit_precision)

钳位并舍入 LUT 条目

参数

u32 user_input

输入值

int bit_precision

硬件 LUT 支持的位数

描述

提取用户提供的反伽玛/伽玛 LUT 值(以 drm_color_lut 条目的形式)并将其舍入到硬件支持的精度,遵循 OpenGL int<->float 转换规则(例如,参见 OpenGL 4.6 规范 - 2.3.5 定点数据转换)。

int drm_color_lut_size(const struct drm_property_blob *blob)

计算 LUT 中的条目数

参数

const struct drm_property_blob *blob

包含 LUT 的 blob

返回

存储在 blob 中的颜色 LUT 中的条目数。

enum drm_color_lut_tests

要执行的特定于硬件的 LUT 测试

常量

DRM_COLOR_LUT_EQUAL_CHANNELS

检查 LUT 的所有条目的红色、绿色和蓝色通道是否都具有相同的值。适用于硬件仅接受每个 LUT 条目的单个值,并假定该值应用于所有三个颜色分量的情况。

DRM_COLOR_LUT_NON_DECREASING

检查 LUT 的条目是否总是平坦或递增(从不递减)。

描述

drm_color_lut_check() 函数使用此处的值的位掩码来确定要对用户空间提供的 LUT 应用哪些测试。

帧缓冲区抽象

帧缓冲区是抽象内存对象,为扫描到 CRTC 提供像素源。应用程序通过 DRM_IOCTL_MODE_ADDFB(2) ioctl 显式请求创建帧缓冲区,并接收一个不透明的句柄,该句柄可以传递给 KMS CRTC 控制、平面配置和页面翻转函数。

帧缓冲区依赖于底层内存管理器来分配后备存储。创建帧缓冲区时,应用程序通过 struct drm_mode_fb_cmd2 参数传递内存句柄(或多平面格式的内存句柄列表)。对于使用 GEM 作为其用户空间缓冲区管理接口的驱动程序,这将是一个 GEM 句柄。但是,驱动程序可以自由使用自己的后备存储对象句柄,例如,vmwgfx 直接向用户空间公开特殊的 TTM 句柄,因此在创建 ioctl 中期望 TTM 句柄而不是 GEM 句柄。

帧缓冲区使用 struct drm_framebuffer 进行跟踪。它们使用 drm_framebuffer_init() 发布 - 调用该函数后,用户空间可以使用和访问帧缓冲区对象。辅助函数 drm_helper_mode_fill_fb_struct() 可用于预填充所需的元数据字段。

drm 帧缓冲区的生命周期由引用计数控制,驱动程序可以使用 drm_framebuffer_get() 获取额外的引用,并使用 drm_framebuffer_put() 再次释放它们。对于永远不会丢弃最后一个引用的驱动程序私有帧缓冲区(例如,当 struct drm_framebuffer 嵌入到 fbdev 辅助结构中时,对于 fbdev 帧缓冲区),驱动程序可以在模块卸载时使用 drm_framebuffer_unregister_private() 手动清理帧缓冲区。但是不建议这样做,最好有一个独立的 struct drm_framebuffer

帧缓冲区函数参考

struct drm_framebuffer_funcs

帧缓冲区钩子

定义:

struct drm_framebuffer_funcs {
    void (*destroy)(struct drm_framebuffer *framebuffer);
    int (*create_handle)(struct drm_framebuffer *fb,struct drm_file *file_priv, unsigned int *handle);
    int (*dirty)(struct drm_framebuffer *framebuffer,struct drm_file *file_priv, unsigned flags,unsigned color, struct drm_clip_rect *clips, unsigned num_clips);
};

成员

destroy

清理帧缓冲区资源,特别是取消引用后备存储。核心保证为通过调用 drm_mode_config_funcs.fb_create 成功创建的每个帧缓冲区调用此函数。驱动程序还必须调用 drm_framebuffer_cleanup() 来释放此帧缓冲区的 DRM 核心资源。

create_handle

在驱动程序特定的缓冲区管理器(GEM 或 TTM)中为传入的 struct drm_file 创建一个有效的缓冲区句柄。核心使用它来实现 GETFB IOCTL,它(对于足够特权的用户)也返回一个本机缓冲区句柄。这可以通过将当前屏幕内容复制到私有缓冲区并在该缓冲区和新内容之间混合来实现模式设置客户端之间的无缝转换。

基于 GEM 的驱动程序应调用 drm_gem_handle_create() 来创建句柄。

返回

成功返回 0,失败返回负错误代码。

dirty

用于 dirty fb IOCTL 的可选回调。

用户空间可以通过此回调通知驱动程序帧缓冲区的某个区域已更改,应刷新到显示硬件。这也可以在内部使用,例如通过 fbdev 仿真,尽管目前情况并非如此。

有关更多信息,请参见 drm_mode.h 中的 struct drm_mode_fb_dirty_cmd 文档,因为所有语义和参数都与此函数有一对一的映射。

原子驱动程序应使用 drm_atomic_helper_dirtyfb() 来实现此钩子。

返回

成功返回 0,失败返回负错误代码。

struct drm_framebuffer

帧缓冲区对象

定义:

struct drm_framebuffer {
    struct drm_device *dev;
    struct list_head head;
    struct drm_mode_object base;
    char comm[TASK_COMM_LEN];
    const struct drm_format_info *format;
    const struct drm_framebuffer_funcs *funcs;
    unsigned int pitches[DRM_FORMAT_MAX_PLANES];
    unsigned int offsets[DRM_FORMAT_MAX_PLANES];
    uint64_t modifier;
    unsigned int width;
    unsigned int height;
    int flags;
    struct list_head filp_head;
    struct drm_gem_object *obj[DRM_FORMAT_MAX_PLANES];
};

成员

dev

此帧缓冲区所属的 DRM 设备

head

放置在 drm_mode_config.fb_list 上,访问受 drm_mode_config.fb_lock 保护。

基础

基本模式设置对象结构,包含引用计数。

comm

分配 fb 的进程的名称,用于 fb 转储。

格式

帧缓冲区格式信息

funcs

帧缓冲区 vfunc 表

pitches

每个缓冲区的行跨度。对于用户空间创建的对象,这是从 drm_mode_fb_cmd2 复制的。

offsets

每个缓冲区,从缓冲区起始位置到实际像素数据的字节偏移量。对于用户空间创建的对象,这是从 drm_mode_fb_cmd2 复制的。

请注意,这是一个线性偏移量,并且不考虑每个 **modifier** 的平铺或缓冲区布局。它旨在用于此帧缓冲区平面的实际像素数据以偏移量开始的情况,例如,当多个平面在同一后备存储缓冲区对象中分配时。对于平铺布局,这通常意味着其 **offsets** 必须至少与平铺大小对齐,但硬件通常有更严格的要求。

这不应用于指定缓冲区数据中的 x/y 像素偏移量(即使对于线性缓冲区)。指定 x/y 像素偏移量是通过 struct drm_plane_state 中的源矩形完成的。

modifier

数据布局修饰符。它用于描述平铺,或辅助缓冲区的特殊布局(如压缩)。对于用户空间创建的对象,这是从 drm_mode_fb_cmd2 复制的。

width

帧缓冲区可见区域的逻辑宽度,以像素为单位。

height

帧缓冲区可见区域的逻辑高度,以像素为单位。

标志

帧缓冲区标志,如 DRM_MODE_FB_INTERLACED 或 DRM_MODE_FB_MODIFIERS。

filp_head

放置在 drm_file.fbs 上,受 drm_file.fbs_lock 保护。

obj

支持帧缓冲区的 GEM 对象,每个平面一个(可选)。

这由 GEM 帧缓冲区辅助函数使用,例如,请参见 drm_gem_fb_create()

描述

请注意,为了驱动程序内部的利益,fb 是引用计数的,例如,某些硬件,禁用 CRTC/平面是异步的,并且扫描输出直到下一个 vblank 才真正完成。因此,某些清理(如释放后备 GEM bo(s) 上的引用)应延迟。在这种情况下,即使已从用户空间角度删除 fb,驱动程序也希望保留对 fb 的引用。请参见 drm_framebuffer_get()drm_framebuffer_put()

引用计数存储在模式对象 **base** 中。

void drm_framebuffer_get(struct drm_framebuffer *fb)

获取帧缓冲区引用

参数

struct drm_framebuffer *fb

DRM 帧缓冲区

描述

此函数会增加帧缓冲区的引用计数。

void drm_framebuffer_put(struct drm_framebuffer *fb)

释放帧缓冲区的引用。

参数

struct drm_framebuffer *fb

DRM 帧缓冲区

描述

此函数会递减帧缓冲区的引用计数,如果引用计数降为零,则会释放该帧缓冲区。

uint32_t drm_framebuffer_read_refcount(const struct drm_framebuffer *fb)

读取帧缓冲区的引用计数。

参数

const struct drm_framebuffer *fb

帧缓冲区

描述

此函数返回帧缓冲区的引用计数。

void drm_framebuffer_assign(struct drm_framebuffer **p, struct drm_framebuffer *fb)

存储对 fb 的引用

参数

struct drm_framebuffer **p

存储帧缓冲区的位置

struct drm_framebuffer *fb

新的帧缓冲区(可能为 NULL)

描述

此函数设置存储帧缓冲区引用的位置,并取消引用先前存储在该位置的帧缓冲区。

struct drm_afbc_framebuffer

一个特殊的 afbc 帧缓冲区对象

定义:

struct drm_afbc_framebuffer {
    struct drm_framebuffer base;
    u32 block_width;
    u32 block_height;
    u32 aligned_width;
    u32 aligned_height;
    u32 offset;
    u32 afbc_size;
};

成员

基础

基本帧缓冲区结构。

block_width

单个 afbc 块的宽度

block_height

单个 afbc 块的高度

aligned_width

对齐的帧缓冲区宽度

aligned_height

对齐的帧缓冲区高度

offset

第一个 afbc 标头的偏移量

afbc_size

afbc 缓冲区的最小大小

描述

一个派生自 struct drm_framebuffer 的类,专用于 afbc 用例。

int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_framebuffer_funcs *funcs)

初始化帧缓冲区

参数

struct drm_device *dev

DRM 设备

struct drm_framebuffer *fb

要初始化的帧缓冲区

const struct drm_framebuffer_funcs *funcs

...使用这些函数

描述

为帧缓冲区的父模式对象分配一个 ID,设置其模式函数和设备文件,并将其添加到主 fd 列表。

重要提示:此函数发布 fb 并使其可供其他用户并发访问。这意味着此时 fb _必须_ 完全设置好 - 因为所有 fb 属性在其生命周期内都是不变的,因此不需要进一步的锁定,而只需要正确的引用计数。

返回

成功时为零,失败时为错误代码。

struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, struct drm_file *file_priv, uint32_t id)

查找 drm 帧缓冲区并获取引用

参数

struct drm_device *dev

drm 设备

struct drm_file *file_priv

用于检查租约的 drm 文件。

uint32_t id

fb 对象的 ID

描述

如果成功,这将获取对帧缓冲区的额外引用 - 调用者需要确保最终使用 drm_framebuffer_put() 再次取消引用返回的帧缓冲区。

void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)

从查找 idr 中注销私有 fb

参数

struct drm_framebuffer *fb

要注销的 fb

描述

驱动程序在清理驱动程序私有帧缓冲区时(例如,用于 fbdev 的帧缓冲区)需要调用此函数。请注意,调用者必须持有自己的引用,即该对象不能通过此调用销毁(因为它会导致锁定反转)。

注意

此函数已弃用。对于驱动程序私有帧缓冲区,不建议将帧缓冲区结构信息嵌入 fbdev 结构,而应首选帧缓冲区指针,并且在要清理帧缓冲区时应调用 drm_framebuffer_put()

void drm_framebuffer_cleanup(struct drm_framebuffer *fb)

删除帧缓冲区对象

参数

struct drm_framebuffer *fb

要删除的帧缓冲区

描述

清理帧缓冲区。此函数旨在从驱动程序的 drm_framebuffer_funcs.destroy 回调中使用。它还可以用于清理嵌入到更大结构中的驱动程序私有帧缓冲区。

请注意,此函数不会从活动使用中删除 fb - 如果它仍然在任何地方使用,则可能会导致混乱,因为用户空间可能会在 id 上调用 getfb 并返回 -EINVAL。显然,在驱动程序卸载时无需担心。

此外,帧缓冲区不会从查找 idr 中删除 - 对于用户创建的帧缓冲区,这将发生在 rmfb ioctl 中。对于驱动程序私有对象(例如,用于 fbdev),驱动程序需要显式调用 drm_framebuffer_unregister_private。

void drm_framebuffer_remove(struct drm_framebuffer *fb)

删除并取消引用帧缓冲区对象

参数

struct drm_framebuffer *fb

要删除的帧缓冲区

描述

扫描 **dev** 的 mode_config 中的所有 CRTC 和平面。如果它们正在使用 **fb**,则会将其删除,并将其设置为 NULL。然后删除对传入帧缓冲区的引用。可能需要模式设置锁。

请注意,如果调用者持有对帧缓冲区的最后一个引用,则此函数会优化清理。在这种情况下,也保证不会获取模式设置锁。

DRM 格式处理

在 DRM 子系统中,帧缓冲区像素格式使用 include/uapi/drm/drm_fourcc.h 中定义的 fourcc 代码进行描述。除了 fourcc 代码之外,还可以选择提供格式修饰符,以便进一步描述缓冲区的格式 - 例如平铺或压缩。

格式修饰符

格式修饰符与 fourcc 代码结合使用,形成唯一的 fourcc:modifier 对。此 format:modifier 对必须完全定义缓冲区的格式和数据布局,并且应该是描述该特定缓冲区的唯一方法。

应避免使用描述相同布局的多个 fourcc:modifier 对,因为此类别名可能会导致不同的驱动程序为相同的数据格式公开不同的名称,从而迫使用户空间了解它们是别名。

格式修饰符可能会更改缓冲区的任何属性,包括平面数量和/或所需的分配大小。格式修饰符是供应商命名空间的,因此 fourcc 代码和修饰符之间的关系特定于所使用的修饰符。例如,某些修饰符可能会保留 fourcc 代码的含义 - 例如平面数量 - 而其他修饰符可能不会。

修饰符必须唯一地编码缓冲区布局。换句话说,缓冲区必须仅匹配单个修饰符。修饰符不得是另一个修饰符布局的子集。例如,在修饰符中编码 pitch 对齐是不正确的:缓冲区可能匹配 64 像素对齐的修饰符和 32 像素对齐的修饰符。也就是说,修饰符可以具有隐式的最小要求。

对于 fourcc 代码和修饰符的组合可以别名的修饰符,需要定义一个规范对,并由所有驱动程序使用。如果所有组合都可能导致混淆并降低不必要的互操作性,则还鼓励使用首选组合。后者的一个例子是 AFBC,其中 ABGR 布局优先于 ARGB 布局。

修饰符用户有两种:

  • 内核和用户空间驱动程序:对于驱动程序来说,修饰符不应该别名很重要,否则两个驱动程序可能支持相同的格式,但使用不同的别名,从而阻止它们以高效的格式共享缓冲区。

  • 与 KMS/GBM/EGL/Vulkan/etc 接口的更高级程序:这些用户将修饰符视为它们可以检查相等性和交叉的不透明令牌。这些用户不需要知道推理修饰符值(即,不希望他们从修饰符中提取信息)。

供应商应尽可能详细地记录其修饰符的使用情况,以确保跨设备、驱动程序和应用程序的最大兼容性。

格式修饰符代码的权威列表位于 include/uapi/drm/drm_fourcc.h 中。

开源用户豁免

因为这是 GL、Vulkan 扩展和其他标准引用的像素格式和修饰符的权威来源,因此开源和闭源驱动程序堆栈都会使用它们,所以通常的上游内核或开源用户空间用户的要求不适用。

为了尽可能确保跨堆栈的兼容性,并避免与不兼容的枚举混淆,所有相关驱动程序堆栈的利益相关者应批准添加内容。

格式函数参考

DRM_FORMAT_MAX_PLANES

DRM_FORMAT_MAX_PLANES

DRM 格式可以拥有的最大平面数

struct drm_format_info

有关 DRM 格式的信息

定义:

struct drm_format_info {
    u32 format;
    u8 depth;
    u8 num_planes;
    union {
        u8 cpp[DRM_FORMAT_MAX_PLANES];
        u8 char_per_block[DRM_FORMAT_MAX_PLANES];
    };
    u8 block_w[DRM_FORMAT_MAX_PLANES];
    u8 block_h[DRM_FORMAT_MAX_PLANES];
    u8 hsub;
    u8 vsub;
    bool has_alpha;
    bool is_yuv;
    bool is_color_indexed;
};

成员

格式

4CC 格式标识符 (DRM_FORMAT_*)

深度

颜色深度(每个像素的位数,不包括填充位),仅对 RGB 格式的子集有效。这是一个遗留字段,请勿在新代码中使用,对于新格式请设置为 0。

num_planes

颜色平面数(1 到 3)

{unnamed_union}

匿名

cpp

每个像素的字节数(每个平面),它与 char_per_block 别名。不建议使用,而建议使用三元组 char_per_blockblock_wblock_h 来更好地描述像素格式。

char_per_block

每个块的字节数(每个平面),其中块定义为像素的矩形,这些像素存储在字节对齐的内存区域中。与 block_wblock_h 一起,用于正确描述平铺格式中的平铺,或描述打包格式中的像素组,对于这些格式,单个像素所需的内存不是字节对齐的。

保留 cpp 是出于历史原因,因为在驱动程序中有许多地方使用了它。在 drm 核心中,对于通用代码路径,首选方法是使用 char_per_blockdrm_format_info_block_width()drm_format_info_block_height(),这样可以以相同的方式处理块格式和非块格式。

对于仅打算与非线性修饰符一起使用的格式,通用格式表中 cppchar_per_block 都必须为 0。如果驱动程序希望核心验证 pitch,则可以从其 drm_mode_config.get_format_info 钩子提供准确的信息。

block_w

块宽度(以像素为单位),旨在通过 drm_format_info_block_width() 访问

block_h

块高度(以像素为单位),旨在通过 drm_format_info_block_height() 访问

hsub

水平色度子采样因子

vsub

垂直色度子采样因子

has_alpha

该格式是否嵌入 alpha 分量?

is_yuv

这是一个 YUV 格式吗?

is_color_indexed

这是一个颜色索引格式吗?

bool drm_format_info_is_yuv_packed(const struct drm_format_info *info)

检查格式信息是否与以单平面布局的 YUV 格式匹配

参数

const struct drm_format_info *info

格式信息

返回

一个布尔值,指示格式信息是否与打包的 YUV 格式匹配。

bool drm_format_info_is_yuv_semiplanar(const struct drm_format_info *info)

检查格式信息是否与以两个平面布局的 YUV 格式(亮度和色度)匹配

参数

const struct drm_format_info *info

格式信息

返回

一个布尔值,指示格式信息是否与半平面 YUV 格式匹配。

bool drm_format_info_is_yuv_planar(const struct drm_format_info *info)

检查格式信息是否与以三个平面布局的 YUV 格式(每个 YUV 分量一个平面)匹配

参数

const struct drm_format_info *info

格式信息

返回

一个布尔值,指示格式信息是否与平面 YUV 格式匹配。

bool drm_format_info_is_yuv_sampling_410(const struct drm_format_info *info)

检查格式信息是否与 4:1:0 子采样的 YUV 格式匹配

参数

const struct drm_format_info *info

格式信息

返回

一个布尔值,指示格式信息是否与 4:1:0 子采样的 YUV 格式匹配。

bool drm_format_info_is_yuv_sampling_411(const struct drm_format_info *info)

检查格式信息是否与 4:1:1 子采样的 YUV 格式匹配

参数

const struct drm_format_info *info

格式信息

返回

一个布尔值,指示格式信息是否与 4:1:1 子采样的 YUV 格式匹配。

bool drm_format_info_is_yuv_sampling_420(const struct drm_format_info *info)

检查格式信息是否与 4:2:0 子采样的 YUV 格式匹配

参数

const struct drm_format_info *info

格式信息

返回

一个布尔值,指示格式信息是否与 4:2:0 子采样的 YUV 格式匹配。

bool drm_format_info_is_yuv_sampling_422(const struct drm_format_info *info)

检查格式信息是否与 4:2:2 子采样的 YUV 格式匹配

参数

const struct drm_format_info *info

格式信息

返回

一个布尔值,指示格式信息是否与 4:2:2 子采样的 YUV 格式匹配。

bool drm_format_info_is_yuv_sampling_444(const struct drm_format_info *info)

检查格式信息是否与 4:4:4 子采样的 YUV 格式匹配

参数

const struct drm_format_info *info

格式信息

返回

一个布尔值,指示格式信息是否与 4:4:4 子采样的 YUV 格式匹配。

int drm_format_info_plane_width(const struct drm_format_info *info, int width, int plane)

给定第一个平面的情况下,平面的宽度

参数

const struct drm_format_info *info

像素格式信息

int width

第一个平面的宽度

int plane

平面索引

返回

plane 的宽度,前提是第一个平面的宽度为 width

int drm_format_info_plane_height(const struct drm_format_info *info, int height, int plane)

给定第一个平面的高度,计算其他平面的高度

参数

const struct drm_format_info *info

像素格式信息

int height

第一个平面的高度

int plane

平面索引

返回

在第一个平面的高度为 **height** 的情况下,计算 **plane** 的高度。

uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)

从传统的描述计算 drm fourcc 代码

参数

uint32_t bpp

每个像素的位数

uint32_t depth

每个像素的位深度

描述

根据给定的 **bpp** / **depth** 值计算 drm fourcc 像素格式代码。

uint32_t drm_driver_legacy_fb_format(struct drm_device *dev, uint32_t bpp, uint32_t depth)

从传统的描述计算 drm fourcc 代码

参数

struct drm_device *dev

DRM 设备

uint32_t bpp

每个像素的位数

uint32_t depth

每个像素的位深度

描述

根据给定的 **bpp** / **depth** 值计算 drm fourcc 像素格式代码。与 drm_mode_legacy_fb_format() 不同,此函数会查看驱动程序的 mode_config,并根据 drm_mode_config.quirk_addfb_prefer_host_byte_order 标志返回小端字节序或主机字节序的帧缓冲区格式。

uint32_t drm_driver_color_mode_format(struct drm_device *dev, unsigned int color_mode)

从颜色模式计算 DRM 4CC 代码

参数

struct drm_device *dev

DRM 设备

unsigned int color_mode

命令行颜色模式

描述

使用 drm_driver_color_mode() 为给定的颜色模式计算 DRM 4CC 像素格式代码。 颜色模式采用内核命令行使用的格式。它在一个值中指定每个像素的位数和颜色深度。

在 fbdev 仿真代码中很有用,因为它处理这些值。该助手不考虑 YUV 或其他复杂的格式。这意味着仅支持传统格式(fmt->depth 是一个传统字段),但帧缓冲区仿真只能处理此类格式,特别是 RGB/BGA 格式。

const struct drm_format_info *drm_format_info(u32 format)

查询给定格式的信息

参数

u32 format

像素格式 (DRM_FORMAT_*)

描述

调用者应仅将受支持的像素格式传递给此函数。 不支持的像素格式将在内核日志中生成警告。

返回

描述像素格式的 struct drm_format_info 的实例,如果不支持该格式,则为 NULL。

const struct drm_format_info *drm_get_format_info(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd)

查询给定帧缓冲区配置的信息

参数

struct drm_device *dev

DRM 设备

const struct drm_mode_fb_cmd2 *mode_cmd

来自用户空间帧缓冲区创建请求的元数据

返回

描述像素格式的 struct drm_format_info 的实例,如果不支持该格式,则为 NULL。

unsigned int drm_format_info_block_width(const struct drm_format_info *info, int plane)

块的像素宽度。

参数

const struct drm_format_info *info

像素格式信息

int plane

平面索引

返回

一个块的像素宽度,取决于平面索引。

unsigned int drm_format_info_block_height(const struct drm_format_info *info, int plane)

块的像素高度

参数

const struct drm_format_info *info

像素格式信息

int plane

平面索引

返回

一个块的像素高度,取决于平面索引。

unsigned int drm_format_info_bpp(const struct drm_format_info *info, int plane)

每个像素的位数

参数

const struct drm_format_info *info

像素格式信息

int plane

平面索引

返回

每个像素的实际位数,取决于平面索引。

uint64_t drm_format_info_min_pitch(const struct drm_format_info *info, int plane, unsigned int buffer_width)

计算最小的所需跨距(以字节为单位)

参数

const struct drm_format_info *info

像素格式信息

int plane

平面索引

unsigned int buffer_width

缓冲区的像素宽度

返回

通过考虑像素格式信息和缓冲区宽度,计算缓冲区所需的最小跨距(以字节为单位)。

Dumb 缓冲区对象

KMS API 没有标准化后备存储对象的创建,而是将其留给驱动程序特定的 ioctl。此外,即使对于基于 GEM 的驱动程序,实际创建缓冲区对象也是通过驱动程序特定的 ioctl 完成的 - GEM 仅具有用于共享和销毁对象的通用用户空间接口。虽然对于包含设备特定用户空间组件(例如在 libdrm 中)的成熟图形堆栈来说这不是问题,但此限制使基于 DRM 的早期启动图形变得不必要的复杂。

Dumb 对象通过提供一个用于创建适用于扫描输出的哑缓冲区的标准 API 来部分缓解此问题,然后可以使用该 API 来创建 KMS 帧缓冲区。

为了支持哑对象,驱动程序必须实现 drm_driver.dumb_createdrm_driver.dumb_map_offset 操作(如果未设置,则后者默认为 drm_gem_dumb_map_offset())。不使用 GEM 句柄的驱动程序还需要实现 drm_driver.dumb_destroy 操作。有关详细信息,请参阅回调。

请注意,哑对象可能不用于 GPU 加速,正如某些 ARM 嵌入式平台上尝试的那样。此类驱动程序确实必须具有硬件特定的 ioctl 来分配合适的缓冲区对象。

平面抽象

平面表示一个图像源,可以在扫描输出过程中与 CRTC 混合或叠加在其之上。平面从 drm_framebuffer 对象获取其输入数据。平面本身指定该图像的裁剪和缩放,以及它在显示管线的可见区域上的位置,该区域由 drm_crtc 表示。平面还可以具有额外的属性,指定像素如何定位和混合,例如旋转或 Z 轴位置。所有这些属性都存储在 drm_plane_state 中。

除非明确指定(通过 CRTC 属性或其他方式),否则 CRTC 的活动区域默认情况下将为黑色。这意味着未被平面覆盖的活动区域部分将为黑色,并且任何平面与 CRTC 背景的 alpha 混合将在最低 zpos 处与黑色混合。

要创建一个平面,KMS 驱动程序会分配并清零 struct drm_plane 的实例(可能作为较大结构的一部分),并通过调用 drm_universal_plane_init() 注册它。

每个平面都有一个类型,请参阅 enum drm_plane_type。一个平面可以与多个 CRTC 兼容,请参阅 drm_plane.possible_crtcs

每个 CRTC 必须有一个独特的主平面,用户空间可以附加该平面来启用 CRTC。换句话说,用户空间必须能够同时将不同的主平面附加到每个 CRTC。主平面仍然可以与多个 CRTC 兼容。主平面的数量必须与 CRTC 的数量完全相同。

传统的 uAPI 不会直接暴露主平面和光标平面。DRM 核心依赖驱动程序来设置用于传统 IOCTL 的主平面和可选的光标平面。这是通过调用 drm_crtc_init_with_planes() 完成的。所有驱动程序都必须为每个 CRTC 提供一个主平面,以避免让传统的用户空间感到意外。

平面函数参考

struct drm_plane_state

可变平面状态

定义:

struct drm_plane_state {
    struct drm_plane *plane;
    struct drm_crtc *crtc;
    struct drm_framebuffer *fb;
    struct dma_fence *fence;
    int32_t crtc_x;
    int32_t crtc_y;
    uint32_t crtc_w, crtc_h;
    uint32_t src_x;
    uint32_t src_y;
    uint32_t src_h, src_w;
    int32_t hotspot_x, hotspot_y;
    u16 alpha;
    uint16_t pixel_blend_mode;
    unsigned int rotation;
    unsigned int zpos;
    unsigned int normalized_zpos;
    enum drm_color_encoding color_encoding;
    enum drm_color_range color_range;
    struct drm_property_blob *fb_damage_clips;
    bool ignore_damage_clips;
    struct drm_rect src, dst;
    bool visible;
    enum drm_scaling_filter scaling_filter;
    struct drm_crtc_commit *commit;
    struct drm_atomic_state *state;
    bool color_mgmt_changed : 1;
};

成员

plane

指向平面的反向指针

crtc

当前绑定的 CRTC,如果禁用则为 NULL。不要直接写入此项,请使用 drm_atomic_set_crtc_for_plane()

fb

当前绑定的帧缓冲区。不要直接写入此项,请使用 drm_atomic_set_fb_for_plane()

栅栏

在扫描输出 fb 之前要等待的可选栅栏。当用户空间使用显式栅栏时,核心原子代码将设置此项。不要直接为驱动程序的隐式栅栏写入此字段。

驱动程序应将任何隐式栅栏存储在它们的 drm_plane_helper_funcs.prepare_fb 回调中。有关合适的助手,请参阅 drm_gem_plane_helper_prepare_fb()

crtc_x

平面在 crtc 上的可见部分的左侧位置,带符号的目标位置允许它部分位于屏幕外。

crtc_y

平面在 crtc 上的可见部分的上方位置,带符号的目标位置允许它部分位于屏幕外。

crtc_w

平面在 crtc 上的可见部分的宽度

crtc_h

平面在 crtc 上的可见部分的高度

src_x

平面内平面可见部分的左侧位置(以 16.16 定点数表示)。

src_y

平面内平面可见部分的上方位置(以 16.16 定点数表示)。

src_h

平面可见部分的高度(以 16.16 表示)

src_w

平面可见部分的宽度(以 16.16 表示)

hotspot_x

鼠标光标热点的 x 偏移量

hotspot_y

鼠标光标热点的 y 偏移量

alpha

平面的不透明度,0 表示完全透明,0xffff 表示完全不透明。有关更多详细信息,请参阅 drm_plane_create_alpha_property()

pixel_blend_mode

alpha 混合方程式选择,描述如何将当前平面的像素与背景合成。值可以是 DRM_MODE_BLEND_* 之一

rotation

平面的旋转。有关更多详细信息,请参阅 drm_plane_create_rotation_property()

zpos

给定平面在 crtc 上的优先级(可选)。

用户空间可以设置可变的 zpos 属性,以便同一 CRTC 上的多个活动平面具有相同的 zpos 值。这是一个用户空间错误,但驱动程序可以通过比较平面对象 ID 来解决冲突;ID 较高的平面堆叠在 ID 较低的平面之上。

有关更多详细信息,请参阅 drm_plane_create_zpos_property()drm_plane_create_zpos_immutable_property()

normalized_zpos

zpos 的归一化值:唯一,范围从 0 到 N-1,其中 N 是给定 crtc 的活动平面数。请注意,驱动程序必须设置 drm_mode_config.normalize_zpos 或调用 drm_atomic_normalize_zpos(),才能在信任此值之前更新此值。

color_encoding

非 RGB 格式的颜色编码

color_range

非 RGB 格式的颜色范围

fb_damage_clips

将损坏(自上次平面更新以来平面帧缓冲区中发生更改的区域)表示为 drm_mode_rect 数组的 Blob,以附加帧缓冲区的帧缓冲区坐标表示。请注意,与平面 src 不同,损坏剪辑不是以 16.16 定点表示的。

有关访问这些剪辑的信息,请参阅 drm_plane_get_damage_clips()drm_plane_get_damage_clips_count()

ignore_damage_clips

驱动程序设置以指示 drm_atomic_helper_damage_iter_init() 助手应忽略 fb_damage_clips blob 属性。

有关更多信息,请参阅 损坏跟踪属性

src

平面的源坐标(以 16.16 表示)。

当使用 drm_atomic_helper_check_plane_state() 时,坐标会被裁剪,但当硬件自动执行裁剪时,驱动程序可以选择改为使用未裁剪的坐标。

dst

平面裁剪后的目标坐标。

当使用 drm_atomic_helper_check_plane_state() 时,坐标会被裁剪,但当硬件自动执行裁剪时,驱动程序可以选择改为使用未裁剪的坐标。

visible

平面的可见性。即使 fb!=NULL 且 crtc!=NULL,由于裁剪,这也可以为 false。

scaling_filter

要应用的缩放滤镜

commit

跟踪挂起的提交以防止释放后使用条件,并用于异步平面更新。

可以为 NULL。

state

指向全局 drm_atomic_state 的后向指针

color_mgmt_changed

颜色管理属性已更改。原子助手和驱动程序使用此属性来控制原子提交控制流。

描述

请注意,目标坐标 crtc_xcrtc_ycrtc_hcrtc_w 以及源坐标 src_xsrc_ysrc_hsrc_w 是用户空间提供的原始坐标。驱动程序应使用 drm_atomic_helper_check_plane_state() 并且仅使用 srcdst 中的派生矩形来编程硬件。

struct drm_plane_funcs

驱动程序平面控制函数

定义:

struct drm_plane_funcs {
    int (*update_plane)(struct drm_plane *plane,struct drm_crtc *crtc, struct drm_framebuffer *fb,int crtc_x, int crtc_y,unsigned int crtc_w, unsigned int crtc_h,uint32_t src_x, uint32_t src_y,uint32_t src_w, uint32_t src_h, struct drm_modeset_acquire_ctx *ctx);
    int (*disable_plane)(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx);
    void (*destroy)(struct drm_plane *plane);
    void (*reset)(struct drm_plane *plane);
    int (*set_property)(struct drm_plane *plane, struct drm_property *property, uint64_t val);
    struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
    void (*atomic_destroy_state)(struct drm_plane *plane, struct drm_plane_state *state);
    int (*atomic_set_property)(struct drm_plane *plane,struct drm_plane_state *state,struct drm_property *property, uint64_t val);
    int (*atomic_get_property)(struct drm_plane *plane,const struct drm_plane_state *state,struct drm_property *property, uint64_t *val);
    int (*late_register)(struct drm_plane *plane);
    void (*early_unregister)(struct drm_plane *plane);
    void (*atomic_print_state)(struct drm_printer *p, const struct drm_plane_state *state);
    bool (*format_mod_supported)(struct drm_plane *plane, uint32_t format, uint64_t modifier);
};

成员

update_plane

这是启用和配置给定 CRTC 和帧缓冲区的平面的传统入口点。它永远不会被调用来禁用平面,即传入的 crtc 和 fb 参数永远不会为 NULL。

帧缓冲区内存坐标中的源矩形由 src_x、src_y、src_w 和 src_h 参数(作为 16.16 定点值)给出。不支持子像素平面坐标的设备可以忽略小数部分。

CRTC 坐标中的目标矩形由 crtc_x、crtc_y、crtc_w 和 crtc_h 参数(作为整数值)给出。设备将源矩形缩放到目标矩形。如果不支持缩放,并且源矩形大小与目标矩形大小不匹配,则驱动程序必须返回 -<errorname>EINVAL</errorname> 错误。

实现原子模式设置的驱动程序应使用 drm_atomic_helper_update_plane() 来实现此挂钩。

返回

成功返回 0,失败返回负错误代码。

disable_plane

这是禁用平面的传统入口点。DRM 核心响应帧缓冲区 ID 设置为 0 的 DRM_IOCTL_MODE_SETPLANE IOCTL 调用而调用此方法。禁用平面不得由 CRTC 处理。

实现原子模式设置的驱动程序应使用 drm_atomic_helper_disable_plane() 来实现此挂钩。

返回

成功返回 0,失败返回负错误代码。

destroy

清理平面资源。此函数仅在驱动程序卸载时通过 drm_mode_config_cleanup() 调用,因为平面无法在 DRM 中热插拔。

reset

将平面硬件和软件状态重置为关闭。此函数不由核心直接调用,仅通过 drm_mode_config_reset() 调用。它不是一个辅助钩子,仅出于历史原因。

原子驱动程序可以使用 drm_atomic_helper_plane_reset() 来使用此钩子重置原子状态。

set_property

这是更新附加到平面的属性的传统入口点。

如果驱动程序不支持任何传统驱动程序私有属性,则此回调是可选的。对于原子驱动程序,它不使用,因为属性处理完全在 DRM 内核中完成。

返回

成功返回 0,失败返回负错误代码。

atomic_duplicate_state

复制此平面的当前原子状态并返回它。核心和辅助函数保证任何通过此钩子复制且仍由调用者拥有的原子状态(即,未通过调用 drm_mode_config_funcs.atomic_commit 转移给驱动程序)将通过调用此结构中的 atomic_destroy_state 钩子进行清理。

此回调对于原子驱动程序是强制性的。

不子类化 struct drm_plane_state 的原子驱动程序应该使用 drm_atomic_helper_plane_duplicate_state()。子类化状态结构以使用驱动程序私有状态扩展它的驱动程序应该使用 __drm_atomic_helper_plane_duplicate_state(),以确保在驱动程序之间以一致的方式复制共享状态。

drm_plane.state 正确初始化之前调用此钩子是一个错误。

注意

如果重复的状态引用了引用计数的资源,则此钩子必须为每个资源获取引用。驱动程序必须在 atomic_destroy_state 中再次释放这些引用。

返回

当分配失败时,重复的原子状态或 NULL。

atomic_destroy_state

销毁使用 atomic_duplicate_state 复制的状态,并释放或取消引用其引用的所有资源

此回调对于原子驱动程序是强制性的。

atomic_set_property

解码驱动程序私有属性值,并将解码的值存储到传入的状态结构中。由于原子内核解码所有标准化的属性(即使对于核心属性集之外的扩展,这些扩展可能并非所有驱动程序都实现),因此这要求驱动程序子类化状态结构。

此类驱动程序私有属性实际上仅应针对真正的硬件/供应商特定状态实现。相反,最好标准化原子扩展,并在内核中解码用于公开此类扩展的属性。

不要直接调用此函数,请使用 drm_atomic_plane_set_property() 代替。

如果驱动程序不支持任何驱动程序私有原子属性,则此回调是可选的。

注意

此函数在原子模式设置的状态组装阶段调用,该阶段可能出于任何原因中止(包括在用户空间请求时仅检查配置是否可能)。驱动程序不得触及任何持久状态(硬件或软件)或数据结构,除了传入的 state 参数。

此外,由于用户空间控制属性的设置顺序,因此此函数不得进行任何输入验证(因为状态更新不完整,因此可能不一致)。相反,任何此类输入验证都必须在各种 atomic_check 回调中完成。

返回

如果找到该属性,则为 0;如果该属性未由驱动程序实现,则为 -EINVAL(这不应该发生,核心只会请求附加到此平面的属性)。驱动程序不允许其他验证。核心已经检查过属性值是否在驱动程序注册属性时设置的范围内(整数、有效枚举值等)。

atomic_get_property

读取解码后的驱动程序私有属性。这用于实现 GETPLANE IOCTL。

不要直接调用此函数,请使用 drm_atomic_plane_get_property() 代替。

如果驱动程序不支持任何驱动程序私有原子属性,则此回调是可选的。

返回

成功时为 0,如果该属性未由驱动程序实现,则为 -EINVAL(这不应该发生,核心只会请求附加到此平面的属性)。

late_register

这个可选的钩子可以用来注册附加到平面的额外用户空间接口,如 debugfs 接口。它在驱动程序加载序列的后期从 drm_dev_register() 调用。从此回调中添加的所有内容都应在 early_unregister 回调中取消注册。

返回值

成功时返回 0,失败时返回负错误代码。

early_unregister

这个可选的钩子应该用于从 late_register 中取消注册附加到平面的额外用户空间接口。它在驱动程序卸载序列的早期从 drm_dev_unregister() 调用,以便在数据结构被拆卸之前禁用用户空间访问。

atomic_print_state

如果驱动程序子类化 struct drm_plane_state,它应该实现这个可选的钩子来打印额外的驱动程序特定状态。

不要直接调用此函数,请使用 drm_atomic_plane_print_state() 代替。

format_mod_supported

这个可选的钩子用于 DRM 来确定给定的格式/修饰符组合对于平面是否有效。这允许 DRM 生成正确的格式位掩码(哪些格式应用于哪个修饰符),并在 atomic_check 时验证修饰符。

如果不存在,则允许平面修饰符列表中的任何修饰符与平面的任何格式一起使用。

返回值

如果给定的修饰符对于平面上的该格式有效,则为 True。否则为 False。

enum drm_plane_type

uapi 平面类型枚举

常量

DRM_PLANE_TYPE_OVERLAY

覆盖平面表示所有非主平面、非光标平面。一些驱动程序在内部将这些类型的平面称为“精灵”。

DRM_PLANE_TYPE_PRIMARY

当不使用缩放/裁剪并且平面覆盖整个 CRTC 时,附加到 CRTC 的主平面最有可能能够点亮 CRTC。

DRM_PLANE_TYPE_CURSOR

当不使用缩放/裁剪并且帧缓冲具有 drm_mode_config.cursor_widthdrm_mode_config.cursor_height 指示的大小,并且如果驱动程序不支持修饰符,则帧缓冲应该具有线性布局时,附加到 CRTC 的光标平面更有可能被启用。

描述

由于历史原因,并非所有平面都相同。此枚举用于区分不同类型的平面,以实现它们的不同 uapi 语义。对于通用平面感知的用户空间以及正在使用原子 IOCTL 的用户空间,这些平面之间没有区别(当然,除了驱动程序和硬件可以支持的内容之外)。

为了与旧版用户空间兼容,默认情况下只向用户空间提供覆盖平面。用户空间客户端可以设置 DRM_CLIENT_CAP_UNIVERSAL_PLANES 客户端能力位,以指示它们希望接收包含所有平面类型的通用平面列表。另请参阅 drm_for_each_legacy_plane()

除了设置每个平面的类型之外,驱动程序还需要为旧版 IOCTL 设置 drm_crtc.primary 和可选的 drm_crtc.cursor 指针。请参阅 drm_crtc_init_with_planes()

警告:此枚举的值是 UABI,因为它们在“type”属性中公开。

struct drm_plane

中央 DRM 平面控制结构

定义:

struct drm_plane {
    struct drm_device *dev;
    struct list_head head;
    char *name;
    struct drm_modeset_lock mutex;
    struct drm_mode_object base;
    uint32_t possible_crtcs;
    uint32_t *format_types;
    unsigned int format_count;
    bool format_default;
    uint64_t *modifiers;
    unsigned int modifier_count;
    struct drm_crtc *crtc;
    struct drm_framebuffer *fb;
    struct drm_framebuffer *old_fb;
    const struct drm_plane_funcs *funcs;
    struct drm_object_properties properties;
    enum drm_plane_type type;
    unsigned index;
    const struct drm_plane_helper_funcs *helper_private;
    struct drm_plane_state *state;
    struct drm_property *alpha_property;
    struct drm_property *zpos_property;
    struct drm_property *rotation_property;
    struct drm_property *blend_mode_property;
    struct drm_property *color_encoding_property;
    struct drm_property *color_range_property;
    struct drm_property *scaling_filter_property;
    struct drm_property *hotspot_x_property;
    struct drm_property *hotspot_y_property;
    struct kmsg_dumper kmsg_panic;
};

成员

dev

此平面所属的 DRM 设备

head

dev 上的所有平面的列表,从 drm_mode_config.plane_list 链接。在 dev 的生命周期内是不变的,因此不需要锁定。

名称

人类可读的名称,可以被驱动程序覆盖

mutex

保护模式设置平面状态,以及此平面链接到的 CRTC 的 drm_crtc.mutex(在活动、正在激活或正在禁用时)。

特别是对于原子驱动程序,这保护了 state

基础

基本模式对象

possible_crtcs

此平面可以绑定到的管道,由 drm_crtc_mask() 构建

format_types

此平面支持的格式数组

format_count

format_types 指向的数组的大小。

format_default

驱动程序尚未为此平面提供支持的格式。仅由非原子驱动程序兼容性包装器使用。

modifiers

此平面支持的修饰符数组

modifier_count

modifier_count 指向的数组的大小。

crtc

当前绑定的 CRTC,仅对非原子驱动程序有意义。对于原子驱动程序,这将被强制为 NULL,原子驱动程序应该检查 drm_plane_state.crtc

fb

当前绑定的帧缓冲,仅对非原子驱动程序有意义。对于原子驱动程序,这将被强制为 NULL,原子驱动程序应该检查 drm_plane_state.fb

old_fb

在模式设置正在进行时临时跟踪旧的 fb。仅由非原子驱动程序使用,对于原子驱动程序强制为 NULL。

funcs

平面控制函数

properties

此平面的属性跟踪

type

平面类型,有关详细信息,请参阅 enum drm_plane_type

index

mode_config.list 中的位置,可以用作数组索引。在平面的生命周期内是不变的。

helper_private

中间层私有数据

state

此平面的当前原子状态。

这受 mutex 保护。请注意,非阻塞原子提交会访问当前平面状态,而无需锁定。通过 struct drm_atomic_state 指针,请参阅 for_each_oldnew_plane_in_state()for_each_old_plane_in_state()for_each_new_plane_in_state()。或者通过原子辅助函数中实现的原子提交操作的仔细排序,请参阅 struct drm_crtc_commit

alpha_property

此平面的可选 alpha 属性。请参阅 drm_plane_create_alpha_property()

zpos_property

此平面可选的 zpos 属性。请参阅drm_plane_create_zpos_property()

rotation_property

此平面可选的旋转属性。请参阅drm_plane_create_rotation_property()

blend_mode_property

此平面可选的“像素混合模式”枚举属性。混合模式属性表示 alpha 混合方程的选择,描述当前平面的像素如何与背景合成。

color_encoding_property

可选的“COLOR_ENCODING”枚举属性,用于指定非 RGB 格式的颜色编码。请参阅drm_plane_create_color_properties()

color_range_property

可选的“COLOR_RANGE”枚举属性,用于指定非 RGB 格式的颜色范围。请参阅drm_plane_create_color_properties()

scaling_filter_property

用于在缩放时应用特定过滤器的属性。

hotspot_x_property

用于设置鼠标热点 x 偏移的属性。

hotspot_y_property

用于设置鼠标热点 y 偏移的属性。

kmsg_panic

用于为此平面注册一个 panic 通知器

描述

平面表示显示块的扫描输出硬件。它们从drm_framebuffer接收输入数据,并将其馈送到drm_crtc。平面控制颜色转换,有关更多详细信息,请参阅平面合成属性,并且还参与输入像素的颜色转换,有关详细信息,请参阅颜色管理属性

drmm_universal_plane_alloc

drmm_universal_plane_alloc (dev, type, member, possible_crtcs, funcs, formats, format_count, format_modifiers, plane_type, name, ...)

分配和初始化一个通用平面对象

参数

dev

DRM 设备

type

包含结构体 drm_plane 的结构体的类型

member

type 内的 drm_plane 的名称

possible_crtcs

可能的 CRTC 的位掩码

funcs

新平面的回调

格式

支持的格式数组 (DRM_FORMAT_*)

format_count

formats 中的元素数量

format_modifiers

由 DRM_FORMAT_MOD_INVALID 终止的结构体 drm_format 修饰符数组

plane_type

平面类型(覆盖、主、光标)

名称

平面名称的 printf 样式格式字符串,如果使用默认名称则为 NULL

...

可变参数

描述

分配并初始化 type 类型的平面对象。清理工作通过使用 drmm_add_action() 注册 drm_plane_cleanup() 来自动处理。

drm_plane_funcs.destroy 钩子必须为 NULL。

仅支持 DRM_FORMAT_MOD_LINEAR 修饰符的驱动程序可以将 format_modifiers 设置为 NULL。该平面将通告线性修饰符。

返回

指向新平面的指针,如果失败则为 ERR_PTR。

drm_universal_plane_alloc

drm_universal_plane_alloc (dev, type, member, possible_crtcs, funcs, formats, format_count, format_modifiers, plane_type, name, ...)

分配和初始化一个通用平面对象

参数

dev

DRM 设备

type

包含结构体 drm_plane 的结构体的类型

member

type 内的 drm_plane 的名称

possible_crtcs

可能的 CRTC 的位掩码

funcs

新平面的回调

格式

支持的格式数组 (DRM_FORMAT_*)

format_count

formats 中的元素数量

format_modifiers

由 DRM_FORMAT_MOD_INVALID 终止的结构体 drm_format 修饰符数组

plane_type

平面类型(覆盖、主、光标)

名称

平面名称的 printf 样式格式字符串,如果使用默认名称则为 NULL

...

可变参数

描述

分配并初始化 type 类型的平面对象。调用者负责使用 kfree() 释放已分配的内存。

鼓励驱动程序使用 drmm_universal_plane_alloc()

仅支持 DRM_FORMAT_MOD_LINEAR 修饰符的驱动程序可以将 format_modifiers 设置为 NULL。该平面将通告线性修饰符。

返回

指向新平面的指针,如果失败则为 ERR_PTR。

unsigned int drm_plane_index(const struct drm_plane *plane)

查找已注册平面的索引

参数

const struct drm_plane *plane

要查找索引的平面

描述

给定一个已注册的平面,返回该平面在 DRM 设备平面列表中的索引。

u32 drm_plane_mask(const struct drm_plane *plane)

查找已注册平面的掩码

参数

const struct drm_plane *plane

要查找掩码的平面

struct drm_plane *drm_plane_find(struct drm_device *dev, struct drm_file *file_priv, uint32_t id)

查找 drm_plane

参数

struct drm_device *dev

DRM 设备

struct drm_file *file_priv

用于检查租约的 drm 文件。

uint32_t id

平面 ID

描述

返回具有 id 的平面,如果不存在则返回 NULL。只是 drm_mode_object_find() 的简单封装。

drm_for_each_plane_mask

drm_for_each_plane_mask (plane, dev, plane_mask)

迭代由位掩码指定的平面

参数

plane

循环游标

dev

DRM 设备

plane_mask

平面索引的位掩码

描述

迭代由位掩码指定的所有平面。

drm_for_each_legacy_plane

drm_for_each_legacy_plane (plane, dev)

为旧版用户空间迭代所有平面

参数

plane

循环游标

dev

DRM 设备

描述

迭代 dev 的所有旧版平面,不包括主平面和光标平面。当用户空间不了解通用平面时,这对于实现用户空间 api 非常有用。另请参阅 enum drm_plane_type

drm_for_each_plane

drm_for_each_plane (plane, dev)

迭代所有平面

参数

plane

循环游标

dev

DRM 设备

描述

迭代 dev 的所有平面,包括主平面和光标平面。

int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, uint32_t possible_crtcs, const struct drm_plane_funcs *funcs, const uint32_t *formats, unsigned int format_count, const uint64_t *format_modifiers, enum drm_plane_type type, const char *name, ...)

初始化一个新的通用平面对象

参数

struct drm_device *dev

DRM 设备

struct drm_plane *plane

要初始化的平面对象

uint32_t possible_crtcs

可能的 CRTC 的位掩码

const struct drm_plane_funcs *funcs

新平面的回调

const uint32_t *formats

支持的格式数组 (DRM_FORMAT_*)

unsigned int format_count

formats 中的元素数量

const uint64_t *format_modifiers

由 DRM_FORMAT_MOD_INVALID 终止的结构体 drm_format 修饰符数组

enum drm_plane_type type

平面类型(覆盖、主、光标)

const char *name

平面名称的 printf 样式格式字符串,如果使用默认名称则为 NULL

...

可变参数

描述

初始化类型为 **type** 的平面对象。 drm_plane_funcs.destroy 钩子应该调用 drm_plane_cleanup()kfree() 来释放平面结构。平面结构不应该使用 devm_kzalloc() 分配。

仅支持 DRM_FORMAT_MOD_LINEAR 修饰符的驱动程序可以将 format_modifiers 设置为 NULL。该平面将通告线性修饰符。

注意

考虑使用 drmm_universal_plane_alloc() 而不是 drm_universal_plane_init(),以便让 DRM 管理的资源基础设施来处理清理和释放。

返回

成功时为零,失败时为错误代码。

void drm_plane_cleanup(struct drm_plane *plane)

清理核心平面使用

参数

struct drm_plane *plane

要清理的平面

描述

此函数清理 **plane** 并将其从 DRM 模式设置核心中移除。请注意,该函数 *不* 释放平面结构本身,这由调用者负责。

struct drm_plane *drm_plane_from_index(struct drm_device *dev, int idx)

查找指定索引处的已注册平面

参数

struct drm_device *dev

DRM 设备

int idx

要查找的已注册平面的索引

描述

给定一个平面索引,从 DRM 设备的平面列表中返回具有匹配索引的已注册平面。这是 drm_plane_index() 的反向操作。

void drm_plane_force_disable(struct drm_plane *plane)

强制禁用平面

参数

struct drm_plane *plane

要禁用的平面

描述

强制禁用该平面。

当平面的当前帧缓冲区被销毁,以及恢复 fbdev 模式时使用。

请注意,此函数不适用于原子驱动程序,因为它没有正确地通过锁获取上下文,因此无法处理重试或驱动程序私有锁。您可能需要使用 drm_atomic_helper_disable_plane()drm_atomic_helper_disable_planes_on_crtc() 代替。

int drm_mode_plane_set_obj_prop(struct drm_plane *plane, struct drm_property *property, uint64_t value)

设置属性的值

参数

struct drm_plane *plane

要设置属性值的 DRM 平面对象

struct drm_property *property

要设置的属性

uint64_t value

应将属性设置为的值

描述

此函数在给定平面对象上设置给定属性。如果回调成功,此函数将调用驱动程序的 ->set_property 回调并更改属性的软件状态。

返回

成功时为零,失败时为错误代码。

bool drm_plane_has_format(struct drm_plane *plane, u32 format, u64 modifier)

检查平面是否支持此格式和修饰符组合

参数

struct drm_plane *plane

DRM 平面

u32 format

像素格式 (DRM_FORMAT_*)

u64 modifier

数据布局修饰符

返回

平面是否支持指定的格式和修饰符组合。

bool drm_any_plane_has_format(struct drm_device *dev, u32 format, u64 modifier)

检查是否有任何平面支持此格式和修饰符组合

参数

struct drm_device *dev

DRM 设备

u32 format

像素格式 (DRM_FORMAT_*)

u64 modifier

数据布局修饰符

返回

是否至少有一个平面支持指定的格式和修饰符组合。

void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)

启用平面帧缓冲损坏剪辑属性。

参数

struct drm_plane *plane

要在其上启用损坏剪辑属性的平面。

描述

此函数允许驱动程序在平面上启用损坏剪辑属性。

unsigned int drm_plane_get_damage_clips_count(const struct drm_plane_state *state)

返回损坏区域裁剪数量。

参数

const struct drm_plane_state *state

平面状态。

描述

一个简单的辅助函数,用于获取用户空间在平面更新期间设置的 drm_mode_rect 裁剪区域的数量。

返回

平面 fb_damage_clips blob 属性中的裁剪区域数量。

struct drm_mode_rect *drm_plane_get_damage_clips(const struct drm_plane_state *state)

返回损坏区域裁剪。

参数

const struct drm_plane_state *state

平面状态。

描述

请注意,此函数返回 uapi 类型 drm_mode_rect。如果驱动程序最多只能处理一个损坏区域,则驱动程序可能需要使用辅助函数 drm_atomic_helper_damage_iter_init()drm_atomic_helper_damage_iter_next()drm_atomic_helper_damage_merged()

返回

平面 fb_damage_clips blob 属性中的损坏区域裁剪。

int drm_plane_create_scaling_filter_property(struct drm_plane *plane, unsigned int supported_filters)

创建一个新的缩放过滤器属性

参数

struct drm_plane *plane

DRM 平面

unsigned int supported_filters

支持的缩放过滤器位掩码,必须包括 BIT(DRM_SCALING_FILTER_DEFAULT)。

描述

此函数允许驱动程序在给定平面上启用缩放滤镜属性。

返回

成功则返回零,失败则返回 -errno

int drm_plane_add_size_hints_property(struct drm_plane *plane, const struct drm_plane_size_hint *hints, int num_hints)

创建尺寸提示属性

参数

struct drm_plane *plane

DRM 平面

const struct drm_plane_size_hint *hints

尺寸提示

int num_hints

尺寸提示的数量

描述

为平面创建尺寸提示属性。

返回

成功则返回零,失败则返回 -errno

平面合成函数参考

int drm_plane_create_alpha_property(struct drm_plane *plane)

创建一个新的 alpha 属性

参数

struct drm_plane *plane

DRM 平面

描述

此函数创建一个通用的、可变的 alpha 属性,并在 DRM 核心中启用对其的支持。它附加到 plane

alpha 属性将被允许在 0(透明)到 0xffff(不透明)的范围内。

返回

成功时返回 0,失败时返回负错误代码。

int drm_plane_create_rotation_property(struct drm_plane *plane, unsigned int rotation, unsigned int supported_rotations)

创建一个新的旋转属性

参数

struct drm_plane *plane

DRM 平面

unsigned int rotation

旋转属性的初始值

unsigned int supported_rotations

支持的旋转和反射的位掩码

描述

这将创建一个新的属性,其中包含选定的转换支持。

由于旋转 180° 与沿 x 轴和 y 轴反射相同,因此旋转属性有些多余。驱动程序可以使用 drm_rotation_simplify() 来标准化此属性的值。

暴露给用户空间的属性是一个位掩码属性(请参阅 drm_property_create_bitmask()),名为 “rotation”,并具有以下位掩码枚举值

DRM_MODE_ROTATE_0

“rotate-0”

DRM_MODE_ROTATE_90

“rotate-90”

DRM_MODE_ROTATE_180

“rotate-180”

DRM_MODE_ROTATE_270

“rotate-270”

DRM_MODE_REFLECT_X

“reflect-x”

DRM_MODE_REFLECT_Y

“reflect-y”

旋转是以逆时针方向指定的度数,X 和 Y 轴位于源矩形内,即旋转之前的 X/Y 轴。反射后,旋转将应用于从源矩形采样的图像,然后再缩放以适应目标矩形。

unsigned int drm_rotation_simplify(unsigned int rotation, unsigned int supported_rotations)

尝试简化旋转

参数

unsigned int rotation

要简化的旋转

unsigned int supported_rotations

支持的旋转

描述

尝试将旋转简化为支持的形式。例如,如果硬件支持除 DRM_MODE_REFLECT_X 之外的所有内容,则可以像这样调用此函数

drm_rotation_simplify(rotation, DRM_MODE_ROTATE_0 |

DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_Y);

以消除 DRM_MODE_REFLECT_X 标志。根据硬件支持的转换类型,此函数可能无法生成支持的转换,因此调用者应在之后检查结果。

int drm_plane_create_zpos_property(struct drm_plane *plane, unsigned int zpos, unsigned int min, unsigned int max)

创建可变的 zpos 属性

参数

struct drm_plane *plane

DRM 平面

unsigned int zpos

zpos 属性的初始值

unsigned int min

zpos 属性的最小可能值

unsigned int max

zpos 属性的最大可能值

描述

此函数初始化通用的可变 zpos 属性,并在 drm 核心中启用对其的支持。然后,驱动程序可以将此属性附加到平面,以在混合操作期间启用对可配置平面排列的支持。将可变 zpos 属性附加到任何平面的驱动程序应在其 drm_mode_config_funcs.atomic_check() 实现期间调用 drm_atomic_normalize_zpos() 辅助函数,该函数将更新规范化的 zpos 值并将其存储在 drm_plane_state.normalized_zpos 中。通常,min 应设置为 0,max 应设置为给定 crtc 的最大平面数 - 1。

如果某些平面的 zpos 无法更改(例如固定的背景或光标/最顶层平面),则驱动程序应调整 min/max 值,并为这些平面分配具有较低或较高值的不可变的 zpos 属性(有关更多信息,请参阅 drm_plane_create_zpos_immutable_property() 函数)。在这种情况下,驱动程序还应在其 plane_reset() 回调中为所有平面分配适当的初始 zpos 值,以便始终正确排序平面。

另请参阅 drm_atomic_normalize_zpos()

暴露给用户空间的属性名为 “zpos”。

返回

成功返回零,失败返回负 errno。

int drm_plane_create_zpos_immutable_property(struct drm_plane *plane, unsigned int zpos)

创建不可变的 zpos 属性

参数

struct drm_plane *plane

DRM 平面

unsigned int zpos

zpos 属性的值

描述

此函数初始化通用的不可变 zpos 属性,并使其在 DRM 核心中得到支持。通过此属性,驱动程序允许用户空间获取用于混合操作的平面排列,并通知用户空间硬件(或驱动程序)不支持更改平面的顺序。有关可变的 zpos,请参见drm_plane_create_zpos_property()

暴露给用户空间的属性名为 “zpos”。

返回

成功返回零,失败返回负 errno。

int drm_atomic_normalize_zpos(struct drm_device *dev, struct drm_atomic_state *state)

计算所有 CRTC 的标准化 zpos 值

参数

struct drm_device *dev

DRM 设备

struct drm_atomic_state *state

DRM 设备的原子状态

描述

此函数计算 DRM 设备的提供的原子状态中所有已修改平面的标准化 zpos 值。

对于每个 CRTC,此函数检查分配给它的所有平面的新状态,并计算这些平面的标准化 zpos 值。平面首先按其 zpos 值进行比较,然后按平面 ID 进行比较(如果 zpos 相等)。zpos 值最小的平面位于底部。drm_plane_state.normalized_zpos 然后填充从 0 到 crtc 中活动平面数减一的唯一值。

返回值:成功时返回零,失败时返回 -errno

int drm_plane_create_blend_mode_property(struct drm_plane *plane, unsigned int supported_modes)

创建一个新的混合模式属性

参数

struct drm_plane *plane

DRM 平面

unsigned int supported_modes

支持模式的位掩码,必须包含 BIT(DRM_MODE_BLEND_PREMULTI)。当前 DRM 假设 alpha 是预乘的,如果该属性默认设置为其他值,则旧的用户空间可能会崩溃。

描述

这将创建一个描述混合模式的新属性。

暴露给用户空间的属性是一个枚举属性(请参阅 drm_property_create_enum()),名为 “像素混合模式”,并具有以下枚举值:

“无”

忽略像素 alpha 的混合公式。

“预乘”

假设像素颜色值已预先乘以 alpha 通道值的混合公式。

“覆盖”

假设像素颜色值未预先乘,并且在将其混合到背景颜色值时将执行此操作的混合公式。

返回

成功则返回零,失败则返回 -errno

平面损坏跟踪函数参考

void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state, struct drm_plane_state *plane_state)

在 atomic_check 上验证平面损坏。

参数

struct drm_atomic_state *state

驱动程序状态对象。

struct drm_plane_state *plane_state

要验证损坏的平面状态。

描述

此辅助函数确保在完全模式设置时丢弃平面状态的损坏。如果驱动程序有更多理由需要执行完整的平面更新,而不是处理各个损坏区域,则应在此处处理这些情况。

请注意,drm_plane_state.fb_damage_clips == NULL 在平面状态中表示应进行完整的平面更新。它还确保辅助迭代器将返回 drm_plane_state.src 作为损坏。

int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int flags, unsigned int color, struct drm_clip_rect *clips, unsigned int num_clips)

dirtyfb 的助手。

参数

struct drm_framebuffer *fb

DRM 帧缓冲。

struct drm_file *file_priv

用于 ioctl 调用的 Drm 文件。

unsigned int flags

脏 fb 注释标志。

unsigned int color

用于注释填充的颜色。

struct drm_clip_rect *clips

脏区域。

unsigned int num_clips

clips 中的剪辑计数。

描述

一个辅助函数,用于在平面更新期间使用损坏接口来实现 drm_framebuffer_funcs.dirty。如果 num_clips 为 0,则此辅助函数将执行完整的平面更新。这与 DIRTFB IOCTL 所期望的行为相同。

请注意,此助手是阻塞实现。这是当前驱动程序和用户空间在其 DIRTYFB IOCTL 实现中所期望的,这是一种限制用户空间速率并确保其渲染不会过多地超前于上传新数据的方法。

返回

成功返回零,失败返回负 errno。

void drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, const struct drm_plane_state *old_state, const struct drm_plane_state *state)

初始化损坏迭代器。

参数

struct drm_atomic_helper_damage_iter *iter

要初始化的迭代器。

const struct drm_plane_state *old_state

用于验证的旧平面状态。

const struct drm_plane_state *state

从中迭代损坏剪辑的平面状态。

描述

初始化一个迭代器,该迭代器将平面损坏 drm_plane_state.fb_damage_clips 剪辑到平面 drm_plane_state.src。如果损坏不存在,因为用户空间未发送或驱动程序已丢弃(它希望执行完整的平面更新),则此迭代器返回完整的平面 src。当前,如果平面 src 发生更改,则此迭代器返回完整的平面 src,但将来可以更改为返回损坏。

对于平面不可见或不应发生平面更新的情况,第一次调用 iter_next 将返回 false。请注意,此助手使用剪裁的 drm_plane_state.src,因此调用此助手的驱动程序应已更早地调用了 drm_atomic_helper_check_plane_state()

bool drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter, struct drm_rect *rect)

推进 damage 迭代器。

参数

struct drm_atomic_helper_damage_iter *iter

要推进的迭代器。

struct drm_rect *rect

返回一个裁剪到平面 src 的 fb 坐标中的矩形。

描述

由于平面 src 是 16.16 定点数,而 damage 剪切是整数,此迭代器会舍入与平面 src 相交的剪切。对于相交的坐标,x1/y1 向下舍入,x2/y2 向上舍入。对于完整平面 src,如果它作为 damage 返回,则进行类似的舍入。此迭代器将跳过平面 src 之外的 damage 剪切。

如果第一次调用迭代器 next 返回 false,则表示无需更新平面。

返回

如果输出有效,则返回 True;如果到达末尾,则返回 false。

bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state, struct drm_plane_state *state, struct drm_rect *rect)

合并的平面 damage

参数

const struct drm_plane_state *old_state

用于验证的旧平面状态。

struct drm_plane_state *state

从中迭代损坏剪辑的平面状态。

struct drm_rect *rect

返回合并的 damage 矩形

描述

此函数将任何有效的平面 damage 剪切合并为一个矩形,并将其返回到 rect 中。

有关详细信息,请参见:drm_atomic_helper_damage_iter_init()drm_atomic_helper_damage_iter_next()

返回

如果存在有效的平面 damage,则返回 True;否则返回 false。

drm_atomic_for_each_plane_damage

drm_atomic_for_each_plane_damage (iter, rect)

平面 damage 的迭代器宏。

参数

iter

要推进的迭代器。

rect

返回一个裁剪到平面 src 的 fb 坐标中的矩形。

描述

请注意,如果第一次调用迭代器宏返回 false,则无需进行平面更新。当用户空间未传递 damage 时,迭代器将返回完整的平面 src。

struct drm_atomic_helper_damage_iter

damage 迭代器的闭包结构。

定义:

struct drm_atomic_helper_damage_iter {
};

成员

描述

此结构跟踪遍历平面 damage 剪切列表所需的状态。

平面 Panic 功能

要为驱动程序启用 DRM panic,主平面必须实现一个 drm_plane_helper_funcs.get_scanout_buffer 辅助函数。然后它会自动注册到 drm panic 处理程序。当发生 panic 时,将调用 drm_plane_helper_funcs.get_scanout_buffer,驱动程序可以提供一个帧缓冲区,以便 panic 处理程序可以在其上绘制 panic 屏幕。目前仅支持线性缓冲区和少数颜色格式。或者,驱动程序还可以提供一个 drm_plane_helper_funcs.panic_flush 回调,该回调将在之后被调用,以向硬件发送额外的命令,使扫描输出缓冲区可见。

平面 Panic 函数参考

struct drm_scanout_buffer

DRM 扫描输出缓冲区

定义:

struct drm_scanout_buffer {
    const struct drm_format_info *format;
    struct iosys_map map[DRM_FORMAT_MAX_PLANES];
    unsigned int width;
    unsigned int height;
    unsigned int pitch[DRM_FORMAT_MAX_PLANES];
    void (*set_pixel)(struct drm_scanout_buffer *sb, unsigned int x, unsigned int y, u32 color);
};

成员

格式

扫描输出缓冲区的 drm 格式。

map

扫描输出缓冲区的虚拟地址,位于内存中或 iomem 中。扫描输出缓冲区应为线性格式,可以直接发送到显示硬件。对于 panic 屏幕,撕裂不是问题。

width

扫描输出缓冲区的宽度,以像素为单位。

height

扫描输出缓冲区的高度,以像素为单位。

pitch

两条连续线起点之间的长度(以字节为单位)。

set_pixel

可选函数,用于在帧缓冲区上设置像素颜色。它允许在驱动程序内部处理特殊的平铺格式。

描述

此结构保存 drm_panic 绘制 panic 屏幕并显示它所需的信息。

drm_panic_trylock

drm_panic_trylock (dev, flags)

尝试进入 panic 打印临界区

参数

dev

struct drm_device

标志

你需要传递给 unlock() 对等的 unsigned long irq 标志

描述

任何 panic 打印代码都必须调用此函数。如果 trylock 失败,则必须中止 panic 打印尝试。

panic 打印代码在持有 panic 锁时可以做出以下假设

具体来说,由于 drm_atomic_helper_swap_state() 中围绕平面更新的保护,以下附加保证成立

  • 取消引用 drm_plane.state 指针是安全的。

  • 在原子检查代码完成后保持不变的 struct drm_plane_state 或其驱动程序的子类中的任何内容都可以安全访问。具体来说,这包括对帧缓冲区和缓冲区对象的引用计数指针。

  • drm_plane_helper_funcs.fb_prepare 设置并由 drm_plane_helper_funcs.fb_cleanup 清理的任何内容都可以安全访问,只要它在这两个调用之间保持不变。这也意味着对于使用动态缓冲区管理的驱动程序,帧缓冲区被固定,因此所有相关的数据结构都可以在不采取任何进一步锁定的情况下访问(无论如何这在 panic 上下文中是不可能的)。

  • 重要的是,由 drm_plane_helper_funcs.begin_fb_accessdrm_plane_helper_funcs.end_fb_access 设置的软件和硬件状态是无法安全访问的。

除非驱动程序使用 drm_panic_lock()drm_panic_unlock() 显式保护这些硬件访问,否则驱动程序不得对硬件的实际状态做出任何假设。

返回

无法获取原始自旋锁时为 0,成功时为非零值。

drm_panic_lock

drm_panic_lock (dev, flags)

保护 panic 打印相关状态

参数

dev

struct drm_device

标志

你需要传递给 unlock() 对等的 unsigned long irq 标志

描述

必须调用此函数来保护 panic 打印代码必须能够依赖的软件和硬件状态。受保护的部分必须尽可能小。它使用 irqsave/irqrestore 变体,并且可以从 irq 处理程序调用。示例包括

  • 访问 peek/poke 或其他类似寄存器,如果这是驱动程序在 panic 时将像素打印到扫描输出缓冲区中的方式。

  • 更新诸如 drm_plane.state 之类的指针,允许 panic 处理程序安全地取消引用这些指针。这在 drm_atomic_helper_swap_state() 中完成。

  • 一个非不变的状态,驱动程序在 panic 打印期间必须能够访问它。

drm_panic_unlock

drm_panic_unlock (dev, flags)

恐慌打印临界区的结束

参数

dev

struct drm_device

标志

获取锁时返回的irq标志

描述

解锁由drm_panic_lock()drm_panic_trylock()获取的原始自旋锁。

bool drm_panic_is_enabled(struct drm_device *dev)

参数

struct drm_device *dev

可能支持drm_panic的drm设备

描述

如果drm设备支持drm_panic,则返回true

显示模式函数参考

enum drm_mode_status

模式的硬件支持状态

常量

MODE_OK

模式正常

MODE_HSYNC

行同步超出范围

MODE_VSYNC

场同步超出范围

MODE_H_ILLEGAL

模式具有非法的水平时序

MODE_V_ILLEGAL

模式具有非法的垂直时序

MODE_BAD_WIDTH

需要不支持的行间距

MODE_NOMODE

没有具有匹配名称的模式

MODE_NO_INTERLACE

不支持隔行扫描模式

MODE_NO_DBLESCAN

不支持双扫描模式

MODE_NO_VSCAN

不支持多扫描模式

MODE_MEM

视频内存不足

MODE_VIRTUAL_X

模式宽度对于指定的虚拟尺寸来说太大

MODE_VIRTUAL_Y

模式高度对于指定的虚拟尺寸来说太大

MODE_MEM_VIRT

在给定虚拟尺寸的情况下,视频内存不足

MODE_NOCLOCK

没有可用的固定时钟

MODE_CLOCK_HIGH

所需的时钟过高

MODE_CLOCK_LOW

所需的时钟过低

MODE_CLOCK_RANGE

时钟/模式不在ClockRange中

MODE_BAD_HVALUE

水平时序超出范围

MODE_BAD_VVALUE

垂直时序超出范围

MODE_BAD_VSCAN

VScan值超出范围

MODE_HSYNC_NARROW

水平同步太窄

MODE_HSYNC_WIDE

水平同步太宽

MODE_HBLANK_NARROW

水平消隐太窄

MODE_HBLANK_WIDE

水平消隐太宽

MODE_VSYNC_NARROW

垂直同步太窄

MODE_VSYNC_WIDE

垂直同步太宽

MODE_VBLANK_NARROW

垂直消隐太窄

MODE_VBLANK_WIDE

垂直消隐太宽

MODE_PANEL

超出面板尺寸

MODE_INTERLACE_WIDTH

宽度对于隔行扫描模式来说太大

MODE_ONE_WIDTH

仅支持一个宽度

MODE_ONE_HEIGHT

仅支持一个高度

MODE_ONE_SIZE

仅支持一个分辨率

MODE_NO_REDUCED

监视器不接受缩减消隐

MODE_NO_STEREO

不支持立体模式

MODE_NO_420

不支持ycbcr 420模式

MODE_STALE

模式已过时

MODE_BAD

未指定原因

MODE_ERROR

错误情况

描述

此枚举用于筛选出驱动程序/硬件组合不支持的模式。

DRM_MODE_RES_MM

DRM_MODE_RES_MM (res, dpi)

根据分辨率和DPI计算显示尺寸

参数

res

以像素为单位的分辨率

dpi

每英寸的点数

DRM_MODE_INIT

DRM_MODE_INIT (hz, hd, vd, hd_mm, vd_mm)

初始化显示模式

参数

hz

以赫兹为单位的垂直刷新率

hd

水平分辨率,宽度

vd

垂直分辨率,高度

hd_mm

以毫米为单位的显示宽度

vd_mm

以毫米为单位的显示高度

描述

此宏初始化一个drm_display_mode,其中包含有关刷新率、分辨率和物理尺寸的信息。

DRM_SIMPLE_MODE

DRM_SIMPLE_MODE (hd, vd, hd_mm, vd_mm)

简单显示模式

参数

hd

水平分辨率,宽度

vd

垂直分辨率,高度

hd_mm

以毫米为单位的显示宽度

vd_mm

以毫米为单位的显示高度

描述

此宏初始化一个drm_display_mode,其中仅包含有关分辨率和物理尺寸的信息。

struct drm_display_mode

DRM内核内部显示模式结构

定义:

struct drm_display_mode {
    int clock;
    u16 hdisplay;
    u16 hsync_start;
    u16 hsync_end;
    u16 htotal;
    u16 hskew;
    u16 vdisplay;
    u16 vsync_start;
    u16 vsync_end;
    u16 vtotal;
    u16 vscan;
    u32 flags;
    int crtc_clock;
    u16 crtc_hdisplay;
    u16 crtc_hblank_start;
    u16 crtc_hblank_end;
    u16 crtc_hsync_start;
    u16 crtc_hsync_end;
    u16 crtc_htotal;
    u16 crtc_hskew;
    u16 crtc_vdisplay;
    u16 crtc_vblank_start;
    u16 crtc_vblank_end;
    u16 crtc_vsync_start;
    u16 crtc_vsync_end;
    u16 crtc_vtotal;
    u16 width_mm;
    u16 height_mm;
    u8 type;
    bool expose_to_userspace;
    struct list_head head;
    char name[DRM_DISPLAY_MODE_LEN];
    enum drm_mode_status status;
    enum hdmi_picture_aspect picture_aspect_ratio;
};

成员

clock

以kHz为单位的像素时钟。

hdisplay

水平显示尺寸

hsync_start

水平同步开始

hsync_end

水平同步结束

htotal

水平总尺寸

hskew

水平倾斜?!

vdisplay

垂直显示尺寸

vsync_start

垂直同步开始

vsync_end

垂直同步结束

vtotal

垂直总尺寸

vscan

垂直扫描?!

标志

同步和时序标志

  • DRM_MODE_FLAG_PHSYNC:水平同步为高电平有效。

  • DRM_MODE_FLAG_NHSYNC:水平同步为低电平有效。

  • DRM_MODE_FLAG_PVSYNC:垂直同步为高电平有效。

  • DRM_MODE_FLAG_NVSYNC:垂直同步为低电平有效。

  • DRM_MODE_FLAG_INTERLACE:模式为隔行扫描。

  • DRM_MODE_FLAG_DBLSCAN:模式使用双扫描。

  • DRM_MODE_FLAG_CSYNC:模式使用复合同步。

  • DRM_MODE_FLAG_PCSYNC:复合同步为高电平有效。

  • DRM_MODE_FLAG_NCSYNC:复合同步为低电平有效。

  • DRM_MODE_FLAG_HSKEW:提供hskew(未使用?)。

  • DRM_MODE_FLAG_BCAST: <已弃用>

  • DRM_MODE_FLAG_PIXMUX: <已弃用>

  • DRM_MODE_FLAG_DBLCLK:双时钟模式。

  • DRM_MODE_FLAG_CLKDIV2:半时钟模式。

此外,还有一些标志用于指定如何打包3D模式

  • DRM_MODE_FLAG_3D_NONE:普通,非3D模式。

  • DRM_MODE_FLAG_3D_FRAME_PACKING:用于左帧和右帧的2个完整帧。

  • DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:像场一样交错。

  • DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:交错线。

  • DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:并排完整帧。

  • DRM_MODE_FLAG_3D_L_DEPTH:?

  • DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:?

  • DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:帧分为顶部和底部部分。

  • DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:帧分为左部分和右部分。

crtc_clock

硬件中的实际像素或点时钟。例如,当使用隔行扫描、双时钟、立体模式或其他改变实际通过导线发送的时序和信号的特殊功能时,它与逻辑**时钟**不同。用户空间可以通过垂直空白时间戳观察到该逻辑时钟。

同样以kHz为单位。

请注意,对于HDMI或DP等数字输出,在点时钟和比特编码级别的信号时钟之间通常存在很大的混淆。尤其是在使用8b/10b编码时,差异正好是10的系数。

crtc_hdisplay

硬件模式水平显示尺寸

crtc_hblank_start

硬件模式水平消隐开始

crtc_hblank_end

硬件模式水平消隐结束

crtc_hsync_start

硬件模式水平同步开始

crtc_hsync_end

硬件模式水平同步结束

crtc_htotal

硬件模式水平总尺寸

crtc_hskew

硬件模式水平倾斜?!

crtc_vdisplay

硬件模式垂直显示尺寸

crtc_vblank_start

硬件模式垂直消隐开始

crtc_vblank_end

硬件模式垂直消隐结束

crtc_vsync_start

硬件模式垂直同步开始

crtc_vsync_end

硬件模式垂直同步结束

crtc_vtotal

硬件模式垂直总尺寸

width_mm

输出的可寻址尺寸(以毫米为单位),投影仪应将其设置为0。

height_mm

输出的可寻址尺寸(以毫米为单位),投影仪应将其设置为0。

type

标志的位掩码,主要与模式的来源有关。可能的标志有

  • DRM_MODE_TYPE_PREFERRED:首选模式,通常是LCD面板的原始分辨率。在任何给定时间,每个连接器应该只有一个首选模式。

  • DRM_MODE_TYPE_DRIVER:由驱动程序创建的模式,实际上所有模式都是由驱动程序创建的。驱动程序必须为他们创建并暴露给用户空间的所有模式设置此位。

  • DRM_MODE_TYPE_USERDEF:通过内核命令行定义或选择的模式。

此外,还有一大堆不应使用的标志,但由于这些标志也用于用户空间ABI,因此仍然存在。我们不再接受具有这些类型的模式

  • DRM_MODE_TYPE_BUILTIN:用于硬编码模式,未使用。请改用DRM_MODE_TYPE_DRIVER。

  • DRM_MODE_TYPE_DEFAULT:同样是遗留代码,请改用DRM_MODE_TYPE_PREFERRED。

  • DRM_MODE_TYPE_CLOCK_C和DRM_MODE_TYPE_CRTC_C:定义了遗留代码,仅出于历史原因而存在。没有人知道它们是什么意思。请勿使用。

expose_to_userspace

指示是否将模式暴露给用户空间。这是为了在drm_mode_getconnector ioctl中准备用户模式的列表时维护一组暴露的模式。此目的仅存在于ioctl函数中,而不应在函数外部使用。

head

用于模式列表的结构体 list_head。

名称

模式的人类可读名称,使用drm_mode_set_name()填充。

status

模式的状态,用于筛选出硬件不支持的模式。请参阅枚举drm_mode_status

picture_aspect_ratio

用于设置模式的HDMI图像宽高比的字段。

描述

这是内核API显示模式信息结构。有关用户空间版本,请参阅struct drm_mode_modeinfo

水平和垂直时序按以下图表定义。

          Active                 Front           Sync           Back
         Region                 Porch                          Porch
<-----------------------><----------------><-------------><-------------->
  //////////////////////|
 ////////////////////// |
//////////////////////  |..................               ................
                                           _______________
<----- [hv]display ----->
<------------- [hv]sync_start ------------>
<--------------------- [hv]sync_end --------------------->
<-------------------------------- [hv]total ----------------------------->*

此结构包含时序的两个副本。第一个是简单的时序,它指定了逻辑模式,就像在刷新率下进行逐行1:1扫描输出一样,用户空间可以通过垂直空白时间戳观察到该刷新率。然后是硬件时序,这些时序针对隔行扫描、双时钟和类似的事情进行了校正。它们作为一种便利措施提供,并且可以使用drm_mode_set_crtcinfo()进行适当的计算。

对于打印,你可以使用 DRM_MODE_FMTDRM_MODE_ARG()

DRM_MODE_FMT

DRM_MODE_FMT

用于 struct drm_display_mode 的 printf 字符串

DRM_MODE_ARG

DRM_MODE_ARG (m)

用于 struct drm_display_mode 的 printf 参数

参数

m

显示模式

bool drm_mode_is_stereo(const struct drm_display_mode *mode)

检查立体模式标志

参数

const struct drm_display_mode *mode

要检查的 drm_display_mode

返回

如果模式是立体模式之一(如并排),则为 True,否则为 false。

void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)

将模式打印到 dmesg

参数

const struct drm_display_mode *mode

要打印的模式

描述

使用 DRM_DEBUG 描述 mode

struct drm_display_mode *drm_mode_create(struct drm_device *dev)

创建一个新的显示模式

参数

struct drm_device *dev

DRM 设备

描述

使用 kzalloc 创建一个新的、已清除的 drm_display_mode,为其分配一个 ID 并返回它。

返回

成功时指向新模式的指针,错误时为 NULL。

void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)

删除一个模式

参数

struct drm_device *dev

DRM 设备

struct drm_display_mode *mode

要删除的模式

描述

释放 mode 的唯一 ID,然后使用 kfree 释放其 mode 结构本身。

void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode)

将模式添加到连接器的 probed_mode 列表

参数

struct drm_connector *connector

新模式的连接器

struct drm_display_mode *mode

模式数据

描述

mode 添加到 connector 的 probed_mode 列表以供后续使用。此列表应在第二步中进行筛选,并将硬件实际支持的所有模式移动到 connector 的 modes 列表中。

struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev, enum drm_connector_tv_mode tv_mode, unsigned long pixel_clock_hz, unsigned int hdisplay, unsigned int vdisplay, bool interlace)

为模拟电视创建一个显示模式

参数

struct drm_device *dev

drm 设备

enum drm_connector_tv_mode tv_mode

用于创建模式的电视模式标准。请参见 DRM_MODE_TV_MODE_*。

unsigned long pixel_clock_hz

像素时钟频率,以赫兹为单位

unsigned int hdisplay

水平显示尺寸

unsigned int vdisplay

垂直显示尺寸

bool interlace

是否计算隔行模式

描述

此函数创建一个适用于模拟电视输出的 struct drm_display_mode 实例,用于常规的模拟电视模式之一。如果这是 DRM_MODE_TV_MODE_MONOCHROME,将创建一个 625 行模式。

请注意,hdisplay 大于 PAL 和 NTSC 定时的通常约束,并且我们将选择忽略大多数定时约束以达到这些分辨率。

返回

指向使用 drm_mode_create() 分配的模式的指针。如果出错,则返回 NULL。

struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, bool reduced, bool interlaced, bool margins)

基于 CVT 算法创建一个模式行

参数

struct drm_device *dev

drm 设备

int hdisplay

水平显示尺寸

int vdisplay

垂直显示尺寸

int vrefresh

垂直刷新率

bool reduced

是否使用缩减消隐

bool interlaced

是否计算隔行模式

bool margins

是否添加边距(边框)

描述

调用此函数以根据 hdisplay、vdisplay、vrefresh 基于 CVT 算法生成模式行。它基于 Graham Loveridge 于 2003 年 4 月 9 日提供的 VESA(TM) 协调视频定时生成器,该生成器位于 http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls

它从 xserver/hw/xfree86/modes/xf86cvt.c 中的 xf86CVTmode 复制而来。我所做的是通过使用整数计算对其进行转换。

返回

基于 CVT 算法的模式行存储在 drm_display_mode 对象中。显示模式对象使用 drm_mode_create() 分配。当无法分配模式时返回 NULL。

struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, bool interlaced, int margins, int GTF_M, int GTF_2C, int GTF_K, int GTF_2J)

基于完整 GTF 算法创建模式行

参数

struct drm_device *dev

drm 设备

int hdisplay

水平显示尺寸

int vdisplay

垂直显示尺寸

int vrefresh

垂直刷新率。

bool interlaced

是否计算隔行模式

int margins

所需的边距(边框)大小

int GTF_M

扩展的 GTF 公式参数

int GTF_2C

扩展的 GTF 公式参数

int GTF_K

扩展的 GTF 公式参数

int GTF_2J

扩展的 GTF 公式参数

描述

GTF 特性块以 0.5 的倍数指定 C 和 J,因此我们在此处传递它们时乘以 2。对于 C 为 40,传递 80。

返回

基于完整 GTF 算法的模式行存储在 drm_display_mode 对象中。显示模式对象使用 drm_mode_create() 分配。当无法分配模式时返回 NULL。

struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, bool interlaced, int margins)

基于 GTF 算法创建模式行

参数

struct drm_device *dev

drm 设备

int hdisplay

水平显示尺寸

int vdisplay

垂直显示尺寸

int vrefresh

垂直刷新率。

bool interlaced

是否计算隔行模式

int margins

所需的边距(边框)大小

描述

返回基于 GTF 算法的模式行

此函数用于基于 GTF 算法创建模式行。通用定时公式来源于

Andy Morrish (1/5/97) 的 GTF 电子表格,可在 https://www.vesa.org 获取

它从 xserver/hw/xfree86/modes/xf86gtf.c 文件中复制而来。我所做的是使用整数计算对其进行转换。我还参考了 drivers/video/fbmon.c 文件中的 fb_get_mode 函数。

标准 GTF 参数

M = 600
C = 40
K = 128
J = 20

返回

基于 GTF 算法的模式行存储在 drm_display_mode 对象中。显示模式对象使用 drm_mode_create() 分配。当无法分配模式时返回 NULL。

void drm_display_mode_from_videomode(const struct videomode *vm, struct drm_display_mode *dmode)

使用 vm 填充 dmode

参数

const struct videomode *vm

用作源的 videomode 结构

struct drm_display_mode *dmode

用作目标的 drm_display_mode 结构

描述

使用 vm 中指定的显示模式填充 dmode

void drm_display_mode_to_videomode(const struct drm_display_mode *dmode, struct videomode *vm)

使用 dmode 填充 vm

参数

const struct drm_display_mode *dmode

用作源的 drm_display_mode 结构

struct videomode *vm

用作目标的 videomode 结构

描述

使用 dmode 中指定的显示模式填充 vm

void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)

从 videomode 中提取有关 pixelclk 和 DE 极性的信息,并将其存储在单独的变量中

参数

const struct videomode *vm

要使用的 videomode 结构

u32 *bus_flags

有关 pixelclk、同步和 DE 极性的信息将存储在此处

描述

根据 vm 中找到的 DISPLAY_FLAGS,在 bus_flags 中设置 DRM_BUS_FLAG_DE_(LOW|HIGH)、DRM_BUS_FLAG_PIXDATA_DRIVE_(POS|NEG)EDGE 和 DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE

int of_get_drm_display_mode(struct device_node *np, struct drm_display_mode *dmode, u32 *bus_flags, int index)

从设备树获取 drm_display_mode

参数

struct device_node *np

带有定时规范的 device_node

struct drm_display_mode *dmode

将设置为返回值

u32 *bus_flags

有关 pixelclk、同步和 DE 极性的信息

int index

设备树中显示定时列表的索引

描述

此函数开销很大,仅当从 DT 读取一个模式时才应使用。要获取多个模式,请从 of_get_display_timings 开始,并使用它进行操作。

返回

成功时为 0,当未找到 videomode 节点时为负 errno 代码。

int of_get_drm_panel_display_mode(struct device_node *np, struct drm_display_mode *dmode, u32 *bus_flags)

从设备树获取面板定时 drm_display_mode

参数

struct device_node *np

带有面板定时规范的 device_node

struct drm_display_mode *dmode

将设置为返回值

u32 *bus_flags

有关 pixelclk、同步和 DE 极性的信息

描述

读取并设置显示模式的强制性设备树属性 width-mm 和 height-mm。

返回

成功时为零,失败时为负错误代码。

void drm_mode_set_name(struct drm_display_mode *mode)

在模式上设置名称

参数

struct drm_display_mode *mode

名称将在此模式中设置

描述

mode 的名称设置为标准格式,即 <hdisplay>x<vdisplay>,对于隔行扫描模式,可以选择添加 ‘i’ 后缀。

int drm_mode_vrefresh(const struct drm_display_mode *mode)

获取模式的 vrefresh

参数

const struct drm_display_mode *mode

mode

返回

modes 的垂直刷新率,以 Hz 为单位,四舍五入到最接近的整数。如果尚未设置,则首先计算该值。

void drm_mode_get_hv_timing(const struct drm_display_mode *mode, int *hdisplay, int *vdisplay)

获取给定模式的 hdisplay/vdisplay

参数

const struct drm_display_mode *mode

要查询的模式

int *hdisplay

要填充的 hdisplay 值

int *vdisplay

要填充的 vdisplay 值

描述

如果指定的模式是适当布局的立体模式,则 vdisplay 值将加倍。

void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)

设置 CRTC 模式设置定时参数

参数

struct drm_display_mode *p

mode

int adjust_flags

调整标志的组合

描述

p 设置 CRTC 模式设置定时参数,必要时进行调整。

  • CRTC_INTERLACE_HALVE_V 标志可用于将隔行扫描模式的垂直定时减半。

  • CRTC_STEREO_DOUBLE 标志可用于计算包含两个眼睛的缓冲区的定时(仅在需要时调整定时,例如,对于“帧打包”或“并排全”)。

  • CRTC_NO_DBLSCAN 和 CRTC_NO_VSCAN 标志分别请求不对双扫描和 vscan > 1 模式执行调整。

void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)

复制模式

参数

struct drm_display_mode *dst

要覆盖的模式

const struct drm_display_mode *src

要复制的模式

描述

将现有模式复制到另一个模式,保留目标模式的链表头。

void drm_mode_init(struct drm_display_mode *dst, const struct drm_display_mode *src)

从另一个模式初始化模式

参数

struct drm_display_mode *dst

要覆盖的模式

const struct drm_display_mode *src

要复制的模式

描述

将现有模式复制到另一个模式,清除目标模式的链表头。通常用于保证链表头在堆栈模式下不会留下堆栈垃圾。

struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, const struct drm_display_mode *mode)

分配并复制现有模式

参数

struct drm_device *dev

用于分配复制模式的drm_device

const struct drm_display_mode *mode

要复制的模式

描述

只是分配一个新模式,将现有模式复制到其中,并返回指向它的指针。用于创建已建立模式的新实例。

返回

成功时指向复制模式的指针,错误时为NULL。

bool drm_mode_match(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2, unsigned int match_flags)

测试模式是否(部分)相等

参数

const struct drm_display_mode *mode1

第一个模式

const struct drm_display_mode *mode2

第二个模式

unsigned int match_flags

哪些部分需要匹配 (DRM_MODE_MATCH_*)

描述

检查 **mode1** 和 **mode2** 是否等效。

返回

如果模式(部分)相等,则为 True,否则为 false。

bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)

测试模式是否相等

参数

const struct drm_display_mode *mode1

第一个模式

const struct drm_display_mode *mode2

第二个模式

描述

检查 **mode1** 和 **mode2** 是否等效。

返回

如果模式相等,则为 True,否则为 false。

bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)

测试模式是否相等

参数

const struct drm_display_mode *mode1

第一个模式

const struct drm_display_mode *mode2

第二个模式

描述

检查 **mode1** 和 **mode2** 是否等效,但不检查像素时钟。

返回

如果模式相等,则为 True,否则为 false。

bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)

测试模式是否相等

参数

const struct drm_display_mode *mode1

第一个模式

const struct drm_display_mode *mode2

第二个模式

描述

检查 **mode1** 和 **mode2** 是否等效,但不检查像素时钟和立体布局。

返回

如果模式相等,则为 True,否则为 false。

enum drm_mode_status drm_mode_validate_driver(struct drm_device *dev, const struct drm_display_mode *mode)

确保模式在某种程度上是合理的

参数

struct drm_device *dev

drm 设备

const struct drm_display_mode *mode

要检查的模式

描述

首先对模式进行基本验证,然后允许驱动程序通过可选的 drm_mode_config_helper_funcs.mode_valid 挂钩检查设备/驱动程序特定的限制。

返回

模式状态

enum drm_mode_status drm_mode_validate_size(const struct drm_display_mode *mode, int maxX, int maxY)

确保模式符合大小约束

参数

const struct drm_display_mode *mode

要检查的模式

int maxX

最大宽度

int maxY

最大高度

描述

此函数是一个辅助函数,可用于根据 DRM 设备/连接器的尺寸限制验证模式。如果模式太大,则其状态成员将使用适当的验证失败代码更新。列表本身不会更改。

返回

模式状态

enum drm_mode_status drm_mode_validate_ycbcr420(const struct drm_display_mode *mode, struct drm_connector *connector)

仅在允许时添加“ycbcr420-only”模式

参数

const struct drm_display_mode *mode

要检查的模式

struct drm_connector *connector

正在操作的drm 连接器

描述

此函数是一个辅助函数,可用于在源不支持 YCBCR420 时过滤掉任何仅限 YCBCR420 的模式。

返回

模式状态

void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose)

从模式列表中移除无效模式

参数

struct drm_device *dev

DRM 设备

struct list_head *mode_list

要检查的模式列表

bool verbose

是否输出详细信息

描述

此辅助函数可用于在验证完成后修剪显示模式列表。所有状态不是 MODE_OK 的模式都将从列表中删除,如果 verbose 为 true,则状态代码和模式名称也会打印到 dmesg。

void drm_mode_sort(struct list_head *mode_list)

排序模式列表

参数

struct list_head *mode_list

要排序的 drm_display_mode 结构列表

描述

按喜爱程度排序 mode_list,将良好模式移动到列表的头部。

void drm_connector_list_update(struct drm_connector *connector)

更新连接器的模式列表

参数

struct drm_connector *connector

要更新的连接器

描述

这将模式从 connector 的 probed_modes 列表移动到实际模式列表。它将探测到的模式与当前列表进行比较,并且仅添加不同/新的模式。

这只是一个辅助函数,本身不验证任何模式,也不修剪任何无效模式。调用者需要自己完成这些操作。

bool drm_mode_parse_command_line_for_connector(const char *mode_option, const struct drm_connector *connector, struct drm_cmdline_mode *mode)

解析连接器的命令行模式行

参数

const char *mode_option

可选的每个连接器模式选项

const struct drm_connector *connector

要为其解析模式行的连接器

struct drm_cmdline_mode *mode

要填充的预分配 drm_cmdline_mode 结构

描述

这将解析 mode_option 命令行模式行,以获取配置连接器的模式和选项。

这使用与 fb modedb.c 相同的参数,除了末尾的额外的强制启用、强制启用数字和强制禁用位

<xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]

可以在模式之后提供其他选项,使用逗号分隔每个选项。有效的选项可以在 modedb 默认视频模式支持 中找到。

需要中间的 drm_cmdline_mode 结构来存储来自命令行模式行的其他选项,例如强制启用/禁用标志。

返回

如果已解析有效的模式行,则为 True,否则为 false。

struct drm_display_mode *drm_mode_create_from_cmdline_mode(struct drm_device *dev, struct drm_cmdline_mode *cmd)

将命令行模式行转换为 DRM 显示模式

参数

struct drm_device *dev

用于创建新模式的 DRM 设备

struct drm_cmdline_mode *cmd

输入命令行模式行

返回

成功时指向转换后的模式的指针,错误时为 NULL。

bool drm_mode_is_420_only(const struct drm_display_info *display, const struct drm_display_mode *mode)

如果给定的视频模式只能以 YCBCR420 输出格式支持

参数

const struct drm_display_info *display

正在操作的显示器

const struct drm_display_mode *mode

要测试的视频模式。

返回

如果该模式可以以 YCBCR420 格式支持,则为 true,否则为 false。

bool drm_mode_is_420_also(const struct drm_display_info *display, const struct drm_display_mode *mode)

如果给定的视频模式也可以以 YCBCR420 输出格式支持(以及 RGB/YCBCR444/422)

参数

const struct drm_display_info *display

正在操作的显示器。

const struct drm_display_mode *mode

要测试的视频模式。

返回

如果该模式可以支持 YCBCR420 格式,则为 true,否则为 false。

bool drm_mode_is_420(const struct drm_display_info *display, const struct drm_display_mode *mode)

如果给定的视频模式可以以 YCBCR420 输出格式支持

参数

const struct drm_display_info *display

正在操作的显示器。

const struct drm_display_mode *mode

要测试的视频模式。

返回

如果该模式可以以 YCBCR420 格式支持,则为 true,否则为 false。

void drm_set_preferred_mode(struct drm_connector *connector, int hpref, int vpref)

设置连接器的首选模式

参数

struct drm_connector *connector

应处理其模式列表的连接器

int hpref

首选模式的水平分辨率

int vpref

首选模式的垂直分辨率

描述

如果某个模式与 hprefvpref 指定的分辨率匹配,则将其标记为首选模式。

连接器抽象

在 DRM 中,连接器是显示接收器的通用抽象,并且还包括固定面板或任何其他可以以某种形式显示像素的事物。与所有其他代表硬件的 KMS 对象(如 CRTC、编码器或平面抽象)相反,连接器可以在运行时热插拔。因此,它们使用 drm_connector_get()drm_connector_put() 进行引用计数。

KMS 驱动程序必须为每个此类接收器创建、初始化、注册和附加 struct drm_connector。该实例像其他 KMS 对象一样创建,并通过设置以下字段进行初始化。使用指向 struct drm_connector_funcs 和连接器类型的指针调用 drm_connector_init() 初始化连接器,然后通过调用 drm_connector_register() 将其暴露给用户空间。

连接器必须附加到编码器才能使用。对于将连接器映射到编码器 1:1 的设备,应在初始化时通过调用 drm_connector_attach_encoder() 附加连接器。驱动程序还必须将 drm_connector.encoder 字段设置为指向附加的编码器。

对于未固定的连接器(如内置面板),驱动程序需要支持热插拔通知。最简单的方法是使用探测辅助函数,请参阅 drm_kms_helper_poll_init(),用于那些没有硬件支持热插拔中断的连接器。对于具有硬件热插拔支持的连接器,可以使用例如 drm_helper_hpd_irq_event()

连接器函数参考

enum drm_connector_status

drm_connector 的状态

常量

connector_status_connected

连接器已明确连接到接收设备,并且可以启用。

connector_status_disconnected

连接器未连接到可以自动检测的接收设备。对于像 DP 或 HDMI 这样的数字输出(可以可靠探测),这意味着那里确实没有任何东西。具有此状态的连接器是否可以点亮取决于驱动程序。

connector_status_unknown

无法可靠地检测到连接器的状态。当探测会引起闪烁(例如,当连接器正在使用时进行负载检测),或者当硬件资源不可用时(例如,当负载检测需要空闲的 CRTC 时),就会发生这种情况。应该可以使用列出的后备模式之一点亮连接器。对于默认配置,当没有 **connector_status_connected** 的连接器时,用户空间应仅尝试点亮具有未知状态的连接器。

描述

此枚举用于跟踪连接器状态。uapi 没有单独的 #defines!

enum drm_connector_registration_state

drm_connector 的用户空间注册状态

常量

DRM_CONNECTOR_INITIALIZING

连接器刚刚创建,但尚未暴露给用户空间。对此连接器的状态如何修改不应有其他限制。

DRM_CONNECTOR_REGISTERED

连接器已完全初始化并在 sysfs 中注册,因此已暴露给用户空间。对此连接器的状态如何修改不应有其他限制。

DRM_CONNECTOR_UNREGISTERED

连接器要么已暴露给用户空间,然后从用户空间取消注册和移除,要么连接器在有机会暴露给用户空间之前被取消注册(例如,仍处于 **DRM_CONNECTOR_INITIALIZING** 状态)。当连接器被取消注册时,对其状态的修改方式有额外的限制

  • 取消注册的连接器只能将其 DPMS 从 On->Off 更改。一旦 DPMS 更改为 Off,就不能切换回 On。

  • 除非导致禁用其分配的 CRTC,否则不允许在未注册的连接器上进行模式设置。这意味着禁用未注册连接器上的 CRTC 是可以的,但启用它则不行。

  • 从未注册的连接器中移除 CRTC 是可以的,但新的 CRTC 永远不能分配给未注册的连接器。

描述

此枚举用于跟踪初始化连接器并将其注册到用户空间的状态,以便 DRM 可以防止在不再存在的连接器上进行虚假的模式设置。

enum drm_connector_tv_mode

模拟电视输出模式

常量

DRM_MODE_TV_MODE_NTSC

CCIR System M(又名 525 线)与 NTSC 彩色编码一起使用。

DRM_MODE_TV_MODE_NTSC_443

**DRM_MODE_TV_MODE_NTSC** 的变体。使用 4.43 MHz 的彩色副载波频率。

DRM_MODE_TV_MODE_NTSC_J

**DRM_MODE_TV_MODE_NTSC** 的变体,在日本使用。使用等于消隐电平的黑电平。

DRM_MODE_TV_MODE_PAL

CCIR System B 与 PAL 彩色系统一起使用。

DRM_MODE_TV_MODE_PAL_M

CCIR System M(又名 525 线)与 PAL 彩色编码一起使用

DRM_MODE_TV_MODE_PAL_N

CCIR System N 与 PAL 彩色编码一起使用。它使用 625 行,但具有 3.58MHz 的彩色副载波频率、SECAM 色彩空间以及比大多数其他 PAL 变体更窄的通道。

DRM_MODE_TV_MODE_SECAM

CCIR System B 与 SECAM 彩色系统一起使用。

DRM_MODE_TV_MODE_MONOCHROME

使用适合 DRM 模式的时序,包括用于 525 线或 625 线模式的均衡脉冲,没有基座或颜色编码。

DRM_MODE_TV_MODE_MAX

模拟电视输出模式的数量。

内部实现细节;这不是 uABI。

描述

此枚举用于指示模拟电视连接器上使用的电视输出模式。

警告:此枚举的值是 uABI,因为它们在“电视模式”连接器属性中公开。

struct drm_scrambling

接收器的加扰支持。

定义:

struct drm_scrambling {
    bool supported;
    bool low_rates;
};

成员

supported

支持高于 340 Mhz 的速率的加扰。

low_rates

支持小于等于 340 Mhz 的速率的加扰。

struct drm_hdmi_dsc_cap

HDMI 接收器的 DSC 功能

定义:

struct drm_hdmi_dsc_cap {
    bool v_1p2;
    bool native_420;
    bool all_bpp;
    u8 bpc_supported;
    u8 max_slices;
    int clk_per_slice;
    u8 max_lanes;
    u8 max_frl_rate_per_lane;
    u8 total_chunk_kbytes;
};

成员

v_1p2

接收器支持 dsc1.2 版本的标志

native_420

接收器是否支持使用 4:2:0 压缩的 DSC

all_bpp

接收器是否支持所有 bpp 与 4:4:4 或 4:2:2 压缩格式

bpc_supported

接收器支持的压缩 bpc:10、12 或 16 bpc

max_slices

支持的最大水平切片数

clk_per_slice

每个切片支持的最大像素时钟 (MHz)

max_lanes

固定速率链路训练支持的 dsc 最大通道数

max_frl_rate_per_lane

每个通道使用 DSC 的最大 frl 速率

total_chunk_kbytes

每行支持的最大块大小 (KB)

描述

描述 HDMI 2.1 接收器提供的 DSC 支持。该信息从为 HDMI 2.1 定义的附加 HFVSDB 块中获取。

struct drm_hdmi_info

有关已连接 HDMI 接收器的运行时信息

定义:

struct drm_hdmi_info {
    struct drm_scdc scdc;
    unsigned long y420_vdb_modes[BITS_TO_LONGS(256)];
    unsigned long y420_cmdb_modes[BITS_TO_LONGS(256)];
    u8 y420_dc_modes;
    u8 max_frl_rate_per_lane;
    u8 max_lanes;
    struct drm_hdmi_dsc_cap dsc_cap;
};

成员

scdc

接收器的 scdc 支持和功能

y420_vdb_modes

仅支持 ycbcr420 输出(而不是正常的 RGB/YCBCR444/422 输出)的模式的位图。CEA-861-G 规范定义的最大 VIC 为 219,因此大小为 256 位以映射到最多 256 个 VIC。

y420_cmdb_modes

也可以支持 ycbcr420 输出以及正常 HDMI 输出的模式的位图。CEA-861-G 规范定义的最大 VIC 为 219,因此大小为 256 位以映射到最多 256 个 VIC。

y420_dc_modes

深色支持索引的位图

max_frl_rate_per_lane

支持固定速率链路

max_lanes

接收器支持

dsc_cap

接收器的 DSC 功能

描述

描述给定显示器是否支持高级 HDMI 2.0 功能。此信息在 CEA-861-F 扩展块(如 HF-VSDB)中提供。

连接器的 link_status 属性值

常量

DRM_LINK_STATUS_GOOD

由于链路训练成功,DP 链路良好

DRM_LINK_STATUS_BAD

由于链路训练失败,DP 链路不良

描述

此枚举用作连接器的链路状态属性值。它设置为 uapi 中定义的值。

enum drm_panel_orientation

drm_display_info 的 panel_orientation 信息

常量

DRM_MODE_PANEL_ORIENTATION_UNKNOWN

drm 驱动程序未提供任何面板方向信息(对于非面板是正常的),在这种情况下,将不会附加“面板方向”连接器属性。

DRM_MODE_PANEL_ORIENTATION_NORMAL

面板的顶部与设备外壳的顶部匹配。

DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP

面板的顶部与设备外壳的底部匹配,即面板倒置安装。

DRM_MODE_PANEL_ORIENTATION_LEFT_UP

面板的左侧与设备外壳的顶部匹配。

DRM_MODE_PANEL_ORIENTATION_RIGHT_UP

面板的右侧与设备外壳的顶部匹配。

描述

此枚举用于跟踪(LCD)面板方向。uapi 没有单独的 #defines!

enum drm_hdmi_broadcast_rgb

HDMI **drm_connector** 的广播 RGB 选择

常量

DRM_HDMI_BROADCAST_RGB_AUTO

RGB 范围根据模式自动选择。

DRM_HDMI_BROADCAST_RGB_FULL

强制使用全范围 RGB。

DRM_HDMI_BROADCAST_RGB_LIMITED

强制使用有限范围 RGB。

struct drm_monitor_range_info

面板在 EDID 中的监视器范围,用于 drm_display_info

定义:

struct drm_monitor_range_info {
    u16 min_vfreq;
    u16 max_vfreq;
};

成员

min_vfreq

这是从 EDID 的详细监视器范围中解析出的最小支持刷新率,单位为赫兹 (Hz)。

max_vfreq

这是从 EDID 的详细监视器范围中解析出的最大支持刷新率,单位为赫兹 (Hz)。

描述

此结构体用于存储从 EDID 的详细监视器范围描述符块解析出的面板支持的频率范围。

struct drm_luminance_range_info

面板的亮度范围,用于 drm_display_info。使用 EDID 中的数据计算得出。

定义:

struct drm_luminance_range_info {
    u32 min_luminance;
    u32 max_luminance;
};

成员

min_luminance

这是支持的最小亮度值。

max_luminance

这是支持的最大亮度值。

描述

此结构体用于存储使用 EDID 的静态 HDR 元数据计算出的面板支持的亮度范围。

enum drm_privacy_screen_status

隐私屏幕状态

常量

PRIVACY_SCREEN_DISABLED

面板上的隐私屏幕已禁用。

PRIVACY_SCREEN_ENABLED

面板上的隐私屏幕已启用。

PRIVACY_SCREEN_DISABLED_LOCKED

面板上的隐私屏幕已禁用并锁定(无法更改)。

PRIVACY_SCREEN_ENABLED_LOCKED

面板上的隐私屏幕已启用并锁定(无法更改)。

描述

此枚举用于通过 “privacy-screen sw-state” 和 “privacy-screen hw-state” 属性跟踪和控制某些显示面板上集成的隐私屏幕的状态。请注意,_LOCKED 枚举值仅对 “privacy-screen hw-state” 属性有效。

enum drm_colorspace

色彩空间

常量

DRM_MODE_COLORIMETRY_DEFAULT

驱动程序特定的行为。

DRM_MODE_COLORIMETRY_NO_DATA

驱动程序特定的行为。

DRM_MODE_COLORIMETRY_SMPTE_170M_YCC

(HDMI) SMPTE ST 170M 色度格式

DRM_MODE_COLORIMETRY_BT709_YCC

(HDMI, DP) ITU-R BT.709 色度格式

DRM_MODE_COLORIMETRY_XVYCC_601

(HDMI, DP) xvYCC601 色度格式

DRM_MODE_COLORIMETRY_XVYCC_709

(HDMI, DP) xvYCC709 色度格式

DRM_MODE_COLORIMETRY_SYCC_601

(HDMI, DP) sYCC601 色度格式

DRM_MODE_COLORIMETRY_OPYCC_601

(HDMI, DP) opYCC601 色度格式

DRM_MODE_COLORIMETRY_OPRGB

(HDMI, DP) opRGB 色度格式

DRM_MODE_COLORIMETRY_BT2020_CYCC

(HDMI, DP) ITU-R BT.2020 Y’c C’bc C’rc (恒定亮度) 色度格式

DRM_MODE_COLORIMETRY_BT2020_RGB

(HDMI, DP) ITU-R BT.2020 R’ G’ B’ 色度格式

DRM_MODE_COLORIMETRY_BT2020_YCC

(HDMI, DP) ITU-R BT.2020 Y’ C’b C’r 色度格式

DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65

(HDMI) SMPTE ST 2113 P3D65 色度格式

DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER

(HDMI) SMPTE ST 2113 P3DCI 色度格式

DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED

(DP) RGB 宽色域定点色度格式

DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT

(DP) RGB 宽色域浮点 (scRGB (IEC 61966-2-2)) 色度格式

DRM_MODE_COLORIMETRY_BT601_YCC

(DP) ITU-R BT.601 色度格式。DP 规范未说明这是 525 行版本还是 625 行版本。

DRM_MODE_COLORIMETRY_COUNT

不是有效值;仅用于计数。

描述

此枚举是 HDMI 和 DP 协议标准支持的合并色度列表。相应的连接器将使用此列表的子集注册属性(由相应协议支持)。用户空间将通过一个将创建并暴露给用户空间的色彩空间属性来设置色彩空间。

DP 定义来自 DP v2.0 规范,HDMI 定义来自 CTA-861-H 规范。

enum drm_bus_flags

用于 drm_display_info 的 bus_flags 信息

常量

DRM_BUS_FLAG_DE_LOW

数据使能信号为低电平有效。

DRM_BUS_FLAG_DE_HIGH

数据使能信号为高电平有效。

DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE

数据在像素时钟的上升沿驱动。

DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE

数据在像素时钟的下降沿驱动。

DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE

数据在像素时钟的上升沿采样。

DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE

数据在像素时钟的下降沿采样。

DRM_BUS_FLAG_DATA_MSB_TO_LSB

数据在总线上以 MSB 到 LSB 的顺序传输。

DRM_BUS_FLAG_DATA_LSB_TO_MSB

数据在总线上以 LSB 到 MSB 的顺序传输。

DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE

同步信号在像素时钟的上升沿驱动。

DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE

同步信号在像素时钟的下降沿驱动。

DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE

同步信号在像素时钟的上升沿采样。

DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE

同步信号在像素时钟的下降沿采样。

DRM_BUS_FLAG_SHARP_SIGNALS

如果必须使用 Sharp 特定的信号(SPL、CLS、PS、REV),则设置此标志。

描述

此枚举定义了总线上信号的信号极性和时钟沿信息,作为位掩码标志。

时钟沿信息由两组符号传达,DRM_BUS_FLAGS_*_DRIVE_* 和 DRM_BUS_FLAGS_*_SAMPLE_*。当使用此枚举从发送器的角度描述总线时,应使用 *_DRIVE_* 标志。当从接收器的角度使用时,应使用 *_SAMPLE_* 标志。 *_DRIVE_* 和 *_SAMPLE_* 标志相互别名,其中 *_SAMPLE_POSEDGE 和 *_SAMPLE_NEGEDGE 标志分别等于 *_DRIVE_NEGEDGE 和 *_DRIVE_POSEDGE。这简化了代码,因为信号通常在驱动边的相反边采样。但是,发送器和接收器可能需要考虑其他信号时序,才能在驱动沿和采样沿之间进行转换。

struct drm_display_info

有关连接的接收器的运行时数据

定义:

struct drm_display_info {
    unsigned int width_mm;
    unsigned int height_mm;
    unsigned int bpc;
    enum subpixel_order subpixel_order;
#define DRM_COLOR_FORMAT_RGB444         (1<<0);
#define DRM_COLOR_FORMAT_YCBCR444       (1<<1);
#define DRM_COLOR_FORMAT_YCBCR422       (1<<2);
#define DRM_COLOR_FORMAT_YCBCR420       (1<<3);
    int panel_orientation;
    u32 color_formats;
    const u32 *bus_formats;
    unsigned int num_bus_formats;
    u32 bus_flags;
    int max_tmds_clock;
    bool dvi_dual;
    bool is_hdmi;
    bool has_audio;
    bool has_hdmi_infoframe;
    bool rgb_quant_range_selectable;
    u8 edid_hdmi_rgb444_dc_modes;
    u8 edid_hdmi_ycbcr444_dc_modes;
    u8 cea_rev;
    struct drm_hdmi_info hdmi;
    bool non_desktop;
    struct drm_monitor_range_info monitor_range;
    struct drm_luminance_range_info luminance_range;
    u8 mso_stream_count;
    u8 mso_pixel_overlap;
    u32 max_dsc_bpp;
    u8 *vics;
    int vics_len;
    u32 quirks;
    u16 source_physical_address;
};

成员

width_mm

物理宽度,单位为毫米 (mm)。

height_mm

物理高度,单位为毫米 (mm)。

bpc

每个颜色通道的最大位数。由 HDMI 和 DP 输出使用。

subpixel_order

液晶面板的子像素顺序。

panel_orientation

内置面板的只读连接器属性,指示面板相对于设备外壳的方向。drm_connector_init() 将此项设置为 DRM_MODE_PANEL_ORIENTATION_UNKNOWN。当不为 UNKNOWN 时,drm_fb_helpers 会使用它来旋转 fb 进行补偿,并将其作为 prop 导出到用户空间。

color_formats

HDMI 颜色格式,在 RGB 和 YCrCb 模式之间选择。使用 DRM_COLOR_FORMAT_ 定义,这些定义与用于描述帧缓冲区中像素格式的定义_不_相同,也与 bus_formats 中的格式不匹配,后者与 v4l 共享。

bus_formats

线路上的像素数据格式,与 color_formats 有些冗余。使用与 v4l 和媒体驱动程序共享的 MEDIA_BUS_FMT_ 定义编码的 num_bus_formats 大小的数组。

num_bus_formats

bus_formats 数组的大小。

bus_flags

总线上像素数据的其他信息(例如像素信号极性),使用 enum drm_bus_flags 值 DRM_BUS_FLAGS_。

max_tmds_clock

接收器支持的最大 TMDS 时钟速率,单位为千赫 (kHz)。0 表示未定义。

dvi_dual

双链路 DVI 接收器?

is_hdmi

如果接收器是 HDMI 设备,则为 True。

应尽可能使用此字段,而不是调用 drm_detect_hdmi_monitor()

has_audio

如果接收器支持音频,则为 True。

应尽可能使用此字段,而不是调用 drm_detect_monitor_audio()

has_hdmi_infoframe

接收器是否支持 HDMI 信息帧?

rgb_quant_range_selectable

接收器是否支持选择 RGB 量化范围?

edid_hdmi_rgb444_dc_modes

RGB 4:4:4 中支持的 hdmi 深色模式的掩码。更多与 bus_formats 冗余的东西。

edid_hdmi_ycbcr444_dc_modes

YCbCr 4:4:4 中支持的 hdmi 深色模式的掩码。更多与 bus_formats 冗余的东西。

cea_rev

HDMI 接收器的 CEA 修订版本。

hdmi

HDMI 接收器的高级功能。

non_desktop

非桌面显示器 (HMD)。

monitor_range

监视器范围描述符支持的频率范围。

luminance_range

面板支持的亮度范围。

mso_stream_count

来自 DisplayID VESA 供应商块的 eDP 多 SST 操作 (MSO) 流计数。0 表示传统的单流传输 (SST),或 2 或 4 个 MSO 流。

mso_pixel_overlap

eDP MSO 段像素重叠,0-8 像素。

max_dsc_bpp

最大 DSC 目标比特率,如果设置为 0,则改为使用监视器的默认值。

vics

vics_len 个 VIC 的数组。EDID 解析的内部内容。

vics_len

vics 中的元素数。EDID 解析的内部内容。

quirks

基于 EDID 的怪癖。EDID 解析的内部内容。

source_physical_address

来自 HDMI 供应商特定数据块的源物理地址,用于 CEC。

默认为 CEC_PHYS_ADDR_INVALID (0xffff)。

描述

描述给定的显示器(例如 CRT 或平板)及其限制。对于像内置面板这样的固定显示接收器,此结构体和 struct drm_connector 之间没有太大区别。但是对于带有真实电缆的接收器,此结构体旨在描述电缆另一端的所有事物。

对于提供 EDID 的接收器,可以通过调用 drm_add_edid_modes() 来填充此结构体。

struct drm_connector_tv_margins

电视接口相关的边距

定义:

struct drm_connector_tv_margins {
    unsigned int bottom;
    unsigned int left;
    unsigned int right;
    unsigned int top;
};

成员

bottom

底部边距,以像素为单位。

left

左侧边距,以像素为单位。

right

右侧边距,以像素为单位。

top

顶部边距,以像素为单位。

描述

描述在电视接口上围绕图像放置的边距(以像素为单位),以处理过扫描。

struct drm_tv_connector_state

电视接口相关的状态

定义:

struct drm_tv_connector_state {
    enum drm_mode_subconnector select_subconnector;
    enum drm_mode_subconnector subconnector;
    struct drm_connector_tv_margins margins;
    unsigned int legacy_mode;
    unsigned int mode;
    unsigned int brightness;
    unsigned int contrast;
    unsigned int flicker_reduction;
    unsigned int overscan;
    unsigned int saturation;
    unsigned int hue;
};

成员

select_subconnector

选择的子接口

subconnector

检测到的子接口

margins

电视边距

legacy_mode

旧式电视模式,驱动程序特定的值

mode

电视模式

brightness

亮度,以百分比表示

contrast

对比度,以百分比表示

flicker_reduction

闪烁减少,以百分比表示

overscan

过扫描,以百分比表示

saturation

饱和度,以百分比表示

hue

色调,以百分比表示

struct drm_connector_hdmi_infoframe

HDMI Infoframe 容器

定义:

struct drm_connector_hdmi_infoframe {
    union hdmi_infoframe data;
    bool set;
};

成员

data

HDMI Infoframe 结构

set

data 的内容是否有效?

struct drm_connector_state

可变连接器状态

定义:

struct drm_connector_state {
    struct drm_connector *connector;
    struct drm_crtc *crtc;
    struct drm_encoder *best_encoder;
    enum drm_link_status link_status;
    struct drm_atomic_state *state;
    struct drm_crtc_commit *commit;
    struct drm_tv_connector_state tv;
    bool self_refresh_aware;
    enum hdmi_picture_aspect picture_aspect_ratio;
    unsigned int content_type;
    unsigned int hdcp_content_type;
    unsigned int scaling_mode;
    unsigned int content_protection;
    enum drm_colorspace colorspace;
    struct drm_writeback_job *writeback_job;
    u8 max_requested_bpc;
    u8 max_bpc;
    enum drm_privacy_screen_status privacy_screen_sw_state;
    struct drm_property_blob *hdr_output_metadata;
    struct drm_connector_hdmi_state hdmi;
};

成员

connector

指向连接器的反向指针

crtc

连接器要连接到的 CRTC,如果禁用则为 NULL。

不要直接更改此项,请改用 drm_atomic_set_crtc_for_connector()

best_encoder

由原子助手使用,通过 drm_connector_helper_funcs.atomic_best_encoderdrm_connector_helper_funcs.best_encoder 回调来选择编码器。

这也在原子助手中使用,以将编码器映射到其当前和之前的连接器,请参阅 drm_atomic_get_old_connector_for_encoder()drm_atomic_get_new_connector_for_encoder()

注意:原子驱动程序必须填写此项(无论是自己填写还是通过助手填写),否则 GETCONNECTOR 和 GETENCODER IOCTL 将不会向用户空间返回正确的数据。

link_status

连接器 link_status 用于跟踪链路是 GOOD 还是 BAD,以便在需要重新训练时通知用户空间。

state

指向全局 drm_atomic_state 的后向指针

commit

跟踪待处理的提交,以防止出现使用后释放的情况。

仅当 crtc 为 NULL 时才设置。

tv

电视接口状态

self_refresh_aware

这跟踪连接器是否知道自刷新状态。对于那些了解自刷新状态的连接器实现,应将其设置为 true。这是必需的,因为 crtc 注册了自刷新助手,并且它不知道下游的连接器是否已实现自刷新进入/退出。

如果驱动程序知道如何处理自刷新请求,则应在 atomic_check 中将其设置为 true。

picture_aspect_ratio

用于控制 HDMI 信息帧纵横比设置的连接器属性。

DRM_MODE_PICTURE_ASPECT_* 值必须与 enum hdmi_picture_aspect 的值匹配

content_type

用于控制 HDMI 信息帧内容类型设置的连接器属性。DRM_MODE_CONTENT_TYPE_* 值必须与这些值匹配。

hdcp_content_type

用于传递受保护内容类型的连接器属性。这通常用于 HDCP。

scaling_mode

用于控制放大倍数的连接器属性,主要用于内置面板。

content_protection

用于请求内容保护的连接器属性。这通常用于 HDCP。

colorspace

用于请求在接收器上更改色彩空间的连接器属性的状态变量。这通常用于切换到更宽的色域,例如 BT2020。

writeback_job

回写连接器的回写作业

为回写连接器保存帧缓冲区和输出栅栏。由于回写完成可能与正常的提交周期异步,因此回写作业的生命周期由该对象与正常的原子状态分开管理。

另请参阅: drm_writeback_queue_job()drm_writeback_signal_completion()

max_requested_bpc

用于限制像素最大位深度的连接器属性。

max_bpc

连接器 max_bpc 基于请求的 max_bpc 属性和从 edid 获取的连接器 bpc 限制。

privacy_screen_sw_state

请参阅 标准连接器属性

hdr_output_metadata

用于 HDR 输出元数据的 DRM blob 属性

hdmi

HDMI 相关变量和属性。由 drm_atomic_helper_connector_hdmi_check() 填充。

struct drm_connector_hdmi_funcs

drm_hdmi_connector 控制函数

定义:

struct drm_connector_hdmi_funcs {
    enum drm_mode_status(*tmds_char_rate_valid)(const struct drm_connector *connector,const struct drm_display_mode *mode, unsigned long long tmds_rate);
    int (*clear_infoframe)(struct drm_connector *connector, enum hdmi_infoframe_type type);
    int (*write_infoframe)(struct drm_connector *connector,enum hdmi_infoframe_type type, const u8 *buffer, size_t len);
};

成员

tmds_char_rate_valid

在 atomic_check 时调用此回调,以确定驱动程序是否支持特定的 TMDS 字符速率。

tmds_char_rate_valid 回调是可选的。

返回值

drm_mode_status.MODE_OKenum drm_mode_status 中的一个失败原因。

clear_infoframe

在提交期间,通过 drm_atomic_helper_connector_hdmi_update_infoframes 调用此回调,以将信息帧清除到硬件中。它将被多次调用,每次针对每个禁用的信息帧类型调用一次。

clear_infoframe 回调是可选的。

返回值:成功时为 0,否则为负错误代码

write_infoframe

在提交期间,通过 drm_atomic_helper_connector_hdmi_update_infoframes 调用此回调,以将信息帧编程到硬件中。它将被多次调用,每次针对每个更新的信息帧类型调用一次。

write_infoframe 回调是必需的。

返回值:成功时为 0,否则为负错误代码

struct drm_connector_funcs

控制给定设备上的连接器

定义:

struct drm_connector_funcs {
    int (*dpms)(struct drm_connector *connector, int mode);
    void (*reset)(struct drm_connector *connector);
    enum drm_connector_status (*detect)(struct drm_connector *connector, bool force);
    void (*force)(struct drm_connector *connector);
    int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
    int (*set_property)(struct drm_connector *connector, struct drm_property *property, uint64_t val);
    int (*late_register)(struct drm_connector *connector);
    void (*early_unregister)(struct drm_connector *connector);
    void (*destroy)(struct drm_connector *connector);
    struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector);
    void (*atomic_destroy_state)(struct drm_connector *connector, struct drm_connector_state *state);
    int (*atomic_set_property)(struct drm_connector *connector,struct drm_connector_state *state,struct drm_property *property, uint64_t val);
    int (*atomic_get_property)(struct drm_connector *connector,const struct drm_connector_state *state,struct drm_property *property, uint64_t *val);
    void (*atomic_print_state)(struct drm_printer *p, const struct drm_connector_state *state);
    void (*oob_hotplug_event)(struct drm_connector *connector, enum drm_connector_status status);
    void (*debugfs_init)(struct drm_connector *connector, struct dentry *root);
};

成员

dpms

用于设置每个连接器的 DPMS 状态的旧式入口点。旧式 DPMS 在连接器上作为标准属性公开,但在 drm 核心中被转移到此回调。请注意,原子驱动程序不再在连接器上实现 4 级 DPMS 支持,而是在 CRTC 对象上只有一个打开/关闭“ACTIVE”属性。

原子驱动程序不使用此挂钩,旧式 DPMS 属性的重新映射完全在 DRM 核心中处理。

返回

成功返回 0,失败返回负错误代码。

reset

将连接器硬件和软件状态重置为关闭。此函数不由核心直接调用,仅通过 drm_mode_config_reset() 调用。它不是一个助手挂钩,仅出于历史原因。

原子驱动程序可以使用 drm_atomic_helper_connector_reset() 使用此挂钩重置原子状态。

detect

检查是否有任何东西连接到连接器。参数 force 在轮询时设置为 false,在由于用户请求检查连接器时设置为 true。驱动程序可以使用 force 来避免在自动探测期间进行代价高昂的破坏性操作。

此回调是可选的,如果未实现,则连接器将被视为始终处于连接状态。

FIXME

请注意,此挂钩仅由探测助手调用。它没有在助手库 vtable 中,纯粹是出于历史原因。用于探测连接器状态的唯一 DRM 核心入口点是 fill_modes

请注意,助手库将已经持有 drm_mode_config.connection_mutex。需要获取其他锁以避免与并发模式设置更改发生竞争的驱动程序需要改用 drm_connector_helper_funcs.detect_ctx

另请注意,无论连接器处于什么状态,都可以调用此回调。需要底层设备通电才能执行检测的驱动程序首先需要确保已正确启用该设备。

返回

drm_connector_status 表示连接器的状态。

force

当用户空间通过 sysfs 接口或内核 cmdline 强制连接器进入特定状态时,将调用此函数以更新内部编码器状态。在这种情况下,不会调用 detect 回调。

FIXME

请注意,此挂钩仅由探测助手调用。它没有在助手库 vtable 中,纯粹是出于历史原因。用于探测连接器状态的唯一 DRM 核心入口点是 fill_modes

fill_modes

输出检测和基本模式验证的入口点。如果需要(例如,当热插拔处理不可靠时),驱动程序应重新探测输出,将所有检测到的模式添加到 drm_connector.modes,并过滤掉设备在任何配置中都无法支持的任何模式。它还需要过滤掉任何比参数 max_width 和 max_height 指示的更宽或更高的模式。

驱动程序还必须从 drm_connector.modes 中删除任何不再有效的模式。此外,它必须更新 drm_connector.statusdrm_connector.edid。如果没有为此输出收到 EDID,则 connector->edid 必须为 NULL。

使用探测助手的驱动程序应使用 drm_helper_probe_single_connector_modes() 来实现此函数。

返回

检测到并填充到 drm_connector.modes 中的模式数量。

set_property

这是更新附加到连接器的属性的旧式入口点。

如果驱动程序不支持任何传统驱动程序私有属性,则此回调是可选的。对于原子驱动程序,它不使用,因为属性处理完全在 DRM 内核中完成。

返回

成功返回 0,失败返回负错误代码。

late_register

这个可选的钩子可以用来注册连接器附加的额外用户空间接口,例如背光控制、i2c、DP aux 或类似的接口。它在驱动程序加载序列的后期,从 drm_connector_register() 中调用,用于注册所有核心 drm 连接器接口。从这个回调添加的所有内容都应该在 early_unregister 回调中注销。

此函数在持有 drm_connector.mutex 时被调用。

返回值

成功时返回 0,失败时返回负错误代码。

early_unregister

这个可选的钩子应该用于注销从 late_register() 附加到连接器的额外用户空间接口。它在驱动程序卸载序列的早期,从 drm_connector_unregister() 中调用,以在数据结构被拆除之前禁用用户空间访问。

此函数在持有 drm_connector.mutex 时被调用。

destroy

清理连接器资源。它在驱动程序卸载时通过 drm_mode_config_cleanup() 调用。当连接器被热插拔时,对于支持连接器热插拔的驱动程序(例如 DisplayPort MST),它也可以在运行时调用。

atomic_duplicate_state

复制此连接器的当前原子状态并返回它。核心和助手保证任何通过此钩子复制的原子状态,并且仍然由调用者拥有(即,没有通过调用 drm_mode_config_funcs.atomic_commit 转移到驱动程序),都会通过调用此结构中的 atomic_destroy_state 钩子来清理。

此回调对于原子驱动程序是强制性的。

不子类化 struct drm_connector_state 的原子驱动程序应该使用 drm_atomic_helper_connector_duplicate_state()。子类化状态结构以使用驱动程序私有状态扩展它的驱动程序应该使用 __drm_atomic_helper_connector_duplicate_state(),以确保跨驱动程序以一致的方式复制共享状态。

drm_connector.state 被正确初始化之前调用此钩子是错误的。

注意

如果重复的状态引用了引用计数的资源,则此钩子必须为每个资源获取引用。驱动程序必须在 atomic_destroy_state 中再次释放这些引用。

返回

当分配失败时,重复的原子状态或 NULL。

atomic_destroy_state

销毁使用 atomic_duplicate_state 复制的状态,并释放或取消引用其引用的所有资源

此回调对于原子驱动程序是强制性的。

atomic_set_property

解码驱动程序私有属性值,并将解码的值存储到传入的状态结构中。由于原子内核解码所有标准化的属性(即使对于核心属性集之外的扩展,这些扩展可能并非所有驱动程序都实现),因此这要求驱动程序子类化状态结构。

此类驱动程序私有属性实际上仅应针对真正的硬件/供应商特定状态实现。相反,最好标准化原子扩展,并在内核中解码用于公开此类扩展的属性。

不要直接调用此函数,请使用 drm_atomic_connector_set_property() 代替。

如果驱动程序不支持任何驱动程序私有原子属性,则此回调是可选的。

注意

此函数在原子模式设置的状态组装阶段调用,该阶段可能出于任何原因中止(包括在用户空间请求时仅检查配置是否可能)。驱动程序不得触及任何持久状态(硬件或软件)或数据结构,除了传入的 state 参数。

此外,由于用户空间控制属性的设置顺序,因此此函数不得进行任何输入验证(因为状态更新不完整,因此可能不一致)。相反,任何此类输入验证都必须在各种 atomic_check 回调中完成。

返回

如果已找到该属性,则为 0;如果该属性未由驱动程序实现,则为 -EINVAL(这不应该发生,核心仅请求附加到此连接器的属性)。驱动程序不允许进行其他验证。核心已经检查过属性值是否在驱动程序注册属性时设置的范围内(整数、有效的枚举值等)。

atomic_get_property

读取解码后的驱动程序私有属性。这用于实现 GETCONNECTOR IOCTL。

不要直接调用此函数,请使用 drm_atomic_connector_get_property() 代替。

如果驱动程序不支持任何驱动程序私有原子属性,则此回调是可选的。

返回

成功时为 0,如果属性未由驱动程序实现,则为 -EINVAL(这不应该发生,核心仅请求附加到此连接器的属性)。

atomic_print_state

如果驱动程序子类化 struct drm_connector_state,它应该实现此可选的钩子来打印额外的驱动程序特定状态。

不要直接调用此函数,请使用 drm_atomic_connector_print_state() 代替。

oob_hotplug_event

当从显示驱动程序/设备外部的源接收到 drm 连接器的热插拔事件时,将调用此函数。

debugfs_init

允许连接器创建特定于连接器的 debugfs 文件。

描述

每个 CRTC 可以连接一个或多个连接器。以下函数允许核心 DRM 代码控制连接器、枚举可用模式等。

struct drm_cmdline_mode

通过内核命令行传递的 DRM 模式

定义:

struct drm_cmdline_mode {
    char name[DRM_DISPLAY_MODE_LEN];
    bool specified;
    bool refresh_specified;
    bool bpp_specified;
    unsigned int pixel_clock;
    int xres;
    int yres;
    int bpp;
    int refresh;
    bool rb;
    bool interlace;
    bool cvt;
    bool margins;
    enum drm_connector_force force;
    unsigned int rotation_reflection;
    enum drm_panel_orientation panel_orientation;
    struct drm_connector_tv_margins tv_margins;
    enum drm_connector_tv_mode tv_mode;
    bool tv_mode_specified;
};

成员

名称

模式的名称。

specified

是否已从命令行读取模式?

refresh_specified

模式是否有首选刷新率?

bpp_specified

模式是否有首选 BPP?

pixel_clock

像素时钟,单位为 kHz。可选。

xres

X 轴上的活动分辨率,以像素为单位。

yres

Y 轴上的活动分辨率,以像素为单位。

bpp

模式的每像素位数。

refresh

刷新率,单位为赫兹。

rb

我们需要使用减少消隐吗?

interlace

该模式是隔行的。

cvt

时序将使用 VESA 协调视频时序计算,而不是从表中查找模式。

margins

将边距添加到模式计算中(xres 的 1.8% 向下舍入为 8 像素,yres 的 1.8%)。

force

忽略连接器的热插拔状态,并强制其状态为 DRM_FORCE_* 值之一。

rotation_reflection

从命令行设置的模式的初始旋转和反射。请参阅 DRM_MODE_ROTATE_* 和 DRM_MODE_REFLECT_*。唯一支持的旋转是 DRM_MODE_ROTATE_0 和 DRM_MODE_ROTATE_180。

panel_orientation

drm-connector “面板方向”属性覆盖值,如果未设置,则为 DRM_MODE_PANEL_ORIENTATION_UNKNOWN。

tv_margins

要应用于模式的电视边距。

tv_mode

电视模式标准。请参阅 DRM_MODE_TV_MODE_*。

tv_mode_specified

模式是否有首选的电视模式?

描述

每个连接器都可以有一个初始模式,以及通过内核命令行传递的附加选项。此结构允许表达这些参数,并将由命令行解析器填充。

struct drm_connector

中央 DRM 连接器控制结构

定义:

struct drm_connector {
    struct drm_device *dev;
    struct device *kdev;
    struct device_attribute *attr;
    struct fwnode_handle *fwnode;
    struct list_head head;
    struct list_head global_connector_list_entry;
    struct drm_mode_object base;
    char *name;
    struct mutex mutex;
    unsigned index;
    int connector_type;
    int connector_type_id;
    bool interlace_allowed;
    bool doublescan_allowed;
    bool stereo_allowed;
    bool ycbcr_420_allowed;
    enum drm_connector_registration_state registration_state;
    struct list_head modes;
    enum drm_connector_status status;
    struct list_head probed_modes;
    struct drm_display_info display_info;
    const struct drm_connector_funcs *funcs;
    struct drm_property_blob *edid_blob_ptr;
    struct drm_object_properties properties;
    struct drm_property *scaling_mode_property;
    struct drm_property *vrr_capable_property;
    struct drm_property *colorspace_property;
    struct drm_property_blob *path_blob_ptr;
    unsigned int max_bpc;
    struct drm_property *max_bpc_property;
    struct drm_privacy_screen *privacy_screen;
    struct notifier_block privacy_screen_notifier;
    struct drm_property *privacy_screen_sw_state_property;
    struct drm_property *privacy_screen_hw_state_property;
    struct drm_property *broadcast_rgb_property;
#define DRM_CONNECTOR_POLL_HPD (1 << 0);
#define DRM_CONNECTOR_POLL_CONNECT (1 << 1);
#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2);
    uint8_t polled;
    int dpms;
    const struct drm_connector_helper_funcs *helper_private;
    struct drm_cmdline_mode cmdline_mode;
    enum drm_connector_force force;
    const struct drm_edid *edid_override;
    struct mutex edid_override_mutex;
    u64 epoch_counter;
    u32 possible_encoders;
    struct drm_encoder *encoder;
#define MAX_ELD_BYTES   128;
    uint8_t eld[MAX_ELD_BYTES];
    bool latency_present[2];
    int video_latency[2];
    int audio_latency[2];
    struct i2c_adapter *ddc;
    int null_edid_counter;
    unsigned bad_edid_counter;
    bool edid_corrupt;
    u8 real_edid_checksum;
    struct dentry *debugfs_entry;
    struct drm_connector_state *state;
    struct drm_property_blob *tile_blob_ptr;
    bool has_tile;
    struct drm_tile_group *tile_group;
    bool tile_is_single_monitor;
    uint8_t num_h_tile, num_v_tile;
    uint8_t tile_h_loc, tile_v_loc;
    uint16_t tile_h_size, tile_v_size;
    struct llist_node free_node;
    struct hdr_sink_metadata hdr_sink_metadata;
    struct drm_connector_hdmi hdmi;
};

成员

dev

父 DRM 设备

kdev

用于 sysfs 属性的内核设备

attr

sysfs 属性

fwnode

平台固件提供的相关 fwnode

驱动程序可以设置此项以将 fwnode 与连接器关联,驱动程序在设置此项时应获取对 fwnode 的引用。drm_connector_cleanup() 将对此调用 fwnode_handle_put()。

head

dev 上的所有连接器列表,从 drm_mode_config.connector_list 链接。受 drm_mode_config.connector_list_lock 保护,但请仅使用 drm_connector_list_iter 来遍历此列表。

global_connector_list_entry

全局连接器列表中的连接器条目,由 drm_connector_find_by_fwnode() 使用。

基础

基本 KMS 对象

名称

人类可读的名称,可以被驱动程序覆盖

mutex

用于通用连接器状态的锁,但目前仅保护 registered。大多数连接器状态仍然受 drm_mode_config.mutex 保护。

index

压缩的连接器索引,它与不支持热添加/删除的驱动程序的 mode_config.list 中的位置匹配。可以用作数组索引。它在连接器的生命周期内是不变的。

connector_type

drm_mode.h 中的 DRM_MODE_CONNECTOR_<foo> 类型之一

connector_type_id

连接器类型枚举的索引

interlace_allowed

此连接器可以处理隔行模式吗?仅由 drm_helper_probe_single_connector_modes() 用于模式过滤。

doublescan_allowed

此连接器可以处理双扫描吗?仅由 drm_helper_probe_single_connector_modes() 用于模式过滤。

stereo_allowed

此连接器可以处理立体模式吗?仅由 drm_helper_probe_single_connector_modes() 用于模式过滤。

ycbcr_420_allowed

此布尔值指示此连接器是否能够处理 YCBCR 420 输出。在解析 EDID 块时,了解源是否能够处理 YCBCR 420 输出非常有帮助。

registration_state

此连接器是正在初始化、已向用户空间公开(已注册),还是未注册?

mutex 保护。

modes

此连接器上可用的模式(来自 fill_modes() + 用户)。受 drm_mode_config.mutex 保护。

status

drm_connector_status 枚举之一(已连接、未连接或未知)。受 drm_mode_config.mutex 保护。

probed_modes

这些是通过使用 DDC 或 BIOS 探测添加的模式,在应用过滤之前。由探测助手使用。受 drm_mode_config.mutex 保护。

display_info

当检测到显示器时,显示信息从 EDID 信息中填充。对于嵌入式系统中非热插拔的显示器(例如平板),驱动程序应使用显示器的物理尺寸初始化 drm_display_info.width_mmdrm_display_info.height_mm 字段。

drm_mode_config.mutex 保护。

funcs

连接器控制函数

edid_blob_ptr

包含 EDID 的 DRM 属性(如果存在)。受 drm_mode_config.mutex 保护。

必须仅通过调用 drm_edid_connector_update()drm_connector_update_edid_property() 来更新此项。

驱动程序不得直接使用此项。

properties

此连接器的属性跟踪

scaling_mode_property

可选的原子属性,用于控制放大。请参阅 drm_connector_attach_content_protection_property()

vrr_capable_property

可选属性,用于帮助用户空间查询连接器上对可变刷新率的硬件支持。驱动程序可以通过调用 drm_connector_attach_vrr_capable_property() 将此属性添加到连接器。

此属性应仅通过调用 drm_connector_set_vrr_capable_property() 更新。

colorspace_property

连接器属性,用于设置接收器支持的合适色彩空间。

path_blob_ptr

DP MST 路径属性的 DRM blob 属性数据。此属性应仅通过调用 drm_connector_set_path_property() 更新。

max_bpc

连接器支持的最大每个颜色通道的位数。

max_bpc_property

用于从连接器驱动输出的最大 bpc 的默认连接器属性。

privacy_screen

此连接器的 drm_privacy_screen,或者为 NULL。

privacy_screen_notifier

隐私屏幕 notifier_block

privacy_screen_sw_state_property

可选的原子属性,用于连接器控制集成的隐私屏幕。

privacy_screen_hw_state_property

可选的原子属性,用于连接器报告实际的集成隐私屏幕状态。

broadcast_rgb_property

连接器属性,用于设置要输出的广播 RGB 选择。

polled

连接器轮询模式,以下各项的组合:

DRM_CONNECTOR_POLL_HPD

连接器生成热插拔事件,无需定期轮询。CONNECT 和 DISCONNECT 标志不得与 HPD 标志一起设置。

DRM_CONNECTOR_POLL_CONNECT

定期轮询连接器的连接状态。

DRM_CONNECTOR_POLL_DISCONNECT

定期轮询连接器的断开状态,即使连接器正在使用,也不会导致闪烁。DAC 很少在没有大量测试的情况下执行此操作。

对于不支持连接状态发现的连接器,设置为 0。

dpms

当前 dpms 状态。对于旧版驱动程序,drm_connector_funcs.dpms 回调必须更新此状态。对于原子驱动程序,这由核心原子代码处理,驱动程序只需考虑 drm_crtc_state.active

helper_private

中间层私有数据

cmdline_mode

从此连接器的内核 cmdline 解析的模式行

force

强制模式设置的 DRM_FORCE_<foo> 状态

edid_override

通过 debugfs 设置的覆盖 EDID。

请勿在 drm_edid_override_* 函数系列之外修改或访问。

edid_override_mutex

保护对 edid_override 的访问。

epoch_counter

用于检测连接器中的任何其他更改,除了状态之外

possible_encoders

可以驱动此连接器的编码器的位掩码,drm_encoder_index() 确定位字段中的索引,并且这些位使用 drm_connector_attach_encoder() 设置。

encoder

当前绑定到此连接器的编码器,如果有。仅对于非原子驱动程序才有意义。原子驱动程序应改为查看 drm_connector_state.best_encoder,如果需要驱动此输出的 CRTC,则查看 drm_connector_state.crtc

eld

类似 EDID 的数据,如果存在

latency_present

来自 ELD 的 AV 延迟信息,如果找到

video_latency

来自 ELD 的视频延迟信息,如果找到。[0]: 逐行扫描,[1]: 隔行扫描

audio_latency

来自 ELD 的音频延迟信息,如果找到 [0]: 逐行扫描,[1]: 隔行扫描

ddc

关联的 ddc 适配器。连接器通常具有其关联的 ddc 适配器。如果驱动程序使用此字段,则会在连接器 sysfs 目录中创建一个适当的符号链接,以便用户可以轻松地确定哪个 i2c 适配器用于特定显示器。

该字段应通过调用 drm_connector_init_with_ddc() 设置。

null_edid_counter

跟踪为我们提供所有零 EDID 的接收器。需要解决一些我们得到全 0 的硬件错误

bad_edid_counter

跟踪为我们提供具有无效校验和的 EDID 的接收器

edid_corrupt

指示上次读取的 EDID 是否已损坏。用于 Displayport 一致性测试 - Displayport Link CTS Core 1.2 rev1.1 4.2.2.6

real_edid_checksum

损坏的 edid 块的实际 edid 校验和。Displayport 1.4 一致性测试 rev1.1 4.2.2.6 中需要

debugfs_entry

此连接器的 debugfs 目录

state

此连接器的当前原子状态。

这由 drm_mode_config.connection_mutex 保护。请注意,非阻塞原子提交会在不加锁的情况下访问当前连接器状态。可以通过 struct drm_atomic_state 指针,请参阅 for_each_oldnew_connector_in_state()for_each_old_connector_in_state()for_each_new_connector_in_state()。或者通过原子帮助程序中实现的原子提交操作的仔细排序,请参阅 struct drm_crtc_commit

tile_blob_ptr

用于 tile 属性的 DRM blob 属性数据(主要由 DP MST 使用)。这适用于通过由 drm_crtc 表示的单独显示管道驱动的屏幕,这些屏幕可能没有使用 genlocked 时钟运行。对于像双链路 LVDS 或双链路 DSI 这样进行 genlocked 的平铺面板,驱动程序应尝试不暴露平铺并虚拟化 drm_crtcdrm_plane(如果需要)。

此属性应仅通过调用 drm_connector_set_tile_property() 更新。

has_tile

此连接器是否连接到平铺的监视器

tile_group

已连接监视器的平铺组

tile_is_single_monitor

平铺是否为一个监视器外壳

num_h_tile

平铺组中水平平铺的数量

num_v_tile

平铺组中垂直平铺的数量

tile_h_loc

此平铺的水平位置

tile_v_loc

此平铺的垂直位置

tile_h_size

此平铺的水平大小。

tile_v_size

此平铺的垂直大小。

free_node

仅由 drm_connector_list_iter 使用的列表,以便能够结合 drm_mode_config.connector_free_work 从任何上下文中清理连接器。

hdr_sink_metadata

从接收器读取的 HDR 元数据信息

hdmi

HDMI 相关变量和属性。

描述

每个连接器可以连接到一个或多个 CRTC,或者如果它们可以共享一个 CRTC,则可以被另一个连接器克隆。每个连接器在更广泛的显示器中也有一个特定的位置(称为“屏幕”,尽管它可以跨越多个监视器)。

struct drm_connector *drm_connector_lookup(struct drm_device *dev, struct drm_file *file_priv, uint32_t id)

查找连接器对象

参数

struct drm_device *dev

DRM 设备

struct drm_file *file_priv

用于检查租约的 drm 文件。

uint32_t id

连接器对象 ID

描述

此函数查找由 id 指定的连接器对象并对其进行引用。

void drm_connector_get(struct drm_connector *connector)

获取连接器引用。

参数

struct drm_connector *connector

DRM 连接器

描述

此函数会递增连接器的引用计数。

void drm_connector_put(struct drm_connector *connector)

释放连接器引用。

参数

struct drm_connector *connector

DRM 连接器

描述

此函数会递减连接器的引用计数,并在引用计数降至零时释放该对象。

bool drm_connector_is_unregistered(struct drm_connector *connector)

连接器是否已从用户空间注销?

参数

struct drm_connector *connector

DRM 连接器

描述

检查 **connector** 是否已从用户空间注销。

返回

如果连接器已注销,则返回 True;如果连接器已注册或尚未在用户空间注册,则返回 false。

struct drm_tile_group

Tile 组元数据

定义:

struct drm_tile_group {
    struct kref refcount;
    struct drm_device *dev;
    int id;
    u8 group_data[8];
};

成员

refcount

引用计数

dev

DRM 设备

id

暴露给用户空间的 tile 组 ID

group_data

标识此组的 Sink 私有数据

描述

**group_data** 对应于具有 EDID 的外部屏幕的 displayid vend/prod/serial。

struct drm_connector_list_iter

connector_list 迭代器

定义:

struct drm_connector_list_iter {
};

成员

描述

此迭代器跟踪需要在 struct drm_mode_config 中遍历 connector_list 的状态。仅与 drm_connector_list_iter_begin()drm_connector_list_iter_end()drm_connector_list_iter_next() 分别使用,或者使用便捷宏 drm_for_each_connector_iter()

请注意,drm_connector_list_iter_next() 的返回值仅在下一个 drm_connector_list_iter_next()drm_connector_list_iter_end() 调用之前有效。 如果你之后想使用该连接器,则需要首先使用 drm_connector_get() 获取你自己的引用。

drm_for_each_connector_iter

drm_for_each_connector_iter (connector, iter)

connector_list 迭代器宏

参数

connector

用作游标的 struct drm_connector 指针

iter

struct drm_connector_list_iter

描述

请注意,**connector** 仅在列表主体内有效,如果你想在调用 drm_connector_list_iter_end() 之后使用 **connector**,则需要首先使用 drm_connector_get() 获取你自己的引用。

drm_connector_for_each_possible_encoder

drm_connector_for_each_possible_encoder (connector, encoder)

迭代连接器的可能编码器

参数

connector

struct drm_connector 指针

encoder

用作游标的 struct drm_encoder 指针

const char *drm_get_connector_type_name(unsigned int type)

返回连接器类型的字符串

参数

unsigned int type

连接器类型 (DRM_MODE_CONNECTOR_*)

返回

连接器类型的名称,如果类型无效,则返回 NULL。

int drm_connector_init(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type)

初始化一个预分配的连接器

参数

struct drm_device *dev

DRM 设备

struct drm_connector *connector

要初始化的连接器

const struct drm_connector_funcs *funcs

此连接器的回调

int connector_type

用户可见的连接器类型

描述

初始化一个预分配的连接器。 连接器应作为驱动程序连接器对象的一部分进行子类化。

在驱动程序卸载时,驱动程序的 drm_connector_funcs.destroy 钩子应调用 drm_connector_cleanup() 并释放连接器结构。 连接器结构不应使用 devm_kzalloc() 分配。

注意

请考虑使用 drmm_connector_init() 而不是 drm_connector_init(),以便让 DRM 管理的资源基础结构负责清理和释放。

返回

成功时为零,失败时为错误代码。

int drm_connector_init_with_ddc(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type, struct i2c_adapter *ddc)

初始化一个预分配的连接器

参数

struct drm_device *dev

DRM 设备

struct drm_connector *connector

要初始化的连接器

const struct drm_connector_funcs *funcs

此连接器的回调

int connector_type

用户可见的连接器类型

struct i2c_adapter *ddc

指向关联的 ddc 适配器的指针

描述

初始化一个预分配的连接器。 连接器应作为驱动程序连接器对象的一部分进行子类化。

在驱动程序卸载时,驱动程序的 drm_connector_funcs.destroy 钩子应调用 drm_connector_cleanup() 并释放连接器结构。 连接器结构不应使用 devm_kzalloc() 分配。

确保连接器的 ddc 字段已正确设置。

注意

请考虑使用 drmm_connector_init() 而不是 drm_connector_init_with_ddc(),以便让 DRM 管理的资源基础结构负责清理和释放。

返回

成功时为零,失败时为错误代码。

int drmm_connector_init(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type, struct i2c_adapter *ddc)

初始化一个预分配的连接器

参数

struct drm_device *dev

DRM 设备

struct drm_connector *connector

要初始化的连接器

const struct drm_connector_funcs *funcs

此连接器的回调

int connector_type

用户可见的连接器类型

struct i2c_adapter *ddc

关联的DDC适配器的可选指针。

描述

初始化一个预分配的连接器。 连接器应作为驱动程序连接器对象的一部分进行子类化。

清理工作由DRM管理的动作中的 drm_connector_cleanup() 自动处理。

连接器结构体应该使用 drmm_kzalloc() 分配。

drm_connector_funcs.destroy 钩子必须为 NULL。

返回

成功时为零,失败时为错误代码。

int drmm_connector_hdmi_init(struct drm_device *dev, struct drm_connector *connector, const char *vendor, const char *product, const struct drm_connector_funcs *funcs, const struct drm_connector_hdmi_funcs *hdmi_funcs, int connector_type, struct i2c_adapter *ddc, unsigned long supported_formats, unsigned int max_bpc)

初始化预先分配的 HDMI 连接器。

参数

struct drm_device *dev

DRM 设备

struct drm_connector *connector

要初始化的 HDMI 连接器的指针。

const char *vendor

HDMI 控制器供应商名称。

const char *product

HDMI 控制器产品名称。

const struct drm_connector_funcs *funcs

此连接器的回调

const struct drm_connector_hdmi_funcs *hdmi_funcs

此连接器的 HDMI 相关回调。

int connector_type

用户可见的连接器类型

struct i2c_adapter *ddc

关联的DDC适配器的可选指针。

unsigned long supported_formats

hdmi_colorspace 的位掩码,列出支持的输出格式。

unsigned int max_bpc

HDMI 连接器支持的最大每字符位数。

描述

初始化预先分配的 HDMI 连接器。连接器可以作为驱动程序连接器对象的一部分进行子类化。

清理工作由DRM管理的动作中的 drm_connector_cleanup() 自动处理。

连接器结构体应该使用 drmm_kzalloc() 分配。

drm_connector_funcs.destroy 钩子必须为 NULL。

返回

成功时为零,失败时为错误代码。

void drm_connector_attach_edid_property(struct drm_connector *connector)

附加 EDID 属性。

参数

struct drm_connector *connector

连接器。

描述

某些连接器类型(例如 DRM_MODE_CONNECTOR_VIRTUAL)默认情况下不会附加 EDID 属性。 此函数可用于在这些情况下显式启用 EDID 属性。

int drm_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder)

将连接器附加到编码器。

参数

struct drm_connector *connector

要附加的连接器。

struct drm_encoder *encoder

要将 connector 附加到的编码器。

描述

此函数将连接器链接到编码器。请注意,编码器和 CRTC 之间的路由限制通过 possible_clones 和 possible_crtcs 位掩码暴露给用户空间。

返回

成功返回零,失败返回负 errno。

bool drm_connector_has_possible_encoder(struct drm_connector *connector, struct drm_encoder *encoder)

检查连接器和编码器是否彼此关联。

参数

struct drm_connector *connector

连接器。

struct drm_encoder *encoder

编码器。

返回

如果 encoderconnector 的可能编码器之一,则为 True。

void drm_connector_cleanup(struct drm_connector *connector)

清理已初始化的连接器。

参数

struct drm_connector *connector

要清理的连接器。

描述

清理连接器,但不释放对象。

int drm_connector_register(struct drm_connector *connector)

注册连接器。

参数

struct drm_connector *connector

要注册的连接器。

描述

为连接器注册用户空间接口。仅在调用 drm_dev_register() 后可以热插拔的连接器(例如 DP MST 连接器)调用此函数。 所有其他连接器将在调用 drm_dev_register() 时自动注册。

当连接器不再可用时,调用者必须调用 drm_connector_unregister()

返回

成功时为零,失败时为错误代码。

void drm_connector_unregister(struct drm_connector *connector)

注销连接器。

参数

struct drm_connector *connector

要注销的连接器。

描述

为连接器注销用户空间接口。仅对通过调用 drm_connector_register() 显式注册的连接器调用此函数。

const char *drm_get_connector_status_name(enum drm_connector_status status)

返回连接器状态的字符串。

参数

enum drm_connector_status status

要计算名称的连接器状态。

描述

与其他 drm_get_*_name 函数相反,此函数返回一个 const 指针,因此是线程安全的。

返回

连接器状态字符串。

void drm_connector_list_iter_begin(struct drm_device *dev, struct drm_connector_list_iter *iter)

初始化 connector_list 迭代器。

参数

struct drm_device *dev

DRM 设备

struct drm_connector_list_iter *iter

connector_list 迭代器

描述

设置 iter 以遍历 devdrm_mode_config.connector_list。必须通过调用 drm_connector_list_iter_end() 来清理 iter。迭代本身使用 drm_connector_list_iter_next()drm_for_each_connector_iter() 进行。

struct drm_connector *drm_connector_list_iter_next(struct drm_connector_list_iter *iter)

返回下一个连接器

参数

struct drm_connector_list_iter *iter

connector_list 迭代器

返回

iter 的下一个连接器,如果列表遍历完成则返回 NULL。

void drm_connector_list_iter_end(struct drm_connector_list_iter *iter)

拆卸 connector_list 迭代器

参数

struct drm_connector_list_iter *iter

connector_list 迭代器

描述

拆卸 iter 并释放遍历列表时获取的任何资源(如 drm_connector 引用)。无论迭代完全完成还是在未遍历整个列表的情况下中止,都必须始终调用此函数。

const char *drm_get_subpixel_order_name(enum subpixel_order order)

返回给定子像素枚举的字符串

参数

enum subpixel_order order

子像素顺序的枚举

描述

请注意,您可以滥用此函数并返回超出范围的值,但这将是调用者的错误。不应有未经清理的用户数据到达此处。

返回

描述枚举的子像素属性的字符串

int drm_display_info_set_bus_formats(struct drm_display_info *info, const u32 *formats, unsigned int num_formats)

设置支持的总线格式

参数

struct drm_display_info *info

用于存储总线格式的显示信息

const u32 *formats

包含支持的总线格式的数组

unsigned int num_formats

fmts 数组中的条目数

描述

将支持的总线格式存储在显示信息结构中。有关可用格式的完整列表,请参见 include/uapi/linux/media-bus-format.h 中的 MEDIA_BUS_FMT_* 定义。

返回

成功返回 0,失败返回负错误代码。

int drm_get_tv_mode_from_name(const char *name, size_t len)

将电视模式名称转换为其枚举值

参数

const char *name

我们要转换的电视模式名称

size_t len

name 的长度

描述

name 转换为 enum drm_connector_tv_mode

返回

成功时为枚举值,否则为负的 errno。

int drm_mode_create_dvi_i_properties(struct drm_device *dev)

创建 DVI-I 特定的连接器属性

参数

struct drm_device *dev

DRM 设备

描述

驱动程序首次创建 DVI-I 连接器时调用。

返回

0

void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector)

为 DP 创建子连接器属性

参数

struct drm_connector *connector

要附加属性的 drm_connector

描述

创建 DP 连接器时由驱动程序调用。

int drm_connector_attach_content_type_property(struct drm_connector *connector)

附加内容类型属性

参数

struct drm_connector *connector

要在其上附加内容类型属性的连接器。

描述

驱动程序首次创建 HDMI 连接器时调用。

返回

0

void drm_connector_attach_tv_margin_properties(struct drm_connector *connector)

附加电视连接器边距属性

参数

struct drm_connector *connector

DRM 连接器

描述

驱动程序需要在连接器上附加电视边距属性时调用。通常用于 SDTV 和 HDMI 连接器。

int drm_mode_create_tv_margin_properties(struct drm_device *dev)

创建电视连接器边距属性

参数

struct drm_device *dev

DRM 设备

描述

此函数由驱动程序的 HDMI 连接器初始化例程调用,为给定设备创建电视边距属性。对于 SDTV 连接器,无需调用此函数,它已从 drm_mode_create_tv_properties_legacy() 中调用。

返回

成功返回 0,失败返回负错误代码。

int drm_mode_create_tv_properties_legacy(struct drm_device *dev, unsigned int num_modes, const char *const modes[])

创建特定于电视的连接器属性

参数

struct drm_device *dev

DRM 设备

unsigned int num_modes

支持的不同电视格式(模式)的数量

const char * const modes[]

指向包含每种格式名称的字符串的指针数组

描述

此函数由驱动程序的电视初始化例程调用,为给定设备创建特定于电视的连接器属性。调用者负责分配格式名称列表并将其传递给此例程。

注意

此函数注册已弃用的“mode”连接器属性,以选择模拟电视模式(即 NTSC、PAL 等)。新驱动程序必须使用 drm_mode_create_tv_properties() 代替。

返回

成功返回 0,失败返回负错误代码。

int drm_mode_create_tv_properties(struct drm_device *dev, unsigned int supported_tv_modes)

创建特定于电视的连接器属性

参数

struct drm_device *dev

DRM 设备

unsigned int supported_tv_modes

支持的电视模式的位掩码(参见 DRM_MODE_TV_MODE_*)

描述

此函数由驱动程序的电视初始化例程调用,为给定设备创建电视特定的连接器属性。

返回

成功返回 0,失败返回负错误代码。

int drm_mode_create_scaling_mode_property(struct drm_device *dev)

创建缩放模式属性

参数

struct drm_device *dev

DRM 设备

描述

由驱动程序首次需要时调用,必须附加到所需的连接器。

原子驱动程序应使用 drm_connector_attach_scaling_mode_property() 来正确分配原子状态中的 drm_connector_state.scaling_mode

返回

0

int drm_connector_attach_vrr_capable_property(struct drm_connector *connector)

创建 vrr_capable 属性

参数

struct drm_connector *connector

在其上创建 vrr_capable 属性的连接器。

描述

原子驱动程序使用它来添加对查询连接器可变刷新率能力的支持。

返回

成功返回零,失败返回负 errno。

int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, u32 scaling_mode_mask)

附加原子缩放模式属性

参数

struct drm_connector *connector

在其上附加缩放模式属性的连接器。

u32 scaling_mode_mask

BIT(DRM_MODE_SCALE_*) 的或掩码。

描述

这用于为原子驱动程序添加对缩放模式的支持。缩放模式将设置为 drm_connector_state.scaling_mode,并且可以从 drm_connector_helper_funcs->atomic_check 用于验证。

这是 drm_mode_create_scaling_mode_property() 的原子版本。

返回

成功返回零,失败返回负 errno。

int drm_mode_create_aspect_ratio_property(struct drm_device *dev)

创建宽高比属性

参数

struct drm_device *dev

DRM 设备

描述

由驱动程序首次需要时调用,必须附加到所需的连接器。

返回

成功返回零,失败返回负 errno。

int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector, u32 supported_colorspaces)

创建 HDMI 色彩空间属性

参数

struct drm_connector *connector

在其上创建色彩空间属性的连接器。

u32 supported_colorspaces

支持的色彩空间的位图

描述

由驱动程序首次需要时调用,必须附加到所需的 HDMI 连接器。

返回

成功返回零,失败返回负 errno。

int drm_mode_create_dp_colorspace_property(struct drm_connector *connector, u32 supported_colorspaces)

创建 DP 色彩空间属性

参数

struct drm_connector *connector

在其上创建色彩空间属性的连接器。

u32 supported_colorspaces

支持的色彩空间的位图

描述

由驱动程序首次需要时调用,必须附加到所需的 DP 连接器。

返回

成功返回零,失败返回负 errno。

int drm_mode_create_content_type_property(struct drm_device *dev)

创建内容类型属性

参数

struct drm_device *dev

DRM 设备

描述

由驱动程序首次需要时调用,必须附加到所需的连接器。

返回

成功返回零,失败返回负 errno。

int drm_mode_create_suggested_offset_properties(struct drm_device *dev)

创建建议的偏移属性

参数

struct drm_device *dev

DRM 设备

描述

为连接器创建建议的 x/y 偏移属性。

返回

成功返回 0,失败返回负错误代码。

int drm_connector_set_path_property(struct drm_connector *connector, const char *path)

在连接器上设置 tile 属性

参数

struct drm_connector *connector

在其上设置属性的连接器。

const char *path

用于属性的路径;不得为 NULL。

描述

这将创建一个属性以向用户空间公开,以指定连接器路径。 这主要用于 DisplayPort MST,其中连接器具有拓扑结构,并且我们希望允许用户空间为它们提供更有意义的名称。

返回

成功返回零,失败返回负 errno。

int drm_connector_set_tile_property(struct drm_connector *connector)

在连接器上设置 tile 属性

参数

struct drm_connector *connector

在其上设置属性的连接器。

描述

这将查找连接器的 tile 信息,并创建一个属性供用户空间解析(如果存在)。该属性的形式为 8 个整数,使用“:”作为分隔符。这用于具有 DisplayPort SST 或 DisplayPort MST 连接器的双端口 tiled 显示器。

返回

成功时返回 0,失败时返回 errno。

设置连接器的链接状态属性

参数

struct drm_connector *connector

drm 连接器

uint64_t link_status

链接状态属性的新值(0:良好,1:不良)

描述

在通常的工作场景中,此链接状态属性将始终设置为“良好”。如果在模式设置期间或之后发生某些故障,内核驱动程序可能会将此链接状态属性设置为“不良”。然后,调用者需要发送一个热插拔 uevent,以便用户空间通过 GET_CONNECTOR_IOCTL 重新检查有效模式并重试 modeset。

添加此属性的原因是为了处理链路训练失败,但它不限于 DP 或链路训练。例如,如果我们实现异步 setcrtc,则可以使用此属性来报告其中的任何故障。

注意

驱动程序不能依赖用户空间来支持此属性并发出 modeset。 因此,他们可以选择在没有用户空间干预的情况下处理问题(如重新训练链路)。

int drm_connector_attach_max_bpc_property(struct drm_connector *connector, int min, int max)

附加“最大 bpc”属性

参数

struct drm_connector *connector

在其上附加最大 bpc 属性的连接器。

int min

连接器支持的最小位深度。

int max

连接器支持的最大位深度。

描述

此功能用于添加对限制连接器位深度的支持。

返回

成功返回零,失败返回负 errno。

int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *connector)

附加“HDR_OUTPUT_METADA”属性

参数

struct drm_connector *connector

要在其上附加属性的连接器。

描述

此功能用于允许用户空间将 HDR 元数据发送到驱动程序。

返回

成功返回零,失败返回负 errno。

int drm_connector_attach_broadcast_rgb_property(struct drm_connector *connector)

附加“广播 RGB”属性

参数

struct drm_connector *connector

要在其上附加属性的连接器。

描述

此功能用于添加对强制连接器上的 RGB 范围的支持

返回

成功返回零,失败返回负 errno。

int drm_connector_attach_colorspace_property(struct drm_connector *connector)

附加“色彩空间”属性

参数

struct drm_connector *connector

要在其上附加属性的连接器。

描述

此功能用于允许用户空间向驱动程序发送输出色彩空间的信号。

返回

成功返回零,失败返回负 errno。

bool drm_connector_atomic_hdr_metadata_equal(struct drm_connector_state *old_state, struct drm_connector_state *new_state)

检查 hdr 元数据是否已更改

参数

struct drm_connector_state *old_state

用于比较的旧连接器状态

struct drm_connector_state *new_state

用于比较的新连接器状态

描述

启用 HDR 的驱动程序使用此功能来测试两个不同的连接器状态之间的 HDR 元数据是否已更改(因此可能需要完全的模式更改)。

返回

如果元数据相等,则为 True,否则为 False

void drm_connector_set_vrr_capable_property(struct drm_connector *connector, bool capable)

为连接器设置可变刷新率能力属性

参数

struct drm_connector *connector

drm 连接器

bool capable

如果连接器具有可变刷新率能力,则为 True

描述

原子驱动程序应使用此函数来更新连接器上指示的可变刷新率支持。

int drm_connector_set_panel_orientation(struct drm_connector *connector, enum drm_panel_orientation panel_orientation)

设置连接器的 panel_orientation

参数

struct drm_connector *connector

要为其设置面板方向属性的连接器。

enum drm_panel_orientation panel_orientation

要设置的 drm_panel_orientation 值

描述

此函数设置连接器的 panel_orientation 并将“面板方向”属性附加到连接器。

在已设置 panel_orientation 的连接器上调用此函数是空操作(例如,已使用内核命令行选项覆盖方向)。

允许使用 DRM_MODE_PANEL_ORIENTATION_UNKNOWN 的 panel_orientation 调用此函数,在这种情况下,它是空操作。

该函数不应在 drm 注册后在面板中调用(即,在 drm 中调用 drm_dev_register())。

返回

成功返回零,失败返回负 errno。

int drm_connector_set_panel_orientation_with_quirk(struct drm_connector *connector, enum drm_panel_orientation panel_orientation, int width, int height)

在检查怪癖后设置连接器的 panel_orientation

参数

struct drm_connector *connector

要为其初始化面板方向属性的连接器。

enum drm_panel_orientation panel_orientation

要设置的 drm_panel_orientation 值

int width

面板的宽度(以像素为单位),用于面板怪癖检测

int height

面板的高度(以像素为单位),用于面板怪癖检测

描述

类似于 drm_connector_set_panel_orientation(),但会检查平台特定的(例如,基于 DMI 的)怪癖,这些怪癖会覆盖传入的 panel_orientation。

返回

成功返回零,失败返回负 errno。

int drm_connector_set_orientation_from_panel(struct drm_connector *connector, struct drm_panel *panel)

从面板的回调设置连接器的 panel_orientation。

参数

struct drm_connector *connector

要为其初始化面板方向属性的连接器。

struct drm_panel *panel

可以提供方向信息的面板。

描述

Drm 驱动程序应在 drm_dev_register() 之前调用此函数。方向是从面板的 .get_orientation() 回调中获取的。

返回

成功返回零,失败返回负 errno。

void drm_connector_create_privacy_screen_properties(struct drm_connector *connector)

创建 drm 连接器的隐私屏幕属性。

参数

struct drm_connector *connector

要为其创建隐私屏幕属性的连接器

描述

此函数为连接器创建“隐私屏幕软件状态”和“隐私屏幕硬件状态”属性。它们未附加。

void drm_connector_attach_privacy_screen_properties(struct drm_connector *connector)

附加 drm 连接器的隐私屏幕属性。

参数

struct drm_connector *connector

要在其上附加隐私屏幕属性的连接器

描述

此函数将“隐私屏幕软件状态”和“隐私屏幕硬件状态”属性附加到连接器。两者的初始状态都设置为“已禁用”。

void drm_connector_attach_privacy_screen_provider(struct drm_connector *connector, struct drm_privacy_screen *priv)

将隐私屏幕附加到连接器

参数

struct drm_connector *connector

要将隐私屏幕附加到的连接器

struct drm_privacy_screen *priv

要附加的 drm_privacy_screen

描述

创建并附加标准的隐私屏幕属性,并注册一个通用通知器,以便在隐私屏幕状态发生外部更改时生成 sysfs 连接器状态事件。此函数获取传入的 drm_privacy_screen 的所有权,并在连接器销毁时调用 drm_privacy_screen_put()

void drm_connector_update_privacy_screen(const struct drm_connector_state *connector_state)

更新连接器的隐私屏幕软件状态

参数

const struct drm_connector_state *connector_state

要更新隐私屏幕的连接器状态

描述

此函数在连接器的隐私屏幕上调用 drm_privacy_screen_set_sw_state()

如果连接器没有隐私屏幕,则此操作为空操作。

void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode, enum drm_connector_status status)

向连接器报告带外热插拔事件

参数

struct fwnode_handle *connector_fwnode

要在其上报告事件的 fwnode_handle

enum drm_connector_status status

热插拔检测逻辑状态

描述

在某些硬件上,热插拔事件通知可能来自显示驱动程序/设备之外。一个例子是某些 USB Type-C 设置,其中硬件多路复用 DisplayPort 数据和辅助线路,但不将 altmode HPD 状态位传递到 GPU 的 DP HPD 引脚。

此函数可用于在通过调用 drm_connector_find_by_fwnode() 获取 drm_connector 引用后报告这些带外事件。

void drm_mode_put_tile_group(struct drm_device *dev, struct drm_tile_group *tg)

删除对图块组的引用。

参数

struct drm_device *dev

DRM 设备

struct drm_tile_group *tg

要删除引用的图块组。

描述

删除对图块组的引用,如果为 0 则释放。

struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, const char topology[8])

获取对现有图块组的引用

参数

struct drm_device *dev

DRM 设备

const char topology[8]

每个监视器唯一的 8 个字节。

描述

使用唯一字节获取对现有图块组的引用。

返回

图块组,如果未找到则为 NULL。

struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, const char topology[8])

从 displayid 描述创建图块组

参数

struct drm_device *dev

DRM 设备

const char topology[8]

每个监视器唯一的 8 个字节。

描述

为唯一监视器创建图块组,并获取该图块组的唯一标识符。

返回

新的图块组或 NULL。

回写连接器

回写连接器用于公开可以将 CRTC 的输出写入内存缓冲区的硬件。它们的使用方式与其他类型的连接器类似,但有一些重要的区别

  • 回写连接器不提供向用户直观输出的方式。

  • 仅当客户端设置 DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 时,回写连接器才对用户空间可见。

  • 回写连接器没有 EDID。

仅当连接器连接到 CRTC 时,帧缓冲区才可以连接到回写连接器。设置帧缓冲区的 WRITEBACK_FB_ID 属性仅适用于一次提交(请参见下文)。当 CRTC 关闭时,无法附加帧缓冲区。

与平面不同,当用户空间删除回写帧缓冲区时,DRM 不会尝试将其从连接器的活动使用中删除。这是因为没有提供中止回写操作的方法,并且在回写正在进行时进行新的提交是未定义的(请参见下面的 WRITEBACK_OUT_FENCE_PTR)。一旦当前回写完成,帧缓冲区将自动不再处于活动使用状态。由于它也已从帧缓冲区列表中删除,因此在过渡期间,任何用户空间应用程序都无法检索对它的引用。

回写连接器具有一些额外的属性,用户空间可以使用这些属性来查询和控制它们

“WRITEBACK_FB_ID”

存储 DRM_MODE_OBJECT_FB 的只写对象属性:它存储要由回写连接器写入的帧缓冲区。此属性类似于平面上的 FB_ID 属性,但将始终读取为零,并且不会跨提交保留。用户空间必须在每次希望填充缓冲区时将此属性设置为输出缓冲区。

“WRITEBACK_PIXEL_FORMATS”

存储支持的像素格式表的不可变 blob 属性。数据是 u32 DRM_FORMAT_* fourcc 值的数组。用户空间可以使用此 blob 来找出连接器的回写引擎支持的像素格式。

“WRITEBACK_OUT_FENCE_PTR”

用户空间可以使用此属性为内核提供一个指针,以使用 sync_file 文件描述符填充该指针,该描述符将在回写完成后发出信号。该值应为 32 位有符号整数的地址,转换为 u64。用户空间应等待此栅栏发出信号,然后再进行任何影响相同 CRTC、平面或连接器的另一次提交。**未能这样做将导致未定义的行为。** 因此,强烈建议所有使用回写连接器的用户空间应用程序*始终*检索提交的输出栅栏并适当使用它。从用户空间来看,此属性将始终读取为零。

struct drm_writeback_connector

DRM 回写连接器

定义:

struct drm_writeback_connector {
    struct drm_connector base;
    struct drm_encoder encoder;
    struct drm_property_blob *pixel_formats_blob_ptr;
    spinlock_t job_lock;
    struct list_head job_queue;
    unsigned int fence_context;
    spinlock_t fence_lock;
    unsigned long fence_seqno;
    char timeline_name[32];
};

成员

基础

基本 drm_connector 对象

encoder

连接器用来满足 DRM 框架要求的内部编码器。**drm_writeback_connector** 的用户通过将 **enc_funcs** 参数传递给 drm_writeback_connector_init() 函数来控制 **encoder** 的行为。对于 drm_writeback_connector_init_with_encoder() 的用户,此字段无效,因为编码器在其驱动程序中进行管理。

pixel_formats_blob_ptr

回写连接器上像素格式列表的 DRM blob 属性数据。另请参见 drm_writeback_connector_init()

job_lock

保护 job_queue

job_queue

保存连接器的回写作业列表;最后一项是最近的一项。第一项可能正在等待硬件开始写入,或者当前正在写入。

另请参阅: drm_writeback_queue_job()drm_writeback_signal_completion()

fence_context

用于栅栏操作的时间线上下文。

fence_lock

用于保护 fence_context 中栅栏的自旋锁。

fence_seqno

Seqno 变量用作连接器时间轴上创建的栅栏的单调计数器。

timeline_name

连接器的栅栏时间轴的名称。

struct drm_writeback_job

DRM 回写作业

定义:

struct drm_writeback_job {
    struct drm_writeback_connector *connector;
    bool prepared;
    struct work_struct cleanup_work;
    struct list_head list_entry;
    struct drm_framebuffer *fb;
    struct dma_fence *out_fence;
    void *priv;
};

成员

connector

指向与作业关联的回写连接器的后向指针

prepared

当使用 drm_writeback_prepare_job() 准备好作业时设置

cleanup_work

用于允许 drm_writeback_signal_completion 将删除帧缓冲区引用的操作推迟到工作队列

list_entry

回写连接器的 **job_queue** 的列表项

fb

回写连接器要写入的帧缓冲区。不要直接设置,请使用 drm_writeback_set_fb()

out_fence

一旦回写完成,栅栏将发出信号

priv

驱动程序私有数据

int drm_writeback_connector_init(struct drm_device *dev, struct drm_writeback_connector *wb_connector, const struct drm_connector_funcs *con_funcs, const struct drm_encoder_helper_funcs *enc_helper_funcs, const u32 *formats, int n_formats, u32 possible_crtcs)

初始化回写连接器及其属性

参数

struct drm_device *dev

DRM 设备

struct drm_writeback_connector *wb_connector

要初始化的回写连接器

const struct drm_connector_funcs *con_funcs

连接器函数虚表

const struct drm_encoder_helper_funcs *enc_helper_funcs

内部编码器要使用的编码器辅助函数虚表

const u32 *formats

回写引擎支持的像素格式数组

int n_formats

格式数组的长度

u32 possible_crtcs

内部回写编码器可能的 crtc

描述

如果尚未创建,此函数将创建回写连接器特定的属性,将连接器初始化为 DRM_MODE_CONNECTOR_WRITEBACK 类型,并正确初始化属性值。 它还会创建一个与 drm_writeback_connector 关联的内部编码器,并将其设置为使用编码器辅助函数的 enc_helper_funcs 虚表。

驱动程序应始终使用此函数而不是 drm_connector_init() 来设置回写连接器。

返回

成功时返回 0,否则返回负错误代码

int drm_writeback_connector_init_with_encoder(struct drm_device *dev, struct drm_writeback_connector *wb_connector, struct drm_encoder *enc, const struct drm_connector_funcs *con_funcs, const u32 *formats, int n_formats)

使用自定义编码器初始化回写连接器

参数

struct drm_device *dev

DRM 设备

struct drm_writeback_connector *wb_connector

要初始化的回写连接器

struct drm_encoder *enc

指向已初始化的 drm 编码器的句柄

const struct drm_connector_funcs *con_funcs

连接器函数虚表

const u32 *formats

回写引擎支持的像素格式数组

int n_formats

格式数组的长度

描述

如果尚未创建,此函数将创建回写连接器特定的属性,将连接器初始化为 DRM_MODE_CONNECTOR_WRITEBACK 类型,并正确初始化属性值。

此函数假定在调用此函数之前已创建并初始化 drm_writeback_connector 的编码器。

此外,此函数还假定此 API 的调用者将管理分配编码器辅助函数、possible_crtcs 和任何其他特定于编码器的操作。

如果驱动程序想要自行管理关联编码器的生命周期,则应始终使用此函数而不是 drm_connector_init() 来设置回写连接器。

返回

成功时返回 0,否则返回负错误代码

void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, struct drm_connector_state *conn_state)

排队回写作业以供稍后发出信号

参数

struct drm_writeback_connector *wb_connector

要在其上排队作业的回写连接器

struct drm_connector_state *conn_state

包含要排队作业的连接器状态

描述

此函数将 conn_state 中包含的作业添加到回写连接器的 job_queue。它拥有回写作业的所有权并将 conn_state->writeback_job 设置为 NULL,因此在此函数返回后,调用方不得访问该作业。

驱动程序必须确保对于给定的回写连接器,作业的排队顺序与硬件完成(并通过 drm_writeback_signal_completion 发出信号)的顺序完全相同。

对于每次调用 drm_writeback_queue_job() 都必须正好调用一次 drm_writeback_signal_completion()

另请参阅:drm_writeback_signal_completion()

void drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector, int status)

发出回写作业完成的信号

参数

struct drm_writeback_connector *wb_connector

其作业已完成的回写连接器

int status

要在回写 out_fence 中设置的状态代码(成功为 0)

描述

驱动程序应调用此函数来发出先前排队的回写作业完成的信号。 它应在硬件完成写入后尽快调用,并且可以从中断上下文中调用。 驱动程序有责任确保对于给定的连接器,硬件完成回写作业的顺序与它们排队的顺序相同。

除非驱动程序持有对帧缓冲区的引用,否则在调用此函数后不得访问帧缓冲区。

另请参阅:drm_writeback_queue_job()

编码器抽象

编码器表示 CRTC(作为由 struct drm_crtc 表示的整体像素管线)和连接器(作为由 struct drm_connector 表示的通用接收器实体)之间的连接元素。编码器从 CRTC 获取像素数据,并将其转换为适合任何连接的连接器的格式。 编码器是暴露给用户空间的物体,最初是为了允许用户空间推断克隆和连接器/CRTC 限制。 不幸的是,几乎所有的驱动程序都弄错了,使得 uabi 几乎没用。 最重要的是,暴露的限制对于当今的硬件来说太简单了,而推断限制的推荐方法是使用原子 IOCTL 的 DRM_MODE_ATOMIC_TEST_ONLY 标志。

否则,编码器根本不会在 uapi 中使用(来自用户空间的任何模式设置请求都会直接将连接器与 CRTC 连接),因此驱动程序可以随意使用它们。 模式设置辅助库强烈使用编码器来促进代码共享。 但是对于更复杂的设置,通常最好将共享代码移动到单独的 drm_bridge 中。 与编码器相比,网桥还具有纯粹的内部抽象的优点,因为它们根本不会暴露给用户空间。

编码器使用 drm_encoder_init() 初始化,并使用 drm_encoder_cleanup() 清理。

编码器函数参考

struct drm_encoder_funcs

编码器控制

定义:

struct drm_encoder_funcs {
    void (*reset)(struct drm_encoder *encoder);
    void (*destroy)(struct drm_encoder *encoder);
    int (*late_register)(struct drm_encoder *encoder);
    void (*early_unregister)(struct drm_encoder *encoder);
    void (*debugfs_init)(struct drm_encoder *encoder, struct dentry *root);
};

成员

reset

将编码器硬件和软件状态重置为关闭。 此函数不是由核心直接调用的,仅通过 drm_mode_config_reset() 调用。 它仅出于历史原因而不是辅助钩子。

destroy

清理编码器资源。这仅在驱动程序卸载时通过 drm_mode_config_cleanup() 调用,因为编码器在 DRM 中不能热插拔。

late_register

这个可选的钩子可用于注册附加到编码器的其他用户空间接口。它在驱动程序加载序列的后期从 drm_dev_register() 调用。从这个回调添加的所有内容都应在 early_unregister 回调中取消注册。

返回值

成功时返回 0,失败时返回负错误代码。

early_unregister

这个可选的钩子应该用于取消注册从 late_register 附加到编码器的其他用户空间接口。它从 drm_dev_unregister() 调用,在驱动程序卸载序列的早期,在数据结构被拆卸之前禁用用户空间访问。

debugfs_init

允许编码器创建特定于编码器的 debugfs 文件。

描述

编码器位于 CRTC 和连接器之间。

struct drm_encoder

中央 DRM 编码器结构

定义:

struct drm_encoder {
    struct drm_device *dev;
    struct list_head head;
    struct drm_mode_object base;
    char *name;
    int encoder_type;
    unsigned index;
    uint32_t possible_crtcs;
    uint32_t possible_clones;
    struct drm_crtc *crtc;
    struct list_head bridge_chain;
    const struct drm_encoder_funcs *funcs;
    const struct drm_encoder_helper_funcs *helper_private;
    struct dentry *debugfs_entry;
};

成员

dev

父 DRM 设备

head

列表管理

基础

基本 KMS 对象

名称

人类可读的名称,可以被驱动程序覆盖

encoder_type

drm_mode.h 中的 DRM_MODE_ENCODER_<foo> 类型之一。到目前为止,定义了以下编码器类型

  • 用于 VGA 和 DVI-I/DVI-A 上的模拟信号的 DRM_MODE_ENCODER_DAC。

  • 用于 DVI、HDMI 和(嵌入式)DisplayPort 的 DRM_MODE_ENCODER_TMDS。

  • 用于显示面板,或通常任何具有专有并行连接器的面板的 DRM_MODE_ENCODER_LVDS。

  • 用于电视输出(复合、S-Video、分量、SCART)的 DRM_MODE_ENCODER_TVDAC。

  • 用于虚拟机的显示的 DRM_MODE_ENCODER_VIRTUAL

  • 用于使用 DSI 串行总线连接的面板的 DRM_MODE_ENCODER_DSI。

  • 用于使用 DPI 并行总线连接的面板的 DRM_MODE_ENCODER_DPI。

  • 用于特殊的伪编码器,允许多个 DP MST 流共享一个物理编码器的 DRM_MODE_ENCODER_DPMST。

index

在 mode_config.list 中的位置,可以用作数组索引。它在编码器的生命周期内是不变的。

possible_crtcs

使用 drm_crtc_index() 作为位域索引的潜在 CRTC 绑定的位掩码。驱动程序必须为所有 drm_crtc 对象设置位,该编码器可以在调用 drm_dev_register() 之前连接到这些对象。

如果驱动程序中出现此错误,您将收到警告。

请注意,由于 CRTC 对象无法热插拔,因此分配的索引是稳定的,因此在注册所有对象之前就已知。

possible_clones

使用 drm_encoder_index() 作为位域索引的潜在克隆兄弟编码器的位掩码。驱动程序必须为所有 drm_encoder 对象设置位,这些对象可以在调用 drm_dev_register() 之前与此编码器一起克隆一个 drm_crtc。驱动程序也应设置表示编码器本身的位。克隆位应设置成当两个编码器可以在克隆配置中使用时,它们都应设置彼此的位。

作为上述规则的例外,如果驱动程序没有实现任何克隆,它可以将 possible_clones 设置为 0。核心将通过为编码器本身设置位来自动修复此问题。

如果驱动程序中出现此错误,您将收到警告。

请注意,由于编码器对象无法热插拔,因此分配的索引是稳定的,因此在注册所有对象之前就已知。

crtc

当前绑定的 CRTC,仅对非原子驱动程序真正有意义。原子驱动程序应改为检查 drm_connector_state.crtc

bridge_chain

附加到此编码器的桥接器。驱动程序不得直接访问此字段。

funcs

控制函数,对于简单的托管编码器可以为 NULL

helper_private

中间层私有数据

debugfs_entry

此 CRTC 的 Debugfs 目录。

描述

CRTC 将像素驱动到编码器,编码器将它们转换为适合给定连接器或一组连接器的信号。

drmm_encoder_alloc

drmm_encoder_alloc (dev, type, member, funcs, encoder_type, name, ...)

分配并初始化一个编码器

参数

dev

drm 设备

type

包含 struct drm_encoder 的结构的类型

member

typedrm_encoder 的名称

funcs

此编码器的回调(可选)

encoder_type

编码器的用户可见类型

名称

编码器名称的 printf 样式格式字符串,或者默认名称的 NULL

...

可变参数

描述

分配并初始化一个编码器。编码器应作为驱动程序编码器对象的一部分进行子类化。通过使用 drmm_add_action() 注册 drm_encoder_cleanup() 来自动处理清理。

drm_encoder_funcs.destroy 钩子必须为 NULL。

返回

指向新编码器的指针,如果失败则为 ERR_PTR。

drmm_plain_encoder_alloc

drmm_plain_encoder_alloc (dev, funcs, encoder_type, name, ...)

分配并初始化一个编码器

参数

dev

drm 设备

funcs

此编码器的回调(可选)

encoder_type

编码器的用户可见类型

名称

编码器名称的 printf 样式格式字符串,或者默认名称的 NULL

...

可变参数

描述

这是 drmm_encoder_alloc() 的简化版本,它仅分配并返回一个 struct drm_encoder 实例,而没有子类化。

返回

指向新的 drm_encoder 结构的指针,如果失败则为 ERR_PTR。

unsigned int drm_encoder_index(const struct drm_encoder *encoder)

查找已注册编码器的索引

参数

const struct drm_encoder *encoder

要查找索引的编码器

描述

给定一个已注册的编码器,返回该编码器在 DRM 设备的编码器列表中的索引。

u32 drm_encoder_mask(const struct drm_encoder *encoder)

查找已注册编码器的掩码

参数

const struct drm_encoder *encoder

要查找掩码的编码器

描述

给定一个已注册的编码器,返回该编码器用于编码器的 possible_clones 字段的掩码位。

bool drm_encoder_crtc_ok(struct drm_encoder *encoder, struct drm_crtc *crtc)

给定的 crtc 是否可以驱动给定的编码器?

参数

struct drm_encoder *encoder

要测试的编码器

struct drm_crtc *crtc

要测试的 crtc

描述

如果 encoder 不能由 crtc 驱动,则返回 false,否则返回 true。

struct drm_encoder *drm_encoder_find(struct drm_device *dev, struct drm_file *file_priv, uint32_t id)

查找 drm_encoder

参数

struct drm_device *dev

DRM 设备

struct drm_file *file_priv

用于检查租约的 drm 文件。

uint32_t id

编码器 ID

描述

返回具有 id 的编码器,如果不存在则返回 NULL。 是 drm_mode_object_find() 的简单封装。

drm_for_each_encoder_mask

drm_for_each_encoder_mask (encoder, dev, encoder_mask)

迭代由位掩码指定的编码器

参数

encoder

循环游标

dev

DRM 设备

encoder_mask

编码器索引的位掩码

描述

迭代由位掩码指定的所有编码器。

drm_for_each_encoder

drm_for_each_encoder (encoder, dev)

迭代所有编码器

参数

encoder

循环游标

dev

DRM 设备

描述

迭代 dev 的所有编码器。

int drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, const struct drm_encoder_funcs *funcs, int encoder_type, const char *name, ...)

初始化一个预先分配的编码器

参数

struct drm_device *dev

drm 设备

struct drm_encoder *encoder

要初始化的编码器

const struct drm_encoder_funcs *funcs

此编码器的回调函数

int encoder_type

编码器的用户可见类型

const char *name

编码器名称的 printf 样式格式字符串,或者默认名称的 NULL

...

可变参数

描述

初始化一个预先分配的编码器。编码器应作为驱动程序编码器对象的一部分进行子类化。在驱动程序卸载时,驱动程序的 drm_encoder_funcs.destroy 钩子应调用 drm_encoder_cleanup()kfree() 编码器结构。编码器结构不应使用 devm_kzalloc() 进行分配。

注意

考虑使用 drmm_encoder_alloc()drmm_encoder_init() 而不是 drm_encoder_init(),以便让 DRM 管理的资源基础结构来处理清理和释放。

返回

成功时为零,失败时为错误代码。

void drm_encoder_cleanup(struct drm_encoder *encoder)

清理一个已初始化的编码器

参数

struct drm_encoder *encoder

要清理的编码器

描述

清理编码器,但不释放对象。

int drmm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, const struct drm_encoder_funcs *funcs, int encoder_type, const char *name, ...)

初始化一个预先分配的编码器

参数

struct drm_device *dev

drm 设备

struct drm_encoder *encoder

要初始化的编码器

const struct drm_encoder_funcs *funcs

此编码器的回调(可选)

int encoder_type

编码器的用户可见类型

const char *name

编码器名称的 printf 样式格式字符串,或者默认名称的 NULL

...

可变参数

描述

初始化一个预先分配的编码器。编码器应作为驱动程序编码器对象的一部分进行子类化。通过使用 drmm_add_action() 注册 drm_encoder_cleanup() 来自动处理清理。编码器结构应使用 drmm_kzalloc() 进行分配。

drm_encoder_funcs.destroy 钩子必须为 NULL。

返回

成功时为零,失败时为错误代码。

KMS 锁定

随着 KMS 向更细粒度的锁定和原子 ioctl 发展,用户空间可以间接控制锁定顺序,因此有必要使用 ww_mutex 和 acquire-context 来避免死锁。但是由于锁定在驱动程序代码中分布更广,我们希望从 acquire-ctx 中获得一些额外的实用程序/跟踪。这由 struct drm_modeset_lockstruct drm_modeset_acquire_ctx 提供。

有关 ww_mutex 的基本原则,请参阅: Wound/Wait 无死锁互斥体设计

基本用法模式是

drm_modeset_acquire_init(ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE)
retry:
foreach (lock in random_ordered_set_of_locks) {
    ret = drm_modeset_lock(lock, ctx)
    if (ret == -EDEADLK) {
        ret = drm_modeset_backoff(ctx);
        if (!ret)
            goto retry;
    }
    if (ret)
        goto out;
}
... do stuff ...
out:
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);

为了方便起见,此控制流在 DRM_MODESET_LOCK_ALL_BEGIN()DRM_MODESET_LOCK_ALL_END() 中实现,以用于需要通过 drm_modeset_lock_all_ctx() 获取所有模式设置锁定的情况。

如果只需要单个模式设置锁定,则不需要 struct drm_modeset_acquire_ctx,并且可以通过在 drm_modeset_lock() 调用中传递 NULL 而不是 ctx 或调用 drm_modeset_lock_single_interruptible() 来简化锁定。之后调用 drm_modeset_unlock() 进行解锁。

在这些使用 ww_mutex 的每个对象锁定之上,还有一个总体的 drm_mode_config.mutex,用于保护其他所有内容。这主要意味着连接器的探测状态,以及防止连接器的热插拔添加/删除。

最后,还有许多专用的锁来保护 drm 核心内部列表和查找数据结构。

struct drm_modeset_acquire_ctx

锁定上下文(请参阅 ww_acquire_ctx)

定义:

struct drm_modeset_acquire_ctx {
    struct ww_acquire_ctx ww_ctx;
    struct drm_modeset_lock *contended;
    depot_stack_handle_t stack_depot;
    struct list_head locked;
    bool trylock_only;
    bool interruptible;
};

成员

ww_ctx

基本获取 ctx

争用

内部用于 -EDEADLK 处理

stack_depot

内部用于争用调试

已锁定

持有的锁列表

trylock_only

原子上下文/panic 通知器中使用的 trylock 模式

可中断

是否应使用可中断锁定。

描述

每个竞争一组锁的线程都必须使用一个获取 ctx。如果任何锁 fxn 返回 -EDEADLK,则它必须回退并重试。

struct drm_modeset_lock

用于锁定模式设置资源。

定义:

struct drm_modeset_lock {
    struct ww_mutex mutex;
    struct list_head head;
};

成员

mutex

资源锁定

head

用于在作为原子更新的一部分时,将其保留在 drm_atomi_state.locked 列表中的位置

描述

用于锁定 CRTC 和其他模式设置资源。

void drm_modeset_lock_fini(struct drm_modeset_lock *lock)

清理锁

参数

struct drm_modeset_lock *lock

要清理的锁

bool drm_modeset_is_locked(struct drm_modeset_lock *lock)

等效于 mutex_is_locked()

参数

struct drm_modeset_lock *lock

要检查的锁

void drm_modeset_lock_assert_held(struct drm_modeset_lock *lock)

等效于 lockdep_assert_held()

参数

struct drm_modeset_lock *lock

要检查的锁

DRM_MODESET_LOCK_ALL_BEGIN

DRM_MODESET_LOCK_ALL_BEGIN (dev, ctx, flags, ret)

用于获取模式设置锁的助手

参数

dev

drm 设备

ctx

本地模式设置获取上下文,将被解引用

标志

要传递给 drm_modeset_acquire_init() 的 DRM_MODESET_ACQUIRE_* 标志

ret

用于跟踪错误状态的本地 ret/err/etc 变量

描述

使用这些宏可以简化使用本地上下文获取所有模式设置锁的操作。 这样做的好处是减少了样板代码,而且在适当的情况下可以正确检查返回值。

在 BEGIN 和 END 之间运行的任何代码都将持有模式设置锁。

必须与 DRM_MODESET_LOCK_ALL_END() 配对使用。 我们将在死锁和错误条件下的标签之间来回跳转。

驱动程序可以获取额外的模式设置锁。 如果任何锁获取失败,控制流需要跳转到 DRM_MODESET_LOCK_ALL_END(),且 ret 参数包含 drm_modeset_lock() 的返回值。

返回

紧跟在 DRM_MODESET_LOCK_ALL_BEGIN() 之后的 ret 的唯一可能值是 0,因此无需进行错误检查

DRM_MODESET_LOCK_ALL_END

DRM_MODESET_LOCK_ALL_END (dev, ctx, ret)

用于释放和清理模式设置锁的助手

参数

dev

drm 设备

ctx

本地模式设置获取上下文,将被解引用

ret

用于跟踪错误状态的本地 ret/err/etc 变量

描述

DRM_MODESET_LOCK_ALL_BEGIN() 的另一半。 如果 ret 为 -EDEADLK,它将跳回 BEGIN。

重要的是,你为 begin 和 end 使用相同的 ret 变量,以便正确处理死锁条件。

返回

除非输入时 ret 为 -EDEADLK,否则 ret 不会被修改。 这意味着,如果你成功获取了锁,ret 将为你代码设置的值。 如果在获取或退避时出现死锁或其他故障,ret 将设置为该故障。 在这两种情况下,都不会运行 BEGIN/END 之间的代码,因此故障将反映无法获取锁。

void drm_modeset_lock_all(struct drm_device *dev)

获取所有模式设置锁

参数

struct drm_device *dev

DRM 设备

描述

此函数获取所有模式设置锁,适用于尚未实现更细粒度方案的情况。 必须调用 drm_modeset_unlock_all() 函数来释放锁。

此函数已弃用。 它会分配一个锁获取上下文,并将其存储在 drm_device.mode_config 中。 这有助于转换现有代码,因为它消除了手动处理获取上下文的需求,但它也很脆弱,因为上下文是全局的,必须注意不要嵌套调用。 新代码应使用 drm_modeset_lock_all_ctx() 函数并显式传入上下文。

void drm_modeset_unlock_all(struct drm_device *dev)

释放所有模式设置锁

参数

struct drm_device *dev

DRM 设备

描述

此函数释放之前调用 drm_modeset_lock_all() 函数获取的所有模式设置锁。

此函数已弃用。 它使用存储在 drm_device.mode_config 中的锁获取上下文。 这有助于转换现有代码,因为它消除了手动处理获取上下文的需求,但它也很脆弱,因为上下文是全局的,必须注意不要嵌套调用。 新代码应将获取上下文直接传递给 drm_modeset_drop_locks() 函数。

void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)

检查是否已锁定所有模式设置锁

参数

struct drm_device *dev

设备

描述

用作调试断言非常有用。

void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, uint32_t flags)

初始化获取上下文

参数

struct drm_modeset_acquire_ctx *ctx

获取上下文

uint32_t flags

0 或 DRM_MODESET_ACQUIRE_INTERRUPTIBLE

描述

当将 DRM_MODESET_ACQUIRE_INTERRUPTIBLE 传递给 flags 时,所有对 drm_modeset_lock() 的调用都将执行可中断的等待。

void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx)

清理获取上下文

参数

struct drm_modeset_acquire_ctx *ctx

获取上下文

void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx)

释放所有锁

参数

struct drm_modeset_acquire_ctx *ctx

获取上下文

描述

释放当前为此获取上下文持有的所有锁。

int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx)

死锁避免退避

参数

struct drm_modeset_acquire_ctx *ctx

获取上下文

描述

如果检测到死锁(即 drm_modeset_lock() 返回 -EDEADLK),则必须调用此函数来释放当前持有的所有锁,并阻止直到争用的锁变为可用。

如果此上下文使用 DRM_MODESET_ACQUIRE_INTERRUPTIBLE 初始化,并且等待已中断,则此函数在成功时返回 0,否则返回 -ERESTARTSYS。

void drm_modeset_lock_init(struct drm_modeset_lock *lock)

初始化锁

参数

struct drm_modeset_lock *lock

要初始化的锁

int drm_modeset_lock(struct drm_modeset_lock *lock, struct drm_modeset_acquire_ctx *ctx)

获取模式设置锁

参数

struct drm_modeset_lock *lock

要获取的锁

struct drm_modeset_acquire_ctx *ctx

获取上下文

描述

如果 ctx 不为 NULL,则使用其 ww 获取上下文,并且该锁将由上下文跟踪,并可以通过调用 drm_modeset_drop_locks() 来释放。如果返回 -EDEADLK,则表示已检测到死锁情况,并且在没有首先调用 drm_modeset_backoff() 的情况下尝试获取更多锁是错误的。

如果 ctx 不为 NULL 且使用 DRM_MODESET_ACQUIRE_INTERRUPTIBLE 初始化,则此函数在中断时将失败并返回 -ERESTARTSYS。

如果 ctx 为 NULL,则函数调用行为类似于正常的、不可中断的非嵌套 mutex_lock() 调用。

int drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock)

获取单个模式设置锁

参数

struct drm_modeset_lock *lock

要获取的锁

描述

此函数的行为类似于带有 NULL 上下文的 drm_modeset_lock(),但执行可中断等待。

此函数在成功时返回 0,或在中断时返回 -ERESTARTSYS。

void drm_modeset_unlock(struct drm_modeset_lock *lock)

释放模式设置锁

参数

struct drm_modeset_lock *lock

要释放的锁

int drm_modeset_lock_all_ctx(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx)

获取所有模式设置锁

参数

struct drm_device *dev

DRM 设备

struct drm_modeset_acquire_ctx *ctx

锁获取上下文

描述

此函数获取所有模式设置锁,适用于尚未实现更细粒度的方案的情况。

drm_modeset_lock_all() 不同,它不获取 drm_mode_config.mutex,因为模式设置状态更改不需要该锁。也需要获取该锁的调用者需要在获取上下文 ctx 之外进行此操作。

使用此函数获取的锁应通过在 ctx 上调用 drm_modeset_drop_locks() 函数来释放。

另请参阅:DRM_MODESET_LOCK_ALL_BEGIN()DRM_MODESET_LOCK_ALL_END()

返回

成功时返回 0,失败时返回负错误代码。

KMS 属性

本文档的这一部分主要针对用户空间开发人员。有关驱动程序 API,请参阅其他部分。

要求

KMS 驱动程序可能需要添加额外的属性来支持新功能。驱动程序中引入的每个新属性除了上述要求外,还需要满足以下几个要求

  • 它必须是标准化的,需要记录

    • 完整的、确切的名称字符串;

    • 如果该属性是枚举类型,则所有有效的取值名称字符串;

    • 接受哪些值,以及这些值的含义;

    • 该属性的作用以及如何使用它;

    • 该属性如何与其他的现有属性交互。

  • 它必须在核心代码中提供一个通用助手,以在该属性附加到的对象上注册该属性。

  • 其内容必须由核心解码,并在对象关联的状态结构中提供。这包括驱动程序可能想要预先计算的任何内容,例如平面的 struct drm_clip_rect。

  • 其初始状态必须与引入该属性之前的行为相匹配。这可能是与硬件行为匹配的固定值,也可能是从固件在启动期间将系统置于的状态继承而来。

  • 在合理的情况下,必须提交 IGT 测试。

由于历史原因,存在非标准的、特定于驱动程序的属性。如果 KMS 驱动程序想要添加对其中一个属性的支持,则在可能的情况下,新属性的要求也适用。此外,记录的行为必须与现有属性的实际语义相匹配,以确保兼容性。最初添加该属性的驱动程序的开发人员应帮助完成这些任务,并且必须在可能的情况下确认记录的行为。

属性类型和 Blob 属性支持

drm_property 表示的属性用于扩展暴露给用户空间的模式设置接口。对于原子模式设置 IOCTL,属性甚至是将所需新模式设置配置的元数据从用户空间传输到内核的唯一方式。属性具有明确定义的值范围,由 drm 核心强制执行。有关不同属性类型和范围的概述,请参阅 struct drm_property 的 flags 成员的文档。

属性不直接存储当前值,而是需要通过使用 drm_object_attach_property() 将它们附加到 drm_mode_object 来实例化。

属性值只有 64 位。为了支持更大的数据堆(如伽玛表、色彩校正矩阵或大型结构),属性可以改为指向具有该附加数据的 drm_property_blob

属性由其符号名称定义,用户空间必须保持从这些名称到原子 IOCTL 和 get/set 属性 IOCTL 中使用的属性 ID 的每个对象的映射。

struct drm_property_enum

枚举的符号值

定义:

struct drm_property_enum {
    uint64_t value;
    struct list_head head;
    char name[DRM_PROP_NAME_LEN];
};

成员

此枚举条目的数值属性值

如果属性的类型为 DRM_MODE_PROP_BITMASK,则 value 存储的是位移,而不是位掩码。换句话说,如果属性值中设置了位号 value,则启用枚举条目。此枚举条目的位掩码为 1 << value

head

枚举值的列表,链接到 drm_property.enum_list

名称

枚举的符号名称

描述

对于枚举和位掩码属性,此结构存储每个值的符号解码。例如,这用于旋转属性。

struct drm_property

模式设置对象属性

定义:

struct drm_property {
    struct list_head head;
    struct drm_mode_object base;
    uint32_t flags;
    char name[DRM_PROP_NAME_LEN];
    uint32_t num_values;
    uint64_t *values;
    struct drm_device *dev;
    struct list_head enum_list;
};

成员

head

每个设备的属性列表,用于清理。

基础

基本 KMS 对象

标志

属性标志和类型。一个属性必须是以下类型之一

DRM_MODE_PROP_RANGE

范围属性报告其最小和最大可接受的无符号值。KMS 核心验证应用程序设置的值是否在该范围内。范围是无符号的。范围属性使用 drm_property_create_range() 创建。

DRM_MODE_PROP_SIGNED_RANGE

范围属性报告其最小和最大可接受的无符号值。KMS 核心验证应用程序设置的值是否在该范围内。范围是有符号的。范围属性使用 drm_property_create_signed_range() 创建。

DRM_MODE_PROP_ENUM

枚举属性采用一个数值,范围从 0 到属性定义的枚举值数量减一,并将一个自由格式的字符串名称与每个值关联。应用程序可以检索已定义的数值-名称对列表,并使用数值来获取和设置属性实例值。枚举属性使用 drm_property_create_enum() 创建。

DRM_MODE_PROP_BITMASK

位掩码属性是枚举属性,此外还限制所有枚举值在 0..63 范围内。位掩码属性实例值组合了属性定义的一个或多个枚举位。位掩码属性使用 drm_property_create_bitmask() 创建。

DRM_MODE_PROP_OBJECT

对象属性用于链接模式设置对象。这在原子支持中广泛使用,通过将 drm_framebuffer 链接到 drm_plane,将 drm_plane 链接到 drm_crtc,并将 drm_connector 链接到 drm_crtc 来创建显示管线。对象属性只能链接到特定类型的 drm_mode_object,此限制由核心强制执行。对象属性使用 drm_property_create_object() 创建。

对象属性的工作方式类似于 blob 属性,但方式更通用。它们仅限于原子驱动程序,并且必须设置 DRM_MODE_PROP_ATOMIC 标志。

DRM_MODE_PROP_BLOB

Blob 属性存储一个没有任何格式限制的二进制 blob。二进制 blob 创建为 KMS 独立对象,blob 属性实例值存储其关联 blob 对象的 ID。Blob 属性通过调用 drm_property_create() 并将 DRM_MODE_PROP_BLOB 作为类型来创建。

用于包含 blob 数据的实际 blob 对象使用 drm_property_create_blob() 或通过相应的 IOCTL 创建。

除了仅接受 blob 对象的内置限制之外,blob 属性的工作方式与对象属性完全相同。blob 属性存在的唯一原因是与现有用户空间的向后兼容性。

此外,属性可以具有以下标志的任意组合

DRM_MODE_PROP_ATOMIC

为编码原子模式设置状态的属性设置。此类属性不会暴露给传统的用户空间。

DRM_MODE_PROP_IMMUTABLE

为用户空间无法更改其值的属性设置。内核允许更新这些属性的值。这通常用于向用户空间暴露探测状态,例如 EDID 或 DP MST 接收器上的连接器路径属性。内核可以通过调用 drm_object_property_set_value() 来更新不可变属性的值。

名称

属性的符号名称

num_values

values 数组的大小。

values

包含属性限制和值的数组。这些限制的解释取决于每个 flags 的类型。

dev

DRM 设备

enum_list

包含枚举和位掩码值的符号名称的 drm_prop_enum_list 结构列表。

描述

此结构表示模式设置对象属性。它将属性的名称与允许的值集相结合。这意味着当驱动程序想要在不同的对象上使用具有相同名称的属性,但具有不同的值范围时,它必须为每个对象创建一个属性。一个例子是 drm_plane 的旋转,例如,当主平面无法旋转时。但是,如果名称和值范围都匹配,则可以为同一个对象多次实例化相同的属性结构。用户空间必须能够应对这种情况,并且不能假设相同的符号属性在所有模式设置对象上都具有相同的模式设置对象 ID。

属性由特殊的函数之一创建,如 flags 结构成员中详细说明的那样。

要实际公开属性,必须使用 drm_object_attach_property() 将其附加到每个对象。目前,属性只能附加到 drm_connectordrm_crtcdrm_plane

属性也用作原子 IOCTL 的通用元数据传输。在传统模式设置 IOCTL 中直接在结构中设置的所有内容(如平面源或目标窗口,或例如到 CRTC 的链接)都作为设置了 DRM_MODE_PROP_ATOMIC 标志的属性公开。

struct drm_property_blob

drm_property 的 Blob 数据

定义:

struct drm_property_blob {
    struct drm_mode_object base;
    struct drm_device *dev;
    struct list_head head_global;
    struct list_head head_file;
    size_t length;
    void *data;
};

成员

基础

基本 KMS 对象

dev

DRM 设备

head_global

drm_mode_config.property_blob_list 中全局 blob 列表上的条目。

head_file

drm_file.blobs 列表中每个文件的 blob 列表上的条目。

length

blob 的大小(以字节为单位),在对象的生命周期内不变

data

实际数据,嵌入在此结构的末尾

描述

Blobs 用于存储比适合 drm_property 可用的 64 位更大的值。

Blobs 使用 drm_property_blob_get()drm_property_blob_put() 进行引用计数。它们使用 drm_property_create_blob() 创建。

bool drm_property_type_is(struct drm_property *property, uint32_t type)

检查属性的类型

参数

struct drm_property *property

要检查的属性

uint32_t type

要与之比较的属性类型

描述

这是一个辅助函数,因为属性类型的 uapi 编码由于历史原因而有点特殊。

struct drm_property *drm_property_find(struct drm_device *dev, struct drm_file *file_priv, uint32_t id)

查找属性对象

参数

struct drm_device *dev

DRM 设备

struct drm_file *file_priv

用于检查租约的 drm 文件。

uint32_t id

属性对象 ID

描述

此函数查找由 id 指定的属性对象并返回它。

struct drm_property *drm_property_create(struct drm_device *dev, u32 flags, const char *name, int num_values)

创建一个新的属性类型

参数

struct drm_device *dev

drm 设备

u32 flags

指定属性类型的标志

const char *name

属性的名称

int num_values

预定义值的数量

描述

这将创建一个新的通用 drm 属性,然后可以使用 drm_object_attach_property() 将其附加到 drm 对象。返回的属性对象必须使用 drm_property_destroy() 释放,这在调用 drm_mode_config_cleanup() 时会自动完成。

返回

成功时指向新创建的属性的指针,失败时为 NULL。

struct drm_property *drm_property_create_enum(struct drm_device *dev, u32 flags, const char *name, const struct drm_prop_enum_list *props, int num_values)

创建一个新的枚举属性类型

参数

struct drm_device *dev

drm 设备

u32 flags

指定属性类型的标志

const char *name

属性的名称

const struct drm_prop_enum_list *props

带有属性值的枚举列表

int num_values

预定义值的数量

描述

这将创建一个新的通用 drm 属性,然后可以使用 drm_object_attach_property() 将其附加到 drm 对象。返回的属性对象必须使用 drm_property_destroy() 释放,这在调用 drm_mode_config_cleanup() 时会自动完成。

用户空间只允许为枚举属性设置预定义的值之一。

返回

成功时指向新创建的属性的指针,失败时为 NULL。

struct drm_property *drm_property_create_bitmask(struct drm_device *dev, u32 flags, const char *name, const struct drm_prop_enum_list *props, int num_props, uint64_t supported_bits)

创建一个新的位掩码属性类型

参数

struct drm_device *dev

drm 设备

u32 flags

指定属性类型的标志

const char *name

属性的名称

const struct drm_prop_enum_list *props

带有属性位标志的枚举列表

int num_props

props 数组的大小

uint64_t supported_bits

所有支持的枚举值的位掩码

描述

这将创建一个新的位掩码 drm 属性,然后可以使用 drm_object_attach_property() 将其附加到 drm 对象。返回的属性对象必须使用 drm_property_destroy() 释放,这会在调用 drm_mode_config_cleanup() 时自动完成。

与普通枚举属性相比,用户空间允许设置任何预定义的属性位标志值的组合。

返回

成功时指向新创建的属性的指针,失败时为 NULL。

struct drm_property *drm_property_create_range(struct drm_device *dev, u32 flags, const char *name, uint64_t min, uint64_t max)

创建一个新的无符号范围属性类型

参数

struct drm_device *dev

drm 设备

u32 flags

指定属性类型的标志

const char *name

属性的名称

uint64_t min

属性的最小值

uint64_t max

属性的最大值

描述

这将创建一个新的通用 drm 属性,然后可以使用 drm_object_attach_property() 将其附加到 drm 对象。返回的属性对象必须使用 drm_property_destroy() 释放,这在调用 drm_mode_config_cleanup() 时会自动完成。

用户空间允许设置(包括最小值和最大值)范围内的任何无符号整数值。

返回

成功时指向新创建的属性的指针,失败时为 NULL。

struct drm_property *drm_property_create_signed_range(struct drm_device *dev, u32 flags, const char *name, int64_t min, int64_t max)

创建一个新的有符号范围属性类型

参数

struct drm_device *dev

drm 设备

u32 flags

指定属性类型的标志

const char *name

属性的名称

int64_t min

属性的最小值

int64_t max

属性的最大值

描述

这将创建一个新的通用 drm 属性,然后可以使用 drm_object_attach_property() 将其附加到 drm 对象。返回的属性对象必须使用 drm_property_destroy() 释放,这在调用 drm_mode_config_cleanup() 时会自动完成。

用户空间允许设置(包括最小值和最大值)范围内的任何有符号整数值。

返回

成功时指向新创建的属性的指针,失败时为 NULL。

struct drm_property *drm_property_create_object(struct drm_device *dev, u32 flags, const char *name, uint32_t type)

创建一个新的对象属性类型

参数

struct drm_device *dev

drm 设备

u32 flags

指定属性类型的标志

const char *name

属性的名称

uint32_t type

来自 DRM_MODE_OBJECT_* 定义的对象类型

描述

这将创建一个新的通用 drm 属性,然后可以使用 drm_object_attach_property() 将其附加到 drm 对象。返回的属性对象必须使用 drm_property_destroy() 释放,这在调用 drm_mode_config_cleanup() 时会自动完成。

用户空间只允许将其设置为给定 type 的任何属性值。 仅适用于原子属性,这是强制执行的。

返回

成功时指向新创建的属性的指针,失败时为 NULL。

struct drm_property *drm_property_create_bool(struct drm_device *dev, u32 flags, const char *name)

创建一个新的布尔属性类型

参数

struct drm_device *dev

drm 设备

u32 flags

指定属性类型的标志

const char *name

属性的名称

描述

这将创建一个新的通用 drm 属性,然后可以使用 drm_object_attach_property() 将其附加到 drm 对象。返回的属性对象必须使用 drm_property_destroy() 释放,这在调用 drm_mode_config_cleanup() 时会自动完成。

这是作为仅具有 {0, 1} 作为有效值的范围属性实现的。

返回

成功时指向新创建的属性的指针,失败时为 NULL。

int drm_property_add_enum(struct drm_property *property, uint64_t value, const char *name)

向枚举属性添加可能的值

参数

struct drm_property *property

要更改的枚举属性

uint64_t value

新枚举的值

const char *name

新枚举的符号名称

描述

此函数向属性添加枚举。

不建议使用它,驱动程序应使用更具体的助手来直接创建已附加所有枚举的属性。

返回

成功时为零,失败时为错误代码。

void drm_property_destroy(struct drm_device *dev, struct drm_property *property)

销毁一个 DRM 属性

参数

struct drm_device *dev

drm 设备

struct drm_property *property

要销毁的属性

描述

此函数会释放一个属性,包括任何附加的资源,例如枚举值。

struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, size_t length, const void *data)

创建新的 blob 属性

参数

struct drm_device *dev

用于创建属性的 DRM 设备

size_t length

为 blob 数据分配的长度

const void *data

如果指定,则将数据复制到 blob 中

描述

为指定的 DRM 设备创建一个新的 blob 属性,可以选择复制数据。请注意,blob 属性旨在保持不变,因此在将 blob 用作任何属性的值之前,必须填写数据。

返回

成功时返回带有单个引用的新 blob 属性,失败时返回 ERR_PTR 值。

void drm_property_blob_put(struct drm_property_blob *blob)

释放 blob 属性引用

参数

struct drm_property_blob *blob

DRM blob 属性

描述

释放对 blob 属性的引用。可能会释放该对象。

struct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob)

获取 blob 属性引用

参数

struct drm_property_blob *blob

DRM blob 属性

描述

获取对现有 blob 属性的引用。返回 blob,这允许它在赋值中用作简写。

struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, uint32_t id)

查找一个 blob 属性并获取引用

参数

struct drm_device *dev

drm 设备

uint32_t id

blob 属性的 ID

描述

如果成功,这将对 blob 属性进行额外的引用。调用者需要确保最终使用 drm_property_blob_put() 再次取消引用返回的属性。

返回

失败时返回 NULL,成功时返回指向 blob 的指针。

int drm_property_replace_global_blob(struct drm_device *dev, struct drm_property_blob **replace, size_t length, const void *data, struct drm_mode_object *obj_holds_id, struct drm_property *prop_holds_id)

替换现有的 blob 属性

参数

struct drm_device *dev

drm 设备

struct drm_property_blob **replace

要替换的 blob 属性指针的位置

size_t length

新 blob 的数据长度,如果没有数据则为 0

const void *data

新 blob 的内容,如果没有数据则为 NULL

struct drm_mode_object *obj_holds_id

可选的、用于保存 blob ID 的属性的对象

struct drm_property *prop_holds_id

可选的、用于保存 blob ID 的属性 return 成功时返回 0,失败时返回错误

描述

此函数将替换 blob 列表中的全局属性,可以选择更新持有该属性 ID 的属性。

如果长度为 0 或数据为 NULL,则不会创建新的 blob,并且如果指定了持有属性,则该属性将设置为 0。

假设调用者保护对 replace 指针的访问,例如通过为其父项持有相关的模式设置对象锁。

例如,drm_connector 有一个“PATH”属性,其中包含 blob 属性的 ID,该属性具有 MST 路径信息的值。使用 replace 指向连接器的 path_blob_ptr、为新路径信息设置的长度和数据、obj_holds_id 设置为连接器的基本对象以及 prop_holds_id 设置为 path 属性名称来调用此函数将执行完全原子的更新。对 path_blob_ptr 的访问受到调用者持有连接器上的锁的保护。

bool drm_property_replace_blob(struct drm_property_blob **blob, struct drm_property_blob *new_blob)

替换 blob 属性

参数

struct drm_property_blob **blob

指向要替换的成员 blob 的指针

struct drm_property_blob *new_blob

用于替换的新 blob

返回

如果 blob 实际上被替换,则返回 true。

int drm_property_replace_blob_from_id(struct drm_device *dev, struct drm_property_blob **blob, uint64_t blob_id, ssize_t expected_size, ssize_t expected_elem_size, bool *replaced)

替换一个 blob 属性并获取引用

参数

struct drm_device *dev

DRM 设备

struct drm_property_blob **blob

指向要替换的成员 blob 的指针

uint64_t blob_id

用于替换的新 blob 的 ID

ssize_t expected_size

blob 属性的预期大小

ssize_t expected_elem_size

blob 属性中元素的预期大小

bool *replaced

如果 blob 实际上被替换

描述

从 ID 查找新的 blob,获取其引用,检查 blob 及其元素 的预期大小,然后用新的 blob 替换旧的 blob。如果替换操作成功,则进行通告。

返回

如果 blob 实际上被替换,则返回 true。如果未找到新的 blob 或大小不匹配,则返回 -EINVAL。

标准连接器属性

DRM 连接器具有一些标准化的属性

EDID

Blob 属性,其中包含从接收器读取的当前 EDID。这对于解析接收器识别信息(如供应商、型号和序列号)非常有用。驱动程序应通过调用 drm_connector_update_edid_property() 来更新此属性,通常在 使用 drm_add_edid_modes() 解析 EDID 后。用户空间无法更改此属性。

用户空间不应解析 EDID 来获取通过其他 KMS 属性公开的信息(因为内核可能会对 EDID 应用限制、怪癖或修复)。例如,用户空间不应尝试从 EDID 解析模式列表。

DPMS

用于设置连接器电源状态的旧属性。对于原子驱动程序,仅为与现有驱动程序的向后兼容性而提供此属性,它会重新映射为控制连接器所连接的 CRTC 上的“ACTIVE”属性。驱动程序永远不应直接设置此属性,它由 DRM 核心通过调用 drm_connector_funcs.dpms 回调来处理。对于原子驱动程序,重新映射到“ACTIVE”属性在 DRM 核心中实现。

请注意,无法通过 MODE_ATOMIC ioctl 设置此属性,用户空间必须改为使用 CRTC 上的“ACTIVE”。

警告

对于也运行在旧驱动程序上的用户空间,“DPMS”语义要复杂得多。首先,用户空间不能依赖 GETCONNECTOR 返回的“DPMS”值来实际反映现实,因为许多驱动程序未能更新它。对于原子驱动程序,这一点在 drm_atomic_helper_update_legacy_modeset_state() 中得到处理。

第二个问题是,DPMS 状态仅在连接器连接到 CRTC 时才是明确定义的。在原子中,DRM 核心强制在这种情况下“ACTIVE”关闭,但“DPMS”不存在此类检查。

最后,当使用旧的 SETCONFIG ioctl 启用输出时,“DPMS”将被强制为 ON。但如上所述,这可能不会反映在旧驱动程序上的软件值中。

总结:仅当已知连接器已启用时才设置“DPMS”,假设成功的 SETCONFIG 调用也会将“DPMS”设置为 on,并且永远不要回读“DPMS”的值,因为它可能不正确。

PATH

用于标识此接收器物理连接方式的连接器路径属性。由 DP MST 使用。应通过调用 drm_connector_set_path_property() 来设置此属性,在 DP MST 的情况下,使用 MST 管理器创建的路径属性。用户空间无法更改此属性。

在 DP MST 的情况下,该属性的格式为 mst:<parent>-<ports>,其中 <parent> 是父连接器的 KMS 对象 ID,<ports> 是以连字符分隔的 DP MST 端口号列表。请注意,KMS 对象 ID 不能保证在重新启动后保持稳定。

TILE

连接器平铺组属性,用于指示一组 DRM 连接器如何组合成一个逻辑屏幕。这被用于高分辨率外部屏幕(通常只使用一根电缆,但会暴露多个 DP MST 接收器)或高分辨率集成面板(如双链路 DSI),这些面板不是锁相的。请注意,对于锁相的平铺面板(如双链路 LVDS 或双链路 DSI),驱动程序应尽量不暴露平铺,并在需要时虚拟化 drm_crtcdrm_plane。驱动程序应使用 drm_connector_set_tile_property() 更新此值。用户空间无法更改此属性。

link-status

连接器 link-status 属性,用于指示链路的状态。link-status 的默认值为“GOOD”。如果在模式设置期间或之后出现错误,则内核驱动程序可能会将其设置为“BAD”并发出热插拔 uevent。驱动程序应使用 drm_connector_set_link_status_property() 更新此值。

当用户空间接收到热插拔 uevent 并检测到“BAD” link-status 时,接收器将不再接收像素(例如,屏幕完全变黑)。可用模式列表可能已更改。如果当前模式已消失,则用户空间应选择新的模式,并执行新的模式设置,并将 link-status 设置为“GOOD”以重新启用连接器。

如果多个连接器共享同一个 CRTC,并且其中一个连接器获得“BAD” link-status,则其他连接器不受影响(即,接收器仍然继续接收像素)。

当用户空间对具有“BAD” link-status 的连接器执行原子提交而不将该属性重置为“GOOD”时,接收器可能仍然不接收像素。当用户空间执行原子提交,将 link-status 属性重置为“GOOD”而没有设置 ALLOW_MODESET 标志时,它可能会失败,因为需要进行模式设置。

用户空间只能将 link-status 更改为“GOOD”,将其更改为“BAD”是空操作。

为了与非原子用户空间向后兼容,内核会尝试在 SETCRTC IOCTL 中自动将 link-status 设置回“GOOD”。如果该模式不再有效,则可能会失败,类似于如果在此期间连接了不同的屏幕可能会失败的情况。

non_desktop

指示在显示标准桌面环境或控制台时应忽略输出。这很可能是因为输出设备不是直线型的。

内容保护

用户空间使用此属性来请求内核保护未来通过链路传输的内容。当请求时,内核将应用适当的保护方式(通常是 HDCP),并使用该属性告知用户空间保护已激活。

驱动程序可以通过在初始化时调用 drm_connector_attach_content_protection_property() 来进行设置。

此属性的值可以是以下之一

DRM_MODE_CONTENT_PROTECTION_UNDESIRED = 0

链路未受保护,内容以明文传输。

DRM_MODE_CONTENT_PROTECTION_DESIRED = 1

用户空间已请求内容保护,但链路当前未受保护。在此状态下,内核应尽快启用内容保护。

DRM_MODE_CONTENT_PROTECTION_ENABLED = 2

用户空间已请求内容保护,并且链路已受保护。只有驱动程序可以将该属性设置为此值。如果用户空间尝试设置为 ENABLED,则内核将返回 -EINVAL。

一些准则

  • 应保留 DESIRED 状态,直到用户空间通过将该属性设置为 UNDESIRED 来取消断言它。这意味着只有当用户明确请求时,ENABLED 才应转换为 UNDESIRED。

  • 如果状态为 DESIRED,则内核应尽可能尝试重新验证链路。这包括禁用/启用、dpms、热插拔、下游设备更改、链路状态失败等。

  • 在以下内核触发的情况下,内核会通过 drm_hdcp_update_content_protection 发送带有连接器 ID 和属性 ID 的 uevent

    • DESIRED -> ENABLED(身份验证成功)

    • ENABLED -> DESIRED(身份验证终止)

  • 请注意,对于用户空间触发的属性状态更改没有 uevent,这些更改不会失败,例如

    • DESIRED/ENABLED -> UNDESIRED

    • UNDESIRED -> DESIRED

  • 用户空间负责轮询该属性或侦听 uevent,以确定该值何时从 ENABLED 转换为 DESIRED。这表示链路不再受保护,用户空间应采取适当的操作(无论可能是什么)。

HDCP 内容类型

此枚举属性由用户空间使用,用于向内核声明显示流的内容类型。这里,显示流是指用户空间打算通过 HDCP 加密显示的任何显示内容。

流的内容类型由流的所有者决定,为“HDCP Type0”或“HDCP Type1”。

该属性的值可以是以下之一
  • “HDCP Type0”:DRM_MODE_HDCP_CONTENT_TYPE0 = 0

  • “HDCP Type1”:DRM_MODE_HDCP_CONTENT_TYPE1 = 1

当内核启动 HDCP 身份验证时(有关详细信息,请参阅“内容保护”),它使用“HDCP 内容类型”中的内容类型,以便与显示接收器执行 HDCP 身份验证。

请注意,在 HDCP 规范版本中,链路可以使用 HDCP 2.2 进行内容类型 0/内容类型 1 的身份验证。而链路只能使用 HDCP 1.4 进行内容类型 0 的身份验证(尽管本质上是隐含的。因为 HDCP 1.4 中没有内容类型的参考)。

HDCP 2.2 身份验证协议本身将“内容类型”作为参数,这是 DP HDCP 2.2 加密算法的输入。

在内容类型 0 的内容保护请求的情况下,内核驱动程序可以选择 HDCP 规范版本 1.4 或 2.2。当 HDCP 2.2 用于“HDCP 类型 0”时,下游中具有 HDCP 2.2 功能的中继器可以将内容发送到经过 HDCP 1.4 身份验证的 HDCP 接收器(类型 0 链路)。但是,如果内容被分类为“HDCP 类型 1”,则上述提到的 HDCP 2.2 中继器不会将内容发送到 HDCP 接收器,因为它无法为“HDCP 类型 1”验证具有 HDCP 1.4 功能的接收器。

请注意,用户空间可以忽略内核驱动程序用于实现“HDCP 内容类型”的 HDCP 版本。

在当前情况下,将内容分类为类型 1 可确保内容只能通过 HDCP 2.2 加密链路显示。

请注意,“HDCP 内容类型”属性是在 HDCP 2.2 中引入的,默认设置为类型 0。它仅由支持 HDCP 2.2(因此支持类型 0 和类型 1)的驱动程序公开。根据 HDCP 规范的后续版本的定义方式,内容类型也可以用于更高的版本。

如果当“内容保护”不是 UNDESIRED 时更改了内容类型,则内核将在同一原子提交中禁用 HDCP 并使用新类型重新启用它。当“内容保护”为 ENABLED 时,这意味着链路已通过 HDCP 身份验证并加密,用于传输“HDCP 内容类型”中提到的流类型。

HDR_OUTPUT_METADATA

连接器属性,使用户空间能够向驱动程序发送 HDR 元数据。此元数据基于用户确定的合成和混合策略,并考虑了硬件和接收端的功能。驱动程序获取此元数据,并在 HDMI 的情况下创建动态范围和母带信息帧 (DRM),在 DP 的情况下创建 SDP 数据包(非音频 INFOFRAME SDP v1.3)。然后将其发送到接收端。这会通知接收端即将到来的帧的颜色编码和亮度参数。

用户空间首先需要通过读取和解析 EDID 来检测接收端的 HDR 功能。HDMI 的 HDR 元数据详细信息在 CTA 861.G 规范中添加。对于 DP,其在 VESA DP 标准 v1.4 中定义。然后,它需要获取以 HDR 编码(基本上是使用 HDR 传输函数)的视频/游戏/应用程序内容的元数据信息。有了这些信息,它需要决定混合策略,并将相关图层/叠加层合成为通用格式。完成混合后,用户空间将知道要发送到接收端的合成帧的元数据。然后,它使用此属性将此元数据通信给驱动程序,驱动程序然后根据连接的编码器类型生成信息帧数据包并发送到接收端。

在以下情况下,用户空间将负责执行色调映射操作
  • 某些图层是 HDR,而另一些图层是 SDR

  • HDR 图层的亮度与接收端不同

它甚至需要进行色彩空间转换,并将所有图层转换为一个通用的色彩空间进行混合。它可以基于相关硬件的功能,使用 GL、Media 或显示引擎来完成此操作。

驱动程序期望将元数据从用户空间放入 struct hdr_output_metadata 结构中。这会作为 blob 接收,并存储在 drm_connector_state.hdr_output_metadata 中。它会解析 EDID,并将接收端元数据保存到 struct hdr_sink_metadata,作为 drm_connector.hdr_sink_metadata。对于 HDMI 编码器,驱动程序使用 drm_hdmi_infoframe_set_hdr_metadata() 辅助函数设置 HDR 元数据,并使用 hdmi_drm_infoframe_pack() 按照规范打包信息帧。

最大 bpc

用户空间使用此范围属性来限制位深度。使用时,驱动程序会根据硬件和接收端支持的有效范围限制 bpc。驱动程序应使用函数 drm_connector_attach_max_bpc_property() 在初始化期间创建属性并将其附加到连接器。

连接器还具有一个标准化的原子属性

CRTC_ID

此连接器应连接到的 drm_crtc 的模式对象 ID。

LCD 面板的连接器也可能具有一个标准化属性

面板方向

在某些设备上,LCD 面板以这样一种方式安装在外壳中,即面板的向上/顶部与设备的顶部不匹配。用户空间可以使用此属性进行检查。请注意,来自触摸屏(具有 INPUT_PROP_DIRECT 的输入设备)的输入坐标仍将 1:1 映射到实际 LCD 面板坐标,因此如果用户空间旋转图片以调整方向,则还必须对触摸屏输入坐标应用相同的转换。此属性通过调用 drm_connector_set_panel_orientation()drm_connector_set_panel_orientation_with_quirk() 进行初始化

缩放模式

此属性定义了如何将非原生模式放大到 LCD 面板的原生模式

不进行放大,缩放留给面板处理。并非所有驱动程序都公开此模式。

输出将放大到面板的完整分辨率,忽略纵横比。

居中

不进行放大,输出在面板的原生分辨率内居中。

全纵横比

输出将放大以最大化宽度或高度,同时保持纵横比。

应通过调用 drm_connector_attach_scaling_mode_property() 来设置此属性。请注意,驱动程序也可以将此属性公开给外部输出,在这种情况下,它们必须支持“无”,这应该是默认值(因为外部屏幕具有内置缩放器)。

subconnector

此属性由 DVI-I、TVout 和 DisplayPort 使用,以指示不同的连接器子类型。枚举值或多或少与主连接器类型的枚举值匹配。对于 DVI-I 和 TVout,还有一个匹配的属性“选择子连接器”,允许在信号类型之间切换。DP 子连接器对应于下游端口。

隐私屏幕软件状态、隐私屏幕硬件状态

这两个可选属性可用于查询某些显示器上可用的电子隐私屏幕的状态;在某些情况下,还可以控制状态。如果驱动程序实现了这些属性,则必须同时存在这两个属性。

“隐私屏幕硬件状态”是只读的,它反映了隐私屏幕的实际状态,可能的值为:“已启用”、“已禁用”、“已启用锁定”、“已禁用锁定”。锁定状态表示无法通过 DRM API 更改状态。例如,某些设备可能存在固件设置选项或硬件滑块开关,提供始终开启/关闭模式。

当未锁定时,可以设置“隐私屏幕软件状态”来更改隐私屏幕状态。在这种情况下,驱动程序必须更新硬件状态属性,以反映软件状态属性提交完成后新的状态。当硬件状态被锁定时设置软件状态属性必须被驱动程序解释为当硬件状态变为解锁时将状态更改为设置状态的请求。例如,如果“隐私屏幕硬件状态”为“已启用锁定”,并且软件状态设置为“已禁用”,然后用户通过更改滑块开关位置解锁该状态,则驱动程序必须在收到解锁事件后将状态设置为“已禁用”。

在某些情况下,隐私屏幕的实际状态可能会在 DRM 代码的控制之外更改。例如,可能存在固件处理的热键,用于切换实际状态,或者可以通过其他用户空间 API(例如写入 /proc/acpi/ibm/lcdshadow)更改实际状态。在这种情况下,驱动程序必须更新硬件状态和软件状态以反映新值,从而覆盖软件状态中的任何挂起状态请求。因此,任何挂起的软件状态请求都会被丢弃。

请注意,状态可以在 DRM 主进程控制之外更改的事实意味着用户空间不得缓存软件状态的值。缓存软件状态值并将其包含在以后的原子提交中可能会导致覆盖通过例如固件处理的热键完成的状态更改。因此,除非用户空间想要更改其值,否则不得将隐私屏幕软件状态包含在原子提交中。

左边距、右边距、上边距、下边距

将边距添加到连接器的视口。这通常用于减轻电视上的过扫描。

该值是以像素为单位的黑边大小,该黑边将被添加。附加的 CRTC 的内容将被缩放以填充边距内的整个区域。

边距配置可能会发送到接收端,例如通过 HDMI AVI 信息帧。

驱动程序可以通过调用 drm_mode_create_tv_margin_properties() 来设置这些属性。

色彩空间

此属性用于通知驱动程序用户空间配置像素操作属性以生成什么颜色编码。这些变体设置了色度、传输特性,以及必要时应使用哪个 YCbCr 转换。HDR_OUTPUT_METADATA 的传输特性优先于此属性。用户空间始终配置像素操作属性以生成完整量化范围数据(请参阅广播 RGB 属性)。

驱动程序会通知接收端期望什么色度、传输特性、YCbCr 转换和量化范围(这可能取决于输出模式、输出格式和其他属性)。驱动程序还会将用户空间提供的数据转换为接收端期望的数据。

用户空间必须通过解析 EDID 来检查接收端是否支持驱动程序允许选择的所有可能色度。

由于历史原因,此属性公开了许多会导致未定义行为的变体。

默认

该行为是特定于驱动程序的。

BT2020_RGB

BT2020_YCC

用户空间配置像素操作属性以生成具有 Rec. ITU-R BT.2020 色度、Rec. ITU-R BT.2020(表 4,RGB)传输特性和全量化范围的 RGB 内容。用户空间可以使用 HDR_OUTPUT_METADATA 属性将传输特性设置为 PQ(Rec. ITU-R BT.2100 表 4)或 HLG(Rec. ITU-R BT.2100 表 5),在这种情况下,用户空间配置像素操作属性以生成具有各自传输特性的内容。用户空间必须确保接收端支持 Rec. ITU-R BT.2020 R’G’B’ 和 Rec. ITU-R BT.2020 Y’C’BC’R 色度。驱动程序可以将接收端配置为使用 RGB 格式,告诉接收端期望 Rec. ITU-R BT.2020 R’G’B’ 色度,并转换为适当的量化范围。驱动程序可以将接收端配置为使用 YCbCr 格式,告诉接收端期望 Rec. ITU-R BT.2020 Y’C’BC’R 色度,使用 Rec. ITU-R BT.2020 非恒定亮度转换矩阵转换为 YCbCr,并转换为适当的量化范围。BT2020_RGB 和 BT2020_YCC 变体是等效的,驱动程序自行在 RGB 和 YCbCr 之间进行选择。

SMPTE_170M_YCC:BT709_YCC:XVYCC_601:XVYCC_709:SYCC_601:opYCC_601:opRGB:BT2020_CYCC:DCI-P3_RGB_D65:DCI-P3_RGB_Theater:RGB_WIDE_FIXED:RGB_WIDE_FLOAT

BT601_YCC

该行为未定义。

由于 HDMI 和 DP 具有不同的色彩空间,因此 drm_mode_create_hdmi_colorspace_property() 用于 HDMI 连接器,而 drm_mode_create_dp_colorspace_property() 用于 DP 连接器。

HDMI 特定连接器属性

广播 RGB(HDMI 特定)

指示所使用的量化范围(全范围或有限范围)。颜色处理管道将进行调整以匹配此属性的值,并且将相应地生成和发送 Infoframes。

此属性仅在 HDMI 输出格式为 RGB 时相关。如果它是 YCbCr 变体之一,则会被忽略。

连接器所连接的 CRTC 必须由用户空间配置为始终产生全范围像素。

此属性的值可以是以下之一

自动

量化范围会根据 HDMI 规范(HDMI 1.4b - 第 6.6 节 - 视频量化范围)自动根据模式选择。

强制使用全量化范围。

有限 16:235

强制使用有限量化范围。与名称所暗示的不同,这适用于任何位/组件数。

除“自动”之外的属性值可能会导致颜色偏差(如果选择了“有限”但显示器预期为“全范围”),或者出现黑屏(如果选择了“全范围”但显示器预期为“有限”)。

驱动程序可以通过调用 drm_connector_attach_broadcast_rgb_property() 来设置此属性。

内容类型(HDMI 特定)

指示要在 HDMI infoframes 中使用的内容类型设置,以向外部设备指示内容类型,以便其相应地调整其显示设置。

此属性的值可以是以下之一

无数据

内容类型未知

图形

内容类型为图形

照片

内容类型为照片

电影

内容类型为电影

游戏

内容类型为游戏

每个内容类型的含义在 CTA-861-G 表 15 中定义。

驱动程序可以通过调用 drm_connector_attach_content_type_property() 来设置此属性。到 infoframe 值的解码通过 drm_hdmi_avi_infoframe_content_type() 完成。

模拟电视特定连接器属性

电视模式

指示在模拟电视连接器上使用的电视模式。此属性的值可以是以下之一

NTSC

电视模式为 CCIR 系统 M(也称为 525 行)以及 NTSC 颜色编码。

NTSC-443

电视模式为 CCIR 系统 M(也称为 525 行)以及 NTSC 颜色编码,但颜色副载波频率为 4.43MHz

NTSC-J

电视模式为 CCIR 系统 M(也称为 525 行)以及 NTSC 颜色编码,但黑电平等于消隐电平。

PAL

电视模式为 CCIR 系统 B(也称为 625 行)以及 PAL 颜色编码。

PAL-M

电视模式为 CCIR 系统 M(也称为 525 行)以及 PAL 颜色编码。

PAL-N

电视模式为 CCIR 系统 N 以及 PAL 颜色编码,颜色副载波频率为 3.58MHz,SECAM 色彩空间,并且通道比其他 PAL 变体窄。

SECAM

电视模式为 CCIR 系统 B(也称为 625 行)以及 SECAM 颜色编码。

单色

使用适合 DRM 模式的时序,包括用于 525 线或 625 线模式的均衡脉冲,没有基座或颜色编码。

驱动程序可以通过调用 drm_mode_create_tv_properties() 来设置此属性。

标准 CRTC 属性

DRM CRTC 有一些标准化属性

活动

用于设置 CRTC 电源状态的原子属性。当设置为 1 时,CRTC 将主动显示内容。当设置为 0 时,CRTC 将关闭电源。不期望用户空间在将 ACTIVE 设置为 0 时重置 CRTC 资源,如模式和平面。

用户空间可以依赖 ACTIVE 更改为 1 以确保原子测试永远不会失败,只要没有其他属性发生更改即可。如果对 ACTIVE 的更改使原子测试失败,则是驱动程序错误。因此,将 ACTIVE 设置为 0 不得释放内部资源(如保留的内存带宽或时钟发生器)。

请注意,连接器上的旧版 DPMS 属性在内部路由以控制原子驱动程序的此属性。

MODE_ID

用于设置 CRTC 显示时序的原子属性。该值是包含 DRM 模式信息的 blob 的 ID。要禁用 CRTC,用户空间必须将此属性设置为 0。

将 MODE_ID 设置为 0 将释放为 CRTC 保留的资源。

SCALING_FILTER

用于设置 CRTC 缩放器的缩放滤镜的原子属性

此属性的值可以是以下之一

默认

驱动程序的默认缩放滤镜

最近邻

最近邻缩放滤镜

标准平面属性

DRM 平面有一些标准化属性

type

描述平面类型的不可变属性。

对于启用了 DRM_CLIENT_CAP_ATOMIC 功能的用户空间,平面类型只是一个提示,并且主要被仅限原子测试的提交所取代。类型提示仍然可以用来更容易地找到驱动程序接受的平面配置。

此属性的值可以是以下之一

“主”

要点亮 CRTC,如果附加一个覆盖整个 CRTC 且未设置缩放或裁剪的主平面,则最有可能起作用。

驱动程序可能支持主平面的更多功能,用户空间可以通过仅限测试的原子提交来找到。

内核在旧版 IOCTL DRM_IOCTL_MODE_SETCRTCDRM_IOCTL_MODE_PAGE_FLIP 中隐式使用一些主平面。因此,用户空间不得将任何主平面的显式用法(例如通过原子提交)与这些旧版 IOCTL 混合使用。

“光标”

要启用此平面,使用未配置缩放或裁剪且具有以下属性的帧缓冲,则最有可能起作用

  • 如果驱动程序提供 DRM_CAP_CURSOR_WIDTHDRM_CAP_CURSOR_HEIGHT 功能,请使用此大小创建帧缓冲。否则,创建一个大小为 64x64 的帧缓冲。

  • 如果驱动程序不支持修饰符,则创建一个具有线性布局的帧缓冲。否则,使用 IN_FORMATS 平面属性。

驱动程序可能支持光标平面的更多功能,用户空间可以通过仅限测试的原子提交来找到。

内核在旧版 IOCTL DRM_IOCTL_MODE_CURSORDRM_IOCTL_MODE_CURSOR2 中隐式使用一些光标平面。因此,用户空间不得将任何光标平面的显式用法(例如通过原子提交)与这些旧版 IOCTL 混合使用。

即使未公开光标平面,某些驱动程序也可能支持光标。在这种情况下,可以使用旧版光标 IOCTL 来配置光标。

“覆盖”

既不是主平面也不是光标平面。

当禁用 DRM_CLIENT_CAP_UNIVERSAL_PLANES 功能时,覆盖平面是唯一公开的平面。

IN_FORMATS

Blob 属性,其中包含此平面支持的缓冲区格式和修饰符对的集合。blob 是一个结构体 drm_format_modifier_blob。如果没有此属性,则平面不支持带有修饰符的缓冲区。用户空间无法更改此属性。

请注意,用户空间可以检查 DRM_CAP_ADDFB2_MODIFIERS 驱动程序功能以获得通用修饰符支持。如果设置了此标志,则每个平面都将具有 IN_FORMATS 属性,即使它仅支持 DRM_FORMAT_MOD_LINEAR。在 linux 内核版本 v5.1 之前,这方面存在各种错误,导致功能标志和每个平面属性之间不一致。

SIZE_HINTS

Blob 属性,其中包含可用于简单“光标式”用例(例如,无缩放)的一组建议平面大小。使用这些提示可以使用户空间免于通过原子/setcursor ioctl 对支持的平面大小进行广泛探测。

该 blob 包含一个 struct drm_plane_size_hint 数组,按偏好顺序排列。为了获得最佳使用效果,用户空间应选择满足其自身要求的第一个大小。

驱动程序应仅将此属性附加到支持非常有限的大小集合的平面。

请注意,属性值 0(即无 blob)保留供将来使用。当前用户空间应忽略该属性,如果该值为 0,并回退到其他一些方法(例如,DRM_CAP_CURSOR_WIDTHDRM_CAP_CURSOR_HEIGHT)来确定要使用的适当平面大小。

平面合成属性

标准平面属性支持的基本平面合成模型仅具有一个源矩形(在 drm_framebuffer 中的逻辑像素内),具有亚像素精度,该矩形被放大到 drm_crtc 的可见区域中的像素对齐的目标矩形。CRTC 的可见区域由请求模式的水平和垂直可见像素(存储在 hdisplayvdisplay 中)定义(存储在 drm_crtc_state.mode 中)。这两个矩形都存储在 drm_plane_state 中。

对于原子 ioctl,平面对象上的以下标准(原子)属性编码基本平面合成模型

SRC_X

源矩形在 drm_framebuffer 中的 X 坐标偏移量,以 16.16 定点表示。必须为正数。

SRC_Y

源矩形在 drm_framebuffer 中的 Y 坐标偏移量,以 16.16 定点表示。必须为正数。

SRC_W

源矩形在 drm_framebuffer 中的宽度,以 16.16 定点表示。SRC_X 加 SRC_W 必须在源帧缓冲的宽度内。必须为正数。

SRC_H

源矩形在 drm_framebuffer 中的高度,以 16.16 定点表示。SRC_Y 加 SRC_H 必须在源帧缓冲的高度内。必须为正数。

CRTC_X

目标矩形的 X 坐标偏移量。可以为负数。

CRTC_Y

目标矩形的 Y 坐标偏移量。可以为负数。

CRTC_W

目标矩形的宽度。CRTC_X 加 CRTC_W 可以延伸超过 drm_crtc 当前可见水平区域。

CRTC_H

目标矩形的高度。CRTC_Y 加 CRTC_H 可以超出 drm_crtc 当前可见的垂直区域。

FB_ID

此平面应扫描输出的 drm_framebuffer 的模式对象 ID。

CRTC_ID

此平面应连接到的 drm_crtc 的模式对象 ID。

请注意,源矩形必须完全位于 drm_framebuffer 的边界内。目标矩形可以位于 CRTC 当前模式的可见区域之外。它必须由驱动程序进行适当的裁剪,这可以通过调用 drm_plane_helper_check_update() 来完成。驱动程序也允许适当地舍入子像素采样位置,但只能舍入到下一个完整像素。绝不允许采样源矩形之外的任何像素,这在缩放时应用比双线性更复杂的滤波时非常重要。缩放时的滤波模式未指定。

在此基本转换之上,驱动程序还可以公开其他属性

alpha

Alpha 使用 drm_plane_create_alpha_property() 设置。它控制整个平面的不透明度,从透明 (0) 到不透明 (0xffff)。它可以与像素 alpha 组合使用。帧缓冲区中的像素值预计不会与平面相关的全局 alpha 进行预乘。

rotation

旋转使用 drm_plane_create_rotation_property() 设置。它在源矩形和目标矩形之间添加一个旋转和反射步骤。如果没有此属性,则矩形仅缩放,而不旋转或反射。

可能的值

“rotate-<度数>”

表示 drm 平面沿逆时针方向旋转了 <度数> 度。

“reflect-<轴>”

表示 drm 平面的内容沿 <轴> 轴反射,方式与镜像相同。

reflect-x

|o |    | o|
|  | -> |  |
| v|    |v |

reflect-y

|o |    | ^|
|  | -> |  |
| v|    |o |
zpos

Z 位置使用 drm_plane_create_zpos_immutable_property()drm_plane_create_zpos_property() 设置。它控制重叠平面的可见性。如果没有此属性,则主平面始终位于光标平面之下,并且所有其他平面之间的顺序未定义。正 Z 轴指向用户,即 Z 位置值较低的平面位于 Z 位置值较高的平面之下。Z 位置值相同的两个平面的顺序未定义。请注意,Z 位置值也可以是不可变的,以告知用户空间有关平面的硬编码堆叠的信息,请参阅 drm_plane_create_zpos_immutable_property()。如果任何平面具有 zpos 属性(可变或不可变),则所有平面都应具有 zpos 属性。

像素混合模式

像素混合模式使用 drm_plane_create_blend_mode_property() 设置。它为 alpha 混合方程选择添加一个混合模式,描述当前平面的像素如何与背景合成。

定义了三种 alpha 混合方程

“无”

忽略像素 alpha 的混合公式

out.rgb = plane_alpha * fg.rgb +
        (1 - plane_alpha) * bg.rgb
“预乘”

假设像素颜色值已与 alpha 通道值进行预乘的混合公式

out.rgb = plane_alpha * fg.rgb +
        (1 - (plane_alpha * fg.alpha)) * bg.rgb
“覆盖”

假设像素颜色值尚未预乘,并且在将其混合到背景颜色值时将执行此操作的混合公式

out.rgb = plane_alpha * fg.alpha * fg.rgb +
        (1 - (plane_alpha * fg.alpha)) * bg.rgb

使用以下符号

“fg.rgb”

平面像素的每个 RGB 分量值

“fg.alpha”

平面像素的 Alpha 分量值。如果平面的像素格式没有 alpha 分量,则假定为 1.0。在这些情况下,此属性无效,因为所有三个方程都变为等效。

“bg.rgb”

背景的每个 RGB 分量值

“plane_alpha”

由平面的“alpha”属性设置的平面 alpha 值。如果平面未公开“alpha”属性,则假定为 1.0

请注意,此处描述的所有属性扩展都适用于平面或 CRTC(例如,对于背景颜色,当前未公开且假定为黑色)。

SCALING_FILTER

指示要用于平面缩放器的缩放过滤器

此属性的值可以是以下之一

默认

驱动程序的默认缩放滤镜

最近邻

最近邻缩放滤镜

驱动程序可以通过调用 drm_plane_create_scaling_filter_property 为平面设置此属性

损坏跟踪属性

FB_DAMAGE_CLIPS 是一个可选的平面属性,它提供了一种在连接到平面的帧缓冲区的帧缓冲区坐标中指定平面上损坏矩形列表的方法。在当前上下文中,损坏是指自上次平面更新(也称为页面翻转)以来平面帧缓冲区中已更改的区域,无论当前连接的帧缓冲区是否与上次平面更新期间连接的帧缓冲区相同。

FB_DAMAGE_CLIPS 是对内核的提示,这可能有助于某些驱动程序在内部进行优化,特别是对于每个帧缓冲区更改都需要通过网络、USB 等传输的虚拟设备。

由于 FB_DAMAGE_CLIPS 是一个提示,因此它是一个可选属性。用户空间可以忽略损坏剪辑属性,在这种情况下,驱动程序将执行完整的平面更新。如果提供了损坏剪辑,则保证损坏剪辑内的区域将更新到平面。为了提高效率,驱动程序可以执行完整更新,也可以更新损坏剪辑中指定的更多内容。由于驱动程序可以自由读取更多内容,因此用户空间必须始终渲染整个可见的帧缓冲区。否则可能会出现损坏。此外,如果用户空间提供的损坏剪辑未包含对帧缓冲区的实际损坏(自上次平面更新以来),则可能导致不正确的渲染。

FB_DAMAGE_CLIPS 是一个 blob 属性,blob 数据的布局只是一个 drm_mode_rect 数组。与平面 drm_plane_state.src 坐标不同,损坏剪辑不是 16.16 定点。与帧缓冲区中的平面 src 类似,损坏剪辑不能为负数。在损坏剪辑中,x1/y1 是包含的,而 x2/y2 是不包含的。虽然内核不会因重叠的损坏剪辑而报错,但强烈建议不要这样做。

对平面损坏接口感兴趣的驱动程序应通过调用 drm_plane_enable_fb_damage_clips() 来启用 FB_DAMAGE_CLIPS 属性。实现损坏的驱动程序可以使用 drm_atomic_helper_damage_iter_init()drm_atomic_helper_damage_iter_next() 辅助迭代器函数来获取裁剪到 drm_plane_state.src 的损坏矩形。

请注意,有两种类型的损坏处理:帧损坏和缓冲区损坏,所实现的损坏处理类型取决于驱动程序的上传目标。实现每个平面或每个 CRTC 上传目标的驱动程序需要处理帧损坏,而实现每个缓冲区上传目标的驱动程序需要处理缓冲区损坏。

现有的损坏辅助函数仅支持帧损坏类型,目前尚未实现缓冲区老化支持或类似的损坏累积算法。

只有处理帧损坏的驱动程序才能使用上述损坏辅助函数来迭代损坏区域。处理缓冲区损坏的驱动程序必须为 drm_atomic_helper_damage_iter_init() 设置 drm_plane_state.ignore_damage_clips,以了解应忽略损坏剪辑并返回 drm_plane_state.src 作为损坏矩形,以强制执行完整的平面更新。

具有每个缓冲区上传目标的驱动程序可以比较旧的和新的平面状态的 drm_plane_state.fb,以确定自上次平面更新以来连接到平面的帧缓冲区是否已更改。如果 drm_plane_state.fb 已更改,则必须将 drm_plane_state.ignore_damage_clips 设置为 true。

这是因为具有每个平面上传目标的驱动程序希望给定平面的后备存储缓冲区不会更改。如果上传缓冲区在页面翻转之间发生更改,则必须整体更新新的上传缓冲区。如果将帧损坏支持添加到 DRM 损坏辅助函数中,则可以在将来改进此功能,类似于用户空间已经如何处理这种情况,如以下文档中所述

色彩管理属性

通过 drm_crtc 对象上的一组 5 个属性来支持色彩管理或色彩空间调整。它们通过调用 drm_crtc_enable_color_mgmt() 设置。

“DEGAMMA_LUT”

Blob 属性,用于设置反伽马查找表 (LUT),该表将帧缓冲区的像素数据映射到变换矩阵之前。数据被解释为 struct drm_color_lut 元素的数组。硬件可能选择不使用 LUT 元素的完整精度,也不使用 LUT 的所有元素(例如,硬件可能选择在 LUT[0] 和 LUT[4] 之间进行插值)。

将此属性设置为 NULL(blob 属性值设置为 0)意味着应使用线性/直通伽马表。这通常也是驱动程序启动时的状态。驱动程序可以通过 drm_crtc_state.degamma_lut 访问此 blob。

“DEGAMMA_LUT_SIZE”

无符号范围属性,用于指定要设置在 DEGAMMA_LUT 属性上的查找表的大小(大小取决于底层硬件)。如果驱动程序支持多种 LUT 大小,则它们应发布最大大小,并适当地对较小尺寸的 LUT 进行子采样(例如,对于拆分伽马模式)。

“CTM”

Blob 属性,用于设置当前变换矩阵 (CTM),该矩阵应用于通过反伽马 LUT 查找后以及通过伽马 LUT 查找之前的像素数据。数据被解释为结构体 drm_color_ctm

将此属性设置为 NULL(blob 属性值设置为 0)意味着应使用单位/直通矩阵。这通常也是驱动程序启动时的状态。驱动程序可以通过 drm_crtc_state.ctm 访问颜色转换矩阵的 blob。

“GAMMA_LUT”

Blob 属性,用于设置伽马查找表 (LUT),该表将变换矩阵后的像素数据映射到发送到连接器的数据。数据被解释为 struct drm_color_lut 元素的数组。硬件可能选择不使用 LUT 元素的完整精度,也不使用 LUT 的所有元素(例如,硬件可能选择在 LUT[0] 和 LUT[4] 之间进行插值)。

将此属性设置为 NULL(blob 属性值设置为 0)意味着应使用线性/直通伽马表。这通常也是驱动程序启动时的状态。驱动程序可以通过 drm_crtc_state.gamma_lut 访问此 blob。

请注意,由于主要来自 Xorg 传统的历史原因,这也被用于存储索引格式(如 DRM_FORMAT_C8)的颜色映射(有时也称为颜色查找表、CLUT 或调色板)。

“GAMMA_LUT_SIZE”

无符号范围属性,用于指定要设置在 GAMMA_LUT 属性上的查找表的大小(大小取决于底层硬件)。如果驱动程序支持多种 LUT 大小,则它们应发布最大大小,并适当地对较小尺寸的 LUT 进行子采样(例如,对于拆分伽马模式)。

还支持传统的伽马表,该表通过调用 drm_mode_crtc_set_gamma_size() 进行设置。然后,DRM 核心会将传统伽马斜坡与“GAMMA_LUT”别名,如果该属性不可用,则与“DEGAMMA_LUT”别名。

对不同非 RGB 颜色编码的支持通过 drm_plane 特定的 COLOR_ENCODING 和 COLOR_RANGE 属性进行控制。它们通过调用 drm_plane_create_color_properties() 进行设置。

“COLOR_ENCODING”

可选的平面枚举属性,用于支持不同的非 RGB 颜色编码。驱动程序可以提供 DRM 平面支持的标准枚举值的子集。

“COLOR_RANGE”

可选的平面枚举属性,用于支持不同的非 RGB 颜色参数范围。驱动程序可以提供 DRM 平面支持的标准枚举值的子集。

瓦片组属性

瓦片组用于表示具有唯一整数标识符的瓦片显示器。使用 DisplayID v1.3 的瓦片显示器具有唯一的 8 字节句柄,我们将其存储在瓦片组中,因此我们对显示器组中的所有瓦片都有一个通用标识符。该属性称为“TILE”。驱动程序可以使用 drm_mode_create_tile_group()drm_mode_put_tile_group()drm_mode_get_tile_group() 管理瓦片组。但这仅适用于通过非标准方式公开瓦片组信息的内部面板。

显式栅栏属性

显式栅栏允许用户空间控制设备之间的缓冲区同步。栅栏或一组栅栏使用同步文件 fd 在用户空间之间来回传输,并且有两个 DRM 属性用于此目的。每个 DRM 平面上的 IN_FENCE_FD 用于将栅栏发送到内核,每个 DRM CRTC 上的 OUT_FENCE_PTR 用于从内核接收栅栏。

相比之下,使用隐式栅栏,内核会跟踪任何正在进行的渲染,并自动确保原子更新会等待任何挂起的渲染完成。这通常在 struct dma_resv 中跟踪,它也可以包含强制的内核栅栏。隐式同步是 Linux 传统的工作方式(例如,X.org 上的 DRI2/3),而显式栅栏是 Android 所需的。

“IN_FENCE_FD”

使用此属性传递一个栅栏,DRM 应在继续执行原子提交请求并在屏幕上显示平面的帧缓冲区之前等待该栅栏。栅栏可以是普通栅栏,也可以是合并栅栏,sync_file 框架将处理这两种情况,如果收到合并栅栏,则使用 fence_array。在此处传递 -1 表示没有要等待的栅栏。

如果原子提交请求具有 DRM_MODE_ATOMIC_TEST_ONLY 标志,它将仅检查同步文件是否有效。

在驱动程序端,栅栏存储在 struct drm_plane_statefence 参数上。还支持隐式栅栏的驱动程序应使用 drm_gem_plane_helper_prepare_fb() 提取隐式栅栏,以确保驱动程序之间在隐式与显式栅栏的优先级方面具有一致的行为。

“OUT_FENCE_PTR”

使用此属性将文件描述符指针传递给 DRM。一旦原子提交请求调用返回,OUT_FENCE_PTR 将填充同步文件的文件描述符编号。此同步文件包含 CRTC 栅栏,当给定 CRTC 的原子提交*请求中存在的所有帧缓冲区都在屏幕上扫描输出时,该栅栏将被发出信号。

如果传递无效指针,原子提交请求将失败。如果原子提交请求因任何其他原因失败,则返回的输出栅栏 fd 将为 -1。在具有 DRM_MODE_ATOMIC_TEST_ONLY 标志的原子提交中,输出栅栏也将设置为 -1。

请注意,输出栅栏没有与驱动程序的特殊接口,并且在内部由 struct drm_pending_vblank_event 在结构体 drm_crtc_state 中表示,该结构体也由非阻塞原子提交帮助程序和现有用户空间的 DRM 事件处理使用。

可变刷新率属性

具有可变刷新率功能的显示器可以通过延长其垂直前沿时间直到页面翻转或超时来动态调整其刷新率。这可以减少或消除页面翻转与垂直消隐间隔不对齐的情况下的卡顿和延迟。

一个示例场景是应用程序在 60Hz 显示器上以 48Hz 的恒定速率翻转。页面翻转会频繁错过垂直消隐间隔,并且相同的内容会显示两次。这可以观察为具有运动内容时的卡顿。

如果可变刷新率在支持 35Hz 到 60Hz 的可变刷新范围的显示器上处于活动状态,则对于示例场景,将观察不到卡顿。35Hz 的最小支持可变刷新率低于页面翻转频率,并且可以延长垂直前沿时间直到发生页面翻转。垂直消隐间隔将直接与页面翻转率对齐。

并非所有用户空间内容都适合与可变刷新率一起使用。垂直前沿时间的较大且频繁的变化可能会使输入敏感型应用程序的感知卡顿恶化。

面板亮度也会随着垂直前沿时间而变化。某些面板的最小垂直前沿时间和最大垂直前沿时间之间的亮度可能存在明显差异。垂直前沿时间的较大且频繁的变化可能会对此类面板产生可观察到的闪烁。

通过 drm_connectordrm_crtc 对象上的属性支持可变刷新率的用户空间控制。

“vrr_capable”

可选的 drm_connector 布尔属性,驱动程序应使用 drm_connector_attach_vrr_capable_property() 将其附加到可能支持可变刷新率的连接器上。驱动程序应通过调用 drm_connector_set_vrr_capable_property() 来更新属性值。

不存在该属性应表示不支持。

“VRR_ENABLED”

默认的 drm_crtc 布尔属性,用于通知驱动程序 CRTC 上的内容适合可变刷新率呈现。如果接收器支持,即如果 drm_connector 对象上的“vrr_capable”属性为真,则驱动程序会将此属性作为启用可变刷新率支持的提示。当启用时,垂直前沿时间将延长直到页面翻转或超时。

最小垂直前沿时间定义为当前模式的垂直前沿时间。

最大垂直前沿时间大于或等于最小垂直前沿时间。该持续时间来自连接器的最小支持可变刷新率。

驱动程序可能会在这些最小和最大边界内设置进一步的限制。

光标热点属性

HOTSPOT_X:用于设置鼠标热点 X 偏移量的属性。HOTSPOT_Y:用于设置鼠标热点 Y 偏移量的属性。

当平面被用作光标图像以显示鼠标指针时,“热点”是光标图像内鼠标事件预期发生位置的偏移量。

正值将热点从光标平面的左上角向右和向下移动。

大多数显示驱动程序不需要此信息,因为热点实际上没有连接到屏幕上的任何可见内容。但是,对于诸如 para-virtualized 驱动程序(例如 qxl、vbox、virtio、vmwgfx)之类的显示驱动程序,这是必要的,这些驱动程序连接到带有鼠标指针的用户控制台。由于这些控制台通常通过网络进行远程访问,因此它们必须等待完整的网络往返后才能向用户显示指针移动。新的鼠标事件必须从用户的控制台通过网络发送到虚拟输入设备,转发到桌面进行处理,然后才能更新光标平面的位置并通过网络发送回用户的控制台。相反,通过热点信息,控制台可以预测新位置,并在收到确认之前在那里绘制鼠标光标。为了正确执行此操作,用户控制台必须能够预测桌面将如何处理鼠标事件,这通常需要桌面的鼠标拓扑信息,即每个 CRTC 在鼠标坐标空间中的位置。这通常使用一些特定于驱动程序的方法发送到 para-virtualized 驱动程序,然后驱动程序通过虚拟显示设备或虚拟机监控程序将其转发到控制台。

通常假设一次只有一个光标平面以这种方式使用,并且桌面将所有鼠标设备馈送到同一个全局指针。需要此功能的 para-virtualized 驱动程序应仅公开单个光标平面,或找到其他方法与支持多个指针的用户空间桌面进行协调。如果设置了热点属性,则假定光标平面仅用于显示鼠标光标图像,因此,组合光标平面 + 偏移量的位置可以用于与来自鼠标设备的输入进行协调。

然后,光标将绘制在 CRTC 控制台中平面的位置,或者作为用户控制台上与其桌面鼠标位置对应的自由浮动光标平面。

希望在公开热点属性的驱动程序上正常工作的 DRM 客户端应通告 DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT。在不专门处理光标平面的驱动程序上设置此属性将返回 EOPNOTSUPP,用户空间可以使用它来衡量他们正在运行的硬件/驱动程序的要求。通告 DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT 意味着用户空间客户端将正确设置热点属性。

现有的 KMS 属性

下表给出了各种模块/驱动程序公开的 DRM 属性的说明。因为此表非常笨拙,所以不要在此处添加任何新属性。而是在上面的章节中记录它们。

所有者模块/驱动程序

属性名称

类型

属性值

附加对象

描述/限制

DVI-I

“子连接器”

枚举

{ “未知”,“DVI-D”,“DVI-A” }

连接器

待定

“选择子连接器”

枚举

{ “自动”,“DVI-D”,“DVI-A” }

连接器

待定

电视

“子连接器”

枚举

{ “未知”,“复合”,“SVIDEO”,“分量”,“SCART” }

连接器

待定

“选择子连接器”

枚举

{ “自动”,“复合”,“SVIDEO”,“分量”,“SCART” }

连接器

待定

“模式”

枚举

{ “NTSC_M”,“NTSC_J”,“NTSC_443”,“PAL_B” } 等

连接器

待定

“左边距”

范围

最小值=0,最大值=100

连接器

待定

“右边距”

范围

最小值=0,最大值=100

连接器

待定

“上边距”

范围

最小值=0,最大值=100

连接器

待定

“下边距”

范围

最小值=0,最大值=100

连接器

待定

“亮度”

范围

最小值=0,最大值=100

连接器

待定

“对比度”

范围

最小值=0,最大值=100

连接器

待定

“闪烁减少”

范围

最小值=0,最大值=100

连接器

待定

“过扫描”

范围

最小值=0,最大值=100

连接器

待定

“饱和度”

范围

最小值=0,最大值=100

连接器

待定

“色调”

范围

最小值=0,最大值=100

连接器

待定

虚拟 GPU

“建议的 X”

范围

最小值=0,最大值=0xffffffff

连接器

用于建议连接器 X 偏移量的属性

“建议的 Y”

范围

最小值=0,最大值=0xffffffff

连接器

用于建议连接器 Y 偏移量的属性

可选

“宽高比”

枚举

{ “无”,“4:3”,“16:9” }

连接器

待定

“音频”

枚举

{ “强制-dvi”,“关闭”,“自动”,“开启” }

连接器

待定

SDVO-电视

“模式”

枚举

{ “NTSC_M”,“NTSC_J”,“NTSC_443”,“PAL_B” } 等

连接器

待定

“左_边距”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“右_边距”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“上_边距”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“下_边距”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“水平位置”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“垂直位置”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“对比度”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“饱和度”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“色调”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“清晰度”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“闪烁_滤镜”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“闪烁_滤镜_自适应”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“闪烁_滤镜_2d”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“电视_色度_滤镜”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“电视_亮度_滤镜”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“点爬行”

范围

最小值=0,最大值=1

连接器

待定

SDVO-电视/LVDS

“亮度”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

CDV gma-500

通用

“广播 RGB”

枚举

{ “完整”,“受限 16:235” }

连接器

待定

Poulsbo

通用

“背光”

范围

最小值=0,最大值=100

连接器

待定

SDVO-电视

“模式”

枚举

{ “NTSC_M”,“NTSC_J”,“NTSC_443”,“PAL_B” } 等

连接器

待定

“左_边距”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“右_边距”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“上_边距”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“下_边距”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“水平位置”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“垂直位置”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“对比度”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“饱和度”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“色调”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“清晰度”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“闪烁_滤镜”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“闪烁_滤镜_自适应”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“闪烁_滤镜_2d”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“电视_色度_滤镜”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“电视_亮度_滤镜”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

“点爬行”

范围

最小值=0,最大值=1

连接器

待定

SDVO-电视/LVDS

“亮度”

范围

最小值=0,最大值=SDVO 相关

连接器

待定

armada

CRTC

“CSC_YUV”

枚举

{ “自动” , “CCIR601”, “CCIR709” }

CRTC

待定

“CSC_RGB”

枚举

{ “自动”, “计算机系统”, “工作室” }

CRTC

待定

覆盖

“颜色键”

范围

最小值=0,最大值=0xffffff

平面

待定

“颜色键_最小值”

范围

最小值=0,最大值=0xffffff

平面

待定

“颜色键_最大值”

范围

最小值=0,最大值=0xffffff

平面

待定

“颜色键_值”

范围

最小值=0,最大值=0xffffff

平面

待定

“颜色键_alpha”

范围

最小值=0,最大值=0xffffff

平面

待定

“颜色键_模式”

枚举

{ “已禁用”,“Y 分量”,“U 分量” , “V 分量”,“RGB”,“R 分量”,“G 分量”,“B 分量” }

平面

待定

“亮度”

范围

最小值=0,最大值=256 + 255

平面

待定

“对比度”

范围

最小值=0,最大值=0x7fff

平面

待定

“饱和度”

范围

最小值=0,最大值=0x7fff

平面

待定

exynos

CRTC

“模式”

枚举

{ “正常”,“空白” }

CRTC

待定

i2c/ch7006_drv

通用

“缩放”

范围

最小值=0,最大值=2

连接器

待定

电视

“模式”

枚举

{ “PAL”, “PAL-M”,“PAL-N”}, ”PAL-Nc” , “PAL-60”, “NTSC-M”, “NTSC-J” }

连接器

待定

nouveau

NV10 覆盖

“颜色键”

范围

最小值=0,最大值=0x01ffffff

平面

待定

“对比度”

范围

最小值=0,最大值=8192-1

平面

待定

“亮度”

范围

最小值=0,最大值=1024

平面

待定

“色调”

范围

最小值=0,最大值=359

平面

待定

“饱和度”

范围

最小值=0,最大值=8192-1

平面

待定

“iturbt_709”

范围

最小值=0,最大值=1

平面

待定

Nv04 覆盖

“颜色键”

范围

最小值=0,最大值=0x01ffffff

平面

待定

“亮度”

范围

最小值=0,最大值=1024

平面

待定

显示

“抖动模式”

枚举

{ “自动”,“关闭”,“开启” }

连接器

待定

“抖动深度”

枚举

{ “自动”,“关闭”,“开启”,“静态 2x2”,“动态 2x2”,“时间” }

连接器

待定

“欠扫描”

枚举

{ “自动”,“6 bpc”,“8 bpc” }

连接器

待定

“欠扫描水平边框”

范围

最小值=0,最大值=128

连接器

待定

“欠扫描垂直边框”

范围

最小值=0,最大值=128

连接器

待定

“鲜艳色调”

范围

最小值=0,最大值=180

连接器

待定

“色彩鲜艳度”

范围

最小值=0,最大值=200

连接器

待定

omap

通用

“z 顺序”

范围

最小值=0,最大值=3

CRTC,平面

待定

qxl

通用

“热插拔_模式_更新”

范围

最小值=0,最大值=1

连接器

待定

radeon

DVI-I

“相干”

范围

最小值=0,最大值=1

连接器

待定

DAC 启用负载检测

“负载检测”

范围

最小值=0,最大值=1

连接器

待定

电视标准

“电视标准”

枚举

{ “ntsc”,“pal”,“pal-m”,“pal-60”,“ntsc-j” , “scart-pal”, “pal-cn”, “secam” }

连接器

待定

旧式 TMDS PLL 检测

“tmds_pll”

枚举

{ “驱动程序”,“bios” }

待定

欠扫描

“欠扫描”

枚举

{ “关闭”,“开启”,“自动” }

连接器

待定

“欠扫描水平边框”

范围

最小值=0,最大值=128

连接器

待定

“欠扫描垂直边框”

范围

最小值=0,最大值=128

连接器

待定

音频

“音频”

枚举

{ “关闭”,“开启”,“自动” }

连接器

待定

FMT 抖动

“抖动”

枚举

{ “关闭”,“开启” }

连接器

待定

“颜色键”

范围

最小值=0,最大值=0x01ffffff

平面

待定

垂直消隐

从计算机的角度来看,每次显示器显示新帧时,扫描输出引擎都会从上到下逐行“扫描输出”显示图像。当前像素行称为当前扫描线。

除了显示器的可见区域外,通常还有几个额外的扫描线实际上没有显示在屏幕上。这些额外的扫描线不包含图像数据,偶尔用于诸如音频和信息帧等功能。由这些扫描线组成的区域称为垂直消隐区域,简称 vblank。

为了历史参考,垂直消隐期旨在为电子枪(在 CRT 上)提供足够的时间移动回到屏幕顶部以开始扫描输出下一帧。水平消隐期也是类似的。它们旨在为电子枪提供足够的时间移动回到屏幕的另一侧以开始扫描下一条扫描线。

physical →   ⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽
top of      |                                        |
display     |                                        |
            |               New frame                |
            |                                        |
            |↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓|
            |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| ← Scanline,
            |↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓|   updates the
            |                                        |   frame as it
            |                                        |   travels down
            |                                        |   ("scan out")
            |               Old frame                |
            |                                        |
            |                                        |
            |                                        |
            |                                        |   physical
            |                                        |   bottom of
vertical    |⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽| ← display
blanking    ┆xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx┆
region   →  ┆xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx┆
            ┆xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx┆
start of →   ⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽
new frame

“显示器的物理顶部”是高精度/校正时间戳的参考点。

在许多显示硬件上,编程需要在垂直消隐期间生效,以便可以安全地更改诸如伽玛、要扫描输出的图像缓冲区等设置,而不会在屏幕上显示任何视觉伪影。在某些不容错的硬件中,某些编程必须在同一个 vblank 中开始和结束。为了帮助硬件编程的计时,通常会提供中断来通知驱动程序何时可以开始更新寄存器。在这种情况下,中断称为 vblank 中断。

vblank 中断可能会在不同的点触发,具体取决于硬件。某些硬件实现将在新帧开始时触发中断,其他实现将在不同的时间点触发中断。

垂直消隐在图形渲染中起着重要作用。要实现无撕裂显示,用户必须将页面翻转和/或渲染同步到垂直消隐。DRM API 提供 ioctl 来执行与垂直消隐同步的页面翻转并等待垂直消隐。

DRM 核心处理大部分垂直消隐管理逻辑,其中涉及过滤掉虚假中断,保持无竞争的消隐计数器,处理计数器回绕和重置以及保持使用计数。它依靠驱动程序来生成垂直消隐中断,并可选择提供硬件垂直消隐计数器。

驱动程序必须使用调用 drm_vblank_init() 初始化垂直消隐处理核心。最起码,驱动程序需要实现 drm_crtc_funcs.enable_vblankdrm_crtc_funcs.disable_vblank,并在其 vblank 中断处理程序中调用 drm_crtc_handle_vblank() 以支持正常工作的 vblank。

垂直消隐中断可以由 DRM 核心或驱动程序本身启用(例如,处理页面翻转操作)。DRM 核心维护一个垂直消隐使用计数,以确保在用户仍然需要中断时不会禁用中断。为了增加使用计数,驱动程序调用 drm_crtc_vblank_get(),并通过 drm_crtc_vblank_put() 再次释放 vblank 引用。在这两个调用之间,保证启用 vblank 中断。

在许多硬件上,禁用 vblank 中断不能以无竞争的方式完成,请参阅 drm_vblank_crtc_config.disable_immediatedrm_driver.max_vblank_count。在这种情况下,vblank 核心仅在定时器过期后禁用 vblank,这可以通过 vblankoffdelay 模块参数配置。

不支持垂直消隐中断的硬件的驱动程序不得调用 drm_vblank_init()。对于此类驱动程序,原子助手将自动生成伪 vblank 事件作为显示更新的一部分。驱动程序也可以通过启用和禁用 struct drm_crtc_state.no_vblank 来控制此功能。

垂直消隐和中断处理函数参考

struct drm_pending_vblank_event

待处理的 vblank 事件跟踪

定义:

struct drm_pending_vblank_event {
    struct drm_pending_event base;
    unsigned int pipe;
    u64 sequence;
    union {
        struct drm_event base;
        struct drm_event_vblank vbl;
        struct drm_event_crtc_sequence seq;
    } event;
};

成员

基础

用于跟踪待处理 DRM 事件的基础结构。

pipe

此事件所属的 drm_crtcdrm_crtc_index()

sequence

帧事件应触发的时间

event

将发送到用户空间的实际事件。

event.base

DRM 事件基类。

event.vbl

通过 MODE_PAGE_FLIP 或 MODE_ATOMIC IOCTL 请求的 vblank 事件的事件有效负载。也由传统的 WAIT_VBLANK IOCTL 生成,但新的用户空间应使用 MODE_QUEUE_SEQUENCE 和 event.seq 代替。

event.seq

MODE_QUEUEU_SEQUENCE IOCTL 的事件有效负载。

struct drm_vblank_crtc_config

CRTC 的 vblank 配置

定义:

struct drm_vblank_crtc_config {
    int offdelay_ms;
    bool disable_immediate;
};

成员

offdelay_ms

Vblank 关闭延迟,单位为毫秒,用于确定 drm_vblank_crtc.disable_timer 在禁用之前等待的时间。

默认为 drm_crtc_vblank_on() 中的 drm_vblank_offdelay 的值。

disable_immediate

有关立即 vblank 禁用的确切语义,请参阅 drm_device.vblank_disable_immediate

此外,这将跟踪每个 crtc 的立即禁用值,以防它需要与给定设备的默认值不同。

默认为 drm_crtc_vblank_on()drm_device.vblank_disable_immediate 的值。

struct drm_vblank_crtc

CRTC 的 vblank 跟踪

定义:

struct drm_vblank_crtc {
    struct drm_device *dev;
    wait_queue_head_t queue;
    struct timer_list disable_timer;
    seqlock_t seqlock;
    atomic64_t count;
    ktime_t time;
    atomic_t refcount;
    u32 last;
    u32 max_vblank_count;
    unsigned int inmodeset;
    unsigned int pipe;
    int framedur_ns;
    int linedur_ns;
    struct drm_display_mode hwmode;
    struct drm_vblank_crtc_config config;
    bool enabled;
    struct kthread_worker *worker;
    struct list_head pending_work;
    wait_queue_head_t work_wait_queue;
};

成员

dev

指向 drm_device 的指针。

queue

vblank 等待程序的等待队列。

disable_timer

用于延迟 vblank 禁用滞后逻辑的禁用定时器。Vblank 禁用通过 drm_vblank_crtc_config.offdelay_msdrm_device.max_vblank_count 值的设置来控制。

seqlock

保护 vblank 计数和时间。

count

当前的软件 vblank 计数器。

请注意,对于给定的 vblank 计数器值,drm_crtc_handle_vblank()drm_crtc_vblank_count()drm_crtc_vblank_count_and_time() 提供了一个屏障:在调用 drm_crtc_handle_vblank() 之前完成的任何写入对于后面函数的调用者都是可见的,前提是 vblank 计数相同或更高。

重要提示:此保证需要屏障,因此永远不要直接访问此字段。请改用 drm_crtc_vblank_count()

time

count 对应的 Vblank 时间戳。

refcount

vblank 中断的用户/等待程序的数量。仅当此引用计数达到 0 时,才能使用 disable_timer 禁用硬件中断。

last

drm_device.vbl_lock 保护,用于回绕处理。

max_vblank_count

此 crtc 的 vblank 寄存器的最大值。此值 +1 将导致 vblank 寄存器回绕。vblank 核心使用它来处理回绕。

如果设置为零,则 vblank 核心将尝试通过高精度时间戳猜测 vblank 中断禁用时经过的 vblank。这种方法会因较长时间内的小竞争和不精确而受到影响,因此始终建议公开硬件 vblank 计数器。

这是通过 drm_crtc_set_max_vblank_count() 设置的运行时可配置的每个 crtc 的最大值。如果使用此值,则驱动程序必须将设备范围的 drm_device.max_vblank_count 保留为零。

如果非零,则必须设置 drm_crtc_funcs.get_vblank_counter

inmodeset

跟踪是否由于模式设置而禁用了 vblank。对于旧版驱动程序,位 2 另外跟踪是否已获取额外的临时 vblank 引用以弥补硬件计数器重置/跳转。KMS 驱动程序应改为调用 drm_crtc_vblank_off()drm_crtc_vblank_on(),它们会显式保存和恢复 vblank 计数。

pipe

与此结构对应的 drm_crtcdrm_crtc_index()

framedur_ns

帧/场持续时间,单位为纳秒,由 drm_crtc_vblank_helper_get_vblank_timestamp() 使用,并由 drm_calc_timestamping_constants() 计算。

linedur_ns

行持续时间,单位为纳秒,由 drm_crtc_vblank_helper_get_vblank_timestamp() 使用,并由 drm_calc_timestamping_constants() 计算。

hwmode

当前硬件显示模式的缓存。仅当设置了 enabled 时才有效。这由诸如 drm_crtc_vblank_helper_get_vblank_timestamp() 之类的助手使用。我们不能仅通过查看 drm_crtc_state.adjusted_mode 来访问硬件模式,因为很难从中断上下文中获取它。

config

存储给定 CRTC 的 vblank 配置值。另请参阅 drm_crtc_vblank_on_config()

enabled

跟踪相应 drm_crtc 的启用状态,以避免重复禁用,从而破坏保存的状态。非原子 KMS 的驱动程序需要它,因为这些驱动程序可能会多次执行其 CRTC 禁用功能。

worker

用于执行 vblank 工作的 kthread_worker

pending_work

等待未来 vblank 的已计划 drm_vblank_work 项的列表。

work_wait_queue

用于发出 drm_vblank_work 项已完成执行或已取消信号的等待队列。

描述

此结构跟踪一个 CRTC 的 vblank 状态。

请注意,出于历史原因,垂直同步消隐处理代码仍然与旧式/非 KMS 驱动程序共享 - 这是一个独立的结构,不直接连接到 struct drm_crtc。但所有公共接口函数都接受一个 struct drm_crtc 来隐藏此实现细节。

u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc)

检索主垂直同步消隐计数器

参数

struct drm_crtc *crtc

要检索哪个计数器

描述

此函数类似于 drm_crtc_vblank_count(),但此函数使用高精度时间戳支持进行插值,以处理与垂直同步消隐中断的竞争。

这对于可以获取扫描输出位置但没有硬件帧计数器的硬件最有用。

int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs)

初始化垂直同步消隐支持

参数

struct drm_device *dev

DRM 设备

unsigned int num_crtcs

dev 支持的 CRTC 数量

描述

此函数初始化 num_crtcs 显示管道的垂直同步消隐支持。清理工作通过使用 drmm_add_action_or_reset() 添加的清理函数自动处理。

返回

成功时返回零,失败时返回负错误代码。

bool drm_dev_has_vblank(const struct drm_device *dev)

测试是否已为设备初始化垂直同步消隐

参数

const struct drm_device *dev

设备

描述

驱动程序可以调用此函数来测试是否已为设备初始化垂直同步消隐支持。对于大多数硬件,这意味着也可以启用垂直同步消隐。

原子助手使用此函数初始化 drm_crtc_state.no_vblank。另请参阅 drm_atomic_helper_check_modeset()

返回

如果已为给定设备初始化垂直同步消隐,则为 True,否则为 False。

wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc)

获取 CRTC 的垂直同步消隐等待队列

参数

struct drm_crtc *crtc

要检索哪个 CRTC 的垂直同步消隐等待队列

描述

此函数返回指向 CRTC 的垂直同步消隐等待队列的指针。驱动程序可以使用它来实现使用 wait_event() 和相关函数的垂直同步消隐等待。

void drm_calc_timestamping_constants(struct drm_crtc *crtc, const struct drm_display_mode *mode)

计算垂直同步消隐时间戳常量

参数

struct drm_crtc *crtc

应该更新其时间戳常量的 drm_crtc。

const struct drm_display_mode *mode

包含扫描输出时序的显示模式

描述

计算并存储垂直同步消隐和交换完成时间戳稍后需要的各种常量,例如,通过 drm_crtc_vblank_helper_get_vblank_timestamp()。它们源自 CRTC 的真实扫描输出时序,因此它们会考虑面板缩放或其他调整。

bool drm_crtc_vblank_helper_get_vblank_timestamp_internal(struct drm_crtc *crtc, int *max_error, ktime_t *vblank_time, bool in_vblank_irq, drm_vblank_get_scanout_position_func get_scanout_position)

精确的垂直同步消隐时间戳助手

参数

struct drm_crtc *crtc

要检索其垂直同步消隐时间戳的 CRTC

int *max_error

时间戳中允许的最大误差(纳秒)。返回时包含时间戳的真实最大误差

ktime_t *vblank_time

指向应接收时间戳的时间的指针

bool in_vblank_irq

drm_crtc_handle_vblank() 调用时为 True。如果设置了标志,一些驱动程序需要为 GPU 特定的垂直消隐 irq 怪癖应用一些解决方法。

drm_vblank_get_scanout_position_func get_scanout_position

用于检索扫描输出位置的回调函数。请参阅 struct drm_crtc_helper_funcs.get_scanout_position。

描述

根据给定的 drm_display_mode 时序和 CRTC 的当前视频扫描输出位置实现精确垂直同步消隐时间戳的计算。

当前实现仅处理标准视频模式。对于双扫描和隔行模式,驱动程序应调整硬件模式(从原子模式设置驱动程序的 drm_crtc_state.adjusted 模式获取)以匹配报告的扫描输出位置。

请注意,原子驱动程序必须在启用 CRTC 之前调用 drm_calc_timestamping_constants()。原子助手已经在 drm_atomic_helper_calc_timestamping_constants() 中处理了这一点。

返回

成功时返回 true,失败时返回 false,即当无法获取准确的时间戳时。

bool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error, ktime_t *vblank_time, bool in_vblank_irq)

精确的垂直同步消隐时间戳助手

参数

struct drm_crtc *crtc

要检索其垂直同步消隐时间戳的 CRTC

int *max_error

时间戳中允许的最大误差(纳秒)。返回时包含时间戳的真实最大误差

ktime_t *vblank_time

指向应接收时间戳的时间的指针

bool in_vblank_irq

drm_crtc_handle_vblank() 调用时为 True。如果设置了标志,一些驱动程序需要为 GPU 特定的垂直消隐 irq 怪癖应用一些解决方法。

描述

根据给定的 drm_display_mode 时序和 CRTC 的当前视频扫描输出位置实现精确垂直同步消隐时间戳的计算。如果实现了 drm_crtc_helper_funcs.get_scanout_position,则可以直接将其用作 kms 驱动程序的 drm_crtc_funcs.get_vblank_timestamp 实现。

当前实现仅处理标准视频模式。对于双扫描和隔行模式,驱动程序应调整硬件模式(从原子模式设置驱动程序的 drm_crtc_state.adjusted 模式获取)以匹配报告的扫描输出位置。

请注意,原子驱动程序必须在启用 CRTC 之前调用 drm_calc_timestamping_constants()。原子助手已经在 drm_atomic_helper_calc_timestamping_constants() 中处理了这一点。

返回

成功时返回 true,失败时返回 false,即当无法获取准确的时间戳时。

u64 drm_crtc_vblank_count(struct drm_crtc *crtc)

检索“处理过的”垂直同步消隐计数器值

参数

struct drm_crtc *crtc

要检索哪个计数器

描述

获取表示自系统启动以来垂直同步消隐事件数量的“处理过的”垂直同步消隐计数值,包括由于模式设置活动而丢失的事件。请注意,此计时器对于竞争的垂直同步消隐中断是不正确的(因为它只报告软件垂直同步消隐计数器),对于此类用例,请参阅 drm_crtc_accurate_vblank_count()

请注意,对于给定的垂直同步消隐计数器值,drm_crtc_handle_vblank()drm_crtc_vblank_count()drm_crtc_vblank_count_and_time() 提供了一个屏障:任何在调用 drm_crtc_handle_vblank() 之前完成的写入,如果垂直同步消隐计数器值相同或更新,则对后面函数的调用者可见。

另请参阅 drm_vblank_crtc.count

返回

软件垂直同步消隐计数器。

u64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, ktime_t *vblanktime)

检索“处理过”的垂直同步消隐计数器值以及与该垂直同步消隐计数器值对应的系统时间戳

参数

struct drm_crtc *crtc

要检索哪个计数器

ktime_t *vblanktime

指向接收垂直同步消隐时间戳的时间的指针。

描述

获取“处理过”的垂直同步消隐计数器值,该值表示自系统启动以来垂直同步消隐事件的数量,包括由于模式设置活动而丢失的事件。返回与当前垂直同步消隐计数器值相对应的垂直同步消隐间隔时间的系统时间戳。

请注意,对于给定的垂直同步消隐计数器值,drm_crtc_handle_vblank()drm_crtc_vblank_count()drm_crtc_vblank_count_and_time() 提供了一个屏障:任何在调用 drm_crtc_handle_vblank() 之前完成的写入,如果垂直同步消隐计数器值相同或更新,则对后面函数的调用者可见。

另请参阅 drm_vblank_crtc.count

int drm_crtc_next_vblank_start(struct drm_crtc *crtc, ktime_t *vblanktime)

计算下一个垂直同步消隐的时间

参数

struct drm_crtc *crtc

用于计算下一个垂直同步消隐时间的 crtc

ktime_t *vblanktime

指向接收下一个垂直同步消隐时间戳的时间的指针。

描述

基于上一个垂直同步消隐的时间和帧时长,计算下一个垂直同步消隐周期开始的预期时间

void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, struct drm_pending_vblank_event *e)

在页面翻转后准备垂直同步消隐事件

参数

struct drm_crtc *crtc

垂直同步消隐事件的源 CRTC

struct drm_pending_vblank_event *e

要发送的事件

描述

许多驱动程序需要为下一个垂直同步消隐中断生成垂直同步消隐事件。例如,当页面翻转中断在页面翻转被准备好时发生,而不是在下一个垂直同步消隐周期内实际执行时发生。此帮助程序函数准确地实现了所需的垂直同步消隐准备行为。

  1. 驱动程序将新的硬件状态提交到垂直同步消隐同步寄存器中。

  2. 发生垂直同步消隐,提交硬件状态。此外,相应的垂直同步消隐中断被触发并由中断处理程序完全处理。

  3. 原子提交操作继续调用 drm_crtc_arm_vblank_event()

  4. 该事件仅为下一个垂直同步消隐发送,这是错误的。

当驱动程序在写入新的硬件状态之前调用 drm_crtc_arm_vblank_event() 时,可能会发生等效的竞争。

使此安全工作的唯一方法是阻止垂直同步消隐触发(并阻止硬件提交任何其他内容),直到整个原子提交序列运行完成。如果硬件没有这样的功能(例如,使用“go”位),则使用此函数是不安全的。相反,驱动程序需要通过调用 drm_crtc_send_vblank_event() 从其中断处理程序手动发送事件,并确保硬件在提交原子更新时不会发生任何可能的竞争。

调用者必须为通过 drm_crtc_vblank_get() 获取的事件 e 持有垂直同步消隐引用,该引用将在下一个垂直同步消隐到达时被丢弃。

注意

使用此函数发送 drm_crtc_state.event 作为原子提交一部分的驱动程序必须确保下一个垂直同步消隐与原子提交提交到硬件的时间完全相同。此函数本身并防止下一个垂直同步消隐中断与此函数调用或原子提交操作竞争。一个可能的序列是

void drm_crtc_send_vblank_event(struct drm_crtc *crtc, struct drm_pending_vblank_event *e)

在页面翻转后发送垂直同步消隐事件的帮助程序

参数

struct drm_crtc *crtc

垂直同步消隐事件的源 CRTC

struct drm_pending_vblank_event *e

要发送的事件

描述

更新最近处理的垂直同步消隐事件的序列号和时间戳,并将其发送到用户空间。调用者必须持有事件锁。

有关可在特定情况下使用的帮助程序,特别是用于为原子提交操作发送事件的帮助程序,请参阅 drm_crtc_arm_vblank_event()

int drm_crtc_vblank_get(struct drm_crtc *crtc)

获取垂直同步消隐事件的引用计数

参数

struct drm_crtc *crtc

要拥有的 CRTC

描述

获取垂直同步消隐事件的引用计数,以避免在使用时禁用它们。

返回

成功时返回零,失败时返回负错误代码。

void drm_crtc_vblank_put(struct drm_crtc *crtc)

放弃垂直同步消隐事件的所有权

参数

struct drm_crtc *crtc

要放弃的计数器

描述

释放给定垂直同步消隐计数器的所有权,如果可能,关闭中断。在 drm_vblank_crtc_config.offdelay_ms 毫秒后禁用中断。

void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe)

等待一个垂直同步消隐

参数

struct drm_device *dev

DRM 设备

unsigned int pipe

CRTC 索引

描述

这会使用 irq 驱动程序接口等待 pipe 上通过一个垂直同步消隐。当 pipe 的垂直同步消隐 irq 被禁用时(例如,由于缺少驱动程序支持或因为 crtc 关闭),调用此操作会失败。

这是 drm_crtc_wait_one_vblank() 的旧版本。

void drm_crtc_wait_one_vblank(struct drm_crtc *crtc)

等待一个垂直同步消隐

参数

struct drm_crtc *crtc

DRM crtc

描述

这会使用 irq 驱动程序接口等待 crtc 上通过一个垂直同步消隐。当 crtc 的垂直同步消隐 irq 被禁用时(例如,由于缺少驱动程序支持或因为 crtc 关闭),调用此操作会失败。

void drm_crtc_vblank_off(struct drm_crtc *crtc)

禁用 CRTC 上的垂直同步消隐事件

参数

struct drm_crtc *crtc

有问题的 CRTC

描述

驱动程序可以使用此函数在禁用 CRTC 时关闭垂直同步中断处理。此函数确保存储最新的垂直同步帧计数,以便 drm_vblank_on 可以再次恢复它。

当硬件垂直同步计数器可以被重置时,例如在暂停或通常禁用 crtc 时,驱动程序必须使用此函数。

void drm_crtc_vblank_reset(struct drm_crtc *crtc)

将 CRTC 上的垂直同步状态重置为关闭

参数

struct drm_crtc *crtc

有问题的 CRTC

描述

驱动程序可以使用此函数在加载时将垂直同步状态重置为关闭。驱动程序应该将此函数与 drm_crtc_vblank_off()drm_crtc_vblank_on() 函数一起使用。与 drm_crtc_vblank_off() 相比,此函数的不同之处在于它不保存垂直同步计数器,因此不需要调用任何驱动程序钩子。

这对于恢复驱动程序状态很有用,例如在驱动程序加载或恢复时。

void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, u32 max_vblank_count)

配置硬件最大垂直同步计数器值

参数

struct drm_crtc *crtc

有问题的 CRTC

u32 max_vblank_count

最大硬件垂直同步计数器值

描述

在运行时更新 crtc 的最大硬件垂直同步计数器值。 对于硬件垂直同步计数器的操作取决于当前活动的显示配置的情况非常有用。

例如,如果当特定连接器处于活动状态时,硬件垂直同步计数器不起作用,则可以将最大值设置为零。当该特定连接器未处于活动状态时,可以将最大值再次设置为适当的非零值。

如果使用,则必须在 drm_vblank_on() 之前调用。

void drm_crtc_vblank_on_config(struct drm_crtc *crtc, const struct drm_vblank_crtc_config *config)

在具有自定义配置选项的 CRTC 上启用垂直同步事件

参数

struct drm_crtc *crtc

有问题的 CRTC

const struct drm_vblank_crtc_config *config

垂直同步配置值

描述

请参阅 drm_crtc_vblank_on()。此外,此函数允许您为给定的 CRTC 提供自定义的垂直同步配置。

请注意,config 是复制的,指针不需要在此函数调用后保持有效。 有关参数的详细信息,请参阅 struct drm_vblank_crtc_config

void drm_crtc_vblank_on(struct drm_crtc *crtc)

在 CRTC 上启用垂直同步事件

参数

struct drm_crtc *crtc

有问题的 CRTC

描述

此函数会恢复使用 drm_crtc_vblank_off() 捕获的垂直同步中断状态,通常在启用 crtc 时调用。请注意,对 drm_crtc_vblank_on()drm_crtc_vblank_off() 的调用可以不平衡,因此也可以在驱动程序加载代码中无条件地调用以反映 crtc 的当前硬件状态。

请注意,与 drm_crtc_vblank_on_config() 不同,此处使用的是默认值。

void drm_crtc_vblank_restore(struct drm_crtc *crtc)

估计错过的垂直同步并更新垂直同步计数。

参数

struct drm_crtc *crtc

有问题的 CRTC

描述

电源管理功能可能会导致在垂直同步禁用和启用之间重置帧计数器。驱动程序可以在其 drm_crtc_funcs.enable_vblank 实现中使用此函数,以使用时间戳来估计自上次 drm_crtc_funcs.disable_vblank 以来错过的垂直同步,并更新垂直同步计数器。

请注意,驱动程序必须具有无竞争的高精度时间戳支持,即必须挂接 drm_crtc_funcs.get_vblank_timestamp,并且必须设置 drm_vblank_crtc_config.disable_immediate 以指示时间戳函数与垂直同步硬件计数器增量之间是无竞争的。

bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe)

处理垂直同步事件

参数

struct drm_device *dev

DRM 设备

unsigned int pipe

发生此事件的 CRTC 的索引

描述

驱动程序应在其垂直同步中断处理程序中调用此例程,以更新垂直同步计数器并发送任何可能挂起的信号。

这是 drm_crtc_handle_vblank() 的旧版本。

bool drm_crtc_handle_vblank(struct drm_crtc *crtc)

处理垂直同步事件

参数

struct drm_crtc *crtc

发生此事件的位置

描述

驱动程序应在其垂直同步中断处理程序中调用此例程,以更新垂直同步计数器并发送任何可能挂起的信号。

这是 drm_handle_vblank() 的本机 KMS 版本。

请注意,对于给定的垂直同步消隐计数器值,drm_crtc_handle_vblank()drm_crtc_vblank_count()drm_crtc_vblank_count_and_time() 提供了一个屏障:任何在调用 drm_crtc_handle_vblank() 之前完成的写入,如果垂直同步消隐计数器值相同或更新,则对后面函数的调用者可见。

另请参阅 drm_vblank_crtc.count

返回

如果事件已成功处理,则为 True,如果失败,则为 false。

垂直同步工作

许多 DRM 驱动程序需要以时间敏感的方式对硬件进行编程,很多时候需要在扫描输出的特定区域内开始和完成的最后期限。 大多数情况下,完成此操作的最安全方法是在驱动程序的 IRQ 处理程序中简单地执行所述时间敏感的编程,这使驱动程序可以避免在这些关键区域被抢占。 或者,更好的是,硬件甚至可以独立于 CPU 处理此类时间关键编程的应用。

虽然有相当多的硬件设计为 CPU 不需要担心极其时间敏感的编程,但在少数情况下,这是不可避免的。 一些不容忍的硬件可能需要完全由 CPU 处理某些时间敏感的编程,并且所述编程甚至可能需要太长时间才能在 IRQ 处理程序中处理。 另一种情况是,驱动程序需要执行需要在特定扫描输出周期内完成的任务,但可能会阻塞,因此无法在 IRQ 上下文中处理。 由于我们不是实时内核,因此在 Linux 中,这两种情况都无法完美解决,因此,如果调度程序决定抢占我们,则可能会导致我们错过最后期限。 但对于某些驱动程序来说,如果我们能将自己被抢占的可能性降低到绝对最低限度,那就足够了。

这就是 drm_vblank_work 的用武之地。 drm_vblank_work 提供了一个简单的通用延迟工作实现,该实现将工作执行延迟到特定的垂直同步过去之后,然后在实时优先级下执行该工作。 这为及时执行时间敏感的硬件编程提供了最佳机会,即使系统处于高负载状态也是如此。 drm_vblank_work 还支持重新调度,因此可以轻松实现自我重新武装的工作项。

垂直同步工作函数参考

struct drm_vblank_work

一个延迟的工作项,它会延迟到目标垂直同步(vblank)信号通过后,然后在中断请求(IRQ)上下文之外以实时优先级执行。

定义:

struct drm_vblank_work {
    struct kthread_work base;
    struct drm_vblank_crtc *vblank;
    u64 count;
    int cancelling;
    struct list_head node;
};

成员

基础

基本的 kthread_work 项,将由 drm_vblank_crtc.worker 执行。驱动程序不应直接与此交互,而应依赖 drm_vblank_work_init() 来初始化它。

垂直同步(vblank)

指向此工作项所属的 drm_vblank_crtc 的指针。

count

此工作将执行的目标垂直同步信号。驱动程序不应直接修改此值,而应使用 drm_vblank_work_schedule()

正在取消

当前正在运行的 drm_vblank_work_cancel_sync() 调用的次数。在所有调用完成之前,无法重新调度工作项。

节点

此工作项在 drm_vblank_crtc.pending_work 中的位置。

描述

另请参阅: drm_vblank_work_schedule() drm_vblank_work_init() drm_vblank_work_cancel_sync() drm_vblank_work_flush() drm_vblank_work_flush_all()

to_drm_vblank_work

to_drm_vblank_work (_work)

kthread_work 中检索相应的 drm_vblank_work

参数

_work

嵌入在 drm_vblank_work 中的 kthread_work

int drm_vblank_work_schedule(struct drm_vblank_work *work, u64 count, bool nextonmiss)

调度一个垂直同步工作

参数

struct drm_vblank_work *work

要调度的垂直同步工作

u64 count

目标垂直同步计数

bool nextonmiss

如果错过了目标垂直同步信号,则延迟到下一个垂直同步信号

描述

调度 work 以在 crtc 垂直同步计数达到 count 时执行。

如果 crtc 垂直同步计数已达到 countnextonmissfalse,则工作将立即开始执行。

如果 crtc 垂直同步计数已达到 countnextonmisstrue,则工作将延迟到下一个垂直同步信号(如同 count 被指定为 crtc 垂直同步计数 + 1)。

如果 work 已被调度,此函数将使用新的 count 重新调度该工作。这可以用于自重置工作项。

返回

如果 work 成功(重新)调度,则返回 1;如果它已经被调度或取消,则返回 0;如果失败,则返回负错误代码。

bool drm_vblank_work_cancel_sync(struct drm_vblank_work *work)

取消一个垂直同步工作并等待它完成执行

参数

struct drm_vblank_work *work

要取消的垂直同步工作

描述

取消已调度的垂直同步工作并等待其执行完成。

返回时,保证 work 不再被调度或运行,即使它是自重置的。

返回

如果工作在开始执行之前被取消,则返回 True;否则返回 false

void drm_vblank_work_flush(struct drm_vblank_work *work)

等待已调度的垂直同步工作完成执行

参数

struct drm_vblank_work *work

要刷新的垂直同步工作

描述

等待 work 完成执行一次。

void drm_vblank_work_flush_all(struct drm_crtc *crtc)

刷新 crtc 上所有当前挂起的垂直同步工作。

参数

struct drm_crtc *crtc

要刷新垂直同步工作的 crtc

描述

等待 crtc 上所有当前排队的垂直同步工作完成执行一次。

void drm_vblank_work_init(struct drm_vblank_work *work, struct drm_crtc *crtc, void (*func)(struct kthread_work *work))

初始化一个垂直同步工作项

参数

struct drm_vblank_work *work

垂直同步工作项

struct drm_crtc *crtc

其垂直同步信号将触发工作执行的 CRTC

void (*func)(struct kthread_work *work)

要执行的工作函数

描述

为特定的 crtc 初始化一个垂直同步工作项。