2018年12月9日日曜日

コンピューとシェーダー覚え

めも 時々書き換える

概要
http://neareal.com/2601/

長所短所、効率等
https://wlog.flatlib.jp/item/1425
DirectCompute だとどうなってるか
https://wlog.flatlib.jp/item/1411

構成要素
シェーダー
バッファ
カーネル カーネルID
スレッド スレッドグループ
定数バッファ

実行はグループ数を指定 (x,y,z)
1グループにつき (x,y,z) スレッドを実行

バッファは普通にランダムアクセスする
実行中のスレッドIDを得ることが可能、バッファアクセスに利用できる
グループIDも取得可能

定数バッファは他のシェーダと同じ

コンピュートバッファは1次元、テクスチャバッファは2次元、という感じ
RW は書き込み可能
StructuredBuffer
AppendStructuredBuffer/ConsumeStructuredBuffer

バッファタイプ
Default structured buffer
Raw byte address buffer
Append AppendStructuredBuffer/ConsumeStructuredBuffer
Counter よくわかんない、カウンタ付きの structured buffer
IndirectArguments DrawIndirect 系に渡すための引数バッファ(dword*5)


DX11では
リソースとその使用方法としてのビューという概念があるみたい
同じリソースを複数のビューから扱えるもよう
リソースはバッファとテクスチャに分けられるみたい
--------
リソース
Texture/RWTexture
Buffer/RWBuffer
ByteAdddressBuffer/RWByteAddressBuffer
StructuredBuffer/RWSturcturedBuffer
ConsumeStructuredBuffer/AppendSturctutedBuffer

ビュー
ShaderResourceView (SRV) R
UnorderedAccessView (UAV) R/W
RenderTargetView (RTV) W
DepthStencilView (DSV) W

この辺は Unity では隠されているかんじ?
-------

バッファ
CopyCount() バッファ間でカウントをコピーできる
・おそらくCPUを介せずにGPU内で可能なんだと思う
SetCounterValue() 
・カウンタをセットできる 定数バッファの SetXxxx() と同じ感じなんじゃないかな
・よくわからないが、たぶん内部がどうなってるとかは考えずに使用していける感じか?
・要素の追加/取得と現在状態(カウンタ)だけ管理すればいいみたいな
SetData( nativeArray, arrayStart, bufferStart, elementCount )
・任意の位置へのアクセス
・帯域も節約できるんだろうか
・複数個所に細かく SetData() した場合の転送効率はどうなんだろう








Linq を毎フレーム使うには

Linq で、オペレータのオブジェクトは全部クラスなわけで、Unity でフレーム内で使用するにはGC的にヤダなぁ、というのがあると思うんです(速度的な面はいいとして)

オペレータってのは遅延実行できて、使いまわすことができるのですが、
そうすると列挙ソースだけ変更したいなっていう要望が発生すると思います。
(もしくはもっといいやり方があるかもしれませんが)

そういう場合のために、ソースを差し替えできるようなクラスを作成してみました。
https://github.com/abarabone/EnumerableCache/blob/master/ConsoleApp1/EnumerableCache.cs?ts=4
絶賛試行錯誤中なんですが。

つうてもまぁ、なんか微妙なかんじです。
一番微妙なのが、struct enumerator ですよね。
Linq オペレータって、内部で foreach() yield return やってるじゃないですか。
そこで生成される enumerator は、class enumerator になりますよね?
んじゃあ結局、毎フレーム列挙する度にオペレータの深さだけGCゴミがたまっていくのは変わらないということなんじゃないかと。

まだ実際に Unity で試してないのであれなんですけど
(テストとかデバッグとかの機能をよく知らないので二の足を踏んでしまいます…)


ところで
Linq のオペレータとかイテレータのシグネチャ?を、

static IEnumerable<TResult> SelectIterator<TSource, TResult>
    (IEnumerable<TSource> source, Func<TSource, int, TResult> selector)

から

static IEnumerable<TResult> SelectIterator<TSource, TResult, TEnumerable>
    (TEnumerable source, Func<TSource, int, TResult> selector)
    where TEnumerable : IEnumerable<TSource>

みたいな感じに変えれば、内部の foreach() で専用の GetEnumerator() を呼ぶ感じになったりしますかね?
(あ、無意味…だって専用の struct enumerator を書かないとだめだし、そうすると foreach() yield return が使用できなくなって、選択的に struct enumerator を呼ぶことができなくなる…よね?)

selector ラムダとかはどうなんだろ、キャッシュされると思うんですけど。

あ、いや、Linq のソース全書き換えとかはさすがにやらないですが…


2018年11月14日水曜日

OneFrameEntityComponentChunk みたいの欲しくないですか

エンティティのコンポーネントデータを処理して、その中から選別されたデータを次の段階の処理へ進めたいとき、なんかのコンテナに詰め替えて処理していくけど、なんかECSっぽくないていうか。

なんかこう、一時的なチャンクみたいな仕組みみたいのが欲しい。
フレームが終われば破棄される、一時的に作成できるエンティティみたいの。
チャンク移動や削除みたいのはしない前提の、作られるだけのタイプ。
そういうのならエンティティ編集にかかる制限は緩くなりそうだけど、ならんかな。
そんで job process component 的なジョブにも対応してるようなやつ。

2018年11月13日火曜日

NativeQueue の Defer な Job を作れないかな

NativeQueue の Defer な Schedule() があるとうれしんだけど、なさそう
つくれないかな

Job の作り方
https://jacksondunstan.com/articles/4857
https://github.com/Unity-Technologies/UnityCsReference/blob/54dd67f09e090b1ad5ba1f55886f327106406b0c/Runtime/Jobs/Managed/IJobParallelFor.cs
https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Unity.Jobs.LowLevel.Unsafe.JobsUtility.html

じょぶは、おおまかにこんな感じでつくるっぽい
・基本となるインターフェースの定義( IJobXxx とかいうやつ)
・JobScheduleParameters と、ジョブの Execute() を実行しつづける関数の準備
・そいつを JobsUtility.ScheduleXxx() 系の関数に渡して、スケジュールしてやる


ユーザーがこさえるジョブのひな型たるインターフェースの定義は、こんな感じ
    [JobProducerType(typeof(IJobParallelForExtensions.ParallelForJobStruct < >))]
    public interface IJobParallelFor
    {
        void Execute(int index);
    }

JobScheduleParameters の準備として重要なのは、ReflectionData をセットすること
で、ReflectionData ってのは、JobsUtility.CreateJobReflectionData() で作成するみたい
その時、ジョブを制御するメソッドを渡してやる(ExecuteJobFunction みたいなデリゲートを定義してそいつにキャストして渡してるもよう)

そのジョブ制御メソッドの中では、基本てきにはループで「ユーザーがこさえたジョブ」の Execute() を実行し続けるんだけど、JobsUtility.GetWorkStealingRange() なるもので中断/終了判定をとっているみたいな気配


…と、そんな感じでじょぶ自体は作れそうなかんじなんだけど、肝心のスケジュールが
JobsUtility.Schedule()
JobsUtility.ScheduleParallelFor()
JobsUtility.ScheduleParallelForDeferArraySize() ←これが個数を後回しにできるやつ
JobsUtility.ScheduleParallelForTransform()
くらいしかない
そのうえ個数遅延は NativeList に対して行うものしか用意されていないっぽい

そういうわけで、なんか目論見は無理そう
あと残された手は NativeList 互換的なコンテナ(個数遅延に渡せるもの)の作成なんだけど、なんか難しそうでヤダな…
そういえば、IJobProcessComponent なんとかってのもあったな、あれもソースみてみるか

追記:キューの内部ブロックかスレッドIDに関する情報を詰めた NativeList を軽く作って Defer に渡し、それをもとにデキューしていく…みたいのってできないかな(やる気はない)

パラレルな読み書きができるネイティブコンテナはないの?

んーーーーーと、
NativeQueue は Concurrent によってパラレル書き込みができるけど、パラレル読み出しができない
NativeList はパラレル書き込みができないけど、JobsUtility.ScheduleParallelForDeferArraySize() を使用するとパラレル読み出しができる

なぜ、パラレル書き込みができてパラレル読み出しができるコンテナがないのか?
理由があるんだろうか?
それともそういうシチュエーションになることがそもそもおかしいのだろうか

そんなこんなで、では NativeList の Concurrent な構造体でも用意してやろうかと、
バッファ実体と長さフィールドへのポインタを格納して、Add() するとインターロックでカウントアップするようなものを作った。
そいつでパラレル書き込みを一応クリアとして、こんどは Defer な Schedule() を使用すると、
InvalidOperationException: The previously scheduled job MotionProgressJob reads from the NativeArray MotionProgressJob.srcEntities. You must call JobHandle.Complete() on the job MotionProgressJob, before you can write to the NativeArray safely.
って言われて、Complete() で待たないとエラー消えない

そんでもって、それを回避できるかなと考えて TempJob で NativeList を作りたいんだけど、
InvalidOperationException: DisposeJob.list uses [DeallocateOnJobCompletion] but the native container does not support deallocation of the memory from a job.
がでてしまう

自分でコンテナを作らないとダメなんだろうか…

2018年11月6日火曜日

Complete() は嫌だなぁ

ああーしまった
Job でカウントアップするなどした結果カウントを取得して、
そいつを .Schedule() の全長として渡したいなんてときは
Job の完了を待たないとだめなんだなぁ そりゃそうだー

OnUpdate( JobHandle inputDeps )
で渡される inputDeps はスケジュールのためのハンドルに過ぎないから、当然 Complete() 待ちはしないといけないんだ
以前のコードにも苦し紛れに Complete() 挟んであった
システムを分けるわけない関係ないな

でもメインスレッド上で待たせるのは嫌だなぁ
これブロックするんでしょ?
どうしたもんかな

2018年11月5日月曜日

ECS

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 とかは対応しないの?

2018年9月16日日曜日

Unity再燃

昔Unityで作っていたゲームを置いていた場所

ECSでまた作り直したい

とりあえずECS でボーンアニメーションさせてみた
https://github.com/abarabone/ecs_motion

ニューラルネットやってみてる

最近ニューラルネットやってみてる 理屈を学ぼうと思って、まずはオブジェクト的に作ってみてる (ベクトル化とかは後回しで) sigmoid, tanh, ReLU MSE, cross entorpy あたりを小規模にいじってみてます でも今 soft max の逆伝...