DRM DUMB相关说明

RK平台drm缓冲区申请与转换详解

概述

笔者在涉及RK平台中如下链路时,对drm申请的buffer相关字段有些疑惑。因此写此贴作为一个记录。

mppdec解码 --> rga缩放 --> drm显示

流程解析

如下接口是申请drm类型的dumb。首先需要传入的fd是设备的文件句柄,比如/dev/dri/card0。随后通过drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg)申请到一个DUMB的内存块,此时出现了handle,随后又通过drmPrimeHandleToFD获取到一个fd(对应buff_fd)。

static struct bo_new *
bo_create_dumb(int fd, unsigned int width, unsigned int height, unsigned int bpp)
{
    struct drm_mode_create_dumb arg;
    struct bo_new *bo;
    int ret;

    bo = calloc(1, sizeof(*bo));
    if (bo == NULL) {
        fprintf(stderr, "failed to allocate buffer object\n");
        return NULL;
    }

    memset(&arg, 0, sizeof(arg));
    arg.bpp = bpp;
    arg.width = width;
    arg.height = height;

    ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
    if (ret) {
        fprintf(stderr, "failed to create dumb buffer: %s\n",
            strerror(errno));
        free(bo);
        return NULL;
    }

    bo->fd = fd;
    bo->handle = arg.handle;
    bo->size = arg.size;
    bo->pitch = arg.pitch;

    drmPrimeHandleToFD(fd, arg.handle, 0, &bo->buff_fd);

    return bo;
}

上述函数执行完毕,我们获取到drm buff的一个handle和一个fd。但是在该drm buff送往drm显示时,还需要再进行一次转换(通过接口drmModeAddFB2 ),需要获取一个fb(对应代码fb_id)。

  kmsmem = calloc(sizeof(KMSMEM), 1);
  kmsmem->bo = bo_create(self->fd, vinfo->format,
                   vinfo->width, vinfo->height,
                   handles, pitches,
                   offsets, UTIL_PATTERN_TILES);

  printf("bo handles: %d, %d, %d, %d, ptr %p\n", handles[0],
      handles[1], handles[2], handles[3], kmsmem->bo->ptr);

  ret = drmModeAddFB2 (self->fd, vinfo->width, vinfo->height,
                        vinfo->format, handles, pitches,
                        offsets, &kmsmem->fb_id, 0);

在drm送显时,则是传入上文提到的fb,比如如下代码中的fb_id

  ret = drmModeSetPlane (self->fd, self->plane_id, self->crtc_id, fb_id, 0,
      result.x, result.y, result.w, result.h,
      /* source/cropping coordinates are given in Q16 */
      src.x << 16, src.y << 16, src.w << 16, src.h << 16);

总结

上文中涉及drm buff的三个变量:handle,fd,fb;我的理解如下:

  • handle:驱动层的标识符,因此通过drmIoctl像驱动获取到的标识符便为handle形式。
  • fd:用户层的标识符,用户可通过该fd,对buffer进行map处理。在rga处理时,可直接使用drm buff的fd作为接口入参。
    // rk扩展ffmpeg解码器时自定义的结构。代码中的fd就是drmbuff的fd。
    drm_fram_desc = (AVDRMFrameDescriptor*)frame->data[0];
    memset(&src_info, 0, sizeof(rga_info_t));
    src_info.fd = drm_fram_desc->objects[0].fd;
    src_info.mmuFlag = 1;

    // 目标为新申请的drm buff的fd,rga缩放后,新的图像存放此处。
    memset(&dst_info, 0, sizeof(rga_info_t));
    dst_info.fd = buffer->bo->buff_fd;
    dst_info.mmuFlag = 1;

    /********** set the rect_info **********/
    rga_set_rect(&src_info.rect, 0, 0, srcWidth, srcHeight, srcWidth/*stride*/, srcHeight, srcFormat);
    rga_set_rect(&dst_info.rect, 0, 0, dstWidth, dstHeight, dstWidth/*stride*/, dstHeight, dstFormat);
    src_info.rotation = rotate;

    ret = c_RkRgaBlit(&src_info, &dst_info, NULL);
    if (ret) {
        av_log(NULL, AV_LOG_FATAL, "rk rga split func failed!\n");
        return;
    }
  • fb:我理解为framebuff的标识符,用于额外封装drm buff为framebuff结构,然后才能通过drm接口送显。之所以封装,是因为framebuff额外提供了当前buff的宽高等信息。
`DRM_IOCTL_MODE_CREATE_DUMB` 是 Linux DRM(Direct Rendering Manager)子系统中的一个 IOCTL 命令,用于创建一个“哑”(dumb)内存缓冲区(framebuffer buffer),常用于简单的显示操作,比如在用户空间直接分配一块显存用于显示。 --- ### 📌 功能说明: `DRM_IOCTL_MODE_CREATE_DUMB` 的作用是: - 在设备内存中分配一块未经过复杂处理的缓冲区(称为“dumb buffer”)。 - 返回该缓冲区的句柄(handle)、大小(size)和步长(pitch,即每行的字节数)。 - 该缓冲区可以被映射到用户空间进行读写,常用于简单的帧缓冲绘图。 --- ### 📦 使用场景: - 快速原型开发或调试时创建简单的帧缓冲。 - 不需要 GPU 加速或复杂内存管理的显示操作。 - 配合 `DRM_IOCTL_MODE_MAP_DUMB` 将缓冲区映射到用户空间进行直接访问。 --- ### 📚 IOCTL 命令定义(简化): ```c DRM_IOCTL_MODE_CREATE_DUMB ``` 它通常使用结构体 `drm_mode_create_dumb` 作为参数传递给内核: ```c struct drm_mode_create_dumb { uint32_t height; uint32_t width; uint32_t bpp; // bits per pixel uint32_t flags; // unused, for future use uint64_t handle; // 返回的 buffer handle uint64_t pitch; // 每行的字节数 uint64_t size; // 缓冲区总大小 }; ``` --- ### 🧪 使用示例(C语言): ```c #include <xf86drm.h> #include <xf86drmMode.h> int fd = open("/dev/dri/card0", O_RDWR); struct drm_mode_create_dumb create = {}; create.width = 1024; create.height = 768; create.bpp = 32; ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); printf("Handle: %u\n", create.handle); printf("Pitch: %lu\n", create.pitch); printf("Size: %lu\n", create.size); ``` --- ### 🔁 后续操作: 创建完 dumb buffer 后,通常还需要以下步骤来使用它: 1. **映射缓冲区到用户空间**: ```c struct drm_mode_map_dumb map = {}; map.handle = create.handle; ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map); void *map_addr = mmap(0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset); ``` 2. **写入图像数据到 `map_addr`**。 3. **绑定 buffer 到 CRTC 或 Plane**,用于显示。 --- ### ✅ 优点: - 使用简单,适合快速创建帧缓冲。 - 不需要 GPU 驱动支持复杂的内存管理。 - 可直接映射并操作内存。 --- ### ❌ 缺点: - 不适用于高性能图形渲染(如 OpenGL、Vulkan)。 - 数据在 CPU 和 GPU 之间传输效率低。 - 不支持复杂的内存布局(如 tiling、compression)。 --- ###
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值