Wolfgang Fellger
2006-07-23 15:26:25 UTC
Hallo,
dann wage ich mich mal vor, um hier mein Assemblergekritzel zu zeigen :)
Ich habe folgende Funktion:
procedure AlphaBlendLine(Dest, Src: Pointer; Length: integer; Value: byte);
asm
push EBX
push ESI
mov EBX, Dest
mov ESI, Src
mov DL, Value
mov DH, $FF
sub DH, DL
inc DH
xor AX, AX
@Loop:
mov AL, [EBX]
mul DL
shl EAX, 8
mov AL, [ESI]
mul DH
shr EAX, 8
add AH, AL
mov [EBX], AH
inc EBX
inc ESI
dec ECX
JNZ @Loop
pop ESI
pop EBX
end;
(Wie man sieht der Inline-Assembler von Delphi. Im Orginal steht da noch ein
register; dahinter - Length wird bereits direkt in ECX übergeben.)
Sinn und Zweck ist, zwei Bilder ineinander zu überblenden. Normalerweise würde
man den Wert eines Zielpixels mit
Z = A*T + B*(1-T)
berechnen; um mir die Fließkommaberechnung zu ersparen wird Value hier als
Bruchteil von 256 gesehen. Das Ganze arbeitet auf 24-bit-Bilddaten.
Funktionsweise: Vor Beginn der Schleife berechne ich (256-Value) und speichere
diesen Wert in DH, neben Value selbst in DL. In der Schleife wird dann erst ein
Byte aus Dest geladen und multipliziert. Anschließend schiebe ich EAX 8 bit
nach links, um die hohen 8 bit des Ergebnisses aufzubewahren. Danach folgt noch
die Multiplikation eines Bytes aus Src, und EAX wird wieder zurückgeschoben.
Nun werden die hohen Ergebnisanteile beider Multiplikationen addiert und das
Ergebnis in Dest gespeichert. Auf einen Überlauf wird nicht geprüft, da hier
keiner vorkommen kann (oder hab ich einen Fall übersehen?).
Funktioniert soweit prächtig[*], daher jetzt die Frage ob jemand noch
Möglichkeiten findet dieses zu beschleunigen. Natürlich bin ich auch für
komplett andere Ansätze offen.
Ich hatte über eine Lösung mit MMX nachgedacht, nur scheitert das daran dass es
leider kein PMUL für gepackte Bytes gibt :-|
So. Ich danke schonmal im Voraus für Antworten.
dann wage ich mich mal vor, um hier mein Assemblergekritzel zu zeigen :)
Ich habe folgende Funktion:
procedure AlphaBlendLine(Dest, Src: Pointer; Length: integer; Value: byte);
asm
push EBX
push ESI
mov EBX, Dest
mov ESI, Src
mov DL, Value
mov DH, $FF
sub DH, DL
inc DH
xor AX, AX
@Loop:
mov AL, [EBX]
mul DL
shl EAX, 8
mov AL, [ESI]
mul DH
shr EAX, 8
add AH, AL
mov [EBX], AH
inc EBX
inc ESI
dec ECX
JNZ @Loop
pop ESI
pop EBX
end;
(Wie man sieht der Inline-Assembler von Delphi. Im Orginal steht da noch ein
register; dahinter - Length wird bereits direkt in ECX übergeben.)
Sinn und Zweck ist, zwei Bilder ineinander zu überblenden. Normalerweise würde
man den Wert eines Zielpixels mit
Z = A*T + B*(1-T)
berechnen; um mir die Fließkommaberechnung zu ersparen wird Value hier als
Bruchteil von 256 gesehen. Das Ganze arbeitet auf 24-bit-Bilddaten.
Funktionsweise: Vor Beginn der Schleife berechne ich (256-Value) und speichere
diesen Wert in DH, neben Value selbst in DL. In der Schleife wird dann erst ein
Byte aus Dest geladen und multipliziert. Anschließend schiebe ich EAX 8 bit
nach links, um die hohen 8 bit des Ergebnisses aufzubewahren. Danach folgt noch
die Multiplikation eines Bytes aus Src, und EAX wird wieder zurückgeschoben.
Nun werden die hohen Ergebnisanteile beider Multiplikationen addiert und das
Ergebnis in Dest gespeichert. Auf einen Überlauf wird nicht geprüft, da hier
keiner vorkommen kann (oder hab ich einen Fall übersehen?).
Funktioniert soweit prächtig[*], daher jetzt die Frage ob jemand noch
Möglichkeiten findet dieses zu beschleunigen. Natürlich bin ich auch für
komplett andere Ansätze offen.
Ich hatte über eine Lösung mit MMX nachgedacht, nur scheitert das daran dass es
leider kein PMUL für gepackte Bytes gibt :-|
So. Ich danke schonmal im Voraus für Antworten.
--
Wolfgang Fellger
[*] Außer für Value=0, diesen Sonderfall sollte ich noch abfangen. Außerdem
wird das Ergebnis durch das doppelte Abrunden zu dunkel, das fällt allerdings
optisch nicht ins Gewicht.
Wolfgang Fellger
[*] Außer für Value=0, diesen Sonderfall sollte ich noch abfangen. Außerdem
wird das Ergebnis durch das doppelte Abrunden zu dunkel, das fällt allerdings
optisch nicht ins Gewicht.