Ich arbeite an der Optimierung einer 4D (128 Bit) Matrix-Vektor-Multiplikation mit ARM NEON Assembler.Wie kann ich eine geloopte 4D Matrix-Vektor-Multiplikation mit ARM NEON optimieren?
Wenn ich die Matrix und den Vektor in die NEON-Register lade und transformiere, bekomme ich keinen großen Leistungsschub, weil der Wechsel zu den NEON-Registern 20 Zyklen kostet. Außerdem lade ich die Matrix für jede Multiplikation neu, obwohl sie sich nicht geändert hat.
Es gibt genug Registerraum, um die Transformation auf mehr Vektoren pro Zeit durchzuführen. Dies erhöht die Leistung.
Aber ..
Ich frage mich, wie schnell dieser Vorgang wäre, wenn ich die Schleife über alle Eckpunkte tun (zunehmende Zeiger) im Assembler. Aber ich bin am Anfang von Neon Assembler und weiß nicht, wie ich das machen soll. Kann mir jemand dabei helfen?
Was ich erreichen möchte:
- Belastungsmatrix und erste Vektor
- Speicher Schleifenzählung "count" und ..
- - LOOP_START -
- führen mehrfach ergänzt (do die Transformation)
- Schreib Q0 bis VOUT
- Erhöhung Zeiger vIN und VOUT von 4 (128 Bit)
- LOAD vIN bis q5.
- - LOOP_END -
vorhandene C-Version von Schleife:
void TransformVertices(ESMatrix* m, GLfloat* vertices, GLfloat* normals, int count)
{
GLfloat* pVertex = vertices;
int i;
// iterate trough vertices only one at a time
for (i = 0; i < count ; i ++)
{
Matrix4Vector4Mul((float *)m, (float *)pVertex, (float *)pVertex);
pVertex += 4;
}
//LoadMatrix((const float*) m);
//// two at a time
//for (i = 0; i < count ; i += 2)
//{
// Matrix4Vector4Mul2((float *)m, (float *)pVertex, (float *)(pVertex + 4));
// pVertex += 8;
//}
}
folgenden Code für NEON-Version auf nur eine Transformation zu tun:
void Matrix4Vector4Mul (const float* m, const float* vIn, float* vOut)
{
asm volatile
(
"vldmia %1, {q1-q4 } \n\t"
"vldmia %2, {q5} \n\t"
"vmul.f32 q0, q1, d10[0] \n\t"
"vmla.f32 q0, q2, d10[1] \n\t"
"vmla.f32 q0, q3, d11[0] \n\t"
"vmla.f32 q0, q4, d11[1] \n\t"
"vstmia %0, {q0}"
: // no output
: "r" (vOut), "r" (m), "r" (vIn)
: "memory", "q0", "q1", "q2", "q3", "q4", "q5"
);
}
C-Version der Umwandlung:
void Matrix4Vector4Mul (const float* m, const float* vIn, float* vOut)
{
Vertex4D* v1 = (Vertex4D*)vIn;
Vertex4D vOut1;
Vertex4D* l0;
Vertex4D* l1;
Vertex4D* l2;
Vertex4D* l3;
// 4x4 Matrix with members m00 - m33
ESMatrix* m1 = (ESMatrix*)m;
l0 = (Vertex4D*)&m1->m00;
vOut1.x = l0->x * v1->x;
vOut1.y = l0->y * v1->x;
vOut1.z = l0->z * v1->x;
vOut1.w = l0->w * v1->x;
l1 = (Vertex4D*)&m1->m10;
vOut1.x += l1->x * v1->y;
vOut1.y += l1->y * v1->y;
vOut1.z += l1->z * v1->y;
vOut1.w += l1->w * v1->y;
l2 = (Vertex4D*)&m1->m20;
vOut1.x += l2->x * v1->z;
vOut1.y += l2->y * v1->z;
vOut1.z += l2->z * v1->z;
vOut1.w += l2->w * v1->z;
l3 = (Vertex4D*)&m1->m30;
vOut1.x += l3->x * v1->w;
vOut1.y += l3->y * v1->w;
vOut1.z += l3->z * v1->w;
vOut1.w += l3->w * v1->w;
*(vOut) = vOut1.x;
*(vOut + 1) = vOut1.y;
*(vOut + 2) = vOut1.z;
*(vOut + 3) = vOut1.w;
}
Leistung: (Transform> 90 000 Vertices | II Android 4.0.4 SGS)
C-Version: 190 FPS
NEON-Version: 162 FPS (.. slower -.-)
--- LOAD Matrix only ONCE (seperate ASM) and then perform two V's at a time ---
NEON-Version: 217 FPS (+ 33 % NEON | + 14 % C-Code)
Bieten Sie Ihre Schleife in einfachen C, würden die Menschen es einfacher. – auselen
oh yeah .. denke du hast Recht! – oc1d
Stellen Sie Matrix4Vector4Mul auch, in der Tat machen Sie sie nur eine Schleife, wie Sie es in Plain c schreiben würden. – auselen