Skip to content

Instantly share code, notes, and snippets.

@runevision
Last active September 12, 2024 10:26
Show Gist options
  • Save runevision/e25310fbdd88a90a4a6a67fff69cb16d to your computer and use it in GitHub Desktop.
Save runevision/e25310fbdd88a90a4a6a67fff69cb16d to your computer and use it in GitHub Desktop.
Using Unity Burst directly on methods without jobs - unofficial example code
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine;
// This example code demonstrates using Unity Burst directly on a static method without jobs.
// Unity NativeArrays can't be used directly in Unity Burst methods (only in Burst jobs),
// so we have to pass pointers to arrays instead.
//
// This PointerArray wrapper can be created from a NativeArray via simple implicit assignment:
//
// NativeArray<float> floatNativeArray = new NativeArray<float>(1000, Allocator.Persistent);
// PointerArray<float> floatPointerArray = floatNativeArray;
//
// The PointerArray can then be used like an array itself, including getting the Length.
public unsafe struct PointerArray<T> where T : unmanaged {
public readonly T* Array;
public readonly int Length;
public T this[uint index] {
get { return Array[index]; }
set { Array[index] = value; }
}
public T this[int index] {
get { return Array[index]; }
set { Array[index] = value; }
}
public PointerArray(T* Array, int Length) {
this.Array = Array;
this.Length = Length;
}
public static implicit operator PointerArray<T>(NativeArray<T> a) {
return new PointerArray<T>((T*)a.GetUnsafePtr(), a.Length);
}
}
[BurstCompile]
public class BurstMethodTester : MonoBehaviour {
enum Mode { NonBurstMethod, NonBurstJob, BurstMethod, BurstJob }
void Start() {
Execute(Mode.NonBurstMethod);
Execute(Mode.NonBurstJob);
Execute(Mode.BurstMethod);
Execute(Mode.BurstJob);
}
void Execute(Mode mode) {
var input = new NativeArray<float>(10000000, Allocator.Persistent);
var output = new NativeArray<float>(1, Allocator.Persistent);
for (int i = 0; i < input.Length; i++)
input[i] = 1.0f * i;
var stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
if (mode == Mode.NonBurstMethod) {
PointerArray<float> outputArr = output;
ExecuteNonBurstMethod(input, ref outputArr);
}
else if (mode == Mode.NonBurstJob) {
var job = new MyNonBurstStruct { Input = input, Output = output };
job.Schedule().Complete();
}
else if (mode == Mode.BurstMethod) {
PointerArray<float> outputArr = output;
ExecuteBurstMethod(input, ref outputArr);
}
else if (mode == Mode.BurstJob) {
var job = new MyBurstStruct { Input = input, Output = output };
job.Schedule().Complete();
}
stopwatch.Stop();
Debug.Log("Took " + stopwatch.ElapsedMilliseconds + "ms with mode " + mode
+ "\nThe result of the sum is: " + output[0]);
input.Dispose();
output.Dispose();
}
[BurstCompile]
public static void ExecuteBurstMethod(in PointerArray<float> Input, ref PointerArray<float> Output) {
float result = 0.0f;
for (int i = 0; i < Input.Length; i++) {
result += Input[i];
}
Output[0] = result;
}
public static void ExecuteNonBurstMethod(in PointerArray<float> Input, ref PointerArray<float> Output) {
float result = 0.0f;
for (int i = 0; i < Input.Length; i++) {
result += Input[i];
}
Output[0] = result;
}
[BurstCompile(CompileSynchronously = true)]
private struct MyBurstStruct : IJob {
[ReadOnly]
public NativeArray<float> Input;
[WriteOnly]
public NativeArray<float> Output;
public void Execute() {
float result = 0.0f;
for (int i = 0; i < Input.Length; i++) {
result += Input[i];
}
Output[0] = result;
}
}
private struct MyNonBurstStruct : IJob {
[ReadOnly]
public NativeArray<float> Input;
[WriteOnly]
public NativeArray<float> Output;
public void Execute() {
float result = 0.0f;
for (int i = 0; i < Input.Length; i++) {
result += Input[i];
}
Output[0] = result;
}
}
}
@runevision
Copy link
Author

BurstMethod and BurstJob perform around 10x of NonBurstMethod and NonBurstJob. Times can vary a lot from one run to the next.

Job vs Method makes no difference here as there's only one job. But the Job version was the original code from Unity's documentation. I adapted the Method version from that and kept the Job version too so I could check if the Method version got the same speed boost or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment