codice macchina x86-64 (e x86-32), 13 15 13 byte
changelog:
Bugfix: la prima versione stava solo controllando G = 0xff, non richiedendo che R e B fossero 0. Ho cambiato modificando lo sfondo in posizione in modo da poter usare lodsd
in primo piano per avere pixel fg eax
per la cmp eax, imm32
codifica in formato breve (5 byte ), anziché cmp dh,0xff
(3 byte).
Salva 2 byte: notato che la modifica del bg in atto ha consentito l'uso di un operando di memoria per cmov
, il salvataggio di un mov
carico di 2 byte (e il salvataggio di un registro, nel caso in cui sia importante).
Questa è una funzione che segue la convenzione di chiamata System V x86-64, richiamabile direttamente da C o C ++ (su sistemi x86-64 non Windows) con questa firma:
void chromakey_blend_RGB32(uint32_t *background /*rdi*/,
const uint32_t *foreground /*rsi*/,
int dummy, size_t pixel_count /*rcx*/);
Il formato dell'immagine è RGB0 32 bpp, con il componente verde al secondo indirizzo di memoria più basso all'interno di ciascun pixel. L' immagine di sfondo in primo piano viene modificata sul posto. pixel_count
è righe * colonne. Non importa di righe / colonne; semplicemente Chromekey unisce comunque molte parole di memoria che specifichi.
RGBA (con A richiesto essere 0xFF) richiederebbe l'utilizzo di una costante diversa, ma nessuna modifica nella dimensione della funzione. I DWORD in primo piano vengono confrontati per l'uguaglianza esatta con una costante arbitraria a 32 bit memorizzata in 4 byte, in modo che qualsiasi ordine di pixel o cromaticità possa essere facilmente supportato.
Lo stesso codice macchina funziona anche in modalità 32 bit. Per assemblare come 32 bit, passare rdi
a edi
nella sorgente. Tutti gli altri registri che diventano 64 bit sono impliciti (lodsd / stosd e loop) e gli altri registri espliciti rimangono a 32 bit. Ma tieni presente che avrai bisogno di un wrapper per chiamare da 32-bit C, perché nessuna delle convenzioni di chiamata standard x86-32 utilizza gli stessi registri di SysV x86-64.
Elenco della NASM (codice macchina + sorgente), commentato per i principianti con descrizioni di ciò che fanno le istruzioni più complesse. (La duplicazione del manuale di riferimento delle istruzioni è un cattivo stile durante il normale utilizzo.)
1 ;; inputs:
2 ;; Background image pointed to by RDI, RGB0 format (32bpp)
3 ;; Foreground image pointed to by RSI, RGBA or RGBx (32bpp)
4 machine ;; Pixel count in RCX
5 code global chromakey_blend_RGB32
6 bytes chromakey_blend_RGB32:
7 address .loop: ;do {
8 00000000 AD lodsd ; eax=[rsi], esi+=4. load fg++
9 00000001 3D00FF0000 cmp eax, 0x0000ff00 ; check for chromakey
10 00000006 0F4407 cmove eax, [rdi] ; eax = (fg==key) ? bg : fg
11 00000009 AB stosd ; [rdi]=eax, edi+=4. store into bg++
12 0000000A E2F4 loop .loop ;} while(--rcx)
13
14 0000000C C3 ret
## next byte starts at 0x0D, function length is 0xD = 13 bytes
Per ottenere l'origine NASM originale da questo elenco, rimuovere i 26 caratteri principali di ogni riga con <chromakey.lst cut -b 26- > chromakey.asm
. Ho generato questo con gli
nasm -felf64 chromakey-blend.asm -l /dev/stdout | cut -b -28,$((28+12))-
elenchi NASM che lasciano più colonne vuote di quelle che voglio tra il codice macchina e l'origine. Per creare un file oggetto che è possibile collegare con C o C ++, utilizzare nasm -felf64 chromakey.asm
. (O yasm -felf64 chromakey.asm
).
non testato , ma sono abbastanza sicuro che l'idea di base di load / load / cmov / store sia valida, perché è così semplice.
Potrei salvare 3 byte se potessi richiedere al chiamante di passare la costante chroma-key (0x00ff00) come argomento extra, invece di codificare la costante nella funzione. Non penso che le solite regole consentano di scrivere una funzione più generica che ha il chiamante impostato costanti per esso. Ma se lo facesse, il 3o argomento (attualmente dummy
) viene passato edx
nell'ABI SysV x86-64. Cambia cmp eax, 0x0000ff00
(5B) in cmp eax, edx
(2B).
Con SSE4 o AVX, è possibile farlo più velocemente (ma con una dimensione del codice maggiore) con pcmpeqd
e blendvps
per eseguire una fusione variabile di dimensioni degli elementi a 32 bit controllata dalla maschera di confronto. (Con pand
, potresti ignorare il byte alto). Per RGB24 compresso, è possibile utilizzare pcmpeqb
e quindi 2x pshufb
+ pand
per ottenere TRUE in byte in cui corrispondono tutti e 3 i componenti di quel pixel pblendvb
.
(So che questo è code-golf, ma ho pensato di provare MMX prima di andare con un intero scalare.)