Relax SPMD job constraints, improve safety and docs

Removed unmanaged struct requirement from SPMD job wrappers and extension methods, allowing managed types. Updated all wrappers and extension methods to require only the interface constraint. Refactored SPMD test jobs to use safe ref-based Store overloads. Improved README and docs with clearer debug/mimalloc instructions and a better SPMD example. Cleaned up Program.cs by removing obsolete experimental code. Enhanced math precision in GGXMipGenerationBenchmark. Updated T4 template to generate new constraints and APIs.
This commit is contained in:
2026-05-01 12:39:37 +09:00
parent 18a181f57a
commit eb01e557d5
7 changed files with 87 additions and 205 deletions

View File

@@ -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.

View File

@@ -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<float>
{
public float2[] arrayA;
public float2[] arrayB;
public float[] results;
public readonly void Execute<TLane>(int baseIndex, ref readonly JobExecutionContext ctx)
where TLane : unmanaged, ISPMDLane<TLane, float>
{
var a = MathV.LoadVector2<TLane, float>(ref arrayA[baseIndex].x);
var b = MathV.LoadVector2<TLane, float>(ref arrayB[baseIndex].x);
var t = TLane.Create(0.5f);
var lerped = MathV.Lerp(a, b, t);
var len = TLane.Sqrt(MathV.LengthSquared(lerped));
len.Store(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.

View File

@@ -18,7 +18,7 @@ public interface IJobSPMD<TNumber0>
}
internal struct SPMDJobWrapper<T, TNumber0> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0>
where T : IJobSPMD<TNumber0>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
{
public T innerJob;
@@ -44,7 +44,7 @@ internal struct SPMDJobWrapper<T, TNumber0> : IJobParallelFor
}
internal struct SPMDScalerJobWrapper<T, TNumber0> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0>
where T : IJobSPMD<TNumber0>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
{
public T innerJob;
@@ -74,7 +74,7 @@ public interface IJobSPMD<TNumber0, TNumber1>
}
internal struct SPMDJobWrapper<T, TNumber0, TNumber1> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1>
where T : IJobSPMD<TNumber0, TNumber1>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
{
@@ -101,7 +101,7 @@ internal struct SPMDJobWrapper<T, TNumber0, TNumber1> : IJobParallelFor
}
internal struct SPMDScalerJobWrapper<T, TNumber0, TNumber1> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1>
where T : IJobSPMD<TNumber0, TNumber1>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
{
@@ -135,7 +135,7 @@ public interface IJobSPMD<TNumber0, TNumber1, TNumber2>
}
internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -163,7 +163,7 @@ internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2> : IJobParallelFo
}
internal struct SPMDScalerJobWrapper<T, TNumber0, TNumber1, TNumber2> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -201,7 +201,7 @@ public interface IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3>
}
internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -230,7 +230,7 @@ internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3> : IJob
}
internal struct SPMDScalerJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -272,7 +272,7 @@ public interface IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>
}
internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -302,7 +302,7 @@ internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumbe
}
internal struct SPMDScalerJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -348,7 +348,7 @@ public interface IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNum
}
internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -379,7 +379,7 @@ internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumbe
}
internal struct SPMDScalerJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -429,7 +429,7 @@ public interface IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNum
}
internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -461,7 +461,7 @@ internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumbe
}
internal struct SPMDScalerJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -515,7 +515,7 @@ public interface IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNum
}
internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -548,7 +548,7 @@ internal struct SPMDJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumbe
}
internal struct SPMDScalerJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7> : IJobParallelFor
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -570,7 +570,6 @@ internal struct SPMDScalerJobWrapper<T, TNumber0, TNumber1, TNumber2, TNumber3,
public static class IJobParallelForSPMDExtensions
{
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
@@ -581,8 +580,8 @@ public static class IJobParallelForSPMDExtensions
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, TNumber0>(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : struct, IJobSPMD<TNumber0>
public static void Run<T, TNumber0>(this T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : IJobSPMD<TNumber0>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
{
if (WideLane.IsSupported)
@@ -630,7 +629,7 @@ public static class IJobParallelForSPMDExtensions
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, TNumber0>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> dependencies)
where T : unmanaged, IJobSPMD<TNumber0>
where T : IJobSPMD<TNumber0>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
{
if (WideLane.IsSupported)
@@ -656,7 +655,6 @@ public static class IJobParallelForSPMDExtensions
}
}
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
@@ -668,8 +666,8 @@ public static class IJobParallelForSPMDExtensions
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, TNumber0, TNumber1>(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : struct, IJobSPMD<TNumber0, TNumber1>
public static void Run<T, TNumber0, TNumber1>(this T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : IJobSPMD<TNumber0, TNumber1>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
{
@@ -719,7 +717,7 @@ public static class IJobParallelForSPMDExtensions
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, TNumber0, TNumber1>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> dependencies)
where T : unmanaged, IJobSPMD<TNumber0, TNumber1>
where T : IJobSPMD<TNumber0, TNumber1>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
{
@@ -746,7 +744,6 @@ public static class IJobParallelForSPMDExtensions
}
}
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
@@ -759,8 +756,8 @@ public static class IJobParallelForSPMDExtensions
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, TNumber0, TNumber1, TNumber2>(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : struct, IJobSPMD<TNumber0, TNumber1, TNumber2>
public static void Run<T, TNumber0, TNumber1, TNumber2>(this T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : IJobSPMD<TNumber0, TNumber1, TNumber2>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -812,7 +809,7 @@ public static class IJobParallelForSPMDExtensions
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, TNumber0, TNumber1, TNumber2>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> dependencies)
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -840,7 +837,6 @@ public static class IJobParallelForSPMDExtensions
}
}
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
@@ -854,8 +850,8 @@ public static class IJobParallelForSPMDExtensions
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3>(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : struct, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3>(this T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -909,7 +905,7 @@ public static class IJobParallelForSPMDExtensions
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, TNumber0, TNumber1, TNumber2, TNumber3>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> dependencies)
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -938,7 +934,6 @@ public static class IJobParallelForSPMDExtensions
}
}
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
@@ -953,8 +948,8 @@ public static class IJobParallelForSPMDExtensions
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : struct, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>(this T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -1010,7 +1005,7 @@ public static class IJobParallelForSPMDExtensions
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> dependencies)
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -1040,7 +1035,6 @@ public static class IJobParallelForSPMDExtensions
}
}
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
@@ -1056,8 +1050,8 @@ public static class IJobParallelForSPMDExtensions
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : struct, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>(this T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -1115,7 +1109,7 @@ public static class IJobParallelForSPMDExtensions
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> dependencies)
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -1146,7 +1140,6 @@ public static class IJobParallelForSPMDExtensions
}
}
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
@@ -1163,8 +1156,8 @@ public static class IJobParallelForSPMDExtensions
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : struct, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>(this T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -1224,7 +1217,7 @@ public static class IJobParallelForSPMDExtensions
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> dependencies)
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -1256,7 +1249,6 @@ public static class IJobParallelForSPMDExtensions
}
}
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
@@ -1274,8 +1266,8 @@ public static class IJobParallelForSPMDExtensions
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>(this ref T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : struct, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>
public static void Run<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>(this T job, int totalIteration, ref readonly JobExecutionContext ctx)
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>
@@ -1337,7 +1329,7 @@ public static class IJobParallelForSPMDExtensions
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> dependencies)
where T : unmanaged, IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>
where T : IJobSPMD<TNumber0, TNumber1, TNumber2, TNumber3, TNumber4, TNumber5, TNumber6, TNumber7>
where TNumber0 : unmanaged, INumber<TNumber0>, IBinaryNumber<TNumber0>, IMinMaxValue<TNumber0>, IBitwiseOperators<TNumber0, TNumber0, TNumber0>
where TNumber1 : unmanaged, INumber<TNumber1>, IBinaryNumber<TNumber1>, IMinMaxValue<TNumber1>, IBitwiseOperators<TNumber1, TNumber1, TNumber1>
where TNumber2 : unmanaged, INumber<TNumber2>, IBinaryNumber<TNumber2>, IMinMaxValue<TNumber2>, IBitwiseOperators<TNumber2, TNumber2, TNumber2>

View File

@@ -33,7 +33,7 @@ public interface IJobSPMD<<#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>
}
internal struct SPMDJobWrapper<T, <#= ForEachDimension(i + 1, j => $"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<T, <#= ForEachDimension(i + 1, j => $"TNumber{j}"
}
internal struct SPMDScalerJobWrapper<T, <#= ForEachDimension(i + 1, j => $"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<T, <#= ForEachDimension(i + 1, j => $"TNumb
public static class IJobParallelForSPMDExtensions
{
<# for (var i = 0; i < 8; i++) { #>
/// <summary>
/// Run the SPMD job with the specified total count and job execution context directly on the calling thread.
/// </summary>
@@ -87,8 +86,8 @@ public static class IJobParallelForSPMDExtensions
/// <param name="job">The SPMD job to run.</param>
/// <param name="totalIteration">The total number of iterations to execute across all lanes.</param>
/// <param name="ctx">The job execution context providing information about the current execution environment.</param>
public static void Run<T, <#= ForEachDimension(i + 1, j => $"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<T, <#= ForEachDimension(i + 1, j => $"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
/// <param name="priority">The priority of the job.</param>
/// <param name="dependencies">Any job handles that this job depends on, which must complete before this job can start.</param>
public static JobHandle ScheduleParallelSPDM<T, <#= ForEachDimension(i + 1, j => $"TNumber{j}") #>>(this JobScheduler jobScheduler, ref T job, int totalIteration, int batchSize, bool preferLocal, JobPriority priority, params ReadOnlySpan<JobHandle> 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)

View File

@@ -62,7 +62,7 @@ internal unsafe struct GGXMipGenerationJobSPMD<TFloat, TInt> : 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)

View File

@@ -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*<Interface*, void>)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*<Interface*, void>)lpVtbl[0])((Interface*)Unsafe.AsPointer(ref this));
// // IB Methods
// public void MethodB() => ((delegate*<Interface*, void>)lpVtbl[1])((Interface*)Unsafe.AsPointer(ref this));
// }
//}
//public interface IC
//{
// [StructLayout(LayoutKind.Sequential)]
// unsafe struct Interface
// {
// public void** lpVtbl;
// public void MethodC() => ((delegate*<Interface*, void>)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*<IB.Interface*, void> MethodA;
// public delegate*<IB.Interface*, void> MethodB;
// }
// public struct Vtbl_IC
// {
// public delegate*<IC.Interface*, void> 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}");
// }
//}
bench.Cleanup();

View File

@@ -23,7 +23,7 @@ internal unsafe struct DotProductJob : IJobSPMD<float>
}
}
internal unsafe struct Vector2LerpJob : IJobSPMD<float>
internal struct Vector2LerpJob : IJobSPMD<float>
{
public float2[] arrayA;
public float2[] arrayB;
@@ -39,11 +39,11 @@ internal unsafe struct Vector2LerpJob : IJobSPMD<float>
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<float>
internal struct Vector4NormalizeJob : IJobSPMD<float>
{
public float4[] input;
public float4[] output;
@@ -53,11 +53,11 @@ internal unsafe struct Vector4NormalizeJob : IJobSPMD<float>
{
var vec = MathV.LoadVector4<TLane, float>(ref input[baseIndex].x);
var normalized = MathV.Normalize(vec);
normalized.Store((float*)Unsafe.AsPointer(ref output[baseIndex].x));
normalized.Store(ref output[baseIndex].x);
}
}
internal unsafe struct Vector3CrossJob : IJobSPMD<float>
internal struct Vector3CrossJob : IJobSPMD<float>
{
public float3[] arrayA;
public float3[] arrayB;
@@ -70,11 +70,11 @@ internal unsafe struct Vector3CrossJob : IJobSPMD<float>
var b = MathV.LoadVector3<TLane, float>(ref arrayB[baseIndex].x);
var cross = MathV.Cross(a, b);
cross.Store((float*)Unsafe.AsPointer(ref results[baseIndex].x));
cross.Store(ref results[baseIndex].x);
}
}
internal unsafe struct MinMaxClampJob : IJobSPMD<float>
internal struct MinMaxClampJob : IJobSPMD<float>
{
public float3[] values;
public float3[] mins;
@@ -89,11 +89,11 @@ internal unsafe struct MinMaxClampJob : IJobSPMD<float>
var max = MathV.LoadVector3<TLane, float>(ref maxs[baseIndex].x);
var clamped = MathV.Clamp(val, min, max);
clamped.Store((float*)Unsafe.AsPointer(ref results[baseIndex].x));
clamped.Store(ref results[baseIndex].x);
}
}
internal unsafe struct DistanceJob : IJobSPMD<float>
internal struct DistanceJob : IJobSPMD<float>
{
public float3[] arrayA;
public float3[] arrayB;
@@ -106,7 +106,7 @@ internal unsafe struct DistanceJob : IJobSPMD<float>
var b = MathV.LoadVector3<TLane, float>(ref arrayB[baseIndex].x);
var dist = MathV.Distance(a, b);
dist.Store((float*)Unsafe.AsPointer(ref results[baseIndex]));
dist.Store(ref results[baseIndex]);
}
}