Unity ECS をやっています
現状を書きなぐります すみませんが推敲しません
ところで「Unity ECS 完全に理解した」という勉強会に行きたかったのだけど、いけなかった。
キャンセルをぎりぎりまでやきもきしながら見守ったのだけども、地方からの移動時間を考えてあきらめて補欠キャンセルした。(が、もしキャンセルしなかったら最終的にギリピッタリで行けたみたいだった。なんてこった。)
内容自体はネットで目にする記事を改めて整理、という感じだったけど、懇親会が
おすしとても有意義そうだった。
それはさておき。
今まで Q6600+gf8600GTという環境で満足していました。
しかしメッシュ描画関連で ComputeShader を使用しないと定数バッファの数が切なくなってきたので、居間の安いノートで試してました(新しいマシンなのでCSサポートしてる)。
が、スペックが心元ないのでグラフィックボードでも買おうかなぁといろいろ見てたら Ryzen 2400G というのが欲しくなってきて、ちょうど amazon がCEDEC(じゃなかったか?)でゲーム関係のタイムセールやっててどうにも安くて異常な心理状態に。買ってしまった。でもなんか今メモリ高い時期だそうで、そこは残念だった…。
スペック的には今までの構成でも不自由なかったんだけど。
結果的に Ryzen2400G + マザボ + メモリ16GB を購入した。
(でもいまだにメモリ使用8G超えたことないんだけど)
本題、最近思ったこと
・System の意義に懐疑的な気持ちが芽生えてきた。
というのも、結局処理は全部JOBで行うので、System が単なるJOBの起動を行う存在になってる。そんならモノビの Update() でもいいんじゃないの?という感じ。
・構造体メインになってGCをガチで減らそうとしてるな…と好印象だったんだけど、結局ラムダとかいろんな利便性を犠牲にする。じゃあC#じゃなくてC++のほうがSIMDイントリンシックも使い放題だし、最近ラムダだの型推論だの追加されてるらしいし(Cは触らなくなって久しいので勉強しないと…)言語機能なんでも自由に使えてそっちのほうがむしろ便利だったりしないんかね?とか思ったり。
・ある程度 System を細分化してたんだけども、それだとほかの System とデータ受け渡すとき(結果を NativeArray に詰めて渡すとか)、TempJob の NativeArray が System をまたいでしまうのがなんかなぁとか思った。どっちに NativeArray 置いていいかとかも悩む。あと、[Inject] とかでほかの System を参照するようにしたときに System のコンストラクタが使えなかったり、依存関係とかめんどくさいなと思った。ので、System あんまり分割しないほうがよくない?とか思って一つにしようとしたら、NativeArray に詰め終わったときに何個詰めたのよって話で Complete() で待たないといけなかったりしたわけで、OnUpdate() に Complete 待ちの Yield あればいいのになぁって思った。ちなみに Await 的な感じでまたせるとしたら、別スレッドでは IsComplete() だっけ?とかで確認しつづけないといけないんだろうか?
・ComponentData を IJobProcessComponentData で処理するのがすごく楽しい。のだけど、あんまりそれでデータを処理していくことも少ないのかな…?と思えてきた。例えば索敵するぞってなってまず ComponentData をECSのしくみに抽出してもらって条件判定するけど、その結果対象となったものは結局別のネイティブコンテナに詰めて(いろいろ考えると NativeArray に詰めることになる?)いくのだろうから、そっからはチャンクとかどうでもよくなってくる。こういうときECSではメンバのない IComponentData を付けて識別させるんでしょ?っておもっていたのだけど、チャンク移動だのエンティティコマンドバッファだの NativeArray が一番効率いいだの、そういう話を聞くとどうもだめなのかなと思えてくる。個人的にはECSの考え方は刺激があって楽しいので、多少効率悪くても分かりやすく書ければECS的なやりかたでやりたい。そもそも効率とかあまり気にしないようにしたいんだけど、どうもだめだ…(そういのからの逃避で Unity 使い始めたので)。
・NativeArray に対して、あれだけ複雑に組み上げられているエンティティとコンポーネントの存在意義は何なのか。それはチャンク移動だと思う。つまり「抽出作業を効率的に行うために事前に分類する」ことと「削除しても歯抜けにならない」ことかと(キャッシュ効率は使う側の問題)。そんならその利点を感じられなければ、ECSいらない、NativeArray とJOBあればいい、ってなる。でもECS事態はすごく楽しい。なんていうかデータ抽出と処理分割がすごく気持ちいい。好き。活かせるようにしたい。でもなんかEとCとSの全部に懐疑心ちょっとだけでてきた。
・ていうか、System 間で NativeArray 渡すってのはそもそもECSからすると逸れてるのでは。そもそもECでぜんぶやれるべきなのでは。流れるデータはECであって、システムはその軌道を左右する程度のデータしか持たないべきなのでは。
試したいこと
・キャッシュヒット率のためにはデータを細分化したほうがいいという話を聞く。
でもJOBなんかだとおそらく、ある程度の処理を一塊にしたほうがよさそうな気もする(スケジュールのコストとか?)。どっちがいいのか試したい。
・上と似たような話。今まで(ECSで)モデルアニメーションさせるのにキャラクター、ボーン、キーストリーム、の単位でそれぞれエンティティにしてたんだけど、Dynamic Buffers もできたことだし、キャラクター単位でJOB化したほうがいいんかな?とか思ったり。まぁ、エンティティ化したほうが、ECS使ってる感あって楽しいんだけど。エンティティってJOBから作るのが面倒なんだよな。ラベル的な ComponentData 張り替える作業もめんどくさいし(メインスレッド負荷とチャンク移動的な)コストかさみそうなイメージあるし。
・JOBで NativeArray にデータを追加していくときなどの、個数のカウントアップ。インターロックとスレッドごとに領域をつくって書き込む方法、どっちが総合的によいだろう。また後者では、結果を受け取った先でJOBで回すとき、一つに結合したと考えてJOBで回す方法と各スレッドごとに領域をただループで回す方法とがあると思うけど、どちらがいいのか。
気づいたこと(疑問とかも)
・Temp で確保した NativeArray って、フレームまたいで Dispose() すると逆に怒られるね…。これってむしろ Dispose() しなくてよくなったってこと?
・Malloc() は Temp とか TempJob とかは対応しないの?