Search Unity

  1. All Pro and Enterprise subscribers: find helpful & inspiring creative, tech, and business know-how in the new Unity Success Hub. Sign in to stay up to date.
    Dismiss Notice
  2. Dismiss Notice

Compute Shaders Crashing

Discussion in 'Shaders' started by joesobo, Jan 20, 2021.

  1. joesobo

    joesobo

    Joined:
    Sep 6, 2018
    Posts:
    17
    So i've been beginning to learn how to use Compute Shaders. I've follow a couple of tutorials so i'm really just getting started with them. However, when working on my latest project, I've been repeatedly crashing Unity with this error. I'm not really sure what this means or how to begin solving it. I did manage to figure out what part of my code was causing it though. It happens whenever I call Append() on an AppendStructuredBuffer. The buffer is already setup with type ComputeBufferType.Append.


    Code (CSharp):
    1. for(int i = 0; triangulation[cellType][i] != -1; i +=3) {
    2.         Triangle tri;
    3.         tri.vertexA = float2(uv.x + relativeOffsets[triangulation[cellType][i]][0], uv.y + relativeOffsets[triangulation[cellType][i]][1]);
    4.         tri.vertexB = float2(uv.x + relativeOffsets[triangulation[cellType][i+1]][0], uv.y + relativeOffsets[triangulation[cellType][i+1]][1]);
    5.         tri.vertexC = float2(uv.x + relativeOffsets[triangulation[cellType][i+2]][0], uv.y + relativeOffsets[triangulation[cellType][i+2]][1]);
    6.         _Triangles.Append(tri);
    7. }
    This is the code where it is crashing my compute shader. To be honest I'm not sure why it even gets to the Append in the first place as triangulation[cellType] should initially equal -1.

    Any help would be much appreciated as I'm quite lost at the moment.
     

    Attached Files:

    Last edited: Jan 20, 2021
  2. joesobo

    joesobo

    Joined:
    Sep 6, 2018
    Posts:
    17
    At this point I've reached a dead end. I need to use the AppendStructuredBuffer as you can never be sure what index or how many triangles each thread will be adding. I have found no way of fixing this to far. Here is the rest of my code. I know its ugly and unclean, I'm just trying to see why this example doesn't work.

    Main Code

    Code (CSharp):
    1. private void CreateBuffers() {
    2.         int numPoints = voxelResolution * voxelResolution;
    3.         int numVoxelsPerResolution = voxelResolution - 1;
    4.         int numVoxels = numVoxelsPerResolution * numVoxelsPerResolution;
    5.         int maxTriangleCount = numVoxels * 3;
    6.  
    7.         Debug.Log(verticeBuffer);
    8.         if (!Application.isPlaying || (verticeBuffer == null || numPoints != verticeBuffer.count)) {
    9.             if (Application.isPlaying) {
    10.                 ReleaseBuffers();
    11.             }
    12.             verticeBuffer = new ComputeBuffer(numPoints, sizeof(float) * 3);
    13.             triangleBuffer = new ComputeBuffer(maxTriangleCount, sizeof(float) * 2 * 3 * 2, ComputeBufferType.Append);
    14.             triCountBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);
    15.             stateBuffer = new ComputeBuffer(numPoints, sizeof(int));
    16.         }
    17.     }
    18.  
    19. public void TriangulateChunk(VoxelChunk chunk) {
    20.         chunk.mesh.Clear();
    21.  
    22.         // Compute Shader Here
    23.         int numThreadsPerResolution = Mathf.CeilToInt(voxelResolution / threadSize);
    24.  
    25.         triangleBuffer.SetCounterValue(0);
    26.         shader.SetBuffer(0, "_Vertices", verticeBuffer);
    27.         shader.SetBuffer(0, "_Triangles", triangleBuffer);
    28.         shader.SetBuffer(0, "_States", stateBuffer);
    29.         shader.SetInt("_Resolution", voxelResolution);
    30.  
    31.         for (int i = 0; i < chunk.voxels.Length; i++) {
    32.             statePositions[i] = chunk.voxels[i].state ? 1 : 0;
    33.         }
    34.         stateBuffer.SetData(statePositions);
    35.  
    36.         shader.Dispatch(0, numThreadsPerResolution, numThreadsPerResolution, 1);
    37.  
    38.         ComputeBuffer.CopyCount(triangleBuffer, triCountBuffer, 0);
    39.         int[] triCountArray = { 0 };
    40.         triCountBuffer.GetData(triCountArray);
    41.         int numTris = triCountArray[0];
    42.  
    43.         Triangle[] tris = new Triangle[numTris];
    44.         triangleBuffer.GetData(tris, 0, 0, numTris);
    45.  
    46.         var vertices = new Vector3[numTris * 3];
    47.         var triangles = new int[numTris * 3];
    48.  
    49.         for (int i = 0; i < numTris; i++) {
    50.             for (int j = 0; j < 3; j++) {
    51.                 triangles[i * 3 + j] = i * 3 + j;
    52.                 vertices[i * 3 + j] = tris[i][j];
    53.             }
    54.         }
    55.  
    56.         chunk.mesh.vertices = vertices;
    57.         chunk.mesh.triangles = triangles;
    58.         chunk.mesh.RecalculateNormals();
    59.     }
    60.  
    Compute Shader

    Code (CSharp):
    1. #pragma kernel CSMain
    2.  
    3. struct Triangle {
    4.     float2 vertexA;
    5.     float2 vertexB;
    6.     float2 vertexC;
    7. };
    8.  
    9. int edges[16] = {
    10.     0x0,
    11.     0x3,
    12.     0x6,
    13.     0x5,
    14.     0x12,
    15.     0x15,
    16.     0x10,
    17.     0x9,
    18.     0x9,
    19.     0x10,
    20.     0x15,
    21.     0x12,
    22.     0x5,
    23.     0x6,
    24.     0x3,
    25.     0x0
    26. };
    27.  
    28. int triangulation[16][9] = {
    29.     {-1, -1, -1, -1, -1, -1, -1, -1, -1},
    30.     {0, 1, 4, -1, -1, -1, -1, -1, -1},
    31.     {1, 2, 5, -1, -1, -1, -1, -1, -1},
    32.     {0, 2, 4, 4, 2, 5, -1, -1, -1},
    33.     {2, 3, 6, -1, -1, -1, -1, -1, -1},
    34.     {0, 1, 4, 2, 3, 6, -1, -1, -1},
    35.     {1, 3, 5, 5, 6, 3, -1, -1, -1},
    36.     {0, 4, 5, 0, 3, 5, 3, 5, 6},
    37.     {0, 3, 7, -1, -1, -1, -1, -1, -1},
    38.     {1, 3, 4, 4, 7, 3, -1, -1, -1},
    39.     {0, 3, 7, 1, 2, 5, -1, -1, -1},
    40.     {3, 7, 4, 3, 2, 4, 2, 5, 4},
    41.     {0, 2, 7, 7, 6, 2, -1, -1, -1},
    42.     {1, 2, 7, 1, 7, 4, 2, 7, 6},
    43.     {0, 1, 6, 0, 6, 7, 1, 6, 5},
    44.     {-1, -1, -1, -1, -1, -1, -1, -1, -1}
    45. };
    46.  
    47. int relativeOffsets[8][2] = {
    48.     {0, 0},
    49.     {0, 1},
    50.     {1, 0},
    51.     {1, 1},
    52.     {0, 0.5},
    53.     {0.5, 0},
    54.     {1, 0.5},
    55.     {0.5, 1}
    56. };
    57.  
    58. RWStructuredBuffer<float3> _Vertices;
    59. AppendStructuredBuffer<Triangle> _Triangles;
    60. RWStructuredBuffer<uint> _States;
    61. uint _Resolution;
    62.  
    63. int2 GetUV (int3 id) {
    64.     return id.xy;
    65. }
    66.  
    67. int indexFromCoord(int x, int y) {
    68.     return y * _Resolution + x;
    69. }
    70.  
    71. void TriangulateCellRows(int2 uv) {
    72.     if (uv.x >= _Resolution-1 || uv.y >= _Resolution-1) {
    73.         return;
    74.     }
    75.  
    76.     int squareCornerStates[4] = {
    77.         _States[indexFromCoord(uv.x, uv.y)],
    78.         _States[indexFromCoord(uv.x + 1, uv.y)],
    79.         _States[indexFromCoord(uv.x, uv.y + 1)],
    80.         _States[indexFromCoord(uv.x + 1, uv.y + 1)],
    81.     };
    82.  
    83.     int cellType = 0;
    84.     if (squareCornerStates[0] == 1) cellType |= 1;
    85.     if (squareCornerStates[1] == 1) cellType |= 2;
    86.     if (squareCornerStates[2] == 1) cellType |= 4;
    87.     if (squareCornerStates[3] == 1) cellType |= 8;
    88.  
    89.     for(int i = 0; triangulation[cellType][i] != -1; i +=3) {
    90.         Triangle tri;
    91.         tri.vertexA = float2(uv.x + relativeOffsets[triangulation[cellType][i]][0], uv.y + relativeOffsets[triangulation[cellType][i]][1]);
    92.         tri.vertexB = float2(uv.x + relativeOffsets[triangulation[cellType][i+1]][0], uv.y + relativeOffsets[triangulation[cellType][i+1]][1]);
    93.         tri.vertexC = float2(uv.x + relativeOffsets[triangulation[cellType][i+2]][0], uv.y + relativeOffsets[triangulation[cellType][i+2]][1]);
    94.         _Triangles.Append(tri);
    95.     }
    96. }
    97.  
    98. [numthreads(8,8,1)]
    99. void CSMain (int3 id : SV_DispatchThreadID)
    100. {
    101.     int2 uv = GetUV(id);
    102.     TriangulateCellRows(uv);
    103. }
     
  3. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    1,968
    This means that the GPU cannot finish the work in a sensible amount of time.
    What's the value you use for "voxelResolution" and how many chunks do you have?
     
  4. joesobo

    joesobo

    Joined:
    Sep 6, 2018
    Posts:
    17
    Only a single chunk on a 8x8 resolution. The CPU had no trouble with it before I started converting to using a computeShader.
     
  5. joesobo

    joesobo

    Joined:
    Sep 6, 2018
    Posts:
    17
    Is there a way to extend the time (seems like a bad solution), or is this definitely some sort of infinite loop thats causing it to take too long?
     
  6. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    1,968
    There might be a problem with your
    for(int i = 0; triangulation[cellType][i] != -1; i +=3)
    loop. Some arrays in
    triangulation
    are not terminated by "-1". It looks like it can read out of bounds, and I'm not sure if it's reading the next row or just getting some "default" value, which is likely a zero.
    Try appending a terminating "-1" in each (making it triangulation[16][10]).
     
  7. joesobo

    joesobo

    Joined:
    Sep 6, 2018
    Posts:
    17
    Ok that was definitely an issue, that I'm surprised I hadn't run into before. Unfortunately it still didn't fix my error. When I think about it, it shouldn't have really played an effect. On the first iteration the entire grid is completely empty, which means cellType will always equal 0. When
    triangulation[cellType][i]
    runs its always should get
    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    }, from the triangulation table. Obviously this should break the loop.

    I ran some more tests and when I append a single triangle with vertices outside the loop it runs.
    When I try to append empty vertices instead of the specific positioned ones while still inside the loop it crashes.
    Also when I completely remove the entire loop or all of its contents it runs

    This leads me to believe that its not the contents of triangulation that are causing the problem, but maybe by the number of triangles that are being appended? 0 runs fine, 1 runs fine, even 2 when I manually append from outside the loop. This confuses the heck out of me since the triangulation shouldn't run at all initially, meaning 0 triangles should get added, which should run fine (similar to how it runs without the loop present).

    So how does a loop that shouldn't run, keep crashing my program (but only when it has contents)?

    If it helps at all I uploaded everything from the project into a git repo. https://github.com/joesobo/Compute-Shaders-Learning. Maybe you could take a look? All you have to do is open up the Main scene.
     
    Last edited: Jan 23, 2021
  8. joesobo

    joesobo

    Joined:
    Sep 6, 2018
    Posts:
    17
    I believe I figured it out. For anyone creating an array within the compute shader, make sure to set it to static. No idea why that caused the crash, but it fixed it
     
    deus0 likes this.
unityunity