7
私はタイトなループで双線形補間を実装しており、SSEで最適化しようとしていますが、速度がゼロになります。ここSSE双線形補間
非SIMDバージョンが実装され、乗算および加算演算子でstruct Vec3f { float x, y, z; }
として定義することができる単純なベクター構造を使用して、コードされ:
#ifdef USE_SIMD
const Color c11 = pixelCache[y1 * size.x + x1];
const Color c12 = pixelCache[y2 * size.x + x1];
const Color c22 = pixelCache[y2 * size.x + x2];
const Color c21 = pixelCache[y1 * size.x + x2];
__declspec(align(16)) float mc11[4] = { 1.0, c11.GetB(), c11.GetG(), c11.GetR() };
__declspec(align(16)) float mc12[4] = { 1.0, c12.GetB(), c12.GetG(), c12.GetR() };
__declspec(align(16)) float mc22[4] = { 1.0, c22.GetB(), c22.GetG(), c22.GetR() };
__declspec(align(16)) float mc21[4] = { 1.0, c21.GetB(), c21.GetG(), c21.GetR() };
// scalars in vector form for SSE
const float s11 = (x2-x)*(y2-y);
const float s12 = (x2-x)*(y-y1);
const float s22 = (x-x1)*(y-y1);
const float s21 = (x-x1)*(y2-y);
__declspec(align(16)) float ms11[4] = {1.0, s11, s11, s11};
__declspec(align(16)) float ms12[4] = {1.0, s12, s12, s12};
__declspec(align(16)) float ms22[4] = {1.0, s22, s22, s22};
__declspec(align(16)) float ms21[4] = {1.0, s21, s21, s21};
__asm {
movaps xmm0, mc11
movaps xmm1, mc12
movaps xmm2, mc22
movaps xmm3, mc21
movaps xmm4, ms11
movaps xmm5, ms12
movaps xmm6, ms22
movaps xmm7, ms21
mulps xmm0, xmm4
mulps xmm1, xmm5
mulps xmm2, xmm6
mulps xmm3, xmm7
addps xmm0, xmm1
addps xmm0, xmm2
addps xmm0, xmm3
movaps mc11, xmm0
}
#else
const Vec3f c11 = toFloat(pixelCache[y1 * size.x + x1]);
const Vec3f c12 = toFloat(pixelCache[y2 * size.x + x1]);
const Vec3f c22 = toFloat(pixelCache[y2 * size.x + x2]);
const Vec3f c21 = toFloat(pixelCache[y1 * size.x + x2]);
const Vec3f colour =
c11*(x2-x)*(y2-y) +
c21*(x-x1)*(y2-y) +
c12*(x2-x)*(y-y1) +
c22*(x-x1)*(y-y1);
#endif
がレジスタを再利用するために、ASMコードを整理(終わっ3つのxmmレジスタのみ)は何の効果ももたらさなかった。私はまた、組み込み関数を使って試しました。
// perform bilinear interpolation
const Vec3f c11 = toFloat(pixelCache[y1 * size.x + x1]);
const Vec3f c12 = toFloat(pixelCache[y2 * size.x + x1]);
const Vec3f c22 = toFloat(pixelCache[y2 * size.x + x2]);
const Vec3f c21 = toFloat(pixelCache[y1 * size.x + x2]);
// scalars in vector form for SSE
const float s11 = (x2-x)*(y2-y);
const float s12 = (x2-x)*(y-y1);
const float s22 = (x-x1)*(y-y1);
const float s21 = (x-x1)*(y2-y);
__m128 mc11 = _mm_set_ps(1.f, c11.b, c11.g, c11.r);
__m128 mc12 = _mm_set_ps(1.f, c12.b, c12.g, c12.r);
__m128 mc22 = _mm_set_ps(1.f, c22.b, c22.g, c22.r);
__m128 mc21 = _mm_set_ps(1.f, c21.b, c21.g, c21.r);
__m128 ms11 = _mm_set_ps(1.f, s11, s11, s11);
__m128 ms12 = _mm_set_ps(1.f, s12, s12, s12);
__m128 ms22 = _mm_set_ps(1.f, s22, s22, s22);
__m128 ms21 = _mm_set_ps(1.f, s21, s21, s21);
mc11 = _mm_mul_ps(mc11, ms11);
mc12 = _mm_mul_ps(mc12, ms12);
mc22 = _mm_mul_ps(mc22, ms22);
mc21 = _mm_mul_ps(mc21, ms21);
mc11 = _mm_add_ps(mc11, mc12);
mc11 = _mm_add_ps(mc11, mc22);
mc11 = _mm_add_ps(mc11, mc21);
Vec3f colour;
_mm_storeu_ps(colour.array, mc11);
そして、役に立たないです。私は何かを逃していますか、ここで余分なスピードを得ることは不可能ですか?
が、私はこれを言うことを憎むが、これは間違いなく正しいアプローチではありません: は、B、C、D、およびXERR用パックピクセルARGB考えると、yerr範囲0から256で、簡単な例です。 。まず、ベクトルを入れるだけの作業(純粋なオーバーヘッド)を費やします。そして、計算の終わりには厄介な依存関係があります。しかし、根本的に、主な問題は、あなたが構造体配列のパッキングを使用していることです。 SIMDについて真剣なら、struct-of-arrayへの切り替えを検討する必要があります。 – Mysticial
さて、ベクターを取り込むことについて知りました。まず、データを並べ替えることで、並べ替えを尊重します。しかし、あなたは "計算の終わりに依存関係"について詳しく述べることができますか? – SimpleMan
あなたはお互いに依存する3つの追加があります。したがって、あなたが次のものを始める前に終わらなければならないので、それらのどれも並行して行うことはできません。私は、バイナリツリーの削減を使って最適化された何らかのリダクションを行っているのを見ています。今は4つのベクトルだけを結合しています。だから、それをどのように再配置するかにかかわらず、多くを得ることはありません。しかし、私は、より大きな画像では、実際にはるかに大きな数の集合を合計していると考えています。 – Mysticial