Chiharu の日記

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

Parallel force - パラレル・フォース 〜SSSE3 乗加算、惜しい!

_mm_maddubs_epi16 を使用したαブレンディングですが、再考察したところ、0-256 は無理ですが、0-128 ならいけますね。α値が 0 のケースはそもそも上流で描画をカットしていますし、またα値が 128 (=256) の場合は上流で単純転送に振り分けています。つまり、0-128 の範囲でブレンドする場合、実際のブレンド関数に渡されるα値は 1-127 となります。これなら当該組み込み関数の乗数として収まる範囲、と。
んー。惜しいなぁ。精度 1/2 かぁ。符号なし演算なら文句なしに採用できたんですが。むー。
(追記)
どうにも悔しかったので、_mm_maddubs_epi16 で高速化しつつ精度を落とさない方法をもう一回考えてみました。
α値が 0-128 (1-127) の範囲であれば、当該組み込み関数が問題なく導入できることは上述のとおりです。この条件は 0-256 (1-255) 精度のα値に対して、下位 1bit 分の精度を捨てることと同義です。しかし、α値の全てのケースで精度低下が発生するわけではありません。0-256 (1-255) 精度でも、α値が偶数の場合は下位 1bit が必ず 0 となるため、当該ビットを切り捨てても精度問題が発生しないことになります。
このことから、α値の精度を 0-256 (1-255) の範囲で保つことを前提に、問題をα値が偶数の場合と奇数の場合に分けて考えます。
※以降、式中の変数は全て整数、かつ演算過程で発生する小数桁は発生時点で全て切り捨てとします。
成立させたいのは下記の式で、_mm_maddubs_epi16 利用のために dst と src に対する乗数(下記の 256 - alpha と alpha に相当)を、符号付 8bit 整数(正の数: 0-127)の範囲に収める必要があります。


dst' = (dst * (256 - alpha) + src * alpha) / 256
※alpha は 1-255 の範囲
α値が偶数の場合、下記の式が成立します。

dst' = (dst * (128 - alpha / 2) + src * alpha / 2) / 128
※alpha は偶数かつ 2-254 の範囲
上式において、dst と src に対する乗数である 128 - alpha / 2 と alpha / 2 はいずれも 0-127 の範囲に収まっており、符号付 8bit 整数で表現可能です。これで下線部に _mm_maddubs_epi16 が適用できるようになります。ここまでは想定どおり。
次。
α値が奇数の場合、下記の式が成立します。

dst' = (dst * (128 - alpha / 2) + src * alpha / 2 + (-dst + src) / 2) / 128
※alpha は奇数かつ 1-255 の範囲
下線部が偶数との相違点です。上式において、alpha / 2 は必ず端数 0.5 が発生しますが、上式は全て整数演算につき、これが切り捨てられます。この端数を拾うため、dst には負の方向へ 0.5、src には正の方向へ 0.5 を掛けて(2 で割って)補正を加えています。
んー。dst と src の乗数が 0-127 の範囲に収まっておらず、また、SIMD 化にはちょっと数式が複雑ですね。変形して SIMD を適用しやすくしましょう。

dst' = (dst * (128 - alpha / 2) + src * alpha / 2 + (-dst + src) / 2) / 128
dst' = (dst * (128 - alpha / 2) + src * alpha / 2 + (dst + src) / 2 - dst) / 128
dst' = (dst * (127 - alpha / 2) + src * alpha / 2 + (dst + src) / 2) / 128
とできました。すると、

dst' = (dst * (127 - alpha / 2) + src * alpha / 2 + (dst + src) / 2) / 128
※alpha は奇数かつ 1-255 の範囲
上式において、dst と src に対する乗数である 127 - alpha / 2 と alpha / 2 はいずれも 0-127 の範囲に収まっており、符号付 8bit 整数で表現可能です。これで下線部にそれぞれ _mm_maddubs_epi16 と _mm_avg_epu8 が適用できるようになりました。
ここまででなんとなく、_mm_maddubs_epi16 がαブレンディングに使えそうな雰囲気になってきました。まぁ。上式が間違っていなければ、の話ですけどね。今日は眠いので、明日にでも実装して答え合わせをしてみます。合っていたら正式採用です。
―――んー。えらそうに説明しちゃったけど、ちゃんとあってるのかなぁ。ちょっと不安。