Skip to content

Instantly share code, notes, and snippets.

@qwe321qwe321qwe321
Last active June 6, 2021 07:03
Show Gist options
  • Save qwe321qwe321qwe321/6bf01b73dc6e9752ba8f00f24cdc741d to your computer and use it in GitHub Desktop.
Save qwe321qwe321qwe321/6bf01b73dc6e9752ba8f00f24cdc741d to your computer and use it in GitHub Desktop.
Test Unity Burst Compiler performance in different scenarios. (Burst: 1.5.3, Unity: 2019.4.17f1)
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using MathRandom = Unity.Mathematics.Random;
using UnityEngine;
using System;
using System.Runtime.InteropServices;
using UnityEngine.Profiling;
namespace PeDev {
public class BurstCompileTest : MonoBehaviour {
public int count = 1000000;
public void OnGUI() {
if (GUILayout.Button("Test1")) {
Profiler.BeginSample("TestPerformance1: Different ways to set values");
TestPerformance1.Execute(count);
Profiler.EndSample();
}
if (GUILayout.Button("Test2+3+4")) {
Profiler.BeginSample("TestPerformance2: math+float432 computation");
TestPerformance2.Execute(count);
Profiler.EndSample();
Profiler.BeginSample("TestPerformance3: Mathf+Vector432 computation");
TestPerformance3.Execute(count);
Profiler.EndSample();
Profiler.BeginSample("TestPerformance4: Does burst compile external static method?");
TestPerformance4.Execute(count);
Profiler.EndSample();
}
if (GUILayout.Button("Test5")) {
Profiler.BeginSample("TestPerformance5: Vector2 vs float2");
TestPerformance5.Execute(count);
Profiler.EndSample();
}
if (GUILayout.Button("Test6")) {
Profiler.BeginSample("TestPerformance6: Does [ReadOnly]/[WriteOnly] matter?");
TestPerformance6.Execute(count);
Profiler.EndSample();
}
}
private static class TestPerformance1 {
public static void Execute(int count) {
NativeArray<MyStruct> myStructs = new NativeArray<MyStruct>(count, Allocator.TempJob);
NativeArray<MyStruct> randomValues = new NativeArray<MyStruct>(count, Allocator.TempJob);
JobHandle handle;
Randomize(randomValues, count);
Profiler.BeginSample("Set Values");
for (int i = 0; i < myStructs.Length; i++) {
MyStruct.SetValue(ref myStructs.GetRef(i), randomValues[i]);
}
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("Set Values by Job");
handle = new SetValueJob() {
array = myStructs,
values = randomValues
}.Schedule();
handle.Complete();
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("Set Values by FunctionPointer.Invoke");
unsafe {
var setValue = BurstCompiler.CompileFunctionPointer((MyStruct.SetValueDelegate)MyStruct.SetValue).Invoke;
for (int i = 0; i < count; i++) {
setValue.Invoke((MyStruct*)myStructs.GetPointer(i), (MyStruct*)randomValues.GetPointer(i));
}
}
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("Set Values by FunctionPointer+Job");
unsafe {
var setValue = BurstCompiler.CompileFunctionPointer((MyStruct.SetValueDelegate)MyStruct.SetValue);
new SetValueFunctionPtrJob() {
array = myStructs,
values = randomValues,
setValue = setValue
}.Run();
}
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("Set Values by Job.Run()");
new SetValueJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("Set Values by Job.Execute()");
new SetValueJob() {
array = myStructs,
values = randomValues
}.Execute();
Profiler.EndSample();
myStructs.Dispose();
randomValues.Dispose();
}
private static void Randomize(NativeArray<MyStruct> values, int count) {
JobHandle handle = new RandomJob() {
array = values,
seedBase = (uint)UnityEngine.Random.Range(0, int.MaxValue),
}.Schedule(count, 64);
handle.Complete();
}
[BurstCompile]
struct RandomJob : IJobParallelFor {
public NativeArray<MyStruct> array;
public uint seedBase;
public void Execute(int index) {
array[index] = MyStruct.Random(seedBase + (uint)index);
}
}
[BurstCompile]
struct SetValueJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
MyStruct.SetValue(ref array.GetRef(i), values[i]);
}
}
}
[BurstCompile]
struct SetValueFunctionPtrJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public FunctionPointer<MyStruct.SetValueDelegate> setValue;
public unsafe void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
setValue.Invoke((MyStruct*)array.GetPointer(i), (MyStruct*)values.GetPointer(i));
}
}
}
[BurstCompile]
struct MyStruct {
public float4 f4;
public float3 f3;
public float2 f2;
public float f1;
public bool b1;
public static void SetValue(ref MyStruct myStruct, MyStruct value) {
myStruct.f4 = value.f4;
myStruct.f3 = value.f3;
myStruct.f2 = value.f2;
myStruct.f1 = value.f1;
myStruct.b1 = value.b1;
}
public static void SetValue(ref MyStruct myStruct, float4 f4, float3 f3, float2 f2, float f1, bool b1) {
myStruct.f4 = f4;
myStruct.f3 = f3;
myStruct.f2 = f2;
myStruct.f1 = f1;
myStruct.b1 = b1;
}
public unsafe delegate void SetValueDelegate(MyStruct* myStruct, MyStruct* value);
[BurstCompile]
public unsafe static void SetValue(MyStruct* myStruct, MyStruct* value) {
myStruct->f4 = value->f4;
myStruct->f3 = value->f3;
myStruct->f2 = value->f2;
myStruct->f1 = value->f1;
myStruct->b1 = value->b1;
}
public static MyStruct Random(uint seed) {
MathRandom random = new MathRandom(seed);
return new MyStruct() {
f4 = random.NextFloat4(),
f3 = random.NextFloat3(),
f2 = random.NextFloat2(),
f1 = random.NextFloat(),
b1 = random.NextBool(),
};
}
}
}
private static class TestPerformance2 {
public static void Execute(int count) {
NativeArray<MyStruct> myStructs = new NativeArray<MyStruct>(count, Allocator.TempJob);
NativeArray<MyStruct> randomValues = new NativeArray<MyStruct>(count, Allocator.TempJob);
Randomize(randomValues, count);
Profiler.BeginSample("AssignJob.Run()");
new AssignJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("SetValuesJob.Run()");
new SetValuesJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("DotJob.Run()");
new DotJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Profiler.BeginSample("LengthJob.Run()");
new LengthJob() {
array = myStructs,
}.Run();
Profiler.EndSample();
Profiler.BeginSample("NormalizeJob.Run()");
new NormalizeJob() {
array = myStructs,
}.Run();
Profiler.EndSample();
myStructs.Dispose();
randomValues.Dispose();
}
private static void Randomize(NativeArray<MyStruct> values, int count) {
JobHandle handle = new RandomJob() {
array = values,
seedBase = (uint)UnityEngine.Random.Range(0, int.MaxValue),
}.Schedule(count, 64);
handle.Complete();
}
[BurstCompile]
struct RandomJob : IJobParallelFor {
public NativeArray<MyStruct> array;
public uint seedBase;
public void Execute(int index) {
array.GetRef(index) = MyStruct.Random(seedBase + (uint)index);
}
}
[BurstCompile]
struct AssignJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = values[i];
}
}
}
[BurstCompile]
struct SetValuesJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
MyStruct.SetValues(ref array.GetRef(i), values[i]);
}
}
}
[BurstCompile]
struct DotJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
MyStruct.Dot(ref array.GetRef(i), values[i]);
}
}
}
[BurstCompile]
struct LengthJob : IJob {
public NativeArray<MyStruct> array;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
MyStruct.Length(ref array.GetRef(i));
}
}
}
[BurstCompile]
struct NormalizeJob : IJob {
public NativeArray<MyStruct> array;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
MyStruct.Normalize(ref array.GetRef(i));
}
}
}
struct MyStruct {
public float4 f4;
public float3 f3;
public float2 f2;
public float result;
public static void SetValues(ref MyStruct myStruct, MyStruct value) {
myStruct.f4 = value.f4;
myStruct.f3 = value.f3;
myStruct.f2 = value.f2;
}
public static void Dot(ref MyStruct myStruct, MyStruct value) {
float dot4 = math.dot(myStruct.f4, value.f4);
float dot3 = math.dot(myStruct.f3, value.f3);
float dot2 = math.dot(myStruct.f2, value.f2);
myStruct.result = dot4 + dot3 + dot2;
}
public static void Length(ref MyStruct myStruct) {
float length4 = math.length(myStruct.f4);
float length3 = math.length(myStruct.f3);
float length2 = math.length(myStruct.f2);
myStruct.result = length4 + length3 + length2;
}
public static void Normalize(ref MyStruct myStruct) {
myStruct.f4 = math.normalize(myStruct.f4);
myStruct.f3 = math.normalize(myStruct.f3);
myStruct.f2 = math.normalize(myStruct.f2);
}
public static MyStruct Random(uint seed) {
MathRandom random = new MathRandom(seed);
return new MyStruct() {
f4 = random.NextFloat4(),
f3 = random.NextFloat3(),
f2 = random.NextFloat2()
};
}
}
}
private static class TestPerformance3 {
public static void Execute(int count) {
NativeArray<MyStruct> myStructs = new NativeArray<MyStruct>(count, Allocator.TempJob);
NativeArray<MyStruct> randomValues = new NativeArray<MyStruct>(count, Allocator.TempJob);
Randomize(randomValues, count);
Profiler.BeginSample("AssignJob.Run()");
new AssignJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("SetValuesJob.Run()");
new SetValuesJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("DotJob.Run()");
new DotJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Profiler.BeginSample("LengthJob.Run()");
new LengthJob() {
array = myStructs,
}.Run();
Profiler.EndSample();
Profiler.BeginSample("NormalizeJob.Run()");
new NormalizeJob() {
array = myStructs,
}.Run();
Profiler.EndSample();
myStructs.Dispose();
randomValues.Dispose();
}
private static void Randomize(NativeArray<MyStruct> values, int count) {
JobHandle handle = new RandomJob() {
array = values,
seedBase = (uint)UnityEngine.Random.Range(0, int.MaxValue),
}.Schedule(count, 64);
handle.Complete();
}
[BurstCompile]
struct RandomJob : IJobParallelFor {
public NativeArray<MyStruct> array;
public uint seedBase;
public void Execute(int index) {
array.GetRef(index) = MyStruct.Random(seedBase + (uint)index);
}
}
[BurstCompile]
struct AssignJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = values[i];
}
}
}
[BurstCompile]
struct SetValuesJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
MyStruct.SetValues(ref array.GetRef(i), values[i]);
}
}
}
[BurstCompile]
struct DotJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
MyStruct.Dot(ref array.GetRef(i), values[i]);
}
}
}
[BurstCompile]
struct LengthJob : IJob {
public NativeArray<MyStruct> array;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
MyStruct.Length(ref array.GetRef(i));
}
}
}
[BurstCompile]
struct NormalizeJob : IJob {
public NativeArray<MyStruct> array;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
MyStruct.Normalize(ref array.GetRef(i));
}
}
}
struct MyStruct {
public Vector4 f4;
public Vector3 f3;
public Vector2 f2;
public float result;
public static void SetValues(ref MyStruct myStruct, MyStruct value) {
myStruct.f4 = value.f4;
myStruct.f3 = value.f3;
myStruct.f2 = value.f2;
}
public static void Dot(ref MyStruct myStruct, MyStruct value) {
float dot4 = Vector4.Dot(myStruct.f4, value.f4);
float dot3 = Vector3.Dot(myStruct.f3, value.f3);
float dot2 = Vector2.Dot(myStruct.f2, value.f2);
myStruct.result = dot4 + dot3 + dot2;
}
public static void Length(ref MyStruct myStruct) {
float length4 = Vector4.Magnitude(myStruct.f4);
float length3 = Vector3.Magnitude(myStruct.f3);
float length2 = myStruct.f2.magnitude;
myStruct.result = length4 + length3 + length2;
}
public static void Normalize(ref MyStruct myStruct) {
myStruct.f4 = Vector4.Normalize(myStruct.f4);
myStruct.f3 = Vector3.Normalize(myStruct.f3);
myStruct.f2 = myStruct.f2.normalized;
}
public static MyStruct Random(uint seed) {
MathRandom random = new MathRandom(seed);
return new MyStruct() {
f4 = random.NextFloat4(),
f3 = random.NextFloat3(),
f2 = random.NextFloat2()
};
}
}
}
private static class TestPerformance4 {
public static void Execute(int count) {
NativeArray<MyStruct> myStructs = new NativeArray<MyStruct>(count, Allocator.TempJob);
NativeArray<MyStruct> randomValues = new NativeArray<MyStruct>(count, Allocator.TempJob);
Randomize(randomValues, count);
Profiler.BeginSample("AssignJob.Run()");
new AssignJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("SetValuesJob.Run()");
new SetValuesJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Randomize(randomValues, count);
Profiler.BeginSample("DotJob.Run()");
new DotJob() {
array = myStructs,
values = randomValues
}.Run();
Profiler.EndSample();
Profiler.BeginSample("LengthJob.Run()");
new LengthJob() {
array = myStructs,
}.Run();
Profiler.EndSample();
Profiler.BeginSample("NormalizeJob.Run()");
new NormalizeJob() {
array = myStructs,
}.Run();
Profiler.EndSample();
myStructs.Dispose();
randomValues.Dispose();
}
private static void Randomize(NativeArray<MyStruct> values, int count) {
JobHandle handle = new RandomJob() {
array = values,
seedBase = (uint)UnityEngine.Random.Range(0, int.MaxValue),
}.Schedule(count, 64);
handle.Complete();
}
[BurstCompile]
struct RandomJob : IJobParallelFor {
public NativeArray<MyStruct> array;
public uint seedBase;
public void Execute(int index) {
array.GetRef(index) = MyStruct.Random(seedBase + (uint)index);
}
}
[BurstCompile]
struct AssignJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = values[i];
}
}
}
[BurstCompile]
struct SetValuesJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
ref var myStruct = ref array.GetRef(i);
var value = values[i];
myStruct.f4 = value.f4;
myStruct.f3 = value.f3;
myStruct.f2 = value.f2;
}
}
}
[BurstCompile]
struct DotJob : IJob {
public NativeArray<MyStruct> array;
public NativeArray<MyStruct> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
ref var myStruct = ref array.GetRef(i);
var value = values[i];
float dot4 = math.dot(myStruct.f4, value.f4);
float dot3 = math.dot(myStruct.f3, value.f3);
float dot2 = math.dot(myStruct.f2, value.f2);
myStruct.result = dot4 + dot3 + dot2;
}
}
}
[BurstCompile]
struct LengthJob : IJob {
public NativeArray<MyStruct> array;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
ref var myStruct = ref array.GetRef(i);
float length4 = math.length(myStruct.f4);
float length3 = math.length(myStruct.f3);
float length2 = math.length(myStruct.f2);
myStruct.result = length4 + length3 + length2;
}
}
}
[BurstCompile]
struct NormalizeJob : IJob {
public NativeArray<MyStruct> array;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
ref var myStruct = ref array.GetRef(i);
myStruct.f4 = math.normalize(myStruct.f4);
myStruct.f3 = math.normalize(myStruct.f3);
myStruct.f2 = math.normalize(myStruct.f2);
}
}
}
struct MyStruct {
public float4 f4;
public float3 f3;
public float2 f2;
public float result;
public static MyStruct Random(uint seed) {
MathRandom random = new MathRandom(seed);
return new MyStruct() {
f4 = random.NextFloat4(),
f3 = random.NextFloat3(),
f2 = random.NextFloat2()
};
}
}
}
private static class TestPerformance5 {
public static void Execute(int count) {
NativeArray<Vector2> vector2s = new NativeArray<Vector2>(count, Allocator.TempJob);
NativeArray<float2> float2s = new NativeArray<float2>(count, Allocator.TempJob);
NativeArray<Vector2> randomValues = new NativeArray<Vector2>(count, Allocator.TempJob);
NativeArray<float> result = new NativeArray<float>(count, Allocator.TempJob);
Randomize(randomValues, count);
Profiler.BeginSample("AssignTofloat2Job");
new AssignTofloat2Job() {
array = float2s,
values = randomValues
}.Run();
Profiler.EndSample();
Profiler.BeginSample("AssignToVector2Job");
new AssignToVector2Job() {
array = vector2s,
values = randomValues
}.Run();
Profiler.EndSample();
Profiler.BeginSample("Dotfloat2Job");
new Dotfloat2Job() {
array = float2s,
result = result
}.Run();
Profiler.EndSample();
Profiler.BeginSample("DotVector2Job");
new DotVector2Job() {
array = vector2s,
result = result
}.Run();
Profiler.EndSample();
Profiler.BeginSample("Lengthfloat2Job");
new Lengthfloat2Job() {
array = float2s,
result = result
}.Run();
Profiler.EndSample();
Profiler.BeginSample("LengthVector2Job");
new LengthVector2Job() {
array = vector2s,
result = result
}.Run();
Profiler.EndSample();
Profiler.BeginSample("Normalizefloat2Job");
new Normalizefloat2Job() {
array = float2s,
}.Run();
Profiler.EndSample();
Profiler.BeginSample("NormalizeVecotr2ByFloat2Job");
new NormalizeVecotr2ByFloat2Job() {
array = vector2s,
}.Run();
Profiler.EndSample();
Profiler.BeginSample("AssignToVector2Job Execute");
new AssignToVector2Job() {
array = vector2s,
values = randomValues
}.Execute();
Profiler.EndSample();
Profiler.BeginSample("NormalizeVector2Job");
new NormalizeVector2Job() {
array = vector2s,
}.Run();
Profiler.EndSample();
Profiler.BeginSample("AssignTofloat2Job Execute");
new AssignTofloat2Job() {
array = float2s,
values = randomValues
}.Execute();
Profiler.EndSample();
vector2s.Dispose();
float2s.Dispose();
randomValues.Dispose();
result.Dispose();
}
private static void Randomize(NativeArray<Vector2> values, int count) {
JobHandle handle = new RandomJob() {
array = values,
seedBase = (uint)UnityEngine.Random.Range(0, int.MaxValue),
}.Schedule(count, 64);
handle.Complete();
}
[BurstCompile]
struct RandomJob : IJobParallelFor {
public NativeArray<Vector2> array;
public uint seedBase;
public void Execute(int index) {
MathRandom random = new MathRandom(seedBase + (uint)index);
array.GetRef(index) = random.NextFloat2();
}
}
[BurstCompile]
struct AssignToVector2Job : IJob {
public NativeArray<Vector2> array;
public NativeArray<Vector2> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = values[i];
}
}
}
[BurstCompile]
struct AssignTofloat2Job : IJob {
public NativeArray<float2> array;
public NativeArray<Vector2> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = values[i];
}
}
}
[BurstCompile]
struct LengthVector2Job : IJob {
public NativeArray<Vector2> array;
public NativeArray<float> result;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
result[i] = array[i].magnitude;
}
}
}
[BurstCompile]
struct DotVector2Job : IJob {
public NativeArray<Vector2> array;
public NativeArray<float> result;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
result[i] = Vector2.Dot(array[i], array[i]);
}
}
}
[BurstCompile]
struct Dotfloat2Job : IJob {
public NativeArray<float2> array;
public NativeArray<float> result;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
result[i] = math.dot(array[i], array[i]);
}
}
}
[BurstCompile]
struct Lengthfloat2Job : IJob {
public NativeArray<float2> array;
public NativeArray<float> result;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
result[i] = math.length(array[i]);
}
}
}
[BurstCompile]
struct NormalizeVector2Job : IJob {
public NativeArray<Vector2> array;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = array[i].normalized;
}
}
}
[BurstCompile]
struct NormalizeVecotr2ByFloat2Job : IJob {
public NativeArray<Vector2> array;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
ref float2 value = ref UnsafeEx.Reinterpret<Vector2, float2>(ref array.GetRef(i));
value = math.normalize(value);
}
}
}
[BurstCompile]
struct Normalizefloat2Job : IJob {
public NativeArray<float2> array;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = math.normalize(array[i]);
}
}
}
}
private static class TestPerformance6 {
public static void Execute(int count) {
NativeArray<float4> float4s = new NativeArray<float4>(count, Allocator.TempJob);
NativeArray<float4> randomValues = new NativeArray<float4>(count, Allocator.TempJob);
Randomize(randomValues, count);
Clear(float4s, count);
Profiler.BeginSample(nameof(AssignWithReadWriteOnlyJob));
new AssignWithReadWriteOnlyJob() {
array = float4s,
values = randomValues
}.Run();
Profiler.EndSample();
Clear(float4s, count);
Profiler.BeginSample(nameof(AssignWithReadOnlyJob));
new AssignWithReadOnlyJob() {
array = float4s,
values = randomValues
}.Run();
Profiler.EndSample();
Clear(float4s, count);
Profiler.BeginSample(nameof(AssignWithWriteOnlyJob));
new AssignWithWriteOnlyJob() {
array = float4s,
values = randomValues
}.Run();
Profiler.EndSample();
Clear(float4s, count);
Profiler.BeginSample(nameof(AssignWithNothingJob));
new AssignWithNothingJob() {
array = float4s,
values = randomValues
}.Run();
Profiler.EndSample();
float4s.Dispose();
randomValues.Dispose();
}
private static void Clear(NativeArray<float4> values, int count) {
JobHandle handle = new ClearJob() {
array = values,
}.Schedule(count, 64);
handle.Complete();
}
private static void Randomize(NativeArray<float4> values, int count) {
JobHandle handle = new RandomJob() {
array = values,
seedBase = (uint)UnityEngine.Random.Range(0, int.MaxValue),
}.Schedule(count, 64);
handle.Complete();
}
[BurstCompile]
struct RandomJob : IJobParallelFor {
public NativeArray<float4> array;
public uint seedBase;
public void Execute(int index) {
MathRandom random = new MathRandom(seedBase + (uint)index);
array.GetRef(index) = random.NextFloat4();
}
}
[BurstCompile]
struct ClearJob : IJobParallelFor {
public NativeArray<float4> array;
public void Execute(int index) {
array[index] = float4.zero;
}
}
[BurstCompile]
struct AssignWithNothingJob : IJob {
public NativeArray<float4> array;
public NativeArray<float4> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = values[i];
}
}
}
[BurstCompile]
struct AssignWithReadOnlyJob : IJob {
public NativeArray<float4> array;
[ReadOnly]
public NativeArray<float4> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = values[i];
}
}
}
[BurstCompile]
struct AssignWithWriteOnlyJob : IJob {
[WriteOnly]
public NativeArray<float4> array;
public NativeArray<float4> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = values[i];
}
}
}
[BurstCompile]
struct AssignWithReadWriteOnlyJob : IJob {
[WriteOnly]
public NativeArray<float4> array;
[ReadOnly]
public NativeArray<float4> values;
public void Execute() {
int count = array.Length;
for (int i = 0; i < count; i++) {
array[i] = values[i];
}
}
}
}
}
}
using System;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
namespace PeDev {
public static class NativeArrayExtensions {
public static ref T GetRef<T>(this NativeArray<T> array, int index)
where T : struct {
// You might want to validate the index first, as the unsafe method won't do that.
if (index < 0 || index >= array.Length) {
throw new ArgumentOutOfRangeException(nameof(index));
}
unsafe {
return ref UnsafeUtilityEx.ArrayElementAsRef<T>(array.GetUnsafePtr(), index);
}
}
public unsafe static void* GetPointer<T>(this NativeArray<T> array, int index)
where T : struct {
// You might want to validate the index first, as the unsafe method won't do that.
if (index < 0 || index >= array.Length)
throw new ArgumentOutOfRangeException(nameof(index));
return (byte*)array.GetUnsafePtr() + index * UnsafeUtility.SizeOf<T>();
}
public static void CopyTo<T>(this NativeArray<T> array, T[] dst, int length)
where T : struct {
NativeArray<T>.Copy(array, dst, length);
}
}
public static class UnsafeEx {
/// <summary>
/// Cast a type to another type in memory level (pointer casting)
/// </summary>
public static ref TDst Reinterpret<TSrc, TDst>(ref TSrc value)
where TSrc : unmanaged
where TDst : unmanaged {
if (UnsafeUtility.SizeOf<TSrc>() != UnsafeUtility.SizeOf<TDst>()) {
throw new InvalidOperationException($"Types {typeof(TSrc)} and {typeof(TDst)} are different sizes - direct reinterpretation is not possible. If this is what you intended, use Reinterpret(<type size>)");
}
unsafe {
fixed (TSrc* ptr = &value) {
return ref System.Runtime.CompilerServices.Unsafe.AsRef<TDst>(ptr);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment