GPU専用の自作新言語、MFGとそのIDEをリリースした!
仕事でここ数年作っていた自作言語、MFGをリリースしました。
MFG - Modern Filter-language for GPU / MFG Studio
正確には言語をリリースしたというよりは言語の開発が出来るIDEもリリースした、という感じです。 MFGStudioというQtで作ったIDE上で開発出来ます。
作ったフィルタはFireAlpacaの次期バージョン、FireAlpaca SE 3.0で動くのですが、こちらのリリースはこれからなので、 現時点ではIDEで開発してプレビューを見れるだけです。 ただそれだけでも結構面白いので試してもらえたら幸いです。
現時点では処理系のコードは公開してませんが、近いうちに公開予定です(社内のライブラリの依存を切ったら公開する予定だけどその時間がまだ取れてない…)。
詳細はMFG/docs/ja/README.md at main · karino2/MFGにドキュメントがあり、 特にGetting Startedを一通りやればどんな言語かは分かりますが、とりあえずここに例を書くと、 以下みたいに書くと、
@title "モザイクフィルター"
@param_i32 MOSAIC_WIDTH(SLIDER, label="サイズ", min=2, max=256, init=16)
let inputEx = sampler<input_u8>(address=.ClampToEdge)
@bounds( (input_u8.extent(0)-1)/MOSAIC_WIDTH+1, (input_u8.extent(1)-1)/MOSAIC_WIDTH+1)
def avg |x, y|{
rsum(0..<MOSAIC_WIDTH, 0..<MOSAIC_WIDTH) |rx, ry|{
let [b, g, r, a] = i32(inputEx( MOSAIC_WIDTH*x+rx, MOSAIC_WIDTH*y+ry ))
[*[b, g, r]*a, a]
}
}
def result_u8 |x2, y2| {
let [b2, g2, r2, a2] = avg( x2/MOSAIC_WIDTH, y2/MOSAIC_WIDTH )
ifel(a2==0,
u8[0, 0, 0, 0],
u8[*[b2, g2, r2]/a2, a2/(MOSAIC_WIDTH*MOSAIC_WIDTH)] )
}
avgとresult_u8というカーネルが作られ(後者は最終結果を入れる特別な予約語)、それに応じたグローバルメモリも確保されて実行される感じです。
今風にデモのgifも貼っておきます。

ざっくりとした特徴
公式ドキュメントの方に真面目にいろいろ書いてあるので、ここではもう少しくだけた内容での特徴などの話を。
シェーダーは普通C言語ベースですが、これを今風のスクリプト言語にしたいな、というのが基本的な考えです。 ただ外部からダウンロードして実行出来るようにしたい。 だからホスト側の処理もここに入っている必要がある。 さらにUIもJupyter NotebookやColabみたいに、何かinputとかを書いて入力を受け取れるくらいは欲しい。
そんな感じで作った言語です。
既存のシェーダーは実際のGPUの動きとコード上の見た目が乖離が大きいのが不満だったので、 もうちょっと実際のGPUのストリームプロセッサなどの動きをそのままモデリングしたような言語にしたい、 具体的にはストリームコアの一つだけブランチしてもあまり意味が無いのでブランチで飛び回るような誤ったイメージはなるべく無くして、 コアでexpressionの評価が同時に行われていくような現実がよりそのままになるような言語にしようとしてます。
またCGのグラフィックス計算がメインとなるので、 機械学習の数値計算のそのへんのノウハウを取り込むべく、RとかnumpyやPythonの機械学習系のドメインでは割と共通になっているような要素をいろいろ取り入れています。 特にループや条件分岐はRの影響が大きく、なるべくベクトライズして書くのが推奨、というような言語になっています。 この辺は自分の機械学習やGPUのハードウェア開発のキャリアの影響を強く受けたものになっています。 この辺の言語比較とかの話はそのうちしていきたい。
シンタックスはいろいろと新しい言語を比べて良さそうなものを選んでいったのですが、 結果としてはSwiftに一番似たシンタックスにはなっています。 Swift 6, Rust 2, R 1, シェーダー1くらい。
例えばタプルの要素を取り出すのは、以下のように
let tup = [1, 2, 3]
let a = tup.2
Swiftの tup.2 となっています。
GPU上ではヒープやスタックや関数ポインタでオブジェクト的な事をするようにはなっていないので、
動的に出来る事は限られています。
そこで静的にいろいろ変形する事で出来る事を入れていこう、
その為には静的にいろいろ出来そうなML系(というかF#)みたいな言語にしようと思って始めたのですが、
出来上がった言語は、表面上はそういう感じじゃないですね(^^;
いやぁ、Swiftは良く考えられた言語です。
触ってて思うMFGStudioのセールスポイント、最も簡単に始められるCGプログラム環境、およびシェーダープログラム環境
さて、今回リリースしたのはMFGStudioというIDEなので、これのセールスポイントを、最近触っていろいろ作っていた自分の印象で述べておきたい。
まず、環境セットアップがめちゃくちゃ楽です。Windowsなら展開したフォルダを適当な場所においてexeを起動するだけ、MacならMFStudio.appをApplication下において起動するだけです。 インタープリタやライブラリなどの準備がいらない。
環境のセットアップが楽なだけじゃなくて、IO周りや画像を用意しなくてもいいのも大きい。 最初からCGプログラムを開始出来ます。 Pythonとかで画像処理する時は入出力とかそのへんの最初のボイラープレートなコードを書くのがかったるいなぁ、 といつも思っていたので、 突然最初からCGプログラムが始められるのがすごく良いです。 結果の確認もその場で見られるので、ファイルに書き出して見てみたりする必要も無い。 しかもUIのプログラムも不要でスライダーとか書けるのも良い。
Python系列でそのへんやるのもかったるいと思っていた自分にとっては、 シェーダーのプログラム環境はさらにセットアップが面倒で、 シェーダーの勉強しても試すのはなかなか面倒だなぁ、といつも思っていたのだけれど、 MFGStudioはシェーダーのプログラム環境としてはセットアップがたぶん世界一楽なものなのでは無いか、 と思っています。 CUDAとかやってる人は、試してもらえればその楽さが良く分かってもらえるかと。
環境のセットアップだけでは無く、ホスト側のコードが要らない、というのもシェーダープログラム環境としては大きい。 シェーダーのホスト側コードはめちゃくちゃ面倒くさいので、 あれらを書かなくても良い、 というのは、すごく良いです。 最初からGPUプログラミング出来る。
CGの論文やグラフィックスプログラミングの教科書をGPUで実装してみた、系の事をやる環境としては、最も手軽に開発出来る環境になっていると自負しています。
そういう訳で、GPUプログラムをしてみるという点ではめちゃくちゃ敷居の低いものにはなっていると思います。
お絵かきソフトのフィルターのためのGPU用言語の意義
お絵かきソフトのフィルター、というのは、一見するよりも要求される事が多い。
お絵かきソフトのレイヤーのサイズというのはかなり大きく、640x480くらいの画像なら動きます、 みたいなアルゴリズムだと、全然使い物にならない。
例えばFireAlpacaにはブラシをluaで書ける機能があります。 けれど同じようにこれでフィルターを書く、というのは全く使い物にならない。 例えば良くあるレンズぼかしのような処理を書いたら、3分くらい帰ってこない、という結果になってしまいます。 (初期の頃に自作VMを作ってなんとかできないか試した時の結果)。
このピクセル数がめちゃくちゃ多いため、かなりの速度が要求される、というのが、フィルターの特徴として挙げられます。
しかもお絵かきソフトのフィルターは、対話的にパラメータを調整したりして、 デザイナがインタラクティブに使う必要があります。 つまりリアルタイム処理です。 これもパフォーマンスの要求をとても大きいものにしています。
これが、既存の言語を単に持ってきてそれでフィルターを書けるようにしました、 では、全く使い物にならない理由でもあります。
しかもグラフィックス処理というのは、アルゴリズムの選択で100倍のオーダーで速度が変わるのも全く珍しくありません。 というよりもだいたい工夫をするとそのくらいのオーダーで早くなります。 富豪的に書くのが許されず、かなりコードを読みにくくするような最適化を皆がしています。 ちょっとした処理が書けます、程度の簡易言語では、全く使い物になりません。 高い生産性を持ち、GPUの機能を活かせ、複雑なコードが書けるような言語でなくてはいけません。
MFGのフィルタは、Weighted Median FilterやMLAAのような凝ったアンチエイリアスなど、 だいたいポストレンダリングエフェクトとしてGPUで実装するようなものは実用的な速度で動きます。 中にはGPUで実装出来ないアルゴリズムも存在して、それらは実現出来ませんが、 これはGPUのシェーダープログラム全般にある制約です。 この制約の中でいろいろなアルゴリズムを実現するノウハウは3D CG業界ではたくさん蓄積されています。 そのおかげで、MFGの適用範囲は一見するよりも遥かに広いものになっています(先人の研究に感謝)。
MFGStudioのメニューから開けるサンプル集には、これまで作ったフィルタのうちの幾つか(それでも20個以上!)を
GPUプログラミング好きや自作言語好きはぜひ試してみてください!
ここ数年かけて頑張って作った自作言語です。面白さはかなりあると思っています。
もしよかったら試してみてください!