アルファブレンディングを計算するときは、8ビットのアルファをfloatに変換する必要があります。これはalpha/255になります。NEONには除算がないので、アルファ*1/255にします。では、q1で1/255ベクトルを生成するにはどうすればよいですか?
vmov.f32 q1、#0.003921569は常にエラーを報告します。
vmov.u32 q1、#255 vrecpe.u32 q1、q1は常にf32で0を生成します。
あなたは近くにいます。逆数を取る前に、255のベクトルをfloatに変換する必要があります。
vmov.u32 q0, #255
vcvt.f32.u32 q0, q0
vrecpe.f32 q1, q0
vrecpe
多少の誤差がありますが、アルファブレンディングには十分に近いはずです。
100%の答えではありませんが、これまで他に何も得られなかったので、私はあなたが始めるのを手伝うと思いました。
私が覚えていることから、使用してロードできるフロートのサブセットvmov.f32
は非常に限られているため、任意のフロートをロードする場合は、定数として格納し、を使用して定数プールからロードする必要がありますvldr
。このような何かがそれを行う必要があります。
ldr r1,=floats
vldr.32 s0,[r1] @1/256
floats:
.float 0.003921569
「100%ではない」部分は、ベクトル命令を調べていないため、このコードでs0
すぐに置き換えることができるかどうか、またはロード後に移動する必要があるかどうかがわかりません。q1
s0
q1
些細なアルファブレンドの場合、浮動小数点を気にする必要はありません。与えられた:
y = rint(x * a / 255.0);
以下を使用すると、浮動小数点なしで8ビット入力に対して同じ結果を得ることができます。
t = x * a;
t += (t + 0x80) >> 8;
y = (t + 0x80) >> 8;
これは次のようなものです:
; given eight 8-bit x in d0, and eight 8-bit a in d1
vmull.u8 q2, d0, d1
vrsra.u16 q2, q2, #8
vrshrn.u16 d2, q2, #8
; result is eight 8-bit (s*a/255) in d2
一般に、最後の2つの演算は、16ビット入力から8ビット出力への255による適切な除算を実装します。しかし、それらは8行8列の乗算の限られた範囲に依存しています。16ビット中間体が乗算の結果以上のものである場合は、クランプする必要があるかもしれません。シーケンスがないvqrsra
ため、シーケンスが長くなります。
; given eight 8-bit x in d0, and eight 8-bit a in d1
vmull.u8 q2, d0, d1
???
vrshr.u16 q3, q2, #8
vqadd.u16 q2, q2, q3
vqrshrn.u16 d2, q2, #8
; result is eight 8-bit (s*a/255) in d2
おそらくfloat32x4_tx= vdupq_n_32(1.0f / 255);が必要です。
コンパイラは定数の計算に注意を払い、vdup命令は値をベクトルの4つのレーンすべてにブロードキャストします
vdup命令は、ソースオペランドとしてNEONスカラーとARMレジスタをサポートします