Search Unity

Boxing a valuetype with Burst

Discussion in 'Burst' started by GilCat, Nov 26, 2018.

  1. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I'm getting this error:
    Code (CSharp):
    1. Unexpected exception Burst.Compiler.IL.CompilerException: Unexpected exception ---> Burst.Compiler.IL.CompilerException: Error while processing function `System.Void SampleSystem/Job::Execute(MyData&)` ---> Burst.Compiler.IL.CompilerException: Unexpected error while processing `IL_0019: box ComplexData args(IL_0018)` at \SampleSystem.cs(24,7) ---> System.NotSupportedException: Boxing a valuetype to a managed object is not supported by burst
    2.  
    Is boxing not allow when using Burst?
    I've wrote a sample system to show this:
    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4.  
    5. public interface IComplexData {
    6.   float ComplexFloat { get; }
    7. }
    8.  
    9. struct ComplexData : IComplexData {
    10.   public float Value;
    11.   public float ComplexFloat => Value;
    12. }
    13.  
    14. public struct MyData : IComponentData {
    15.   public float Value;
    16. }
    17.  
    18. public class SampleSystem : JobComponentSystem
    19. {
    20.   [BurstCompile]
    21.   struct Job : IJobProcessComponentData<MyData> {
    22.     public void Execute(ref MyData data) {
    23.       var complexData = new ComplexData { Value = data.Value };
    24.       DoSomethingWithData(complexData);
    25.     }
    26.   }
    27.  
    28.   protected override JobHandle OnUpdate(JobHandle inputDeps) {
    29.     inputDeps = new Job().Schedule(this, inputDeps);
    30.     return base.OnUpdate(inputDeps);
    31.   }
    32.  
    33.   private static float DoSomethingWithData(IComplexData data) {
    34.     return data.ComplexFloat * 100f;
    35.   }
    36. }
    Thanks for the great job on ECS
     
  2. GilCat likes this.
  3. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    boxing = wrapping value type with an object and storing it on the managed heap

    objects are not blittable and not supported by jobs and burst
     
    GilCat likes this.
  4. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    Thanks for the clarification.
    Doing it like this solves it:
    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4.  
    5. public interface IComplexData {
    6.   float ComplexFloat { get; }
    7. }
    8.  
    9. struct ComplexData : IComplexData {
    10.   public float Value;
    11.   public float ComplexFloat => Value;
    12. }
    13.  
    14. public struct MyData : IComponentData {
    15.   public float Value;
    16. }
    17.  
    18. public class SampleSystem : JobComponentSystem
    19. {
    20.   [BurstCompile]
    21.   struct Job : IJobProcessComponentData<MyData> {
    22.     public void Execute(ref MyData data) {
    23.       var complexData = new ComplexData { Value = data.Value };
    24.       DoSomethingWithData(complexData);
    25.     }
    26.   }
    27.  
    28.   protected override JobHandle OnUpdate(JobHandle inputDeps) {
    29.     inputDeps = new Job().Schedule(this, inputDeps);
    30.     return base.OnUpdate(inputDeps);
    31.   }
    32.  
    33.   private static float DoSomethingWithData<T>(T data) where T : struct, IComplexData {
    34.     return data.ComplexFloat * 100f;
    35.   }
    36. }
     
  5. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    DoSomethingWithData each time will be executed on the different thread, or no?
     
  6. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    Yes! That is the idea. The example is incomplete and it was only to show the error in the first place.
     
  7. xoofx

    xoofx

    Unity Technologies

    Joined:
    Nov 5, 2016
    Posts:
    417
    Yes, it is not allowed because they are involving a reference type (through an interface in your case)

    The correct way to solve it is as you did, by using generic methods with structs and interface constraints. It will make the call to the struct implementation completely inline-able and this is a lot more efficient than using interface calls.
     
    GilCat likes this.