código de máquina x86-64 (e x86-32), 13 15 13 bytes
changelog:
Correção de bug: a primeira versão estava apenas checando G = 0xff, não exigindo que R e B fossem 0. Alterei para modificar o plano de fundo no local para que eu pudesse usar lodsd
em primeiro plano para ter pixels fg na codificação de eax
formato curto cmp eax, imm32
(5 bytes ), em vez de cmp dh,0xff
(3 bytes).
Economize 2 bytes: observe que modificar o bg no local permite o uso de um operando de memória cmov
, economizando uma mov
carga de 2 bytes (e salvando um registro, caso isso importe).
Esta é uma função que segue a convenção de chamada do System V x86-64, que pode ser chamada diretamente de C ou C ++ (em sistemas x86-64 não Windows) com esta assinatura:
void chromakey_blend_RGB32(uint32_t *background /*rdi*/,
const uint32_t *foreground /*rsi*/,
int dummy, size_t pixel_count /*rcx*/);
O formato da imagem é RGB0 32bpp, com o componente verde no segundo endereço de memória mais baixo em cada pixel. A imagem de fundo do primeiro plano é modificada no local. pixel_count
é linhas * colunas. Não se preocupa com linhas / colunas; apenas o chromekey combina no entanto muitas dwords de memória que você especificar.
RGBA (com A necessário para 0xFF) exigiria o uso de uma constante diferente, mas nenhuma alteração no tamanho da função. Os DWORDs em primeiro plano são comparados quanto à igualdade exata em relação a uma constante arbitrária de 32 bits armazenada em 4 bytes, para que qualquer cor de ordem de pixel ou chave de croma possa ser facilmente suportada.
O mesmo código de máquina também funciona no modo de 32 bits. Para montar como 32 bits, altere rdi
para edi
na fonte. Todos os outros registradores que se tornam 64 bits são implícitos (lodsd / stosd e loop), e os outros registros explícitos permanecem em 32 bits. Mas observe que você precisará de um wrapper para chamar de C de 32 bits, porque nenhuma das convenções de chamada x86-32 padrão usa os mesmos registros do x86-64 SysV.
Listagem NASM (código de máquina + fonte), comentada para iniciantes em asm com descrições do que as instruções mais complexas fazem. (Duplicar o manual de referência das instruções é um estilo ruim no 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 obter a fonte NASM original dessa lista, retire os 26 caracteres iniciais de cada linha <chromakey.lst cut -b 26- > chromakey.asm
. Eu
nasm -felf64 chromakey-blend.asm -l /dev/stdout | cut -b -28,$((28+12))-
criei isso com listagens NASM, deixando mais colunas em branco do que eu quero entre o código da máquina e a fonte. Para criar um arquivo de objeto que você pode vincular com C ou C ++, use nasm -felf64 chromakey.asm
. (Ou yasm -felf64 chromakey.asm
)
não testado , mas estou bastante confiante de que a idéia básica de load / load / cmov / store é sólida, porque é muito simples.
Eu poderia salvar 3 bytes se exigisse que o chamador passasse a constante de chave de croma (0x00ff00) como um argumento extra, em vez de codificar a constante na função. Eu não acho que as regras usuais permitam escrever uma função mais genérica que tenha o chamador configurado constantes para ele. Mas, se o fez, o terceiro argumento (atualmente dummy
) é passado na edx
ABI x86-64 SysV. Apenas mude cmp eax, 0x0000ff00
(5B) para cmp eax, edx
(2B).
Com o SSE4 ou AVX, você pode fazer isso mais rapidamente (mas com um tamanho de código maior) pcmpeqd
e blendvps
fazer uma mistura variável de tamanho de elemento de 32 bits controlada pela máscara de comparação. (Com pand
, você pode ignorar o byte alto). Para RGB24 compactado, você pode usar pcmpeqb
e, em seguida, 2x pshufb
+ pand
para obter VERDADEIRO em bytes, onde todos os 3 componentes desse pixel correspondem pblendvb
.
(Eu sei que isso é código-golfe, mas considerei tentar o MMX antes de usar o número inteiro escalar.)