Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
Burst Compiler
https://docs.unity3d.com/Packages/com.unity.burst@1.8/manual/
Admin
Burst is an LLVM-based compiler that translates a high-performance subset of C# into
...
Tokens:
58,455
Snippets:
429
Trust Score:
10
Update:
3 weeks ago
Context
Chat
Benchmark
74.78
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### X86 assembly for the C# example Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-skiplocalsinit.html The generated X86 assembly for the C# example. The line 'movabs rax, offset burst.memset.inline.X64_SSE4.i32@@32' indicates a memset call to zero out the stack allocation. ```asm push rbp .seh_pushreg rbp push rsi .seh_pushreg rsi push rdi .seh_pushreg rdi mov rbp, rsp .seh_setframe rbp, 0 .seh_endprologue mov edi, ecx lea r8d, [4*rdi] lea rax, [r8 + 15] and rax, -16 movabs r11, offset __chkstk call r11 sub rsp, rax mov rsi, rsp sub rsp, 32 movabs rax, offset burst.memset.inline.X64_SSE4.i32@@32 mov rcx, rsi xor edx, edx xor r9d, r9d call rax add rsp, 32 test edi, edi jle .LBB0_7 mov eax, edi cmp edi, 8 jae .LBB0_3 xor ecx, ecx jmp .LBB0_6 .LBB0_3: mov ecx, eax and ecx, -8 movabs rdx, offset __xmm@00000003000000020000000100000000 movdqa xmm0, xmmword ptr [rdx] mov rdx, rsi add rdx, 16 movabs rdi, offset __xmm@00000004000000040000000400000004 movdqa xmm1, xmmword ptr [rdi] movabs rdi, offset __xmm@00000008000000080000000800000008 movdqa xmm2, xmmword ptr [rdi] mov rdi, rcx .p2align 4, 0x90 .LBB0_4: movdqa xmm3, xmm0 paddd xmm3, xmm1 movdqu xmmword ptr [rdx - 16], xmm0 movdqu xmmword ptr [rdx], xmm3 paddd xmm0, xmm2 add rdx, 32 add rdi, -8 jne .LBB0_4 cmp rcx, rax je .LBB0_7 .p2align 4, 0x90 .LBB0_6: mov dword ptr [rsi + 4*rcx], ecx inc rcx cmp rax, rcx jne .LBB0_6 .LBB0_7: sub rsp, 32 movabs rax, offset "DoSomethingWithLUT" mov rcx, rsi call rax nop mov rsp, rbp pop rdi pop rsi pop rbp ret ``` -------------------------------- ### C# example using Loop.ExpectVectorized Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-loop-vectorization.html This example shows the original Bar method with the Loop.ExpectVectorized intrinsic added. It is used to express the assumption that the loop should be vectorized, and Burst will validate this at compile-time. ```csharp [MethodImpl(MethodImplOptions.NoInlining)] private static unsafe void Bar([NoAlias] int* a, [NoAlias] int* b, int count) { for (var i = 0; i < count; i++) { Unity.Burst.CompilerServices.Loop.ExpectVectorized(); a[i] += b[i]; } } ``` -------------------------------- ### Logging using string.Format Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-string-support.html Logs a formatted string using string.Format with an integer argument. This is the direct equivalent of the interpolation example. ```csharp int value = 256; Debug.Log(string.Format("This is an integer value {0}", value)); ``` -------------------------------- ### Job-based alternative to function pointers in Burst Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-function-pointers.html Shows the recommended approach for best performance: using a job instead of a function pointer. The job processes data with full aliasing knowledge, allowing Burst to optimize broadly. This runs 1.26x faster than the batched function pointer example and 1.93x faster than the non-batched example, and is simpler code. ```csharp [BurstCompile] struct MyJob : IJobParallelFor { [ReadOnly] public NativeArray<float> Input; [WriteOnly] public NativeArray<float> Output; public unsafe void Execute(int index) { Output[i] = math.sqrt(Input[i]); } } ``` -------------------------------- ### C# example of stackalloc with initialization Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-skiplocalsinit.html Shows a method that allocates a stack array and initializes it in a loop. The assembly output includes a memset call because Burst doesn't know the array is fully initialized. ```csharp static unsafe int DoSomethingWithLUT(int* data); static unsafe int DoSomething(int size) { int* data = stackalloc int[size]; // Initialize every field of data to be an incrementing set of values. for (int i = 0; i < size; i++) { data[i] = i; } // Use the data elsewhere. return DoSomethingWithLUT(data); } ``` -------------------------------- ### Nested type namespacing example Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/debugging-profiling-tools.html Shows how nested types are namespaced in C/C++ style. For example, SubSpot is referred to as Pillow::Spot::SubSpot when casting a pointer in a debugger watch window. ```csharp namespace Pillow { public struct Spot { public struct SubSpot { public int a; public int b; } public int a; public int b; public SubSpot sub; } ``` -------------------------------- ### Bump Allocator with NoAlias Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/aliasing-noalias.html The same bump allocator example updated with the [return: NoAlias] attribute. ```csharp [MethodImpl(MethodImplOptions.NoInlining)] [return: NoAlias] unsafe int* BumpAlloc(int* alloca) { int location = alloca[0]++; return alloca + location; } unsafe int Func() { int* alloca = stackalloc int[128]; // Store our size at the start of the alloca. alloca[0] = 1; int* ptr1 = BumpAlloc(alloca); int* ptr2 = BumpAlloc(alloca); *ptr1 = 42; *ptr2 = 13; return *ptr1; } ``` -------------------------------- ### C# example that produces a compile-time error Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-loop-vectorization.html This example shows a loop with a branch that prevents vectorization, but uses Loop.ExpectVectorized. Burst emits a compile-time error because the loop is not vectorized as expected. ```csharp [MethodImpl(MethodImplOptions.NoInlining)] private static unsafe void Bar([NoAlias] int* a, [NoAlias] int* b, int count) { for (var i = 0; i < count; i++) { Unity.Burst.CompilerServices.Loop.ExpectVectorized(); if (a[i] > b[i]) { break; } a[i] += b[i]; } } ``` -------------------------------- ### Build and copy mod DLLs with a menu button (ScriptBatch) Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/modding-support.html Adds a menu item 'Modding/Build X64 Mod (Example)' that builds a Standalone Player for Windows x64, then copies the managed DLL and the lib_burst_generated.dll into a user-chosen Mod folder. Assumes Windows and that the managed assembly is named 'TestMod_Managed'. Logs warnings if the destination DLLs are in use. ```csharp using UnityEditor; using System.IO; using UnityEngine; public class ScriptBatch { [MenuItem("Modding/Build X64 Mod (Example)")] public static void BuildGame() { string modName = "TestMod"; string projectFolder = Path.Combine(Application.dataPath, ".."); string buildFolder = Path.Combine(projectFolder, "PluginTemp"); // Get filename. string path = EditorUtility.SaveFolderPanel("Choose Final Mod Location", "", ""); FileUtil.DeleteFileOrDirectory(buildFolder); Directory.CreateDirectory(buildFolder); // Build player. var report = BuildPipeline.BuildPlayer(new[] { "Assets/Scenes/SampleScene.unity" }, Path.Combine(buildFolder, $"{modName}.exe"), BuildTarget.StandaloneWindows64, BuildOptions.Development); if (report.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded) { // Copy Managed library var managedDest = Path.Combine(path, $"{modName}_Managed.dll"); var managedSrc = Path.Combine(buildFolder, $"{modName}_Data/Managed/{modName}_Managed.dll"); FileUtil.DeleteFileOrDirectory(managedDest); if (!File.Exists(managedDest)) // Managed side not unloaded FileUtil.CopyFileOrDirectory(managedSrc, managedDest); else Debug.LogWarning($"Couldn't update managed dll, {managedDest} is it currently in use?"); // Copy Burst library var burstedDest = Path.Combine(path, $"{modName}_win_x86_64.dll"); var burstedSrc = Path.Combine(buildFolder, $"{modName}_Data/Plugins/x86_64/lib_burst_generated.dll"); FileUtil.DeleteFileOrDirectory(burstedDest); if (!File.Exists(burstedDest)) FileUtil.CopyFileOrDirectory(burstedSrc, burstedDest); else Debug.LogWarning($"Couldn't update bursted dll, {burstedDest} is it currently in use?"); } } } ``` -------------------------------- ### Compile a static method with [BurstCompile] Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/getting-started.html Apply [BurstCompile] to both the static class and the static method to enable Burst compilation. The example defines a utility class with a method that performs a multiply-add operation on float4 vectors. ```csharp using Unity.Burst; using Unity.Collections; using Unity.Jobs; using UnityEngine; [BurstCompile] public static class MyBurstUtilityClass { [BurstCompile] public static void BurstCompiled_MultiplyAdd(in float4 mula, in float4 mulb, in float4 add, out float4 result) { result = mula * mulb + add; } } ``` -------------------------------- ### Configure Burst compilation with [BurstCompile] Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/compilation-burstcompile.html Use this attribute to set the floating precision and float mode for Burst compilation. The example sets FloatPrecision.Medium and FloatMode.Fast. ```csharp [BurstCompile(FloatPrecision.Medium, FloatMode.Fast)] ``` -------------------------------- ### Create Unity Profiler markers in Burst code with ProfilerMarker Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/debugging-profiling-tools.html Creates Unity Profiler markers from Burst-compiled code by calling new ProfilerMarker("MarkerName"). The example uses a static marker with Auto() and a local marker with Begin()/End() to profile a loop. Requires the [BurstCompile] attribute and CompileSynchronously = true for synchronous compilation. ```csharp [BurstCompile] private static class ProfilerMarkerWrapper { private static readonly ProfilerMarker StaticMarker = new ProfilerMarker("TestStaticBurst"); [BurstCompile(CompileSynchronously = true)] public static int CreateAndUseProfilerMarker(int start) { using (StaticMarker.Auto()) { var p = new ProfilerMarker("TestBurst"); p.Begin(); var result = 0; for (var i = start; i < start + 100000; i++) { result += i; } p.End(); return result; } } } ``` -------------------------------- ### Compile a job with Burst using [BurstCompile] Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/getting-started.html Apply [BurstCompile] to the job struct to enable Burst compilation. The example creates a job that sums the elements of a NativeArray<float> and stores the result in a single-element output array. Use this pattern when you need to compile a job with Burst for better performance. ```csharp using Unity.Burst; using Unity.Collections; using Unity.Jobs; using UnityEngine; public class MyBurst2Behavior : MonoBehaviour { void Start() { var input = new NativeArray<float>(10, Allocator.Persistent); var output = new NativeArray<float>(1, Allocator.Persistent); for (int i = 0; i < input.Length; i++) input[i] = 1.0f * i; var job = new MyJob { Input = input, Output = output }; job.Schedule().Complete(); Debug.Log("The result of the sum is: " + output[0]); input.Dispose(); output.Dispose(); } // Using BurstCompile to compile a Job with Burst [BurstCompile] private struct MyJob : 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; } } } ``` -------------------------------- ### Assembly output of the non-vectorized loop Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-loop-vectorization.html This is the assembly output for the previous C# example, showing the scalar loop with a single integer addition per iteration. It is provided to illustrate the performance issue. ```assembly .LBB1_3: mov r9d, dword ptr [rcx + 4*r10] mov eax, dword ptr [rdx + 4*r10] cmp r9d, eax jg .LBB1_4 add eax, r9d mov dword ptr [rcx + 4*r10], eax inc r10 cmp r8, r10 jne .LBB1_3 ``` -------------------------------- ### C# example of a loop that breaks auto-vectorization Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-loop-vectorization.html This example shows a loop with a branch that prevents auto-vectorization, resulting in scalar code. It is used to illustrate a situation where the loop vectorization assumptions might be needed. ```csharp [MethodImpl(MethodImplOptions.NoInlining)] private static unsafe void Bar([NoAlias] int* a, [NoAlias] int* b, int count) { for (var i = 0; i < count; i++) { if (a[i] > b[i]) { break; } a[i] += b[i]; } } ``` -------------------------------- ### Logging with a string literal Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-string-support.html Logs a string literal using Debug.Log. This is a basic example of string usage in Burst. ```csharp Debug.Log("This a string literal"); ``` -------------------------------- ### Using FixedString128 for string arguments Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-string-support.html Shows how to pass a string to a method using FixedString128 instead of a managed string. The example creates an interpolated string with an integer value and passes it to a custom logging method. ```csharp int value = 256; FixedString128 text = $"This is an integer value {value} used with FixedString128"; MyCustomLog(text); // ... // String can be passed as an argument to a method using a FixedString, // but not using directly a managed `string`: public static void MyCustomLog(in FixedString128 log) { Debug.Log(text); } ``` -------------------------------- ### Assembly Output for Bump Allocator with NoAlias Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/aliasing-noalias.html The assembly generated by Burst for the BumpAlloc example with the [return: NoAlias] attribute, showing optimized register usage. ```assembly push rsi push rdi push rbx sub rsp, 544 lea rcx, [rsp + 36] movabs rax, offset memset mov r8d, 508 xor edx, edx call rax mov dword ptr [rsp + 32], 1 movabs rbx, offset "BumpAlloc(int* alloca)" lea rsi, [rsp + 32] mov rcx, rsi call rbx mov rdi, rax mov rcx, rsi call rbx mov dword ptr [rdi], 42 mov dword ptr [rax], 13 mov eax, 42 add rsp, 544 pop rbx pop rdi pop rsi ret ``` -------------------------------- ### Interlocked alignment example Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-system-support.html Shows a struct with explicit layout where field b is not naturally aligned, causing undefined behavior when used with Interlocked.Read. The example is used to illustrate the alignment requirement for atomic operations. ```csharp [StructLayout(LayoutKind.Explicit)] struct Foo { [FieldOffset(0)] public long a; [FieldOffset(5)] public long b; public long AtomicReadAndAdd() { return Interlocked.Read(ref a) + Interlocked.Read(ref b); } } ``` -------------------------------- ### Optimal batched function pointer example in Burst Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-function-pointers.html Shows an improved function pointer usage where the function pointer processes a batch of data, allowing Burst to vectorize the call and reduce per-item overhead. The job becomes IJobParallelForBatch and passes a count to the function pointer, resulting in a 1.53x performance gain over non-batched function pointers. ```csharp [BurstCompile] public class MyFunctionPointers { public unsafe delegate void MyFunctionPointerDelegate(int count, float* input, float* output); [BurstCompile] public static unsafe void MyFunctionPointer(int count, float* input, float* output) { for (int i = 0; i < count; i++) { output[i] = math.sqrt(input[i]); } } } [BurstCompile] struct MyJob : IJobParallelForBatch { public FunctionPointer<MyFunctionPointers.MyFunctionPointerDelegate> FunctionPointer; [ReadOnly] public NativeArray<float> Input; [WriteOnly] public NativeArray<float> Output; public unsafe void Execute(int index, int count) { var inputPtr = (float*)Input.GetUnsafeReadOnlyPtr() + index; var outputPtr = (float*)Output.GetUnsafePtr() + index; FunctionPointer.Invoke(count, inputPtr, outputPtr); } } ``` -------------------------------- ### PluginManager modding manager example Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/modding-support.html Scans the 'Mods' folder, loads managed and Burst-compiled DLLs for each mod, and invokes their interface methods. Requires domain reload to unload managed assemblies and automatically unloads Burst DLLs on exiting Play mode; the modsEnabled Boolean allows disabling the system for Editor testing. ```C# using System; using System.Collections.Generic; using System.IO; using System.Reflection; using UnityEngine; using Unity.Burst; public class PluginManager : MonoBehaviour { public bool modsEnabled; public GameObject objectForPlugins; List<PluginModule> plugins; void Start() { plugins = new List<PluginModule>(); // If mods are disabled, early out - this allows us to disable mods, enter Play Mode, exit Play Mode //and be sure that the managed assemblies have been unloaded (assuming DomainReload occurs) if (!modsEnabled) return; var folder = Path.GetFullPath(Path.Combine(Application.dataPath, "..", "Mods")); if (Directory.Exists(folder)) { var mods = Directory.GetDirectories(folder); foreach (var mod in mods) { var modName = Path.GetFileName(mod); var monoAssembly = Path.Combine(mod, $"{modName}_managed.dll"); if (File.Exists(monoAssembly)) { var managedPlugin = Assembly.LoadFile(monoAssembly); var pluginModule = managedPlugin.GetType("MyPluginModule"); var plugin = Activator.CreateInstance(pluginModule) as PluginModule; plugins.Add(plugin); } var burstedAssembly = Path.Combine(mod, $"{modName}_win_x86_64.dll"); // Burst dll (assuming windows 64bit) if (File.Exists(burstedAssembly)) { BurstRuntime.LoadAdditionalLibrary(burstedAssembly); } } } foreach (var plugin in plugins) { plugin.Startup(objectForPlugins); } } // Update is called once per frame void Update() { foreach (var plugin in plugins) { plugin.Update(objectForPlugins); } } } ``` -------------------------------- ### BC1371: Example that triggers the warning Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/compilation-warnings.html Shows the original code that triggers BC1371 when the local variable `myValue` is optimized away in release mode, causing the `BurstCompiledCode` argument to be discarded along with the `[BurstDiscard]` method. ```csharp [BurstDiscard] static void DoSomeManagedStuff(int x) { // Only run when Burst compilation is disabled } // A function that computes some result which we need to pass to managed code int BurstCompiledCode(int x,int y) { return y+2*x; } [BurstCompile] void BurstedMethod() { var myValue = BurstCompiledCode(1,3); DoSomeManagedStuff(myValue); } ``` -------------------------------- ### Scalar loop example for Burst vectorization Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-loop-vectorization.html Shows a scalar loop that Burst vectorizes. The Bar method adds elements of b to a in a loop, and Foo allocates two arrays and calls Bar. The [NoAlias] attributes and [MethodImpl(MethodImplOptions.NoInlining)] are used to help Burst generate vectorized code. ```csharp [MethodImpl(MethodImplOptions.NoInlining)] private static unsafe void Bar([NoAlias] int* a, [NoAlias] int* b, int count) { for (var i = 0; i < count; i++) { a[i] += b[i]; } } public static unsafe void Foo(int count) { var a = stackalloc int[count]; var b = stackalloc int[count]; Bar(a, b, count); } ``` -------------------------------- ### CopyJob with Input and Output arrays Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/aliasing.html A Burst-compiled IJob that copies data from an input NativeArray to an output NativeArray. The loop iterates over the input length and assigns each element to the output. This example is used to illustrate memory aliasing scenarios. ```csharp [BurstCompile] private struct CopyJob : IJob { [ReadOnly] public NativeArray<float> Input; [WriteOnly] public NativeArray<float> Output; public void Execute() { for (int i = 0; i < Input.Length; i++) { Output[i] = Input[i]; } } } ``` -------------------------------- ### Bump Allocator without NoAlias Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/aliasing-noalias.html A bump allocator example demonstrating how Burst handles pointer returns without the NoAlias attribute. ```csharp // Only ever returns a unique address into the stackalloc'ed memory. // We've made this no-inline because Burst will always try and inline // small functions like these, which would defeat the purpose of this // example [MethodImpl(MethodImplOptions.NoInlining)] unsafe int* BumpAlloc(int* alloca) { int location = alloca[0]++; return alloca + location; } unsafe int Func() { int* alloca = stackalloc int[128]; // Store our size at the start of the alloca. alloca[0] = 1; int* ptr1 = BumpAlloc(alloca); int* ptr2 = BumpAlloc(alloca); *ptr1 = 42; *ptr2 = 13; return *ptr1; } ``` -------------------------------- ### C#: Using [SkipLocalsInit] to skip stack initialization Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-skiplocalsinit.html Apply [SkipLocalsInit] to a method to tell Burst that stack allocations don't need to be zero-initialized. Only use this attribute if you won't encounter undefined behavior. The example initializes each stack allocated field before use. ```C# using Unity.Burst.CompilerServices; static unsafe int DoSomethingWithLUT(int* data); [SkipLocalsInit] static unsafe int DoSomething(int size) { int* data = stackalloc int[size]; // Initialize every field of data to be an incrementing set of values. for (int i = 0; i < size; i++) { data[i] = i; } // Use the data elsewhere. return DoSomethingWithLUT(data); } ``` -------------------------------- ### Hint.Likely intrinsic example Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-hint.html Use this intrinsic to tell Burst that a Boolean condition is likely to be true, so it can focus optimization on the branch that is most likely to be executed. The code inside the likely branch is optimized with that assumption, while the else branch is kept out of the optimizer's way. ```csharp if (Unity.Burst.CompilerServices.Hint.Likely(b)) { // Any code in here will be optimized by Burst with the assumption that we'll probably get here! } else { // Whereas the code in here will be kept out of the way of the optimizer. } ``` -------------------------------- ### Hint.Unlikely intrinsic example Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-hint.html Use this intrinsic to tell Burst that a Boolean condition is unlikely to be true, so it can optimize against it. The code in the unlikely branch is kept out of the optimizer's way, while the else branch is optimized with the assumption that it will be reached. ```csharp if (Unity.Burst.CompilerServices.Hint.Unlikely(b)) { // Whereas the code in here will be kept out of the way of the optimizer. } else { // Any code in here will be optimized by Burst with the assumption that we'll probably get here! } ``` -------------------------------- ### Container struct with Length field Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/optimization-assumerange.html A simple container struct with a public int Length field, used as a starting point for the following example that constrains Length to be non-negative. ```csharp struct MyContainer { public int Length; // Some other data... } ``` -------------------------------- ### CircularList struct example Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/aliasing-noalias.html An example of a struct containing a pointer to itself, which is a case where Burst's default assumptions about aliasing might not hold. ```csharp unsafe struct CircularList { public CircularList* next; public CircularList() { // The 'empty' list just points to itself. next = this; } } ``` -------------------------------- ### Using generic jobs with concrete types Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/compilation-generic-jobs.html Shows how to schedule direct and nested generic jobs with fully resolved generic arguments (int and float). Burst detects these at Player build time. ```csharp // Direct Generic Job var myJob = new MyGenericJob<int>(); myJob.Schedule(); // Nested Generic Job var myJobSystem = new MyGenericSystem<float>(); myJobSystem.Run(); ``` -------------------------------- ### BurstCompile OptimizeFor Field Example Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/building-aot-settings.html Use the OptimizeFor field in a BurstCompile attribute to set the optimization mode for a specific job, overriding the global default. The example shows a job struct with OptimizeFor.FastCompilation. ```csharp [BurstCompile(OptimizeFor = OptimizeFor.FastCompilation)] public struct MyJob : IJob { // ... } ``` -------------------------------- ### String format arguments and specifiers Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-string-support.html Demonstrates supported string format specifiers in Burst: padding left/right, hexadecimal uppercase/lowercase, and decimal with leading zeros. Each line shows the expected output in a comment. ```csharp int value = 256; // Padding left: "This value ` 256` Debug.Log($"This value `{value,5}`"); // Padding right: "This value `256 ` Debug.Log($"This value `{value,-5}`"); // Hexadecimal uppercase: "This value `00FF` Debug.Log($"This value `{value:X4}`"); // Hexadecimal lowercase: "This value `00ff` Debug.Log($"This value `{value:x4}`"); // Decimal with leading-zero: "This value `0256` Debug.Log($"This value `{value:D4}`"); ``` -------------------------------- ### Example of aliasing in a function Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/aliasing-noalias.html A function where Burst must reload a value because it cannot determine if the parameters alias. ```csharp int Foo(ref int a, ref int b) { b = 13; a = 42; return b; } ``` -------------------------------- ### Assembly Output for Bump Allocator without NoAlias Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/aliasing-noalias.html The assembly generated by Burst for the BumpAlloc example without the NoAlias attribute. ```assembly push rsi push rdi push rbx sub rsp, 544 lea rcx, [rsp + 36] movabs rax, offset memset mov r8d, 508 xor edx, edx call rax mov dword ptr [rsp + 32], 1 movabs rbx, offset "BumpAlloc(int* alloca)" lea rsi, [rsp + 32] mov rcx, rsi call rbx mov rdi, rax mov rcx, rsi call rbx mov dword ptr [rdi], 42 mov dword ptr [rax], 13 mov eax, dword ptr [rdi] add rsp, 544 pop rbx pop rdi pop rsi ret ``` -------------------------------- ### Vector lane left packing with v128 intrinsics Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-burst-intrinsics-processors.html Demonstrates using v128 vector types and direct intrinsic calls (cmplt_ps, movemask_ps, shuffle_epi8, popcnt_u32) to perform lane left packing on a NativeArray<float> with a lookup table of shuffle masks. ```csharp v128 a = Input.ReinterpretLoad<v128>(i); v128 mask = cmplt_ps(a, Limit); int m = movemask_ps(a); v128 packed = shuffle_epi8(a, Lut[m]); Output.ReinterpretStore(outputIndex, packed); outputIndex += popcnt_u32((uint)m); ``` -------------------------------- ### Static imports for X86 and Arm Neon intrinsics Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-burst-intrinsics-processors.html Use these static imports to access Burst's SIMD intrinsics without qualifying each call. Import the X86 family (SSE through AVX2, FMA, F16C, BMI) and Arm Neon as needed. ```csharp using static Unity.Burst.Intrinsics.X86; using static Unity.Burst.Intrinsics.X86.Sse; using static Unity.Burst.Intrinsics.X86.Sse2; using static Unity.Burst.Intrinsics.X86.Sse3; using static Unity.Burst.Intrinsics.X86.Ssse3; using static Unity.Burst.Intrinsics.X86.Sse4_1; using static Unity.Burst.Intrinsics.X86.Sse4_2; using static Unity.Burst.Intrinsics.X86.Popcnt; using static Unity.Burst.Intrinsics.X86.Avx; using static Unity.Burst.Intrinsics.X86.Avx2; using static Unity.Burst.Intrinsics.X86.Fma; using static Unity.Burst.Intrinsics.X86.F16C; using static Unity.Burst.Intrinsics.X86.Bmi1; using static Unity.Burst.Intrinsics.X86.Bmi2; using static Unity.Burst.Intrinsics.Arm.Neon; ``` -------------------------------- ### Generic job with generic parameter indirection Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/compilation-generic-jobs.html Shows a generic method that schedules a generic job using a generic parameter TData. Burst cannot detect this job at standalone-player build time. ```csharp public static void GenericJobSchedule<TData>() where TData: struct { // Generic argument: Generic Parameter TData // This Job won't be detected by the Burst Compiler at standalone-player build time. var job = new MyGenericJob<TData>(); job.Schedule(); } // The implicit MyGenericJob<int> will run at Editor time in full Burst speed // but won't be detected at standalone-player build time. GenericJobSchedule<int>(); ``` -------------------------------- ### Logging using string interpolation Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-string-support.html Logs an interpolated string with an integer value. This is equivalent to using string.Format directly. ```csharp int value = 256; Debug.Log($"This is an integer value {value}"); ``` -------------------------------- ### Read-only managed array in a Burst job Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-type-support.html Example of a Burst job that accesses a read-only static managed array. The array must be static readonly and accessed directly, not passed around. Burst makes a read-only copy at compile time, so C# code should not modify the array elements. ```csharp [BurstCompile] public struct MyJob : IJob { private static readonly int[] _preComputeTable = new int[] { 1, 2, 3, 4 }; public int Index { get; set; } public void Execute() { int x = _preComputeTable[0]; int z = _preComputeTable[Index]; } } ``` -------------------------------- ### Detect Burst vs managed execution using [BurstDiscard] with ref parameter Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/compilation-burstdiscard.html Use a ref parameter in a [BurstDiscard] method to indicate whether code is running on Burst or managed. The method sets the ref parameter to false when running under Burst, allowing the caller to detect the execution context. ```csharp [BurstDiscard] private static void SetIfManaged(ref bool b) => b = false; private static bool IsBurst() { var b = true; SetIfManaged(ref b); return b; } ``` -------------------------------- ### Call Burst-compiled method from managed code Source: https://docs.unity3d.com/Packages/com.unity.burst%401.8/manual/csharp-calling-burst-code.html Shows a Burst-compiled utility class and how to call it from managed code. The method uses structs and passes by reference per function pointer rules. When attached to an object and run, it prints float4(98f, 2f, -3f, 4f) to the log. ```csharp [BurstCompile] public static class MyBurstUtilityClass { [BurstCompile] public static void BurstCompiled_MultiplyAdd(in float4 mula, in float4 mulb, in float4 add, out float4 result) { result = mula * mulb + add; } } ``` ```csharp public class MyMonoBehaviour : MonoBehaviour { void Start() { var mula = new float4(1, 2, 3, 4); var mulb = new float4(-1,1,-1,1); var add = new float4(99,0,0,0); MyBurstUtilityClass.BurstCompiled_MultiplyAdd(mula, mulb, add, out var result); Debug.Log(result); } } ```