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 lodsd
fg pikselleri kullanmak için ön planda kullanabilmek için değiştirdim (5 bayt ) yerine (3 bayt).eax
cmp eax, imm32
cmp dh,0xff
2 bayt kaydet: bg'yi yerinde değiştirmenin, cmov
2 baytlık bir mov
yü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_count
Satı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 rdi
etmek edi
iç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
) edx
x86-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 pcmpeqd
ve blendvps
yapabilirsiniz. ( pand
Yü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 pcmpeqb
ve ardından 2x pshufb
+ tuşlarını pand
kullanabilirsiniz pblendvb
.
(Bunun kod golf olduğunu biliyorum, ancak skalar tamsayıya gitmeden önce MMX'i denemeyi düşündüm.)