diff --git a/src/benchmarks/micro/MicroBenchmarks.csproj b/src/benchmarks/micro/MicroBenchmarks.csproj
index 0787630ff8c..e49272f95da 100644
--- a/src/benchmarks/micro/MicroBenchmarks.csproj
+++ b/src/benchmarks/micro/MicroBenchmarks.csproj
@@ -8,6 +8,8 @@
pdbonly
true
true
+
+ true
@@ -68,5 +70,9 @@
-
-
\ No newline at end of file
+
+
+
+
+
+
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/Camera.cs b/src/benchmarks/micro/coreclr/PacketTracer/Camera.cs
new file mode 100644
index 00000000000..e7bd54e9d40
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/Camera.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal class Camera
+ {
+ public Camera(VectorPacket256 pos, VectorPacket256 forward, VectorPacket256 up, VectorPacket256 right)
+ {
+ Pos = pos;
+ Forward = forward;
+ Up = up;
+ Right = right;
+ }
+
+ public VectorPacket256 Pos;
+ public VectorPacket256 Forward;
+ public VectorPacket256 Up;
+ public VectorPacket256 Right;
+
+ public static Camera Create(VectorPacket256 pos, VectorPacket256 lookAt)
+ {
+ VectorPacket256 forward = (lookAt - pos).Normalize();
+ VectorPacket256 down =
+ new VectorPacket256(Vector256.Zero, Vector256.Create(-1.0f), Vector256.Zero);
+ Vector256 OnePointFive = Vector256.Create(1.5f);
+ VectorPacket256 right = OnePointFive * VectorPacket256.CrossProduct(forward, down).Normalize();
+ VectorPacket256 up = OnePointFive * VectorPacket256.CrossProduct(forward, right).Normalize();
+
+ return new Camera(pos, forward, up, right);
+ }
+ }
+}
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/Color.cs b/src/benchmarks/micro/coreclr/PacketTracer/Color.cs
new file mode 100644
index 00000000000..4cc936e2faf
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/Color.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal struct Color
+ {
+ public float R { get; }
+ public float G { get; }
+ public float B { get; }
+
+ public static readonly Color Background = new Color(0, 0, 0);
+
+ public Color(float _r, float _g, float _b)
+ {
+ R = _r;
+ G = _g;
+ B = _b;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/ColorPacket.cs b/src/benchmarks/micro/coreclr/PacketTracer/ColorPacket.cs
new file mode 100644
index 00000000000..e6953e58def
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/ColorPacket.cs
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+using ColorPacket256 = HardwareIntrinsics.RayTracer.VectorPacket256;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal static class ColorPacket256Helper
+ {
+ private static readonly Vector256 One = Vector256.Create(1.0f);
+ private static readonly Vector256 Max = Vector256.Create(255.0f);
+
+ public static Int32RGBPacket256 ConvertToIntRGB(this VectorPacket256 colors)
+ {
+ var rsMask = Compare(colors.Xs, One, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ var gsMask = Compare(colors.Ys, One, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ var bsMask = Compare(colors.Zs, One, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+
+ var rs = BlendVariable(colors.Xs, One, rsMask);
+ var gs = BlendVariable(colors.Ys, One, gsMask);
+ var bs = BlendVariable(colors.Zs, One, bsMask);
+
+ var rsInt = ConvertToVector256Int32(Multiply(rs, Max));
+ var gsInt = ConvertToVector256Int32(Multiply(gs, Max));
+ var bsInt = ConvertToVector256Int32(Multiply(bs, Max));
+
+ return new Int32RGBPacket256(rsInt, gsInt, bsInt);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ColorPacket256 Times(ColorPacket256 left, ColorPacket256 right)
+ {
+ return new VectorPacket256(Multiply(left.Xs, right.Xs), Multiply(left.Ys, right.Ys),
+ Multiply(left.Zs, right.Zs));
+ }
+
+ public static readonly ColorPacket256 BackgroundColor = new ColorPacket256(Vector256.Zero);
+ public static readonly ColorPacket256 DefaultColor = new ColorPacket256(Vector256.Zero);
+ }
+
+ internal struct Int32RGBPacket256
+ {
+ public Vector256 Rs;
+ public Vector256 Gs;
+ public Vector256 Bs;
+
+ public Int32RGBPacket256(Vector256 rs, Vector256 gs, Vector256 bs)
+ {
+ Rs = rs;
+ Gs = gs;
+ Bs = bs;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/Intersections.cs b/src/benchmarks/micro/coreclr/PacketTracer/Intersections.cs
new file mode 100644
index 00000000000..6640e3d1631
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/Intersections.cs
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using static System.Runtime.Intrinsics.X86.Avx;
+using static System.Runtime.Intrinsics.X86.Avx2;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal struct Intersections
+ {
+ public Vector256 Distances;
+ public Vector256 ThingIndices;
+
+ public static readonly Vector256 NullDistance = Vector256.Create(float.MaxValue);
+ public static readonly Vector256 NullIndex = Vector256.Create(-1);
+
+ public Intersections(Vector256 dis, Vector256 things)
+ {
+ Distances = dis;
+ ThingIndices = things;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool AllNullIntersections()
+ {
+ return AllNullIntersections(Distances);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool AllNullIntersections(Vector256 dis)
+ {
+ var cmp = Compare(dis, NullDistance, FloatComparisonMode.EqualOrderedNonSignaling);
+ var zero = Vector256.Zero;
+ // efficiently generate an all-one mask vector by lower latency AVX2 ComapreEqual
+ var mask = Avx2.CompareEqual(zero, zero);
+ return TestC(cmp, mask.AsSingle());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/LightPacket.cs b/src/benchmarks/micro/coreclr/PacketTracer/LightPacket.cs
new file mode 100644
index 00000000000..f27de9ddb1e
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/LightPacket.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using ColorPacket256 = HardwareIntrinsics.RayTracer.VectorPacket256;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal class LightPacket256
+ {
+ public VectorPacket256 Positions;
+ public ColorPacket256 Colors;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public LightPacket256(Vector pos, Color col)
+ {
+ Positions = new VectorPacket256(pos.X, pos.Y, pos.Z);
+ Colors = new ColorPacket256(col.R, col.G, col.B);
+ }
+ }
+}
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/ObjectPacket.cs b/src/benchmarks/micro/coreclr/PacketTracer/ObjectPacket.cs
new file mode 100644
index 00000000000..d4c80fd7acf
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/ObjectPacket.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.Intrinsics;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal abstract class ObjectPacket256
+ {
+ public Surface Surface { get; }
+ public abstract Vector256 Intersect(RayPacket256 rayPacket256);
+ public abstract VectorPacket256 Normals(VectorPacket256 pos);
+
+ public ObjectPacket256(Surface surface)
+ {
+ Surface = surface;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/PacketTracer.cs b/src/benchmarks/micro/coreclr/PacketTracer/PacketTracer.cs
new file mode 100644
index 00000000000..f1ae3fc03ba
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/PacketTracer.cs
@@ -0,0 +1,265 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using static System.Runtime.Intrinsics.X86.Avx2;
+using static System.Runtime.Intrinsics.X86.Sse2;
+using System.Runtime.Intrinsics;
+
+using ColorPacket256 = HardwareIntrinsics.RayTracer.VectorPacket256;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal class Packet256Tracer
+ {
+ public int Width { get; }
+ public int Height { get; }
+ private static readonly int MaxDepth = 5;
+
+ private static readonly Vector256 SevenToZero = Vector256.Create(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f);
+
+ public Packet256Tracer(int width, int height)
+ {
+ if ((width % VectorPacket256.Packet256Size) != 0)
+ {
+ width += VectorPacket256.Packet256Size - (width % VectorPacket256.Packet256Size);
+ }
+
+ Width = width;
+ Height = height;
+ }
+
+ internal unsafe void RenderVectorized(Scene scene, int* rgb)
+ {
+ Camera camera = scene.Camera;
+ // Iterate y then x in order to preserve cache locality.
+ for (int y = 0; y < Height; y++)
+ {
+ int stride = y * Width;
+ for (int x = 0; x < Width; x += VectorPacket256.Packet256Size)
+ {
+ float fx = x;
+ Vector256 Xs = Add(Vector256.Create(fx), SevenToZero);
+ VectorPacket256 dirs = GetPoints(Xs, Vector256.Create((float) (y)), camera);
+ var rayPacket256 = new RayPacket256(camera.Pos, dirs);
+ var SoAcolors = TraceRay(rayPacket256, scene, depth: 0);
+
+ var AoS = SoAcolors.Transpose();
+ var intAoS = AoS.ConvertToIntRGB();
+
+ int* output = &rgb[(x + stride) * 3]; // Each pixel has 3 fields (RGB)
+ {
+ Store(output, intAoS.Rs);
+ Store(output + 8, intAoS.Gs);
+ Store(output + 16, intAoS.Bs);
+ }
+
+ }
+ }
+
+ }
+
+ private ColorPacket256 TraceRay(RayPacket256 rayPacket256, Scene scene, int depth)
+ {
+ var isect = MinIntersections(rayPacket256, scene);
+ if (isect.AllNullIntersections())
+ {
+ return ColorPacket256Helper.BackgroundColor;
+ }
+
+ var color = Shade(isect, rayPacket256, scene, depth);
+ var isNull = Compare(isect.Distances, Intersections.NullDistance,
+ FloatComparisonMode.EqualOrderedNonSignaling);
+ var backgroundColor = ColorPacket256Helper.BackgroundColor.Xs;
+ return new ColorPacket256(BlendVariable(color.Xs, backgroundColor, isNull),
+ BlendVariable(color.Ys, backgroundColor, isNull),
+ BlendVariable(color.Zs, backgroundColor, isNull));
+ }
+
+ private Vector256 TestRay(RayPacket256 rayPacket256, Scene scene)
+ {
+ var isect = MinIntersections(rayPacket256, scene);
+ if (isect.AllNullIntersections())
+ {
+ return Vector256.Zero;
+ }
+
+ var isNull = Compare(isect.Distances, Intersections.NullDistance,
+ FloatComparisonMode.EqualOrderedNonSignaling);
+ return BlendVariable(isect.Distances, Vector256.Zero, isNull);
+ }
+
+ private Intersections MinIntersections(RayPacket256 rayPacket256, Scene scene)
+ {
+ Intersections mins = new Intersections(Intersections.NullDistance, Intersections.NullIndex);
+ for (int i = 0; i < scene.Things.Length; i++)
+ {
+ Vector256 distance = scene.Things[i].Intersect(rayPacket256);
+
+ if (!Intersections.AllNullIntersections(distance))
+ {
+ var notNullMask = Compare(distance, Intersections.NullDistance,
+ FloatComparisonMode.NotEqualOrderedNonSignaling);
+ var nullMinMask = Compare(mins.Distances, Intersections.NullDistance,
+ FloatComparisonMode.EqualOrderedNonSignaling);
+
+ var lessMinMask = Compare(mins.Distances, distance,
+ FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ var minMask = And(notNullMask, Or(nullMinMask, lessMinMask));
+ var minDis = BlendVariable(mins.Distances, distance, minMask);
+ var minIndices = BlendVariable(mins.ThingIndices.AsSingle(),
+ Vector256.Create(i).AsSingle(),
+ minMask).AsInt32();
+ mins.Distances = minDis;
+ mins.ThingIndices = minIndices;
+ }
+ }
+
+ return mins;
+ }
+
+ private ColorPacket256 Shade(Intersections isect, RayPacket256 rays, Scene scene, int depth)
+ {
+
+ var ds = rays.Dirs;
+ var pos = isect.Distances * ds + rays.Starts;
+ var normals = scene.Normals(isect.ThingIndices, pos);
+ var reflectDirs =
+ ds - (Multiply(VectorPacket256.DotProduct(normals, ds), Vector256.Create(2.0f)) * normals);
+ var colors = GetNaturalColor(isect.ThingIndices, pos, normals, reflectDirs, scene);
+
+ if (depth >= MaxDepth)
+ {
+ return colors + new ColorPacket256(.5f, .5f, .5f);
+ }
+
+ return colors + GetReflectionColor(isect.ThingIndices, pos + (Vector256.Create(0.001f) * reflectDirs),
+ normals, reflectDirs, scene, depth);
+ }
+
+ private ColorPacket256 GetNaturalColor(Vector256 things, VectorPacket256 pos, VectorPacket256 norms,
+ VectorPacket256 rds, Scene scene)
+ {
+ var colors = ColorPacket256Helper.DefaultColor;
+ for (int i = 0; i < scene.Lights.Length; i++)
+ {
+ var lights = scene.Lights[i];
+ var zero = Vector256.Zero;
+ var colorPacket = lights.Colors;
+ var ldis = lights.Positions - pos;
+ var livec = ldis.Normalize();
+ var neatIsectDis = TestRay(new RayPacket256(pos, livec), scene);
+
+ // is in shadow?
+ var mask1 = Compare(neatIsectDis, ldis.Lengths, FloatComparisonMode.LessThanOrEqualOrderedNonSignaling);
+ var mask2 = Compare(neatIsectDis, zero, FloatComparisonMode.NotEqualOrderedNonSignaling);
+ var isInShadow = And(mask1, mask2);
+
+ Vector256 illum = VectorPacket256.DotProduct(livec, norms);
+ Vector256 illumGraterThanZero =
+ Compare(illum, zero, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ var tmpColor1 = illum * colorPacket;
+ var defaultRGB = zero;
+ Vector256 lcolorR = BlendVariable(defaultRGB, tmpColor1.Xs, illumGraterThanZero);
+ Vector256 lcolorG = BlendVariable(defaultRGB, tmpColor1.Ys, illumGraterThanZero);
+ Vector256 lcolorB = BlendVariable(defaultRGB, tmpColor1.Zs, illumGraterThanZero);
+ ColorPacket256 lcolor = new ColorPacket256(lcolorR, lcolorG, lcolorB);
+
+ Vector256 specular = VectorPacket256.DotProduct(livec, rds.Normalize());
+ Vector256 specularGraterThanZero =
+ Compare(specular, zero, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+
+ var difColor = new ColorPacket256(1, 1, 1);
+ var splColor = new ColorPacket256(1, 1, 1);
+ var roughness = Vector256.Create(1.0f);
+
+ for (int j = 0; j < scene.Things.Length; j++)
+ {
+ Vector256 thingMask = CompareEqual(things, Vector256.Create(j)).AsSingle();
+ Vector256 rgh = Vector256.Create(scene.Things[j].Surface.Roughness);
+ var dif = scene.Things[j].Surface.Diffuse(pos);
+ var spl = scene.Things[j].Surface.Specular;
+
+ roughness = BlendVariable(roughness, rgh, thingMask);
+
+ difColor.Xs = BlendVariable(difColor.Xs, dif.Xs, thingMask);
+ difColor.Ys = BlendVariable(difColor.Ys, dif.Ys, thingMask);
+ difColor.Zs = BlendVariable(difColor.Zs, dif.Zs, thingMask);
+
+ splColor.Xs = BlendVariable(splColor.Xs, spl.Xs, thingMask);
+ splColor.Ys = BlendVariable(splColor.Ys, spl.Ys, thingMask);
+ splColor.Zs = BlendVariable(splColor.Zs, spl.Zs, thingMask);
+ }
+
+ var tmpColor2 = VectorMath.Pow(specular, roughness) * colorPacket;
+ Vector256 scolorR = BlendVariable(defaultRGB, tmpColor2.Xs, specularGraterThanZero);
+ Vector256 scolorG = BlendVariable(defaultRGB, tmpColor2.Ys, specularGraterThanZero);
+ Vector256 scolorB = BlendVariable(defaultRGB, tmpColor2.Zs, specularGraterThanZero);
+ ColorPacket256 scolor = new ColorPacket256(scolorR, scolorG, scolorB);
+
+ var oldColor = colors;
+
+ colors = colors + ColorPacket256Helper.Times(difColor, lcolor) +
+ ColorPacket256Helper.Times(splColor, scolor);
+
+ colors = new ColorPacket256(BlendVariable(colors.Xs, oldColor.Xs, isInShadow),
+ BlendVariable(colors.Ys, oldColor.Ys, isInShadow),
+ BlendVariable(colors.Zs, oldColor.Zs, isInShadow));
+
+ }
+
+ return colors;
+ }
+
+ private ColorPacket256 GetReflectionColor(Vector256 things, VectorPacket256 pos, VectorPacket256 norms,
+ VectorPacket256 rds, Scene scene, int depth)
+ {
+ return scene.Reflect(things, pos) * TraceRay(new RayPacket256(pos, rds), scene, depth + 1);
+ }
+
+ private readonly static Vector256 ConstTwo = Vector256.Create(2.0f);
+
+ private VectorPacket256 GetPoints(Vector256 x, Vector256 y, Camera camera)
+ {
+ Vector256 widthVector = Vector256.Create((float) (Width));
+ Vector256 heightVector = Vector256.Create((float) (Height));
+
+ var widthRate1 = Divide(widthVector, ConstTwo);
+ var widthRate2 = Multiply(widthVector, ConstTwo);
+
+ var heightRate1 = Divide(heightVector, ConstTwo);
+ var heightRate2 = Multiply(heightVector, ConstTwo);
+
+ var recenteredX = Divide(Subtract(x, widthRate1), widthRate2);
+ var recenteredY = Subtract(Vector256.Zero, Divide(Subtract(y, heightRate1), heightRate2));
+
+ var result = camera.Forward + (recenteredX * camera.Right) + (recenteredY * camera.Up);
+
+ return result.Normalize();
+ }
+
+ internal readonly Scene DefaultScene = CreateDefaultScene();
+
+ private static Scene CreateDefaultScene()
+ {
+ ObjectPacket256[] things =
+ {
+ new SpherePacket256(new VectorPacket256(-0.5f, 1f, 1.5f), Vector256.Create(0.5f), Surfaces.MatteShiny),
+ new SpherePacket256(new VectorPacket256(0f, 1f, -0.25f), Vector256.Create(1f), Surfaces.Shiny),
+ new PlanePacket256((new VectorPacket256(0, 1, 0)), Vector256.Create(0f), Surfaces.CheckerBoard)
+ };
+
+ LightPacket256[] lights =
+ {
+ new LightPacket256(new Vector(-2f, 2.5f, 0f), new Color(.5f, .45f, .41f)),
+ new LightPacket256(new Vector(2, 4.5f, 2), new Color(.99f, .95f, .8f))
+ };
+
+ Camera camera = Camera.Create(new VectorPacket256(2.75f, 2f, 3.75f), new VectorPacket256(-0.6f, .5f, 0f));
+
+ return new Scene(things, lights, camera);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/PlanePacket.cs b/src/benchmarks/micro/coreclr/PacketTracer/PlanePacket.cs
new file mode 100644
index 00000000000..271fcce80f0
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/PlanePacket.cs
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal sealed class PlanePacket256 : ObjectPacket256
+ {
+ public VectorPacket256 Norms;
+ public Vector256 Offsets;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public PlanePacket256(VectorPacket256 norms, Vector256 offsets, Surface surface) : base(surface)
+ {
+ Norms = norms;
+ Offsets = offsets;
+ }
+
+ public override VectorPacket256 Normals(VectorPacket256 pos)
+ {
+ return Norms;
+ }
+
+ public override Vector256 Intersect(RayPacket256 rayPacket256)
+ {
+ var denom = VectorPacket256.DotProduct(Norms, rayPacket256.Dirs);
+ var dist = Divide(Add(VectorPacket256.DotProduct(Norms, rayPacket256.Starts), Offsets),
+ Subtract(Vector256.Zero, denom));
+ var gtMask = Compare(denom, Vector256.Zero, FloatComparisonMode.GreaterThanOrderedNonSignaling);
+ return BlendVariable(dist, Intersections.NullDistance, gtMask);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/RayPacket.cs b/src/benchmarks/micro/coreclr/PacketTracer/RayPacket.cs
new file mode 100644
index 00000000000..acfa7626030
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/RayPacket.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal class RayPacket256
+ {
+ public VectorPacket256 Starts;
+ public VectorPacket256 Dirs;
+
+ public RayPacket256(VectorPacket256 starts, VectorPacket256 dirs)
+ {
+ Starts = starts;
+ Dirs = dirs;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/Render.cs b/src/benchmarks/micro/coreclr/PacketTracer/Render.cs
new file mode 100644
index 00000000000..7a6d31e7c51
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/Render.cs
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Concurrent;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+using BenchmarkDotNet.Attributes;
+using MicroBenchmarks;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ [BenchmarkCategory(Categories.CoreCLR)]
+ public class SoA
+ {
+ private const int RunningTime = 1000;
+ private const int Width = 248;
+ private const int Height = 248;
+
+ private int[] rgbBuffer = new int[Width * 3 * Height]; // Each pixel has 3 fields (RGB)
+
+ [GlobalSetup]
+ public unsafe void Setup() => Render(); // run it once during the Setup to avoid https://github.com/dotnet/BenchmarkDotNet/issues/837s
+
+ [Benchmark]
+ public unsafe void Render()
+ {
+ if (!Avx2.IsSupported)
+ return;
+
+ // Create a ray tracer, and create a reference to "sphere2" that we are going to bounce
+ var packetTracer = new Packet256Tracer(Width, Height);
+ var scene = packetTracer.DefaultScene;
+ var sphere2 = (SpherePacket256)scene.Things[0]; // The first item is assumed to be our sphere
+ var baseY = sphere2.Radiuses;
+ sphere2.Centers.Ys = sphere2.Radiuses;
+
+ float dy2 = 0.8f * MathF.Abs(MathF.Sin((float) (1 * Math.PI / 3000)));
+ sphere2.Centers.Ys = Avx.Add(baseY, Vector256.Create(dy2));
+
+ fixed (int* ptr = rgbBuffer)
+ {
+ packetTracer.RenderVectorized(scene, ptr);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/Scene.cs b/src/benchmarks/micro/coreclr/PacketTracer/Scene.cs
new file mode 100644
index 00000000000..4aae44b86fb
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/Scene.cs
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Collections.Generic;
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using static System.Runtime.Intrinsics.X86.Avx2;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal class Scene
+ {
+ public ObjectPacket256[] Things;
+ public LightPacket256[] Lights;
+ public Camera Camera;
+
+ public Scene(ObjectPacket256[] things, LightPacket256[] lights, Camera camera)
+ {
+ Things = things;
+ Lights = lights;
+ Camera = camera;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256 Normals(Vector256 things, VectorPacket256 pos)
+ {
+ VectorPacket256 norms = new VectorPacket256(1, 1, 1);
+
+ for (int i = 0; i < Things.Length; i++)
+ {
+ Vector256 mask = CompareEqual(things, Vector256.Create(i)).AsSingle();
+ var n = Things[i].Normals(pos);
+ norms.Xs = BlendVariable(norms.Xs, n.Xs, mask);
+ norms.Ys = BlendVariable(norms.Ys, n.Ys, mask);
+ norms.Zs = BlendVariable(norms.Zs, n.Zs, mask);
+ }
+
+ return norms;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector256 Reflect(Vector256 things, VectorPacket256 pos)
+ {
+ Vector256 rfl = Vector256.Create(1.0f);
+ for (int i = 0; i < Things.Length; i++)
+ {
+ Vector256 mask = CompareEqual(things, Vector256.Create(i)).AsSingle();
+ rfl = BlendVariable(rfl, Things[i].Surface.Reflect(pos), mask);
+ }
+
+ return rfl;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/SpherePacket.cs b/src/benchmarks/micro/coreclr/PacketTracer/SpherePacket.cs
new file mode 100644
index 00000000000..0d43fca3629
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/SpherePacket.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal sealed class SpherePacket256 : ObjectPacket256
+ {
+ public VectorPacket256 Centers;
+ public Vector256 Radiuses;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public SpherePacket256(VectorPacket256 centers, Vector256 radiuses, Surface surface) : base(surface)
+ {
+ Centers = centers;
+ Radiuses = radiuses;
+ }
+
+ public override VectorPacket256 Normals(VectorPacket256 pos)
+ {
+ return (pos - Centers).Normalize();
+ }
+
+ public override Vector256 Intersect(RayPacket256 rayPacket256)
+ {
+ var eo = Centers - rayPacket256.Starts;
+ var v = VectorPacket256.DotProduct(eo, rayPacket256.Dirs);
+ var zero = Vector256.Zero;
+ var vLessZeroMask = Compare(v, zero, FloatComparisonMode.LessThanOrderedNonSignaling);
+ var discs = Subtract(Multiply(Radiuses, Radiuses),
+ Subtract(VectorPacket256.DotProduct(eo, eo), Multiply(v, v)));
+ var discLessZeroMask = Compare(discs, zero, FloatComparisonMode.LessThanOrderedNonSignaling);
+ var dists = BlendVariable(Subtract(v, Sqrt(discs)), zero, Or(vLessZeroMask, discLessZeroMask));
+ var isZero = Compare(dists, zero, FloatComparisonMode.EqualOrderedNonSignaling);
+ return BlendVariable(dists, Intersections.NullDistance, isZero);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/Surface.cs b/src/benchmarks/micro/coreclr/PacketTracer/Surface.cs
new file mode 100644
index 00000000000..1fdc2215946
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/Surface.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.Intrinsics;
+using System;
+using ColorPacket256 = HardwareIntrinsics.RayTracer.VectorPacket256;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal class Surface
+ {
+ public Func Diffuse;
+ public VectorPacket256 Specular;
+ public Func> Reflect;
+ public float Roughness;
+
+ public Surface(Func Diffuse,
+ VectorPacket256 Specular,
+ Func> Reflect,
+ float Roughness)
+ {
+ this.Diffuse = Diffuse;
+ this.Specular = Specular;
+ this.Reflect = Reflect;
+ this.Roughness = Roughness;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/Surfaces.cs b/src/benchmarks/micro/coreclr/PacketTracer/Surfaces.cs
new file mode 100644
index 00000000000..ad241abb534
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/Surfaces.cs
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+using static System.Runtime.Intrinsics.X86.Avx;
+using ColorPacket256 = HardwareIntrinsics.RayTracer.VectorPacket256;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal static class Surfaces
+ {
+ private static readonly ColorPacket256 White = new ColorPacket256(Vector256.Create(1.0f));
+
+ private static readonly ColorPacket256 Black = new ColorPacket256(0.02f, 0.0f, 0.14f);
+
+ // Only works with X-Z plane.
+ public static readonly Surface CheckerBoard =
+ new Surface(
+ delegate(VectorPacket256 pos)
+ {
+ var floored = ConvertToVector256Int32(Add(Floor(pos.Zs), Floor(pos.Xs)));
+ var modMask = Vector256.Create(1);
+ var evenMaskint = Avx2.And(floored, modMask);
+ var evenMask = Avx2.CompareEqual(evenMaskint, modMask);
+
+ var resultX = BlendVariable(Black.Xs, White.Xs, evenMask.AsSingle());
+ var resultY = BlendVariable(Black.Ys, White.Ys, evenMask.AsSingle());
+ var resultZ = BlendVariable(Black.Zs, White.Zs, evenMask.AsSingle());
+
+ return new ColorPacket256(resultX, resultY, resultZ);
+ },
+ new VectorPacket256(1f, 1f, 1f),
+ delegate(VectorPacket256 pos)
+ {
+ var floored = ConvertToVector256Int32(Add(Floor(pos.Zs), Floor(pos.Xs)));
+ var modMask = Vector256.Create(1);
+ var evenMaskUint = Avx2.And(floored, modMask);
+ var evenMask = Avx2.CompareEqual(evenMaskUint, modMask);
+
+ return BlendVariable(Vector256.Create(0.5f), Vector256.Create(0.1f), evenMask.AsSingle());
+ },
+ 150f);
+
+ public static readonly Surface Shiny =
+ new Surface(
+ delegate(VectorPacket256 pos) { return new VectorPacket256(1f, 1f, 1f); },
+ new VectorPacket256(.5f, .5f, .5f),
+ delegate(VectorPacket256 pos) { return Vector256.Create(0.7f); },
+ 250f);
+
+ public static readonly Surface MatteShiny =
+ new Surface(
+ delegate(VectorPacket256 pos) { return new VectorPacket256(1f, 1f, 1f); },
+ new VectorPacket256(.25f, .25f, .25f),
+ delegate(VectorPacket256 pos) { return Vector256.Create(0.7f); },
+ 250f);
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/Vector.cs b/src/benchmarks/micro/coreclr/PacketTracer/Vector.cs
new file mode 100644
index 00000000000..46e69a3c5ba
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/Vector.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal struct Vector
+ {
+ public float X { get; set; }
+ public float Y { get; set; }
+ public float Z { get; set; }
+
+ public Vector(float x, float y, float z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/VectorMath.cs b/src/benchmarks/micro/coreclr/PacketTracer/VectorMath.cs
new file mode 100644
index 00000000000..78af804bd96
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/VectorMath.cs
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using static System.Runtime.Intrinsics.X86.Avx;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ public static class VectorMath
+ {
+ static readonly Vector256 MaxValue = Vector256.Create(88.0f);
+ static readonly Vector256 MinValue = Vector256.Create(-88.0f);
+ static readonly Vector256 Log2 = Vector256.Create(1.44269502f);
+ static readonly Vector256 C1 = Vector256.Create(0.693359375f);
+ static readonly Vector256 C2 = Vector256.Create(-0.0002121944417f);
+ static readonly Vector256 P0 = Vector256.Create(0.0001987569121f);
+ static readonly Vector256 P1 = Vector256.Create(0.001398199936f);
+ static readonly Vector256 P2 = Vector256.Create(0.008333452046f);
+ static readonly Vector256 P3 = Vector256.Create(0.04166579619f);
+ static readonly Vector256 P4 = Vector256.Create(0.1666666567f);
+ static readonly Vector256 LogP0 = Vector256.Create(0.07037683576f);
+ static readonly Vector256 LogP1 = Vector256.Create(-0.1151461005f);
+ static readonly Vector256 LogP2 = Vector256.Create(0.1167699844f);
+ static readonly Vector256 LogP3 = Vector256.Create(-0.1242014095f);
+ static readonly Vector256 LogP4 = Vector256.Create(0.1424932331f);
+ static readonly Vector256 LogP5 = Vector256.Create(-0.1666805744f);
+ static readonly Vector256 LogP6 = Vector256.Create(0.2000071406f);
+ static readonly Vector256 LogP7 = Vector256.Create(-0.2499999404f);
+ static readonly Vector256 LogP8 = Vector256.Create(0.3333333135f);
+ static readonly Vector256 LogQ1 = Vector256.Create(-0.0002121944417f);
+ static readonly Vector256 LogQ2 = Vector256.Create(0.693359375f);
+ static readonly Vector256 Point5 = Vector256.Create(0.5f);
+ static readonly Vector256 Sqrthf = Vector256.Create(0.7071067691f);
+ static readonly Vector256 One = Vector256.Create(1.0f);
+ static readonly Vector256 Ox7 = Vector256.Create(127);
+ static readonly Vector256 MinNormPos = Vector256.Create(8388608);
+ static readonly Vector256 MantMask = Vector256.Create(-2139095041);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Pow(Vector256 left, Vector256 right)
+ {
+ return Exp(Multiply(right, Log(left)));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Exp(Vector256 value)
+ {
+ value = Min(value, MaxValue);
+ value = Max(value, MinValue);
+ Vector256 fx = Multiply(value, Log2);
+ fx = Floor(Add(fx, Point5));
+
+ Vector256 tmp = Multiply(fx, C1);
+ Vector256 z = Multiply(fx, C2);
+ Vector256 x = Subtract(value, tmp);
+ x = Subtract(x, z);
+ z = Multiply(x, x);
+ Vector256 y = P0;
+ y = Add(Multiply(y, x), P1);
+ y = Add(Multiply(y, x), P2);
+ y = Add(Multiply(y, x), P3);
+ y = Add(Multiply(y, x), P4);
+ y = Add(Multiply(y, x), Point5);
+ y = Add(Add(Multiply(y, z), x), One);
+
+ Vector256 pow2n = ConvertToVector256Int32(fx);
+ pow2n = Avx2.Add(pow2n, Ox7);
+ pow2n = Avx2.ShiftLeftLogical(pow2n, 23);
+
+ return Multiply(y, pow2n.AsSingle());
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 Log(Vector256 value)
+ {
+ Vector256 invalidMask = Compare(value, Vector256.Zero,
+ FloatComparisonMode.LessThanOrEqualOrderedNonSignaling);
+ Vector256 x = Max(value, MinNormPos.AsSingle());
+ Vector256 ei = Avx2.ShiftRightLogical(x.AsInt32(), 23);
+ x = Or(And(x, MantMask.AsSingle()), Point5);
+ ei = Avx2.Subtract(ei, Ox7);
+ Vector256 e = Add(ConvertToVector256Single(ei), One);
+ Vector256 mask = Compare(x, Sqrthf, FloatComparisonMode.LessThanOrderedNonSignaling);
+ Vector256 tmp = And(x, mask);
+ x = Subtract(x, One);
+ e = Subtract(e, And(One, mask));
+ x = Add(x, tmp);
+ Vector256 z = Multiply(x, x);
+ Vector256 y = LogP0;
+ y = Add(Multiply(y, x), LogP1);
+ y = Add(Multiply(y, x), LogP2);
+ y = Add(Multiply(y, x), LogP3);
+ y = Add(Multiply(y, x), LogP4);
+ y = Add(Multiply(y, x), LogP5);
+ y = Add(Multiply(y, x), LogP6);
+ y = Add(Multiply(y, x), LogP7);
+ y = Add(Multiply(y, x), LogP8);
+ y = Multiply(Multiply(y, x), z);
+ y = Add(y, Multiply(e, LogQ1));
+ y = Subtract(y, Multiply(z, Point5));
+ x = Add(Add(x, y), Multiply(e, LogQ2));
+ return Or(x, invalidMask);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/benchmarks/micro/coreclr/PacketTracer/VectorPacket.cs b/src/benchmarks/micro/coreclr/PacketTracer/VectorPacket.cs
new file mode 100644
index 00000000000..6ce607bc6d8
--- /dev/null
+++ b/src/benchmarks/micro/coreclr/PacketTracer/VectorPacket.cs
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using static System.Runtime.Intrinsics.X86.Avx;
+using static System.Runtime.Intrinsics.X86.Sse;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Intrinsics;
+using System.Runtime.CompilerServices;
+
+namespace HardwareIntrinsics.RayTracer
+{
+ internal struct VectorPacket256
+ {
+ public Vector256 Xs;
+ public Vector256 Ys;
+ public Vector256 Zs;
+
+ public Vector256 Lengths
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return Sqrt(DotProduct(this, this)); }
+ }
+
+
+ public readonly static int Packet256Size = 8;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256(Vector256 init)
+ {
+ Xs = init;
+ Ys = init;
+ Zs = init;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256(float xs, float ys, float zs)
+ {
+ Xs = Vector256.Create(xs);
+ Ys = Vector256.Create(ys);
+ Zs = Vector256.Create(zs);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256(Vector256 _Xs, Vector256 _ys, Vector256 _Zs)
+ {
+ Xs = _Xs;
+ Ys = _ys;
+ Zs = _Zs;
+ }
+
+ // Convert AoS vectors to SoA Packet256
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe VectorPacket256(float* vectors)
+ {
+ Vector256 m03 = LoadVector128(&vectors[0]).ToVector256(); // load lower halves
+ Vector256 m14 = LoadVector128(&vectors[4]).ToVector256();
+ Vector256 m25 = LoadVector128(&vectors[8]).ToVector256();
+ m03 = InsertVector128(m03, LoadVector128(&vectors[12]), 1); // load higher halves
+ m14 = InsertVector128(m14, LoadVector128(&vectors[16]), 1);
+ m25 = InsertVector128(m25, LoadVector128(&vectors[20]), 1);
+
+ var xy = Shuffle(m14, m25, 2 << 6 | 1 << 4 | 3 << 2 | 2);
+ var yz = Shuffle(m03, m14, 1 << 6 | 0 << 4 | 2 << 2 | 1);
+ var _Xs = Shuffle(m03, xy, 2 << 6 | 0 << 4 | 3 << 2 | 0);
+ var _ys = Shuffle(yz, xy, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+ var _Zs = Shuffle(yz, m25, 3 << 6 | 0 << 4 | 3 << 2 | 1);
+
+ Xs = _Xs;
+ Ys = _ys;
+ Zs = _Zs;
+ }
+
+ // Convert SoA VectorPacket256 to AoS
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256 Transpose()
+ {
+ var rxy = Shuffle(Xs, Ys, 2 << 6 | 0 << 4 | 2 << 2 | 0);
+ var ryz = Shuffle(Ys, Zs, 3 << 6 | 1 << 4 | 3 << 2 | 1);
+ var rzx = Shuffle(Zs, Xs, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+
+ var r03 = Shuffle(rxy, rzx, 2 << 6 | 0 << 4 | 2 << 2 | 0);
+ var r14 = Shuffle(ryz, rxy, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+ var r25 = Shuffle(rzx, ryz, 3 << 6 | 1 << 4 | 3 << 2 | 1);
+
+ var m0 = r03.GetLower();
+ var m1 = r14.GetLower();
+ var m2 = r25.GetLower();
+ var m3 = ExtractVector128(r03, 1);
+ var m4 = ExtractVector128(r14, 1);
+ var m5 = ExtractVector128(r25, 1);
+
+ var _Xs = Vector256.Create(m0, m1);
+ var _ys = Vector256.Create(m2, m3);
+ var _Zs = Vector256.Create(m4, m5);
+
+ return new VectorPacket256(_Xs, _ys, _Zs);
+ }
+
+ // Convert SoA VectorPacket256 to an incomplete AoS
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256 FastTranspose()
+ {
+ var rxy = Shuffle(Xs, Ys, 2 << 6 | 0 << 4 | 2 << 2 | 0);
+ var ryz = Shuffle(Ys, Zs, 3 << 6 | 1 << 4 | 3 << 2 | 1);
+ var rzx = Shuffle(Zs, Xs, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+
+ var r03 = Shuffle(rxy, rzx, 2 << 6 | 0 << 4 | 2 << 2 | 0);
+ var r14 = Shuffle(ryz, rxy, 3 << 6 | 1 << 4 | 2 << 2 | 0);
+ var r25 = Shuffle(rzx, ryz, 3 << 6 | 1 << 4 | 3 << 2 | 1);
+
+ return new VectorPacket256(r03, r14, r25);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 operator +(VectorPacket256 left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Add(left.Xs, right.Xs), Add(left.Ys, right.Ys), Add(left.Zs, right.Zs));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 operator -(VectorPacket256 left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Subtract(left.Xs, right.Xs), Subtract(left.Ys, right.Ys),
+ Subtract(left.Zs, right.Zs));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 operator /(VectorPacket256 left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Divide(left.Xs, right.Xs), Divide(left.Ys, right.Ys), Divide(left.Zs, right.Zs));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector256 DotProduct(VectorPacket256 left, VectorPacket256 right)
+ {
+ var x2 = Multiply(left.Xs, right.Xs);
+ var y2 = Multiply(left.Ys, right.Ys);
+ var z2 = Multiply(left.Zs, right.Zs);
+ return Add(Add(x2, y2), z2);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 CrossProduct(VectorPacket256 left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Subtract(Multiply(left.Ys, right.Zs), Multiply(left.Zs, right.Ys)),
+ Subtract(Multiply(left.Zs, right.Xs), Multiply(left.Xs, right.Zs)),
+ Subtract(Multiply(left.Xs, right.Ys), Multiply(left.Ys, right.Xs)));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VectorPacket256 operator *(Vector256 left, VectorPacket256 right)
+ {
+ return new VectorPacket256(Multiply(left, right.Xs), Multiply(left, right.Ys), Multiply(left, right.Zs));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public VectorPacket256 Normalize()
+ {
+ var length = this.Lengths;
+ return new VectorPacket256(Divide(Xs, length), Divide(Ys, length), Divide(Zs, length));
+ }
+ }
+}
\ No newline at end of file