Autor Beitrag
Spaceguide
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: So 02.04.06 19:39 
Gegeben sind zwei Arrays:

ausblenden Delphi-Quelltext
1:
2:
TPackSingle = array [0..3of single;
TPackByte = array [0..3of byte;


Ich würde gerne eine schnelle Umwandlung mittels SSE realisieren:

-TPackSingle mit 255 multiplizieren
-Abschneiden, falls <0 oder >255
-Runden und in TPackByte speichern

Der SSE-Befehl "CVTPS2PI" wandelt zwei Singles in zwei Ints um. Befehle zum Abschneiden (Saturation) gibts es soweit ich weiss auch. Eventuell kann man ja auch alle vier Floats auf einen Rutsch umwandeln?

Moderiert von user profile iconChristian S.: Delphi-Tags hinzugefügt
zemy
ontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic starofftopic star
Beiträge: 207

Win XP Prof.
D7
BeitragVerfasst: So 02.04.06 23:18 
WIllst du also ne schnelle Version von
ausblenden Delphi-Quelltext
1:
2:
for i:=0 to 3 do
 bytearray[i]:=trunc(singlearray[i]*255and &0000FF;

???

(Blos verständnishalber...)

MfG

_________________
LifeIsToShortToThinkAboutTheShortness
Spaceguide Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: So 02.04.06 23:28 
So ähnlich, eher:


ausblenden Delphi-Quelltext
1:
2:
3:
 
 for i:=0 to 3 do
 bytearray[i]:=Max(Min(Round(singlearray[i]*255),255),0);
Allesquarks
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 510

Win XP Prof
Delphi 7 E
BeitragVerfasst: Mo 03.04.06 00:09 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure roundsingles(var singlepack1:TPacksingles;var integerpack1:TPackinteger);
asm
CVTPS2DQ xmm0, @singlepack1;//Achtung SSE2 arme Leute mit AMD ohne 64 Bit hab leider selber keinen

{Aus Assembler Joachim Rohde:
CVTPS2DQ konvertiert vier gepackte Fließkommazahlen mit einfeacher Genauigkeit aus dem zweiten Operanden in vier gepackte vorzeichenbehaftete Doublewords (Das sind ja integer), die ganze Zahlen enthalten, in den ersten Operanden... gemäß Rounding Control im MXSCR-Register...}


movaps @integerpack1,xmm0;

{oder falls nicht funktioniert
movups @integerpack1;}


end;


Jetzt sind es zwar integer aber das ist sowieso besser, da die bytes dann aligned sind und außerdem gibt es diese Befehle in SSE-glaube ich nicht. Man könnte jetzt zwar mit extract byte etc rumspielen aber das würde den Geschwindigkeitsvorteil glaube ich aufzehren. Die SSE Umgebung muss erst initialisiert werden. Das sollte nicht in der Procedur geschehen wenn die in einer Schleife läuft. Und wenn im ganzen Programm insgesamt nur vier Werte gerundet werden sollen dann bringt es noch keinen Geschwindigkeitsvorteil.
Spaceguide Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: Mo 03.04.06 00:59 
Naja, SSE2 will ich nicht unbedingt vorraussetzen.

So bekomm ich es auf SSE zum laufen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure RoundSingles(const src:TPacksingle; var dst :TPackinteger);
asm
 movups xmm0, [src]
 CVTPS2PI mm0, xmm0
 movq [dst],mm0
 movups xmm1, [src]+8 //Offset = Src[2] = 2*SizeOf(single)
 CVTPS2PI mm1, xmm1
 movq [dst]+8,mm1 //Offset = Dst[2] = 2*SizeOf(integer)
end;


...fehlt noch das Abschneiden des Wertebereichs.
Allesquarks
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 510

Win XP Prof
Delphi 7 E
BeitragVerfasst: Mo 03.04.06 02:07 
Ich würde aber die singles nicht doppelt laden (mit dem Offset von 8). Erstens arbeiten SSE Befehle meines wissens am schnellsten bei einer Speicherausrichtung von 16, die dann mindestens einmal verfehlt wird außerdem liegen die Daten ja schon im xmm Register und es sollte schneller sein sie in diesem zu verschieben. MOVHLPS move packed single-precision floating point values high to low oder obere zwei in untere zwei.

//Edit der Smilie ist ne 8
Spaceguide Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 552


(D3/D7/D8) Prof.
BeitragVerfasst: Mo 03.04.06 02:56 
Yo, gute Idee. Hier mal eine Version mit Saturation, da kann man bestimmt noch etwas optimieren, sieht nämlich nicht sehr elegant aus. Die ganze Routine ist aber jetzt schon schneller als ein simples Round()!

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure RoundSingles(var src:TPacksingle; var dst : TPackByte);
asm
 MOVUPS xmm0, [src] //load 4 singles into xmm0
 CVTPS2PI mm0, xmm0 //round lower two into mm0
 PACKUSWB mm0,mm0 //AABB???? => 0A0B????, saturate 0-255
 MOVD eax,mm0 //0A0B => EAX
 MOV ecx,eax  //0A0B => ECX
 SHR eax,8 //0A0B => 00A0
 OR eax,ecx // 0A0B OR 0AAB
 MOV [dst],ax //AB => dst[0-1]

 MOVHLPS xmm0, xmm0 //copy the two high fps from xmm0 to the low of xmm0
 CVTPS2PI mm0, xmm0
 PACKUSWB mm0,mm0
 MOVD eax,mm0
 MOV ecx,eax
 SHR ecx,8
 OR eax,ecx

 mov [dst]+2,ax //AB => dst[2-3]
 emms
end;