x86-64 (ve x86-32) makine kodu, 13 15 13 bayt
changelog:
Hata düzeltme: ilk sürüm yalnızca G = 0xff'i kontrol ediyordu, R ve B'nin 0 olmasını gerektirmiyordu. Arka planı yerinde değiştirerek kısa form kodlaması için lodsdfg pikselleri kullanmak için ön planda kullanabilmek için değiştirdim (5 bayt ) yerine (3 bayt).eaxcmp eax, imm32cmp dh,0xff
2 bayt kaydet: bg'yi yerinde değiştirmenin, cmov2 baytlık bir movyükü (ve önemli olması durumunda bir kayıt defterini kaydetme) hafıza işleneni kullanmasına izin verildiğini fark ettim .
Bu, x86-64 System V çağrı kuralını izleyen, doğrudan C veya C ++ ile (x86-64 dışı Windows sistemlerinde) bu imzayla çağrılabilen bir işlevdir:
void chromakey_blend_RGB32(uint32_t *background /*rdi*/,
const uint32_t *foreground /*rsi*/,
int dummy, size_t pixel_count /*rcx*/);
Görüntü formatı RGB0 32bpp'dir, yeşil bileşen her pikselin 2. en düşük hafıza adresindedir. Ön plan arka plan görüntüsü yerinde değiştirilir. pixel_countSatırlar * sütunlar. Satırlar / sütunlar umrunda değil; sadece chromekey, ancak belirlediğiniz birçok belleğin harmanını karıştırır.
RGBA (A'nın 0xFF olması gerekir) farklı bir sabit kullanmayı gerektirir, ancak işlev boyutunda değişiklik yapılmaz. Ön plan DWORD'leri, 4 baytta depolanan keyfi bir 32 bit sabitine karşı tam eşitlik için karşılaştırılır, böylece herhangi bir piksel sırası veya renk anahtarı rengi kolayca desteklenebilir.
Aynı makine kodu 32 bit modunda da çalışır. 32 bit olarak monte rdietmek ediiçin kaynağa geçin . 64 bit olan diğer tüm kayıtlar örtüktür (lodsd / stosd ve loop) ve diğer açık kayıtlar 32-bit kalır. Ancak, 32 bit C'den aramak için bir sarmalayıcıya ihtiyacınız olacağını unutmayın, çünkü standart x86-32 çağrı kurallarının hiçbiri x86-64 SysV ile aynı regleri kullanmaz.
NASM listelemesi (makine kodu + kaynak), yeni başlayanlara, daha karmaşık talimatların ne yaptığının açıklamalarını içeren bir yorumda bulundu. (Talimat referans kılavuzunun çoğaltılması normal kullanımda kötüdür.)
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
Orijinal NASM kaynağını bu listeden çıkarmak için, her satırın önde gelen 26 karakterini ile sıyırın <chromakey.lst cut -b 26- > chromakey.asm.
nasm -felf64 chromakey-blend.asm -l /dev/stdout | cut -b -28,$((28+12))-
NASM listeleri ile bunu oluşturdum , makine kodu ve kaynak arasında istediğimden daha fazla boş sütun bırakın. Bir nesne dosyası oluşturmak için C veya C ++ ile bağlayabilirsiniz, kullanın nasm -felf64 chromakey.asm. (Veyayasm -felf64 chromakey.asm ).
denenmemiş , ancak yük / yük / cmov / mağaza temel fikrinin sağlam olduğuna eminim, çünkü çok basit.
Arayanın, sabit fonksiyona sabit kodlama yerine, chroma-key sabitini (0x00ff00) ekstra bir argüman olarak geçirmesini gerektirebilirsem, 3 byte tasarruf edebilirim. Alışılmış kuralların, arayan kişi için sabit ayarlanmış daha genel bir fonksiyon yazmasına izin verdiğini sanmıyorum. Ama eğer öyleyse, 3. argüman (şu anda dummy) edxx86-64 SysV ABI'ye iletilir . Sadece cmp eax, 0x0000ff00(5B) 'yi cmp eax, edx(2B) olarak değiştirin.
SSE4 veya AVX ile, bunu daha hızlı (ancak daha büyük kod boyutu) karşılaştırma maskesi tarafından kontrol edilen 32 bitlik bir eleman boyutu değişken karışımı ile yapabilir pcmpeqdve blendvpsyapabilirsiniz. ( pandYüksek baytları görmezden gelebilirsiniz). Paketlenmiş RGB24 için, o pikselin 3 bileşeninin hepsinin eşleştiği bayt cinsinden DOĞRU almak için pcmpeqbve ardından 2x pshufb+ tuşlarını pandkullanabilirsiniz pblendvb.
(Bunun kod golf olduğunu biliyorum, ancak skalar tamsayıya gitmeden önce MMX'i denemeyi düşündüm.)