Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
このPRにはいくつかの要素が含まれています。
各項目について説明します
性能を低下させる範囲での無駄なアロケーションの撤廃
既存の実装ではReadAllBytesでbyte[]を取ってきて、それからJSONをstring化していました。
しかし、このstringに対してJsonUtilityを使用するわけでもなく、IndexOfからSubStringするのはロスが大きいことがわかりました。
IndexOf自体は非常に高速で問題はありません。
しかし、元のJSONがかなり巨大(3万文字相当)だったりしますので、かなり非効率的でした。
このPRではbyte[]をUnsafeUtility.PinGCArrayAndGetDataAddressし、byte*を取得し、それに対して作業することで巨大string生成を避けています。
なお、JsonUtility.FromJson<GltfTextureModel>などの部分ではstringを生成していますが、これはJsonUtilityが信じられないほど高速であったためです。
Utf8Jsonを元にしてほぼゼロアロケーションの実装をしてみたのですが、速度向上を果たせませんでした。
Taskを使用したAsyncの廃止
このライブラリで一番性能的にボトルネックになっているのはImageConverter.LoadImage拡張メソッドです。
これは必ずメインスレッド上で動作させなければなりません。
他は誤差と言えるでしょう。
重いTaskを利用してAsync対応をするのは疑問です。
インターフェースの新規定義
後述C# Job Systemを利用した非同期ローダーと同期であるMetaLoaderのAPIを揃えるついでにインターフェースを定義しました。
C# Job SystemとAsyncReadManagerを利用したファイルベースの非同期ローディング方法の提案
JobMetaLoaderという構造体を新たに定義しました。
物理ディスク上のファイルから読み込む場合に限り、ReadAllBytesで全byte列を取得せずともよいローダです。
処理の流れとしては
コンストラクタでインスタンス生成時にメタデータの最初の20byteを非同期で読みます。
その後、読み込み終了時に別スレッドでJSONファイルの長さを調べ、JSONファイルを全てUnsaUtility.Mallocで確保した領域に非同期で読み出します。
そして読み出し後にこれも別スレッドでメタデータを解釈します。
Readメソッドを呼ぶとメタデータ解釈後までメインスレッドをブロックします。
Readを呼ぶとその中でサムネイルをLoadImageするのに必要な分量だけ非同期で読み出します。
その後LoadThumbnail()を呼ぶと読み出し終了までメインスレッドがブロックされ、Texture2Dが生成されて戻されます。
各段階についてJobHandleが露出していますので、コルーチンやUniRx、UniTaskなどと組み合わせることで柔軟に非同期処理が行えると思います。