世界を動かす技術を、日本語で。

RustによるGPUカーネルドライバの作成:GPUドライバの仕組みに関する簡単な紹介

概要

  • Tyr はRust製の最新Linuxカーネル向けGPUドライバで、Arm Mali CSFベースGPUに対応
  • 本記事では GPUドライバの仕組み を、Vulkanアプリ「VkCube」を例に解説
  • UMD(ユーザーモードドライバ)KMD(カーネルモードドライバ) の役割分担を整理
  • Tyrが提供する APIインターフェース を紹介
  • 次回は CSFアーキテクチャ 詳細に進む予定

Tyr開発記 第2回: VkCubeを通じて学ぶGPUドライバの仕組み

  • Tyr は、Rustで書かれたLinuxカーネル向けの 最先端GPUドライバ
  • Arm Mali CSFベースGPU をサポート
  • シリーズ第2回として、 GPUドライバの動作原理 を解説
  • VkCube はVulkan APIを使い、画面上に回転するキューブを描画するシンプルなアプリケーション
    • 学習用途に最適な題材

UMD(ユーザーモードドライバ)とKMD(カーネルモードドライバ)の役割

  • UMD :API(Vulkan, OpenGL, OpenCL等)を実装し、アプリケーションからの要求をGPU向けコマンドに変換
    • 例:MesaのVulkanドライバ panvk
  • KMD :GPUとの直接通信を担う特権層
    • 例:Linuxカーネルに統合を目指す Tyr
  • KMD はUMDからのコマンドを受け、実際に GPUハードウェア制御 を行う
  • UMDは描画データ(ジオメトリ・テクスチャ・シェーダ等)を管理し、 KMDにGPUメモリ割当やコマンド送信 を依頼
  • 描画結果取得や通知、リソース管理も重要な責務

VkCubeのワークフロー概要

  • UMD がVkCubeの描画命令を VkCommandBuffers として構築
  • 必要なデータ(ジオメトリ、色、回転行列等)とシェーダプログラムを GPUメモリに配置
  • KMDに対し「描画開始」「状態設定」「完了通知」「結果格納先メモリ確保」等を要求
  • 並列実行・非同期完了 に対応するため、依存関係やスケジューリングもKMDの役割
  • デバイス初期化複数アプリ間の公平な資源割当 もKMDの仕事

GPUドライバの複雑性

  • 複雑さの大半はUMD側 に集中
    • 高水準API命令をGPU向け低水準命令へ変換
  • KMD は、UMDが実装可能なように 必要最低限の操作を提供
    • 複数タスク間でGPU資源を公平に割り当て

TyrのAPIインターフェース

  • Tyr(Panthor互換)が提供する 主なAPI一覧

    • DRM_PANTHOR_DEV_QUERY :デバイス情報取得
    • DRM_PANTHOR_VM_CREATE/DESTROY/BIND/GET_STATE :仮想メモリ管理
    • DRM_PANTHOR_BO_CREATE/BO_MMAP_OFFSET :バッファオブジェクト管理
    • DRM_PANTHOR_GROUP_CREATE/DESTROY/GET_STATE :スケジューリンググループ管理
    • DRM_PANTHOR_GROUP_SUBMIT :ジョブ(コマンドバッファ)の投入
    • DRM_PANTHOR_TILER_HEAP_CREATE/DESTROY :タイル用ヒープ管理
  • 上記APIは 描画命令の実装とは直接関係しない低水準インターフェース

    • UMD がこれらを組み合わせて 描画処理を実現
  • APIは以下のカテゴリに分類可能

    • デバイス情報取得
    • メモリアロケーションと分離
    • グループ作成・管理
    • ジョブ投入
    • タイラー用ヒープ管理

今後の展望

  • 本記事で GPUドライバの基本概念 を整理
  • 次回以降、 Arm CSFアーキテクチャMCU(Micro Controller Unit) などハードウェア構成要素を詳解予定

Hackerたちの意見

おお、それいいね。俺はrk3588のやつを使ってて、デスクトップでpanfrostを使ってるんだけど、Firefoxで黒いパッチとか透明なパッチが出ることがあるんだ。変な感じ。

RK3588は、この記事の主題であるpanthorドライバーを使っていて、panfrostじゃないよ。

いい記事だね。でもちょっと短いな。ワクワクしてきたところで終わっちゃった。続きが楽しみだよ。

来週のエキサイティングなエピソードをお楽しみに!そこで、キューからコマンドが取り出されてGPUで実行されるのを見られるよ!ここで話している抽象化レベルは、データがユーザーとカーネルの境界を越えるところだね。主にキューとバッファの管理が中心だから、操作は少ないんだ。実際のアクションは、キューに入れたコマンドが実行されるときに起こる。GPUから戻ってくるコマンド完了のストリームもあるし、どうなるか楽しみだね。この非同期性はほとんどドライバーの問題じゃないよ。それはユーザーコードレベルに持ち上げられて、ドライバーが完了を届けるからね。

タイトルに「Rust GPUドライバー」って入れると「Arm Mali CSFベースのGPUドライバー」よりクリックが増えるのはわかるけど、これってArm Mali CSFベースのGPUドライバーじゃないの?メタツール(ツールを作るためのツール)にこだわるのは嫌なんだよね。ここでの目的はRustで何かを作ることだったみたいだけど、記事では「Arm MaliをサポートするGPUドライバーカーネル」って書いてあるし、ただのArm Maliドライバーじゃないんだよね。ドライバーを書く仕事の理解が間違ってると思う。OSのAPIとメーカーのAPIの間に配線をつなぐだけなのに、追加の抽象化レイヤーを作るフレームワークを構築するわけじゃないから、ちょっと厳しく言っちゃったけど、あなたはその人じゃないよ。ごめん、ちょっと辛口になっちゃった。

Rustが重要なのは、GPUのためにRustのインフラを使った最初の(もしそうでないなら最初の)ものだからだね。

これはLinux用の最初のRustベースのGPUドライバーの一つだから、ちょっと関係あるよね。

申し訳ないけど、厳しい言い方になっちゃったね。君は現代のGPUドライバーがどんなものか全然わかってないみたいだ。15年くらいドライバーを書いてないけど、その間に状況はもっと悪化してるのは知ってるよ。Linuxカーネルのソースコードを見てみなよ。GPUドライバーは、コード行数で言ったら、最大のコンポーネントなんだから。しかも、多くのドライバーは複数のカードをサポートしてる。毎個のGPUカードに完全に独立したドライバーを持つのが理にかなうと思う?GPUドライバーは「2つのAPIの間にワイヤーをつなぐ」だけじゃないんだ。実際、その2つのAPIはかなり違うからね。もちろん、反論してもいいよ。君が書いたGPUドライバーを見せて、ワイヤーをつなげてみてよ。

とても興味深いね。これの続編はあるのかな?それとも論理的な続きが…

今日出たばかりだから、もっと情報が出てくると思うよ。

uring_cmdがioctlsの代わりに考慮されたか気になるな。これって新しい分野に見えるけど、メリットはほとんどなかったのかな?もしそうなら、なんで?

記事で説明されているドライバーは、ユーザー空間のMesaライブラリが期待するAPIを使ってるよ。

GPUはすでに非同期デバイスで、自分自身のコマンドキューを持ってるから、IOCTLSはそのコマンドキューへの比較的安価な書き込みを抽象化してるだけだと思う。だから、CPU上に別の非同期コマンドキューを作ってその書き込みをスケジュールするのはあまり役に立たないんじゃないかな。もしGPUのコマンドキュー自体をuringにしてユーザー空間にマッピングするつもりなら、それにはio_uring APIの仕様をサポートするためにかなりのファームウェアの変更が必要になるだろうし、ハードウェアの特性によってはそれが可能かどうかも怪しいよ。