машинный код x86-64 (и x86-32), 13 15 13 байт
Список изменений:
Исправление: первая версия проверяла только G = 0xff, не требуя, чтобы R и B равнялись 0. Я перешел на модификацию фона на месте, чтобы я мог использовать lodsd
на переднем плане, чтобы использовать пиксели fg eax
для краткого cmp eax, imm32
кодирования (5 байт) ) вместо cmp dh,0xff
(3 байта).
Сохранить 2 байта: заметил, что изменение bg на месте позволило использовать операнд памяти для cmov
сохранения 2-байтовой mov
загрузки (и сохранения регистра в случае, если это имеет значение).
Это функция, соответствующая соглашению о вызовах x86-64 System V, вызываемая непосредственно из C или C ++ (в системах x86-64, отличных от Windows), с такой сигнатурой:
void chromakey_blend_RGB32(uint32_t *background /*rdi*/,
const uint32_t *foreground /*rsi*/,
int dummy, size_t pixel_count /*rcx*/);
Формат изображения - RGB0 32bpp, с зеленым компонентом на 2-м младшем адресе памяти в каждом пикселе. На переднем плане фоновое изображение изменяется на месте. pixel_count
это строки * столбцы. Это не заботится о строках / столбцах; он просто сочетает ChromeKey с любым количеством мечей памяти, которые вы укажете.
RGBA (с A требуется равным 0xFF) потребует использования другой константы, но без изменения размера функции. DWORD переднего плана сравниваются на предмет точного равенства с произвольной 32-битной константой, хранящейся в 4 байтах, поэтому любой цвет в пиксельном порядке или цветность ключа цвета могут быть легко поддержаны.
Тот же машинный код также работает в 32-битном режиме. Для того, чтобы собрать как 32-бит, изменения , rdi
чтобы edi
в источнике. Все остальные регистры, которые становятся 64-битными, являются неявными (lodsd / stosd и loop), а другие явные регистры остаются 32-битными. Но обратите внимание, что вам понадобится оболочка для вызова из 32-битного C, потому что ни одно из стандартных соглашений о вызовах x86-32 не использует те же regs, что и x86-64 SysV.
Список NASM (машинный код + исходный код), прокомментированный для начинающих asm с описанием того, что делают более сложные инструкции. (Дублирование справочного руководства - плохой стиль при обычном использовании.)
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
Чтобы получить исходный источник NASM из этого списка, зачеркните первые 26 символов каждой строки <chromakey.lst cut -b 26- > chromakey.asm
. Я сгенерировал это с помощью
nasm -felf64 chromakey-blend.asm -l /dev/stdout | cut -b -28,$((28+12))-
списков NASM, которые оставляют больше пустых столбцов между машинным кодом и исходным кодом. Чтобы создать объектный файл, вы можете связать с C или C ++, используйте nasm -felf64 chromakey.asm
. (Или yasm -felf64 chromakey.asm
)
непроверенный , но я вполне уверен, что основная идея загрузки / загрузки / cmov / store - это звук, потому что это так просто.
Я мог бы сохранить 3 байта, если бы потребовал, чтобы вызывающая сторона передавала константу хроматического ключа (0x00ff00) в качестве дополнительного аргумента вместо жесткого кодирования константы в функцию. Я не думаю, что обычные правила позволяют писать более общую функцию, в которой вызывающий объект устанавливает для нее константы. Но если это так, третий аргумент (в настоящее время dummy
) передается в edx
x86-64 SysV ABI. Просто измените cmp eax, 0x0000ff00
(5B) на cmp eax, edx
(2B).
С SSE4 или AVX вы могли бы сделать это быстрее (но с большим размером кода) с помощью pcmpeqd
и blendvps
сделать 32-разрядное изменение размера элемента, управляемое маской сравнения. (С помощью pand
вы можете игнорировать старший байт). Для упакованного RGB24 вы можете использовать, pcmpeqb
а затем 2x pshufb
+, pand
чтобы получить ИСТИНА в байтах, где совпадают все 3 компонента этого пикселя pblendvb
.
(Я знаю, что это код-гольф, но я решил попробовать MMX, прежде чем переходить к скалярному целому числу.)