Código de máquina x86-64 (y x86-32), 13 15 13 bytes
registro de cambios:
Corrección de errores: la primera versión solo verificaba G = 0xff, no requería que R y B fueran 0. Cambié a modificar el fondo en su lugar para poder usar lodsd
en primer plano para tener píxeles fg eax
para la cmp eax, imm32
codificación de forma corta (5 bytes ), en lugar de cmp dh,0xff
(3 bytes).
Guardar 2 bytes: noté que modificar el bg en su lugar permitía usar un operando de memoria para cmov
, guardar una mov
carga de 2 bytes (y guardar un registro, en caso de que sea importante).
Esta es una función que sigue la convención de llamadas del Sistema V x86-64, que se puede llamar directamente desde C o C ++ (en sistemas x86-64 que no son Windows) con esta firma:
void chromakey_blend_RGB32(uint32_t *background /*rdi*/,
const uint32_t *foreground /*rsi*/,
int dummy, size_t pixel_count /*rcx*/);
El formato de imagen es RGB0 32bpp, con el componente verde en la segunda dirección de memoria más baja dentro de cada píxel. La imagen de fondo en primer plano se modifica in situ. pixel_count
es filas * columnas. No le importan las filas / columnas; solo combina chromekey sin importar la cantidad de palabras de memoria que especifique.
RGBA (con A requerido para ser 0xFF) requeriría el uso de una constante diferente, pero ningún cambio en el tamaño de la función. Las DWORD en primer plano se comparan para una igualdad exacta frente a una constante arbitraria de 32 bits almacenada en 4 bytes, por lo que cualquier orden de píxeles o color de clave de croma puede ser fácilmente compatible.
El mismo código de máquina también funciona en modo de 32 bits. Para ensamblar como 32 bits, cambie rdi
a edi
en la fuente. Todos los demás registros que se convierten en 64 bits son implícitos (lodsd / stosd y loop), y los otros registros explícitos permanecen en 32 bits. Pero tenga en cuenta que necesitará un contenedor para llamar desde C de 32 bits, porque ninguna de las convenciones de llamadas estándar x86-32 usa los mismos registros que SysV x86-64.
Listado NASM (código de máquina + fuente), comentado para principiantes de ASM con descripciones de lo que hacen las instrucciones más complejas. (Duplicar el manual de referencia de instrucciones es un mal estilo en uso normal).
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
Para obtener la fuente NASM original de esta lista, elimine los 26 caracteres principales de cada línea con <chromakey.lst cut -b 26- > chromakey.asm
. Generé esto con
nasm -felf64 chromakey-blend.asm -l /dev/stdout | cut -b -28,$((28+12))-
listados NASM, dejando más columnas en blanco de las que quiero entre el código de máquina y la fuente. Para crear un archivo de objeto que pueda vincular con C o C ++, use nasm -felf64 chromakey.asm
. (O yasm -felf64 chromakey.asm
)
no probado , pero estoy bastante seguro de que la idea básica de load / load / cmov / store es sólida, porque es muy simple.
Podría ahorrar 3 bytes si pudiera requerir que la persona que llama pase la constante de clave de croma (0x00ff00) como un argumento adicional, en lugar de codificar la constante en la función. No creo que las reglas habituales permitan escribir una función más genérica que tenga las llamadas configuradas constantes para ello. Pero si lo hizo, el tercer argumento (actualmente dummy
) se pasa edx
en el x86-64 SysV ABI. Simplemente cambie cmp eax, 0x0000ff00
(5B) a cmp eax, edx
(2B).
Con SSE4 o AVX, puede hacerlo más rápido (pero con un tamaño de código más grande) con pcmpeqd
y blendvps
para hacer una combinación variable de tamaño de elemento de 32 bits controlada por la máscara de comparación. (Con pand
, podrías ignorar el byte alto). Para RGB24 empaquetado, puede usar pcmpeqb
y luego 2x pshufb
+ pand
para obtener VERDADERO en bytes donde coinciden los 3 componentes de ese píxel pblendvb
.
(Sé que esto es código-golf, pero consideré probar MMX antes de usar un entero escalar).