Mercurial > hg > Events > OSC2010
diff presen/osc2010.ind @ 0:9887d6547572
presen not done.
author | tkaito |
---|---|
date | Wed, 29 Sep 2010 22:55:09 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/presen/osc2010.ind Wed Sep 29 22:55:09 2010 +0900 @@ -0,0 +1,398 @@ +-title: 2009-09-26 (土) Cerium を用いた PS3 でのゲームの作り方 + +--Linux 上でのゲームフレームワーク + + Cerium Task Manager + + Blender / SceneGraph + +--Cell ってどうなの? + + 結局、Video Chip に触れない + SPUでレンダリング + ソフトレンダリングにしては速いが... + + 新型PS3では、Linux は使えない + とかいろいろだめ + +--Cell Architecture + +<img src="photo/Cell-main2.png" alt="pipeline" height="200"> + +Linux 側から使える SPE は 6 個 +SPE は 256KB の Local Store (LS) +SPE からメインメモリへ直接アクセスできない (DMAを使う) +SPE は 128 ビットレジスタを 128 個持っている + + +--楽するための並列プログラム + +トリビアルなプログラムでも並列実行する必要がある + +Single Thread でもPPE がクソ遅いので、SPEで実行するべき + +例えば、 + + Word Count + +--プログラムを Task に分割 + +Task には依存関係がある + +Open/CL , Spurs Engine + +--並列性 + + データ並列 + パイプライン + +結局、これしかないらしい。 + +--階層的並列プログラミング + + Row Level での並列性 + Vector/Streaming + 結局、データ並列とパイプライン + + SPE Level での + データ読み込み、 実行、データ書込 + のパイプライン並列 + + High Level での並列性 + Rendering + Scene Graph + +-- データ読み込み、 実行、データ書込 + +<img src="photo/pipeline.jpg" alt="pipeline" height="300"> + +パイプラインバッファはいくつ? + +--Task は良いけど、データはどうするの? + +データを右から左に... + 処理中に必要なデータがメインメモリ上にある + でも、SPE には、256k しかメモリがない + +メインメモリ(256MB、広くはないが十分)から、256Kに必要なだけキャッシュする + ハードウェアでやれよ! + 普通の並列ハードウェアはキャッシュになっている + IBMはそう提案したらしいが、SCEの人が拒否したらしい + +なので、自分でキャッシュする必要がある + +--Cerium Task Manager + + Open/GL Mesa に Cell driver を書いたが、 + メインメモリに依存しすぎ + Task base で書く必要がある + Redering Engine も自前で一つ持っていて良い + SPEは256Kなのでコード管理も必要 + SPURSは公開されないらしい + +そんな経緯で作成することに... + +--Crium Task Manager の特徴 + + PPU/SPUで、Task の互換性がある + SPU上の最適化は当面禁止 + OS X 上でも動く + コードのデバッグはOS X 上でやる + 並列化とチューニングだけPS3上で行なう + + SPU上のメモリをCode と Data を Hash とメモリリストで管理する + SPUに入り切らない巨大なTaskでも実行できる + +--ゲームの作り方 + + Blender で、3Dモデリング + 階層化、グルーピング + + これを、Blender の Python plugin で XMLに変換 + 画像/Texture もXMLに埋め込まれる + + XMLを読み込み SceneGraph を作る + +<img src="photo/cerium_sg_tree.jpg" alt="sg" > + +--Blender から SceneGraph 用の xml 生成 + +PythonScript の導入 + +<ol> +<li> Blender をダウンロードしてインストール</li> +<li> export_xml.py を用意する</li> +<li>"/Applications/blender-version/blender.app/Contens/MacOS/.blender/scripts +" + 以下にexport_xml.py をコピー</li> +<li>Blender を起動すると File -> Export に Libps3 (.xml) が追加される</li> +</ol> + +ゲームの初期化部分でcrateFromXMLfileを呼ぶ +<font size="4"><pre> +void +game_init(TaskManager *manager, int bg) +{ + sgroot->createFromXMLfile(manager, "xml_file/SG.xml"); +... +</pre></font> + +--SceneGraph + + 階層化された3Dオブジェクト + 子供の向きを決定する変換行列 + Camera + 背景 + 入力デバイス + +SceneGraph のノードには、 + MoveTask + Collision Task + + がある + +--ゲームとは、 + + SceneGraph を + MoveTask + CollsionTask + で書き換えていく + MoveTask, CollsionTask は、ステートパターンで + 入れ換えられる + +これで、すべて書ける。 + +--つまり、 + + SceneGraph の構築 + MoveTask + CollsionTask +だけを書けば、あとは、Cell が自動的に並列に実行してくれる + +--Task の作り方 + +SchedTask を継承した class を作る +<pre> +class SpeTask : public SchedTask { + SchedConstructor( SpeTask ); + int run(TaskManager *manager, void *rbuf, void *wbuf); +}; +</pre> + +run 関数は Task における main 関数のようなもの +SchedConstructor() で class 名を登録する +(C++のnew を使うとメモリを食われる...) + +SchedRegisterTask(TASK_SPE, SpeTask) で SpeTask に TASK_SPE という ID をつけて +登録します + + +--Task の作り方(Con't) +<pre> +/* 先ほど登録した ID を指定して Task を生成 */ +HTaskPtr task = manager->create_task(TASK_SPE); + +/* 入出力先の指定 */ +task->add_inData(rbuff, rbuff_SIZE); +task->add_outData(wbuff, wbuff_SIZE); + +/* CPU の指定 */ +task->set_cpu(SPE_ANY); + +/* Task の投入 */ +task->spawn(); +</pre> + +--Task の作り方(Con't) +Task は依存関係を記述する事ができる +<pre> +/* taskB は taskA が終わるまで待つ */ +taskB->wait_for(taskA); + +/* taskC は taskB が終わるまで待つ */ +taskC->wait_for(taskB); +</pre> + +--並列アーキテクチャは並列でないと... + +特に、Cell/PS3 は、SPUで実行しないとだめ + 既存のプログラミングでは、まったく歯が立たない + +トリビアルなプログラムでも、並列にする必要がある + +--WordCount + + Task をグラフ構造的に構築する (SceneGraphのMoveTask) + File を mmap する + mmap した部分をTask に割り当て、word countする + Task の構築 + Task の依存関係 + + char *file_mmap = st_mmap.file_mmap; + +--WordCount + +<img src="photo/wc_graf1.jpg" alt="sg" height="300"> + +--WordCount + + int word_flag = 0; + int i; + for (i = 0; i < task_num; i++) { + t_exec = manager->create_task(TASK_EXEC); + t_exec->add_inData(file_mmap + i*division_size, division_size); + t_exec->add_outData(o_data + i*status_num, division_out_size); + t_exec->add_param(division_size); + t_exec->add_param(word_flag); + t_exec->set_cpu(SPE_ANY); + t_print->wait_for(t_exec); + t_exec->spawn(); + word_flag = ((file_mmap[(i+1)*division_size-1] != 0x20) && (file_mmap[(i+ +1)*division_size-1] != 0x0A)); + size -= division_size; + } +</pre> + +--WordCount 各SPEの結果を合計 +<pre> + .... + /* taskの数 */ + int task_num = size / division_size; + int out_task_num = task_num + (division_size*task_num < size); + + t_print = manager->create_task(TASK_PRINT); + t_print->add_inData(o_data, out_size); + t_print->add_param(out_task_num); + t_print->add_param(status_num); +</pre> + + + +--やってはいけないこと + + 最初に大量のTaskをすべて作る + Task が自分でデータを拾って来る + Task 同士が、同期を行なう + +--Cerium Engine での同期 + + Task 内では同期はしない + Local Storage/専有したメインメモリしか使わない + + Task が終了した時に、Single Thread で動いているPPE + がデータの整理/同期を行なう + + Task 側では、Task の生成は行なわない + Task の post_func (continuation) で、Taskを生成する + +--SPE Task, PPE Task + Task 内で生成しても即座には実行されない + Task 終了時に、SPEに送る Task List が作られる + Task List のアドレスがSPEにメールされる + SPEがメールを見て、Task List を読み込み実行する + Task List の読み込みとSPEのTaskの実行は並列 + Task List がなくなる(なくなりそうになると)と、 + PPEにメールで要求する + +PPE Task + SPE Task と互換。メインメモリを自由に参照できる + +--Fifo TaskManager + +全部、同じCPU上で実行する。 + +OS X 上で動作する (Linux でも) + +デバッグ用 + +--MemList と Hash + + get_segment/put_segment/wait_segement + 明示的にキャッシュ制御する必要がある + +特に、 + +Dynamic SPE Task + SPE上に常駐しないTask + MemList と Hash で管理されている + +256K (GBAと同じ!?) しかメモリがないので重要 + +--SPU上でのコード管理 + + GCCのOverlayを使う + Overlay では、異なる場所にコードを置けない + 部分的にPICではなく、絶対参照に変更する + + 自分自身へは相対参照。ライブラリへは絶対参照 + Perl Script で書き換える + +--Task list + + task_list にオブジェクト生成するコードを入れる + オブジェクトが生成されてしまえば、普通に扱える + + task 実行中にコードが追い出されることはない + 現在実行中のコード + 次にロードするコード + の二つは必ずメモリ上にある + + +--SceneGraph と Rendering Engine + + SceneGraph -> SceneGraph + SceneGraph -> Polygon + Polygon -> Span Pack + Span Pack を Texture を使って Rendering + + これらを大きく並列に実行する + Rendering は細かく並列に実行する + +--SceneGraph と Rendering Engine + +1 dot 1 dot SPUが書いていく + +<td><img src="photo/rendering.png" alt="rendering" ></td> + +--Rendering Task + +SG2PP + SceneGraph を操作後、ポリゴンに変換し PolygonPack (ポリゴンの集合)を生成する +PP2SP + ポリゴンの中から、Span (ポリゴン内にあるx軸に水平な線分) を抽出し、 SpanPack (Span の集合)を生成する +DrawSpan + Span を使って 1 ラインずつ FrameBuffer に描画していく + + + +--Demo されている Chain + + 相互制約が非常に大きい物理シミュレーションの例 + 非ホロノミック系なので、単純な積分では力学を決定できない + SPU上で、すべての要素を同時に計算する必要がある + (あまり並列計算向きではない...ベクトル向き) + +(地味です...) + + +--まとめ + +Blender/Linux/Cerium を用いたオープンソースなゲームフレームワーク + +SceneGraphを作れば、move/collision を記述するだけで並列に実行される + +ソフトウェアレンダリングなんで、なんでも自分で書ける + +--将来的には、 + + C++ やめたい。悪いことばかり。メモリ食い。 + + CbC (Continuatin based C)で書き直す予定。 + + Cell は、やばそうなので、新しい並列アーキテクチャとか。 + + Open Scene Graph, Open/CLとの関係とか。 + + + +