Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Jobs don't always run.

Discussion in 'Entity Component System' started by Peeling, Jun 15, 2019.

  1. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    442
    EDIT: Solved! The Burst compiler didn't like accessing constants defined outside the job struct. Once the job finished compiling it stopped working.

    I've begun trying to use the job system to speed up some initialisation processes.

    I'm generating a number of distance-field textures (for nicely scaling icons etc) at app launch, and successfully used jobs to parallelise the propagation function. So far so good.

    Next I wanted to parallelise the primitive paint functions that I use to seed the distance fields. For example, I might paint a rounded rectangle, cut out a smaller rounded rectangle, and thus create a rectangle outline.

    Unfortunately, converting THAT to use jobs didn't work. Or rather, the first two jobs work as expected, and then they just stop working - even when launched using IJob.Run() rather than Execute(). I can step into the job the first two times it's launched, but after that Unity just steps over the Run() command like it's not there.

    Here's the code. igrid1 and igrid2 are 1D int4 nativearrays of size width*height. The intention was to launch several jobs on different slices of the array, but even using a single slice doesn't work.

    NB: iinside is an int4(0,0,0,0)
    iempty is an int4(9999,9999,199960002,0)
    paintmaths is a bitmask of which src/dest combos result in a solid pixel. Standard 'or' paint mode has paintmaths=14

    Code (CSharp):
    1.  
    2.  
    3. [BurstCompile]
    4. public struct PaintJob : IJob
    5. {
    6.  
    7.     public NativeSlice<int4> igrid1;
    8.     public NativeSlice<int4> igrid2;
    9.     public int b;
    10.     public int t;
    11.     public int width;
    12.     public int height;
    13.     public float cx, cy, fw, fh, cr, ang;
    14.     public int shape;
    15.     public int paintmaths;
    16.  
    17.     public void Paint(int x, int y, int src)
    18.     {
    19.         int l = (x + y * width);
    20.         int dst = (igrid1[l].z == 0) ? 2:0;
    21.         if ((paintmaths & (1 << (src+dst))) !=0)
    22.         {
    23.             igrid1[l] = Propagation.iinside;
    24.             igrid2[l] = Propagation.iempty;
    25.         }
    26.         else
    27.         {
    28.             igrid2[l] = Propagation.iinside;
    29.             igrid1[l] = Propagation.iempty;
    30.         }
    31.     }
    32.  
    33.  
    34.     public void Execute()
    35.     {
    36.         ang *= Mathf.Deg2Rad;
    37.  
    38.         switch (shape)
    39.         {
    40.             case 0:
    41.                 PaintCircle();
    42.                 break;
    43.             case 1:
    44.                 PaintRect();
    45.                 break;
    46.             case 2:
    47.                 PaintRoundedRect();
    48.                 break;
    49.         }
    50.     }
    51.  
    52.     void PaintCircle()
    53.     {
    54.  
    55.     }
    56.  
    57.     void PaintRect()
    58.     {
    59.  
    60.     }
    61.  
    62.     void PaintRoundedRect()
    63.     {
    64.         float cos = Mathf.Cos(ang);
    65.         float sin = Mathf.Sin(ang);
    66.  
    67.         int l = 0, r = width - 1;
    68.  
    69.         float circx, circy;
    70.         float cr2 = cr * cr;
    71.  
    72.         for (int y = b; y <= t; ++y)
    73.         {
    74.             for (int x = l; x <= r; ++x)
    75.             {
    76.  
    77.                 float locx = (x - cx) * cos + (y - cy) * sin;
    78.                 float locy = (y - cy) * cos - (x - cx) * sin;
    79.  
    80.                 circx = Mathf.Clamp(locx, cr - fw, fw - cr);
    81.                 circy = Mathf.Clamp(locy, cr - fh, fh - cr);
    82.                 float dx = locx - circx;
    83.                 float dy = locy - circy;
    84.                 float d2 = (dx * dx + dy * dy);
    85.                 Paint(x, y, (d2 <= cr2)?1:0);
    86.             }
    87.         }
    88.     }
    89. }
    90.  
    91.  
    92.     public void PaintRoundedRect(int paintmaths pf, float cx, float cy, float fw, float fh, float cr, float ang = 0f)
    93.     {
    94.  
    95.         PaintJob pj = new PaintJob()
    96.         {
    97.             width = this.width,
    98.             height = this.height,
    99.             igrid1 = this.igrid1.Slice(0, width * height),
    100.             igrid2 = this.igrid2.Slice(0, width * height),
    101.             t = height - 1,
    102.             b = 0,
    103.             cx = cx,
    104.             cy = cy,
    105.             fw = fw,
    106.             fh = fh,
    107.             cr = cr,
    108.             ang = ang,
    109.             paintmaths = paintmaths,
    110.             shape = 2
    111.         };
    112.  
    113.         pj.Run();
    114.  
    115.     }
    116.  
     
    Last edited: Jun 15, 2019
  2. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    442
    Update: If I remove [BurstCompile] it works as expected.

    Updated Update: If I force synchronous compilation, it doesn't work *at all*. So I'm guessing the first two times it 'works' it hasn't actually compiled yet.
     
    Last edited: Jun 15, 2019
  3. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    502
    Oh you know what I had a similar experience recently...
    It works at first cause it's not running the burst code until the burst compilation is complete. As soon as it completes, it stops working because there is something in your code that burst doesn't like.

    How about ang *= Mathf.Deg2Rad;
    Try using ang = math.Radians(ang) instead.

    I had to hunt bit by bit until I found the line it didn't like. I didn't see any obvious reason why it wouldn't like it though. Luckily for me it was something that could be refactored another way anyway...
     
    Last edited: Jun 15, 2019
  4. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    442
    Ah, nice! Turns out it doesn't like accessing static int4s (iempty and iinside).

    Does the Burst compiler generate any visible errors?
     
  5. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    502
    I suppose it's meant to. This seems to me like a burst bug.
     
  6. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,683
    Wrong. Burst like const/readonly fields if they outside of job, moreover only this filed types can be accessed without problem, cos they inlined in compiled bursted job.
     
  7. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    442
    Well, it didn't like accessing mine. I moved them inside the job and it started working.
     
  8. tim_jones

    tim_jones

    Unity Technologies

    Joined:
    May 2, 2019
    Posts:
    287
    @Peeling can you paste the definitions of `Propagation.iempty` and `Propagation.iinside` here?