diff --git a/Misaki.HighPerformance.Mathematics.SPMD/ISPMD.cs b/Misaki.HighPerformance.Mathematics.SPMD/ISPMDLane.cs similarity index 96% rename from Misaki.HighPerformance.Mathematics.SPMD/ISPMD.cs rename to Misaki.HighPerformance.Mathematics.SPMD/ISPMDLane.cs index 15c3b27..e808cb9 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/ISPMD.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/ISPMDLane.cs @@ -5,7 +5,7 @@ namespace Misaki.HighPerformance.Mathematics.SPMD; /// /// Common marker interface for SPMD lane types. /// -public interface ISPMD +public interface ISPMDLane { /// /// Gets the number of lanes (vector width) for the SPMD implementation. @@ -29,8 +29,8 @@ public interface ISPMD /// /// The concrete SPMD lane type implementing this interface. /// The underlying numeric element type. -public interface ISPMD : ISPMD, IEquatable - where TSelf : ISPMD +public unsafe interface ISPMDLane : ISPMDLane, IEquatable + where TSelf : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { /// @@ -116,7 +116,15 @@ public interface ISPMD : ISPMD, IEquatable /// /// Unsafe pointer overloads are provided for scenarios where sequential lane data is already contiguous in memory. /// - static abstract unsafe TSelf Load(TNumber* pValue); + static abstract TSelf Load(TNumber* pValue); + + static abstract TSelf MaskLoad(TSelf mask, ref TNumber value); + static abstract TSelf MaskLoad(TSelf mask, TNumber* pValue); + + static abstract TSelf Gather(TNumber* pData, TSelf indices, int scale); + static abstract TSelf Gather(TNumber* pData, int* pIndices, int scale); + static abstract TSelf Gather(ref TNumber baseAddress, TSelf indices, int scale); + static abstract TSelf Gather(ref TNumber baseAddress, ref int baseIndex, int scale); /// /// Stores the lane value to the specified reference. @@ -127,7 +135,7 @@ public interface ISPMD : ISPMD, IEquatable /// Stores the lane value to the specified pointer. /// /// The pointer to store to. - unsafe void Store(TNumber* pDestination); + void Store(TNumber* pDestination); /// /// Compresses the data specified by the given mask and stores the compressed result in the provided destination /// variable. @@ -149,7 +157,7 @@ public interface ISPMD : ISPMD, IEquatable /// /// Implementations may use hardware-specific shuffle tables to reorder the selected lanes before storing, falling back to a scalar loop otherwise. /// - unsafe int CompressStore(TSelf mask, TNumber* pDestination); + int CompressStore(TSelf mask, TNumber* pDestination); /// /// Converts the lane value to a vector. @@ -157,6 +165,8 @@ public interface ISPMD : ISPMD, IEquatable /// The backing vector representation. Vector AsVector(); + TNumber* GetUnsafePtr(); + /// /// Casts the lane value to another SPMD lane type with a different underlying numeric type. /// @@ -164,7 +174,7 @@ public interface ISPMD : ISPMD, IEquatable /// The underlying numeric type of the other SPMD lane. /// The casted lane value. TOther Cast() - where TOther : ISPMD + where TOther : ISPMDLane where TOtherNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators; /// @@ -174,7 +184,7 @@ public interface ISPMD : ISPMD, IEquatable /// The underlying numeric type of the other SPMD lane. /// The bit-cast lane value. TOther BitCast() - where TOther : ISPMD + where TOther : ISPMDLane where TOtherNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators; /// diff --git a/Misaki.HighPerformance.Mathematics.SPMD/README.md b/Misaki.HighPerformance.Mathematics.SPMD/README.md index 227f0ec..13c3ad9 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/README.md +++ b/Misaki.HighPerformance.Mathematics.SPMD/README.md @@ -21,8 +21,8 @@ This package is intended for code that wants to express vectorized work in a way ## Main types -- `ISPMD` -- `ISPMD` +- `ISPMDLane` +- `ISPMDLane` - `ScalerLane` - `WideLane` - `IJobSPMD` diff --git a/Misaki.HighPerformance.Mathematics.SPMD/ScalerLane.cs b/Misaki.HighPerformance.Mathematics.SPMD/ScalerLane.cs index 7085eb5..9667066 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/ScalerLane.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/ScalerLane.cs @@ -5,7 +5,7 @@ using System.Runtime.InteropServices; namespace Misaki.HighPerformance.Mathematics.SPMD; [StructLayout(LayoutKind.Sequential)] -public readonly unsafe struct ScalarLane : ISPMD, TNumber> +public readonly unsafe struct ScalarLane : ISPMDLane, TNumber> where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { public readonly TNumber value; @@ -19,25 +19,25 @@ public readonly unsafe struct ScalarLane : ISPMD, T public static ScalarLane Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(TNumber.Zero); + get => new ScalarLane(TNumber.Zero); } public static ScalarLane One { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(TNumber.One); + get => new ScalarLane(TNumber.One); } public static ScalarLane MinValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(TNumber.MinValue); + get => new ScalarLane(TNumber.MinValue); } public static ScalarLane MaxValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(TNumber.MaxValue); + get => new ScalarLane(TNumber.MaxValue); } public readonly TNumber this[int index] @@ -54,39 +54,76 @@ public readonly unsafe struct ScalarLane : ISPMD, T [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Create(TNumber value) { - return new(value); + return new ScalarLane(value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Create(params ReadOnlySpan values) { - return new(values[0]); + return new ScalarLane(values[0]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Create(Vector value) { - return new(value[0]); + return new ScalarLane(value[0]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Sequence(TNumber start, TNumber step) { - return new(start); + return new ScalarLane(start); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Load(ref TNumber value) { - return new(value); + return new ScalarLane(value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Load(TNumber* pValue) { - return new(*pValue); + return new ScalarLane(*pValue); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ScalarLane MaskLoad(ScalarLane mask, ref TNumber value) + { + return new ScalarLane(mask.value != TNumber.Zero ? value : TNumber.Zero); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ScalarLane MaskLoad(ScalarLane mask, TNumber* pValue) + { + return new ScalarLane(mask.value != TNumber.Zero ? *pValue : TNumber.Zero); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ScalarLane Gather(TNumber* pData, ScalarLane indices, int scale) + { + return new ScalarLane(pData[int.CreateTruncating(indices.value) * scale / sizeof(TNumber)]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ScalarLane Gather(TNumber* pData, int* pIndices, int scale) + { + return new ScalarLane(pData[pIndices[0] * scale / sizeof(TNumber)]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ScalarLane Gather(ref TNumber baseAddress, ScalarLane indices, int scale) + { + return new ScalarLane(Unsafe.Add(ref baseAddress, int.CreateTruncating(indices.value) * scale / sizeof(TNumber))); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ScalarLane Gather(ref TNumber baseAddress, ref int baseIndex, int scale) + { + return new ScalarLane(Unsafe.Add(ref baseAddress, int.CreateTruncating(baseIndex) * scale / sizeof(TNumber))); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Store(ref TNumber destination) { @@ -123,9 +160,15 @@ public readonly unsafe struct ScalarLane : ISPMD, T return Vector.Create(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly TNumber* GetUnsafePtr() + { + return (TNumber*)Unsafe.AsPointer(ref Unsafe.AsRef(in value)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public TOther Cast() - where TOther : ISPMD + where TOther : ISPMDLane where TOtherNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return TOther.Create(TOtherNumber.CreateChecked(value)); @@ -133,7 +176,7 @@ public readonly unsafe struct ScalarLane : ISPMD, T [MethodImpl(MethodImplOptions.AggressiveInlining)] public TOther BitCast() - where TOther : ISPMD + where TOther : ISPMDLane where TOtherNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Unsafe.BitCast, TOther>(this); @@ -142,61 +185,61 @@ public readonly unsafe struct ScalarLane : ISPMD, T [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator +(ScalarLane a, ScalarLane b) { - return new(a.value + b.value); + return new ScalarLane(a.value + b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator -(ScalarLane a, ScalarLane b) { - return new(a.value - b.value); + return new ScalarLane(a.value - b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator *(ScalarLane a, ScalarLane b) { - return new(a.value * b.value); + return new ScalarLane(a.value * b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator /(ScalarLane a, ScalarLane b) { - return new(a.value / b.value); + return new ScalarLane(a.value / b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator %(ScalarLane a, ScalarLane b) { - return new(a.value % b.value); + return new ScalarLane(a.value % b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator -(ScalarLane a) { - return new(-a.value); + return new ScalarLane(-a.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator &(ScalarLane a, ScalarLane b) { - return new(a.value & b.value); + return new ScalarLane(a.value & b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator |(ScalarLane a, ScalarLane b) { - return new(a.value | b.value); + return new ScalarLane(a.value | b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator ^(ScalarLane a, ScalarLane b) { - return new(a.value ^ b.value); + return new ScalarLane(a.value ^ b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane operator ~(ScalarLane a) { - return new(~a.value); + return new ScalarLane(~a.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -240,7 +283,7 @@ public readonly unsafe struct ScalarLane : ISPMD, T [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator ScalarLane(TNumber value) { - return new(value); + return new ScalarLane(value); } @@ -248,7 +291,7 @@ public readonly unsafe struct ScalarLane : ISPMD, T [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Abs(ScalarLane value) { - return new(TNumber.Abs(value.value)); + return new ScalarLane(TNumber.Abs(value.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -276,7 +319,7 @@ public readonly unsafe struct ScalarLane : ISPMD, T [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Frac(ScalarLane value) { - return new(value.value - TNumber.CreateTruncating(value.value)); + return new ScalarLane(value.value - TNumber.CreateTruncating(value.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -301,37 +344,37 @@ public readonly unsafe struct ScalarLane : ISPMD, T [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Lerp(ScalarLane a, ScalarLane b, ScalarLane t) { - return new(a.value + (b.value - a.value) * t.value); + return new ScalarLane(a.value + (b.value - a.value) * t.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane MultipleAdd(ScalarLane a, ScalarLane b, ScalarLane c) { - return new(TNumber.MultiplyAddEstimate(a.value, b.value, c.value)); + return new ScalarLane(TNumber.MultiplyAddEstimate(a.value, b.value, c.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Min(ScalarLane a, ScalarLane b) { - return new(TNumber.Min(a.value, b.value)); + return new ScalarLane(TNumber.Min(a.value, b.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Max(ScalarLane a, ScalarLane b) { - return new(TNumber.Max(a.value, b.value)); + return new ScalarLane(TNumber.Max(a.value, b.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Clamp(ScalarLane value, ScalarLane min, ScalarLane max) { - return new(TNumber.Clamp(value.value, min.value, max.value)); + return new ScalarLane(TNumber.Clamp(value.value, min.value, max.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Saturate(ScalarLane value) { - return Clamp(value, new(TNumber.Zero), new(TNumber.One)); + return Clamp(value, new ScalarLane(TNumber.Zero), new ScalarLane(TNumber.One)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -638,19 +681,19 @@ public readonly unsafe struct ScalarLane : ISPMD, T [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Sign(ScalarLane value) { - return new((value.value > TNumber.Zero) ? TNumber.One : (value.value < TNumber.Zero) ? ~TNumber.Zero : TNumber.Zero); + return new ScalarLane((value.value > TNumber.Zero) ? TNumber.One : (value.value < TNumber.Zero) ? ~TNumber.Zero : TNumber.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane CopySign(ScalarLane magnitude, ScalarLane sign) { - return new(TNumber.CopySign(magnitude.value, sign.value)); + return new ScalarLane(TNumber.CopySign(magnitude.value, sign.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Rcp(ScalarLane value) { - return new(TNumber.One / value.value); + return new ScalarLane(TNumber.One / value.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -662,37 +705,37 @@ public readonly unsafe struct ScalarLane : ISPMD, T [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Select(ScalarLane conditionMask, ScalarLane ifTrue, ScalarLane ifFalse) { - return new(conditionMask.value != TNumber.Zero ? ifTrue.value : ifFalse.value); + return new ScalarLane(conditionMask.value != TNumber.Zero ? ifTrue.value : ifFalse.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane GreaterThan(ScalarLane a, ScalarLane b) { - return new(a.value > b.value ? ~TNumber.Zero : TNumber.Zero); + return new ScalarLane(a.value > b.value ? ~TNumber.Zero : TNumber.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane GreaterThanOrEqual(ScalarLane a, ScalarLane b) { - return new(a.value >= b.value ? ~TNumber.Zero : TNumber.Zero); + return new ScalarLane(a.value >= b.value ? ~TNumber.Zero : TNumber.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane LessThan(ScalarLane a, ScalarLane b) { - return new(a.value < b.value ? ~TNumber.Zero : TNumber.Zero); + return new ScalarLane(a.value < b.value ? ~TNumber.Zero : TNumber.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane LessThanOrEqual(ScalarLane a, ScalarLane b) { - return new(a.value <= b.value ? ~TNumber.Zero : TNumber.Zero); + return new ScalarLane(a.value <= b.value ? ~TNumber.Zero : TNumber.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ScalarLane Equal(ScalarLane a, ScalarLane b) { - return new(a.value == b.value ? ~TNumber.Zero : TNumber.Zero); + return new ScalarLane(a.value == b.value ? ~TNumber.Zero : TNumber.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.gen.cs b/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.gen.cs index 146994c..f873e2c 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.gen.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.gen.cs @@ -14,7 +14,7 @@ public interface IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane0 : unmanaged, ISPMD; + where TLane0 : unmanaged, ISPMDLane; } internal struct SPMDJobWrapper : IJobParallelFor @@ -69,8 +69,8 @@ public interface IJobSPMD where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane0 : unmanaged, ISPMD - where TLane1 : unmanaged, ISPMD; + where TLane0 : unmanaged, ISPMDLane + where TLane1 : unmanaged, ISPMDLane; } internal struct SPMDJobWrapper : IJobParallelFor @@ -129,9 +129,9 @@ public interface IJobSPMD where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane0 : unmanaged, ISPMD - where TLane1 : unmanaged, ISPMD - where TLane2 : unmanaged, ISPMD; + where TLane0 : unmanaged, ISPMDLane + where TLane1 : unmanaged, ISPMDLane + where TLane2 : unmanaged, ISPMDLane; } internal struct SPMDJobWrapper : IJobParallelFor @@ -194,10 +194,10 @@ public interface IJobSPMD where TNumber3 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane0 : unmanaged, ISPMD - where TLane1 : unmanaged, ISPMD - where TLane2 : unmanaged, ISPMD - where TLane3 : unmanaged, ISPMD; + where TLane0 : unmanaged, ISPMDLane + where TLane1 : unmanaged, ISPMDLane + where TLane2 : unmanaged, ISPMDLane + where TLane3 : unmanaged, ISPMDLane; } internal struct SPMDJobWrapper : IJobParallelFor @@ -264,11 +264,11 @@ public interface IJobSPMD where TNumber4 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane0 : unmanaged, ISPMD - where TLane1 : unmanaged, ISPMD - where TLane2 : unmanaged, ISPMD - where TLane3 : unmanaged, ISPMD - where TLane4 : unmanaged, ISPMD; + where TLane0 : unmanaged, ISPMDLane + where TLane1 : unmanaged, ISPMDLane + where TLane2 : unmanaged, ISPMDLane + where TLane3 : unmanaged, ISPMDLane + where TLane4 : unmanaged, ISPMDLane; } internal struct SPMDJobWrapper : IJobParallelFor @@ -339,12 +339,12 @@ public interface IJobSPMD, IBinaryNumber, IMinMaxValue, IBitwiseOperators { void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane0 : unmanaged, ISPMD - where TLane1 : unmanaged, ISPMD - where TLane2 : unmanaged, ISPMD - where TLane3 : unmanaged, ISPMD - where TLane4 : unmanaged, ISPMD - where TLane5 : unmanaged, ISPMD; + where TLane0 : unmanaged, ISPMDLane + where TLane1 : unmanaged, ISPMDLane + where TLane2 : unmanaged, ISPMDLane + where TLane3 : unmanaged, ISPMDLane + where TLane4 : unmanaged, ISPMDLane + where TLane5 : unmanaged, ISPMDLane; } internal struct SPMDJobWrapper : IJobParallelFor @@ -419,13 +419,13 @@ public interface IJobSPMD, IBinaryNumber, IMinMaxValue, IBitwiseOperators { void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane0 : unmanaged, ISPMD - where TLane1 : unmanaged, ISPMD - where TLane2 : unmanaged, ISPMD - where TLane3 : unmanaged, ISPMD - where TLane4 : unmanaged, ISPMD - where TLane5 : unmanaged, ISPMD - where TLane6 : unmanaged, ISPMD; + where TLane0 : unmanaged, ISPMDLane + where TLane1 : unmanaged, ISPMDLane + where TLane2 : unmanaged, ISPMDLane + where TLane3 : unmanaged, ISPMDLane + where TLane4 : unmanaged, ISPMDLane + where TLane5 : unmanaged, ISPMDLane + where TLane6 : unmanaged, ISPMDLane; } internal struct SPMDJobWrapper : IJobParallelFor @@ -504,14 +504,14 @@ public interface IJobSPMD, IBinaryNumber, IMinMaxValue, IBitwiseOperators { void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane0 : unmanaged, ISPMD - where TLane1 : unmanaged, ISPMD - where TLane2 : unmanaged, ISPMD - where TLane3 : unmanaged, ISPMD - where TLane4 : unmanaged, ISPMD - where TLane5 : unmanaged, ISPMD - where TLane6 : unmanaged, ISPMD - where TLane7 : unmanaged, ISPMD; + where TLane0 : unmanaged, ISPMDLane + where TLane1 : unmanaged, ISPMDLane + where TLane2 : unmanaged, ISPMDLane + where TLane3 : unmanaged, ISPMDLane + where TLane4 : unmanaged, ISPMDLane + where TLane5 : unmanaged, ISPMDLane + where TLane6 : unmanaged, ISPMDLane + where TLane7 : unmanaged, ISPMDLane; } internal struct SPMDJobWrapper : IJobParallelFor diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.tt b/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.tt index 1b2c284..a7e7a5c 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.tt +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.tt @@ -15,7 +15,7 @@ const string TLane = "TLane"; const string TNumber = "TNumber"; const string GenericParameters = $"{TLane}, {TNumber}"; -var TLaneRestrictions = $@"where {TLane} : ISPMD<{TLane}, {TNumber}>"; +var TLaneRestrictions = $@"where {TLane} : ISPMDLane<{TLane}, {TNumber}>"; var TNumberRestrictions = $@"where {TNumber} : unmanaged, INumber<{TNumber}>, IBinaryNumber<{TNumber}>, IMinMaxValue<{TNumber}>, IBitwiseOperators<{TNumber}, {TNumber}, {TNumber}>"; for (var i = 0; i < 8; i++) { #> @@ -192,7 +192,7 @@ public string GetTLaneRestrictions(int dimension, string space = " ") var sb = new StringBuilder(); for (var i = 0; i < dimension; i++) { - sb.Append(space + $@"where TLane{i} : unmanaged, ISPMD"); + sb.Append(space + $@"where TLane{i} : unmanaged, ISPMDLane"); if (i < dimension - 1) { sb.AppendLine(); diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/MathV.Vector.gen.cs b/Misaki.HighPerformance.Mathematics.SPMD/Templates/MathV.Vector.gen.cs index 9d3ed64..358eb96 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/MathV.Vector.gen.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/MathV.Vector.gen.cs @@ -11,13 +11,13 @@ namespace Misaki.HighPerformance.Mathematics.SPMD; public static unsafe partial class MathV { - #region Vector2 +# region Vector2 // Creation Functions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Create(in TLane x, in TLane y) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -29,7 +29,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 CreateVector2(in TLane value) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -41,7 +41,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 LoadVector2(TNumber* pSrc) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var width = TLane.LaneWidth; @@ -64,7 +64,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 LoadVector2(ref TNumber src) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return LoadVector2((TNumber*)Unsafe.AsPointer(ref src)); @@ -72,7 +72,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Load(TNumber* px, TNumber* py) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -84,7 +84,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Load(ref TNumber x, ref TNumber y) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -94,11 +94,93 @@ public static unsafe partial class MathV }; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 GatherVector2(TNumber* pData, TLane indices, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 2]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = int.CreateTruncating(indices[i]); + buffer[0 * TLane.LaneWidth + i] = pData[scalarIdx + 0 * scale]; + buffer[1 * TLane.LaneWidth + i] = pData[scalarIdx + 1 * scale]; + } + + return new Vector2 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 GatherVector2(TNumber* pData, int* pIndices, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 2]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = pIndices[i]; + buffer[0 * TLane.LaneWidth + i] = pData[scalarIdx + 0 * scale]; + buffer[1 * TLane.LaneWidth + i] = pData[scalarIdx + 1 * scale]; + } + + return new Vector2 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 GatherVector2(ref TNumber baseAddress, TLane indices, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 2]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = int.CreateTruncating(indices[i]); + buffer[0 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 0 * scale); + buffer[1 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 1 * scale); + } + + return new Vector2 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 GatherVector2(ref TNumber baseAddress, ref int baseIndex, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 2]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = Unsafe.Add(ref baseIndex, i); + buffer[0 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 0 * scale); + buffer[1 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 1 * scale); + } + + return new Vector2 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + }; + } + + // Math Functions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Abs(in Vector2 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -110,7 +192,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane Dot(in Vector2 a, in Vector2 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return a.x * b.x + a.y * b.y; @@ -118,7 +200,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Sqrt(in Vector2 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -130,7 +212,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Rsqrt(in Vector2 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -142,7 +224,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Normalize(in Vector2 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return vector * TLane.Rsqrt(Dot(vector, vector)); @@ -150,7 +232,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Reflect(in Vector2 incident, in Vector2 normal) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var dot = Dot(incident, normal); @@ -159,7 +241,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Min(in Vector2 a, in Vector2 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -171,7 +253,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Max(in Vector2 a, in Vector2 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -183,7 +265,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Clamp(in Vector2 value, in Vector2 min, in Vector2 max) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Min(Max(value, min), max); @@ -191,7 +273,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Saturate(in Vector2 value) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Clamp(value, CreateVector2(TLane.Zero), CreateVector2(TLane.One)); @@ -199,7 +281,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Lerp(in Vector2 a, in Vector2 b, TLane t) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return a + (b - a) * t; @@ -207,15 +289,15 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane Length(in Vector2 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return TLane.Sqrt(Dot(vector, vector)); } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane LengthSquared(in Vector2 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Dot(vector, vector); @@ -223,7 +305,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane Distance(in Vector2 a, in Vector2 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var diff = b - a; @@ -232,7 +314,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane DistanceSquared(in Vector2 a, in Vector2 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var diff = b - a; @@ -241,7 +323,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Step(in Vector2 edge, in Vector2 value) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Select(value >= edge, Vector2.One, Vector2.Zero); @@ -249,7 +331,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Smoothstep(Vector2 xMin, Vector2 xMax, Vector2 x) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var t = Saturate((x - xMin) / (xMax - xMin)); @@ -261,7 +343,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Select(TLane condition, in Vector2 a, in Vector2 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -273,7 +355,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Select(Vector2 condition, in Vector2 a, in Vector2 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector2 @@ -283,15 +365,15 @@ public static unsafe partial class MathV }; } - #endregion +# endregion - #region Vector3 +# region Vector3 // Creation Functions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Create(in TLane x, in TLane y, in TLane z) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -304,7 +386,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 CreateVector3(in TLane value) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -317,7 +399,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 LoadVector3(TNumber* pSrc) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var width = TLane.LaneWidth; @@ -343,7 +425,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 LoadVector3(ref TNumber src) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return LoadVector3((TNumber*)Unsafe.AsPointer(ref src)); @@ -351,7 +433,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Load(TNumber* px, TNumber* py, TNumber* pz) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -364,7 +446,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Load(ref TNumber x, ref TNumber y, ref TNumber z) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -375,11 +457,101 @@ public static unsafe partial class MathV }; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 GatherVector3(TNumber* pData, TLane indices, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 3]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = int.CreateTruncating(indices[i]); + buffer[0 * TLane.LaneWidth + i] = pData[scalarIdx + 0 * scale]; + buffer[1 * TLane.LaneWidth + i] = pData[scalarIdx + 1 * scale]; + buffer[2 * TLane.LaneWidth + i] = pData[scalarIdx + 2 * scale]; + } + + return new Vector3 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + z = TLane.Load(buffer + 2 * TLane.LaneWidth), + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 GatherVector3(TNumber* pData, int* pIndices, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 3]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = pIndices[i]; + buffer[0 * TLane.LaneWidth + i] = pData[scalarIdx + 0 * scale]; + buffer[1 * TLane.LaneWidth + i] = pData[scalarIdx + 1 * scale]; + buffer[2 * TLane.LaneWidth + i] = pData[scalarIdx + 2 * scale]; + } + + return new Vector3 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + z = TLane.Load(buffer + 2 * TLane.LaneWidth), + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 GatherVector3(ref TNumber baseAddress, TLane indices, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 3]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = int.CreateTruncating(indices[i]); + buffer[0 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 0 * scale); + buffer[1 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 1 * scale); + buffer[2 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 2 * scale); + } + + return new Vector3 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + z = TLane.Load(buffer + 2 * TLane.LaneWidth), + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 GatherVector3(ref TNumber baseAddress, ref int baseIndex, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 3]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = Unsafe.Add(ref baseIndex, i); + buffer[0 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 0 * scale); + buffer[1 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 1 * scale); + buffer[2 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 2 * scale); + } + + return new Vector3 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + z = TLane.Load(buffer + 2 * TLane.LaneWidth), + }; + } + + // Math Functions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Abs(in Vector3 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -392,7 +564,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane Dot(in Vector3 a, in Vector3 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return a.x * b.x + a.y * b.y + a.z * b.z; @@ -400,7 +572,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Sqrt(in Vector3 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -413,7 +585,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Rsqrt(in Vector3 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -426,7 +598,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Normalize(in Vector3 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return vector * TLane.Rsqrt(Dot(vector, vector)); @@ -434,7 +606,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Reflect(in Vector3 incident, in Vector3 normal) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var dot = Dot(incident, normal); @@ -443,7 +615,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Min(in Vector3 a, in Vector3 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -456,7 +628,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Max(in Vector3 a, in Vector3 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -469,7 +641,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Clamp(in Vector3 value, in Vector3 min, in Vector3 max) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Min(Max(value, min), max); @@ -477,7 +649,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Saturate(in Vector3 value) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Clamp(value, CreateVector3(TLane.Zero), CreateVector3(TLane.One)); @@ -485,7 +657,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Lerp(in Vector3 a, in Vector3 b, TLane t) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return a + (b - a) * t; @@ -493,15 +665,15 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane Length(in Vector3 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return TLane.Sqrt(Dot(vector, vector)); } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane LengthSquared(in Vector3 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Dot(vector, vector); @@ -509,7 +681,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane Distance(in Vector3 a, in Vector3 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var diff = b - a; @@ -518,7 +690,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane DistanceSquared(in Vector3 a, in Vector3 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var diff = b - a; @@ -527,7 +699,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Step(in Vector3 edge, in Vector3 value) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Select(value >= edge, Vector3.One, Vector3.Zero); @@ -535,7 +707,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Smoothstep(Vector3 xMin, Vector3 xMax, Vector3 x) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var t = Saturate((x - xMin) / (xMax - xMin)); @@ -547,7 +719,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Select(TLane condition, in Vector3 a, in Vector3 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -560,7 +732,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Select(Vector3 condition, in Vector3 a, in Vector3 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -571,15 +743,15 @@ public static unsafe partial class MathV }; } - #endregion +# endregion - #region Vector4 +# region Vector4 // Creation Functions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Create(in TLane x, in TLane y, in TLane z, in TLane w) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -593,7 +765,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 CreateVector4(in TLane value) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -607,7 +779,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LoadVector4(TNumber* pSrc) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var width = TLane.LaneWidth; @@ -636,7 +808,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LoadVector4(ref TNumber src) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return LoadVector4((TNumber*)Unsafe.AsPointer(ref src)); @@ -644,7 +816,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Load(TNumber* px, TNumber* py, TNumber* pz, TNumber* pw) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -658,7 +830,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Load(ref TNumber x, ref TNumber y, ref TNumber z, ref TNumber w) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -670,11 +842,109 @@ public static unsafe partial class MathV }; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 GatherVector4(TNumber* pData, TLane indices, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 4]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = int.CreateTruncating(indices[i]); + buffer[0 * TLane.LaneWidth + i] = pData[scalarIdx + 0 * scale]; + buffer[1 * TLane.LaneWidth + i] = pData[scalarIdx + 1 * scale]; + buffer[2 * TLane.LaneWidth + i] = pData[scalarIdx + 2 * scale]; + buffer[3 * TLane.LaneWidth + i] = pData[scalarIdx + 3 * scale]; + } + + return new Vector4 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + z = TLane.Load(buffer + 2 * TLane.LaneWidth), + w = TLane.Load(buffer + 3 * TLane.LaneWidth), + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 GatherVector4(TNumber* pData, int* pIndices, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 4]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = pIndices[i]; + buffer[0 * TLane.LaneWidth + i] = pData[scalarIdx + 0 * scale]; + buffer[1 * TLane.LaneWidth + i] = pData[scalarIdx + 1 * scale]; + buffer[2 * TLane.LaneWidth + i] = pData[scalarIdx + 2 * scale]; + buffer[3 * TLane.LaneWidth + i] = pData[scalarIdx + 3 * scale]; + } + + return new Vector4 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + z = TLane.Load(buffer + 2 * TLane.LaneWidth), + w = TLane.Load(buffer + 3 * TLane.LaneWidth), + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 GatherVector4(ref TNumber baseAddress, TLane indices, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 4]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = int.CreateTruncating(indices[i]); + buffer[0 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 0 * scale); + buffer[1 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 1 * scale); + buffer[2 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 2 * scale); + buffer[3 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 3 * scale); + } + + return new Vector4 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + z = TLane.Load(buffer + 2 * TLane.LaneWidth), + w = TLane.Load(buffer + 3 * TLane.LaneWidth), + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 GatherVector4(ref TNumber baseAddress, ref int baseIndex, int scale) + where TLane : ISPMDLane + where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators + { + var buffer = stackalloc TNumber[TLane.LaneWidth * 4]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = Unsafe.Add(ref baseIndex, i); + buffer[0 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 0 * scale); + buffer[1 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 1 * scale); + buffer[2 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 2 * scale); + buffer[3 * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + 3 * scale); + } + + return new Vector4 + { + x = TLane.Load(buffer + 0 * TLane.LaneWidth), + y = TLane.Load(buffer + 1 * TLane.LaneWidth), + z = TLane.Load(buffer + 2 * TLane.LaneWidth), + w = TLane.Load(buffer + 3 * TLane.LaneWidth), + }; + } + + // Math Functions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Abs(in Vector4 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -688,7 +958,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane Dot(in Vector4 a, in Vector4 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; @@ -696,7 +966,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Sqrt(in Vector4 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -710,7 +980,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Rsqrt(in Vector4 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -724,7 +994,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Normalize(in Vector4 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return vector * TLane.Rsqrt(Dot(vector, vector)); @@ -732,7 +1002,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Reflect(in Vector4 incident, in Vector4 normal) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var dot = Dot(incident, normal); @@ -741,7 +1011,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Min(in Vector4 a, in Vector4 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -755,7 +1025,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Max(in Vector4 a, in Vector4 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -769,7 +1039,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Clamp(in Vector4 value, in Vector4 min, in Vector4 max) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Min(Max(value, min), max); @@ -777,7 +1047,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Saturate(in Vector4 value) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Clamp(value, CreateVector4(TLane.Zero), CreateVector4(TLane.One)); @@ -785,7 +1055,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Lerp(in Vector4 a, in Vector4 b, TLane t) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return a + (b - a) * t; @@ -793,15 +1063,15 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane Length(in Vector4 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return TLane.Sqrt(Dot(vector, vector)); } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane LengthSquared(in Vector4 vector) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Dot(vector, vector); @@ -809,7 +1079,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane Distance(in Vector4 a, in Vector4 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var diff = b - a; @@ -818,7 +1088,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TLane DistanceSquared(in Vector4 a, in Vector4 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var diff = b - a; @@ -827,7 +1097,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Step(in Vector4 edge, in Vector4 value) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Select(value >= edge, Vector4.One, Vector4.Zero); @@ -835,7 +1105,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Smoothstep(Vector4 xMin, Vector4 xMax, Vector4 x) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { var t = Saturate((x - xMin) / (xMax - xMin)); @@ -847,7 +1117,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Select(TLane condition, in Vector4 a, in Vector4 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -861,7 +1131,7 @@ public static unsafe partial class MathV [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Select(Vector4 condition, in Vector4 a, in Vector4 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector4 @@ -873,14 +1143,14 @@ public static unsafe partial class MathV }; } - #endregion +# endregion - #region Vector3 Specific +# region Vector3 Specific [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Cross(in Vector3 a, in Vector3 b) - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return new Vector3 @@ -891,6 +1161,6 @@ public static unsafe partial class MathV }; } - #endregion +# endregion } diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/MathV.Vector.tt b/Misaki.HighPerformance.Mathematics.SPMD/Templates/MathV.Vector.tt index 06814dd..122e8bb 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/MathV.Vector.tt +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/MathV.Vector.tt @@ -21,7 +21,7 @@ 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 TLaneRestrictions = $@"where {TLane} : ISPMDLane<{TLane}, {TNumber}>"; var TNumberRestrictions = $@"where {TNumber} : unmanaged, INumber<{TNumber}>, IBinaryNumber<{TNumber}>, IMinMaxValue<{TNumber}>, IBitwiseOperators<{TNumber}, {TNumber}, {TNumber}>"; #> @@ -35,7 +35,7 @@ public static unsafe partial class MathV // Creation Functions [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static <#= vectorType #> Create<<#= GenericParameters #>>(<#= ForEachDimension(dimension, i => $"in TLane {components[i]}") #>) + public static <#= vectorType #> Create<<#= GenericParameters #>>(<#= ForEachDimension(dimension, i => $"in {TLane} {components[i]}") #>) <#= TLaneRestrictions #> <#= TNumberRestrictions #> { @@ -48,7 +48,7 @@ public static unsafe partial class MathV } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static <#= vectorType #> CreateVector<#= dimension #><<#= GenericParameters #>>(in TLane value) + public static <#= vectorType #> CreateVector<#= dimension #><<#= GenericParameters #>>(in <#= TLane #> value) <#= TLaneRestrictions #> <#= TNumberRestrictions #> { @@ -61,14 +61,14 @@ public static unsafe partial class MathV } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static <#= vectorType #> LoadVector<#= dimension #><<#= GenericParameters #>>(TNumber* pSrc) + 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]; + var <#= components[i] #> = stackalloc <#= TNumber #>[width]; <# } #> for (var i = 0; i < width; i++) @@ -87,11 +87,11 @@ public static unsafe partial class MathV } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static <#= vectorType #> LoadVector<#= dimension #><<#= GenericParameters #>>(ref TNumber src) + public static <#= vectorType #> LoadVector<#= dimension #><<#= GenericParameters #>>(ref <#= TNumber #> src) <#= TLaneRestrictions #> <#= TNumberRestrictions #> { - return LoadVector<#= dimension #><<#= GenericParameters #>>((TNumber*)Unsafe.AsPointer(ref src)); + return LoadVector<#= dimension #><<#= GenericParameters #>>((<#= TNumber #>*)Unsafe.AsPointer(ref src)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -120,10 +120,100 @@ public static unsafe partial class MathV }; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static <#= vectorType #> GatherVector<#= dimension #><<#= GenericParameters #>>(<#= TNumber #>* pData, <#= TLane #> indices, int scale) + <#= TLaneRestrictions #> + <#= TNumberRestrictions #> + { + var buffer = stackalloc <#= TNumber #>[TLane.LaneWidth * <#= dimension #>]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = int.CreateTruncating(indices[i]); +<# for (int i = 0; i < dimension; i++) { #> + buffer[<#= i #> * TLane.LaneWidth + i] = pData[scalarIdx + <#= i #> * scale]; +<# } #> + } + + return new <#= vectorType #> + { +<# for (int i = 0; i < dimension; i++) { #> + <#= components[i] #> = TLane.Load(buffer + <#= i #> * TLane.LaneWidth), +<# } #> + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static <#= vectorType #> GatherVector<#= dimension #><<#= GenericParameters #>>(<#= TNumber #>* pData, int* pIndices, int scale) + <#= TLaneRestrictions #> + <#= TNumberRestrictions #> + { + var buffer = stackalloc <#= TNumber #>[TLane.LaneWidth * <#= dimension #>]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = pIndices[i]; +<# for (int i = 0; i < dimension; i++) { #> + buffer[<#= i #> * TLane.LaneWidth + i] = pData[scalarIdx + <#= i #> * scale]; +<# } #> + } + + return new <#= vectorType #> + { +<# for (int i = 0; i < dimension; i++) { #> + <#= components[i] #> = TLane.Load(buffer + <#= i #> * TLane.LaneWidth), +<# } #> + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static <#= vectorType #> GatherVector<#= dimension #><<#= GenericParameters #>>(ref <#= TNumber #> baseAddress, <#= TLane #> indices, int scale) + <#= TLaneRestrictions #> + <#= TNumberRestrictions #> + { + var buffer = stackalloc <#= TNumber #>[TLane.LaneWidth * <#= dimension #>]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = int.CreateTruncating(indices[i]); +<# for (int i = 0; i < dimension; i++) { #> + buffer[<#= i #> * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + <#= i #> * scale); +<# } #> + } + + return new <#= vectorType #> + { +<# for (int i = 0; i < dimension; i++) { #> + <#= components[i] #> = TLane.Load(buffer + <#= i #> * TLane.LaneWidth), +<# } #> + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static <#= vectorType #> GatherVector<#= dimension #><<#= GenericParameters #>>(ref <#= TNumber #> baseAddress, ref int baseIndex, int scale) + <#= TLaneRestrictions #> + <#= TNumberRestrictions #> + { + var buffer = stackalloc <#= TNumber #>[TLane.LaneWidth * <#= dimension #>]; + for (var i = 0; i < TLane.LaneWidth; i++) + { + var scalarIdx = Unsafe.Add(ref baseIndex, i); +<# for (int i = 0; i < dimension; i++) { #> + buffer[<#= i #> * TLane.LaneWidth + i] = Unsafe.Add(ref baseAddress, scalarIdx + <#= i #> * scale); +<# } #> + } + + return new <#= vectorType #> + { +<# for (int i = 0; i < dimension; i++) { #> + <#= components[i] #> = TLane.Load(buffer + <#= i #> * TLane.LaneWidth), +<# } #> + }; + } + + // Math Functions [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static <#= vectorType #> Abs<<#= GenericParameters #>>(in Vector<#= dimension #> vector) + public static <#= vectorType #> Abs<<#= GenericParameters #>>(in Vector<#= dimension #>> vector) <#= TLaneRestrictions #> <#= TNumberRestrictions #> { diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs index c795322..dc393bf 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/Vector2.gen.cs @@ -6,7 +6,7 @@ using System.Runtime.CompilerServices; namespace Misaki.HighPerformance.Mathematics.SPMD; public unsafe struct Vector2 : IEquatable> - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { public TLane x; @@ -49,7 +49,7 @@ public unsafe struct Vector2 : IEquatable= 2) @@ -420,8 +420,11 @@ public unsafe struct Vector2 : IEquatable : IEquatable> - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { public TLane x; @@ -52,12 +52,12 @@ public unsafe struct Vector3 : IEquatable= 3) { - throw new IndexOutOfRangeException($"Index {index} is out of range for Vector2."); + throw new IndexOutOfRangeException($"Index {index} is out of range for Vector3."); } } @@ -459,8 +459,12 @@ public unsafe struct Vector3 : IEquatable : IEquatable> - where TLane : ISPMD + where TLane : ISPMDLane where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { public TLane x; @@ -55,12 +55,12 @@ public unsafe struct Vector4 : IEquatable= 4) { - throw new IndexOutOfRangeException($"Index {index} is out of range for Vector2."); + throw new IndexOutOfRangeException($"Index {index} is out of range for Vector4."); } } @@ -498,8 +498,13 @@ public unsafe struct Vector4 : IEquatable"; +private string TLaneRestrictions = $@"where {TLane} : ISPMDLane<{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 }; @@ -83,12 +83,12 @@ public unsafe struct {typeName} : IEquatable<{typeName}> }} [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Conditional(""ENABLE_COLLECTION_CHECKS"")] + [Conditional(""MHP_ENABLE_SAFETY_CHECKS"")] private static void RangeCheck(int index) {{ if (index < 0 || index >= {dimension}) {{ - throw new IndexOutOfRangeException($""Index {{index}} is out of range for Vector2.""); + throw new IndexOutOfRangeException($""Index {{index}} is out of range for Vector{dimension}.""); }} }} @@ -418,9 +418,11 @@ public unsafe struct {typeName} : IEquatable<{typeName}> }} [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() + public override readonly int GetHashCode() {{ - throw new NotImplementedException(); + var hash = new HashCode(); +{ForEachDimension(dimension, 8, Environment.NewLine, (dim, sb) => sb.Append($"hash.Add({components[dim]});"))} + return hash.ToHashCode(); }} }}"); diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/WideLane.gen.cs b/Misaki.HighPerformance.Mathematics.SPMD/Templates/WideLane.gen.cs index 6653e63..43cdfac 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/WideLane.gen.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/WideLane.gen.cs @@ -3,12 +3,12 @@ using System.Runtime.CompilerServices; namespace Misaki.HighPerformance.Mathematics.SPMD; -public readonly unsafe partial struct WideLane : ISPMD, TNumber> +public readonly unsafe partial struct WideLane : ISPMDLane, TNumber> where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { [MethodImpl(MethodImplOptions.AggressiveInlining)] public TOther Cast() - where TOther : ISPMD + where TOther : ISPMDLane where TOtherNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { if (typeof(TNumber) == typeof(float) && typeof(TOtherNumber) == typeof(int)) diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/WideLane.tt b/Misaki.HighPerformance.Mathematics.SPMD/Templates/WideLane.tt index 435b6ed..b0278f7 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/WideLane.tt +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/WideLane.tt @@ -22,12 +22,12 @@ var conversions = new CastRoute[] }; #> -public readonly unsafe partial struct WideLane : ISPMD, TNumber> +public readonly unsafe partial struct WideLane : ISPMDLane, TNumber> where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { [MethodImpl(MethodImplOptions.AggressiveInlining)] public TOther Cast() - where TOther : ISPMD + where TOther : ISPMDLane where TOtherNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { <# foreach (var c in conversions) { #> diff --git a/Misaki.HighPerformance.Mathematics.SPMD/WideLane.cs b/Misaki.HighPerformance.Mathematics.SPMD/WideLane.cs index 0e280ec..e4ef3e7 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/WideLane.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/WideLane.cs @@ -32,7 +32,7 @@ public static unsafe class WideLane } [StructLayout(LayoutKind.Sequential)] -public readonly unsafe partial struct WideLane : ISPMD, TNumber> +public readonly unsafe partial struct WideLane : ISPMDLane, TNumber> where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { private static readonly Vector s_indices; @@ -48,13 +48,13 @@ public readonly unsafe partial struct WideLane : ISPMD Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(Vector.Zero); + get => new WideLane(Vector.Zero); } public static WideLane One { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(Vector.One); + get => new WideLane(Vector.One); } public static WideLane MinValue @@ -134,39 +134,102 @@ public readonly unsafe partial struct WideLane : ISPMD Create(TNumber value) { - return new(Vector.Create(value)); + return new WideLane(Vector.Create(value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Create(params ReadOnlySpan values) { - return new(Vector.Create(values)); + return new WideLane(Vector.Create(values)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Create(Vector value) { - return new(value); + return new WideLane(value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Sequence(TNumber start, TNumber step) { - return new(Vector.Create(start) + (Vector.Create(step) * s_indices)); + return new WideLane(Vector.Create(start) + (Vector.Create(step) * s_indices)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Load(ref TNumber value) { - return new(Vector.LoadUnsafe(ref value)); + return new WideLane(Vector.LoadUnsafe(ref value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Load(TNumber* pValue) { - return new(Vector.Load(pValue)); + return new WideLane(Vector.Load(pValue)); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WideLane MaskLoad(WideLane mask, ref TNumber value) + { + return MaskLoad(mask, (TNumber*)Unsafe.AsPointer(ref value)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WideLane MaskLoad(WideLane mask, TNumber* pValue) + { + var vector = Vector.Load(pValue); + return new WideLane(Vector.ConditionalSelect(mask.value, vector, Vector.Zero)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WideLane Gather(TNumber* pData, WideLane indices, int scale) + { + var buffer = stackalloc TNumber[LaneWidth]; + for (var i = 0; i < LaneWidth; i++) + { + buffer[i] = pData[int.CreateTruncating(indices[i]) * scale / sizeof(TNumber)]; + } + + return new WideLane(Vector.Load(buffer)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WideLane Gather(TNumber* pData, int* pIndices, int scale) + { + var buffer = stackalloc TNumber[LaneWidth]; + for (var i = 0; i < LaneWidth; i++) + { + buffer[i] = pData[pIndices[i] * scale / sizeof(TNumber)]; + } + + return new WideLane(Vector.Load(buffer)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WideLane Gather(ref TNumber baseAddress, WideLane indices, int scale) + { + var buffer = stackalloc TNumber[LaneWidth]; + for (var i = 0; i < LaneWidth; i++) + { + buffer[i] = Unsafe.Add(ref baseAddress, int.CreateTruncating(indices[i]) * scale / sizeof(TNumber)); + } + + return new WideLane(Vector.Load(buffer)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WideLane Gather(ref TNumber baseAddress, ref int baseIndex, int scale) + { + var buffer = stackalloc TNumber[LaneWidth]; + for (var i = 0; i < LaneWidth; i++) + { + buffer[i] = Unsafe.Add(ref baseAddress, Unsafe.Add(ref baseIndex, i) * scale / sizeof(TNumber)); + } + + return new WideLane(Vector.Load(buffer)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Store(ref TNumber destination) { @@ -301,9 +364,15 @@ public readonly unsafe partial struct WideLane : ISPMD() - where TOther : ISPMD + where TOther : ISPMDLane where TOtherNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { return Unsafe.BitCast, TOther>(this); @@ -313,61 +382,61 @@ public readonly unsafe partial struct WideLane : ISPMD operator +(WideLane a, WideLane b) { - return new(a.value + b.value); + return new WideLane(a.value + b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane operator -(WideLane a, WideLane b) { - return new(a.value - b.value); + return new WideLane(a.value - b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane operator *(WideLane a, WideLane b) { - return new(a.value * b.value); + return new WideLane(a.value * b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane operator /(WideLane a, WideLane b) { - return new(a.value / b.value); + return new WideLane(a.value / b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane operator %(WideLane a, WideLane b) { - return new(a.value - VectorFloor(a.value / b.value) * b.value); + return new WideLane(a.value - VectorFloor(a.value / b.value) * b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane operator -(WideLane a) { - return new(-a.value); + return new WideLane(-a.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane operator &(WideLane a, WideLane b) { - return new(a.value & b.value); + return new WideLane(a.value & b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane operator |(WideLane a, WideLane b) { - return new(a.value | b.value); + return new WideLane(a.value | b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane operator ^(WideLane a, WideLane b) { - return new(a.value ^ b.value); + return new WideLane(a.value ^ b.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane operator ~(WideLane a) { - return new(~a.value); + return new WideLane(~a.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -417,7 +486,7 @@ public readonly unsafe partial struct WideLane : ISPMD Abs(WideLane value) { - return new(Vector.Abs(value.value)); + return new WideLane(Vector.Abs(value.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -442,19 +511,19 @@ public readonly unsafe partial struct WideLane : ISPMD Frac(WideLane value) { - return new(value.value - VectorFloor(value.value)); + return new WideLane(value.value - VectorFloor(value.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Sqrt(WideLane value) { - return new(Vector.SquareRoot(value.value)); + return new WideLane(Vector.SquareRoot(value.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Lerp(WideLane a, WideLane b, WideLane t) { - return new(a.value + (b.value - a.value) * t.value); + return new WideLane(a.value + (b.value - a.value) * t.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -478,26 +547,26 @@ public readonly unsafe partial struct WideLane : ISPMD((a.value * b.value) + c.value); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Min(WideLane a, WideLane b) { - return new(Vector.Min(a.value, b.value)); + return new WideLane(Vector.Min(a.value, b.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Max(WideLane a, WideLane b) { - return new(Vector.Max(a.value, b.value)); + return new WideLane(Vector.Max(a.value, b.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Clamp(WideLane value, WideLane min, WideLane max) { - return new(Vector.Clamp(value.value, min.value, max.value)); + return new WideLane(Vector.Clamp(value.value, min.value, max.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -826,7 +895,7 @@ public readonly unsafe partial struct WideLane : ISPMD CopySign(WideLane magnitude, WideLane sign) { - return new(Vector.CopySign(magnitude.value, sign.value)); + return new WideLane(Vector.CopySign(magnitude.value, sign.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -878,7 +947,7 @@ public readonly unsafe partial struct WideLane : ISPMD Select(WideLane conditionMask, WideLane ifTrue, WideLane ifFalse) { - return new(Vector.ConditionalSelect( + return new WideLane(Vector.ConditionalSelect( conditionMask.value, ifTrue.value, ifFalse.value)); @@ -887,31 +956,31 @@ public readonly unsafe partial struct WideLane : ISPMD GreaterThan(WideLane a, WideLane b) { - return new(Vector.GreaterThan(a.value, b.value)); + return new WideLane(Vector.GreaterThan(a.value, b.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane GreaterThanOrEqual(WideLane a, WideLane b) { - return new(Vector.GreaterThanOrEqual(a.value, b.value)); + return new WideLane(Vector.GreaterThanOrEqual(a.value, b.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane LessThan(WideLane a, WideLane b) { - return new(Vector.LessThan(a.value, b.value)); + return new WideLane(Vector.LessThan(a.value, b.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane LessThanOrEqual(WideLane a, WideLane b) { - return new(Vector.LessThanOrEqual(a.value, b.value)); + return new WideLane(Vector.LessThanOrEqual(a.value, b.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static WideLane Equal(WideLane a, WideLane b) { - return new(Vector.Equals(a.value, b.value)); + return new WideLane(Vector.Equals(a.value, b.value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Misaki.HighPerformance.Mathematics/random.cs b/Misaki.HighPerformance.Mathematics/random.cs index 6528283..51e95a3 100644 --- a/Misaki.HighPerformance.Mathematics/random.cs +++ b/Misaki.HighPerformance.Mathematics/random.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Runtime.CompilerServices; using static Misaki.HighPerformance.Mathematics.math; @@ -711,53 +711,53 @@ public struct random return t; } - [Conditional("ENABLE_COLLECTION_CHECKS")] + [Conditional("MHP_ENABLE_SAFETY_CHECKS")] private void CheckInitState() { -#if ENABLE_COLLECTION_CHECKS +#if MHP_ENABLE_SAFETY_CHECKS if (state == 0) throw new System.ArgumentException("Seed must be non-zero"); #endif } - [Conditional("ENABLE_COLLECTION_CHECKS")] + [Conditional("MHP_ENABLE_SAFETY_CHECKS")] private static void CheckIndexForHash(uint index) { if (index == uint.MaxValue) throw new System.ArgumentException("Index must not be uint.MaxValue"); } - [Conditional("ENABLE_COLLECTION_CHECKS")] + [Conditional("MHP_ENABLE_SAFETY_CHECKS")] private void CheckState() { -#if ENABLE_COLLECTION_CHECKS +#if MHP_ENABLE_SAFETY_CHECKS if(state == 0) throw new System.ArgumentException("Invalid state 0. Random object has not been properly initialized"); #endif } - [Conditional("ENABLE_COLLECTION_CHECKS")] + [Conditional("MHP_ENABLE_SAFETY_CHECKS")] private void CheckNextIntMax(int max) { -#if ENABLE_COLLECTION_CHECKS +#if MHP_ENABLE_SAFETY_CHECKS if (max < 0) throw new System.ArgumentException("max must be positive"); #endif } - [Conditional("ENABLE_COLLECTION_CHECKS")] + [Conditional("MHP_ENABLE_SAFETY_CHECKS")] private void CheckNextIntMinMax(int min, int max) { -#if ENABLE_COLLECTION_CHECKS +#if MHP_ENABLE_SAFETY_CHECKS if (min > max) throw new System.ArgumentException("min must be less than or equal to max"); #endif } - [Conditional("ENABLE_COLLECTION_CHECKS")] + [Conditional("MHP_ENABLE_SAFETY_CHECKS")] private void CheckNextUIntMinMax(uint min, uint max) { -#if ENABLE_COLLECTION_CHECKS +#if MHP_ENABLE_SAFETY_CHECKS if (min > max) throw new System.ArgumentException("min must be less than or equal to max"); #endif diff --git a/Misaki.HighPerformance.Test/Benchmark/GGXMipGenerationBenchmark.cs b/Misaki.HighPerformance.Test/Benchmark/GGXMipGenerationBenchmark.cs index dbb2757..2420b96 100644 --- a/Misaki.HighPerformance.Test/Benchmark/GGXMipGenerationBenchmark.cs +++ b/Misaki.HighPerformance.Test/Benchmark/GGXMipGenerationBenchmark.cs @@ -20,8 +20,8 @@ internal unsafe struct MipLevel } internal unsafe struct GGXMipGenerationJobSPMD : IJobParallelFor - where TFloat : unmanaged, ISPMD - where TInt : unmanaged, ISPMD + where TFloat : unmanaged, ISPMDLane + where TInt : unmanaged, ISPMDLane { public const uint SAMPLE_COUNT = 1024u; @@ -104,34 +104,12 @@ internal unsafe struct GGXMipGenerationJobSPMD : IJobParallelFor var py = (uv.y * (h - 1.0f)).Cast(); // Clamp - px = TInt.Clamp(px, TInt.Zero, TInt.Create(w - 1)); - py = TInt.Clamp(py, TInt.Zero, TInt.Create(h - 1)); + px = TInt.Clamp(px, TInt.Zero, w - 1); + py = TInt.Clamp(py, TInt.Zero, h - 1); // Assuming float RGB array format var idx = (py * w + px) * 3; - - var laneWidth = TFloat.LaneWidth; - - var rBuffer = stackalloc float[laneWidth]; - var gBuffer = stackalloc float[laneWidth]; - var bBuffer = stackalloc float[laneWidth]; - - // Gather operation: extract scalar indices, perform random memory reads, and construct SoA buffers - for (var i = 0; i < laneWidth; i++) - { - var scalarIdx = idx[i]; - - rBuffer[i] = img[scalarIdx]; - gBuffer[i] = img[scalarIdx + 1]; - bBuffer[i] = img[scalarIdx + 2]; - } - - // Load the gathered contiguous arrays back into TLane types - var rLane = TFloat.Load(rBuffer); - var gLane = TFloat.Load(gBuffer); - var bLane = TFloat.Load(bBuffer); - - return MathV.Create(rLane, gLane, bLane); + return MathV.GatherVector3(img, idx.GetUnsafePtr(), 1); } public void Execute(int loopIndex, ref readonly JobExecutionContext ctx) @@ -179,9 +157,10 @@ internal unsafe struct GGXMipGenerationJobSPMD : IJobParallelFor TFloat.Create(V.z) ); - var vPrefilteredColorX = TFloat.Zero; - var vPrefilteredColorY = TFloat.Zero; - var vPrefilteredColorZ = TFloat.Zero; + //var vPrefilteredColorX = TFloat.Zero; + //var vPrefilteredColorY = TFloat.Zero; + //var vPrefilteredColorZ = TFloat.Zero; + var vPrefilteredColor = Vector3.Zero; var vTotalWeight = TFloat.Zero; // 3. Monte Carlo Integration Loop @@ -219,10 +198,7 @@ internal unsafe struct GGXMipGenerationJobSPMD : IJobParallelFor var fireflyWeight = TFloat.One / (TFloat.One + luma); var finalWeight = NdotL * fireflyWeight; - vPrefilteredColorX += sampleColor.x * finalWeight; - vPrefilteredColorY += sampleColor.y * finalWeight; - vPrefilteredColorZ += sampleColor.z * finalWeight; - + vPrefilteredColor += sampleColor * finalWeight; vTotalWeight += finalWeight; } @@ -231,9 +207,9 @@ internal unsafe struct GGXMipGenerationJobSPMD : IJobParallelFor for (var i = 0; i < TFloat.LaneWidth; i++) { - prefilteredColor.x += vPrefilteredColorX[i]; - prefilteredColor.y += vPrefilteredColorY[i]; - prefilteredColor.z += vPrefilteredColorZ[i]; + prefilteredColor.x += vPrefilteredColor.x[i]; + prefilteredColor.y += vPrefilteredColor.y[i]; + prefilteredColor.z += vPrefilteredColor.z[i]; totalWeight += vTotalWeight[i]; } diff --git a/Misaki.HighPerformance.Test/Jobs/NoiseJobVector.cs b/Misaki.HighPerformance.Test/Jobs/NoiseJobVector.cs index 9d13cad..69ee8a7 100644 --- a/Misaki.HighPerformance.Test/Jobs/NoiseJobVector.cs +++ b/Misaki.HighPerformance.Test/Jobs/NoiseJobVector.cs @@ -239,7 +239,7 @@ internal unsafe struct NoiseJobMathSPMD : IJobSPMD [MethodImpl(MethodImplOptions.AggressiveInlining)] private static T GradDot(T ix, T iy, T fx, T fy) - where T : unmanaged, ISPMD + where T : unmanaged, ISPMDLane { var c289 = T.Create(289f); var c34 = T.Create(34f); @@ -267,7 +267,7 @@ internal unsafe struct NoiseJobMathSPMD : IJobSPMD [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Noise(T uvX, T uvY) - where T : unmanaged, ISPMD + where T : unmanaged, ISPMDLane { var c1 = T.Create(1f); var c6 = T.Create(6f); @@ -292,7 +292,7 @@ internal unsafe struct NoiseJobMathSPMD : IJobSPMD } public readonly void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane : unmanaged, ISPMD + where TLane : unmanaged, ISPMDLane { var indices = TLane.Sequence(baseIndex, 1f); var w = TLane.Create(width); diff --git a/Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs b/Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs index c3d3a79..52e0b72 100644 --- a/Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs +++ b/Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs @@ -13,7 +13,7 @@ internal unsafe struct DotProductJob : IJobSPMD public float* results; // output array (dot products) public readonly void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane : unmanaged, ISPMD + where TLane : unmanaged, ISPMDLane { var vecA = MathV.LoadVector3((float*)(arrayA + baseIndex)); var vecB = MathV.LoadVector3((float*)(arrayB + baseIndex)); @@ -30,7 +30,7 @@ internal unsafe struct Vector2LerpJob : IJobSPMD public float[] results; public readonly void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane : unmanaged, ISPMD + where TLane : unmanaged, ISPMDLane { var a = MathV.LoadVector2(ref arrayA[baseIndex].x); var b = MathV.LoadVector2(ref arrayB[baseIndex].x); @@ -49,7 +49,7 @@ internal unsafe struct Vector4NormalizeJob : IJobSPMD public float4[] output; public readonly void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane : unmanaged, ISPMD + where TLane : unmanaged, ISPMDLane { var vec = MathV.LoadVector4(ref input[baseIndex].x); var normalized = MathV.Normalize(vec); @@ -64,7 +64,7 @@ internal unsafe struct Vector3CrossJob : IJobSPMD public float3[] results; public readonly void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane : unmanaged, ISPMD + where TLane : unmanaged, ISPMDLane { var a = MathV.LoadVector3(ref arrayA[baseIndex].x); var b = MathV.LoadVector3(ref arrayB[baseIndex].x); @@ -82,7 +82,7 @@ internal unsafe struct MinMaxClampJob : IJobSPMD public float3[] results; public readonly void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane : unmanaged, ISPMD + where TLane : unmanaged, ISPMDLane { var val = MathV.LoadVector3(ref values[baseIndex].x); var min = MathV.LoadVector3(ref mins[baseIndex].x); @@ -100,7 +100,7 @@ internal unsafe struct DistanceJob : IJobSPMD public float[] results; public readonly void Execute(int baseIndex, ref readonly JobExecutionContext ctx) - where TLane : unmanaged, ISPMD + where TLane : unmanaged, ISPMDLane { var a = MathV.LoadVector3(ref arrayA[baseIndex].x); var b = MathV.LoadVector3(ref arrayB[baseIndex].x);