January 01, 2011

[C++]高速化について思うところ

明けましておめでとうございます♪
遥佐保(はるか・さお)です
2011年もどうぞ、よろしくお願いします

これはC++ Advent Calendar jp 2010への26日目(補欠1号!)の参加記事です

C++の仕様やBoostについては全然詳しくないので、、すみません
C++でのゲーム作成の時期が長かったので、高速化について、思うところを記載してみます
読み物として目を通して頂ければと思います

最初に。。
ゲームは結果を出せれば何でもアリな世界で
極端な話どんなに可動性に欠けても規格に則ってなくても
良い作品が出来ればそれでヨシ!という感じなので
有識者が見たら反感を買うコードがうじゃうじゃかもしれません

例えば、オブジェクトを生成するためには new するわけですが、new は知ってのとおり、1フレーム内で大量に処理するには時間がかかり過ぎるし、タイミングによっては最悪、確保出来ない場合(※)もあります
 (※)確保出来なかった場合どうなるのか?ですが、優先順位を決めて
    確保の可否を判断したりします
    自分がどうしても確保されなければならないOBJの場合
    他の生きているOBJで優先順位の低いやつを探して
    そのOBJを殺し、自分に新たに割り当てたりします

そうなってくると、最初に予め new しておいて、それを使いまわすということになるのですが、そしたらコンストラクタやデストラクタに依存しない作りをルールにしておく必要があります
 // もしくは、デストラクタを明示的に自力で呼ぶルール

全然事情の知らない人が、このルールだけを見たら
「C++のデストラクタは信用できないから使わないんだってさ、ばかじゃないの!?」
と言うかもしれないけど、ゲームはメモリ確保関連は動的に見えて、ほぼ静的なので
こりゃ仕方ない

そういうのって凄まじい試行錯誤から生み出された究極のソースコードなので、許してもらいたいです
↓↓例えばこんな例
// 最初に確保
void* p_mem = operator new( max_size * sizeof( WORK ));
WORK* box = static_cast<WORK*>( p_mem );
for( i = 0; i < max_size; i ++ ){
new( &box[i] ) WORK();
}

// 自分でデストラクタ呼び
box[i].~WORK();

*インライン化をうまく使う

何度も何度も、1フレームに何千回と呼ばれるような処理も中にはあります
その処理を関数にしておくと、もちろん関数呼び出しの分処理が遅くなってしまいます
そこでインライン化です
これはC言語のマクロ展開ほとんど同じです
 // マクロ展開はプリプロセッサで行われるけど、インライン化はコンパイラが行います
 // インライン化の方が型宣言の指定などがきっちりできるしね
結構みんなインライン化大好きなのですが、ソースコードの量が増えていくことになるので、多分あまり大きなインライン関数を書いてしまうと、キャッシュが効きにくくなったり、ソースの肥大化によるコンパイル時間の増加(そこらじゅうでincludeされてたり)など、諸刃の剣ですけどね


*STLコンテナは使用用途を考えて

vector,mapなど使うのは、楽して(作業時間をかけずに)早く作りたいときだと思います
例えばツール類やデバック環境での操作などなど

実行速度を求めだすと、やはりこれらは使えないかな。。
私的には最後はC風の自作コンテナが攻めるところになってくるのかと思います
(そこまでやっても、実は対して高速化できないんですけどねぇ
 それよりは、ポリゴン数減らす方がよっぽど速度向上になるんですけど
 プログラマの頑張りどころではあるので、こういうところに行き着くのかも。。)


*オーダリングテーブルなどは高速化対象になる

オーダリングテーブルとは、3D描画処理を行う場合によく使用されます
自分(カメラ)から見て奥のもの、つまり遠くのものから書いていく必要があります
不透明なオブジェクトばかりの場合(建物とか人物とか)ピクセル単位のZバッファがかかるので、あまり意識しなくても良いのですが、半透明のオブジェクトを描画するときには、既に自分より奥のものを描画し終わっている必要があります

というわけで、奥のものから順に描画していくための仕組みがオーダリングテーブルです
プログラマはオーダリングテーブルに自分の描画したいポリゴンを登録しておけば
あとは描画システムがそのテーブル順に描画していくことになります

例えばZバッファ(奥行)を1024段階(程度)に分割します
自分のオブジェクトの位置(ポジション)を1024段階のどこに相当するか、割り当てます
その後、奥から順にレンダリングしていきます

// 分かりやすく書くとvectorで
vector <Ordering_tbl> ot;
for( i = 0; i < ot.size(); ++ i ){
ot[i].draw();
}

こういう部分は高速化のやりがいがあるところです
使用する立場から見ると、各ot[n]の中がさらにリンクになっていると、効果抜群です
ばかみたいですが、過去に自作リンク作ったことがあるので、参考までに


他に余談ですが、いわゆる「生ポインタ」の隠ぺいなどは、実はあまり考えてなかったような気がします
生ぽ使うな!ってことは、使用者のスキルが低いときには大変有効です、新人さんと組むとか
もちろん、ケアレスミスを防ぐ意味では、有識者に対しても効果ありなのですが、そこに力を注ぐ風潮は、わたしの周りにはあんまり無かったかな。。
やっぱり昔ながらのアセンブラ上がりの方も多かったため、今の風潮にはマッチしてないのかもしれませんね

だらだらと書いてしまいました
どうぞ、今年もよろしくお願いします

haruka_sao at 23:50コメント(0)トラックバック(0)C++ | プログラミング 

トラックバックURL

コメントする

名前:
URL:
  情報を記憶: 評価:  顔   星
 
 
 
Sao's Tech Memo
mvp_logo_140

Microsoft MVP for Windows Development
[Jan,2016-Dec,2017]
Microsoft MVP for Windows
Platform Development
[Jan,2015-Dec,2015]
Microsoft MVP for
Client Development
[Jan,2014-Dec,2014]
Microsoft MVP for Client App Dev [Jan,2010-Dec,2013]
Recent Comments
訪問者数
  • 今日:
  • 昨日:
  • 累計:

記事検索