Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

(Case 1175538) Burst Compiled Job crashes on Android Build

Discussion in 'Data Oriented Technology Stack' started by liiir1985, Aug 16, 2019.

  1. liiir1985

    liiir1985

    Joined:
    Jul 30, 2014
    Posts:
    86
    We recently upgraded the burst compiler from 1.0.4 to 1.1.1, and we find out that the job compiled with the new version of burst compiler crashes on Android. This job works perfectly on 1.0.4, so I think this is a regression.

    I also tested the same job on windows, and iOS, they all workd without any problem, but on Android it'll crash 100%.

    I've submit the reproduce project in the bug report.
     
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,707
    It's great you submitted the project but there is not much point posting here without posting some code of the job for the rest of us!

    All my libraries currently compile fine to latest Android using 19.2 + latest burst so it's not just a general issue.
     
    Last edited: Aug 19, 2019
  3. liiir1985

    liiir1985

    Joined:
    Jul 30, 2014
    Posts:
    86
    Well I'm using the following code:
    Code (CSharp):
    1. internal struct ActorCollisionInfo
    2. {
    3.     [Flags]
    4.     public enum CombatStatusMasks
    5.     {
    6.         None,
    7.         Dead = 1,
    8.         Stun = 2,
    9.         Stiff = 4,
    10.         Invisible = 8,
    11.     }
    12.  
    13.     public long ObjectID;
    14.     public int Faction;
    15.     public float3 Position;
    16.     public float CollisionRadius;
    17.     public CombatStatusMasks CombatStatusMask;
    18. }
    19.  
    20. internal struct ActorBoundsInfo
    21. {
    22.     public Bounds bounds;
    23.     public long ObjectID;
    24. }
    25. [BurstCompile]
    26. internal unsafe struct CollisionJob: IJob
    27. {
    28.     [NativeDisableUnsafePtrRestriction] public ActorCollisionInfo* CollisionInfos;
    29.     public ActorCollisionInfo SourceInfo;
    30.     public float3 Direction;
    31.     public float3 LeftVector;
    32.     public float MaxDistance;
    33.     public int ActorCount;
    34.     public int RayCount;
    35.     public float RayWidth;
    36.     public int Factions;
    37.     [NativeDisableUnsafePtrRestriction] public bool* IsHit;
    38.     [NativeDisableUnsafePtrRestriction] public float* Distance;
    39.     [NativeDisableUnsafePtrRestriction] public float3* HitPoint;
    40.     [NativeDisableUnsafePtrRestriction] public byte* Relations;
    41.  
    42.     struct RayCastResult
    43.     {
    44.         public bool isHit;
    45.         public float3 hitPoint;
    46.         public float distance;
    47.     }
    48.  
    49.     public void Execute()
    50.     {
    51.         float shortest = MaxDistance;
    52.         float2 origin = SourceInfo.Position.xz;
    53.         float2 dir = Direction.xz;
    54.         float2 left = math.normalize(LeftVector.xz);
    55.         if (RayCount <= 0)
    56.             RayCount = 1;
    57.         int batch = RayCount / 2;
    58.  
    59.         if (RayCount % 2 == 0)
    60.         {
    61.             RayCastResult result = default;
    62.             float halfSegWidth = RayWidth / 2;
    63.             for(int i = 0; i < batch; i++)
    64.             {
    65.                 var pos = origin + left * halfSegWidth + left * RayWidth * i;
    66.                 RayCast(ref result, ref pos, ref dir, ref shortest);
    67.                 pos = origin - left * halfSegWidth - left * RayWidth * i;
    68.                 RayCast(ref result, ref pos, ref dir, ref shortest);
    69.             }
    70.  
    71.             *HitPoint = result.hitPoint;
    72.             *Distance = result.distance;
    73.             *IsHit = result.isHit;
    74.         }
    75.         else
    76.         {
    77.             RayCastResult result = default;
    78.             RayCast(ref result, ref origin, ref dir, ref shortest);
    79.             for(int i = 0; i <= batch; i++)
    80.             {
    81.                 var pos = origin + left * RayWidth * i;
    82.                 RayCast(ref result, ref pos, ref dir, ref shortest);
    83.                 pos = origin - left * RayWidth * i;
    84.                 RayCast(ref result, ref pos, ref dir, ref shortest);
    85.             }
    86.  
    87.             *HitPoint = result.hitPoint;
    88.             *Distance = result.distance;
    89.             *IsHit = result.isHit;
    90.         }
    91.     }
    92.  
    93.     void RayCast(ref RayCastResult result, ref float2 origin, ref float2 dir, ref float shortest)
    94.     {
    95.         float3 hp = float3.zero;
    96.         float distance = 0;
    97.         bool resHit = false;
    98.         for(int i = 0; i < ActorCount; i++)
    99.         {
    100.             var info = CollisionInfos[i];
    101.             if (ShouldIgnore(ref SourceInfo, ref info))
    102.                 continue;
    103.             float2 center = info.Position.xz;
    104.             float radius = info.CollisionRadius;
    105.             var isHit = GetLineCircleIntersection(ref origin, ref dir, ref center, radius, out var hitpoint);
    106.             var hd = hitpoint - origin;
    107.             float d = math.length(hd);
    108.             if(isHit && math.dot(hd, Direction.xz) >=0 && d < shortest)
    109.             {
    110.                 shortest = d;
    111.                 if (d < 0)
    112.                     d = 0.001f;
    113.                 hp = SourceInfo.Position + Direction * d;
    114.                 hp.y = info.Position.y;
    115.                 distance = d;
    116.                 resHit = true;
    117.             }
    118.         }
    119.  
    120.         result.isHit |= resHit;
    121.         if (resHit)
    122.         {
    123.             result.hitPoint = hp;
    124.             result.distance = distance;
    125.         }
    126.     }
    127.  
    128.     bool ShouldIgnore(ref ActorCollisionInfo source, ref ActorCollisionInfo target)
    129.     {
    130.         if (source.ObjectID == target.ObjectID)
    131.             return true;
    132.         if (Relations[Factions * source.Faction + target.Faction] == 0)
    133.             return true;
    134.         if (target.Faction < 0)
    135.             return true;
    136.         if (target.CollisionRadius < 0.00001f)
    137.             return true;
    138.         if ((target.CombatStatusMask & ActorCollisionInfo.CombatStatusMasks.Dead) == ActorCollisionInfo.CombatStatusMasks.Dead)
    139.             return true;
    140.         return false;
    141.     }
    142.  
    143.     static bool GetLineCircleIntersection(ref float2 origin, ref float2 direction, ref float2 center, float radius, out float2 hitPoint)
    144.     {
    145.         float t;
    146.         if(math.distance(origin, center) <= radius)
    147.         {
    148.             hitPoint = origin;
    149.             return true;
    150.         }
    151.  
    152.         var dx = direction.x;
    153.         var dy = direction.y;
    154.         var a = dx * dx + dy * dy;
    155.         var b = 2 * (dx * (origin.x - center.x) + dy * (origin.y - center.y));
    156.         var c = (origin.x - center.x) * (origin.x - center.x) + (origin.y - center.y) * (origin.y - center.y) - radius * radius;
    157.  
    158.         var determinate = b * b - 4 * a * c;
    159.         if((a <= 0.0000001f) || (determinate < -0.0000001f))
    160.         {
    161.             hitPoint = float2.zero;
    162.             return false;
    163.         }
    164.  
    165.         if(determinate < 0.00000001f && determinate > -0.00000001f)
    166.         {
    167.             t = -b / (2 * a);
    168.             hitPoint = new float2(origin.x + t * dx, origin.y + t * dy);
    169.             return true;
    170.         }
    171.  
    172.         t = (-b + Mathf.Sqrt(determinate)) / (2 * a);
    173.         var hit1 = new float2(origin.x + t * dx, origin.y + t * dy);
    174.         t = (-b - Mathf.Sqrt(determinate)) / (2 * a);
    175.         var hit2 = new float2(origin.x + t * dx, origin.y + t * dy);
    176.         if(math.distance(origin, hit1) < math.distance(origin, hit2))
    177.         {
    178.             hitPoint = hit1;
    179.             return true;
    180.         }
    181.         else
    182.         {
    183.             hitPoint = hit2;
    184.             return true;
    185.         }
    186.     }
    187.  
    188.     public static (bool isHit, Vector3 hitPoint, float distance) GetIntersectionPoint()
    189.     {
    190.         var (bounds, count) = GetBounds();
    191.         var (factions, relations) = GetRelations();
    192.         fixed(ActorCollisionInfo* ptr = bounds)
    193.         {
    194.             fixed(byte* ptr2 = relations)
    195.             {
    196.                 bool isHit;
    197.                 float distance;
    198.                 float3 hitPoint;
    199.                 ActorCollisionInfo sourceInfo = new ActorCollisionInfo();
    200.                 sourceInfo.Position = Vector3.one * 3;
    201.                 sourceInfo.CollisionRadius = 1;
    202.                 CollisionJob job = new CollisionJob()
    203.                 {
    204.                     SourceInfo = sourceInfo,
    205.                     Direction = -Vector3.one,
    206.                     LeftVector = Vector3.left,
    207.                     MaxDistance = 10,
    208.                     RayCount = 1,
    209.                     RayWidth = 0.5f,
    210.                     CollisionInfos = ptr,
    211.                     ActorCount = count,
    212.                     IsHit = &isHit,
    213.                     Distance = &distance,
    214.                     HitPoint = &hitPoint,
    215.                     Factions = factions,
    216.                     Relations = ptr2,
    217.                 };
    218.                 job.Run();
    219.                 return (isHit, hitPoint, distance);
    220.             }
    221.         }
    222.     }
    223.  
    224.     static (ActorCollisionInfo[] bounds, int count) GetBounds()
    225.     {
    226.         ActorCollisionInfo[] arr = new ActorCollisionInfo[]
    227.         {
    228.             new ActorCollisionInfo()
    229.             {
    230.                 ObjectID =1,
    231.                 CollisionRadius = 1,
    232.             }
    233.         };
    234.         return (arr, 1);
    235.     }
    236.  
    237.     static (int,byte[]) GetRelations()
    238.     {
    239.         byte[] arr = new byte[] { 1, 1, 1, 1, 1, 1, 1, 1 };
    240.         return (2, arr);
    241.     }
    242. }
    And calling the following line would crash on Android

    var (isHit, hp, d) = CollisionJob.GetIntersectionPoint();

    I found out that it crashed inside RayCast method, I think it has something to do with the unsafe pointer but I'm not sure about it
     
  4. liiir1985

    liiir1985

    Joined:
    Jul 30, 2014
    Posts:
    86
    Is anybody looking into this issue?
    Didn't receive any information from Unity for a long time:(