Linux drm_syncobj機(jī)制原理與應(yīng)用方式
1. 概念
1.1 什么是 drm_syncobj
DRM Sync Object(同步對(duì)象,簡(jiǎn)稱 syncobj)是 Linux DRM(Direct Rendering Manager)子系統(tǒng)中用于 GPU 命令同步的內(nèi)核抽象。
syncobj 的設(shè)計(jì)初衷是為用戶空間提供一種高效、靈活的 GPU 任務(wù)同步原語(yǔ),主要用于顯卡驅(qū)動(dòng)和用戶空間(如 Vulkan、OpenCL、OpenGL 等)之間的同步需求。
syncobj 的核心作用是包裝一個(gè)指向 dma_fence 結(jié)構(gòu)體的指針(可能為 NULL),通過(guò) ioctl 接口,用戶空間可以創(chuàng)建、銷毀、導(dǎo)入、導(dǎo)出、信號(hào)、重置、等待等操作 syncobj,從而實(shí)現(xiàn) GPU 命令流的精細(xì)同步。
1.2 設(shè)計(jì)目標(biāo)
- 跨進(jìn)程/跨驅(qū)動(dòng)共享:syncobj 可通過(guò) fd 句柄在進(jìn)程間傳遞,實(shí)現(xiàn)多進(jìn)程/多驅(qū)動(dòng)同步。
- 支持二元與時(shí)間線語(yǔ)義:既可作為簡(jiǎn)單的“signaled/unsignal”二元同步原語(yǔ),也可作為時(shí)間線(timeline)同步原語(yǔ),支持多點(diǎn)同步。
- 高效用戶空間接口:通過(guò)一組 ioctl,用戶空間可靈活操作 syncobj,滿足 Vulkan 等現(xiàn)代圖形 API 的同步需求。
drm_syncobj是為用戶空間設(shè)計(jì)的,因此內(nèi)核自身不會(huì)使用該結(jié)構(gòu)體,只有各家的GPU驅(qū)動(dòng)才會(huì)使用。
1.3 主要數(shù)據(jù)結(jié)構(gòu)
| 結(jié)構(gòu)體名稱 | 作用說(shuō)明 |
|---|---|
| struct drm_syncobj | 同步對(duì)象的核心結(jié)構(gòu),包含 fence 指針、回調(diào)鏈表、事件鏈表、鎖等。 |
| struct dma_fence | 底層同步原語(yǔ),表示 GPU 命令完成的信號(hào)。 |
| struct dma_fence_chain | 時(shí)間線模式下的鏈?zhǔn)?fence,支持多點(diǎn)同步。 |
| struct syncobj_wait_entry | 用于等待的輔助結(jié)構(gòu)。 |
| struct syncobj_eventfd_entry | 用于事件通知的輔助結(jié)構(gòu)。 |
2. 原理分析
2.1 同步機(jī)制原理
2.1.1 二元同步對(duì)象
在二元模式下,syncobj 通過(guò)維護(hù)一個(gè)可替換的 fence 指針實(shí)現(xiàn)同步狀態(tài)管理。
該設(shè)計(jì)充分利用了 dma_fence 的單向狀態(tài)特性(不可逆的"已信號(hào)"狀態(tài),dma_fence的單向狀態(tài)轉(zhuǎn)換決定了的單個(gè)dma_fence是短命的),通過(guò)動(dòng)態(tài)創(chuàng)建并替換 fence 對(duì)象實(shí)現(xiàn)狀態(tài)重置。
- 信號(hào)操作:驅(qū)動(dòng)創(chuàng)建新的已信號(hào)
dma_fence替換原對(duì)象。 - 重置操作:驅(qū)動(dòng)創(chuàng)建新的未信號(hào)
dma_fence替換原對(duì)象。
2.1.2 時(shí)間線同步對(duì)象
- 時(shí)間線模式下,syncobj 維護(hù)一個(gè)
dma_fence_chain,每個(gè)鏈節(jié)點(diǎn)代表一個(gè)時(shí)間點(diǎn)(seqno)。 - GPU 驅(qū)動(dòng)可在任意時(shí)間點(diǎn)插入新的 fence,實(shí)現(xiàn)多點(diǎn)同步。
- 用戶空間可針對(duì)任意時(shí)間點(diǎn)進(jìn)行信號(hào)、等待、查詢等操作。
2.1.3 等待機(jī)制
- 主機(jī)側(cè)等待:通過(guò)
DRM_IOCTL_SYNCOBJ_WAIT或DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT,用戶空間可等待一個(gè)或多個(gè) syncobj 的 fence 被信號(hào)。支持等待全部或任意一個(gè)、超時(shí)、deadline、等待 fence 出現(xiàn)等多種模式。 - 事件通知:通過(guò) eventfd 機(jī)制,用戶空間可注冊(cè)事件,當(dāng) syncobj 被信號(hào)時(shí),eventfd 被喚醒,便于集成到事件循環(huán)。
2.1.4 導(dǎo)入/導(dǎo)出機(jī)制
- fd 句柄導(dǎo)入/導(dǎo)出:syncobj 可導(dǎo)出為 fd,在進(jìn)程間傳遞,所有 fd 共享同一個(gè)底層 syncobj。
- sync_file 導(dǎo)入/導(dǎo)出:可將 syncobj 當(dāng)前 fence 導(dǎo)出為 sync_file,或從 sync_file 導(dǎo)入 fence 到 syncobj。sync_file 是 Linux 通用的同步文件描述符,便于與其他子系統(tǒng)(如 dma-buf)集成。
2.2 典型流程
- 用戶空間通過(guò) ioctl 創(chuàng)建 syncobj,獲得 handle 或 fd。
- GPU 驅(qū)動(dòng)在提交命令時(shí),將 fence 綁定到 syncobj。
- a. 用戶空間可通過(guò) ioctl 等待 syncobj 被信號(hào),或查詢其狀態(tài)。b. GPU執(zhí)行完命令后,發(fā)中斷,中斷處理中singal syncobj。a和b兩個(gè)過(guò)程是同時(shí)進(jìn)行的,看哪個(gè)先完成。
- syncobj 可在進(jìn)程間傳遞,實(shí)現(xiàn)跨進(jìn)程同步。
- 時(shí)間線模式下,用戶空間和驅(qū)動(dòng)可在任意時(shí)間點(diǎn)操作 syncobj,實(shí)現(xiàn)復(fù)雜同步場(chǎng)景。
這個(gè)典型使用流程是理解syncobj的關(guān)鍵,記住一點(diǎn):syncobj是用戶空間使用的。
3. 實(shí)現(xiàn)
syncobj 支持如下基本操作:
| 操作類型 | 說(shuō)明 |
|---|---|
| 創(chuàng)建與銷毀 | 分配和釋放同步對(duì)象資源 |
| 信號(hào)與重置 | 設(shè)置同步對(duì)象為已完成或未完成狀態(tài) |
| 等待 | 阻塞或非阻塞地等待同步對(duì)象變?yōu)橐淹瓿蔂顟B(tài) |
| 導(dǎo)入與導(dǎo)出 | 將同步對(duì)象的狀態(tài)在進(jìn)程間傳遞,實(shí)現(xiàn)跨進(jìn)程同步 |
| timeline 操作 | 部分驅(qū)動(dòng)支持 timeline syncobj,可以表示多個(gè)時(shí)間點(diǎn)的同步狀態(tài) |
3.1 接口分類和功能
| 分類 | 主要接口/函數(shù)名 | 功能說(shuō)明 |
|---|---|---|
| 創(chuàng)建與銷毀 | drm_syncobj_create | 分配并初始化 syncobj,支持初始信號(hào)狀態(tài)(SIGNALED) |
| drm_syncobj_destroy | 釋放 syncobj,清理所有引用和資源 | |
| 導(dǎo)入與導(dǎo)出 | drm_syncobj_get_handle / drm_syncobj_get_fd | 將 syncobj 導(dǎo)出為 handle 或 fd |
| drm_syncobj_handle_to_fd / drm_syncobj_fd_to_handle | fd 與 handle 互轉(zhuǎn),支持跨進(jìn)程共享 | |
| drm_syncobj_import_sync_file_fence / drm_syncobj_export_sync_file | 與 sync_file 互操作,便于與 dma-buf 等子系統(tǒng)集成 | |
| 信號(hào)與重置 | drm_syncobj_replace_fence | 替換 syncobj 的 fence,實(shí)現(xiàn)信號(hào)或重置 |
| drm_syncobj_assign_null_handle | 分配一個(gè)已信號(hào)的 stub fence,實(shí)現(xiàn)“信號(hào)”操作 | |
| drm_syncobj_signal_ioctl / drm_syncobj_reset_ioctl | 用戶空間 ioctl 接口,批量信號(hào)或重置 syncobj | |
| 時(shí)間線操作 | drm_syncobj_add_point | 在時(shí)間線 syncobj 上添加新的時(shí)間點(diǎn)(fence_chain) |
| drm_syncobj_transfer_to_timeline / drm_syncobj_transfer_to_binary | 在不同 syncobj 間轉(zhuǎn)移時(shí)間點(diǎn)或 fence,實(shí)現(xiàn)復(fù)雜同步場(chǎng)景 | |
| drm_syncobj_timeline_signal_ioctl | 用戶空間 ioctl,批量信號(hào)時(shí)間線上的多個(gè)點(diǎn) | |
| drm_syncobj_query_ioctl | 查詢時(shí)間線 syncobj 的狀態(tài),支持查詢最后提交點(diǎn)或最后信號(hào)點(diǎn) | |
| 等待與事件通知 | drm_syncobj_array_wait_timeout | 核心等待實(shí)現(xiàn),支持多種等待模式(全部、任意、超時(shí)、deadline等) |
| drm_syncobj_eventfd_ioctl | 注冊(cè) eventfd,當(dāng) syncobj 被信號(hào)時(shí)喚醒用戶空間 | |
| dma_fence_add_callback | fence 信號(hào)時(shí)的喚醒和事件通知回調(diào)機(jī)制 | |
| 內(nèi)存與引用管理 | kref 引用計(jì)數(shù)機(jī)制 | syncobj 通過(guò)引用計(jì)數(shù)管理生命周期,確保多進(jìn)程/多 fd 安全 |
| 嚴(yán)格引用管理 | 所有導(dǎo)入/導(dǎo)出、等待、事件等操作均嚴(yán)格管理引用,防止資源泄漏 |
3.2 關(guān)鍵代碼分析
這部分專門出一篇博文介紹,還在編寫中....
4. 為什么設(shè)計(jì) drm_syncobj
下面是 drm_syncobj 與 dma_resv、sync_file 的對(duì)比分析,并說(shuō)明 drm_syncobj 的設(shè)計(jì)初衷和優(yōu)勢(shì)。
| 對(duì)比項(xiàng) | dma_resv(內(nèi)核使用) | sync_file | drm_syncobj(設(shè)計(jì)初衷與優(yōu)勢(shì)) |
|---|---|---|---|
| 主要用途 | 內(nèi)核對(duì)象,管理 dma-buf 的同步(讀/寫 fence) | 用戶空間同步文件,導(dǎo)出/傳遞 fence | 用戶空間可管理的同步對(duì)象,專為 GPU/Vulkan 設(shè)計(jì) |
| 用戶空間接口 | 無(wú)直接接口,驅(qū)動(dòng)內(nèi)部使用 | 通過(guò) fd 傳遞,支持 epoll/select | 豐富 ioctl 接口,支持創(chuàng)建、導(dǎo)入、導(dǎo)出、信號(hào)、等待 |
| 跨進(jìn)程/驅(qū)動(dòng) | 僅限 dma-buf 相關(guān)驅(qū)動(dòng)間 | 可跨進(jìn)程傳遞,但只封裝單個(gè) fence | 可跨進(jìn)程/驅(qū)動(dòng)共享,支持 timeline 多點(diǎn)同步 |
| 時(shí)間線支持 | 不支持,只有讀/寫二元 fence | 不支持,單一 fence | 支持 timeline fence_chain,滿足 Vulkan timeline |
| 事件通知 | 無(wú) | 支持 eventfd | 支持 eventfd,且可針對(duì) timeline 任意點(diǎn) |
| 資源管理 | 內(nèi)核自動(dòng)管理 | 用戶空間 fd 管理,生命周期與 fd 綁定 | 引用計(jì)數(shù)(kref),fd/handle均可安全管理 |
| 設(shè)計(jì)初衷 | dma-buf 內(nèi)核同步,面向驅(qū)動(dòng)開(kāi)發(fā) | 通用 fence 導(dǎo)出/傳遞,面向用戶空間 | 面向 GPU/Vulkan 用戶空間同步,靈活高效 |
| 典型應(yīng)用場(chǎng)景 | 顯存緩沖區(qū)同步,驅(qū)動(dòng)內(nèi)部 | 用戶空間異步等待、跨進(jìn)程同步 | Vulkan fence/semaphore、跨進(jìn)程/驅(qū)動(dòng) GPU 協(xié)作 |
- 滿足現(xiàn)代圖形 API(如 Vulkan)的同步需求:Vulkan 需要 timeline semaphore、跨進(jìn)程/驅(qū)動(dòng)同步、事件通知等高級(jí)功能,dma_resv/sync_file 無(wú)法滿足。
- 用戶空間可控:drm_syncobj 提供豐富的 ioctl 接口,用戶空間可靈活創(chuàng)建、管理、導(dǎo)入、導(dǎo)出、等待、信號(hào)同步對(duì)象。
- 支持 timeline fence:drm_syncobj 支持多點(diǎn)同步,適配 Vulkan timeline semaphore,遠(yuǎn)超 sync_file 的單點(diǎn)能力。
- 跨進(jìn)程/驅(qū)動(dòng)協(xié)作:通過(guò) fd/handle 機(jī)制,drm_syncobj 可在多進(jìn)程、多驅(qū)動(dòng)間安全共享和同步。
- 高效事件通知:集成 eventfd,便于用戶空間異步編程和事件循環(huán)。
drm_syncobj 是為現(xiàn)代 GPU 用戶空間同步場(chǎng)景量身定制的內(nèi)核抽象,彌補(bǔ)了 dma_resv/sync_file 在靈活性、擴(kuò)展性和用戶空間接口上的不足。
用戶態(tài)的應(yīng)用接口封裝在libdrm中,具體實(shí)現(xiàn)分析見(jiàn):Linux libdrm 中 drm_syncobj的實(shí)現(xiàn)原理。這兩篇對(duì)照著看,基本上是一一對(duì)應(yīng)。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
linux之SSH連接WSL2本地環(huán)境的操作方式
這篇文章主要介紹了linux之SSH連接WSL2本地環(huán)境的操作方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-05-05
Ubuntu18.04一次性升級(jí)Python所有庫(kù)的方法步驟
這篇文章主要介紹了Ubuntu18.04一次性升級(jí)Python所有庫(kù)的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
如何利用多核CPU來(lái)加速你的Linux命令(GNU Parallel)
這篇文章主要介紹了如何利用多核CPU來(lái)加速你的Linux命令(GNU Parallel),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
Apache SeaTunnel 集群部署超詳細(xì)教程
SeaTunnel Engine 的Master服務(wù)和Worker服務(wù)分離,每個(gè)服務(wù)單獨(dú)一個(gè)進(jìn)程,這篇文章主要介紹了Apache SeaTunnel 集群部署詳細(xì)教程,需要的朋友可以參考下2024-12-12
Linux系統(tǒng)下使用rpm方式安裝最新mysql5.7.17完整步驟
這篇文章主要介紹了Linux系統(tǒng)下使用rpm方式安裝最新mysql5.7.17完整步驟,需要的朋友可以參考下2017-01-01

