Pracuję nad optymalizacją mnożenia macierzy-wektorów 4D (128-bitowych) za pomocą ARM NEON Asembler.Jak zoptymalizować zapętlone mnożenie macierzy wektorowej 4D za pomocą ARM NEON?
Jeśli załaduję macierz i wektor do rejestrów NEON i zmienię to, nie otrzymam dużego zwiększenia wydajności, ponieważ przejście do rejestrów NEON kosztuje 20 cykli. Ponadto przeładowuję macierz dla każdego mnożenia, mimo że się nie zmieniła.
Jest wystarczająco dużo przestrzeni rejestrów, aby wykonać transformację na więcej wektorów w czasie. To zwiększa wydajność.
Ale ..
Zastanawiam się, jak szybko ta operacja będzie, jeśli zrobić pętlę nad wszystkimi wierzchołkami (zwiększenie wskaźników) w ramach asemblerze. Ale jestem na samym początku asemblera Neonów i choć nie wiem jak to zrobić. Czy ktoś może mi w tym pomóc?
Co chcę osiągnąć:
- macierz obciążenia i pierwszy wektor
- sklep licznik pętli "Count" i ..
- - LOOP_START -
- wykonać mnożenie-dodaje (zrobić transformacja)
- zapisu q0 do Vout
- wzrost wskaźniki Vin i Vout przez 4 (128 Bit)
- ŁADUJ vIn do q5.
- - LOOP_END -
istniejący C-Version pętli:
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;
//}
}
następujący kod dla NEON wersja robić tylko jedną transformację:
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 transformacji:
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;
}
Wydajność: (Przekształcenie> 90 000 werteksów | Android 4.0.4 SGS II)
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)
Podaj swoją pętlę w prostym C, ludzie będą mogli łatwiej. – auselen
o tak ... zgaduję, że masz rację! – oc1d
Dostarcz także Matrix4Vector4Mul, w rzeczywistości utwórz je w jedną pętlę, tak jak napisałeś to w zwykłym c. – auselen