drm 驱动是如何创建 fb device 的

drm 驱动是如何创建 fb device 的

什么是 drm?

drm 是一个 Linux 内核的显示系统驱动框架,区别于另外一个 DRM数字版权保护

  • drm 是一个管理 GPU 的显示框架
  • 在内核级别提供内存管理,中断处理, DMA控
  • 为应用程序提供统一的操作接口

如何使用 drm 接口

  • libdrm
  • fb device

libdrm

内核提供的 IOCTRL 太多,libdrm 用于简化编程管理当前的显示器,并修改当前的模式成为 KMS ( drm-kms - Kernel Mode-Setting

借助 libdrm 的强大 API 接口,如果内核支持 PRIME API ,也可以使用 PRIME 接口实现更为灵活的内存操作。

fb device

drm 驱动可以模拟一个 fb device, 默认是 default CRTC, 更多关于 fb device ,可以参考 内核 framebuffer 文档, fb device 是大多数 Linux 系统显示的基础。

  • The X Server, Linux 桌面系统的显示服务
  • Android gralloc, 安卓系统显示 HAL

本文讨论的问题是 drm 驱动是如何虚拟 drm crts 为 fb device

文章基于内核版本 linux-3.18

VERSION = 3
PATCHLEVEL = 18
SUBLEVEL = 0
EXTRAVERSION = -linux4sam_5.0-alpha7
NAME = Diseased Newt

drm 的代码位于:

drivers/gpu/drm/

1. 设备驱动创建 fbdev

drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c: dc->fbdev = drm_fbdev_cma_init(dev, 24,
drivers/gpu/drm/sti/sti_drm_drv.c: drm_fbdev_cma_init(dev, 32,
drivers/gpu/drm/tilcdc/tilcdc_drv.c: priv->fbdev = drm_fbdev_cma_init(dev, bpp,
drivers/gpu/drm/rcar-du/rcar_du_kms.c: fbdev = drm_fbdev_cma_init(dev, 32, dev->mode_config.num_crtc,

调用的是 drm_fbdev_cma_init

struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
unsigned int preferred_bpp, unsigned int num_crtc,
unsigned int max_conn_count)
{
struct drm_fbdev_cma *fbdev_cma;
struct drm_fb_helper *helper;
int ret;

fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL);

...
helper = &fbdev_cma->fb_helper;

drm_fb_helper_prepare(dev, helper, &drm_fb_cma_helper_funcs);

...
ret = drm_fb_helper_initial_config(helper, preferred_bpp);
    if (ret < 0) {
        dev_err(dev->dev, "Failed to set initial hw configuration.\n");
    goto err_drm_fb_helper_fini;
}

return fbdev_cma;

其中最重要的数据结构是 drm_fb_helper_funcs

static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
.fb_probe = drm_fbdev_cma_create,

};

2. 完成 fb 设备的创建:

static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
    struct drm_fb_helper_surface_size *sizes)
{
    struct drm_fbdev_cma *fbdev_cma = to_fbdev_cma(helper);
    struct drm_mode_fb_cmd2 mode_cmd = { 0 };
    struct drm_device *dev = helper->dev;
    struct drm_gem_cma_object *obj;
    struct drm_framebuffer *fb;
    unsigned int bytes_per_pixel;
    unsigned long offset;
    struct fb_info *fbi;
    size_t size;
    int ret;

    DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
            sizes->surface_width, sizes->surface_height,
            sizes->surface_bpp);

    bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);

    mode_cmd.width = sizes->surface_width;
    mode_cmd.height = sizes->surface_height;
    mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
    mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
        sizes->surface_depth);

    size = mode_cmd.pitches[0] * mode_cmd.height;
    obj = drm_gem_cma_create(dev, size);
    if (IS_ERR(obj))
        return -ENOMEM;

    fbi = framebuffer_alloc(0, dev->dev);
    if (!fbi) {
        dev_err(dev->dev, "Failed to allocate framebuffer info.\n");
        ret = -ENOMEM;
        goto err_drm_gem_cma_free_object;
    }

    fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1);
    if (IS_ERR(fbdev_cma->fb)) {
        dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
        ret = PTR_ERR(fbdev_cma->fb);
        goto err_framebuffer_release;
    }

    fb = &fbdev_cma->fb->fb;
    helper->fb = fb;
    helper->fbdev = fbi;

    fbi->par = helper;
    fbi->flags = FBINFO_FLAG_DEFAULT;
    fbi->fbops = &drm_fbdev_cma_ops;

    ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
    if (ret) {
        dev_err(dev->dev, "Failed to allocate color map.\n");
        goto err_drm_fb_cma_destroy;
    }

    drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
    drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);

    offset = fbi->var.xoffset * bytes_per_pixel;
    offset += fbi->var.yoffset * fb->pitches[0];

    dev->mode_config.fb_base = (resource_size_t)obj->paddr;
    fbi->screen_base = obj->vaddr + offset;
    fbi->fix.smem_start = (unsigned long)(obj->paddr + offset);
    fbi->screen_size = size;
    fbi->fix.smem_len = size;

    return 0;

err_drm_fb_cma_destroy:
    drm_framebuffer_unregister_private(fb);
    drm_fb_cma_destroy(fb);
err_framebuffer_release:
    framebuffer_release(fbi);
err_drm_gem_cma_free_object:
    drm_gem_cma_free_object(&obj->base);
    return ret;
}

流程图

Created with Raphaël 2.1.0 drm_fbdev_cma_init drm_fb_helper_initial_config drm_fb_helper_single_fb_probe register_framebuffer
<think>好的,我现在需要帮助用户解决在Linux环境下使用DRM和Qt进行开发或配置的问题。首先,我得回顾一下用户提供的引用内容,看看有没有相关的信息可以利用。 引用[1]提到了Linux内核的编译方法,特别是如何编译特定模块,比如驱动模块。这可能和DRM(Direct Rendering Manager)相关,因为DRMLinux内核中负责与显卡交互的子系统。用户可能需要配置或编译内核模块来支持DRM。 引用[2]涉及Qt的交叉编译和静态编译参数。用户可能需要在特定环境下配置Qt,可能与DRM结合使用,比如嵌入式系统或需要高性能图形渲染的场景。 引用[3]和[4]提到了音视频相关的库和工具,比如libva、ffmpeg的编译和配置。虽然用户现在的问题是关于DRM和Qt,但可能在多媒体处理方面有关联,比如使用Qt进行视频播放,需要DRM进行硬件加速。 接下来,我需要整理DRM和Qt结合开发的步骤。首先,确保内核支持DRM,可能需要编译相关模块。然后,配置Qt以支持DRM,可能需要使用特定的平台插件,比如eglfs或linuxfb。另外,用户可能需要处理图形渲染、多屏幕管理或硬件加速等问题。 需要注意用户可能的实际应用场景,比如嵌入式设备、kiosk系统或需要直接操作硬件的图形应用。可能需要指导如何配置Qt的环境变量,比如指定平台插件,或者处理权限问题,比如访问DRM设备需要用户组权限。 另外,交叉编译可能是一个需求,特别是如果用户的目标平台与开发环境不同,比如ARM架构的嵌入式设备。需要参考引用[2]中的Qt交叉编译步骤,结合DRM的配置。 最后,生成相关问题,帮助用户进一步探索可能遇到的挑战,比如调试方法、多屏支持、性能优化等。</think>### Linux环境下DRM与Qt开发配置指南 #### 一、内核DRM配置 1. **验证DRM驱动状态** 执行`dmesg | grep -i drm`查看内核加载的DRM驱动模块 $$ lsmod | grep drm $$ 典型输出示例:`drm_kms_helper`, `drm`, `i915`(Intel显卡) 2. **编译特定DRM模块**(参考引用[1]) ```bash cd /usr/src/linux make drivers/gpu/drm/i915/ # 编译Intel显卡驱动模块 make M=drivers/gpu/drm # 编译整个DRM子系统 ``` #### 二、Qt环境配置 1. **编译Qt时启用DRM支持**(参考引用[2]) 在Qt配置参数中添加: ```bash -device linux-rasp-pi4-v3d-g++ \ -eglfs \ -kms \ -opengl es2 ``` 需确认OpenGL ES和libdrm开发包已安装: $$ sudo apt-get install libgl1-mesa-dev libdrm-dev $$ 2. **环境变量配置**(参考引用[3]) ```bash export QT_QPA_PLATFORM=eglfs # 使用EGLFS平台插件 export QT_QPA_EGLFS_INTEGRATION=eglfs_kms # 启用KMS后端 export QT_LOGGING_RULES=qt.qpa.*=true # 启用Qt平台诊断日志 ``` #### 三、开发关键接口 1. **DRM API基础操作** ```c int fd = open("/dev/dri/card0", O_RDWR); drmModeRes *res = drmModeGetResources(fd); drmModeCrtcPtr crtc = drmModeGetCrtc(fd, res->crtcs[0]); ``` 2. **Qt与DRM交互** 使用`QScreen`类获取显示参数: ```cpp QList<QScreen*> screens = QGuiApplication::screens(); for(QScreen* screen : screens) { qDebug() << "Display geometry:" << screen->geometry(); } ``` #### 四、典型应用场景配置 **嵌入式显示系统示例**: 1. 创建`/etc/xdg/qt5/qt-env.sh`: ```bash export QT_QPA_PLATFORM=eglfs export QT_QPA_EGLFS_KMS_CONFIG=/etc/drm.conf export QT_QPA_EGLFS_ALWAYS_SET_MODE=1 ``` 2. DRM配置文件示例: ```json { "device": "/dev/dri/card0", "hwcursor": true, "pbuffers": true } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无才顽石

如果文章对你有用,请我喝瓶水吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值