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]