Einzelnen Beitrag anzeigen

Lyan

Registriert seit: 5. Aug 2011
188 Beiträge
 
#1

Verbesserungsvorschläge für Vector3 Class

  Alt 18. Mai 2019, 02:10
Delphi-Version: 10.2 Tokyo
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.

Geändert von Lyan (18. Mai 2019 um 03:06 Uhr)
  Mit Zitat antworten Zitat