3回目のMMX

なんとなく遥か昔に24bitカラー(888)から16bitカラー(565)に落とす話題があったのを思い出してこういうのってMMXで速く出来るんじゃないかとまたまた勉強ついでにやってみることにしました(^^;
24bitから16bitに落とすには、厳密にはそれぞれの色をそのままの割合で落とすのですが、どうせ下位bitは無視しても問題ないだろうということで、上位ビットだけ持ってくると速いです。

WORD RGB888TO565( const DWORD rgb888 )
{
	const WORD wr = static_cast< WORD >( ( rgb888 >> 8 ) & 0x0000f800 );
	const WORD wg = static_cast< WORD >( ( rgb888 >> 5 ) & 0x000007e0 );
	const WORD wb = static_cast< WORD >( ( rgb888 >> 3 ) & 0x0000001f );
 	return ( wr | wg | wb );
}

これを全ピクセルについてやるわけです。MMXの利点は64bitを1命令でやってしまうところなので、うまく2ピクセルずつやれば単純計算で2倍の速度がでるはずです。

void RGB888to565( BYTE* pbyColor565, const BYTE* pbyColor888, unsigned int nX, unsigned int nY )
{
	const __int64 maskR = 0x000000f80000f800;
	const __int64 maskG = 0x00000007e00007e0;
	const __int64 maskB = 0x000000001f00001f;

	const unsigned int nSize = nX * nY;

	_asm{
		mov eax, pbyColor565
		mov ebx, pbyColor888

		mov ecx, nSize
		shr ecx, 1
		jz BYTE0
		

		movq mm0, maskR
		movq mm1, maskG
		movq mm2, maskB

	LOOP1:
		movq mm7, [ebx]
		//R
		movq mm3, mm7
		psrl mm3, 8
		pand mm3, mm0

		//G
		movq mm4, mm7
		psrl mm4, 5
		pand mm4, mm1

		//B
		movq mm5, mm7
		psrl mm5, 3
		pand mm5, mm2

		//まぜまぜ
		por mm3, mm4
		por mm3, mm5

		//上のピクセルがずれているので補正
		movq mm6, mm3
		psrl mm6, 24
		punpcklwd mm3, mm6
//		psll mm6, 16
//		por mm3,mm6


		//転送
		movd [eax], mm3

		//次の2ピクセルに移動
		add eax, 4
		add ebx, 6

		dec ecx
		jnz LOOP1


	BYTE0:
		mov  ecx, nSize
		and  ecx, 1
		jz   END
		
		mov ecx, [ebx]

		mov edx, ecx
		shr edx, 8
		and edx, 0000f800h
		mov [eax], dx

		mov edx, ecx
		shr edx, 5
		and edx, 000007e0h
		or [eax], dx

		mov edx, ecx
		shr edx, 3
		and edx, 0000001fh
		or [eax], dx
	END:
		emms
	}
	return;
}

一応、テクスチャが相手だということでXとYに分けてますが一緒です(^^; 今回はSrcとDestでサイズが違うので普通にbyte数にすると誤用される可能性があるということで分けました(ていうか使うのかこれ?)

ようやくMMXらしくなってきました(何) レジスタがたくさんあるのがいいですね。あまり考える必要がない(^^;
今回、勉強のために無駄にpunpcklwdという命令を使ってます。これはアンパック命令というやつらしくて二つの変数の下位(上位)半分を交互に入れるという命令です(詳しくは適当なMMXのページでも見てください)。今回は下位4バイトしか使ってないのでその威力は微々たるものですがまあ勉強のためということで。

んで結果なんですが、普通にコンパイルしたらかなり速かったんですが、最適化コンパイルだと残念ながら殆どかわりませんね。やっぱりちゃんとuとかvとか考えなきゃいけないのかな?
うーん、先は長そうだ(^^;