Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Generic component type breaks standalone build

Discussion in 'Data Oriented Technology Stack' started by kingstone426, Nov 9, 2019 at 9:28 AM.

  1. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    19
    I have implemented a job component system that uses generic jobs and components.
    All works well in the editor but when I try to do a standalone build, it fails with this error:

    Unable to find interface method `Unity.Entities.IJobForEach_C`1<GenericComponent`1<T>>.Execute(ref T0)` from type `GenericJob`1`
    at Unity.Entities.JobForEachExtensions.JobStruct_Process_C`2<GenericJob`1<Unity.Transforms.Translation>,GenericComponent`1<T>>.ExecuteChunk(ref Unity.Entities.JobForEachExtensions.JobStruct_Process_C`2<GenericJob`1<Unity.Transforms.Translation>,GenericComponent`1<T>> jobData, System.IntPtr bufferRangePatchData, int begin, int end, Unity.Entities.ArchetypeChunk* chunks, int* entityIndices)
    at Unity.Entities.JobForEachExtensions.JobStruct_Process_C`2<GenericJob`1<Unity.Transforms.Translation>,GenericComponent`1<T>>.Execute(ref Unity.Entities.JobForEachExtensions.JobStruct_Process_C`2<GenericJob`1<Unity.Transforms.Translation>,GenericComponent`1<T>> jobData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex)

    The standalone build succeeds if I remove [BurstCompile].
    Build target is Windows x86 Standalone
    I have tried both Mono and IL2CPP backends and I am using:
    Unity 2019.3.0b8
    Burst 1.1.2
    DOTS Windows Platform 0.1.6
    Entities 0.1.1

    This is my code:

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Burst;
    3. using Unity.Jobs;
    4. using Unity.Transforms;
    5.  
    6. [assembly: RegisterGenericComponentType(typeof(GenericJob<Translation>))]
    7. [assembly: RegisterGenericComponentType(typeof(GenericComponent<Translation>))]
    8.  
    9. public class MySystem : JobComponentSystem
    10. {
    11.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    12.     {
    13.         inputDeps = new GenericJob<Translation>().Schedule(this);
    14.         inputDeps.Complete();
    15.         return inputDeps;
    16.     }
    17. }
    18.  
    19. public struct GenericComponent<T> : IComponentData
    20. where T : struct, IComponentData
    21. {
    22.     public T data;
    23. }
    24.  
    25. [BurstCompile]
    26. public struct GenericJob<T> : IJobForEach<GenericComponent<T>> where T : struct, IComponentData
    27. {
    28.     public void Execute(ref GenericComponent<T> componentData)
    29.     {
    30.      
    31.     }
    32. }
     
    Last edited: Nov 9, 2019 at 9:38 AM
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,830
    I do not believe declaring a IJobForEach like that is currently supported by burst. There are currently some limitations on how generics work, specifically with IJobForEach but I can't remember precisely.
     
    Last edited: Nov 9, 2019 at 10:20 AM
    kingstone426 likes this.
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,830
    I should add generics do work on most other job types without issue so while it might be a little more boilerplate you can still get an generic jobs working.

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Burst;
    3. using Unity.Jobs;
    4. using Unity.Transforms;
    5.  
    6. [assembly: RegisterGenericComponentType(typeof(GenericComponent<Translation>))]
    7.  
    8. public class TranslationMySystem : MySystem<Translation>
    9. {
    10. }
    11.  
    12. public class MySystem<T> : JobComponentSystem
    13.     where T : struct, IComponentData
    14. {
    15.     private EntityQuery query;
    16.  
    17.     protected override void OnCreate()
    18.     {
    19.         // data for testing
    20.         this.EntityManager.CreateEntity(typeof(T));
    21.  
    22.         this.query = this.GetEntityQuery(ComponentType.ReadWrite<T>());
    23.     }
    24.  
    25.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    26.     {
    27.         inputDeps = new GenericJob<T>
    28.             {
    29.                 TType = this.GetArchetypeChunkComponentType<T>(),
    30.             }
    31.             .Schedule(this.query, inputDeps);
    32.  
    33.         return inputDeps;
    34.     }
    35. }
    36.  
    37. [BurstCompile]
    38. public struct GenericJob<T> : IJobChunk
    39.     where T : struct, IComponentData
    40. {
    41.     public ArchetypeChunkComponentType<T> TType;
    42.  
    43.     public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    44.     {
    45.         var array = chunk.GetNativeArray(this.TType);
    46.  
    47.         for (var i = 0; i < chunk.Count; i++)
    48.         {
    49.             T componentData = array[i];
    50.         }
    51.     }
    52. }
    53.  
    54. public struct GenericComponent<T> : IComponentData
    55.     where T : struct, IComponentData
    56. {
    57.     public T data;
    58. }
    59.  
     
    florianhanke likes this.
  4. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    19
    Works like a charm! :D

    Thanks!
     
  5. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    608
    Keep in mind Burst probably isn't running in a build for generic jobs scheduled by a generic method or system.
     
  6. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,830
    Oh yeah, that's totally true (and I just tested).

    This is not something I have really tried but seemed like a quick solution to throw up but I guess it's not really a solution then!

    However, something like this does work though (and I actually tested it this time.)

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Burst;
    3. using Unity.Collections;
    4. using Unity.Jobs;
    5. using Unity.Transforms;
    6.  
    7. [assembly: RegisterGenericComponentType(typeof(GenericComponent<Translation>))]
    8.  
    9. public class MySystem : JobComponentSystem
    10. {
    11.     private EntityQuery query;
    12.  
    13.     protected override void OnCreate()
    14.     {
    15.         // data for testing
    16.         using (var n = new NativeArray<Entity>(1000000, Allocator.Temp))
    17.         {
    18.             var a = this.EntityManager.CreateArchetype(typeof(GenericComponent<Translation>));
    19.             this.EntityManager.CreateEntity(a, n);
    20.         }
    21.  
    22.         this.query = this.GetEntityQuery(ComponentType.ReadWrite<GenericComponent<Translation>>());
    23.     }
    24.  
    25.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    26.     {
    27.         inputDeps = new GenericJob<GenericComponent<Translation>>
    28.             {
    29.                 TType = this.GetArchetypeChunkComponentType<GenericComponent<Translation>>(),
    30.             }
    31.             .Schedule(this.query, inputDeps);
    32.  
    33.         return inputDeps;
    34.     }
    35. }
    36.  
    37. [BurstCompile]
    38. public struct GenericJob<T> : IJobChunk
    39.     where T : struct, IComponentData
    40. {
    41.     public ArchetypeChunkComponentType<T> TType;
    42.  
    43.     public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    44.     {
    45.         var array = chunk.GetNativeArray(this.TType);
    46.  
    47.         for (var i = 0; i < chunk.Count; i++)
    48.         {
    49.             T componentData = array[i];
    50.         }
    51.     }
    52. }
    53.  
    54. public struct GenericComponent<T> : IComponentData
    55.     where T : struct, IComponentData
    56. {
    57.     public T data;
    58. }
    59.