トップページ > プログラム > 2015年05月20日 > Uv5CefPe

書き込み順位&時間帯一覧

2 位/201 ID中時間01234567891011121314151617181920212223Total
書き込み数41212000000000132102010020



使用した名前一覧書き込んだスレッド一覧
デフォルトの名無しさん
940
【C++】高速化手法【SSE】

書き込みレス一覧

【C++】高速化手法【SSE】
932 :デフォルトの名無しさん[sage]:2015/05/20(水) 00:03:13.46 ID:Uv5CefPe
初心者ですみません。

画像のアルファブレンディング付きコピーを行いたいです。
asm{}ではなく、なんて言うのかは知りませんが、xmmintrin.hに載ってる組み込み関数を使いたいです。
サンプルソースが載っているお勧めサイトはありますか?英語でもかまいません。

また、画像のアルファブレンディング付きコピーのような処理は、SSEで速くなるでしょうか?
どうにもメモリがボトルネックになりそうな気がしてまして。
キャッシュのプリフェッチなんかも必要でしょうか?
【C++】高速化手法【SSE】
934 :デフォルトの名無しさん[sage]:2015/05/20(水) 00:15:39.94 ID:Uv5CefPe
レスサンクス。
速くなるならチャレンジしてみようかしら。
【C++】高速化手法【SSE】
935 :デフォルトの名無しさん[sage]:2015/05/20(水) 00:33:47.38 ID:Uv5CefPe
画像のsrcとdstは32bitのA8R8G8B8で、
これをSIMDでα付き合成したいわけですが、
この場合、MMXを使うべきなのでしょうか?
個人的にはSSE2あたりを使いたいのですが。
__m128だとfloat[4]なので、一度に1dot分ずつしか処理できないんですかね?
128bit長もあるのに。
__m128の定義を見ると、
unsigned __int8 m128_u8[16];
ってのがあるので、8bitの整数処理もサポートしてそうなんですが、
xmmintrin.hを見る限り、使えそうな関数が無いのですが、
どうすればよいんでしょうか?
【C++】高速化手法【SSE】
936 :デフォルトの名無しさん[sage]:2015/05/20(水) 00:58:40.19 ID:Uv5CefPe
__m128i _mm_adds_epi8(__m128i a, __m128i b);
8bitの飽和加算はみつけたんだが、乗算が見つからん。たすけてくり〜〜
【C++】高速化手法【SSE】
937 :デフォルトの名無しさん[sage]:2015/05/20(水) 01:10:31.88 ID:Uv5CefPe
__m128 _mm_cvtpu8_ps(__m64 a)
もうよく分からないので↑つかってfloat[4]に変換して
1dotずつ計算します。
整数演算でよいのに浮動小数点使うのはなんか釈然としませんが。
【C++】高速化手法【SSE】
940 :デフォルトの名無しさん[sage]:2015/05/20(水) 02:10:09.47 ID:Uv5CefPe
auto &d = dst; auto &s = src;
__m64 d64, s64;
d64.m64_u32[0] = d; s64.m64_u32[0] = s;
__m128 d128 = _mm_cvtpu8_ps( d64 ); __m128 s128 = _mm_cvtpu8_ps( s64 );
float f256 = 256.0f, finv256 = 1.0f/256.0f, f1 = 1.0f;
__m128 _1 = _mm_load1_ps( &f1 );
__m128 _256 = _mm_load1_ps( &f256 );
__m128 _inv256 = _mm_load1_ps( &finv256 );
d128 = _mm_mul_ps( d128, _inv256 ); s128 = _mm_mul_ps( s128, _inv256 );
__m128 a128 = _mm_load1_ps( s128.m128_f32+3 );
__m128 _1_sub_a128 = _mm_sub_ps( _1, a128 );
d128 = _mm_mul_ps( d128, _1_sub_a128 ); s128 = _mm_mul_ps( s128, a128 );
d128 = _mm_add_ps( d128, s128 ); d128 = _mm_mul_ps( d128, _256 );
d64 = _mm_cvtps_pi16( d128 );
auto ar = d64.m64_u16; d = (0xFF<<24)|(ar[2]<<16)|(ar[1]<<8)|(ar[0]);
一応出来ました。まだ飽和処理してませんが。速くなったかどうかは分かりませぬ。
【C++】高速化手法【SSE】
942 :940[sage]:2015/05/20(水) 02:33:37.51 ID:Uv5CefPe
上記のコードですが、SSEを使わない下記のコードと比べてとても遅いです。当然Releaseでです。
auto &d = dst; auto &s = src;
uint32_t a = s>>24;
uint32_t dr = 0xFF&(d>>16);
uint32_t dg = 0xFF&(d>>8);
uint32_t db = 0xFF&d;
uint32_t sr = 0xFF&(s>>16);
uint32_t sg = 0xFF&(s>>8);
uint32_t sb = 0xFF&s;
uint32_t r = ( dr * (255-a) + sr * a )>>8;
uint32_t g = ( dg * (255-a) + sg * a )>>8;
uint32_t b = ( db * (255-a) + sb * a )>>8;
d = (0xFF<<24)|(r<<16)|(g<<8)|(b);
私の努力は無意味だったようです。
【C++】高速化手法【SSE】
945 :デフォルトの名無しさん[sage]:2015/05/20(水) 03:48:44.67 ID:Uv5CefPe
floatの計算と定数のセットをループの外部に追いやってもやっぱり遅いです。
私が思うに、いくら並列計算をするといっても、
たかが整数8bitの計算に浮動小数点を使うのは馬鹿げていたのではないかと。
おそらくですが、整数⇔浮動小数点 の変換が重たいのではないかと想像しています。
画像のアルファブレンディングのような処理は、MMXですべきだったのかもしれません。
_mm_mulhi_pi16を使ってみようかと思います。
【C++】高速化手法【SSE】
948 :940[sage]:2015/05/20(水) 04:44:30.33 ID:Uv5CefPe
__m64 d64, s64, a64, b64;
d64.m64_u16[0] = 0xFF&(d_>>16);d64.m64_u16[1] = 0xFF&(d_>>8);d64.m64_u16[2] = 0xFF&(d_>>0);
s64.m64_u16[0] = 0xFF&(s_>>16);s64.m64_u16[1] = 0xFF&(s_>>8);s64.m64_u16[2] = 0xFF&(s_>>0);
a64.m64_u16[0] = 0xFF&(s_>>24);a64.m64_u16[1] = 0xFF&(s_>>24);a64.m64_u16[2] = 0xFF&(s_>>24);
b64 = _mm_subs_pu16( _255, a64 );
d64 = _mm_mullo_pi16( d64, b64 );
s64 = _mm_mullo_pi16( s64, a64 );
d64 = _mm_add_pi16( d64, s64 );
uint32_t r = d64.m64_u16[0]>>8;
uint32_t g = d64.m64_u16[1]>>8;
uint32_t b = d64.m64_u16[2]>>8;
d = (0xFF<<24)|(r<<16)|(g<<8)|(b);
浮動小数点演算を使わないように、上記のように書き直してみましたが、
>>942のコードよりも3倍遅くなりました。もう嫌です。
【C++】高速化手法【SSE】
949 :デフォルトの名無しさん[sage]:2015/05/20(水) 04:52:06.80 ID:Uv5CefPe
画像の合成はDirectXさんに頑張ってもらうことにします。
【C++】高速化手法【SSE】
964 :940[sage]:2015/05/20(水) 14:46:38.07 ID:Uv5CefPe
あれからまた少し頑張ってました。
__m64 d64, s64, a64, b64;
d64.m64_u64 = *d; d64 = _mm_unpacklo_pi8( d64, _0 );
s64.m64_u64 = *s; s64 = _mm_unpacklo_pi8( s64, _0 );
uint32_t a = (0xFF000000&(*s))>>24;
a64.m64_u32[0] = a|(a<<8)|(a<<16); a64 = _mm_unpacklo_pi8( a64, _0 );
b64 = _mm_subs_pu16( _255, a64 );
d64 = _mm_mullo_pi16( d64, b64 );
s64 = _mm_mullo_pi16( s64, a64 );
d64 = _mm_add_pi16( d64, s64 );
d64 = _mm_srli_pi16( d64, 8 );
d64 = _mm_packs_pu16( d64, s64 );
*d = d64.m64_u32[0];
最初のころの>>940や>>948のコードと比べるとだいぶ良くなってきましたが、
それでも何も考えずに書いた>>942のコードよりも2倍遅いです。
3倍から2倍になったので進歩はしましたが・・・。
【C++】高速化手法【SSE】
965 :940[sage]:2015/05/20(水) 15:07:11.63 ID:Uv5CefPe
__m128を使えば2dot同時に処理できるのでもう少し速くなるかもしれませんが、
>>964の時点で何も考えずに書いたコード>>942よりも2倍遅いので、
このまま__m128化しただけではどうにもなりませんね。
【C++】高速化手法【SSE】
968 :デフォルトの名無しさん[sage]:2015/05/20(水) 15:23:09.81 ID:Uv5CefPe
いい組み込み関数が見つかったので、アルファ値のセットの部分を変更しました。
ちっとも速くなりませんでしたが。
__m64 d64, s64, a64, b64;
d64.m64_u64 = *d; d64 = _mm_unpacklo_pi8( d64, _0 );
s64.m64_u64 = *s; s64 = _mm_unpacklo_pi8( s64, _0 );
uint16_t a = (0xFF000000&(*s))>>24; a64 = _mm_set1_pi16( (short)a );
b64 = _mm_subs_pu16( _255, a64 );
d64 = _mm_mullo_pi16( d64, b64 );
s64 = _mm_mullo_pi16( s64, a64 );
d64 = _mm_add_pi16( d64, s64 );
d64 = _mm_srli_pi16( d64, 8 );
d64 = _mm_packs_pu16( d64, _0 );
*d = d64.m64_u32[0];
【C++】高速化手法【SSE】
973 :デフォルトの名無しさん[sage]:2015/05/20(水) 15:37:34.28 ID:Uv5CefPe
それでちょっと考えたのですが、今のCPUはすっごいスーパースカラーが有るので、
今回のようにrgb各要素は依存関係が無いが、1dot全体では処理順に依存関係が出てしまっている場合、
SIMD化は意味が無いのかもしれません。
>>942のコードは、rgb各要素に対してスーパースカラーが働く。
SIMD化した>>968は、rgb各要素はSIMD化しているし、
演算に依存関係があるのでスーパースカラーの働く余地は無い。
よって、SIMD化のオーバーヘッドだけが付きまとうと。
なので、SIMD化した後もスーパースカラが働くように、
並列化の方向を array of structure から structure of array に変える必要があるのかもしれません。
つまり、mr = ( r1,r2,r3r,4 ), mg = ( g1, g2, g3, g4 ), mb = ( b1,b2,b3,b4 ) として、
1ループで4dot同時に処理すると。こうすればスーパースカラーが働きますよね。
ただ、もっと単純に、ループアンローリングして、複数のピクセルの処理をまぜこぜにして書いて、
スーパースカラーを促したほうが、楽そうです。どちらが良いでしょうか?
>>967
それは修正しました。
【C++】高速化手法【SSE】
978 :デフォルトの名無しさん[sage]:2015/05/20(水) 16:08:36.79 ID:Uv5CefPe
_mm_unpacklo_pi8ってそんなに遅いんですか?
【C++】高速化手法【SSE】
982 :940[sage]:2015/05/20(水) 16:49:29.01 ID:Uv5CefPe
だんごさんの方式で適当に書いた>>942のコードより、4倍速くなりました!!
ありがとうございました。大変勉強になりました。4倍は凄いことです
【C++】高速化手法【SSE】
983 :940[sage]:2015/05/20(水) 17:15:33.68 ID:Uv5CefPe
でも _mm_mullo_epi32 は SSE4からなんだよねぇ。
Core2の途中ぐらいから対応か・・・。
_mm_mullo_epi32を使わないとなると、あんま綺麗にまとまらんよねぇ。
どうしたものか。
【C++】高速化手法【SSE】
993 :940[sage]:2015/05/20(水) 19:43:33.43 ID:Uv5CefPe
_mm_mullo_epi32 が SSE4からなのが嫌だったので、
いったんfloatに変換してから掛け算してまた戻すようにした。
時間が1.18倍になった。
また、_mm_castps_si128を二回使う方法で代用してみた。
時間がが1.39倍になった。
【C++】高速化手法【SSE】
994 :940[sage]:2015/05/20(水) 19:56:59.95 ID:Uv5CefPe
_mm_packs_epi32
ほうほうこんないいものがあったのか。
8dot一気に処理できそうな予感
【C++】高速化手法【SSE】
996 :940[sage]:2015/05/20(水) 21:24:41.69 ID:Uv5CefPe
とりあえず、だいんごさんの方法で、読み込んで、
uint32_t[4]をuint16_t[8]にpackする方法で、元の適当なコード比で5倍近くの速度が出たので、
これで良しとします。


※このページは、『2ちゃんねる』の書き込みを基に自動生成したものです。オリジナルはリンク先の2ちゃんねるの書き込みです。
※このサイトでオリジナルの書き込みについては対応できません。
※何か問題のある場合はメールをしてください。対応します。