Chiharu の日記

絵描き C/C++ プログラマーの日記です。

Parallel force - パラレル・フォース 〜SSE2 苦戦

まさかの凡ミス。SSE2 用の組み込み関数の意味をとり間違えていました。テストしてたらα値付きイメージのフェードで色化け。調べてみると、驚愕の事実。_mm_mul_epu32 がまさか 32bit x 32bit = 64bit だったなんて!普通に乗算結果の下位 32bit を期待していたのですが…。私が期待していた処理は _mm_mullo_epi32 らしく、これは SSE4 でのサポートの様子。くっそー。Intel め。足元見やがって!こんちくしょー!!こっちは Pentium M / Pentium 4 世代からサポートしたいのに、SSE4 て。仕方がないです。このフローの最適解ではないけれど、ルーチン書き換えます…。
(追記)
結局、速度重視につき、演算精度を落として対応しました。落としたのは、0-255 → 0-256 レンジ変換処理。といっても、プログラム中では輝度が統一されるため、演算精度の低下に起因する描画内容の破綻はありません。また、レンジの下端と上端の保証は変わらないので、まぁ、目視確認は多分不能な程度の精度低下です。α値の中間階調が若干変わる程度です。
具体的には...

inline const PixPacked32 convertRange255to256(const PixLevel iPixLevel)
{
  // return iAlpha * 256 / 255;
  return iPixLevel * 65794 / 65536;  // 0-255 → 0-256
}

上記が...

inline const PixPacked32 convertRange255to256(const PixLevel iPixLevel)
{
  // return iAlpha * 256 / 255;
  return iPixLevel * 129 / 128;  // 0-255 → 0-256
}

このように変わりました。利点は SIMD でのレンジ変換時に、16bit 精度で計算できることです。α値のレンジ変換時の乗算が _mm_mullo_epi16 で計算できるようになりました。従来処理は 32bit 精度が必要でした。中間階調の傾きが若干きつくなりましたが、まぁ、問題ない範囲でしょう。