情報を伝達せよ
そういう訳でウチのマシンのメモリ転送速度を計測してみました。
計測部はこんな感じのコードです。
//グローバルで確保 BYTE p[4*800*600]; BYTE q[4*800*600]; ... //実働部分 CTimer timer; timer.Set(0); timer.Reset(); for(int j=0;j<6000;++j) { for(int i=0;i<4*800*600;++i) { p[i] = q[i]; } } CDbg().Out(timer.Get());
4*600*800(XRGB8888を想定)の画像転送のつもり。6000回試行したのを5回記録取って平均を出します。
計測結果A(単位:ミリ秒)
53890 / 6000 = 8.9817
56660 / 6000 = 9.4433
54700 / 6000 = 9.1167
53767 / 6000 = 8.9612
55726 / 6000 = 9.2877
平均:9.1581
……? 9.1581ms? ということは1秒間に転送できるのは1000/9.1581=約109枚。これだと30FPSで3.6枚、60FPSなら1.8枚。全然駄目じゃん……(当初の予定では60FPSで5〜6枚転送したかった(前回の日記を参照))。
いや、ちょっと待て。いくらなんでもこりゃ遅すぎだよ。XRGB8888->XRGB8888なんだから1バイトじゃなくて、4バイト単位で転送していいんじゃないか? あと大容量データ転送なんだからQWORD境界アラインも取らないと。
コードを修正して再試行
//グローバルで確保 BYTE * m_pPtr; unsigned int * m_pBits; BYTE * m_pPtr2; unsigned int * m_pBits2; ... //実働部分 m_pPtr = new BYTE[4 * 600 * 800 + 7]; m_pPtr2 = new BYTE[4 * 600 * 800 + 7]; m_pBits = (unsigned int * )( *1; delete m_pPtr; delete m_pPtr2;
計測結果B(単位:ミリ秒)
54264 / 6000 = 9.044
54376 / 6000 = 9.063
53987 / 6000 = 8.998
53659 / 6000 = 8.943
54095 / 6000 = 9.016
平均:9.0128
1秒間の転送枚数:約111枚
30FPSで1フレーム中に転送できる枚数:3.7枚
同60FPS:1.85枚
全然変わらねえorz
(総論)
無し!
(長い余談)
マシン語でキチキチなコード書いたり、ループ展開するとかしなければ、これくらいが(少なくともみはえるのマシンの通常環境では)適正速度と考えられます。画像描画する場合にはこれを逆算して枚数を決める事にします。と言っても、これはあくまでウチのスペックなので、平均を考えるともう少し低めに見積もった方がいいのでしょうね……。
計測結果Aの方は、バイト単位でコピーしてるので、αブレンディングのシミュレートとも考えられそうです(もっと遅くなるでしょうが)。こうなると、先日書いたみはえるの希望は絵に描いた餅(用法変じゃないか?)。反省。
でまあ、この結果を踏まえてもう一度考えてみました。
αブレンディング転送が必要なプレーンは実際にはそんなに多くは無いし、ましてや全画面転送するような事は無い。α値の付いた文字を描画するのだって、毎回全ての文字を転送しなくても、一度描画した分はどこかにストックしておいてXRGB転送すればいい(キャラ絵だって一度背景に載せたら丸ごと保存して置けばいい)。
よって、毎フレームARGB転送が必要なプレーンは、ごく一部に限定できる。
という結論になりました。「全部の画像をYGA/ARGB8888で保存して、なんでもかんでもBltAlphaFastで転送すれば管理が楽じゃーん」とか言ってた自分を恥じます。
師匠、今回もご指導ありがとうございました。毎度毎度不肖な弟子ですまんですm(__)m。
*1:unsigned int)m_pPtr + 7) & ~7 ); m_pBits2 = (unsigned int * )( ((unsigned int)m_pPtr2 + 7) & ~7 ); CTimer timer; timer.Set(0); timer.Reset(); for(int j=0;j<6000;++j) { for(int i=0;i<800*600;++i) { m_pBits[i] = m_pBits2[i]; } } CDbg().Out(timer.Get(