Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Verbesserungsvorschläge für Vector3 Class (https://www.delphipraxis.net/200714-verbesserungsvorschlaege-fuer-vector3-class.html)

Lyan 18. Mai 2019 01:10

Delphi-Version: 10.2 Tokyo

Verbesserungsvorschläge für Vector3 Class
 
Ich hatte/habe Probleme eine simple, effiziente Vector3-Klasse zu finden, die außerdem auch zugriff via [] erlaubt. Habe also heute meine eigene geschrieben, habe ein paar Fragen dazu.

1) Ist es möglich Heap/Stack in Delphi immer 16 Byte zu alignen, dass ich movaps anstatt movups nutzen kann? Heap whs. via custom allocator, Stack finde ich gar keine Lösung zu.
2) Um movups überhaupt zu verwenden, musste ich 128 bit (Values: array[0..3] of Single) allocaten. Alternativ hätte ich movq/movss nutzen können, jetzt stellt sich mir allgemein die Frage was schneller ist und ob man das als extrem unschön ansehen sollte dass ich 4 anstatt 3 Singles ;) habe. Ich sehe halt das Problem, wenn man davon ausgeht dass es 3 Werte sind und SizeOf(TVector3) macht man überrascht sein könnte.
3) Kann man das mit dem property access "[]" so wie ich es gemacht habe verbesser? Ich habe extra keinen Index check, ich rede eher von anderen Methoden, wie ich es z.B. aus c++ gewöhnt war mit operator [] überschreiben.
4) In c++ hätte ich die Vectors als const referenz übergeben. Also hier ja dann eigtl. const var? Wie geht das?
5) Allgemeine verbesserungen

Weiteres: Ich habe hier entnommen, dass ab Ryzen oder Skylake keine Performance-Unterschiede mehr sind zwischen movups/movaps (und bei neuren Prozessoren whs.).

Danke für die Hilfe!

Delphi-Quellcode:
unit UnitVector3;

interface

type TVector3 = record
  private
    FValues: array[0..3]of Single;
    function GetValue(AIndex: Integer): Single; inline;
    procedure SetValue(AIndex: Integer; AValue: Single); inline;
  public
    // properties
    property X: Single read FValues[0] write FValues[0];
    property Y: Single read FValues[1] write FValues[1];
    property Z: Single read FValues[2] write FValues[2];
    property Values[AIndex: Integer]: Single read GetValue write SetValue; default;

    // funcs
    class function Create(const AX, AY, AZ: Single): TVector3; inline; static;
    procedure SetNormalize;
    function Normalize: TVector3;
    function Length: Single;
    function LengthSquared: Single;
    function Length2D: Single;
    function LengthSquared2D: Single;
    function Dot(const B: TVector3): Single;
    function Cross(const B: TVector3): TVector3;
    function Distance(const B: TVector3): Single;
    function DistanceSquared(const B: TVector3): Single;

    // operators
    class operator Negative(const A: TVector3): TVector3; inline;
    class operator Positive(const A: TVector3): TVector3; inline;
    class operator Equal(const A, B: TVector3): Boolean; inline;
    class operator NotEqual(const A, B: TVector3): Boolean; inline;

    // Vector mit Vector
    class operator Add(const A, B: TVector3): TVector3;
    class operator Subtract(const A, B: TVector3): TVector3;
    class operator Multiply(const A, B: TVector3): TVector3;
    class operator Divide(const A, B: TVector3): TVector3;

    // Vector mit Single
    class operator Add(const A: TVector3; const B: Single): TVector3;
    class operator Subtract(const A: TVector3; const B: Single): TVector3;
    class operator Multiply(const A: TVector3; const B: Single): TVector3;
    class operator Divide(const A: TVector3; const B: Single): TVector3;

    // Single mit Vector
    class operator Add(const A: Single; const B: TVector3): TVector3;
    class operator Subtract(const A: Single; const B: TVector3): TVector3;
    class operator Multiply(const A: Single; const B: TVector3): TVector3;
    class operator Divide(const A: Single; const B: TVector3): TVector3;
end;

implementation

{ TVector3 }

class operator TVector3.Add(const A, B: TVector3): TVector3; assembler;
asm
  movups xmm0, [A]
  movups xmm1, [B]
  addps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.Add(const A: TVector3; const B: Single): TVector3; assembler;
asm
  movups xmm0, [A]
  movss  xmm1, [B]
  shufps xmm1, xmm1, 0
  addps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.Add(const A: Single; const B: TVector3): TVector3; assembler;
asm
  movups xmm0, [B]
  movss  xmm1, [A]
  shufps xmm1, xmm1, 0
  addps  xmm0, xmm1
  movups [Result], xmm0
end;

class function TVector3.Create(const AX, AY, AZ: Single): TVector3;
begin
  Result.X := AX;
  Result.Y := AY;
  Result.Z := AZ;
end;

function TVector3.Cross(const B: TVector3): TVector3; assembler;
asm
  movups xmm0, [Self]
  movups xmm1, [B]
  movaps xmm2, xmm0
  movaps xmm3, xmm1
  shufps xmm0, xmm0, $C9
  shufps xmm1, xmm1, $D2
  mulps  xmm0, xmm1
  shufps xmm2, xmm2, $D2
  shufps xmm3, xmm3, $C9
  mulps  xmm2, xmm3
  subps  xmm0, xmm2
  movups [Result], xmm0
end;

function TVector3.Distance(const B: TVector3): Single; assembler;
asm
  movups xmm0, [Self]
  movups xmm1, [B]
  subps  xmm0, xmm1
  dpps   xmm0, xmm0, $71
  sqrtps xmm0, xmm0
  movss [Result], xmm0
end;

function TVector3.DistanceSquared(const B: TVector3): Single; assembler;
asm
  movups xmm0, [Self]
  movups xmm1, [B]
  subps  xmm0, xmm1
  dpps   xmm0, xmm0, $71
  movss [Result], xmm0
end;

class operator TVector3.Divide(const A: Single; const B: TVector3): TVector3; assembler;
asm
  movups xmm0, [B]
  movss  xmm1, [A]
  shufps xmm1, xmm1, 0
  divps  xmm0, xmm1
  movups [Result], xmm0
end;

function TVector3.Dot(const B: TVector3): Single; assembler;
asm
  movups xmm0, [Self]
  movups xmm1, [B]
  dpps   xmm0, xmm1, $71
  movss [Result], xmm0
end;

class operator TVector3.Divide(const A: TVector3; const B: Single): TVector3; assembler;
asm
  movups xmm0, [A]
  movss  xmm1, [B]
  shufps xmm1, xmm1, 0
  divps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.Divide(const A, B: TVector3): TVector3; assembler;
asm
  movups xmm0, [A]
  movups xmm1, [B]
  divps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.Equal(const A, B: TVector3): Boolean;
begin
  Result := (A.X = B.X) and (A.Y = B.Y) and (A.Z = B.Z);
end;

function TVector3.GetValue(AIndex: Integer): Single;
begin
  Result := FValues[AIndex];
end;

function TVector3.Length: Single; assembler;
asm
  movups xmm0, [Self]
  dpps   xmm0, xmm0, $71
  sqrtps xmm0, xmm0
  movss  [Result], xmm0
end;

function TVector3.Length2D: Single; assembler;
asm
  movups xmm0, [Self]
  dpps   xmm0, xmm0, $31
  sqrtps xmm0, xmm0
  movss  [Result], xmm0
end;

function TVector3.LengthSquared: Single; assembler;
asm
  movups xmm0, [Self]
  dpps   xmm0, xmm0, $71
  movss  [Result], xmm0
end;

function TVector3.LengthSquared2D: Single; assembler;
asm
  movups xmm0, [Self]
  dpps   xmm0, xmm0, $31
  movss  [Result], xmm0
end;

class operator TVector3.Multiply(const A: Single; const B: TVector3): TVector3; assembler;
asm
  movups xmm0, [B]
  movss  xmm1, [A]
  shufps xmm1, xmm1, 0
  mulps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.Multiply(const A: TVector3; const B: Single): TVector3; assembler;
asm
  movups xmm0, [A]
  movss  xmm1, [B]
  shufps xmm1, xmm1, 0
  mulps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.Multiply(const A, B: TVector3): TVector3; assembler;
asm
  movups xmm0, [A]
  movups xmm1, [B]
  mulps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.Negative(const A: TVector3): TVector3;
begin
  Result.X := -A.X;
  Result.Y := -A.Y;
  Result.Z := -A.Z;
end;

function TVector3.Normalize: TVector3; assembler;
asm
  movups xmm0, [Self]
  movaps xmm1, xmm0
  dpps   xmm0, xmm0, $7F
  rsqrtps xmm0, xmm0
  mulps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.NotEqual(const A, B: TVector3): Boolean;
begin
  Result := (A.X <> B.X) or (A.Y <> B.Y) or (A.Z <> B.Z);
end;

class operator TVector3.Positive(const A: TVector3): TVector3;
begin
  Result := A;
end;

procedure TVector3.SetNormalize; assembler;
asm
  movups xmm0, [Self]
  movaps xmm1, xmm0
  dpps   xmm0, xmm0, $7F
  rsqrtps xmm0, xmm0
  mulps  xmm0, xmm1
  movups [Self], xmm0
end;

procedure TVector3.SetValue(AIndex: Integer; AValue: Single);
begin
  FValues[AIndex] := AValue;
end;

class operator TVector3.Subtract(const A: Single; const B: TVector3): TVector3; assembler;
asm
  movups xmm0, [B]
  movss  xmm1, [A]
  shufps xmm1, xmm1, 0
  subps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.Subtract(const A: TVector3; const B: Single): TVector3; assembler;
asm
  movups xmm0, [A]
  movss  xmm1, [B]
  shufps xmm1, xmm1, 0
  subps  xmm0, xmm1
  movups [Result], xmm0
end;

class operator TVector3.Subtract(const A, B: TVector3): TVector3; assembler;
asm
  movups xmm0, [A]
  movups xmm1, [B]
  subps  xmm0, xmm1
  movups [Result], xmm0
end;

end.

TurboMagic 18. Mai 2019 08:42

AW: Verbesserungsvorschläge für Vector3 Class
 
Zur Steuerung der Allokation gibt es die $A Direktive. Schon geschaut, ob die inzwischen auch 16 Byte ALlokation kann?

Mavarik 18. Mai 2019 10:11

AW: Verbesserungsvorschläge für Vector3 Class
 
Zitat:

Zitat von Lyan (Beitrag 1432478)
Habe also heute meine eigene geschrieben...

I like this Idea to have an ASM Vector Lib.

But it had to be multiplattform/CPU and 32/64.

Perhaps you like to take a look at this!

Mavarik

TiGü 20. Mai 2019 08:31

AW: Verbesserungsvorschläge für Vector3 Class
 
Warum antwortest du auf englisch? :gruebel:

Der schöne Günther 20. Mai 2019 09:16

AW: Verbesserungsvorschläge für Vector3 Class
 
Babylon.

Sieht gar nicht übel aus, aber grade bei so wildem Assembler-Kram - Gibt es keine Tests?

freimatz 20. Mai 2019 13:43

AW: Verbesserungsvorschläge für Vector3 Class
 
Nun ja die Grundsatzfrage ist, ob das nur für ihn ist oder auch für andere. Das "und SizeOf(TVector3) macht man überrascht sein könnte." deutet vielleicht eher auf letzteres. Dann fehlt auch noch Doku, unter anderem zuerst was ein Vector3 denn ist. (In unser Software haben wir tausende an Vektor-Rechnungen, der Begriff ist mir noch nicht untergekommen, google hilft auch wenig weiter.)
Was für uns die unit unbrauchbar macht ist, dass die auf Single basiert und nicht auf Double.

TiGü 20. Mai 2019 15:01

AW: Verbesserungsvorschläge für Vector3 Class
 
Zitat:

Zitat von freimatz (Beitrag 1432611)
Dann fehlt auch noch Doku, unter anderem zuerst was ein Vector3 denn ist. (In unser Software haben wir tausende an Vektor-Rechnungen, der Begriff ist mir noch nicht untergekommen, google hilft auch wenig weiter.)

Hm, wenn ich "Vector3" in Google eingebe kommt unter den ersten vier Suchtreffern:
https://docs.unity3d.com/ScriptReference/Vector3.html
https://docs.microsoft.com/de-de/dot...tframework-4.8

Ist wohl nicht ganz so unüblich als Benennung.

Also ein Vektor im Raum der durch die Koordinaten x, y, z definiert ist.

Wie heißen denn eure Vektoren-Datentypen?

Der schöne Günther 20. Mai 2019 16:37

AW: Verbesserungsvorschläge für Vector3 Class
 
Ich finde Vector3 eigentlich auch eindeutig als Namen.
Nur mir fehlt wirklich Doku, der Quelltext hilft mir leider nicht weiter. Stell es doch auf z.B. Github, der ein oder andere (z.B ich) macht sicher gerne ein paar Tests dafür...

TRomano 21. Mai 2019 08:35

AW: Verbesserungsvorschläge für Vector3 Class
 
Hallo,

unter https://www.agner.org/optimize/ findest Du die aktuellsten Ressourcen zur Optimierung von Assembler-Source auf die verschiedenen CPU´s.

Nun ja, es gibt schon noch Unterschiede von (v)movups und (v)movaps. In den dort hintelegten Instruction tables von Prof. Agner kannst du das wunderbar für jeden Prozessor nachlesen. Das geht bis zu den Ryzens von AMD.
Wahrscheinlich ist das derartig verallgemeinert worden, weil es kaum mehr große Unterschiede macht, ob die Mov-Befehle mit oder oder entsprechendes Alignment benutzt. Zu mindestens bei diesen relativ kleinen Jobs in deinen Routinen. Bei der Bearbeitung riesiger Datenmengen kann das allerdings immer noch einen Unterschied machen.
Leider unterstützt Delphi noch immer kein AVX, AVX2, geschweige den AVX5212 mit all seinen Derivaten, direkt, so das man hier zu externen Assemblern greifen muss und dann die entsprechenden Object-Files einbinden muss.

Gruß Thomas

Mavarik 21. Mai 2019 10:18

AW: Verbesserungsvorschläge für Vector3 Class
 
Zitat:

Zitat von TiGü (Beitrag 1432577)
Warum antwortest du auf englisch? :gruebel:


Keinen Plan... Sorry...

War sicherlich gerade mit anderen im Chat...


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:34 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz