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 lodsddi latar depan untuk memiliki fg piksel dalam eaxuntuk cmp eax, imm32pengkodean 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 movbeban 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_countadalah 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 rdike edidalam 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 edxSysV 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 pcmpeqddan blendvpsuntuk 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 pcmpeqbdan kemudian 2x pshufb+ panduntuk 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.)