x86-64 (und x86-32) Maschinencode, 13 15 13 Bytes
Änderungsprotokoll:
Bugfix: Die erste Version überprüfte nur G = 0xff, ohne dass R und B 0 sein mussten. Ich änderte den Hintergrund, so dass ich lodsd
im Vordergrund fg Pixel eax
für die Kurzformkodierung cmp eax, imm32
(5 Bytes) verwenden konnte ) anstelle von cmp dh,0xff
(3 Byte).
Save 2 bytes (2 Byte speichern): Es wurde bemerkt, dass das Ändern des BG an Ort und Stelle die Verwendung eines Speicheroperanden zum cmov
Speichern eines 2-Byte- mov
Ladevorgangs (und zum Speichern eines Registers, falls dies wichtig ist) ermöglicht.
Dies ist eine Funktion, die der Aufrufkonvention von x86-64 System V folgt und direkt von C oder C ++ (auf x86-64-Systemen ohne Windows) mit dieser Signatur aufgerufen werden kann:
void chromakey_blend_RGB32(uint32_t *background /*rdi*/,
const uint32_t *foreground /*rsi*/,
int dummy, size_t pixel_count /*rcx*/);
Das Bildformat ist RGB0 32bpp, wobei sich die grüne Komponente an der zweitniedrigsten Speicheradresse in jedem Pixel befindet. Das Vordergrund- Hintergrundbild wird direkt geändert. pixel_count
ist Zeilen * Spalten. Es kümmert sich nicht um Zeilen / Spalten; Mit chromekey können Sie beliebig viele Speicherbereiche mischen.
RGBA (wobei A 0xFF sein muss) würde die Verwendung einer anderen Konstante erfordern, jedoch keine Änderung der Funktionsgröße. Vordergrund-DWORDs werden auf exakte Gleichheit mit einer beliebigen 32-Bit-Konstante verglichen, die in 4 Bytes gespeichert ist, sodass jede Pixel- oder Chroma-Key-Farbe problemlos unterstützt werden kann.
Der gleiche Maschinencode funktioniert auch im 32-Bit-Modus. Zur Montage als 32-Bit, ändern rdi
zu edi
in der Quelle. Alle anderen Register, die 64-Bit werden, sind implizit (lodsd / stosd und loop), und die anderen expliziten Register bleiben 32-Bit. Beachten Sie jedoch, dass Sie einen Wrapper benötigen, um von 32-Bit-C aus aufzurufen, da keine der standardmäßigen x86-32-Aufrufkonventionen dieselben Regeln wie x86-64 SysV verwendet.
NASM-Auflistung (Maschinencode + Quelle), kommentiert für Anfänger mit Beschreibungen dessen, was die komplexeren Anweisungen tun. (Das Duplizieren der Bedienungsanleitung ist bei normaler Verwendung nicht korrekt.)
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
Um die ursprüngliche NASM-Quelle aus dieser Auflistung zu entfernen, entfernen Sie die führenden 26 Zeichen jeder Zeile mit <chromakey.lst cut -b 26- > chromakey.asm
. Ich habe dies mit
nasm -felf64 chromakey-blend.asm -l /dev/stdout | cut -b -28,$((28+12))-
NASM-Auflistungen generiert. Lassen Sie mehr leere Spalten zwischen dem Computercode und der Quelle, als ich möchte. Verwenden Sie zum Erstellen einer Objektdatei, die Sie mit C oder C ++ verknüpfen können nasm -felf64 chromakey.asm
. (Oder yasm -felf64 chromakey.asm
).
ungetestet , aber ich bin ziemlich zuversichtlich, dass die Grundidee von load / load / cmov / store solide ist, weil es so einfach ist.
Ich könnte 3 Bytes einsparen, wenn der Aufrufer die Chroma-Key-Konstante (0x00ff00) als zusätzliches Argument übergeben müsste, anstatt die Konstante fest in die Funktion zu codieren. Ich glaube nicht, dass die üblichen Regeln das Schreiben einer allgemeineren Funktion erlauben, für die der Aufrufer Konstanten eingerichtet hat. Ist dies jedoch der Fall , wird das 3. Argument (derzeit dummy
) edx
im x86-64-SysV-ABI übergeben. Ändern Sie einfach cmp eax, 0x0000ff00
(5B) zu cmp eax, edx
(2B).
Mit SSE4 oder AVX können Sie dies möglicherweise schneller (aber mit größerer Codegröße) pcmpeqd
und blendvps
mit einer variablen 32-Bit-Elementgröße ausführen, die von der Vergleichsmaske gesteuert wird. (Mit pand
können Sie das High-Byte ignorieren). Für gepacktes RGB24 können Sie pcmpeqb
und dann 2x pshufb
+ verwenden pand
, um WAHR in Bytes zu erhalten, bei denen dann alle 3 Komponenten dieses Pixels übereinstimmen pblendvb
.
(Ich weiß, dass dies Codegolf ist, aber ich habe darüber nachgedacht, MMX zu testen, bevor ich mich für eine skalare Ganzzahl entschieden habe.)