DRM显示学习(TODO)

Android显示系统和DRM驱动框架简介

Android显示系统和DRM驱动框架简介

SM7250(高通5G)平台LCD bringup

DRM(Direct Rendering Manager) 是 Linux 内核中的一个子系统,主要用于管理和控制现代显卡的图形显示功能。它为用户空间的图形应用程序提供直接访问图形硬件的接口,从而实现高效的 2D 和 3D 渲染以及视频输出。DRM 负责处理 GPU 和显示输出设备的管理,并与内核的其他子系统(如 KMS 和 GEM)配合工作,以实现更高效的图形处理。

DRM 的核心组成部分:

  1. KMS(Kernel Mode Setting)

    • KMS 是 DRM 的一部分,负责设置显示设备的分辨率、刷新率、色深等。
    • KMS 控制显示设备的资源管理,比如帧缓冲(Framebuffer)的分配和切换。
  2. GEM(Graphics Execution Manager)

    • GEM 是用于管理 GPU 内存的 DRM 子系统,负责缓冲区分配、映射和 GPU 任务调度。
  3. Buffer Management

    • DRM 框架中使用缓冲区(Buffer)来存储图形数据,如帧缓冲区,用于向显示设备提供图像。
  4. DRM Driver

    • 每个支持 DRM 的显卡厂商都会提供相应的 DRM 驱动,来对接用户空间和内核空间的图形操作。例如,Intel、AMD、NVIDIA 提供了各自的 DRM 驱动程序。

DRM 操作流程:

  1. 初始化显卡资源和缓冲区。
  2. 设置显示模式(分辨率、刷新率等)。
  3. 渲染图像并将其传输到缓冲区。
  4. 将缓冲区内容传递到显示设备进行显示。

========================================

9月27更新

看了一下,tinydrm直接也有st7735的驱动。好,这次一并拿下。

DRM的示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <sys/mman.h>
#include <string.h>

int main() {
    int drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
    if (drm_fd < 0) {
        perror("Cannot open /dev/dri/card0");
        exit(1);
    }

    // 获取资源
    drmModeRes *resources = drmModeGetResources(drm_fd);
    if (!resources) {
        perror("drmModeGetResources failed");
        close(drm_fd);
        exit(1);
    }

    // 查找连接器
    drmModeConnector *connector = NULL;
    for (int i = 0; i < resources->count_connectors; i++) {
        connector = drmModeGetConnector(drm_fd, resources->connectors[i]);
        if (connector->connection == DRM_MODE_CONNECTED) {
            break;
        }
        drmModeFreeConnector(connector);
        connector = NULL;
    }

    if (!connector) {
        perror("No connected connector found");
        drmModeFreeResources(resources);
        close(drm_fd);
        exit(1);
    }

    // 查找第一个支持的模式
    drmModeModeInfo mode = connector->modes[0];

    // 获取显示控制器 (CRTC)
    drmModeCrtc *crtc = drmModeGetCrtc(drm_fd, resources->crtcs[0]);

    // 创建帧缓冲
    uint32_t fb;
    int width = mode.hdisplay;
    int height = mode.vdisplay;
    int stride = width * 4; // 4 bytes per pixel (32-bit color)
    int size = stride * height;

    uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
    handles[0] = 0;
    pitches[0] = stride;
    offsets[0] = 0;

    // 使用 Dumb Buffer 创建 Framebuffer
    struct drm_mode_create_dumb create_dumb = {};
    create_dumb.width = width;
    create_dumb.height = height;
    create_dumb.bpp = 32;
    if (ioctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) < 0) {
        perror("DRM_IOCTL_MODE_CREATE_DUMB failed");
        drmModeFreeResources(resources);
        close(drm_fd);
        exit(1);
    }

    handles[0] = create_dumb.handle;
    pitches[0] = create_dumb.pitch;

    // 分配 framebuffer
    if (drmModeAddFB(drm_fd, width, height, 24, 32, pitches[0], handles[0], &fb) < 0) {
        perror("drmModeAddFB failed");
        drmModeFreeResources(resources);
        close(drm_fd);
        exit(1);
    }

    // 映射 framebuffer 到内存
    struct drm_mode_map_dumb map_dumb = {};
    map_dumb.handle = create_dumb.handle;
    if (ioctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb) < 0) {
        perror("DRM_IOCTL_MODE_MAP_DUMB failed");
        drmModeFreeResources(resources);
        close(drm_fd);
        exit(1);
    }

    void *fb_ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, map_dumb.offset);
    if (fb_ptr == MAP_FAILED) {
        perror("mmap failed");
        drmModeFreeResources(resources);
        close(drm_fd);
        exit(1);
    }

    // 将 framebuffer 清空(全黑)
    memset(fb_ptr, 0, size);

    // 设置 CRTC 并显示 framebuffer
    if (drmModeSetCrtc(drm_fd, crtc->crtc_id, fb, 0, 0, &connector->connector_id, 1, &mode) < 0) {
        perror("drmModeSetCrtc failed");
        munmap(fb_ptr, size);
        drmModeFreeResources(resources);
        close(drm_fd);
        exit(1);
    }

    printf("Framebuffer set to %dx%d\n", width, height);

    // 等待5秒后退出
    sleep(5);

    // 清理
    munmap(fb_ptr, size);
    drmModeRmFB(drm_fd, fb);
    drmModeFreeCrtc(crtc);
    drmModeFreeConnector(connector);
    drmModeFreeResources(resources);
    close(drm_fd);
    return 0;
}

学习 DRM (Direct Rendering Manager) 是理解 Linux 系统中的显示管理和 GPU 驱动开发的关键部分。以下是在树莓派系统上学习 DRM 的步骤和建议:

### 1. **准备开发环境**
   - 使用最新的树莓派 OS,确保你有一个 Raspberry Pi 4 或者更高版本(如 Raspberry Pi 5),它们的 GPU 支持更好。
   - 安装开发工具:
     ```bash
     sudo apt update
     sudo apt install build-essential git libdrm-dev linux-headers-$(uname -r)
     ```
   - 获取 Linux 内核源码:
     ```bash
     git clone https://github.com/raspberrypi/linux.git
     cd linux
     ```

### 2. **阅读 DRM 源码**
   - 在 Linux 内核的 `drivers/gpu/drm/` 目录下有 DRM 驱动的核心代码,建议从 `drm_drv.c`, `drm_fb_helper.c`, 和 `drm_mode_config.c` 开始阅读,理解 DRM 驱动框架的基本工作方式。

### 3. **从简单的 DRM 示例程序开始**
   - 先从编写简单的用户空间应用程序开始,使用 `libdrm` 与 DRM 内核接口进行交互。可以参考 `libdrm` 的文档以及一些简单的 DRM 例子程序,如:
     - [DRM Simple Test](https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset.c)
     - 使用 `kmscube` 工具来展示 DRM 驱动的基本功能。
       ```bash
       sudo apt install kmscube
       kmscube
       ```

### 4. **理解 Framebuffer 和 KMS**
   - 树莓派系统在使用 DRM 时往往会涉及到 KMS (Kernel Mode Setting),它管理模式设置(如分辨率、刷新率等)和图形输出。可以通过 `/dev/dri/card0` 设备文件进行访问。
   - 学习如何使用 Framebuffer (`/dev/fb0`) 与 DRM 进行结合操作。

### 5. **修改或编写 DRM 驱动**
   - 如果希望深入学习,可以尝试修改树莓派的 DRM 驱动或编写自定义驱动程序。树莓派的 DRM 驱动位于 `drivers/gpu/drm/vc4/`(对于 VideoCore GPU)。
   - 阅读 [树莓派 DRM 驱动开发文档](https://www.raspberrypi.org/documentation/computers/linux_kernel.html) 或相关的驱动开发指南。

### 6. **调试和日志输出**
   - DRM 提供了丰富的调试支持,使用 `dmesg` 命令查看内核日志,可以找到 DRM 相关的输出。你可以在模块加载时启用更详细的日志:
     ```bash
     sudo modprobe drm debug=0x1ff
     dmesg | grep drm
     ```

### 7. **学习资源**
   - Linux DRM 文档:`Documentation/gpu/drm-kms.rst`(内核源码中)。
   - [DRM kernel documentation](https://drm.pages.freedesktop.org/doc/): Freedesktop 的 DRM 官方文档。
   - [DRM and KMS Overview](https://www.collabora.com/news-and-blog/blog/2021/10/14/drm-kms-introduction-part-1/):Collabora 的 DRM/KMS 概述。

通过从用户空间程序入手,逐步深入到内核驱动层面,是学习 DRM 在树莓派上的一个有效途径。

待补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值