Add Vector type in SPMD to total of load vector size * lane width of number into memory for simd calculation.
This commit is contained in:
@@ -28,7 +28,7 @@ public interface IJobParallelFor
|
|||||||
public static class IJobExtensions
|
public static class IJobExtensions
|
||||||
{
|
{
|
||||||
public static void Run<T>(this ref T job, int threadIndex)
|
public static void Run<T>(this ref T job, int threadIndex)
|
||||||
where T : unmanaged, IJob
|
where T : struct, IJob
|
||||||
{
|
{
|
||||||
job.Execute(threadIndex);
|
job.Execute(threadIndex);
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ public static class IJobExtensions
|
|||||||
public static class IJobParallelForExtensions
|
public static class IJobParallelForExtensions
|
||||||
{
|
{
|
||||||
public static void Run<T>(this ref T job, int totalIterations, int threadIndex)
|
public static void Run<T>(this ref T job, int totalIterations, int threadIndex)
|
||||||
where T : unmanaged, IJobParallelFor
|
where T : struct, IJobParallelFor
|
||||||
{
|
{
|
||||||
for (var i = 0; i < totalIterations; i++)
|
for (var i = 0; i < totalIterations; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
|
|||||||
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
public interface IJobSPMD<TNumber>
|
public interface IJobSPMD<TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
void Execute<TLane>(int baseIndex, int threadIndex)
|
void Execute<TLane>(int baseIndex, int threadIndex)
|
||||||
where TLane : ISPMD<TLane, TNumber>;
|
where TLane : ISPMD<TLane, TNumber>;
|
||||||
@@ -13,7 +13,7 @@ public interface IJobSPMD<TNumber>
|
|||||||
|
|
||||||
internal struct SPMDJobWrapper<T, TNumber> : IJobParallelFor
|
internal struct SPMDJobWrapper<T, TNumber> : IJobParallelFor
|
||||||
where T : unmanaged, IJobSPMD<TNumber>
|
where T : unmanaged, IJobSPMD<TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
public T innerJob;
|
public T innerJob;
|
||||||
public int totalCount;
|
public int totalCount;
|
||||||
@@ -40,7 +40,7 @@ internal struct SPMDJobWrapper<T, TNumber> : IJobParallelFor
|
|||||||
|
|
||||||
internal struct SPMDScalerJobWrapper<T, TNumber> : IJobParallelFor
|
internal struct SPMDScalerJobWrapper<T, TNumber> : IJobParallelFor
|
||||||
where T : unmanaged, IJobSPMD<TNumber>
|
where T : unmanaged, IJobSPMD<TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
public T innerJob;
|
public T innerJob;
|
||||||
public int totalCount;
|
public int totalCount;
|
||||||
@@ -55,32 +55,42 @@ internal struct SPMDScalerJobWrapper<T, TNumber> : IJobParallelFor
|
|||||||
public static class IJobParallelForSPMDExtensions
|
public static class IJobParallelForSPMDExtensions
|
||||||
{
|
{
|
||||||
public static void Run<T, TNumber>(this ref T job, int totalCount, int threadIndex)
|
public static void Run<T, TNumber>(this ref T job, int totalCount, int threadIndex)
|
||||||
where T : unmanaged, IJobSPMD<TNumber>
|
where T : struct, IJobSPMD<TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
var iterations = (totalCount + WideLane<TNumber>.LaneWidth - 1) / WideLane<TNumber>.LaneWidth;
|
if (WideLane.IsSupported)
|
||||||
for (var loopIndex = 0; loopIndex < iterations; loopIndex++)
|
|
||||||
{
|
{
|
||||||
var baseIndex = loopIndex * WideLane<TNumber>.LaneWidth;
|
var iterations = (totalCount + WideLane<TNumber>.LaneWidth - 1) / WideLane<TNumber>.LaneWidth;
|
||||||
var remaining = totalCount - baseIndex;
|
for (var loopIndex = 0; loopIndex < iterations; loopIndex++)
|
||||||
|
{
|
||||||
|
var baseIndex = loopIndex * WideLane<TNumber>.LaneWidth;
|
||||||
|
var remaining = totalCount - baseIndex;
|
||||||
|
|
||||||
if (remaining >= WideLane<TNumber>.LaneWidth)
|
if (remaining >= WideLane<TNumber>.LaneWidth)
|
||||||
{
|
|
||||||
job.Execute<WideLane<TNumber>>(baseIndex, threadIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (var i = 0; i < remaining; i++)
|
|
||||||
{
|
{
|
||||||
job.Execute<ScalarLane<TNumber>>(baseIndex + i, threadIndex);
|
job.Execute<WideLane<TNumber>>(baseIndex, threadIndex);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 0; i < remaining; i++)
|
||||||
|
{
|
||||||
|
job.Execute<ScalarLane<TNumber>>(baseIndex + i, threadIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var loopIndex = 0; loopIndex < totalCount; loopIndex++)
|
||||||
|
{
|
||||||
|
job.Execute<ScalarLane<TNumber>>(loopIndex, threadIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JobHandle ScheduleParallelSPDM<T, TNumber>(this JobScheduler jobScheduler, ref T job, int totalCount, int batchSize, int threadIndex, JobHandle dependency)
|
public static JobHandle ScheduleParallelSPDM<T, TNumber>(this JobScheduler jobScheduler, ref T job, int totalCount, int batchSize, int threadIndex, JobHandle dependency)
|
||||||
where T : unmanaged, IJobSPMD<TNumber>
|
where T : unmanaged, IJobSPMD<TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
if (WideLane.IsSupported)
|
if (WideLane.IsSupported)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public interface ISPMD
|
|||||||
/// <typeparam name="TNumber">The underlying numeric element type.</typeparam>
|
/// <typeparam name="TNumber">The underlying numeric element type.</typeparam>
|
||||||
public interface ISPMD<TSelf, TNumber> : ISPMD, IEquatable<TSelf>
|
public interface ISPMD<TSelf, TNumber> : ISPMD, IEquatable<TSelf>
|
||||||
where TSelf : ISPMD<TSelf, TNumber>
|
where TSelf : ISPMD<TSelf, TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a lane value where all lanes are set to numeric zero.
|
/// Gets a lane value where all lanes are set to numeric zero.
|
||||||
@@ -241,7 +241,39 @@ public interface ISPMD<TSelf, TNumber> : ISPMD, IEquatable<TSelf>
|
|||||||
/// <param name="b">The second value to compare.</param>
|
/// <param name="b">The second value to compare.</param>
|
||||||
/// <returns>All bits set where the elements are not equal; otherwise, all bits cleared.</returns>
|
/// <returns>All bits set where the elements are not equal; otherwise, all bits cleared.</returns>
|
||||||
static abstract TSelf operator !=(TSelf a, TSelf b);
|
static abstract TSelf operator !=(TSelf a, TSelf b);
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether one instance of the type is greater than another instance component-wise.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first value to compare.</param>
|
||||||
|
/// <param name="b">The second value to compare.</param>
|
||||||
|
/// <returns>A value indicating whether the first parameter is greater than the second parameter.</returns>
|
||||||
|
static abstract TSelf operator >(TSelf a, TSelf b);
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the first operand is greater than or equal to the second operand component-wise.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first value to compare.</param>
|
||||||
|
/// <param name="b">The second value to compare.</param>
|
||||||
|
/// <returns>All bits set where the first parameter is greater than or equal to the second parameter; otherwise, all bits cleared.</returns>
|
||||||
|
static abstract TSelf operator >=(TSelf a, TSelf b);
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether one instance of the type is less than another instance component-wise.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first value to compare.</param>
|
||||||
|
/// <param name="b">The second value to compare.</param>
|
||||||
|
/// <returns>All bits set where the first parameter is less than the second parameter; otherwise, all bits cleared.</returns>
|
||||||
|
static abstract TSelf operator <(TSelf a, TSelf b);
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the first operand is less than or equal to the second operand component-wise.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first value to compare.</param>
|
||||||
|
/// <param name="b">The second value to compare.</param>
|
||||||
|
/// <returns>All bits set where the first parameter is less than or equal to the second parameter; otherwise, all bits cleared.</returns>
|
||||||
|
static abstract TSelf operator <=(TSelf a, TSelf b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implicitly converts a scalar numeric value to a lane value where all lanes are set to that value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The scalar numeric value to convert.</param>
|
||||||
static abstract implicit operator TSelf(TNumber value);
|
static abstract implicit operator TSelf(TNumber value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,153 +0,0 @@
|
|||||||
using System.Numerics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
|
||||||
|
|
||||||
public static unsafe partial class MathV
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> LoadVector3<TLane, TNumber>(TNumber* pSrc)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
var width = TLane.LaneWidth;
|
|
||||||
|
|
||||||
var x = stackalloc TNumber[width];
|
|
||||||
var y = stackalloc TNumber[width];
|
|
||||||
var z = stackalloc TNumber[width];
|
|
||||||
|
|
||||||
for (var i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
x[i] = pSrc[i * 3 + 0];
|
|
||||||
y[i] = pSrc[i * 3 + 1];
|
|
||||||
z[i] = pSrc[i * 3 + 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = TLane.Load(x),
|
|
||||||
y = TLane.Load(y),
|
|
||||||
z = TLane.Load(z)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(ref TNumber src)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return LoadVector3<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src));
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(TNumber* pX, TNumber* pY, TNumber* pZ)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = TLane.Load(pX),
|
|
||||||
y = TLane.Load(pY),
|
|
||||||
z = TLane.Load(pZ)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(ref TNumber x, ref TNumber y, ref TNumber z)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = TLane.Load(ref x),
|
|
||||||
y = TLane.Load(ref y),
|
|
||||||
z = TLane.Load(ref z)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> Abs<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = TLane.Abs(vector.x),
|
|
||||||
y = TLane.Abs(vector.y),
|
|
||||||
z = TLane.Abs(vector.z),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static TLane Dot<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return a.x * b.x + a.y * b.y + a.z * b.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static TLane LengthSquared<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return Dot(vector, vector);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> Sqrt<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = TLane.Sqrt(vector.x),
|
|
||||||
y = TLane.Sqrt(vector.y),
|
|
||||||
z = TLane.Sqrt(vector.z),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3<TLane, TNumber> Rsqrt<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = TLane.Rsqrt(vector.x),
|
|
||||||
y = TLane.Rsqrt(vector.y),
|
|
||||||
z = TLane.Rsqrt(vector.z),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> Normalize<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return vector * TLane.Rsqrt(Dot(vector, vector));
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> Cross<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = a.y * b.z - a.z * b.y,
|
|
||||||
y = a.z * b.x - a.x * b.z,
|
|
||||||
z = a.x * b.y - a.y * b.x,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> Reflect<TLane, TNumber>(in Vector3<TLane, TNumber> incident, in Vector3<TLane, TNumber> normal)
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
var dot = Dot(incident, normal);
|
|
||||||
return incident - normal * (dot + dot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,8 +7,81 @@
|
|||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Templates\Vector2 - Copy (2).gen.cs" />
|
||||||
|
<Compile Remove="Templates\Vector2 - Copy.gen.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Templates\Vector2.gen.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Vector2.tt</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="Templates\Vector{T}Helper.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Vector{T}Helper.ttinclude</DependentUpon>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Misaki.HighPerformance.Jobs\Misaki.HighPerformance.Jobs.csproj" />
|
<ProjectReference Include="..\Misaki.HighPerformance.Jobs\Misaki.HighPerformance.Jobs.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Templates\MathV.Vector.tt">
|
||||||
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
|
<LastGenOutput>MathV.Vector.gen.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<None Update="Templates\Vector3.tt">
|
||||||
|
<LastGenOutput>Vector3.gen.cs</LastGenOutput>
|
||||||
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
|
</None>
|
||||||
|
<None Update="Templates\Vector4.tt">
|
||||||
|
<LastGenOutput>Vector4.gen.cs</LastGenOutput>
|
||||||
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
|
</None>
|
||||||
|
<None Update="Templates\Vector2.tt">
|
||||||
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Vector2.gen.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<None Update="Templates\Vector{T}Helper.ttinclude">
|
||||||
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Vector{T}Helper.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Templates\MathV.Vector.gen.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>MathV.Vector.tt</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Templates\Vector2.gen.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Vector2.tt</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Templates\Vector3.gen.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Vector3.tt</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Templates\Vector4.gen.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Vector4.tt</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Templates\Vector{T}Helper.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Vector{T}Helper.ttinclude</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Misaki.HighPerformance.Mathematics.SPMD;
|
|||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, TNumber>
|
public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
public readonly TNumber value;
|
public readonly TNumber value;
|
||||||
|
|
||||||
@@ -186,13 +186,37 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<TNumber> operator ==(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
public static ScalarLane<TNumber> operator ==(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
{
|
{
|
||||||
return new(a.value == b.value ? ~TNumber.Zero : TNumber.Zero);
|
return Equal(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<TNumber> operator !=(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
public static ScalarLane<TNumber> operator !=(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
{
|
{
|
||||||
return new(a.value != b.value ? ~TNumber.Zero : TNumber.Zero);
|
return ~Equal(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator >(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return GreaterThan(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator >=(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return GreaterThanOrEqual(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator <(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return LessThan(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ScalarLane<TNumber> operator <=(ScalarLane<TNumber> a, ScalarLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return LessThanOrEqual(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -479,7 +503,7 @@ public readonly unsafe struct ScalarLane<TNumber> : ISPMD<ScalarLane<TNumber>, T
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ScalarLane<TNumber> Exp2(ScalarLane<TNumber> value)
|
public static ScalarLane<TNumber> Exp2(ScalarLane<TNumber> value)
|
||||||
{
|
{
|
||||||
return Pow(new ScalarLane<TNumber>(TNumber.CreateChecked(2)), value);
|
return Pow(new ScalarLane<TNumber>(TNumber.CreateTruncating(2)), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|||||||
@@ -0,0 +1,873 @@
|
|||||||
|
/// <auto-generated/>
|
||||||
|
/// This code is automatically generated by a T4 template.
|
||||||
|
/// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
/// </auto-generated>
|
||||||
|
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
|
|
||||||
|
public static unsafe partial class MathV
|
||||||
|
{
|
||||||
|
# region Vector2
|
||||||
|
|
||||||
|
// Creation Functions
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Create<TLane, TNumber>(in TLane x, in TLane y)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = x,
|
||||||
|
y = y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> CreateVector2<TLane, TNumber>(in TLane value)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = value,
|
||||||
|
y = value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> LoadVector2<TLane, TNumber>(TNumber* pSrc)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var width = TLane.LaneWidth;
|
||||||
|
|
||||||
|
var x = stackalloc TNumber[width];
|
||||||
|
var y = stackalloc TNumber[width];
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
x[i] = pSrc[i * 2 + 0];
|
||||||
|
y[i] = pSrc[i * 2 + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(x),
|
||||||
|
y = TLane.Load(y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> LoadVector2<TLane, TNumber>(ref TNumber src)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return LoadVector2<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Load<TLane, TNumber>(TNumber* px, TNumber* py)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(px),
|
||||||
|
y = TLane.Load(py),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Load<TLane, TNumber>(ref TNumber x, ref TNumber y)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(ref x),
|
||||||
|
y = TLane.Load(ref y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Math Functions
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Abs<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Abs(vector.x),
|
||||||
|
y = TLane.Abs(vector.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Dot<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return a.x * b.x + a.y * b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Sqrt<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Sqrt(vector.x),
|
||||||
|
y = TLane.Sqrt(vector.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Rsqrt<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Rsqrt(vector.x),
|
||||||
|
y = TLane.Rsqrt(vector.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Normalize<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return vector * TLane.Rsqrt(Dot(vector, vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Reflect<TLane, TNumber>(in Vector2<TLane, TNumber> incident, in Vector2<TLane, TNumber> normal)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var dot = Dot(incident, normal);
|
||||||
|
return incident - normal * (dot + dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Min<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Min(a.x, b.x),
|
||||||
|
y = TLane.Min(a.y, b.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Max<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Max(a.x, b.x),
|
||||||
|
y = TLane.Max(a.y, b.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Clamp<TLane, TNumber>(in Vector2<TLane, TNumber> value, in Vector2<TLane, TNumber> min, in Vector2<TLane, TNumber> max)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Min(Max(value, min), max);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Saturate<TLane, TNumber>(in Vector2<TLane, TNumber> value)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Clamp(value, CreateVector2<TLane, TNumber>(TLane.Zero), CreateVector2<TLane, TNumber>(TLane.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Lerp<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b, TLane t)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return a + (b - a) * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Length<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return TLane.Sqrt(Dot(vector, vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane LengthSquared<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Dot(vector, vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Distance<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var diff = b - a;
|
||||||
|
return TLane.Sqrt(Dot(diff, diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane DistanceSquared<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var diff = b - a;
|
||||||
|
return Dot(diff, diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Step<TLane, TNumber>(in Vector2<TLane, TNumber> edge, in Vector2<TLane, TNumber> value)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Select(value >= edge, Vector2<TLane, TNumber>.One, Vector2<TLane, TNumber>.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Smoothstep<TLane, TNumber>(Vector2<TLane, TNumber> xMin, Vector2<TLane, TNumber> xMax, Vector2<TLane, TNumber> x)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var t = Saturate((x - xMin) / (xMax - xMin));
|
||||||
|
var two = TLane.Create(TNumber.CreateTruncating(2));
|
||||||
|
var three = TLane.Create(TNumber.CreateTruncating(3));
|
||||||
|
|
||||||
|
return t * t * (CreateVector2<TLane, TNumber>(three) - (CreateVector2<TLane, TNumber>(two) * t));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Select<TLane, TNumber>(TLane condition, in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Select(condition, b.x, a.x),
|
||||||
|
y = TLane.Select(condition, b.y, a.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> Select<TLane, TNumber>(Vector2<TLane, TNumber> condition, in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Select(condition.x, b.x, a.x),
|
||||||
|
y = TLane.Select(condition.y, b.y, a.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region Vector3
|
||||||
|
|
||||||
|
// Creation Functions
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Create<TLane, TNumber>(in TLane x, in TLane y, in TLane z)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = x,
|
||||||
|
y = y,
|
||||||
|
z = z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> CreateVector3<TLane, TNumber>(in TLane value)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = value,
|
||||||
|
y = value,
|
||||||
|
z = value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> LoadVector3<TLane, TNumber>(TNumber* pSrc)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var width = TLane.LaneWidth;
|
||||||
|
|
||||||
|
var x = stackalloc TNumber[width];
|
||||||
|
var y = stackalloc TNumber[width];
|
||||||
|
var z = stackalloc TNumber[width];
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
x[i] = pSrc[i * 3 + 0];
|
||||||
|
y[i] = pSrc[i * 3 + 1];
|
||||||
|
z[i] = pSrc[i * 3 + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(x),
|
||||||
|
y = TLane.Load(y),
|
||||||
|
z = TLane.Load(z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> LoadVector3<TLane, TNumber>(ref TNumber src)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return LoadVector3<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(TNumber* px, TNumber* py, TNumber* pz)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(px),
|
||||||
|
y = TLane.Load(py),
|
||||||
|
z = TLane.Load(pz),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(ref TNumber x, ref TNumber y, ref TNumber z)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(ref x),
|
||||||
|
y = TLane.Load(ref y),
|
||||||
|
z = TLane.Load(ref z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Math Functions
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Abs<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Abs(vector.x),
|
||||||
|
y = TLane.Abs(vector.y),
|
||||||
|
z = TLane.Abs(vector.z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Dot<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return a.x * b.x + a.y * b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Sqrt<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Sqrt(vector.x),
|
||||||
|
y = TLane.Sqrt(vector.y),
|
||||||
|
z = TLane.Sqrt(vector.z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Rsqrt<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Rsqrt(vector.x),
|
||||||
|
y = TLane.Rsqrt(vector.y),
|
||||||
|
z = TLane.Rsqrt(vector.z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Normalize<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return vector * TLane.Rsqrt(Dot(vector, vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Reflect<TLane, TNumber>(in Vector3<TLane, TNumber> incident, in Vector3<TLane, TNumber> normal)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var dot = Dot(incident, normal);
|
||||||
|
return incident - normal * (dot + dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Min<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Min(a.x, b.x),
|
||||||
|
y = TLane.Min(a.y, b.y),
|
||||||
|
z = TLane.Min(a.z, b.z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Max<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Max(a.x, b.x),
|
||||||
|
y = TLane.Max(a.y, b.y),
|
||||||
|
z = TLane.Max(a.z, b.z),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Clamp<TLane, TNumber>(in Vector3<TLane, TNumber> value, in Vector3<TLane, TNumber> min, in Vector3<TLane, TNumber> max)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Min(Max(value, min), max);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Saturate<TLane, TNumber>(in Vector3<TLane, TNumber> value)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Clamp(value, CreateVector3<TLane, TNumber>(TLane.Zero), CreateVector3<TLane, TNumber>(TLane.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Lerp<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b, TLane t)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return a + (b - a) * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Length<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return TLane.Sqrt(Dot(vector, vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane LengthSquared<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Dot(vector, vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Distance<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var diff = b - a;
|
||||||
|
return TLane.Sqrt(Dot(diff, diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane DistanceSquared<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var diff = b - a;
|
||||||
|
return Dot(diff, diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Step<TLane, TNumber>(in Vector3<TLane, TNumber> edge, in Vector3<TLane, TNumber> value)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Select(value >= edge, Vector3<TLane, TNumber>.One, Vector3<TLane, TNumber>.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Smoothstep<TLane, TNumber>(Vector3<TLane, TNumber> xMin, Vector3<TLane, TNumber> xMax, Vector3<TLane, TNumber> x)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var t = Saturate((x - xMin) / (xMax - xMin));
|
||||||
|
var two = TLane.Create(TNumber.CreateTruncating(2));
|
||||||
|
var three = TLane.Create(TNumber.CreateTruncating(3));
|
||||||
|
|
||||||
|
return t * t * (CreateVector3<TLane, TNumber>(three) - (CreateVector3<TLane, TNumber>(two) * t));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Select<TLane, TNumber>(TLane condition, in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Select(condition, b.x, a.x),
|
||||||
|
y = TLane.Select(condition, b.y, a.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> Select<TLane, TNumber>(Vector3<TLane, TNumber> condition, in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Select(condition.x, b.x, a.x),
|
||||||
|
y = TLane.Select(condition.y, b.y, a.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region Vector4
|
||||||
|
|
||||||
|
// Creation Functions
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Create<TLane, TNumber>(in TLane x, in TLane y, in TLane z, in TLane w)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = x,
|
||||||
|
y = y,
|
||||||
|
z = z,
|
||||||
|
w = w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> CreateVector4<TLane, TNumber>(in TLane value)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = value,
|
||||||
|
y = value,
|
||||||
|
z = value,
|
||||||
|
w = value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> LoadVector4<TLane, TNumber>(TNumber* pSrc)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var width = TLane.LaneWidth;
|
||||||
|
|
||||||
|
var x = stackalloc TNumber[width];
|
||||||
|
var y = stackalloc TNumber[width];
|
||||||
|
var z = stackalloc TNumber[width];
|
||||||
|
var w = stackalloc TNumber[width];
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
x[i] = pSrc[i * 4 + 0];
|
||||||
|
y[i] = pSrc[i * 4 + 1];
|
||||||
|
z[i] = pSrc[i * 4 + 2];
|
||||||
|
w[i] = pSrc[i * 4 + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(x),
|
||||||
|
y = TLane.Load(y),
|
||||||
|
z = TLane.Load(z),
|
||||||
|
w = TLane.Load(w),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> LoadVector4<TLane, TNumber>(ref TNumber src)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return LoadVector4<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Load<TLane, TNumber>(TNumber* px, TNumber* py, TNumber* pz, TNumber* pw)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(px),
|
||||||
|
y = TLane.Load(py),
|
||||||
|
z = TLane.Load(pz),
|
||||||
|
w = TLane.Load(pw),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Load<TLane, TNumber>(ref TNumber x, ref TNumber y, ref TNumber z, ref TNumber w)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Load(ref x),
|
||||||
|
y = TLane.Load(ref y),
|
||||||
|
z = TLane.Load(ref z),
|
||||||
|
w = TLane.Load(ref w),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Math Functions
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Abs<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Abs(vector.x),
|
||||||
|
y = TLane.Abs(vector.y),
|
||||||
|
z = TLane.Abs(vector.z),
|
||||||
|
w = TLane.Abs(vector.w),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Dot<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return a.x * b.x + a.y * b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Sqrt<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Sqrt(vector.x),
|
||||||
|
y = TLane.Sqrt(vector.y),
|
||||||
|
z = TLane.Sqrt(vector.z),
|
||||||
|
w = TLane.Sqrt(vector.w),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Rsqrt<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Rsqrt(vector.x),
|
||||||
|
y = TLane.Rsqrt(vector.y),
|
||||||
|
z = TLane.Rsqrt(vector.z),
|
||||||
|
w = TLane.Rsqrt(vector.w),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Normalize<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return vector * TLane.Rsqrt(Dot(vector, vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Reflect<TLane, TNumber>(in Vector4<TLane, TNumber> incident, in Vector4<TLane, TNumber> normal)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var dot = Dot(incident, normal);
|
||||||
|
return incident - normal * (dot + dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Min<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Min(a.x, b.x),
|
||||||
|
y = TLane.Min(a.y, b.y),
|
||||||
|
z = TLane.Min(a.z, b.z),
|
||||||
|
w = TLane.Min(a.w, b.w),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Max<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Max(a.x, b.x),
|
||||||
|
y = TLane.Max(a.y, b.y),
|
||||||
|
z = TLane.Max(a.z, b.z),
|
||||||
|
w = TLane.Max(a.w, b.w),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Clamp<TLane, TNumber>(in Vector4<TLane, TNumber> value, in Vector4<TLane, TNumber> min, in Vector4<TLane, TNumber> max)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Min(Max(value, min), max);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Saturate<TLane, TNumber>(in Vector4<TLane, TNumber> value)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Clamp(value, CreateVector4<TLane, TNumber>(TLane.Zero), CreateVector4<TLane, TNumber>(TLane.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Lerp<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b, TLane t)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return a + (b - a) * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Length<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return TLane.Sqrt(Dot(vector, vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane LengthSquared<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Dot(vector, vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane Distance<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var diff = b - a;
|
||||||
|
return TLane.Sqrt(Dot(diff, diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TLane DistanceSquared<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var diff = b - a;
|
||||||
|
return Dot(diff, diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Step<TLane, TNumber>(in Vector4<TLane, TNumber> edge, in Vector4<TLane, TNumber> value)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return Select(value >= edge, Vector4<TLane, TNumber>.One, Vector4<TLane, TNumber>.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Smoothstep<TLane, TNumber>(Vector4<TLane, TNumber> xMin, Vector4<TLane, TNumber> xMax, Vector4<TLane, TNumber> x)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
var t = Saturate((x - xMin) / (xMax - xMin));
|
||||||
|
var two = TLane.Create(TNumber.CreateTruncating(2));
|
||||||
|
var three = TLane.Create(TNumber.CreateTruncating(3));
|
||||||
|
|
||||||
|
return t * t * (CreateVector4<TLane, TNumber>(three) - (CreateVector4<TLane, TNumber>(two) * t));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Select<TLane, TNumber>(TLane condition, in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Select(condition, b.x, a.x),
|
||||||
|
y = TLane.Select(condition, b.y, a.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> Select<TLane, TNumber>(Vector4<TLane, TNumber> condition, in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Select(condition.x, b.x, a.x),
|
||||||
|
y = TLane.Select(condition.y, b.y, a.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,327 @@
|
|||||||
|
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||||
|
<#@ assembly name="System.Core" #>
|
||||||
|
<#@ import namespace="System.Linq" #>
|
||||||
|
<#@ import namespace="System.Text" #>
|
||||||
|
<#@ import namespace="System.Collections.Generic" #>
|
||||||
|
<#@ output extension=".gen.cs" #>
|
||||||
|
/// <auto-generated/>
|
||||||
|
/// This code is automatically generated by a T4 template.
|
||||||
|
/// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
/// </auto-generated>
|
||||||
|
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
|
<#
|
||||||
|
const string TLane = "TLane";
|
||||||
|
const string TNumber = "TNumber";
|
||||||
|
const string GenericParameters = $"{TLane}, {TNumber}";
|
||||||
|
|
||||||
|
var dimensions = new int[] { 2, 3, 4 };
|
||||||
|
var components = new char[] { 'x', 'y', 'z', 'w' };
|
||||||
|
var TLaneRestrictions = $@"where {TLane} : ISPMD<{TLane}, {TNumber}>";
|
||||||
|
var TNumberRestrictions = $@"where {TNumber} : unmanaged, INumber<{TNumber}>, IBinaryNumber<{TNumber}>, IMinMaxValue<{TNumber}>, IBitwiseOperators<{TNumber}, {TNumber}, {TNumber}>";
|
||||||
|
#>
|
||||||
|
|
||||||
|
public static unsafe partial class MathV
|
||||||
|
{
|
||||||
|
<# foreach (int dimension in dimensions) {
|
||||||
|
var vectorType = $"Vector{dimension}<{TLane}, {TNumber}>";
|
||||||
|
#>
|
||||||
|
# region Vector<#= dimension #>
|
||||||
|
|
||||||
|
// Creation Functions
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Create<<#= GenericParameters #>>(<#= ForEachDimension(dimension, i => $"in TLane {components[i]}") #>)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = <#= components[i] #>,
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> CreateVector<#= dimension #><<#= GenericParameters #>>(in TLane value)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = value,
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> LoadVector<#= dimension #><<#= GenericParameters #>>(TNumber* pSrc)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
var width = TLane.LaneWidth;
|
||||||
|
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
var <#= components[i] #> = stackalloc TNumber[width];
|
||||||
|
<# } #>
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #>[i] = pSrc[i * <#= dimension #> + <#= i #>];
|
||||||
|
<# } #>
|
||||||
|
}
|
||||||
|
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = <#= TLane #>.Load(<#= components[i] #>),
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> LoadVector<#= dimension #><<#= GenericParameters #>>(ref TNumber src)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return LoadVector<#= dimension #><<#= GenericParameters #>>((TNumber*)Unsafe.AsPointer(ref src));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Load<<#= GenericParameters #>>(<#= ForEachDimension(dimension, i => $"TNumber* p{components[i]}") #>)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = <#= TLane #>.Load(p<#= components[i] #>),
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Load<<#= GenericParameters #>>(<#= ForEachDimension(dimension, i => $"ref TNumber {components[i]}") #>)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = <#= TLane #>.Load(ref <#= components[i] #>),
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Math Functions
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Abs<<#= GenericParameters #>>(in Vector<#= dimension #><TLane, TNumber> vector)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = <#= TLane #>.Abs(vector.<#= components[i] #>),
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= TLane #> Dot<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return a.x * b.x + a.y * b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Sqrt<<#= GenericParameters #>>(in <#= vectorType #> vector)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = <#= TLane #>.Sqrt(vector.<#= components[i] #>),
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Rsqrt<<#= GenericParameters #>>(in <#= vectorType #> vector)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = <#= TLane #>.Rsqrt(vector.<#= components[i] #>),
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Normalize<<#= GenericParameters #>>(in <#= vectorType #> vector)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return vector * <#= TLane #>.Rsqrt(Dot(vector, vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Reflect<<#= GenericParameters #>>(in <#= vectorType #> incident, in <#= vectorType #> normal)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
var dot = Dot(incident, normal);
|
||||||
|
return incident - normal * (dot + dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Min<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = <#= TLane #>.Min(a.<#= components[i] #>, b.<#= components[i] #>),
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Max<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
<# for (int i = 0; i < dimension; i++) { #>
|
||||||
|
<#= components[i] #> = <#= TLane #>.Max(a.<#= components[i] #>, b.<#= components[i] #>),
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Clamp<<#= GenericParameters #>>(in <#= vectorType #> value, in <#= vectorType #> min, in <#= vectorType #> max)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return Min(Max(value, min), max);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Saturate<<#= GenericParameters #>>(in <#= vectorType #> value)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return Clamp(value, CreateVector<#= dimension #><<#= GenericParameters #>>(<#= TLane #>.Zero), CreateVector<#= dimension #><<#= GenericParameters #>>(<#= TLane #>.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Lerp<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b, <#= TLane #> t)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return a + (b - a) * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= TLane #> Length<<#= GenericParameters #>>(in <#= vectorType #> vector)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return <#= TLane #>.Sqrt(Dot(vector, vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= TLane #> LengthSquared<<#= GenericParameters #>>(in <#= vectorType #> vector)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return Dot(vector, vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= TLane #> Distance<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
var diff = b - a;
|
||||||
|
return <#= TLane #>.Sqrt(Dot(diff, diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= TLane #> DistanceSquared<<#= GenericParameters #>>(in <#= vectorType #> a, in <#= vectorType #> b)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
var diff = b - a;
|
||||||
|
return Dot(diff, diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Step<<#= GenericParameters #>>(in <#= vectorType #> edge, in <#= vectorType #> value)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return Select(value >= edge, <#= vectorType #>.One, <#= vectorType #>.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Smoothstep<<#= GenericParameters #>>(<#= vectorType #> xMin, <#= vectorType #> xMax, <#= vectorType #> x)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
var t = Saturate((x - xMin) / (xMax - xMin));
|
||||||
|
var two = <#= TLane #>.Create(<#= TNumber #>.CreateTruncating(2));
|
||||||
|
var three = <#= TLane #>.Create(<#= TNumber #>.CreateTruncating(3));
|
||||||
|
|
||||||
|
return t * t * (CreateVector<#= dimension #><<#= GenericParameters #>>(three) - (CreateVector<#= dimension #><<#= GenericParameters #>>(two) * t));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Select<<#= GenericParameters #>>(<#= TLane #> condition, in <#= vectorType #> a, in <#= vectorType #> b)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
x = <#= TLane #>.Select(condition, b.x, a.x),
|
||||||
|
y = <#= TLane #>.Select(condition, b.y, a.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static <#= vectorType #> Select<<#= GenericParameters #>>(<#= vectorType #> condition, in <#= vectorType #> a, in <#= vectorType #> b)
|
||||||
|
<#= TLaneRestrictions #>
|
||||||
|
<#= TNumberRestrictions #>
|
||||||
|
{
|
||||||
|
return new <#= vectorType #>
|
||||||
|
{
|
||||||
|
x = <#= TLane #>.Select(condition.x, b.x, a.x),
|
||||||
|
y = <#= TLane #>.Select(condition.y, b.y, a.y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
}
|
||||||
|
|
||||||
|
<#+
|
||||||
|
public string ForEachDimension(int dimension, Func<int, string> action, string spliter = ", ")
|
||||||
|
{
|
||||||
|
return string.Join(spliter, Enumerable.Range(0, dimension).Select(i => action(i)));
|
||||||
|
}
|
||||||
|
#>
|
||||||
417
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs
Normal file
417
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
|
public unsafe struct Vector2<TLane, TNumber> : IEquatable<Vector2<TLane, TNumber>>
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
public TLane x;
|
||||||
|
public TLane y;
|
||||||
|
|
||||||
|
public static Vector2<TLane, TNumber> Zero
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Zero,
|
||||||
|
y = TLane.Zero,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2<TLane, TNumber> One
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.One,
|
||||||
|
y = TLane.One,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TLane this[int index]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
RangeCheck(index);
|
||||||
|
return Unsafe.Add(ref x, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[Conditional("ENABLE_COLLECTION_CHECKS")]
|
||||||
|
private static void RangeCheck(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= 2)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException($"Index {index} is out of range for Vector2.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(TNumber* pDst)
|
||||||
|
{
|
||||||
|
var width = TLane.LaneWidth;
|
||||||
|
|
||||||
|
var x = stackalloc TNumber[width];
|
||||||
|
var y = stackalloc TNumber[width];
|
||||||
|
|
||||||
|
this.x.Store(x);
|
||||||
|
this.y.Store(y);
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
pDst[i * 2 + 0] = x[i];
|
||||||
|
pDst[i * 2 + 1] = y[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(ref TNumber dst)
|
||||||
|
{
|
||||||
|
Store((TNumber*)Unsafe.AsPointer(ref dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(TNumber* px, TNumber* py)
|
||||||
|
{
|
||||||
|
x.Store(px);
|
||||||
|
y.Store(py);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(ref TNumber x, ref TNumber y)
|
||||||
|
{
|
||||||
|
this.x.Store(ref x);
|
||||||
|
this.y.Store(ref y);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator +(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x + right.x,
|
||||||
|
y = left.y + right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator +(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x + lane,
|
||||||
|
y = vector.y + lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator +(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane + vector.x,
|
||||||
|
y = lane + vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator -(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x - right.x,
|
||||||
|
y = left.y - right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator -(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x - lane,
|
||||||
|
y = vector.y - lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator -(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane - vector.x,
|
||||||
|
y = lane - vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator *(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x * right.x,
|
||||||
|
y = left.y * right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator *(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x * lane,
|
||||||
|
y = vector.y * lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator *(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane * vector.x,
|
||||||
|
y = lane * vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator /(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x / right.x,
|
||||||
|
y = left.y / right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator /(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x / lane,
|
||||||
|
y = vector.y / lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator /(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane / vector.x,
|
||||||
|
y = lane / vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator ==(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x == right.x,
|
||||||
|
y = left.y == right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator ==(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x == lane,
|
||||||
|
y = vector.y == lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator ==(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane == vector.x,
|
||||||
|
y = lane == vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator !=(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x != right.x,
|
||||||
|
y = left.y != right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator !=(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x != lane,
|
||||||
|
y = vector.y != lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator !=(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane != vector.x,
|
||||||
|
y = lane != vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator >(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x > right.x,
|
||||||
|
y = left.y > right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator >(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x > lane,
|
||||||
|
y = vector.y > lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator >(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane > vector.x,
|
||||||
|
y = lane > vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator >=(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x >= right.x,
|
||||||
|
y = left.y >= right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator >=(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x >= lane,
|
||||||
|
y = vector.y >= lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator >=(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane >= vector.x,
|
||||||
|
y = lane >= vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator <(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x < right.x,
|
||||||
|
y = left.y < right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator <(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x < lane,
|
||||||
|
y = vector.y < lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator <(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane < vector.x,
|
||||||
|
y = lane < vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator <=(in Vector2<TLane, TNumber> left, in Vector2<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x <= right.x,
|
||||||
|
y = left.y <= right.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator <=(in Vector2<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x <= lane,
|
||||||
|
y = vector.y <= lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector2<TLane, TNumber> operator <=(TLane lane, in Vector2<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector2<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane <= vector.x,
|
||||||
|
y = lane <= vector.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly bool Equals(Vector2<TLane, TNumber> other)
|
||||||
|
{
|
||||||
|
return this.x.Equals(other.x) && this.y.Equals(other.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override readonly bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is Vector2<TLane, TNumber> other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.tt
Normal file
13
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.tt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||||
|
<#@ assembly name="System.Core" #>
|
||||||
|
<#@ include file="Vector{T}Helper.ttinclude" #>
|
||||||
|
<#@ output extension=".gen.cs" #>
|
||||||
|
<#
|
||||||
|
var code = GenerateVectorType(2);
|
||||||
|
#>
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
<#= code #>
|
||||||
455
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector3.gen.cs
Normal file
455
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector3.gen.cs
Normal file
@@ -0,0 +1,455 @@
|
|||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
|
public unsafe struct Vector3<TLane, TNumber> : IEquatable<Vector3<TLane, TNumber>>
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
public TLane x;
|
||||||
|
public TLane y;
|
||||||
|
public TLane z;
|
||||||
|
|
||||||
|
public static Vector3<TLane, TNumber> Zero
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Zero,
|
||||||
|
y = TLane.Zero,
|
||||||
|
z = TLane.Zero,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3<TLane, TNumber> One
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.One,
|
||||||
|
y = TLane.One,
|
||||||
|
z = TLane.One,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TLane this[int index]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
RangeCheck(index);
|
||||||
|
return Unsafe.Add(ref x, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[Conditional("ENABLE_COLLECTION_CHECKS")]
|
||||||
|
private static void RangeCheck(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= 3)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException($"Index {index} is out of range for Vector2.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(TNumber* pDst)
|
||||||
|
{
|
||||||
|
var width = TLane.LaneWidth;
|
||||||
|
|
||||||
|
var x = stackalloc TNumber[width];
|
||||||
|
var y = stackalloc TNumber[width];
|
||||||
|
var z = stackalloc TNumber[width];
|
||||||
|
|
||||||
|
this.x.Store(x);
|
||||||
|
this.y.Store(y);
|
||||||
|
this.z.Store(z);
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
pDst[i * 2 + 0] = x[i];
|
||||||
|
pDst[i * 2 + 1] = y[i];
|
||||||
|
pDst[i * 2 + 2] = z[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(ref TNumber dst)
|
||||||
|
{
|
||||||
|
Store((TNumber*)Unsafe.AsPointer(ref dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(TNumber* px, TNumber* py, TNumber* pz)
|
||||||
|
{
|
||||||
|
x.Store(px);
|
||||||
|
y.Store(py);
|
||||||
|
z.Store(pz);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(ref TNumber x, ref TNumber y, ref TNumber z)
|
||||||
|
{
|
||||||
|
this.x.Store(ref x);
|
||||||
|
this.y.Store(ref y);
|
||||||
|
this.z.Store(ref z);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator +(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x + right.x,
|
||||||
|
y = left.y + right.y,
|
||||||
|
z = left.z + right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator +(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x + lane,
|
||||||
|
y = vector.y + lane,
|
||||||
|
z = vector.z + lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator +(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane + vector.x,
|
||||||
|
y = lane + vector.y,
|
||||||
|
z = lane + vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator -(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x - right.x,
|
||||||
|
y = left.y - right.y,
|
||||||
|
z = left.z - right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator -(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x - lane,
|
||||||
|
y = vector.y - lane,
|
||||||
|
z = vector.z - lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator -(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane - vector.x,
|
||||||
|
y = lane - vector.y,
|
||||||
|
z = lane - vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator *(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x * right.x,
|
||||||
|
y = left.y * right.y,
|
||||||
|
z = left.z * right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator *(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x * lane,
|
||||||
|
y = vector.y * lane,
|
||||||
|
z = vector.z * lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator *(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane * vector.x,
|
||||||
|
y = lane * vector.y,
|
||||||
|
z = lane * vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator /(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x / right.x,
|
||||||
|
y = left.y / right.y,
|
||||||
|
z = left.z / right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator /(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x / lane,
|
||||||
|
y = vector.y / lane,
|
||||||
|
z = vector.z / lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator /(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane / vector.x,
|
||||||
|
y = lane / vector.y,
|
||||||
|
z = lane / vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator ==(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x == right.x,
|
||||||
|
y = left.y == right.y,
|
||||||
|
z = left.z == right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator ==(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x == lane,
|
||||||
|
y = vector.y == lane,
|
||||||
|
z = vector.z == lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator ==(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane == vector.x,
|
||||||
|
y = lane == vector.y,
|
||||||
|
z = lane == vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator !=(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x != right.x,
|
||||||
|
y = left.y != right.y,
|
||||||
|
z = left.z != right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator !=(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x != lane,
|
||||||
|
y = vector.y != lane,
|
||||||
|
z = vector.z != lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator !=(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane != vector.x,
|
||||||
|
y = lane != vector.y,
|
||||||
|
z = lane != vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator >(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x > right.x,
|
||||||
|
y = left.y > right.y,
|
||||||
|
z = left.z > right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator >(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x > lane,
|
||||||
|
y = vector.y > lane,
|
||||||
|
z = vector.z > lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator >(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane > vector.x,
|
||||||
|
y = lane > vector.y,
|
||||||
|
z = lane > vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator >=(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x >= right.x,
|
||||||
|
y = left.y >= right.y,
|
||||||
|
z = left.z >= right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator >=(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x >= lane,
|
||||||
|
y = vector.y >= lane,
|
||||||
|
z = vector.z >= lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator >=(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane >= vector.x,
|
||||||
|
y = lane >= vector.y,
|
||||||
|
z = lane >= vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator <(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x < right.x,
|
||||||
|
y = left.y < right.y,
|
||||||
|
z = left.z < right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator <(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x < lane,
|
||||||
|
y = vector.y < lane,
|
||||||
|
z = vector.z < lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator <(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane < vector.x,
|
||||||
|
y = lane < vector.y,
|
||||||
|
z = lane < vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator <=(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x <= right.x,
|
||||||
|
y = left.y <= right.y,
|
||||||
|
z = left.z <= right.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator <=(in Vector3<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x <= lane,
|
||||||
|
y = vector.y <= lane,
|
||||||
|
z = vector.z <= lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector3<TLane, TNumber> operator <=(TLane lane, in Vector3<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector3<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane <= vector.x,
|
||||||
|
y = lane <= vector.y,
|
||||||
|
z = lane <= vector.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly bool Equals(Vector3<TLane, TNumber> other)
|
||||||
|
{
|
||||||
|
return this.x.Equals(other.x) && this.y.Equals(other.y) && this.z.Equals(other.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override readonly bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is Vector3<TLane, TNumber> other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector3.tt
Normal file
13
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector3.tt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||||
|
<#@ assembly name="System.Core" #>
|
||||||
|
<#@ include file="Vector{T}Helper.ttinclude" #>
|
||||||
|
<#@ output extension=".gen.cs" #>
|
||||||
|
<#
|
||||||
|
var code = GenerateVectorType(3);
|
||||||
|
#>
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
<#= code #>
|
||||||
493
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector4.gen.cs
Normal file
493
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector4.gen.cs
Normal file
@@ -0,0 +1,493 @@
|
|||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
|
||||||
|
public unsafe struct Vector4<TLane, TNumber> : IEquatable<Vector4<TLane, TNumber>>
|
||||||
|
where TLane : ISPMD<TLane, TNumber>
|
||||||
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
|
{
|
||||||
|
public TLane x;
|
||||||
|
public TLane y;
|
||||||
|
public TLane z;
|
||||||
|
public TLane w;
|
||||||
|
|
||||||
|
public static Vector4<TLane, TNumber> Zero
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.Zero,
|
||||||
|
y = TLane.Zero,
|
||||||
|
z = TLane.Zero,
|
||||||
|
w = TLane.Zero,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector4<TLane, TNumber> One
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = TLane.One,
|
||||||
|
y = TLane.One,
|
||||||
|
z = TLane.One,
|
||||||
|
w = TLane.One,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TLane this[int index]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
RangeCheck(index);
|
||||||
|
return Unsafe.Add(ref x, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[Conditional("ENABLE_COLLECTION_CHECKS")]
|
||||||
|
private static void RangeCheck(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= 4)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException($"Index {index} is out of range for Vector2.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(TNumber* pDst)
|
||||||
|
{
|
||||||
|
var width = TLane.LaneWidth;
|
||||||
|
|
||||||
|
var x = stackalloc TNumber[width];
|
||||||
|
var y = stackalloc TNumber[width];
|
||||||
|
var z = stackalloc TNumber[width];
|
||||||
|
var w = stackalloc TNumber[width];
|
||||||
|
|
||||||
|
this.x.Store(x);
|
||||||
|
this.y.Store(y);
|
||||||
|
this.z.Store(z);
|
||||||
|
this.w.Store(w);
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
pDst[i * 2 + 0] = x[i];
|
||||||
|
pDst[i * 2 + 1] = y[i];
|
||||||
|
pDst[i * 2 + 2] = z[i];
|
||||||
|
pDst[i * 2 + 3] = w[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(ref TNumber dst)
|
||||||
|
{
|
||||||
|
Store((TNumber*)Unsafe.AsPointer(ref dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(TNumber* px, TNumber* py, TNumber* pz, TNumber* pw)
|
||||||
|
{
|
||||||
|
x.Store(px);
|
||||||
|
y.Store(py);
|
||||||
|
z.Store(pz);
|
||||||
|
w.Store(pw);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(ref TNumber x, ref TNumber y, ref TNumber z, ref TNumber w)
|
||||||
|
{
|
||||||
|
this.x.Store(ref x);
|
||||||
|
this.y.Store(ref y);
|
||||||
|
this.z.Store(ref z);
|
||||||
|
this.w.Store(ref w);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator +(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x + right.x,
|
||||||
|
y = left.y + right.y,
|
||||||
|
z = left.z + right.z,
|
||||||
|
w = left.w + right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator +(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x + lane,
|
||||||
|
y = vector.y + lane,
|
||||||
|
z = vector.z + lane,
|
||||||
|
w = vector.w + lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator +(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane + vector.x,
|
||||||
|
y = lane + vector.y,
|
||||||
|
z = lane + vector.z,
|
||||||
|
w = lane + vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator -(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x - right.x,
|
||||||
|
y = left.y - right.y,
|
||||||
|
z = left.z - right.z,
|
||||||
|
w = left.w - right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator -(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x - lane,
|
||||||
|
y = vector.y - lane,
|
||||||
|
z = vector.z - lane,
|
||||||
|
w = vector.w - lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator -(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane - vector.x,
|
||||||
|
y = lane - vector.y,
|
||||||
|
z = lane - vector.z,
|
||||||
|
w = lane - vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator *(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x * right.x,
|
||||||
|
y = left.y * right.y,
|
||||||
|
z = left.z * right.z,
|
||||||
|
w = left.w * right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator *(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x * lane,
|
||||||
|
y = vector.y * lane,
|
||||||
|
z = vector.z * lane,
|
||||||
|
w = vector.w * lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator *(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane * vector.x,
|
||||||
|
y = lane * vector.y,
|
||||||
|
z = lane * vector.z,
|
||||||
|
w = lane * vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator /(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x / right.x,
|
||||||
|
y = left.y / right.y,
|
||||||
|
z = left.z / right.z,
|
||||||
|
w = left.w / right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator /(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x / lane,
|
||||||
|
y = vector.y / lane,
|
||||||
|
z = vector.z / lane,
|
||||||
|
w = vector.w / lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator /(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane / vector.x,
|
||||||
|
y = lane / vector.y,
|
||||||
|
z = lane / vector.z,
|
||||||
|
w = lane / vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator ==(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x == right.x,
|
||||||
|
y = left.y == right.y,
|
||||||
|
z = left.z == right.z,
|
||||||
|
w = left.w == right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator ==(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x == lane,
|
||||||
|
y = vector.y == lane,
|
||||||
|
z = vector.z == lane,
|
||||||
|
w = vector.w == lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator ==(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane == vector.x,
|
||||||
|
y = lane == vector.y,
|
||||||
|
z = lane == vector.z,
|
||||||
|
w = lane == vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator !=(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x != right.x,
|
||||||
|
y = left.y != right.y,
|
||||||
|
z = left.z != right.z,
|
||||||
|
w = left.w != right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator !=(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x != lane,
|
||||||
|
y = vector.y != lane,
|
||||||
|
z = vector.z != lane,
|
||||||
|
w = vector.w != lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator !=(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane != vector.x,
|
||||||
|
y = lane != vector.y,
|
||||||
|
z = lane != vector.z,
|
||||||
|
w = lane != vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator >(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x > right.x,
|
||||||
|
y = left.y > right.y,
|
||||||
|
z = left.z > right.z,
|
||||||
|
w = left.w > right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator >(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x > lane,
|
||||||
|
y = vector.y > lane,
|
||||||
|
z = vector.z > lane,
|
||||||
|
w = vector.w > lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator >(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane > vector.x,
|
||||||
|
y = lane > vector.y,
|
||||||
|
z = lane > vector.z,
|
||||||
|
w = lane > vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator >=(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x >= right.x,
|
||||||
|
y = left.y >= right.y,
|
||||||
|
z = left.z >= right.z,
|
||||||
|
w = left.w >= right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator >=(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x >= lane,
|
||||||
|
y = vector.y >= lane,
|
||||||
|
z = vector.z >= lane,
|
||||||
|
w = vector.w >= lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator >=(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane >= vector.x,
|
||||||
|
y = lane >= vector.y,
|
||||||
|
z = lane >= vector.z,
|
||||||
|
w = lane >= vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator <(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x < right.x,
|
||||||
|
y = left.y < right.y,
|
||||||
|
z = left.z < right.z,
|
||||||
|
w = left.w < right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator <(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x < lane,
|
||||||
|
y = vector.y < lane,
|
||||||
|
z = vector.z < lane,
|
||||||
|
w = vector.w < lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator <(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane < vector.x,
|
||||||
|
y = lane < vector.y,
|
||||||
|
z = lane < vector.z,
|
||||||
|
w = lane < vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator <=(in Vector4<TLane, TNumber> left, in Vector4<TLane, TNumber> right)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = left.x <= right.x,
|
||||||
|
y = left.y <= right.y,
|
||||||
|
z = left.z <= right.z,
|
||||||
|
w = left.w <= right.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator <=(in Vector4<TLane, TNumber> vector, TLane lane)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = vector.x <= lane,
|
||||||
|
y = vector.y <= lane,
|
||||||
|
z = vector.z <= lane,
|
||||||
|
w = vector.w <= lane,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector4<TLane, TNumber> operator <=(TLane lane, in Vector4<TLane, TNumber> vector)
|
||||||
|
{
|
||||||
|
return new Vector4<TLane, TNumber>
|
||||||
|
{
|
||||||
|
x = lane <= vector.x,
|
||||||
|
y = lane <= vector.y,
|
||||||
|
z = lane <= vector.z,
|
||||||
|
w = lane <= vector.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly bool Equals(Vector4<TLane, TNumber> other)
|
||||||
|
{
|
||||||
|
return this.x.Equals(other.x) && this.y.Equals(other.y) && this.z.Equals(other.z) && this.w.Equals(other.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override readonly bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is Vector4<TLane, TNumber> other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector4.tt
Normal file
13
Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector4.tt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||||
|
<#@ assembly name="System.Core" #>
|
||||||
|
<#@ include file="Vector{T}Helper.ttinclude" #>
|
||||||
|
<#@ output extension=".gen.cs" #>
|
||||||
|
<#
|
||||||
|
var code = GenerateVectorType(4);
|
||||||
|
#>
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
|
<#= code #>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,420 @@
|
|||||||
|
<#@ import namespace="System.Text" #>
|
||||||
|
<#+
|
||||||
|
private const string TLane = "TLane";
|
||||||
|
private const string TNumber = "TNumber";
|
||||||
|
|
||||||
|
private string TLaneRestrictions = $@"where {TLane} : ISPMD<{TLane}, {TNumber}>";
|
||||||
|
private string TNumberRestrictions = $@"where {TNumber} : unmanaged, INumber<{TNumber}>, IBinaryNumber<{TNumber}>, IMinMaxValue<{TNumber}>, IBitwiseOperators<{TNumber}, {TNumber}, {TNumber}>";
|
||||||
|
|
||||||
|
private int[] dimensions = new int[] { 2, 3, 4 };
|
||||||
|
private char[] components = new char[] { 'x', 'y', 'z', 'w' };
|
||||||
|
|
||||||
|
public string Indent(string str, int spaces)
|
||||||
|
{
|
||||||
|
var indent = new string(' ', spaces);
|
||||||
|
return indent + str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ForEachDimension(int maxDimension, int indentation, string spliter, Action<int, StringBuilder> action, bool spliterOnFirst = true)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
for (var dimension = 0; dimension < maxDimension; dimension++)
|
||||||
|
{
|
||||||
|
if ((dimension > 0 || spliterOnFirst) && indentation > 0)
|
||||||
|
{
|
||||||
|
sb.Append(new string(' ', indentation));
|
||||||
|
}
|
||||||
|
|
||||||
|
action(dimension, sb);
|
||||||
|
if (dimension < maxDimension - 1)
|
||||||
|
{
|
||||||
|
sb.Append(spliter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringBuilder GenerateVectorType(int dimension)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
var typeName = $"Vector{dimension}<{TLane}, {TNumber}>";
|
||||||
|
|
||||||
|
sb.AppendLine(@$"
|
||||||
|
public unsafe struct {typeName} : IEquatable<{typeName}>
|
||||||
|
{TLaneRestrictions}
|
||||||
|
{TNumberRestrictions}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 4, Environment.NewLine, (dim, sb) => sb.Append($"public {TLane} {components[dim]};"))}
|
||||||
|
|
||||||
|
public static {typeName} Zero
|
||||||
|
{{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 16, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = {TLane}.Zero,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
public static {typeName} One
|
||||||
|
{{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 16, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = {TLane}.One,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
public {TLane} this[int index]
|
||||||
|
{{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{{
|
||||||
|
RangeCheck(index);
|
||||||
|
return Unsafe.Add(ref x, index);
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[Conditional(""ENABLE_COLLECTION_CHECKS"")]
|
||||||
|
private static void RangeCheck(int index)
|
||||||
|
{{
|
||||||
|
if (index < 0 || index >= {dimension})
|
||||||
|
{{
|
||||||
|
throw new IndexOutOfRangeException($""Index {{index}} is out of range for Vector2."");
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store({TNumber}* pDst)
|
||||||
|
{{
|
||||||
|
var width = {TLane}.LaneWidth;
|
||||||
|
|
||||||
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"var {components[dim]} = stackalloc {TNumber}[width];"))}
|
||||||
|
|
||||||
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"this.{components[dim]}.Store({components[dim]});"))}
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"pDst[i * 2 + {dim}] = {components[dim]}[i];"))}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store(ref {TNumber} dst)
|
||||||
|
{{
|
||||||
|
Store(({TNumber}*)Unsafe.AsPointer(ref dst));
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store({ForEachDimension(dimension, 1, ", ", (dim, sb) => sb.Append($"{TNumber}* p{components[dim]}"), false)})
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]}.Store(p{components[dim]});"))}
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Store({ForEachDimension(dimension, 1, ", ", (dim, sb) => sb.Append($"ref {TNumber} {components[dim]}"), false)})
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"this.{components[dim]}.Store(ref {components[dim]});"))}
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator +(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} + right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator +(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} + lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator +({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane + vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator -(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} - right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator -(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} - lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator -({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane - vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator *(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} * right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator *(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} * lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator *({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane * vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator /(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} / right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator /(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} / lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator /({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane / vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator ==(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} == right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator ==(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} == lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator ==({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane == vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator !=(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} != right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator !=(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} != lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator !=({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane != vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator >(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} > right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator >(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} > lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator >({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane > vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator >=(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} >= right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator >=(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} >= lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator >=({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane >= vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator <(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} < right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator <(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} < lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator <({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane < vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator <=(in {typeName} left, in {typeName} right)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = left.{components[dim]} <= right.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator <=(in {typeName} vector, {TLane} lane)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = vector.{components[dim]} <= lane,"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static {typeName} operator <=({TLane} lane, in {typeName} vector)
|
||||||
|
{{
|
||||||
|
return new {typeName}
|
||||||
|
{{
|
||||||
|
{ForEachDimension(dimension, 12, Environment.NewLine, (dim, sb) => sb.Append($"{components[dim]} = lane <= vector.{components[dim]},"))}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly bool Equals({typeName} other)
|
||||||
|
{{
|
||||||
|
return {ForEachDimension(dimension, 0, " && ", (dim, sb) => sb.Append($"this.{components[dim]}.Equals(other.{components[dim]})"), false)};
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override readonly bool Equals(object? obj)
|
||||||
|
{{
|
||||||
|
return obj is {typeName} other && Equals(other);
|
||||||
|
}}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override int GetHashCode()
|
||||||
|
{{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}}
|
||||||
|
}}");
|
||||||
|
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
#>
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Numerics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
|
||||||
|
|
||||||
public unsafe struct Vector3<TLane, TNumber> : IEquatable<Vector3<TLane, TNumber>>
|
|
||||||
where TLane : ISPMD<TLane, TNumber>
|
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
||||||
{
|
|
||||||
public TLane x;
|
|
||||||
public TLane y;
|
|
||||||
public TLane z;
|
|
||||||
|
|
||||||
public TLane this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RangeCheck(index);
|
|
||||||
return Unsafe.Add(ref x, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
[Conditional("ENABLE_COLLECTION_CHECKS")]
|
|
||||||
private static void RangeCheck(int index)
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= 3)
|
|
||||||
{
|
|
||||||
throw new IndexOutOfRangeException($"Index {index} is out of range for Vector3.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Store(TNumber* pDst)
|
|
||||||
{
|
|
||||||
var width = TLane.LaneWidth;
|
|
||||||
|
|
||||||
var x = stackalloc TNumber[width];
|
|
||||||
var y = stackalloc TNumber[width];
|
|
||||||
var z = stackalloc TNumber[width];
|
|
||||||
|
|
||||||
this.x.Store(x);
|
|
||||||
this.y.Store(y);
|
|
||||||
this.z.Store(z);
|
|
||||||
|
|
||||||
for (var i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
pDst[i * 3 + 0] = x[i];
|
|
||||||
pDst[i * 3 + 1] = y[i];
|
|
||||||
pDst[i * 3 + 2] = z[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Store(ref TNumber dst)
|
|
||||||
{
|
|
||||||
Store((TNumber*)Unsafe.AsPointer(ref dst));
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Store(TNumber* pX, TNumber* pY, TNumber* pZ)
|
|
||||||
{
|
|
||||||
x.Store(pX);
|
|
||||||
y.Store(pY);
|
|
||||||
z.Store(pZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Store(ref TNumber x, ref TNumber y, ref TNumber z)
|
|
||||||
{
|
|
||||||
this.x.Store(ref x);
|
|
||||||
this.y.Store(ref y);
|
|
||||||
this.z.Store(ref z);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> operator +(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = left.x + right.x,
|
|
||||||
y = left.y + right.y,
|
|
||||||
z = left.z + right.z,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> operator +(in Vector3<TLane, TNumber> vector, TLane lane)
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = vector.x + lane,
|
|
||||||
y = vector.y + lane,
|
|
||||||
z = vector.z + lane,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> operator -(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = left.x - right.x,
|
|
||||||
y = left.y - right.y,
|
|
||||||
z = left.z - right.z,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> operator -(in Vector3<TLane, TNumber> vector, TLane lane)
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = vector.x - lane,
|
|
||||||
y = vector.y - lane,
|
|
||||||
z = vector.z - lane,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> operator *(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = left.x * right.x,
|
|
||||||
y = left.y * right.y,
|
|
||||||
z = left.z * right.z,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> operator *(in Vector3<TLane, TNumber> vector, TLane lane)
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = vector.x * lane,
|
|
||||||
y = vector.y * lane,
|
|
||||||
z = vector.z * lane,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> operator /(in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = left.x / right.x,
|
|
||||||
y = left.y / right.y,
|
|
||||||
z = left.z / right.z,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> operator == (in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = left.x == right.x,
|
|
||||||
y = left.y == right.y,
|
|
||||||
z = left.z == right.z,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector3<TLane, TNumber> operator != (in Vector3<TLane, TNumber> left, in Vector3<TLane, TNumber> right)
|
|
||||||
{
|
|
||||||
return new Vector3<TLane, TNumber>
|
|
||||||
{
|
|
||||||
x = left.x != right.x,
|
|
||||||
y = left.y != right.y,
|
|
||||||
z = left.z != right.z,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public readonly bool Equals(Vector3<TLane, TNumber> other)
|
|
||||||
{
|
|
||||||
return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public override readonly bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
return obj is Vector3<TLane, TNumber> other && Equals(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -33,7 +33,7 @@ public static unsafe class WideLane
|
|||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumber>
|
public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumber>
|
||||||
where TNumber : unmanaged, INumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
||||||
{
|
{
|
||||||
private static readonly Vector<TNumber> s_indices;
|
private static readonly Vector<TNumber> s_indices;
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
var pValues = stackalloc TNumber[LaneWidth];
|
var pValues = stackalloc TNumber[LaneWidth];
|
||||||
for (var i = 0; i < LaneWidth; i++)
|
for (var i = 0; i < LaneWidth; i++)
|
||||||
{
|
{
|
||||||
pValues[i] = TNumber.CreateChecked(i);
|
pValues[i] = TNumber.CreateTruncating(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_indices = Vector.Load(pValues);
|
s_indices = Vector.Load(pValues);
|
||||||
@@ -373,6 +373,30 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
return ~Equal(a, b);
|
return ~Equal(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static WideLane<TNumber> operator >(WideLane<TNumber> a, WideLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return GreaterThan(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static WideLane<TNumber> operator >=(WideLane<TNumber> a, WideLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return GreaterThanOrEqual(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static WideLane<TNumber> operator <(WideLane<TNumber> a, WideLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return LessThan(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static WideLane<TNumber> operator <=(WideLane<TNumber> a, WideLane<TNumber> b)
|
||||||
|
{
|
||||||
|
return LessThanOrEqual(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static implicit operator WideLane<TNumber>(TNumber value)
|
public static implicit operator WideLane<TNumber>(TNumber value)
|
||||||
@@ -538,7 +562,7 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
// This is complex to do right (Payne-Hanek), but for games
|
// This is complex to do right (Payne-Hanek), but for games
|
||||||
// a simple approximation: value = value - (PI * Round(value / PI)) is good enough.
|
// a simple approximation: value = value - (PI * Round(value / PI)) is good enough.
|
||||||
|
|
||||||
var pi = Create(TNumber.CreateChecked(Math.PI));
|
var pi = Create(TNumber.CreateTruncating(Math.PI));
|
||||||
var x = value - pi * Round(value / pi);
|
var x = value - pi * Round(value / pi);
|
||||||
|
|
||||||
// 2. The Approximation (Remez Polynomial)
|
// 2. The Approximation (Remez Polynomial)
|
||||||
@@ -546,8 +570,8 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
// Factored (Horner's Method) for fewer ops: value * (1 + value^2 * (c1 + c2*value^2))
|
// Factored (Horner's Method) for fewer ops: value * (1 + value^2 * (c1 + c2*value^2))
|
||||||
|
|
||||||
var x2 = x * x;
|
var x2 = x * x;
|
||||||
var vc1 = Create(TNumber.CreateChecked(0.3333314036)); // 1/3
|
var vc1 = Create(TNumber.CreateTruncating(0.3333314036)); // 1/3
|
||||||
var vc2 = Create(TNumber.CreateChecked(0.1333923995)); // 2/15
|
var vc2 = Create(TNumber.CreateTruncating(0.1333923995)); // 2/15
|
||||||
|
|
||||||
// x2 * (c1 + c2 * x2)
|
// x2 * (c1 + c2 * x2)
|
||||||
var poly = MultipleAdd(x2, vc2, vc1);
|
var poly = MultipleAdd(x2, vc2, vc1);
|
||||||
@@ -560,7 +584,7 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
{
|
{
|
||||||
// asin(value) = pi/2 - acos(value)
|
// asin(value) = pi/2 - acos(value)
|
||||||
|
|
||||||
var piOver2 = Create(TNumber.CreateChecked(Math.PI / 2));
|
var piOver2 = Create(TNumber.CreateTruncating(Math.PI / 2));
|
||||||
return piOver2 - Acos(value);
|
return piOver2 - Acos(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,10 +596,10 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
|
|
||||||
var x = Abs(value);
|
var x = Abs(value);
|
||||||
|
|
||||||
var c0 = Create(TNumber.CreateChecked(1.5707288f)); // pi/2
|
var c0 = Create(TNumber.CreateTruncating(1.5707288f)); // pi/2
|
||||||
var c1 = Create(TNumber.CreateChecked(-0.2121144f));
|
var c1 = Create(TNumber.CreateTruncating(-0.2121144f));
|
||||||
var c2 = Create(TNumber.CreateChecked(0.0742610f));
|
var c2 = Create(TNumber.CreateTruncating(0.0742610f));
|
||||||
var c3 = Create(TNumber.CreateChecked(-0.0187293f));
|
var c3 = Create(TNumber.CreateTruncating(-0.0187293f));
|
||||||
|
|
||||||
var term1 = MultipleAdd(x, c3, c2);
|
var term1 = MultipleAdd(x, c3, c2);
|
||||||
var term2 = MultipleAdd(x, term1, c1);
|
var term2 = MultipleAdd(x, term1, c1);
|
||||||
@@ -584,7 +608,7 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
var sqrtTerm = Sqrt(One - x);
|
var sqrtTerm = Sqrt(One - x);
|
||||||
var result = poly * sqrtTerm;
|
var result = poly * sqrtTerm;
|
||||||
|
|
||||||
var pi = Create(TNumber.CreateChecked(Math.PI));
|
var pi = Create(TNumber.CreateTruncating(Math.PI));
|
||||||
var isNegative = LessThan(value, Zero);
|
var isNegative = LessThan(value, Zero);
|
||||||
|
|
||||||
return Select(isNegative, pi - result, result);
|
return Select(isNegative, pi - result, result);
|
||||||
@@ -595,8 +619,8 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
{
|
{
|
||||||
// atan(value) = value * (c1 + c2*value^2)
|
// atan(value) = value * (c1 + c2*value^2)
|
||||||
|
|
||||||
var c1 = Create(TNumber.CreateChecked(0.97239411f));
|
var c1 = Create(TNumber.CreateTruncating(0.97239411f));
|
||||||
var c2 = Create(TNumber.CreateChecked(-0.19194795f));
|
var c2 = Create(TNumber.CreateTruncating(-0.19194795f));
|
||||||
|
|
||||||
var x2 = value * value;
|
var x2 = value * value;
|
||||||
var poly = MultipleAdd(x2, c2, c1);
|
var poly = MultipleAdd(x2, c2, c1);
|
||||||
@@ -622,8 +646,8 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
var t2 = t * t;
|
var t2 = t * t;
|
||||||
|
|
||||||
// 2. Polynomial Approximation (Odd function: value * (c1 + c2*value^2))
|
// 2. Polynomial Approximation (Odd function: value * (c1 + c2*value^2))
|
||||||
var c1 = Create(TNumber.CreateChecked(0.97239411f));
|
var c1 = Create(TNumber.CreateTruncating(0.97239411f));
|
||||||
var c2 = Create(TNumber.CreateChecked(-0.19194795f));
|
var c2 = Create(TNumber.CreateTruncating(-0.19194795f));
|
||||||
|
|
||||||
// (c1 + c2 * t2)
|
// (c1 + c2 * t2)
|
||||||
var poly = MultipleAdd(c2, t2, c1);
|
var poly = MultipleAdd(c2, t2, c1);
|
||||||
@@ -633,12 +657,12 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
|
|
||||||
// 3. Reconstruct the angle
|
// 3. Reconstruct the angle
|
||||||
// If we swapped value/y (yGtX), the identity is: atan(value/y) = PI/2 - atan(y/value)
|
// If we swapped value/y (yGtX), the identity is: atan(value/y) = PI/2 - atan(y/value)
|
||||||
var halfPi = Create(TNumber.CreateChecked(1.570796327f));
|
var halfPi = Create(TNumber.CreateTruncating(1.570796327f));
|
||||||
result = Select(yGtX, halfPi - result, result);
|
result = Select(yGtX, halfPi - result, result);
|
||||||
|
|
||||||
// 4. Adjust for Quadrants (Signs)
|
// 4. Adjust for Quadrants (Signs)
|
||||||
// If value < 0, we are in quadrants 2 or 3, so we need to add PI
|
// If value < 0, we are in quadrants 2 or 3, so we need to add PI
|
||||||
var pi = Create(TNumber.CreateChecked(3.141592654f));
|
var pi = Create(TNumber.CreateTruncating(3.141592654f));
|
||||||
var xLtZero = LessThan(x, Zero);
|
var xLtZero = LessThan(x, Zero);
|
||||||
result = Select(xLtZero, pi - result, result);
|
result = Select(xLtZero, pi - result, result);
|
||||||
|
|
||||||
@@ -680,7 +704,7 @@ public readonly unsafe struct WideLane<TNumber> : ISPMD<WideLane<TNumber>, TNumb
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static WideLane<TNumber> Exp2(WideLane<TNumber> value)
|
public static WideLane<TNumber> Exp2(WideLane<TNumber> value)
|
||||||
{
|
{
|
||||||
return Pow(Create(TNumber.CreateChecked(2)), value);
|
return Pow(Create(TNumber.CreateTruncating(2)), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Intrinsics;
|
using System.Runtime.Intrinsics;
|
||||||
@@ -6813,16 +6814,7 @@ public static partial class math
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int lzcnt(uint x)
|
public static int lzcnt(uint x)
|
||||||
{
|
{
|
||||||
if (x == 0)
|
return BitOperations.LeadingZeroCount(x);
|
||||||
{
|
|
||||||
return 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
LongDoubleUnion u;
|
|
||||||
u.doubleValue = 0.0;
|
|
||||||
u.longValue = 0x4330000000000000L + x;
|
|
||||||
u.doubleValue -= 4503599627370496.0;
|
|
||||||
return 0x41E - (int)(u.longValue >> 52);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns the componentwise number of leading zeros in the binary representations of a uint2 vector.</summary>
|
/// <summary>Returns the componentwise number of leading zeros in the binary representations of a uint2 vector.</summary>
|
||||||
@@ -6869,20 +6861,7 @@ public static partial class math
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int lzcnt(ulong x)
|
public static int lzcnt(ulong x)
|
||||||
{
|
{
|
||||||
if (x == 0)
|
return BitOperations.LeadingZeroCount(x);
|
||||||
{
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
var xh = (uint)(x >> 32);
|
|
||||||
var bits = xh != 0 ? xh : (uint)x;
|
|
||||||
var offset = xh != 0 ? 0x41E : 0x43E;
|
|
||||||
|
|
||||||
LongDoubleUnion u;
|
|
||||||
u.doubleValue = 0.0;
|
|
||||||
u.longValue = 0x4330000000000000L + bits;
|
|
||||||
u.doubleValue -= 4503599627370496.0;
|
|
||||||
return offset - (int)(u.longValue >> 52);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -6963,17 +6942,7 @@ public static partial class math
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int tzcnt(uint x)
|
public static int tzcnt(uint x)
|
||||||
{
|
{
|
||||||
if (x == 0)
|
return BitOperations.TrailingZeroCount(x);
|
||||||
{
|
|
||||||
return 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
x &= (uint)-x;
|
|
||||||
LongDoubleUnion u;
|
|
||||||
u.doubleValue = 0.0;
|
|
||||||
u.longValue = 0x4330000000000000L + x;
|
|
||||||
u.doubleValue -= 4503599627370496.0;
|
|
||||||
return (int)(u.longValue >> 52) - 0x3FF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -7053,22 +7022,7 @@ public static partial class math
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int tzcnt(ulong x)
|
public static int tzcnt(ulong x)
|
||||||
{
|
{
|
||||||
if (x == 0)
|
return BitOperations.TrailingZeroCount(x);
|
||||||
{
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = x & (ulong)-(long)x;
|
|
||||||
var xl = (uint)x;
|
|
||||||
|
|
||||||
var bits = xl != 0 ? xl : (uint)(x >> 32);
|
|
||||||
var offset = xl != 0 ? 0x3FF : 0x3DF;
|
|
||||||
|
|
||||||
LongDoubleUnion u;
|
|
||||||
u.doubleValue = 0.0;
|
|
||||||
u.longValue = 0x4330000000000000L + bits;
|
|
||||||
u.doubleValue -= 4503599627370496.0;
|
|
||||||
return (int)(u.longValue >> 52) - offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using Misaki.HighPerformance.Mathematics.SPMD;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.Intrinsics;
|
using System.Runtime.Intrinsics;
|
||||||
|
|
||||||
|
|||||||
181
Misaki.HighPerformance.Test/Jobs/NoiseJob3D.cs
Normal file
181
Misaki.HighPerformance.Test/Jobs/NoiseJob3D.cs
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
using Misaki.HighPerformance.Jobs;
|
||||||
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
using static Misaki.HighPerformance.Mathematics.math;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Test.Jobs;
|
||||||
|
|
||||||
|
public static partial class noise
|
||||||
|
{
|
||||||
|
// Modulo 289 without a division (only multiplications)
|
||||||
|
public static float mod289(float x)
|
||||||
|
{
|
||||||
|
return x - floor(x * (1.0f / 289.0f)) * 289.0f;
|
||||||
|
}
|
||||||
|
public static float2 mod289(float2 x)
|
||||||
|
{
|
||||||
|
return x - floor(x * (1.0f / 289.0f)) * 289.0f;
|
||||||
|
}
|
||||||
|
public static float3 mod289(float3 x)
|
||||||
|
{
|
||||||
|
return x - floor(x * (1.0f / 289.0f)) * 289.0f;
|
||||||
|
}
|
||||||
|
public static float4 mod289(float4 x)
|
||||||
|
{
|
||||||
|
return x - floor(x * (1.0f / 289.0f)) * 289.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modulo 7 without a division
|
||||||
|
public static float3 mod7(float3 x)
|
||||||
|
{
|
||||||
|
return x - floor(x * (1.0f / 7.0f)) * 7.0f;
|
||||||
|
}
|
||||||
|
public static float4 mod7(float4 x)
|
||||||
|
{
|
||||||
|
return x - floor(x * (1.0f / 7.0f)) * 7.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permutation polynomial: (34x^2 + x) math.mod 289
|
||||||
|
public static float permute(float x)
|
||||||
|
{
|
||||||
|
return mod289((34.0f * x + 1.0f) * x);
|
||||||
|
}
|
||||||
|
public static float3 permute(float3 x)
|
||||||
|
{
|
||||||
|
return mod289((34.0f * x + 1.0f) * x);
|
||||||
|
}
|
||||||
|
public static float4 permute(float4 x)
|
||||||
|
{
|
||||||
|
return mod289((34.0f * x + 1.0f) * x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float taylorInvSqrt(float r)
|
||||||
|
{
|
||||||
|
return 1.79284291400159f - 0.85373472095314f * r;
|
||||||
|
}
|
||||||
|
public static float4 taylorInvSqrt(float4 r)
|
||||||
|
{
|
||||||
|
return 1.79284291400159f - 0.85373472095314f * r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float2 fade(float2 t)
|
||||||
|
{
|
||||||
|
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
|
||||||
|
}
|
||||||
|
public static float3 fade(float3 t)
|
||||||
|
{
|
||||||
|
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
|
||||||
|
}
|
||||||
|
public static float4 fade(float4 t)
|
||||||
|
{
|
||||||
|
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float4 grad4(float j, float4 ip)
|
||||||
|
{
|
||||||
|
var ones = float4(1.0f, 1.0f, 1.0f, -1.0f);
|
||||||
|
var pxyz = floor(frac(float3(j) * ip.xyz) * 7.0f) * ip.z - 1.0f;
|
||||||
|
float pw = 1.5f - dot(abs(pxyz), ones.xyz);
|
||||||
|
var p = float4(pxyz, pw);
|
||||||
|
var s = float4(p < 0.0f);
|
||||||
|
p.xyz = p.xyz + (s.xyz * 2.0f - 1.0f) * s.www;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hashed 2-D gradients with an extra rotation.
|
||||||
|
// (The constant 0.0243902439 is 1/41)
|
||||||
|
public static float2 rgrad2(float2 p, float rot)
|
||||||
|
{
|
||||||
|
// For more isotropic gradients, math.sin/math.cos can be used instead.
|
||||||
|
float u = permute(permute(p.x) + p.y) * 0.0243902439f + rot; // Rotate by shift
|
||||||
|
u = frac(u) * 6.28318530718f; // 2*pi
|
||||||
|
return float2(cos(u), sin(u));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal unsafe struct NoiseJob3D : IJobParallelFor
|
||||||
|
{
|
||||||
|
public float* buffers;
|
||||||
|
|
||||||
|
public int size; // size x size x size
|
||||||
|
|
||||||
|
public void Execute(int loopIndex, int threadIndex)
|
||||||
|
{
|
||||||
|
var v = float3(
|
||||||
|
(loopIndex % size) / (float)size,
|
||||||
|
((loopIndex / size) % size) / (float)size,
|
||||||
|
(loopIndex / (size * size)) / (float)size
|
||||||
|
);
|
||||||
|
|
||||||
|
var C = float2(1.0f / 6.0f, 1.0f / 3.0f);
|
||||||
|
var D = float4(0.0f, 0.5f, 1.0f, 2.0f);
|
||||||
|
|
||||||
|
// First corner
|
||||||
|
var i = floor(v + dot(v, C.yyy));
|
||||||
|
var x0 = v - i + dot(i, C.xxx);
|
||||||
|
|
||||||
|
// Other corners
|
||||||
|
var g = step(x0.yzx, x0.xyz);
|
||||||
|
var l = 1.0f - g;
|
||||||
|
var i1 = min(g.xyz, l.zxy);
|
||||||
|
var i2 = max(g.xyz, l.zxy);
|
||||||
|
|
||||||
|
// x0 = x0 - 0.0 + 0.0 * C.xxx;
|
||||||
|
// x1 = x0 - i1 + 1.0 * C.xxx;
|
||||||
|
// x2 = x0 - i2 + 2.0 * C.xxx;
|
||||||
|
// x3 = x0 - 1.0 + 3.0 * C.xxx;
|
||||||
|
var x1 = x0 - i1 + C.xxx;
|
||||||
|
var x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
|
||||||
|
var x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
|
||||||
|
|
||||||
|
// Permutations
|
||||||
|
i = noise.mod289(i);
|
||||||
|
var p = noise.permute(noise.permute(noise.permute(
|
||||||
|
i.z + float4(0.0f, i1.z, i2.z, 1.0f))
|
||||||
|
+ i.y + float4(0.0f, i1.y, i2.y, 1.0f))
|
||||||
|
+ i.x + float4(0.0f, i1.x, i2.x, 1.0f));
|
||||||
|
|
||||||
|
// Gradients: 7x7 points over a square, mapped onto an octahedron.
|
||||||
|
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
|
||||||
|
float n_ = 0.142857142857f; // 1.0/7.0
|
||||||
|
var ns = n_ * D.wyz - D.xzx;
|
||||||
|
|
||||||
|
var j = p - 49.0f * floor(p * ns.z * ns.z); // math.mod(p,7*7)
|
||||||
|
|
||||||
|
var x_ = floor(j * ns.z);
|
||||||
|
var y_ = floor(j - 7.0f * x_); // math.mod(j,N)
|
||||||
|
|
||||||
|
var x = x_ * ns.x + ns.yyyy;
|
||||||
|
var y = y_ * ns.x + ns.yyyy;
|
||||||
|
var h = 1.0f - abs(x) - abs(y);
|
||||||
|
|
||||||
|
var b0 = float4(x.xy, y.xy);
|
||||||
|
var b1 = float4(x.zw, y.zw);
|
||||||
|
|
||||||
|
//float4 s0 = float4(math.lessThan(b0,0.0))*2.0 - 1.0;
|
||||||
|
//float4 s1 = float4(math.lessThan(b1,0.0))*2.0 - 1.0;
|
||||||
|
var s0 = floor(b0) * 2.0f + 1.0f;
|
||||||
|
var s1 = floor(b1) * 2.0f + 1.0f;
|
||||||
|
var sh = -step(h, float4(0.0f));
|
||||||
|
|
||||||
|
var a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
||||||
|
var a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
||||||
|
|
||||||
|
var p0 = float3(a0.xy, h.x);
|
||||||
|
var p1 = float3(a0.zw, h.y);
|
||||||
|
var p2 = float3(a1.xy, h.z);
|
||||||
|
var p3 = float3(a1.zw, h.w);
|
||||||
|
|
||||||
|
//Normalise gradients
|
||||||
|
var norm = noise.taylorInvSqrt(float4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
|
||||||
|
p0 *= norm.x;
|
||||||
|
p1 *= norm.y;
|
||||||
|
p2 *= norm.z;
|
||||||
|
p3 *= norm.w;
|
||||||
|
|
||||||
|
// Mix final noise value
|
||||||
|
var m = max(0.6f - float4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0f);
|
||||||
|
m *= m;
|
||||||
|
|
||||||
|
buffers[loopIndex] = 42.0f * dot(m * m, float4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using Misaki.HighPerformance.Mathematics.SPMD;
|
using Misaki.HighPerformance.Mathematics.SPMD;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Test.UnitTest.Jobs;
|
namespace Misaki.HighPerformance.Test.UnitTest.Jobs;
|
||||||
|
|
||||||
@@ -21,6 +22,93 @@ internal unsafe struct DotProductJob : IJobSPMD<float>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal unsafe struct Vector2LerpJob : IJobSPMD<float>
|
||||||
|
{
|
||||||
|
public float2[] arrayA;
|
||||||
|
public float2[] arrayB;
|
||||||
|
public float[] results;
|
||||||
|
|
||||||
|
public readonly void Execute<TLane>(int baseIndex, int threadIndex)
|
||||||
|
where TLane : ISPMD<TLane, float>
|
||||||
|
{
|
||||||
|
var a = MathV.LoadVector2<TLane, float>(ref arrayA[baseIndex].x);
|
||||||
|
var b = MathV.LoadVector2<TLane, float>(ref arrayB[baseIndex].x);
|
||||||
|
|
||||||
|
var t = TLane.Create(0.5f);
|
||||||
|
var lerped = MathV.Lerp(a, b, t);
|
||||||
|
var len = TLane.Sqrt(MathV.LengthSquared(lerped));
|
||||||
|
|
||||||
|
len.Store((float*)Unsafe.AsPointer(ref results[baseIndex]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal unsafe struct Vector4NormalizeJob : IJobSPMD<float>
|
||||||
|
{
|
||||||
|
public float4[] input;
|
||||||
|
public float4[] output;
|
||||||
|
|
||||||
|
public readonly void Execute<TLane>(int baseIndex, int threadIndex)
|
||||||
|
where TLane : ISPMD<TLane, float>
|
||||||
|
{
|
||||||
|
var vec = MathV.LoadVector4<TLane, float>(ref input[baseIndex].x);
|
||||||
|
var normalized = MathV.Normalize(vec);
|
||||||
|
normalized.Store((float*)Unsafe.AsPointer(ref output[baseIndex].x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal unsafe struct Vector3CrossJob : IJobSPMD<float>
|
||||||
|
{
|
||||||
|
public float3[] arrayA;
|
||||||
|
public float3[] arrayB;
|
||||||
|
public float3[] results;
|
||||||
|
|
||||||
|
public readonly void Execute<TLane>(int baseIndex, int threadIndex)
|
||||||
|
where TLane : ISPMD<TLane, float>
|
||||||
|
{
|
||||||
|
var a = MathV.LoadVector3<TLane, float>(ref arrayA[baseIndex].x);
|
||||||
|
var b = MathV.LoadVector3<TLane, float>(ref arrayB[baseIndex].x);
|
||||||
|
|
||||||
|
var cross = MathV.Cross(a, b);
|
||||||
|
cross.Store((float*)Unsafe.AsPointer(ref results[baseIndex].x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal unsafe struct MinMaxClampJob : IJobSPMD<float>
|
||||||
|
{
|
||||||
|
public float3[] values;
|
||||||
|
public float3[] mins;
|
||||||
|
public float3[] maxs;
|
||||||
|
public float3[] results;
|
||||||
|
|
||||||
|
public readonly void Execute<TLane>(int baseIndex, int threadIndex)
|
||||||
|
where TLane : ISPMD<TLane, float>
|
||||||
|
{
|
||||||
|
var val = MathV.LoadVector3<TLane, float>(ref values[baseIndex].x);
|
||||||
|
var min = MathV.LoadVector3<TLane, float>(ref mins[baseIndex].x);
|
||||||
|
var max = MathV.LoadVector3<TLane, float>(ref maxs[baseIndex].x);
|
||||||
|
|
||||||
|
var clamped = MathV.Clamp(val, min, max);
|
||||||
|
clamped.Store((float*)Unsafe.AsPointer(ref results[baseIndex].x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal unsafe struct DistanceJob : IJobSPMD<float>
|
||||||
|
{
|
||||||
|
public float3[] arrayA;
|
||||||
|
public float3[] arrayB;
|
||||||
|
public float[] results;
|
||||||
|
|
||||||
|
public readonly void Execute<TLane>(int baseIndex, int threadIndex)
|
||||||
|
where TLane : ISPMD<TLane, float>
|
||||||
|
{
|
||||||
|
var a = MathV.LoadVector3<TLane, float>(ref arrayA[baseIndex].x);
|
||||||
|
var b = MathV.LoadVector3<TLane, float>(ref arrayB[baseIndex].x);
|
||||||
|
|
||||||
|
var dist = MathV.Distance(a, b);
|
||||||
|
dist.Store((float*)Unsafe.AsPointer(ref results[baseIndex]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class SPMDTest
|
public class SPMDTest
|
||||||
{
|
{
|
||||||
@@ -57,4 +145,180 @@ public class SPMDTest
|
|||||||
NativeMemory.Free(arrayB);
|
NativeMemory.Free(arrayB);
|
||||||
NativeMemory.Free(results);
|
NativeMemory.Free(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestSPMDVector2Lerp()
|
||||||
|
{
|
||||||
|
const int count = 100;
|
||||||
|
|
||||||
|
var arrayA = new float2[count];
|
||||||
|
var arrayB = new float2[count];
|
||||||
|
var results = new float[count];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
arrayA[i] = new float2(i, i + 1);
|
||||||
|
arrayB[i] = new float2(i + 10, i + 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
var job = new Vector2LerpJob
|
||||||
|
{
|
||||||
|
arrayA = arrayA,
|
||||||
|
arrayB = arrayB,
|
||||||
|
results = results
|
||||||
|
};
|
||||||
|
|
||||||
|
job.Run<Vector2LerpJob, float>(count, -1);
|
||||||
|
|
||||||
|
// Verify first result: lerp([0,1], [10,11], 0.5) = [5,6], length = sqrt(25+36) = sqrt(61)
|
||||||
|
var expectedFirst = math.sqrt(5 * 5 + 6 * 6);
|
||||||
|
Assert.AreEqual(expectedFirst, results[0], 0.001f);
|
||||||
|
|
||||||
|
// Verify result at index 50
|
||||||
|
var expected50 = math.sqrt(55 * 55 + 56 * 56);
|
||||||
|
Assert.AreEqual(expected50, results[50], 0.001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestSPMDVector4Normalize()
|
||||||
|
{
|
||||||
|
const int count = 100;
|
||||||
|
|
||||||
|
var input = new float4[count];
|
||||||
|
var output = new float4[count];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
input[i] = new float4(i + 1, i + 2, i + 3, i + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
var job = new Vector4NormalizeJob
|
||||||
|
{
|
||||||
|
input = input,
|
||||||
|
output = output
|
||||||
|
};
|
||||||
|
|
||||||
|
job.Run<Vector4NormalizeJob, float>(count, -1);
|
||||||
|
|
||||||
|
// Verify first result: normalize([1,2,3,4])
|
||||||
|
var len0 = math.sqrt(1 * 1 + 2 * 2 + 3 * 3 + 4 * 4);
|
||||||
|
var expected0 = new float4(1 / len0, 2 / len0, 3 / len0, 4 / len0);
|
||||||
|
Assert.AreEqual(expected0.x, output[0].x, 0.001f);
|
||||||
|
Assert.AreEqual(expected0.y, output[0].y, 0.001f);
|
||||||
|
Assert.AreEqual(expected0.z, output[0].z, 0.001f);
|
||||||
|
Assert.AreEqual(expected0.w, output[0].w, 0.001f);
|
||||||
|
|
||||||
|
// Verify all normalized vectors have length ~1
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var length = math.sqrt(output[i].x * output[i].x + output[i].y * output[i].y +
|
||||||
|
output[i].z * output[i].z + output[i].w * output[i].w);
|
||||||
|
Assert.AreEqual(1.0f, length, 0.001f, $"Vector at index {i} is not normalized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestSPMDVector3Cross()
|
||||||
|
{
|
||||||
|
const int count = 100;
|
||||||
|
|
||||||
|
var arrayA = new float3[count];
|
||||||
|
var arrayB = new float3[count];
|
||||||
|
var results = new float3[count];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
arrayA[i] = new float3(1, 0, 0);
|
||||||
|
arrayB[i] = new float3(0, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var job = new Vector3CrossJob
|
||||||
|
{
|
||||||
|
arrayA = arrayA,
|
||||||
|
arrayB = arrayB,
|
||||||
|
results = results
|
||||||
|
};
|
||||||
|
|
||||||
|
job.Run<Vector3CrossJob, float>(count, -1);
|
||||||
|
|
||||||
|
// cross([1,0,0], [0,1,0]) = [0,0,1]
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0.0f, results[i].x, 0.001f);
|
||||||
|
Assert.AreEqual(0.0f, results[i].y, 0.001f);
|
||||||
|
Assert.AreEqual(1.0f, results[i].z, 0.001f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestSPMDMinMaxClamp()
|
||||||
|
{
|
||||||
|
const int count = 100;
|
||||||
|
|
||||||
|
var values = new float3[count];
|
||||||
|
var mins = new float3[count];
|
||||||
|
var maxs = new float3[count];
|
||||||
|
var results = new float3[count];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
values[i] = new float3(i - 50, i + 10, i - 25);
|
||||||
|
mins[i] = new float3(-10, 0, -5);
|
||||||
|
maxs[i] = new float3(10, 50, 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
var job = new MinMaxClampJob
|
||||||
|
{
|
||||||
|
values = values,
|
||||||
|
mins = mins,
|
||||||
|
maxs = maxs,
|
||||||
|
results = results
|
||||||
|
};
|
||||||
|
|
||||||
|
job.Run<MinMaxClampJob, float>(count, -1);
|
||||||
|
|
||||||
|
// Verify clamping works correctly
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var val = values[i];
|
||||||
|
var min = mins[i];
|
||||||
|
var max = maxs[i];
|
||||||
|
var expected = math.clamp(val, min, max);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected.x, results[i].x, 0.001f);
|
||||||
|
Assert.AreEqual(expected.y, results[i].y, 0.001f);
|
||||||
|
Assert.AreEqual(expected.z, results[i].z, 0.001f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestSPMDDistance()
|
||||||
|
{
|
||||||
|
const int count = 100;
|
||||||
|
|
||||||
|
var arrayA = new float3[count];
|
||||||
|
var arrayB = new float3[count];
|
||||||
|
var results = new float[count];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
arrayA[i] = new float3(0, 0, 0);
|
||||||
|
arrayB[i] = new float3(3, 4, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var job = new DistanceJob
|
||||||
|
{
|
||||||
|
arrayA = arrayA,
|
||||||
|
arrayB = arrayB,
|
||||||
|
results = results
|
||||||
|
};
|
||||||
|
|
||||||
|
job.Run<DistanceJob, float>(count, -1);
|
||||||
|
|
||||||
|
// distance([0,0,0], [3,4,0]) = 5
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
Assert.AreEqual(5.0f, results[i], 0.001f);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user