x86-64 (और x86-32) मशीन कोड, 13 15 13 बाइट्स
चैंज:
बगफिक्स: पहला संस्करण केवल G = 0xff की जाँच कर रहा था, R और B की आवश्यकता नहीं थी। 0. मैंने जगह में बैकग्राउंड को संशोधित करने के लिए बदल दिया, इसलिए मैं शॉर्ट-फॉर्म एन्कोडिंग के लिए lodsd
fg पिक्सल के eax
लिए अग्रभूमि पर उपयोग कर सकता था cmp eax, imm32
(5 बाइट्स) ), के बजाय cmp dh,0xff
(3 बाइट्स)।
2 बाइट्स सहेजें: ध्यान दें कि cmov
2-बाइट mov
लोड (और उस स्थिति में, मामले में एक रजिस्टर को बचाने) के लिए मेमोरी ऑपरेंड का उपयोग करने की अनुमति दी गई जगह में बीजी को संशोधित करना ।
यह x86-64 सिस्टम V कॉलिंग कन्वेंशन का अनुसरण करने वाला एक फ़ंक्शन है, इस हस्ताक्षर के साथ C या C ++ (x86-64 गैर-विंडोज सिस्टम पर) से सीधे कॉल करने योग्य है:
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
पंक्तियाँ है * कॉलम। यह पंक्तियों / स्तंभों की परवाह नहीं करता है; यह सिर्फ क्रोमकेई मिश्रणों को निर्दिष्ट करता है जो आपके द्वारा निर्दिष्ट मेमोरी के बहुत सारे पासवर्ड हैं।
RGBA (A के लिए 0xFF होना आवश्यक है) को एक अलग स्थिरांक का उपयोग करने की आवश्यकता होगी, लेकिन फ़ंक्शन आकार में कोई परिवर्तन नहीं। फोरग्राउंड DWORD की तुलना 4 बाइट्स में संग्रहीत एक मनमानी 32-बिट स्थिरांक के खिलाफ सटीक समानता के लिए की जाती है, इसलिए किसी भी पिक्सेल-ऑर्डर या क्रोमा-की रंग को आसानी से समर्थित किया जा सकता है।
एक ही मशीन कोड 32-बिट मोड में भी काम करता है। के रूप में 32-बिट, परिवर्तन इकट्ठा करने के लिए rdi
करने के लिए edi
स्रोत में। अन्य सभी रजिस्टर जो 64-बिट बनते हैं वे निहित (लॉस्ड / स्टोसड, और लूप) हैं, और अन्य स्पष्ट रजिस्टरों में 32-बिट रहते हैं। लेकिन ध्यान दें कि आपको 32-बिट C से कॉल करने के लिए एक रैपर की आवश्यकता होगी, क्योंकि मानक x86-32 में से कोई भी कॉलिंग कन्वेंशन 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
)
निष्कलंक , लेकिन मुझे पूरा विश्वास है कि लोड / लोड / सेमीोव / स्टोर का मूल विचार ध्वनि है, क्योंकि यह बहुत सरल है।
मैं 3 बाइट्स बचा सकता था अगर मुझे फ़ंक्शन में निरंतर हार्ड-कोडिंग के बजाय एक अतिरिक्त arg के रूप में क्रोमा-कुंजी स्थिरांक (0x00ff00) को पास करने के लिए कॉलर की आवश्यकता हो सकती है। मुझे नहीं लगता कि सामान्य नियम एक अधिक सामान्य फ़ंक्शन लिखने की अनुमति देते हैं जिसके लिए कॉलर ने इसके लिए स्थिरांक स्थापित किया है। लेकिन अगर ऐसा किया गया, तो x86-64 SysV ABI में 3rd arg (वर्तमान में dummy
) पास किया edx
गया। बस cmp eax, 0x0000ff00
(5B) से cmp eax, edx
(2B) बदलें ।
SSE4 या AVX के साथ, आप इस तेज़ (लेकिन बड़े कोड आकार) के साथ pcmpeqd
और blendvps
तुलना मास्क द्वारा नियंत्रित 32-बिट तत्व आकार चर-मिश्रण करने के लिए कर सकते हैं। (के साथ pand
, आप उच्च बाइट को नजरअंदाज कर सकते हैं)। पैक RGB24 के लिए, आप बाइट्स में TRUE प्राप्त करने के लिए pcmpeqb
2x और फिर 2x pshufb
+ pand
का उपयोग कर सकते हैं, जहाँ उस पिक्सेल के सभी 3 घटक मेल खाते हैं, फिर pblendvb
।
(मुझे पता है कि यह कोड-गोल्फ है, लेकिन मैंने स्केलर पूर्णांक के साथ जाने से पहले MMX की कोशिश करने पर विचार किया था।)