当前位置: 代码网 > 服务器>服务器>Linux > Linux libdrm中drm_syncobj的实现原理

Linux libdrm中drm_syncobj的实现原理

2025年09月22日 Linux 我要评论
1. 前言在博文:linux drm_syncobj 机制原理与应用中介绍了内核drm_syncobj机制的相关原理,本篇是用户态libdrm中的syncobj的api实现分析。syncobj 的设计

1. 前言

在博文:linux drm_syncobj 机制原理与应用中介绍了内核drm_syncobj机制的相关原理,本篇是用户态libdrm中的syncobj的api实现分析。

syncobj 的设计初衷是为用户空间提供一种高效、灵活的 gpu 任务同步原语。

它具备如下特点:

  • 对象化管理:同步状态以对象(syncobj)形式存在,用户空间可通过句柄引用和操作。
  • 多次信号/等待:支持多次信号和等待,适合异步和多阶段任务。
  • 跨进程同步:支持同步对象的导入/导出,实现进程间同步。
  • timeline 扩展:部分驱动支持 timeline syncobj,可表示多个时间点的同步状态。

传统 fence 仅能表示单次同步事件,且生命周期受限。而 syncobj 支持多次信号/等待,且可导入/导出,适合复杂的同步场景。timeline syncobj 更是将同步扩展到多时间点,极大提升了灵活性。

2. syncobj 相关 ioctls概览与典型流程

syncobj 的所有操作都通过 ioctl 与内核 drm 驱动交互。

和内核实现一文中的维度划分保持一致,把ioctl划分如下。

维度ioctl 名称功能描述
创建与销毁drm_ioctl_syncobj_create创建同步对象,分配资源并返回句柄
drm_ioctl_syncobj_destroy销毁同步对象,释放资源
导入与导出drm_ioctl_syncobj_handle_to_fd将同步对象句柄导出为文件描述符,实现跨进程同步
drm_ioctl_syncobj_fd_to_handle从文件描述符导入同步对象句柄,实现跨进程同步
信号与重置drm_ioctl_syncobj_signal将同步对象设为已完成(signaled)状态
drm_ioctl_syncobj_reset将同步对象设为未完成(unsignaled)状态
时间线操作drm_ioctl_syncobj_timeline_signal对 timeline syncobj 的指定时间点进行信号
drm_ioctl_syncobj_timeline_wait等待 timeline syncobj 的指定时间点完成
drm_ioctl_syncobj_timeline_query查询 timeline syncobj 当前时间点状态
等待与事件通知drm_ioctl_syncobj_wait等待同步对象变为已完成状态,支持阻塞/非阻塞及超时
drm_ioctl_syncobj_query查询同步对象的当前状态

典型流程:

  • 创建 syncobj:通过 drmsyncobjcreate 创建同步对象,获得句柄。将该句柄随任务传递给内核驱动。
  • 导入/导出:如需跨进程同步,通过 drmsyncobjhandletofd 和 drmsyncobjfdtohandle 实现句柄与 fd 的转换。
  • 信号/重置:根据任务完成情况,调用 drmsyncobjsignal 或 drmsyncobjreset 设置同步对象状态。
  • timeline 操作:如需多时间点同步,使用 timeline 相关 api 进行信号、等待和查询。
  • 等待/通知:通过 drmsyncobjwait 或 drmsyncobjtimelinewait 等待任务完成(任务完成后,会signal该任务关联的步骤1的同步对象),驱动后续处理。
  • 销毁:任务完成后,调用 drmsyncobjdestroy 释放资源。

3. 创建与销毁

3.1 创建同步对象

3.1.1 drm_ioctl_syncobj_create

该 ioctl 用于在内核中分配一个同步对象,并返回其句柄。

用户空间通过 libdrm 的 drmsyncobjcreate api 调用。

  • 支持普通 syncobj 和 timeline syncobj 创建
  • 句柄在用户空间唯一标识同步对象
  • 可指定初始状态(已信号/未信号)
drm_public int drmsyncobjcreate(int fd, uint32_t flags, uint32_t *handle)
{
    struct drm_syncobj_create args;
    int ret;

    memclear(args);
    args.flags = flags;
    args.handle = 0;
    ret = drmioctl(fd, drm_ioctl_syncobj_create, &args);
    if (ret)
        return ret;
    *handle = args.handle;
    return 0;
}
  • fd:打开的drm 设备文件描述符
  • flags:可选标志,如 drm_syncobj_create_signaled(初始为已信号状态)、drm_syncobj_create_timeline(创建 timeline syncobj)
  • handle:返回的同步对象句柄

3.2 销毁同步对象

3.2.1 drm_ioctl_syncobj_destroy

该 ioctl 用于释放同步对象资源。libdrm 封装为 drmsyncobjdestroy

drm_public int drmsyncobjdestroy(int fd, uint32_t handle)
{
    struct drm_syncobj_destroy args;

    memclear(args);
    args.handle = handle;
    return drmioctl(fd, drm_ioctl_syncobj_destroy, &args);
}
  • fd:drm 设备文件描述符
  • handle:要销毁的同步对象句柄

后续的api我不再给出具体实现,感兴趣的朋友请查看源码。

4. 导入与导出

4.1 导出同步对象到文件描述符

4.1.1 drm_ioctl_syncobj_handle_to_fd

该 ioctl 用于将 syncobj 句柄导出为文件描述符,实现跨进程同步。

libdrm 封装为 drmsyncobjhandletofd

int drmsyncobjhandletofd(int fd, uint32_t handle, int *out_fd);

4.2 从文件描述符导入同步对象

4.2.1 drm_ioctl_syncobj_fd_to_handle

该 ioctl 用于将文件描述符导入为 syncobj 句柄。

libdrm 封装为 drmsyncobjfdtohandle

drmsyncobjfdtohandle(fd, syncobj_fd, &imported_handle);

5. 信号与重置

5.1 信号同步对象

5.1.1 drm_ioctl_syncobj_signal

该 ioctl 用于将同步对象设为已完成(signaled)状态。

libdrm 封装为 drmsyncobjsignal

int drmsyncobjsignal(int fd, const uint32_t *handles, uint32_t count);

5.2 重置同步对象

5.2.1 drm_ioctl_syncobj_reset

该 ioctl 用于将同步对象设为未完成(unsignaled)状态。

libdrm 封装为 drmsyncobjreset

int drmsyncobjreset(int fd, const uint32_t *handles, uint32_t count);

6. 时间线操作

这个高级用法,我还没有在项目中用到过,有用例的朋友欢迎分享。

6.1 timeline syncobj 简介

timeline syncobj 是对传统同步对象的扩展,允许一个 syncobj 维护多个时间点(value),每个 value 都可单独信号和等待。

适用于多帧渲染、批量任务调度等复杂场景。

6.2 timeline 信号

6.2.1 drm_ioctl_syncobj_timeline_signal

该 ioctl 用于对 timeline syncobj 的指定时间点进行信号。

libdrm 封装为 drmsyncobjtimelinesignal

int drmsyncobjtimelinesignal(int fd, const uint32_t *handles,
                       const uint64_t *points, uint32_t count);
  • fd:drm 设备文件描述符
  • handles:syncobj 句柄数组
  • points:对应时间点数组
  • count:数量

6.3 timeline 等待

6.3.1 drm_ioctl_syncobj_timeline_wait

该 ioctl 用于等待 timeline syncobj 的指定时间点完成。

libdrm 封装为 drmsyncobjtimelinewait

int drmsyncobjtimelinewait(int fd, const uint32_t *handles,
                           const uint64_t *points, uint32_t count,
                           uint64_t timeout_nsec, uint32_t flags,
                           uint32_t *first_signaled);
  • fd:drm 设备文件描述符
  • handles:syncobj 句柄数组
  • points:对应时间点数组
  • count:数量
  • timeout_nsec:超时时间(纳秒)
  • flags:等待标志
  • first_signaled:返回第一个完成的 syncobj 索引

等待与事件通知

7.1 普通等待

7.1.1 drm_ioctl_syncobj_wait

该 ioctl 用于等待普通 syncobj 变为已完成状态。

libdrm 封装为 drmsyncobjwait

  • 支持阻塞和非阻塞等待
  • 可批量等待多个同步对象
int drmsyncobjwait(int fd, const uint32_t *handles, 
                uint32_t count, uint64_t timeout_nsec,
                uint32_t flags, uint32_t *first_signaled);
  • fd:drm 设备文件描述符
  • handles:syncobj 句柄数组
  • count:数量
  • timeout_nsec:超时时间
  • flags:等待标志(如阻塞/非阻塞)
  • first_signaled:返回第一个完成的 syncobj 索引

8. 应用示例

应用场景:要使用dma引擎给一个大buffer填充数据,即buffer填充任务;然后把该buffer交给gpu的渲染任务,渲染任务要等待填充任务完成后在进行。

填充任务的执行是一个dma引擎设备;渲染任务的执行是一个gpu设备。cpu负责给这两个设备发送任务和数据。涉及到跨设备、跨驱动的异步操作的同步问题。

该场景的实现代码如下。

  • 用户态:
uint32_t dma_syncobj;

//创建drm_syncobj对象,获取句柄
drmsyncobjcreate(fd, flags, &dma_syncobj);
//将句柄随transfer任务传递给内核
dma_transfer(bo, size, data, dma_syncobj);

//其他准备工作
.....

//等待transfer的任务完成,即dma_syncobj同步对象被signal
drmsyncobjwait(fd, &dma_syncobj, 1, ...);

submit_render_jobs(fd, jobs);
  • 内核驱动:
do_dma_transfer(bo, size, data, dma_syncobj)
{
    //使用dma引擎传输数据到bo
    dma_transfer(bo, size, data);

    //signal dma_syncobj同步对象
    drm_syncobj_replace_fence(syn_obj, signaled_fence);
}

9. 总结

drm_syncobj 作为 libdrm 用户空间的同步对象抽象,通过一系列 drm_ioctl_syncobj_* ioctl,为开发者提供了高效、灵活的 gpu 任务同步机制。其支持创建与销毁、导入与导出、信号与重置、时间线操作、等待与事件通知等多种操作,适用于多队列渲染、跨进程同步、异步任务调度等多种应用场景。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com