DRM设备信息

在DRM(Direct Rendering Manager)中,resourcesconnectormodeencoderCRTC 是显示管线的重要组成部分。它们之间有着紧密的关系,形成了从图像生成到输出的完整路径。让我们详细解释它们的含义:

  1. Resources
  • drmModeRes 是一个结构体,它包含了系统中可用的所有 DRM 资源,包括连接器(connectors)、CRTCs(Cathode Ray Tube Controllers)、编码器(encoders)、framebuffers 等。可以将它理解为系统所有显示硬件的集合。
  • 资源提供了系统中所有可用的显示设备信息,并帮助查找具体的连接器、编码器等。
  1. Connector
  • drmModeConnector 表示实际的物理显示设备接口(如HDMI、VGA、DP等)。它用于连接实际的显示设备(显示器、电视等)。
  • 连接器会告诉你是否有显示设备连接,支持的显示模式有哪些(如分辨率、刷新率等),以及当前所选择的模式。
  • 每个连接器可以连接到一个编码器。
  1. Mode
  • drmModeModeInfo 表示显示模式(如分辨率、刷新率、扫描率等)。
  • 连接器拥有一个或多个可用的显示模式,显示设备可以支持不同的分辨率和刷新率。通过模式,可以确定显示图像的具体参数。
  • 在初始化时,选择一个适合的模式,用于后续的显示输出。
  1. Encoder
  • drmModeEncoder 负责将图像信号从图形缓冲区(framebuffer)编码成可以传输到显示设备的信号,并且将信号传递给 CRTC。
  • 每个编码器会与一个特定的连接器和一个 CRTC 配对。
  • 一个连接器只能使用一个编码器。
  1. CRTC
  • drmModeCrtc 是一个控制器,用于控制显示硬件。CRTC 负责从帧缓冲区读取图像数据,并将这些数据送入编码器,编码器再将其发送到连接器和显示设备。
  • CRTC 还控制图像在屏幕上的位置,以及如何扫描帧缓冲区。
  • 每个 CRTC 可以驱动一个或多个连接器,具体取决于系统的设计。

关系总结:

  • Resources 是系统中所有资源的集合,包含了所有可用的连接器、编码器、CRTC 等。
  • Connector 是与实际显示设备相连的接口,提供支持的显示模式信息。每个连接器连接到一个Encoder。
  • Encoder 负责将图像数据编码,并将其发送给 ConnectorCRTC
  • CRTC 是硬件控制器,控制图像从帧缓冲区到显示设备的流动。
  • Mode 定义了显示的分辨率、刷新率等信息,模式是由 Connector 支持并用于驱动显示输出的。

图示关系(简化):

[ Resources ] -> [ Connector ] -> [ Encoder ] -> [ CRTC ] -> [ Framebuffer ]
                     ^                                      |
                     |                                      v
                 [ Mode ]                              [ Display Output ]
  • Resources 提供系统中的所有连接器和编码器信息。
  • Connector 选择显示模式,并通过 Encoder 传输到 CRTC
  • CRTC 负责将图像从帧缓冲区显示到实际的显示设备上。

示例代码

下面是一个示例代码,展示了如何获取并打印设备信息:

#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

// 函数:获取连接器类型名称
const char* getConnectorTypeName(uint32_t type) {
    switch (type) {
        case DRM_MODE_CONNECTOR_Unknown: return "Unknown";
        case DRM_MODE_CONNECTOR_VGA: return "VGA";
        case DRM_MODE_CONNECTOR_DVII: return "DVI-I";
        case DRM_MODE_CONNECTOR_DVID: return "DVI-D";
        case DRM_MODE_CONNECTOR_DVIA: return "DVI-A";
        case DRM_MODE_CONNECTOR_Composite: return "Composite";
        case DRM_MODE_CONNECTOR_SVIDEO: return "S-Video";
        case DRM_MODE_CONNECTOR_LVDS: return "LVDS";
        case DRM_MODE_CONNECTOR_Component: return "Component";
        case DRM_MODE_CONNECTOR_9PinDIN: return "9-Pin DIN";
        case DRM_MODE_CONNECTOR_DisplayPort: return "DisplayPort";
        case DRM_MODE_CONNECTOR_HDMIA: return "HDMI-A";
        case DRM_MODE_CONNECTOR_HDMIB: return "HDMI-B";
        case DRM_MODE_CONNECTOR_TV: return "TV";
        case DRM_MODE_CONNECTOR_eDP: return "eDP";
        case DRM_MODE_CONNECTOR_VIRTUAL: return "Virtual";
        case DRM_MODE_CONNECTOR_DSI: return "DSI";
        default: return "Unknown";
    }
}

int main() {
    int drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
    if (drm_fd < 0) {
        std::cerr << "Cannot open /dev/dri/card0" << std::endl;
        return -1;
    }

    drmModeRes* resources = drmModeGetResources(drm_fd);
    if (!resources) {
        std::cerr << "drmModeGetResources failed" << std::endl;
        close(drm_fd);
        return -1;
    }

    for (int i = 0; i < resources->count_connectors; i++) {
        drmModeConnector* connector = drmModeGetConnector(drm_fd, resources->connectors[i]);
        if (connector) {
            std::cout << "Connector ID: " << connector->connector_id << std::endl;
            std::cout << "Type: " << getConnectorTypeName(connector->connector_type) << std::endl;
            std::cout << "Connection Status: " << (connector->connection == DRM_MODE_CONNECTED ? "Connected" : "Not Connected") << std::endl;
            std::cout << "Modes available: " << connector->count_modes << std::endl;

            // 打印每个可用模式的详细信息
            for (int j = 0; j < connector->count_modes; j++) {
                drmModeModeInfo mode = connector->modes[j];
                std::cout << "Mode " << j+1 << ": " << mode.name << " " << mode.hdisplay << "x" << mode.vdisplay << "@" << mode.vrefresh << "Hz" << std::endl;
            }

            // 打印编码器信息
            if (connector->encoder_id != 0) {
                drmModeEncoder* encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
                if (encoder) {
                    std::cout << "Encoder ID: " << encoder->encoder_id << std::endl;
                    std::cout << "Encoder Type: " << encoder->encoder_type << std::endl;
                    std::cout << "CRTC ID: " << encoder->crtc_id << std::endl;
                    std::cout << "Possible CRTCs: " << encoder->possible_crtcs << std::endl;
                    std::cout << "Possible Clones: " << encoder->possible_clones << std::endl;
                    drmModeFreeEncoder(encoder);
                } else {
                    std::cerr << "Failed to get encoder for connector ID: " << connector->connector_id << std::endl;
                }
            } else {
                std::cout << "No encoder associated with this connector." << std::endl;
            }
            std::cout << "-----------------------------" << std::endl;
            drmModeFreeConnector(connector);
        }
    }
    drmModeFreeResources(resources);
    close(drm_fd);
    return 0;
}

代码说明

  • 获取连接器类型名称:

    • 函数 getConnectorTypeName 用于将连接器类型常量转换为可读的字符串。
  • 打开 DRM 设备:

    • 使用 open 函数打开 DRM 设备文件。
  • 获取 DRM 资源:

    • 使用 drmModeGetResources 函数获取 DRM 资源,包括连接器、CRTC、encoder 等。
  • 遍历连接器:

    • 遍历所有连接器,并获取每个连接器的详细信息。
  • 输出连接器信息:

    • 输出连接器的 ID、类型、连接状态以及可用模式的数量。
    • 遍历并输出每个可用模式的详细信息,包括模式名称、分辨率和刷新率、编码器信息。
  • 释放资源:

    • 使用 drmModeFreeConnectordrmModeFreeResources 释放分配的资源,并关闭 DRM 文件描述符。

connector_id(连接器标识号)

DRM 连接器的 ID 是在系统启动或者显示设备初始化时由内核分配的。这些 ID 是内核模块(如 drm 模块)在检测和初始化图形设备时自动生成的,通常是固定的,并且在每次启动或热插拔设备时保持一致,除非有设备发生了改变(如新增或移除显示器)。

ID 分配的过程
  1. 系统启动或设备初始化:

    • 当系统启动时,内核会加载图形驱动程序(如 i915 驱动程序用于 Intel 显卡)。这些驱动程序会自动检测连接到显卡的所有显示设备(如 HDMI、VGA、DP 等连接器)。
  2. 分配资源:

    • 在检测到显示设备后,驱动程序会为每个连接器、CRTC、encoder 等硬件资源分配一个唯一的 ID。这些 ID 是内核在运行时自动生成的,通常基于硬件的初始化顺序。
  3. 设备热插拔:

    • 如果在系统运行过程中插入或拔出显示设备,驱动程序会重新检测并更新连接器的状态和 ID。如果是新连接的设备,将为其分配一个新的连接器 ID。
ID 的持久性
  • 持久性:

    • 连接器 ID 在设备或系统重启时通常是保持不变的,因为这些 ID 是基于硬件资源的固定顺序分配的,除非系统硬件配置发生了改变(例如增加或移除显示设备)。
  • 热插拔行为:

    • 当显示器连接或断开时,内核会重新评估现有的硬件资源,并可能为新连接的设备分配新的连接器 ID。
示例情景
  • 如果你在系统启动时连接了两个显示器,这些显示器的连接器 ID 可能分别是 3233。即使你拔掉其中一个显示器再重新插入,它的连接器 ID 也可能保持不变。
  • 然而,如果你在运行时添加了一个新的显示器,系统可能会分配一个新的连接器 ID,例如 34,用于这个新连接的显示器。
总结

连接器 ID 是在系统启动或者显示设备初始化时,由内核和图形驱动程序自动分配的。这些 ID 通常在系统运行期间保持不变,并且在热插拔显示设备时也会尽量保持一致,但在添加新设备时可能会生成新的 ID。

connector_type (类型)

连接器的类型表示物理接口的类型,比如 HDMI、VGA、DisplayPort 等。DRM 提供了一些常量来表示这些类型:

  • DRM_MODE_CONNECTOR_Unknown
  • DRM_MODE_CONNECTOR_VGA
  • DRM_MODE_CONNECTOR_DVII
  • DRM_MODE_CONNECTOR_DVID
  • DRM_MODE_CONNECTOR_DVIA
  • DRM_MODE_CONNECTOR_Composite
  • DRM_MODE_CONNECTOR_SVIDEO
  • DRM_MODE_CONNECTOR_LVDS
  • DRM_MODE_CONNECTOR_Component
  • DRM_MODE_CONNECTOR_9PinDIN
  • DRM_MODE_CONNECTOR_DisplayPort
  • DRM_MODE_CONNECTOR_HDMIA
  • DRM_MODE_CONNECTOR_HDMIB
  • DRM_MODE_CONNECTOR_TV
  • DRM_MODE_CONNECTOR_eDP
  • DRM_MODE_CONNECTOR_VIRTUAL
  • DRM_MODE_CONNECTOR_DSI

这些常量定义在 drm_mode.h 文件中。你可以使用这些常量来识别和处理不同类型的连接器。

connect->modes[i] (连接器模式)

连接器的可用模式(connector->count_modes)表示该连接器支持的显示模式的数量。这些显示模式定义了显示器可以使用的分辨率和刷新率等参数。每个连接器可以有多个可用模式,每个模式都包含详细的显示参数,如分辨率、刷新率、像素时钟等。

在使用 DRM (Direct Rendering Manager) API 时,打印出来的 Mode 代表显示器支持的显示模式。显示模式定义了显示器如何展示图像,包括分辨率、刷新率、同步信号等。这些模式由 drmModeModeInfo 结构体表示,通常是通过调用 drmModeGetConnector 函数获取到的 drmModeConnector 结构体中的 modes 数组访问的。

drmModeModeInfo 结构体

drmModeModeInfo结构体用于描述一个显示模式的详细信息。它通常定义在drm_mode.h中,这个结构体的成员变量具体包括:

typedef struct _drmModeModeInfo {
    uint32_t clock;       // 像素时钟,以 kHz 为单位
    uint16_t hdisplay;    // 水平可见区域的像素数(水平分辨率)
    uint16_t hsync_start; // 水平同步信号开始的像素位置
    uint16_t hsync_end;   // 水平同步信号结束的像素位置
    uint16_t htotal;      // 一行中总的像素数,包括前后间隔、同步信号等
    uint16_t hskew;       // 水平偏移
    uint16_t vdisplay;    // 垂直可见区域的像素数(垂直分辨率)
    uint16_t vsync_start; // 垂直同步信号开始的扫描线位置
    uint16_t vsync_end;   // 垂直同步信号结束的扫描线位置
    uint16_t vtotal;      // 一帧中总的扫描线数,包括前后间隔、同步信号等
    uint16_t vscan;       // 垂直扫描倍数(通常为1,适用于双扫描显示模式)
    uint32_t vrefresh;    // 垂直刷新率,以 Hz 为单位
    uint32_t flags;       // 信号标志,指示同步信号的极性等
    uint32_t type;        // 模式类型,如 PREFERRED、DRIVER 等
    char name[DRM_DISPLAY_MODE_LEN]; // 模式名称(例如 "1024x768")
} drmModeModeInfo;
主要字段说明
  1. hdisplayvdisplay:

    • 这是最常见的分辨率(水平和垂直像素数)。例如,1920x1080 表示水平分辨率为 1920 像素,垂直分辨率为 1080 像素。
  2. vrefresh:

    • 这是垂直刷新率,通常以赫兹 (Hz) 表示,表示每秒刷新显示器的次数。例如,60 Hz 表示显示器每秒刷新 60 次。
  3. clock:

    • 这是像素时钟,表示每秒传输的像素数量,以千赫兹 (kHz) 为单位。像素时钟决定了显示器处理图像数据的速度。
  4. hsync_start, hsync_end, htotal, vsync_start, vsync_end, vtotal:

    • 这些字段描述了同步信号的时序,主要用于控制图像扫描的时序和同步,通常不需要手动设置。
  5. flags:

    • 这些标志位用于表示同步信号的极性或其他特定的模式特性。例如,DRM_MODE_FLAG_PHSYNC 表示正极性水平同步信号。
  6. type:

    • 这个字段表示模式的类型。例如,DRM_MODE_TYPE_PREFERRED 表示这是显示器的首选模式(通常是默认模式),而 DRM_MODE_TYPE_DRIVER 表示这是由驱动程序生成的模式。
  7. name:

    • 这是模式的名称,通常以分辨率的形式出现,例如 "1920x1080""1024x768"
总结

drmModeModeInfo 中描述的模式信息包含了显示器在特定模式下工作的详细参数,包括分辨率、刷新率和信号时序。理解这些参数可以帮助你选择和配置合适的显示模式,确保图形输出与显示设备兼容并且工作在最佳状态。

encoder(编码器)

在 DRM (Direct Rendering Manager) 框架中,编码器(drmModeEncoder)是一个关键的组件,用于将图形数据从显示引擎传输到显示设备上。它充当了连接显示硬件和显示输出之间的桥梁。

编码器的作用
  1. 将像素数据从 CRTC 传递到连接器

    • 在 DRM 中,CRTC (Cathode Ray Tube Controller) 负责处理和生成图像帧。编码器则从 CRTC 接收已经渲染好的图像数据,并通过适当的方式传递给连接器。
    • 连接器则负责将图像数据输出到实际的显示设备(如 HDMI、DisplayPort、VGA 等)。
  2. 确定数据传输的具体方式

    • 编码器定义了图像数据是如何通过特定接口(例如 HDMI、DisplayPort)传输的。不同的接口可能需要不同的编码器。
    • 例如,HDMI 编码器和 DisplayPort 编码器之间可能会有很大的不同,因为它们的传输协议和信号要求不同。
  3. 控制与配置显示信号

    • 编码器负责配置各种信号特性,如时钟频率、同步信号极性、颜色格式等,以确保显示器能正确接收和显示图像。
    • 在多显示器设置中,不同的显示器可能使用不同的编码器来连接不同的输出端口。
  4. 多路复用与共享

    • 一个编码器可以连接到多个连接器,允许灵活地配置显示输出。例如,两个显示器可能共享同一个 CRTC,但使用不同的编码器和连接器进行输出。
    • 这使得 DRM 可以支持复杂的显示配置,比如镜像显示或扩展桌面。
编码器的实际使用

在典型的 DRM 应用程序中,开发者通常会执行以下步骤:

  1. 获取系统资源

    • 使用 drmModeGetResources 获取当前 DRM 设备的资源,包括 CRTCs、连接器和编码器。
  2. 选择连接器

    • 使用 drmModeGetConnector 获取连接器信息,选择一个有效且已连接的连接器(通常是连接到显示器的)。
  3. 查找对应的编码器

    • 使用连接器的 encoder_id 获取编码器的详细信息。编码器将确定如何将 CRTC 的输出传输给连接器。
  4. 设置 CRTC 和显示模式

    • 将 CRTC 与编码器和连接器关联起来,设置显示模式(如分辨率、刷新率等),使得最终的图像可以正确显示在屏幕上。
编码器的示例

假设你有一个连接到 HDMI 接口的显示器,以下是编码器的典型流程:

  1. 选择 HDMI 连接器

    • 通过 DRM 获取当前所有连接器,找到连接到 HDMI 接口的那个。
  2. 获取编码器

    • 通过 HDMI 连接器的 encoder_id 获取对应的 HDMI 编码器。这个编码器负责将 CRTC 的输出转换为 HDMI 信号。
  3. 设置 CRTC 和模式

    • 使用获取到的编码器和 HDMI 连接器,设置合适的显示模式并将图像显示到屏幕上。
drmModeEncoder结构体

drmModeEncoder 是一个在 Direct Rendering Manager (DRM) 框架中使用的结构体,用于描述编码器的相关信息。编码器在 DRM 中是负责将图形数据从 CRTC(显示控制器)传递到连接器的桥梁。这个结构体包含了与编码器有关的多个属性。下面是这个结构体中每个变量的含义:

1. uint32_t encoder_id
  • 含义: 编码器的唯一标识符。
  • 详细说明: 这个 ID 用来唯一标识一个编码器。当你需要获取或操作特定的编码器时,这个 ID 会非常有用。它是 DRM 内核为每个编码器分配的唯一值。
2. uint32_t encoder_type
  • 含义: 编码器的类型。
  • 详细说明: 这个字段描述了编码器的类型,通常表示它支持哪种连接类型(例如,HDMI、VGA、DisplayPort 等)。通过这个字段,你可以了解编码器支持的输出接口类型。这些类型通常在 DRM 内核代码中定义为常量,例如:
    • DRM_MODE_ENCODER_NONE
    • DRM_MODE_ENCODER_DAC
    • DRM_MODE_ENCODER_TMDS
    • DRM_MODE_ENCODER_LVDS
    • DRM_MODE_ENCODER_DSI
    • DRM_MODE_ENCODER_VIRTUAL
    • DRM_MODE_ENCODER_DPMST
3. uint32_t crtc_id
  • 含义: 当前编码器正在使用的 CRTC 的 ID。
  • 详细说明: 这个字段表示与编码器关联的 CRTC(显示控制器)的 ID。如果编码器没有与任何 CRTC 关联,该值可能是 0。CRTC 是负责生成和处理帧缓冲区内容的硬件模块,编码器将 CRTC 的输出传输给连接器。
4. uint32_t possible_crtcs
  • 含义: 编码器可以连接的 CRTC 的位掩码。
  • 详细说明: 这个字段是一个位掩码,用来表示编码器可能支持的所有 CRTC。每一位代表一个可能的 CRTC。如果某一位为 1,则表示编码器可以与该 CRTC 配对。这使得一个编码器可以与多个 CRTC 兼容,而不仅仅是单个 CRTC。
5. uint32_t possible_clones
  • 含义: 编码器可能的克隆(clone)编码器的位掩码。
  • 详细说明: 这个字段是一个位掩码,表示哪些编码器可以与当前编码器进行克隆输出(即镜像输出)。克隆输出意味着两个或多个编码器将相同的图像信号传输到不同的连接器和显示器上。这个位掩码的每一位表示一个可能的克隆编码器,如果某一位为 1,则表示可以克隆输出到该编码器。

CRTC

CRTC(Cathode Ray Tube Controller)是负责处理图形数据的硬件模块。它从帧缓冲区中读取图像数据,并生成显示输出信号。每个 CRTC 可以与一个编码器和连接器配对,从而控制一个显示器。在 DRM 中,CRTC 是显示控制的核心部分,负责管理显示模式、分辨率、刷新率等。

drmModeCrtc 结构体

drmModeCrtc 结构体用于描述一个 CRTC(Cathode Ray Tube Controller)的状态及其相关属性。在 DRM(Direct Rendering Manager)框架中,CRTC 是一个负责从帧缓冲区读取图像数据并生成显示输出的硬件模块。该结构体包含了与 CRTC 相关的多个字段,每个字段代表一个特定的属性或状态。以下是这个结构体中每个变量的含义:

1. uint32_t crtc_id
  • 含义: CRTC 的唯一标识符。
  • 详细说明: 这个字段表示 CRTC 的唯一 ID,系统内的每个 CRTC 都有一个唯一的 ID,用于在多个 CRTC 之间进行区分。这个 ID 在配置和控制显示设备时非常有用。
2. uint32_t buffer_id
  • 含义: 当前连接到 CRTC 的帧缓冲区(Framebuffer)的 ID。
  • 详细说明: 这个字段表示 CRTC 当前使用的帧缓冲区的 ID。如果 buffer_id 为 0,则表示 CRTC 当前未连接到任何帧缓冲区(即未输出图像)。
3. uint32_t x, y
  • 含义: CRTC 在帧缓冲区中的起始位置。
  • 详细说明: 这两个字段表示 CRTC 输出的图像在帧缓冲区中的位置,x 是横向位置,y 是纵向位置。这对于多显示器设置(如拼接显示器或分割屏幕)特别重要,允许开发者指定显示区域在帧缓冲区中的位置。
4. uint32_t width, height
  • 含义: CRTC 当前输出的图像的宽度和高度。
  • 详细说明: 这两个字段表示 CRTC 当前输出的图像的分辨率(宽度和高度)。这个分辨率由 CRTC 的显示模式决定。
5. int mode_valid
  • 含义: 表示当前的显示模式是否有效。
  • 详细说明: 这个字段是一个布尔值(通常为 0 或 1),用来指示 mode 字段中的显示模式是否有效。有效模式表示 CRTC 当前配置的模式可以正确用于显示输出。
6. drmModeModeInfo mode
  • 含义: 当前的显示模式信息。
  • 详细说明: 这个字段是一个 drmModeModeInfo 结构体,包含了 CRTC 当前使用的显示模式的详细信息,例如分辨率、刷新率、信号极性等。该结构体定义了 CRTC 如何将图像显示在屏幕上,是配置显示输出的重要参数。
7. int gamma_size
  • 含义: Gamma 校正表的大小。
  • 详细说明: 这个字段表示 CRTC 支持的 gamma 校正表的大小,即 gamma stops 的数量。Gamma 校正用于调整显示器的亮度和色彩,以实现更好的图像质量。gamma_size 决定了 gamma 校正表的精度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值