Singularity/Library/PackageCache/com.unity.burst@1.8.4/Tests/Runtime/UnityBenchShared/SphereCulling.cs
2024-05-06 11:45:45 -07:00

543 lines
15 KiB
C#

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;
[assembly: InternalsVisibleTo("Burst.Benchmarks")]
namespace UnityBenchShared
{
internal struct Sphere
{
private float x, y, z, r;
public Sphere(float x, float y, float z, float r)
{
this.x = x;
this.y = y;
this.z = z;
this.r = r;
}
public bool Intersects(Sphere other)
{
float dx = x - other.x;
float dy = y - other.y;
float dz = z - other.z;
float rs = r + other.r;
return dx * dx + dy * dy + dz * dz < (rs * rs);
}
}
internal static class SphereCulling
{
public static int BenchCount = 128 * 1024 + 3;
}
internal interface IJob<T> : IJob
{
T Result { get; set; }
}
/// <summary>
/// Simple AOS with a Sphere struct using plain floats
/// </summary>
internal struct SphereCullingAOSJob : IJob<bool>, IDisposable
{
public Sphere Against;
[ReadOnly] public NativeArray<Sphere> Spheres;
[MarshalAs(UnmanagedType.U1)]
private bool result;
public bool Result
{
get => result;
set => result = value;
}
public void Execute()
{
bool result = false;
for (int i = 0; i < Spheres.Length; ++i)
{
result |= Spheres[i].Intersects(Against);
}
Result = result;
}
public struct Provider : IArgumentProvider
{
public object Value
{
get
{
int length = SphereCulling.BenchCount * 2;
var job = new SphereCullingAOSJob()
{
Spheres = new NativeArray<Sphere>(length, Allocator.Persistent),
Against = new Sphere(0, 0, 0, 1)
};
var random = new System.Random(0);
for (int i = 0; i < job.Spheres.Length; i++)
{
// Most don't intersects
var x = random.Next(100) + 3.0f;
if (i == job.Spheres.Length / 2)
{
// only this one
x = 0.5f;
}
job.Spheres[i] = new Sphere(x, x, x, 1.0f);
}
return job;
}
}
}
public void Dispose()
{
Spheres.Dispose();
}
}
/// <summary>
/// Simple AOS with a float4 for the struct and using
/// </summary>
internal struct SphereCullingFloat4AOSJob : IJob<bool>, IDisposable
{
public float4 Against;
[ReadOnly]
public NativeArray<float4> Spheres;
[MarshalAs(UnmanagedType.U1)]
private bool result;
public bool Result
{
get => result;
set => result = value;
}
public static bool Intersects(float4 value, float4 other)
{
float rs = value.w + other.w;
return math.dot(value.xyz, other.xyz) < (rs * rs);
}
public void Execute()
{
bool result = false;
for (int i = 0; i < Spheres.Length; ++i)
{
result |= Intersects(Spheres[i], Against);
}
Result = result;
}
public struct Provider : IArgumentProvider
{
public object Value
{
get
{
int length = SphereCulling.BenchCount;
var job = new SphereCullingFloat4AOSJob()
{
Spheres = new NativeArray<float4>(length, Allocator.Persistent),
Against = new float4(0, 0, 0, 1)
};
var random = new System.Random(0);
for (int i = 0; i < job.Spheres.Length; i++)
{
// Most don't intersects
var x = random.Next(100) + 3.0f;
if (i == job.Spheres.Length / 2)
{
// only this one
x = 0.5f;
}
job.Spheres[i] = new float4(x, x, x, 1.0f);
}
return job;
}
}
}
public void Dispose()
{
Spheres.Dispose();
}
}
/// <summary>
/// Simple SOA with 4 NativeArray for X,Y,Z,R
/// </summary>
internal struct SphereCullingSOAJob : IJob<bool>, IDisposable
{
[ReadOnly] public NativeArray<float> X;
[ReadOnly] public NativeArray<float> Y;
[ReadOnly] public NativeArray<float> Z;
[ReadOnly] public NativeArray<float> R;
public float4 Against;
[MarshalAs(UnmanagedType.U1)]
private bool result;
public bool Result
{
get => result;
set => result = value;
}
public void Execute()
{
bool result = false;
for (int i = 0; i < X.Length; ++i)
{
float dx = X[i] - Against.x;
float dy = Y[i] - Against.y;
float dz = Z[i] - Against.z;
float rs = R[i] + Against.w;
result |= dx * dx + dy * dy + dz * dz < (rs * rs);
}
Result = result;
}
public struct Provider : IArgumentProvider
{
public object Value
{
get
{
int length = SphereCulling.BenchCount * 2;
var job = new SphereCullingSOAJob()
{
X = new NativeArray<float>(length, Allocator.Persistent),
Y = new NativeArray<float>(length, Allocator.Persistent),
Z = new NativeArray<float>(length, Allocator.Persistent),
R = new NativeArray<float>(length, Allocator.Persistent),
Against = new float4(0, 0, 0, 1)
};
var random = new System.Random(0);
for (int i = 0; i < job.X.Length; i++)
{
// Most don't intersects
var x = random.Next(100) + 3.0f;
if (i == job.X.Length / 2)
{
// only this one
x = 0.5f;
}
job.X[i] = x;
job.Y[i] = x;
job.Z[i] = x;
job.R[i] = 1;
}
return job;
}
}
}
public void Dispose()
{
X.Dispose();
Y.Dispose();
Z.Dispose();
R.Dispose();
}
}
/// <summary>
/// SOA with chunks of x,y,z,r using `float4`
/// </summary>
internal struct SphereCullingChunkSOAJob : IJob<bool>, IDisposable
{
public struct Chunk
{
public float4 X;
public float4 Y;
public float4 Z;
public float4 R;
}
[ReadOnly] public NativeArray<Chunk> Chunks;
public float4 Against;
[MarshalAs(UnmanagedType.U1)]
private bool result;
public bool Result
{
get => result;
set => result = value;
}
public void Execute()
{
bool result = false;
for (int i = 0; i < Chunks.Length; ++i)
{
var chunk = Chunks[i];
for (int j = 0; j < 4; j++)
{
float dx = chunk.X[j] - Against.x;
float dy = chunk.Y[j] - Against.y;
float dz = chunk.Z[j] - Against.z;
float rs = chunk.R[j] + Against.w;
result |= dx * dx + dy * dy + dz * dz < (rs * rs);
}
}
Result = result;
}
public struct Provider : IArgumentProvider
{
public object Value
{
get
{
// Approximate a similar batch
int length = ((SphereCulling.BenchCount * 2) + 4) / 4;
var job = new SphereCullingChunkSOAJob
{
Chunks = new NativeArray<SphereCullingChunkSOAJob.Chunk>(length, Allocator.Persistent),
Against = new float4(0, 0, 0, 1)
};
var random = new System.Random(0);
for (int i = 0; i < job.Chunks.Length; i++)
{
var chunk = job.Chunks[i];
for (int j = 0; j < 4; j++)
{
// Most don't intersects
var x = random.Next(100) + 3.0f;
if (i == job.Chunks.Length / 2)
{
// only this one
x = 0.5f;
}
chunk.X[j] = x;
chunk.Y[j] = x;
chunk.Z[j] = x;
chunk.R[j] = 1;
}
job.Chunks[i] = chunk;
}
return job;
}
}
}
public void Dispose()
{
Chunks.Dispose();
}
}
/// <summary>
/// SOA with chunks of x,y,z,r using `fixed float x[4]`
/// </summary>
internal struct SphereCullingChunkFixedSOAJob : IJob<bool>, IDisposable
{
public unsafe struct Chunk
{
public fixed float X[4];
public fixed float Y[4];
public fixed float Z[4];
public fixed float R[4];
}
[ReadOnly] public NativeArray<Chunk> Chunks;
public float4 Against;
[MarshalAs(UnmanagedType.U1)]
private bool result;
public bool Result
{
get => result;
set => result = value;
}
public unsafe void Execute()
{
bool result = false;
for (int i = 0; i < Chunks.Length; ++i)
{
var chunk = Chunks[i];
for (int j = 0; j < 4; j++)
{
float dx = chunk.X[j] - Against.x;
float dy = chunk.Y[j] - Against.y;
float dz = chunk.Z[j] - Against.z;
float rs = chunk.R[j] + Against.w;
result |= dx * dx + dy * dy + dz * dz < (rs * rs);
}
}
Result = result;
}
public struct Provider : IArgumentProvider
{
public unsafe object Value
{
get
{
// Approximate a similar batch
int length = ((SphereCulling.BenchCount) + 4) / 2;
var job = new SphereCullingChunkFixedSOAJob
{
Chunks = new NativeArray<Chunk>(length, Allocator.Persistent),
Against = new float4(0, 0, 0, 1)
};
var random = new System.Random(0);
for (int i = 0; i < job.Chunks.Length; i++)
{
var chunk = job.Chunks[i];
for (int j = 0; j < 4; j++)
{
// Most don't intersects
var x = random.Next(100) + 3.0f;
if (i == job.Chunks.Length / 2)
{
// only this one
x = 0.5f;
}
chunk.X[j] = x;
chunk.Y[j] = x;
chunk.Z[j] = x;
chunk.R[j] = 1;
}
job.Chunks[i] = chunk;
}
return job;
}
}
}
public void Dispose()
{
Chunks.Dispose();
}
}
/// <summary>
/// </summary>
internal struct SphereCullingChunkSOAManualJob : IJob<bool>, IDisposable
{
public struct Chunk
{
public float4 X;
public float4 Y;
public float4 Z;
public float4 R;
}
[ReadOnly] public NativeArray<Chunk> Chunks;
public float4 Against;
[MarshalAs(UnmanagedType.U1)]
private bool result;
public bool Result
{
get => result;
set => result = value;
}
public void Execute()
{
bool4 result = false;
for (int i = 0; i < Chunks.Length; ++i)
{
var chunk = Chunks[i];
float4 dx = chunk.X - Against.x;
float4 dy = chunk.Y - Against.y;
float4 dz = chunk.Z - Against.z;
float4 rs = chunk.R + Against.w;
result |= dx * dx + dy * dy + dz * dz < (rs * rs);
}
Result = math.any(result);
}
public struct Provider : IArgumentProvider
{
public object Value
{
get
{
// Approximate a similar batch
int length = (SphereCulling.BenchCount + 4) / 4;
var job = new SphereCullingChunkSOAManualJob
{
Chunks = new NativeArray<SphereCullingChunkSOAManualJob.Chunk>(length, Allocator.Persistent),
Against = new float4(0, 0, 0, 1)
};
var random = new System.Random(0);
for (int i = 0; i < job.Chunks.Length; i++)
{
var chunk = job.Chunks[i];
for (int j = 0; j < 4; j++)
{
// Most don't intersects
var x = random.Next(100) + 3.0f;
if (i == job.Chunks.Length / 2)
{
// only this one
x = 0.5f;
}
chunk.X[j] = x;
chunk.Y[j] = x;
chunk.Z[j] = x;
chunk.R[j] = 1;
}
job.Chunks[i] = chunk;
}
return job;
}
}
}
public void Dispose()
{
Chunks.Dispose();
}
}
}