| Autor: | Wojciech Muła |
|---|---|
| Dodany: | 6.02.2002 |
| Aktualizacja: | 3.03.2002 |
Najprościej jest po prostu zamieniać bajty (bądź słowa):
; edi - wskazuje na początek linii (pierwszy piksel)
; obrazy 8-bitowe ; obrazy 15/16-bitowe
; esi wskazuje na koniec linii
lea esi, [edi + img_width-1] ; lea esi, [edi + img_width-2]
mov ecx, img_width/2 ; mov ecx, img_width/2
flipx:
mov al, [edi] ; mov ax, [edi]
xchg al, [esi] ; xchg ax, [esi]
mov [edi], al ; mov [edi], ax
; kolejny piksel
inc edi ; add edi, byte 2
; wcześniejszy piksel
dec esi ; sub esi, byte 2
loop flipx
Podstawową wadą programu jest liczba odwołań do pamięci, równa 3*img_width/2. Poniżej zoptymalizowany program dla obrazów grayscale.
; edi - pierwszy piksel
; esi - ostatni piksel
mov ecx, img_width/8 ; tylko img_width/8 iteracji
flipx:
mov eax, [edi]
mov ebx, [esi]
bswap eax ; instrukcja bswap zamienia kolejność bajtów -
bswap ebx ; jest wręcz idealna dla tego zastosowania
mov [esi], eax
mov [edi], ebx
add edi, 4
sub esi, 4
loop flipx
W tym przypadku liczba pobrań jest równa img_width/2, tj. 3 razy mniej niż w poprzednim programie. Jedyną, myślę niezbyt dokuczliwą wadą, jest wymogów by szerokość obrazu (img_width) była całkowitą wielokrotnością czwórki.
Użycie rozszerzonych rozkazów MMX może znacznie przyspieszyć kod --- przedstawiam kod zamieniający kolejność bajtów w rejestrze MMX.
movq mm0, [edi] ; mm0 = |a|b|c|d|e|f|g|h|
movq mm1, mm0 ; mm1 = |a|b|c|d|e|f|g|h|
psrlw mm0, 8 ; mm0 = |0a|0c|0e|0g|
psllw mm1, 8 ; mm1 = |b0|d0|f0|h0|
por mm0, mm1 ; mm0 = |ba|dc|fe|hg| -- zamiana bajtów w słowach
pshufw mm0, mm0, 0x1b ; 0x1b= |00|01|10|11|
; mm0 = |hg|fe|dc|ba|
Przy przetwarzaniu obrazów 15/16 bpp można pobierać po 2 piksele do rejestru 32-bitowego, po czym dokonać obrotu bitowego (w lewo, bądź prawo) o 16 pozycji.
mov eax, [edi+0] ; eax = |piksel1|piksel0| mov ebx, [edi+4] ; ebx = |piksel3|piksel2| rol eax, 16 ; eax = |piksel0|piksel1| rol ebx, 16 ; ebx = |piksel2|piksel3| mov [esi-4], ebx mov [esi-8], eax
Użycie rozkazu pshufw umożliwi blisko dwukrotne przyspieszenie.
movq mm0, [edi+0] ; załaduj 4 piksele movq mm1, [edi+8] ; i kolejne 4 pshufw mm0, mm0, 0x1b ; 0x1b = |00|01|10|11| pshufw mm1, mm1, 0x1b ; movq mm0, [esi-8] movq mm0, [esi-16]