diff --git a/Content.Benchmarks/ColorInterpolateBenchmark.cs b/Content.Benchmarks/ColorInterpolateBenchmark.cs index 1330549b8a..24b8914d14 100644 --- a/Content.Benchmarks/ColorInterpolateBenchmark.cs +++ b/Content.Benchmarks/ColorInterpolateBenchmark.cs @@ -1,15 +1,20 @@ using System; -using System.Collections.Generic; using System.Runtime.CompilerServices; +#if NETCOREAPP +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif using BenchmarkDotNet.Attributes; using Robust.Shared.Maths; using SysVector4 = System.Numerics.Vector4; namespace Content.Benchmarks { + [DisassemblyDiagnoser] public class ColorInterpolateBenchmark { - private readonly List<(Color, Color)> _colors = new List<(Color, Color)>(); + private (Color, Color)[] _colors; + private Color[] _output; [Params(100)] public int N { get; set; } @@ -18,6 +23,9 @@ namespace Content.Benchmarks { var random = new Random(3005); + _colors = new (Color, Color)[N]; + _output = new Color[N]; + for (var i = 0; i < N; i++) { var r1 = random.NextFloat(); @@ -30,123 +38,122 @@ namespace Content.Benchmarks var b2 = random.NextFloat(); var a2 = random.NextFloat(); - _colors.Add((new Color(r1, g1, b1, a1), new Color(r2, g2, b2, a2))); + _colors[i] = (new Color(r1, g1, b1, a1), new Color(r2, g2, b2, a2)); } } [Benchmark] public void BenchSimple() { - foreach (var (a, b) in _colors) + for (var i = 0; i < N; i++) { - InterpolateSimple(a, b, 0.5f); + ref var tuple = ref _colors[i]; + _output[i] = InterpolateSimple(tuple.Item1, tuple.Item2, 0.5f); } } - //[Benchmark] - public void BenchSysVector4() - { - foreach (var (a, b) in _colors) - { - InterpolateSysVector4(a, b, 0.5f); - } - } - //[Benchmark] - public void BenchSysVector4Blit() + [Benchmark] + public void BenchSysVector4In() { - foreach (var (a, b) in _colors) + for (var i = 0; i < N; i++) { - InterpolateSysVector4Blit(a, b, 0.5f); - } - } - - //[Benchmark] - public void BenchSysVector4BlitNoException() - { - foreach (var (a, b) in _colors) - { - InterpolateSysVector4BlitNoException(a, b, 0.5f); + ref var tuple = ref _colors[i]; + _output[i] = InterpolateSysVector4In(tuple.Item1, tuple.Item2, 0.5f); } } [Benchmark] - public void BenchSysVector4AsRefNoException() + public void BenchSysVector4() { - foreach (var (a, b) in _colors) + for (var i = 0; i < N; i++) { - InterpolateSysVector4BlitNoExceptionAsRef(a, b, 0.5f); + ref var tuple = ref _colors[i]; + _output[i] = InterpolateSysVector4(tuple.Item1, tuple.Item2, 0.5f); } } - public static Color InterpolateSimple(Color endPoint1, Color endPoint2, float lambda) +#if NETCOREAPP + [Benchmark] + public void BenchSimd() + { + for (var i = 0; i < N; i++) + { + ref var tuple = ref _colors[i]; + _output[i] = InterpolateSimd(tuple.Item1, tuple.Item2, 0.5f); + } + } + + [Benchmark] + public void BenchSimdIn() + { + for (var i = 0; i < N; i++) + { + ref var tuple = ref _colors[i]; + _output[i] = InterpolateSimdIn(tuple.Item1, tuple.Item2, 0.5f); + } + } +#endif + + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public static Color InterpolateSimple(Color a, Color b, float lambda) { - if (lambda < 0 || lambda > 1) - throw new ArgumentOutOfRangeException(nameof(lambda)); return new Color( - endPoint1.R * lambda + endPoint2.R * (1 - lambda), - endPoint1.G * lambda + endPoint2.G * (1 - lambda), - endPoint1.B * lambda + endPoint2.B * (1 - lambda), - endPoint1.A * lambda + endPoint2.A * (1 - lambda) + a.R + (b.R - a.R) * lambda, + a.G + (b.G - a.G) * lambda, + a.B + (b.G - a.B) * lambda, + a.A + (b.A - a.A) * lambda ); } - public static Color InterpolateSysVector4(Color endPoint1, Color endPoint2, float lambda) - { - if (lambda < 0 || lambda > 1) - throw new ArgumentOutOfRangeException(nameof(lambda)); - - var vec1 = new SysVector4(endPoint1.R, endPoint1.G, endPoint1.B, endPoint1.A); - var vec2 = new SysVector4(endPoint2.R, endPoint2.G, endPoint2.B, endPoint2.A); - - var res = SysVector4.Lerp(vec1, vec2, 1 - lambda); - - return new Color( - res.X, res.Y, res.Z, res.W); - } - - public static unsafe Color InterpolateSysVector4Blit(in Color endPoint1, in Color endPoint2, float lambda) - { - if (lambda < 0 || lambda > 1) - throw new ArgumentOutOfRangeException(nameof(lambda)); - - - fixed (Color* p1 = &endPoint1) - fixed (Color* p2 = &endPoint2) - { - var vp1 = (SysVector4*) p1; - var vp2 = (SysVector4*) p2; - - var res = SysVector4.Lerp(*vp1, *vp2, 1 - lambda); - - return *(Color*) (&res); - } - } - - public static unsafe Color InterpolateSysVector4BlitNoException(in Color endPoint1, in Color endPoint2, + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public static Color InterpolateSysVector4(Color a, Color b, float lambda) { - fixed (Color* p1 = &endPoint1) - fixed (Color* p2 = &endPoint2) - { - var vp1 = (SysVector4*) p1; - var vp2 = (SysVector4*) p2; + ref var sva = ref Unsafe.As(ref a); + ref var svb = ref Unsafe.As(ref b); - var res = SysVector4.Lerp(*vp2, *vp1, lambda); - - return *(Color*) (&res); - } - } - - public static unsafe Color InterpolateSysVector4BlitNoExceptionAsRef(in Color endPoint1, in Color endPoint2, - float lambda) - { - ref var sv1 = ref Unsafe.As(ref Unsafe.AsRef(endPoint1)); - ref var sv2 = ref Unsafe.As(ref Unsafe.AsRef(endPoint2)); - - var res = SysVector4.Lerp(sv2, sv1, lambda); + var res = SysVector4.Lerp(sva, svb, lambda); return Unsafe.As(ref res); } + + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public static Color InterpolateSysVector4In(in Color endPoint1, in Color endPoint2, + float lambda) + { + ref var sva = ref Unsafe.As(ref Unsafe.AsRef(endPoint1)); + ref var svb = ref Unsafe.As(ref Unsafe.AsRef(endPoint2)); + + var res = SysVector4.Lerp(svb, sva, lambda); + + return Unsafe.As(ref res); + } + +#if NETCOREAPP + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public static Color InterpolateSimd(Color a, Color b, + float lambda) + { + var vecA = Unsafe.As>(ref a); + var vecB = Unsafe.As>(ref b); + + vecB = Fma.MultiplyAdd(Sse.Subtract(vecB, vecA), Vector128.Create(lambda), vecA); + + return Unsafe.As, Color>(ref vecB); + } + + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public static Color InterpolateSimdIn(in Color a, in Color b, + float lambda) + { + var vecA = Unsafe.As>(ref Unsafe.AsRef(a)); + var vecB = Unsafe.As>(ref Unsafe.AsRef(b)); + + vecB = Fma.MultiplyAdd(Sse.Subtract(vecB, vecA), Vector128.Create(lambda), vecA); + + return Unsafe.As, Color>(ref vecB); + } +#endif } }