Cell Task Manager Cerium の
SPU内データ管理
多賀野海人、小林佑亮、宮國渡、河野真治
琉球大学
Apr, 24, 2009
研究の背景
現在、学生実験で PS3Linux を用いてゲーム開発を行っているが、
学生には困難であることがわかってきている
- 問題1 : Cell アーキテクチャプログラミング
- Many Core による並列プログラミング
(データ、コードの分割の必要性)
- Cell の仕様 (DMA、データのアライメント、etc..)
- 問題2 : ゲーム開発用の Framework が無い
実験期間の大半を Cell の勉強に費やさねばならず、
開発されるゲームのレベルが例年一定以上にならない
研究の背景 (Con't)
我々の研究室では PS3 ゲーム開発用フレームワーク Cerium を開発した。さらに、PS3 の GPU の情報が
公開されていないことから、Rendering Engine も独自のものを持つことにした
- 問題点1 : SPE の Local Store
- Cell に搭載されている SPE は Local Store (256KB) にしかアクセスできず、
直接メインメモリにアクセスすることができない
- 問題点2 : MFC を用いた DMA 命令
- メインメモリにアクセスするには MFC を用いて Direct Memory Access 命令を送らなければならない
- DMA には待ち時間が存在する。待ち時間の間 SPE が動作しなければマルチコアプロセッサのパフォーマンス
が極端に下がる
研究目的
SPE 内のデータ管理を行い Cell プログラミングの並列度を確保する手法を提案する
描画における Texture の処理
- 描画に必要な Texture データの SPE への分割、転送処理
DMA 転送待ち時間の間の SPE の処理
- 既に SPE 内にデータが転送されている場合、そのデータの管理を SPE 内で行うことによって、
DMA 転送待ち時間の間も SPE 内での処理を継続させる
発表の流れ
- Cell アーキテクチャの概要
- Cerium
- Rendering 部分の高速化
- 比較
- まとめ
Cell アーキテクチャの概要
- Cell アーキテクチャの概要
- Cerium
- Rendering 部分の高速化
- 比較
- まとめ
Cell Broadband Engine
- 1 個の PPE と 8 個の SPE がリングバスで構成されている
- SPE は 256KB の Local Store (LS) を持つ
- SPE からメインメモリへ直接アクセスできない
- SPE が持つ MFC (Memory Flow Controller) へ DMA 命令を送ることで行う
- SPE は 128 ビットレジスタを 128 個持っている
Cell の基本機能
Cell の基本機能 (Con't)
- DMA 転送には待ち時間が存在する。
- 待ち時間の間 SPE 有効に使わなければ、マルチコアプロセッサのパフォーマンスが極端に下がる。
- Task のデータを読み込む (1)
- 読み込んだデータの処理 (2) を行っている間に次の Task のデータを読み込む
- 処理したデータの転送 (3) の間に、2 で読み込んだデータの処理、次の Task のデータの読み込みを行う
Cerium
- Cell アーキテクチャの概要
- Cerium
- Rendering 部分の高速化
- 比較
- まとめ
Cerium
PS3 ゲーム開発用フレームワーク
- Scene Graph
- ゲームに登場するオブジェクトやルールなど、ゲームを構成する要素をもつ木構造
- Rendering Engine
- Task Manager
- Task と呼ばれる分割された各プログラムを管理するライブラリ
Scene Graph
- Blender
で生成したオブジェクトを独自の XML 形式で出力
- XML が持つ情報 (頂点座標、テクスチャ座標、イメージ) などから SceneGraphNode を生成
- ポリゴン情報の他に、オブジェクトの操作 (move、
collision) を持つ
[1]オープンソースの3Dモデリングツール
OpenGL
- OpenGL
- オープンソースの3Dグラフィックスプログラムインターフェース
- 変換行列、光源、カメラなどの API を実装
- 親子関係の表現も可能
Cerium での OpenGL の使用の問題
- SceneGraph の OpenGL の API にあわせるオーバーヘッド
- SceneGraph は自身の変換行列を持っている
- SceneGraph 単体でオブジェクトの操作は可能
- SceneGraph だけで問題ない
Rendering Engine
|
- SG2PP
SceneGraph を操作後、ポリゴンに変換し PolygonPack (ポリゴンの集合)を生成する
- PP2SP
ポリゴンの中から、Span (ポリゴン内にあるx軸に水平な線分) を抽出し、
SpanPack (Span の集合)を生成する
- DrawSpan
Span を使って 1 ラインずつ FrameBuffer に描画していく
|
Task Manager
Task と呼ばれる、分割された各プログラムを管理する
- Task の単位はサブルーチンまたは関数
- Task 同士の依存関係を考慮する
- 実行可能になった Task を各 SPE に割り振る
- C++ で実装
Rendering 部分の高速化
- Cell アーキテクチャの概要
- Cerium
- Rendering 部分の高速化
- 比較
- まとめ
Rendering 部分の高速化
- SPE の LS は256KB しかないので、Texture 情報を一度に転送すると容量を超えてしまう可能性がある。
- そこで、描画に必要な Texture データを分割、転送するという手法を用いる。
Rendering 部分の高速化 (Con't)
- Tile Array を用いた Rendering
- Polygon の Span から、描画に必要な Texture A を含む Tile を計算する
- Tile を SPE に転送し、Tile の中の pixel 情報 (RGBα値) を取得して描画を行う
Scale
Texture の縮小画像の作成
描画されるオブジェクトが小さい場合、そのままの大きさの Texture は必要ない
Span の長さと、縮小 Texture の大きさが一致するような Scale の縮小 Texture を選択する
Texture は縦横ともに 1/2、1/4、1/8 と、2分の1ずつ縮小させる (最小 8x8 pixel)
Scale の効果検証
- 10個のオブジェクトを用いたサンプル
- Polygon 総数 は 19860
- Texture は合計 10 枚
( 8x8(3)、512x384(2)、616x123(4)、1024x768(1) )
キャッシュ
- SPE 上の Texture データのキャッシュの有効性を検証する
- キャッシュを用いた場合と用いてない場合を SPE の数を変更して比較する
(1920x1080の画像の表示をサンプルとして使用)
|
キャッシュ なし |
キャッシュ あり |
SPE 1 個 |
0.08 FPS |
0.42 FPS |
SPE 6 個 |
0.59 FPS |
2.54 FPS |
キャッシュの有無による処理速度の比較
他システムとの比較
- Cell アーキテクチャの概要
- Cerium
- Rendering 部分の高速化
- 比較
- まとめ
比較 - OSMesa (Gallium)
- 先行研究 (神里)
- 現在 PS3Linux からは GPU にアクセスできない
- frame buffer は使用できる ため、OSMesa を使用
- OSMesa の機能の一部を SPE に乗せ、高速化に成功
- ソースコードの複雑化を招いた
- 以降のメンテナンスや機能の追加、改良が困難と判断し、独自に Rendering Engine を持つことに
- Gallium
- OSMesa の Cell Driver
- OpenGL で動作
- PS3 上のゲーム開発において、レンダリングのみを SPE に実装するのでは足りない
- ゲームに登場するオブジェクトの計算 (衝突判定等)
- Amdahl 則の問題
- レンダリングだけでなく、ゲームオブジェクトも SPE で処理できるように
しなければならない
比較 - Gallium (Con't)
- 実行速度比較
- 出力解像度は 1920x1080
- 地球のテクスチャを貼った球体のオブジェクトを表示
|
ポリゴン数 : 1984
Gallium (SPE 6 個) |
5.4 FPS |
Cerium (SPE 6 個) |
9.5 FPS |
|
- Gallium には OpenGL API の機能が全て乗っているわけではない
- Cerium とのレンダリングの機能の違い
まとめ
- Cell アーキテクチャの概要
- Cerium
- Rendering 部分の高速化
- 比較
- まとめ
Rendering Engine (Con't)
Scale選択
static int
getScale(int width, int height, int tex_width, int tex_height, int scale_max)
{
int base, tex_base;
int scale = 1;
/**
* width と height で、長い方を基準に、
* texture の scale を決める
*/
if (width > height) {
base = width;
tex_base = tex_width;
} else {
base = height;
tex_base = tex_height;
}
if (tex_base > base) {
int t_scale = tex_base/base;
while (t_scale >>= 1) {
scale <<= 1;
}
}
return (scale > scale_max) ? scale_max : scale;
}