色深度が 8bit のアルファブレンドの計算式の定義を以下とする。
(dest * (255 - alpha) + src * alpha + 127) / 255
これを高速化するにはどうするか? 除算は遅いのでシフト演算などに変形するのが定石。
よく見かけるのが 255 ≒ 256 と見做してシフト演算に置き換えるだけの方法。
(dest * (255 - alpha) + src * alpha + 128) >> 8
255 → 256 では 1/255 の誤差がある。値域が 0~255 の計算においてこれは無視できない。
(実際に使ってみるとわかるが、最大値の 255 が得られないためブレンドを重ねるとだんだん暗くなる。)
では、16bit に桁を増やせば誤差が 1/65535 となって無視できるのではないだろうか?
まずは 255 での除算を 65535 での除算に変形してみる。
$\frac{x}{255} = \frac{x}{256 - 1} = \frac{(256 + 1)x}{(256 + 1)(256 - 1)} = \frac{257x}{65535}$
ということで 257 をかけてから 65535 で割る。
((dest * (255 - alpha) + src * alpha) * 257 + 32767) / 65535
そして 65535 ≒ 65536 と見做してシフト演算に置き換え。
((dest * (255 - alpha) + src * alpha) * 257 + ???) >> 16
??? の箇所は実際にプログラムで試してみて誤差が出なくなる値を見つけよう。
アセンブラで書く場合は x * 257
→ (x << 8) + x
といった細かな式変形も忘れずに。
さらに SIMD 命令を利用すると RGBA のブレンドを同時に行うことが可能。