情報を伝達せよ

そういう訳でウチのマシンのメモリ転送速度を計測してみました。

 計測部はこんな感じのコードです。

	//グローバルで確保
	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(