2012/04/09

モデルの非同期&分割ロード

先日上げたデモ動画では、モデルのロードで非同期処理と分割処理を組み合わせています。ここでは、それらの実装について書いてみようかなと。

最初は、モデル ファイルの読み込みから VertexBuffer の作成までを 1 つの処理とし、Game Thread とは別の Thread へ渡してみましたが、上手く動きませんでした。Game Thread が呼び出す Game.Draw() では SpriteBatch などが描画処理を行いますが、その最中に別の Thread が VertexBuffer.SetData() を呼び出すと、どちらかの Thread の処理がコケます。
僕は GPU が絡む部分がよくわからないので、詳しい人からのツッコミが欲しい所ですが、恐らく、どちらも GPU へ命令を渡す部分であり、そこでの競合が発生するのだと思います。

こういう問題があったため、モデルのロード処理を、まずは以下の 2 つに分割しています。

  1. モデル ファイル読み込みから頂点データを作成
  2. 1 で作成された頂点データから VertexBuffer を作成

こうしておき、1 だけを別の Thread へ渡します。この時、コールバック メソッドも同時に渡し、1 を終えたら呼び出されるようにします。そして、コールバック メソッドは 2 を Game Thread で管理するキューへ入れます。
この時、更に 2 を分割してからキューに入れます。僕の用いるモデルは複数の VertexBuffer を用いるため、VertexBuffer の単位で処理を分割してキューに入れます。XNA の Model クラスで喩えるならば、ModelMeshPart を個別に構築する感じです。

キューに入れられた処理は、Game Thread が呼び出す Game.Update() で順に取り出され、VertexBuffer を作成します。そして、何度かの Game.Update() の呼び出しで全ての VertexBuffer の作成が完了したら、モデルのロードが完了したということになります。

要するに、1 だけを非同期にし、2 を Game.Update() 内で行うようにしたわけです。そして、2 を可能な限り細分化し、Game.Update() での負荷を下げたという感じです。

1 の非同期処理は、僕は ThreadPool を利用して Thread に割り当てています。ただし、そのまま使うと Thread 数の制御ができないため、ここでもいったんキューに入れ、Thread 数を制御しながら割り当てています。

で、ここまでやってデモ アプリを計測したら、1 を非同期にする程でもなかったというオチでしたが、今後のコード次第ではどうなるか分からないので、このパターンのままやろうかなと。
 ContentManager.Load() でロードする場合でも、その単位でキューに入れれば Game.Update() の負荷を下げられるんじゃないかと思います。

なお、デモ動画の段階では、1 の処理完了で即座にコールバック メソッドを呼び出していますが、今はこれもいったんキューに入れ、Game.Update() 内でコールバックが呼び出されるようにしています。
基本的には、多少回り道をする処理となっても、同期をとる箇所をまとめてしまう方が、他の部分で lock を書いたりせずに済んで見通しが良いのではないかと思います。lock 漏れも怖いですし、それらのデッドロックも怖いですし。

ソースコードの例としては、非同期処理については、以下のコードを HTTP 通信の非同期処理に用いています。

https://github.com/willcraftia/Blocks/tree/master/Framework/Threading

上記はモデルのロード処理ではないですが、同様のパターンを用いて非同期処理を行なっています。
モデルのロード部分は、専用モデルを用いていることから複雑でありオススメできないサンプルですが、興味のある人は以下などをどうぞ。

https://github.com/willcraftia/Blocks/tree/master/Blocks/Content

上記にある InterBlockMeshLoadQueue が非同期処理、BlockMeshLoadQueue が VertexBuffer  分割キューです。
※master にあるコードなのである日突然消えたりするかもしれません。

なるべく短命なオブジェクトが生成されないように工夫してみたつもりですが、どうですかねぇ・・・。

2012/04/03

はじめに

はじめまして、あるいは、こんにちは。

過去、 3D でドット風モデルと物理システムを用いたプログラムを XNA で作成し、それを動画として上げていましたが、3D グラフィックスの分野は全くの素人であったため、試行錯誤により滅茶苦茶なプログラムを書いていました。また、いつしか目的を見失っていた所もありました。

最近は、それらを頭で整理できるようになってきたので「ちょっとブログでもやってみようかな?」という軽い気持ちで始めています。なお、このブログのハンドル名は、Google 先生が最近怪しいので、気持ち程度に本来のものから変更しています。

XNA の話題が多くなるかもしれないですが、XNA の範囲にない技術も使っていくので、色々と雑多な内容になるかと思っています。開発やゲームに関係するという縛りの上で、しょうもない日記も上げるかもしれません。

いずれにせよ、飽きるまではやってみようかな・・・と。

ひとまずは、XNAで作成した UI Framework のデモ動画を用意しているので、近いうちにニコニコ動画へ上げると思います。

それではよろしくお願いします。

libgdx いじり

Google が提供している Java 版の Tango Examples は Rajawali をベースにしているため、自分が仕事で開発する Tango アプリも Rajawali ベースとしていましたが、最近は libGDX への移行を進めています。一応、要点については移行が...