kode mesin x86-64 (dan x86-32), 13 15 13 byte
changelog:
Perbaikan bug: versi pertama hanya memeriksa G = 0xff, tidak memerlukan R dan B menjadi 0. Saya mengubah untuk memodifikasi latar di tempat sehingga saya dapat menggunakan lodsd
di latar depan untuk memiliki fg piksel dalam eax
untuk cmp eax, imm32
pengkodean bentuk pendek (5 byte) ), alih-alih cmp dh,0xff
(3 byte).
Simpan 2 byte: perhatikan bahwa memodifikasi bg pada tempatnya diizinkan menggunakan operan memori untuk cmov
, menghemat mov
beban 2-byte (dan menyimpan register, jika perlu).
Ini adalah fungsi yang mengikuti konvensi pemanggilan Sistem V x86-64, dapat dipanggil langsung dari C atau C ++ (pada sistem x86-64 non-Windows) dengan tanda tangan ini:
void chromakey_blend_RGB32(uint32_t *background /*rdi*/,
const uint32_t *foreground /*rsi*/,
int dummy, size_t pixel_count /*rcx*/);
Format gambar adalah RGB0 32bpp, dengan komponen hijau di alamat memori terendah ke-2 dalam setiap piksel. Gambar latar latar depan dimodifikasi di tempat. pixel_count
adalah baris * kolom. Itu tidak peduli tentang baris / kolom; itu hanya campuran chromekey namun banyak memori yang Anda tentukan.
RGBA (dengan A harus 0xFF) akan membutuhkan menggunakan konstanta yang berbeda, tetapi tidak ada perubahan dalam ukuran fungsi. DWORD foreground dibandingkan untuk kesetaraan tepat terhadap konstanta 32-bit yang sewenang-wenang yang disimpan dalam 4 byte, sehingga warna urutan-pixel atau warna kunci-kroma dapat dengan mudah didukung.
Kode mesin yang sama juga berfungsi dalam mode 32-bit. Untuk berkumpul sebagai 32-bit, ubah rdi
ke edi
dalam sumber. Semua register lain yang menjadi 64-bit adalah implisit (lodsd / stosd, dan loop), dan regs eksplisit lainnya tetap 32-bit. Tetapi perhatikan bahwa Anda memerlukan pembungkus untuk menelepon dari 32-bit C, karena tidak ada konvensi pemanggilan x86-32 standar yang menggunakan regs yang sama dengan SysV x86-64.
Daftar NASM (kode mesin + sumber), dikomentari untuk pemula ASM dengan deskripsi tentang apa yang dilakukan instruksi yang lebih kompleks. (Menggandakan manual referensi instruksi adalah gaya yang buruk dalam penggunaan 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
Untuk mengeluarkan sumber NASM asli dari daftar ini, hapus 26 karakter utama dari setiap baris <chromakey.lst cut -b 26- > chromakey.asm
. Saya membuat ini dengan
nasm -felf64 chromakey-blend.asm -l /dev/stdout | cut -b -28,$((28+12))-
daftar NASM meninggalkan lebih banyak kolom kosong daripada yang saya inginkan antara kode mesin dan sumber. Untuk membuat file objek, Anda dapat menautkannya dengan C atau C ++, gunakan nasm -felf64 chromakey.asm
. (Atau yasm -felf64 chromakey.asm
).
belum diuji , tapi saya cukup yakin bahwa ide dasar load / load / cmov / store adalah suara, karena sangat sederhana.
Saya bisa menghemat 3 byte jika saya bisa meminta penelepon untuk meneruskan kunci chroma-key (0x00ff00) sebagai argumen tambahan, alih-alih mengkodekan konstanta ke dalam fungsi. Saya tidak berpikir aturan yang biasa memungkinkan penulisan fungsi yang lebih umum yang membuat pemanggil mengatur konstanta untuk itu. Tetapi jika itu terjadi, arg ke-3 (saat ini dummy
) diteruskan dalam edx
SysV ABI x86-64. Ubah cmp eax, 0x0000ff00
(5B) menjadi cmp eax, edx
(2B).
Dengan SSE4 atau AVX, Anda mungkin melakukan ini lebih cepat (tetapi ukuran kode lebih besar) dengan pcmpeqd
dan blendvps
untuk melakukan campuran variabel ukuran elemen ukuran 32-bit yang dikendalikan oleh topeng pembanding. (Dengan pand
, Anda dapat mengabaikan byte tinggi). Untuk RGB24 yang dikemas, Anda dapat menggunakan pcmpeqb
dan kemudian 2x pshufb
+ pand
untuk mendapatkan TRUE dalam byte di mana ketiga komponen piksel itu cocok, lalu pblendvb
.
(Saya tahu ini adalah kode-golf, tapi saya sempat mempertimbangkan mencoba MMX sebelum menggunakan skalar integer.)