543 lines
15 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|