|
1 | | -// Copyright (c) Six Labors. |
| 1 | +// Copyright (c) Six Labors. |
2 | 2 | // Licensed under the Six Labors Split License. |
3 | 3 |
|
4 | 4 | using System.Diagnostics; |
5 | 5 | using System.Numerics; |
6 | 6 | using System.Runtime.CompilerServices; |
7 | | -using System.Runtime.InteropServices; |
8 | 7 | using System.Runtime.Intrinsics; |
| 8 | +using System.Runtime.Intrinsics.Arm; |
9 | 9 | using System.Runtime.Intrinsics.X86; |
10 | 10 |
|
11 | 11 | namespace SixLabors.ImageSharp; |
@@ -36,30 +36,39 @@ internal static Vector4 PseudoRound(this Vector4 v) |
36 | 36 |
|
37 | 37 | /// <summary> |
38 | 38 | /// Rounds all values in 'v' to the nearest integer following <see cref="MidpointRounding.ToEven"/> semantics. |
39 | | - /// Source: |
40 | | - /// <see> |
41 | | - /// <cref>https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110</cref> |
42 | | - /// </see> |
43 | 39 | /// </summary> |
44 | 40 | /// <param name="v">The vector</param> |
45 | 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
46 | 42 | internal static Vector<float> FastRound(this Vector<float> v) |
47 | 43 | { |
48 | | - if (Avx2.IsSupported) |
| 44 | + // .NET9+ has a built-in method for this Vector.Round |
| 45 | + if (Avx2.IsSupported && Vector<float>.Count == Vector256<float>.Count) |
49 | 46 | { |
50 | 47 | ref Vector256<float> v256 = ref Unsafe.As<Vector<float>, Vector256<float>>(ref v); |
51 | 48 | Vector256<float> vRound = Avx.RoundToNearestInteger(v256); |
52 | 49 | return Unsafe.As<Vector256<float>, Vector<float>>(ref vRound); |
53 | 50 | } |
54 | | - else |
| 51 | + |
| 52 | + if (Sse41.IsSupported && Vector<float>.Count == Vector128<float>.Count) |
| 53 | + { |
| 54 | + ref Vector128<float> v128 = ref Unsafe.As<Vector<float>, Vector128<float>>(ref v); |
| 55 | + Vector128<float> vRound = Sse41.RoundToNearestInteger(v128); |
| 56 | + return Unsafe.As<Vector128<float>, Vector<float>>(ref vRound); |
| 57 | + } |
| 58 | + |
| 59 | + if (AdvSimd.IsSupported && Vector<float>.Count == Vector128<float>.Count) |
55 | 60 | { |
56 | | - var magic0 = new Vector<int>(int.MinValue); // 0x80000000 |
57 | | - var sgn0 = Vector.AsVectorSingle(magic0); |
58 | | - var and0 = Vector.BitwiseAnd(sgn0, v); |
59 | | - var or0 = Vector.BitwiseOr(and0, new Vector<float>(8388608.0f)); |
60 | | - var add0 = Vector.Add(v, or0); |
61 | | - return Vector.Subtract(add0, or0); |
| 61 | + ref Vector128<float> v128 = ref Unsafe.As<Vector<float>, Vector128<float>>(ref v); |
| 62 | + Vector128<float> vRound = AdvSimd.RoundToNearest(v128); |
| 63 | + return Unsafe.As<Vector128<float>, Vector<float>>(ref vRound); |
62 | 64 | } |
| 65 | + |
| 66 | + // https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L11 |
| 67 | + Vector<float> sign = v & new Vector<float>(-0F); |
| 68 | + Vector<float> val_2p23_f32 = sign | new Vector<float>(8388608F); |
| 69 | + |
| 70 | + val_2p23_f32 = (v + val_2p23_f32) - val_2p23_f32; |
| 71 | + return val_2p23_f32 | sign; |
63 | 72 | } |
64 | 73 |
|
65 | 74 | [Conditional("DEBUG")] |
|
0 commit comments