SIMDのVector処理を試してみる2017年09月27日 19:26

画像の明度、彩度を調整する処理について、高速化のためにCPUのSIMDを利用したVector処理を試みる。SSEやAVXといった仕組みである。UWPアプリでは、System.Numericsをusingで導入することで利用できる。参考文献はこちら

Vector定義部分

定義の部分。赤枠内がVectorの定義。明度や彩度の計算には、ピクセルのRGB(各8bit)のそれぞれの値の最大値と最小値の導出、それらの足し引きが必要。vminが最小値、vmaxが最大値、vsumが最大値と最小値の合計、vdeltaが最大値と最小値の差分。データ型はushort。合計を求めるときにbyteでは、オーバフローする。

難しいのは、Vector処理をどこに適用するかの構想。ピクセルはBGRA8で構成されているので、4要素のVector4が思い浮かぶが、明度や彩度の計算では、ピクセル内のBGR相互の演算が必要。これに対応する演算やメソッドは用意されていない。

そこで、今回はBGRそれぞれをバラして、別々のVectorに設定し、同時にBGR間の演算を複数個一括で行うことを考える。バラしてVectorに構成しなおすオーバヘッドと、複数個一括演算の効率向上のせめぎ合い。

いくつ同時に処理できるかは、277行目で取得。手許の環境は、AVXは未実装。SSEになるのか、8を返すので、ushort(16bit)が8個で128bit。

Vector処理部分

処理の本体部分。tryで囲んだ内部で、ピクセルデータを格納するbyte配列からBGRそれぞれのVectorを生成。try catchは、不正なインデックス例外が多発したためのデバッグ用。

次の囲みで、Vector間の大小判定、加減算を行う。

その下のコメントで、乗除算も行っているが、ushortではオーバフローになるし、誤差も大きいので実用にならない。その下のfor文でVectorをバラして、doubleで計算することに。

性能向上度合いはどうか。1024x800程度あれば、数割ほどの短縮。画像が大きくなれば、効果は大きくなる。ただし、実際の操作では、メモリ管理などのオーバヘッドの方が大きく、体感できる効果は大きくない。副作用として、コードが長くなるのと、抽象度が下がる。

この先は、CUDAなどGPUに任せることになるか。OpenCLに手をつけるべきか、どうしたものか。