MMXとか使ってみたり

ペンの大きさを変えられるようにして、気づいたのですが、ペンの半径を100などに設定すると処理が非常に遅くなります。
ということで、何かしらの高速化を。

調べてみると、アルファブレンディングMMXを使って高速化している人が多いので、やってみました。
ストロークを書く時や画面の更新の際にはアルファ処理をバンバンやっているので、そこそこ影響はあると思います。
アセンブラなんて、大学2年の機械語序論以来…

参考

まずは、ピクセルアルファブレンディングをやっている部分をMMXで書き換えてみると…
あれ、あんま速くならない。
ベンチをとってみると、遅くなってる…ん〜、なんでだろう。
インラインアセンブラに入る部分が微妙にオーバーヘッドになっているご様子

ということで、今度はアルファ転送を行っている関数自体をアセンブラで書いてみることに。

結果は、アセンブラで書いていないほうが1024×1024のアルファ処理に40msec、アセンブラ+MMXのほうが8msecとかなり速くなりました。
やったね!

ストロークも半径200くらいにしても快適に描けます(エアブラシはちょっと重い)。
ARGB×ARGBのアルファブレンド処理はまだ高速化していないので、ここも改良すれば他のソフト並みに快適にブラシが使えるようになると思います。

誤差が・・・

MMXには割り算なんて便利なものがないわけで、当然シフト演算で代用するわけです。
しかしながら、アルファブレンドの計算には/255なんて処理が必要になります。
皆さん、8ビットシフトでごまかしているのですが、これをやると薄い所や濃い所で誤差が…
白いストロークを描くと透明なところが黒ずんだり、不透明にならなかったりと不都合が多いので修正を…

いわゆる、固定小数点演算というやつに書き換えます。65536/255かけて16ビットシフトといった具合に。
ここで問題その2。
MMXを使って、ARGBを同時に演算するには、16ビット×4のセットで数値を扱う必要があるわけです。
ARGBの各要素は8ビット使っていて、65536/255と各要素をかける時には、色情報×αの16ビットを使っている状態にあります。
「65536/255かけて16ビットシフト」を行うには、掛け算した結果の32ビットのうち上位16ビットを取ってこれば解決なのですが、
MMXには符号なしパック演算命令がないっぽいのです。
つまり、輝度が高くてアルファ値の高い色要素は負の値として扱われ、それ以外と演算結果が異なります。
ん〜、困った。まぁ、ちゃんと計算すればいいのですが…

で、掛け算結果の上位ビットを取ってくる命令は
pmulhw
らしいので、ダメもとで
pmulhuw
で調べてみたら、あった。

MMX2(ペン!!!以降?)にはこの命令が追加されたらしく、面倒だったのでこの命令を使うことに。
結果、いい感じにアルファブレンドされるようになりました。
ARGB×ARGBの計算でも固定小数点演算をバンバンやる予定なので、これは良かった。

ちなみに、pmulhuwを使わない場合は、以下のページにやり方が

ということで、晴れて高速化に成功。
これは楽しい★