5

私の画像処理プロジェクトはグレースケール画像で動作します。ARM Cortex-A8 プロセッサ プラットフォームを使用しています。NEONを活用したい。

私はグレースケールの画像を持っています (以下の例を考えてください)。私のアルゴリズムでは、列のみを追加する必要があります。

4 つの 8 ビット ピクセル値( uint8_t ) を4 つの uint32_tとして128 ビット NEON レジスタの 1 つに並列にロードするにはどうすればよいですか? これを行うには、どの組み込み関数を使用する必要がありますか?

つまり:

代替テキスト

よく見ると、255 + 255 を実行する瞬間は 512 であり、8 ビット レジスタに保持できないため、32 ビットとしてロードする必要があります。

例えば

255 255 255 255 ......... (640 pixels)
255 255 255 255
255 255 255 255
255 255 255 255
.
.
.
.
.
(480 pixels) 
4

5 に答える 5

11

SIMD が ARM でどのように機能するかを理解するために少し時間を費やすことをお勧めします。見る:

を見てみましょう:

  1. http://blogs.arm.com/software-enablement/161-coding-for-neon-part-1-load-and-stores/
  2. http://blogs.arm.com/software-enablement/196-coding-for-neon-part-2-dealing-with-leftovers/
  3. http://blogs.arm.com/software-enablement/241-coding-for-neon-part-3-matrix-multiplication/
  4. http://blogs.arm.com/software-enablement/277-coding-for-neon-part-4-shifting-left-and-right/

始めましょう。次に、インライン アセンブラまたは domen が推奨する対応する ARM 組み込み関数を使用して、SIMD コードを実装できます。

于 2010-09-09T22:38:11.043 に答える
5

コンパイラと(おそらく不足している)拡張機能によって異なります。

つまり。GCCの場合、これが出発点になる可能性があります:http: //gcc.gnu.org/onlinedocs/gcc/ARM-NEON-Intrinsics.html

于 2010-09-09T11:01:41.420 に答える
3

最大 480 個の 8 ビット値を合計する必要がある場合、技術的には 17 ビットの中間ストレージが必要になります。ただし、加算を 2 段階、つまり、上位 240 行と下位 240 行で実行すると、それぞれ 16 ビットで実行できます。次に、2 つの半分の結果を加算して、最終的な答えを得ることができます。

実際には、vaddw と呼ばれるアルゴリズムに適した NEON 命令があります。dword ベクトルを qword ベクトルに追加し、後者には前者の 2 倍の幅の要素が含まれます。あなたの場合、vaddw.u8 を使用して、8 つのピクセルを 8 つの 16 ビット アキュムレータに追加できます。次に、vaddw.u16 を使用して、8 つの 16 ビット アキュムレータの 2 つのセットを 8 つの 32 ビット アキュムレータの 1 つのセットに追加できます。両方の半分を取得するには、命令を 2 回使用する必要があることに注意してください。

必要に応じて、vmovn または vqmovn を使用して、値を 16 ビットまたは 8 ビットに戻すこともできます。

于 2010-10-25T20:56:46.757 に答える
2

4 つの 8 ビット値を 4 つの 32 ビット レジスタにロードできる命令はありません。

それらをロードしてから、vshl を 2 回使用する必要があります。ネオンは 32 個のレジスタを使用できないため、4 ピクセルではなく 8 ピクセルで作業する必要があります。

16 ビットレジスタのみ使用できます。十分なはずです...

于 2011-04-09T15:18:14.733 に答える
0

シングル レーン ロード命令 ( vld1 <register>[<lane>], [<address]) を使用して 4 バイトを q レジスタにロードし、次に 2 つのムーブ ロング命令 ( vmovl) を使用して、それらを最初に 16 ビットに、次に 32 ビットにプロモートします。結果は次のようになります (GNU 構文で)

vld1 d0[0], [<address>] @Now d0 = (*<addr>, *<addr+1>, *<addr+2>, *<addr+3>, <junk>, ... <junk> )
vmovl.u8 q0, d0 @Now q1 = (d0, d1) = ((uint16_t)*<addr>, ... (uint16_t)*<addr+3>, <junk>, ... <junk>)
vmovl.u16 q0, d2 @Now d0 = ((uint32_t)*<addr>, ... (uint32_t)*<addr+3>), d1 = (<junk>, ... <junk>)

<address>4 バイト アラインされていることが保証できる場合は[<address>: 32]、代わりにロード命令に書き込み、1 ~ 2 サイクル節約します。ただし、それを行ってアドレスが整列されていない場合は、エラーが発生します。

ええと、アセンブリではなく組み込み関数を使用する必要があることに気付きました。組み込み関数についても同じことが言えます。

uint32x4_t v8; // Will actually hold 4 uint8_t
v8 = vld1_lane_u32(ptr, v8, 0);
const uint16x4_t v16 = vget_low_u16(vmovl_u8(vreinterpret_u8_u32(v8)));
const uint32x4_t v32 = vmovl_u16(v16);
于 2012-08-07T16:47:25.673 に答える