"Odkopuję", bo udało mi się to rozgryźć i chciałem zapytać o coś jeszcze.
Miałem oryginalny kod:
procedure TDisplay.Fill(const AColor: Cardinal);
var
I: Cardinal;
P: ^Cardinal;
begin
P := @Buffer.Color[0];
for I := 0 to Buffer.Size - 1 do
begin
P^ := AColor;
Inc(P, 1);
end;
end;
I przerobiłem go na:
procedure TDisplay.FillASM(const AColor: Cardinal);
var
Mask: array[0..3] of Integer;
asm
lea ebx, Mask;
mov edx, AColor;
mov [ebx], edx;
mov [ebx + 4], edx;
mov [ebx + 8], edx;
mov [ebx + 12], edx;
movups xmm0, [ebx];
mov ebx, [eax].Buffer.Color[0]; //Buffer.Color to jednowymiarowa tablica dynamiczna wypełniona integerami
mov ecx, [eax].Buffer.Size; //Buffer.Size to jego szerokość pomnożona przez jego długość, np. 1920 x 1080
shr ecx, 2;
mov eax, 0;
@Loop:
movups [ebx + eax], xmm0;
add eax, 16;
dec ecx;
jnz @Loop;
end;
Różnica szybkości jest KOLOSALNA! pętla z 1000 powtórzeń w przypadku pierwszego kodu dawała 400-410 milisekund. Kod w ASM zamyka się w granicach... 27-28 ms! Próbowałem też wersji kodu, w której wykorzystałem więcej niż 1 rejestr, tzn coś takiego:
procedure TDisplay.FillASM(const AColor: Cardinal);
var
Mask: array[0..3] of Integer;
asm
lea ebx, Mask;
mov edx, AColor;
mov [ebx], edx;
mov [ebx + 4], edx;
mov [ebx + 8], edx;
mov [ebx + 12], edx;
movups xmm0, [ebx];
movups xmm1, xmm0;
movups xmm2, xmm0;
movups xmm3, xmm0;
mov ebx, [eax].Buffer.Color[0];
mov ecx, [eax].Buffer.Size;
shr ecx, 4;
mov eax, 0;
@Loop:
movups [ebx + eax], xmm0;
movups [ebx + eax + 16], xmm1;
movups [ebx + eax + 32], xmm2;
movups [ebx + eax + 48], xmm3;
add eax, 64;
dec ecx;
jnz @Loop;
end;
Jednak nie miało to żadnego wpływu na szybkość działania. Jako że nie jestem zbyt biegły w ASM, nie jestem pewien z czym to jest związane. Czy chodzi o to, że CPU w jednym cyklu może dokonać tylko jednej operacji, polegającej na zapisie wartości w rejestrze do pamięci?
Drugie pytanie jest bardziej prozaiczne. Czy mój kody jest dobrze napisany? Wszystko optymalizuję tak jak trzeba? Mam wątpliwości zwłaszcza z tym zapisywaniem maski do rejestrów xmm, ale nie wiem, czy da się to zrobić lepiej. I czy maska w takiej formie jest konieczna? Jak samodzielnie alokować pamięć w ASM?