diff --git a/Misaki.HighPerformance.LowLevel/README.md b/Misaki.HighPerformance.LowLevel/README.md index e4ab787..20c2b76 100644 --- a/Misaki.HighPerformance.LowLevel/README.md +++ b/Misaki.HighPerformance.LowLevel/README.md @@ -59,13 +59,6 @@ arr.Dispose(); AllocationManager.Dispose(); ``` -You can enable debug features for leak detection and use-after-free checks by defining `MHP_ENABLE_SAFETY_CHECKS` in your project. And define `MHP_ENABLE_STACKTRACE` to enable additional debug features such as tracking allocations and providing detailed error messages. -> Which means if you disable the safety checks, the library will not perform any safety checks and provide the maximum performance, and it will be your responsibility to ensure correct usage to avoid memory leaks and undefined behavior. -> Even `IUnsafeCollection.IsCreated` will only check if the internal pointer is non-null, without verifying the actual validity of the memory. - -You can also define `MHP_ENABLE_MIMALLOC` to use mimalloc as the underlying allocator instead of the default C allocator. -> Using mimalloc requires to install the `TerraFX.Interop.Mimalloc` package. - ## Package reference ```bash @@ -75,3 +68,10 @@ dotnet add package Misaki.HighPerformance.LowLevel ## Notes This project targets `net10.0`, enables unsafe code, and is packaged as content files for downstream consumption. + +You can enable debug features for leak detection and use-after-free checks by defining `MHP_ENABLE_SAFETY_CHECKS` in your project. And define `MHP_ENABLE_STACKTRACE` to enable additional debug features such as tracking allocations and providing detailed error messages. +> Which means if you disable the safety checks, the library will not perform any safety checks and provide the maximum performance, and it will be your responsibility to ensure correct usage to avoid memory leaks and undefined behavior. +> Even `IUnsafeCollection.IsCreated` will only check if the internal pointer is non-null, without verifying the actual validity of the memory. + +You can also define `MHP_ENABLE_MIMALLOC` to use mimalloc as the underlying allocator instead of the default C allocator. +> Using mimalloc requires to install the `TerraFX.Interop.Mimalloc` package. \ No newline at end of file diff --git a/Misaki.HighPerformance.Mathematics.SPMD/README.md b/Misaki.HighPerformance.Mathematics.SPMD/README.md index 13c3ad9..961c142 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/README.md +++ b/Misaki.HighPerformance.Mathematics.SPMD/README.md @@ -31,10 +31,29 @@ This package is intended for code that wants to express vectorized work in a way ## Example ```csharp -// Define an SPMD-friendly numeric lane type and use it to express data-parallel work. -// See the source templates for the current concrete lane implementations. +public struct Vector2LerpJob : IJobSPMD +{ + public float2[] arrayA; + public float2[] arrayB; + public float[] results; + + public readonly void Execute(int baseIndex, ref readonly JobExecutionContext ctx) + where TLane : unmanaged, ISPMDLane + { + var a = MathV.LoadVector2(ref arrayA[baseIndex].x); + var b = MathV.LoadVector2(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(ref results[baseIndex]); + } +} ``` +You can visit `GGXMipGenerationBenchmark.cs` for a more complete example of how to use the SPMD abstractions in a real algorithm. + ## Package reference ```bash @@ -44,3 +63,5 @@ dotnet add package Misaki.HighPerformance.Mathematics.SPMD ## Notes This project targets `net10.0` and depends on the mathematics project for shared numeric concepts. + +You can enable `MHP_FASTMATH` to allow the use of faster math intrinsics where appropriate, but be aware that this may lead to less precise results in some cases. \ No newline at end of file diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.gen.cs b/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.gen.cs index f873e2c..faac736 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.gen.cs +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.gen.cs @@ -18,7 +18,7 @@ public interface IJobSPMD } internal struct SPMDJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { public T innerJob; @@ -44,7 +44,7 @@ internal struct SPMDJobWrapper : IJobParallelFor } internal struct SPMDScalerJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { public T innerJob; @@ -74,7 +74,7 @@ public interface IJobSPMD } internal struct SPMDJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { @@ -101,7 +101,7 @@ internal struct SPMDJobWrapper : IJobParallelFor } internal struct SPMDScalerJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { @@ -135,7 +135,7 @@ public interface IJobSPMD } internal struct SPMDJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -163,7 +163,7 @@ internal struct SPMDJobWrapper : IJobParallelFo } internal struct SPMDScalerJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -201,7 +201,7 @@ public interface IJobSPMD } internal struct SPMDJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -230,7 +230,7 @@ internal struct SPMDJobWrapper : IJob } internal struct SPMDScalerJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -272,7 +272,7 @@ public interface IJobSPMD } internal struct SPMDJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -302,7 +302,7 @@ internal struct SPMDJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -348,7 +348,7 @@ public interface IJobSPMD : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -379,7 +379,7 @@ internal struct SPMDJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -429,7 +429,7 @@ public interface IJobSPMD : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -461,7 +461,7 @@ internal struct SPMDJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -515,7 +515,7 @@ public interface IJobSPMD : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -548,7 +548,7 @@ internal struct SPMDJobWrapper : IJobParallelFor - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -570,7 +570,6 @@ internal struct SPMDScalerJobWrapper /// Run the SPMD job with the specified total count and job execution context directly on the calling thread. /// @@ -581,8 +580,8 @@ public static class IJobParallelForSPMDExtensions /// The SPMD job to run. /// The total number of iterations to execute across all lanes. /// The job execution context providing information about the current execution environment. - public static void Run(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx) - where T : struct, IJobSPMD + public static void Run(this T job, int totalIteration, ref readonly JobExecutionContext ctx) + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { if (WideLane.IsSupported) @@ -630,7 +629,7 @@ public static class IJobParallelForSPMDExtensions /// The priority of the job. /// Any job handles that this job depends on, which must complete before this job can start. public static JobHandle ScheduleParallelSPDM(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan dependencies) - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { if (WideLane.IsSupported) @@ -656,7 +655,6 @@ public static class IJobParallelForSPMDExtensions } } - /// /// Run the SPMD job with the specified total count and job execution context directly on the calling thread. /// @@ -668,8 +666,8 @@ public static class IJobParallelForSPMDExtensions /// The SPMD job to run. /// The total number of iterations to execute across all lanes. /// The job execution context providing information about the current execution environment. - public static void Run(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx) - where T : struct, IJobSPMD + public static void Run(this T job, int totalIteration, ref readonly JobExecutionContext ctx) + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { @@ -719,7 +717,7 @@ public static class IJobParallelForSPMDExtensions /// The priority of the job. /// Any job handles that this job depends on, which must complete before this job can start. public static JobHandle ScheduleParallelSPDM(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan dependencies) - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { @@ -746,7 +744,6 @@ public static class IJobParallelForSPMDExtensions } } - /// /// Run the SPMD job with the specified total count and job execution context directly on the calling thread. /// @@ -759,8 +756,8 @@ public static class IJobParallelForSPMDExtensions /// The SPMD job to run. /// The total number of iterations to execute across all lanes. /// The job execution context providing information about the current execution environment. - public static void Run(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx) - where T : struct, IJobSPMD + public static void Run(this T job, int totalIteration, ref readonly JobExecutionContext ctx) + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -812,7 +809,7 @@ public static class IJobParallelForSPMDExtensions /// The priority of the job. /// Any job handles that this job depends on, which must complete before this job can start. public static JobHandle ScheduleParallelSPDM(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan dependencies) - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -840,7 +837,6 @@ public static class IJobParallelForSPMDExtensions } } - /// /// Run the SPMD job with the specified total count and job execution context directly on the calling thread. /// @@ -854,8 +850,8 @@ public static class IJobParallelForSPMDExtensions /// The SPMD job to run. /// The total number of iterations to execute across all lanes. /// The job execution context providing information about the current execution environment. - public static void Run(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx) - where T : struct, IJobSPMD + public static void Run(this T job, int totalIteration, ref readonly JobExecutionContext ctx) + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -909,7 +905,7 @@ public static class IJobParallelForSPMDExtensions /// The priority of the job. /// Any job handles that this job depends on, which must complete before this job can start. public static JobHandle ScheduleParallelSPDM(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan dependencies) - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -938,7 +934,6 @@ public static class IJobParallelForSPMDExtensions } } - /// /// Run the SPMD job with the specified total count and job execution context directly on the calling thread. /// @@ -953,8 +948,8 @@ public static class IJobParallelForSPMDExtensions /// The SPMD job to run. /// The total number of iterations to execute across all lanes. /// The job execution context providing information about the current execution environment. - public static void Run(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx) - where T : struct, IJobSPMD + public static void Run(this T job, int totalIteration, ref readonly JobExecutionContext ctx) + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -1010,7 +1005,7 @@ public static class IJobParallelForSPMDExtensions /// The priority of the job. /// Any job handles that this job depends on, which must complete before this job can start. public static JobHandle ScheduleParallelSPDM(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan dependencies) - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -1040,7 +1035,6 @@ public static class IJobParallelForSPMDExtensions } } - /// /// Run the SPMD job with the specified total count and job execution context directly on the calling thread. /// @@ -1056,8 +1050,8 @@ public static class IJobParallelForSPMDExtensions /// The SPMD job to run. /// The total number of iterations to execute across all lanes. /// The job execution context providing information about the current execution environment. - public static void Run(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx) - where T : struct, IJobSPMD + public static void Run(this T job, int totalIteration, ref readonly JobExecutionContext ctx) + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -1115,7 +1109,7 @@ public static class IJobParallelForSPMDExtensions /// The priority of the job. /// Any job handles that this job depends on, which must complete before this job can start. public static JobHandle ScheduleParallelSPDM(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan dependencies) - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -1146,7 +1140,6 @@ public static class IJobParallelForSPMDExtensions } } - /// /// Run the SPMD job with the specified total count and job execution context directly on the calling thread. /// @@ -1163,8 +1156,8 @@ public static class IJobParallelForSPMDExtensions /// The SPMD job to run. /// The total number of iterations to execute across all lanes. /// The job execution context providing information about the current execution environment. - public static void Run(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx) - where T : struct, IJobSPMD + public static void Run(this T job, int totalIteration, ref readonly JobExecutionContext ctx) + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -1224,7 +1217,7 @@ public static class IJobParallelForSPMDExtensions /// The priority of the job. /// Any job handles that this job depends on, which must complete before this job can start. public static JobHandle ScheduleParallelSPDM(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan dependencies) - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -1256,7 +1249,6 @@ public static class IJobParallelForSPMDExtensions } } - /// /// Run the SPMD job with the specified total count and job execution context directly on the calling thread. /// @@ -1274,8 +1266,8 @@ public static class IJobParallelForSPMDExtensions /// The SPMD job to run. /// The total number of iterations to execute across all lanes. /// The job execution context providing information about the current execution environment. - public static void Run(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx) - where T : struct, IJobSPMD + public static void Run(this T job, int totalIteration, ref readonly JobExecutionContext ctx) + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators @@ -1337,7 +1329,7 @@ public static class IJobParallelForSPMDExtensions /// The priority of the job. /// Any job handles that this job depends on, which must complete before this job can start. public static JobHandle ScheduleParallelSPDM(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan dependencies) - where T : unmanaged, IJobSPMD + where T : IJobSPMD where TNumber0 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber1 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators where TNumber2 : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators diff --git a/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.tt b/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.tt index 41a6286..ff64ed3 100644 --- a/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.tt +++ b/Misaki.HighPerformance.Mathematics.SPMD/Templates/IJobSPMD.tt @@ -33,7 +33,7 @@ public interface IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> } internal struct SPMDJobWrapper $"TNumber{j}") #>> : IJobParallelFor - where T : unmanaged, IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> + where T : IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> <#= GetTNumberRestrictions(i + 1) #> { public T innerJob; @@ -59,7 +59,7 @@ internal struct SPMDJobWrapper $"TNumber{j}" } internal struct SPMDScalerJobWrapper $"TNumber{j}") #>> : IJobParallelFor - where T : unmanaged, IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> + where T : IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> <#= GetTNumberRestrictions(i + 1) #> { public T innerJob; @@ -76,7 +76,6 @@ internal struct SPMDScalerJobWrapper $"TNumb public static class IJobParallelForSPMDExtensions { <# for (var i = 0; i < 8; i++) { #> - /// /// Run the SPMD job with the specified total count and job execution context directly on the calling thread. /// @@ -87,8 +86,8 @@ public static class IJobParallelForSPMDExtensions /// The SPMD job to run. /// The total number of iterations to execute across all lanes. /// The job execution context providing information about the current execution environment. - public static void Run $"TNumber{j}") #>>(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx) - where T : struct, IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> + public static void Run $"TNumber{j}") #>>(this T job, int totalIteration, ref readonly JobExecutionContext ctx) + where T : IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> <#= GetTNumberRestrictions(i + 1) #> { if (WideLane.IsSupported) @@ -136,7 +135,7 @@ public static class IJobParallelForSPMDExtensions /// The priority of the job. /// Any job handles that this job depends on, which must complete before this job can start. public static JobHandle ScheduleParallelSPDM $"TNumber{j}") #>>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan dependencies) - where T : unmanaged, IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> + where T : IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>> <#= GetTNumberRestrictions(i + 1) #> { if (WideLane.IsSupported) diff --git a/Misaki.HighPerformance.Test/Benchmark/GGXMipGenerationBenchmark.cs b/Misaki.HighPerformance.Test/Benchmark/GGXMipGenerationBenchmark.cs index 346aaeb..7cce3f2 100644 --- a/Misaki.HighPerformance.Test/Benchmark/GGXMipGenerationBenchmark.cs +++ b/Misaki.HighPerformance.Test/Benchmark/GGXMipGenerationBenchmark.cs @@ -62,7 +62,7 @@ internal unsafe struct GGXMipGenerationJobSPMD : IJobParallelFor var phi = 2.0f * PI * Xi.x; - var cosTheta = TFloat.Sqrt((1.0f - Xi.y) / (1.0f + (a * a - 1.0f) * Xi.y)); + var cosTheta = TFloat.Sqrt((1.0f - Xi.y) / TFloat.MultipleAdd(a * a - 1.0f, Xi.y, 1.0f)); var sinTheta = TFloat.Sqrt(1.0f - cosTheta * cosTheta); // Spherical to Cartesian coordinates (Halfway vector) diff --git a/Misaki.HighPerformance.Test/Program.cs b/Misaki.HighPerformance.Test/Program.cs index 7af3c77..aab3b0f 100644 --- a/Misaki.HighPerformance.Test/Program.cs +++ b/Misaki.HighPerformance.Test/Program.cs @@ -28,134 +28,4 @@ for (int i = 0; i < count; i++) sw.Stop(); var avgTime = sw.Elapsed.TotalMilliseconds / count; Console.WriteLine($"GGX Mip Generation (Inline): {avgTime} ms"); -bench.Cleanup(); - -//AllocationManager.Initialize(AllocationManagerInitOpts.Default); -//var set = new UnsafeBitSet(100, AllocationHandle.Persistent, AllocationOption.Clear); -//set.SetBit(0); -//Console.WriteLine(set.NextSetBit(0)); - -//set.Dispose(); -//AllocationManager.Dispose(); - -//unsafe -//{ -// var testC = new TestC(); -// testC.BindToVtables(); -// testC.MyValue = 42; - -// // 1. Casting to IB (Direct cast, offset 0) -// var pB = (IB.Interface*)&testC; -// pB->MethodA(); -// pB->MethodB(); - -// // 2. Casting to IC (Pointer adjustment needed!) -// // We must offset the pointer by the size of one void* so it points to lpVtbl_IC -// var pC = (IC.Interface*)((byte*)&testC + sizeof(void*)); -// pC->MethodC(); -//} - -//public interface IA -//{ -// [StructLayout(LayoutKind.Sequential)] -// unsafe struct Interface -// { -// public void** lpVtbl; -// public void MethodA() => ((delegate*)lpVtbl[0])((Interface*)Unsafe.AsPointer(ref this)); -// } -//} - -//public interface IB : IA -//{ -// [StructLayout(LayoutKind.Sequential)] -// new unsafe struct Interface -// { -// public void** lpVtbl; -// // IA Methods -// public void MethodA() => ((delegate*)lpVtbl[0])((Interface*)Unsafe.AsPointer(ref this)); -// // IB Methods -// public void MethodB() => ((delegate*)lpVtbl[1])((Interface*)Unsafe.AsPointer(ref this)); -// } -//} - -//public interface IC -//{ -// [StructLayout(LayoutKind.Sequential)] -// unsafe struct Interface -// { -// public void** lpVtbl; -// public void MethodC() => ((delegate*)lpVtbl[0])((Interface*)Unsafe.AsPointer(ref this)); -// } -//} - -//[StructLayout(LayoutKind.Sequential)] -//public unsafe partial struct TestC -//{ -// // Offset 0: Primary VTable (Covers IB and IA) -// public void** lpVtbl_IB; - -// // Offset 8 (on 64-bit): Secondary VTable (Covers IC) -// public void** lpVtbl_IC; - -// // Offset 16: Fields -// public int MyValue; -//} - -//public unsafe partial struct TestC -//{ -// public struct Vtbl_IB -// { -// public delegate* MethodA; -// public delegate* MethodB; -// } - -// public struct Vtbl_IC -// { -// public delegate* MethodC; -// } - -// [FixedAddressValueType] -// public static readonly Vtbl_IB Table_IB = new Vtbl_IB -// { -// MethodA = &Native_MethodA, -// MethodB = &Native_MethodB -// }; - -// [FixedAddressValueType] -// public static readonly Vtbl_IC Table_IC = new Vtbl_IC -// { -// MethodC = &Native_MethodC -// }; - -// public void BindToVtables() -// { -// fixed (Vtbl_IB* pIB = &Table_IB) -// lpVtbl_IB = (void**)pIB; -// fixed (Vtbl_IC* pIC = &Table_IC) -// lpVtbl_IC = (void**)pIC; -// } - -// // --- IB & IA Implementations --- -// public static void Native_MethodA(IB.Interface* self) -// { -// // For IB/IA, no adjustment is needed because lpVtbl_IB is at offset 0 -// var pThis = (TestC*)self; -// Console.WriteLine($"MethodA called. MyValue: {pThis->MyValue}"); -// } - -// public static void Native_MethodB(IB.Interface* self) -// { -// var pThis = (TestC*)self; -// Console.WriteLine($"MethodB called. MyValue: {pThis->MyValue}"); -// } - -// // --- IC Implementations --- -// public static void Native_MethodC(IC.Interface* self) -// { -// // WARNING: 'self' points to the lpVtbl_IC field, NOT the start of TestC! -// // We must shift the pointer backward by the size of lpVtbl_IB (sizeof(void*)) -// // to reconstruct the original TestC pointer, otherwise we read garbage memory. -// var pThis = (TestC*)((byte*)self - sizeof(void*)); -// Console.WriteLine($"MethodC called. MyValue: {pThis->MyValue}"); -// } -//} \ No newline at end of file +bench.Cleanup(); \ No newline at end of file diff --git a/Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs b/Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs index 52e0b72..a70da2f 100644 --- a/Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs +++ b/Misaki.HighPerformance.Test/UnitTest/Jobs/SPMDTest.cs @@ -23,7 +23,7 @@ internal unsafe struct DotProductJob : IJobSPMD } } -internal unsafe struct Vector2LerpJob : IJobSPMD +internal struct Vector2LerpJob : IJobSPMD { public float2[] arrayA; public float2[] arrayB; @@ -39,11 +39,11 @@ internal unsafe struct Vector2LerpJob : IJobSPMD var lerped = MathV.Lerp(a, b, t); var len = TLane.Sqrt(MathV.LengthSquared(lerped)); - len.Store((float*)Unsafe.AsPointer(ref results[baseIndex])); + len.Store(ref results[baseIndex]); } } -internal unsafe struct Vector4NormalizeJob : IJobSPMD +internal struct Vector4NormalizeJob : IJobSPMD { public float4[] input; public float4[] output; @@ -53,11 +53,11 @@ internal unsafe struct Vector4NormalizeJob : IJobSPMD { var vec = MathV.LoadVector4(ref input[baseIndex].x); var normalized = MathV.Normalize(vec); - normalized.Store((float*)Unsafe.AsPointer(ref output[baseIndex].x)); + normalized.Store(ref output[baseIndex].x); } } -internal unsafe struct Vector3CrossJob : IJobSPMD +internal struct Vector3CrossJob : IJobSPMD { public float3[] arrayA; public float3[] arrayB; @@ -70,11 +70,11 @@ internal unsafe struct Vector3CrossJob : IJobSPMD var b = MathV.LoadVector3(ref arrayB[baseIndex].x); var cross = MathV.Cross(a, b); - cross.Store((float*)Unsafe.AsPointer(ref results[baseIndex].x)); + cross.Store(ref results[baseIndex].x); } } -internal unsafe struct MinMaxClampJob : IJobSPMD +internal struct MinMaxClampJob : IJobSPMD { public float3[] values; public float3[] mins; @@ -89,11 +89,11 @@ internal unsafe struct MinMaxClampJob : IJobSPMD var max = MathV.LoadVector3(ref maxs[baseIndex].x); var clamped = MathV.Clamp(val, min, max); - clamped.Store((float*)Unsafe.AsPointer(ref results[baseIndex].x)); + clamped.Store(ref results[baseIndex].x); } } -internal unsafe struct DistanceJob : IJobSPMD +internal struct DistanceJob : IJobSPMD { public float3[] arrayA; public float3[] arrayB; @@ -106,7 +106,7 @@ internal unsafe struct DistanceJob : IJobSPMD var b = MathV.LoadVector3(ref arrayB[baseIndex].x); var dist = MathV.Distance(a, b); - dist.Store((float*)Unsafe.AsPointer(ref results[baseIndex])); + dist.Store(ref results[baseIndex]); } }