1
\$\begingroup\$

I have written an erosion simulator that I want to execute from the editor (for generating terrain and such outside of play mode). Unfortunately, when I crank the parameters on my simulation, unity hangs. The UI becomes unresponsive, none of the menus work anymore. However, the process is still running - windows doesn't claim that the program is no longer responding.

The weird thing is that task manager claims that the GPU is sitting at zero utilization while Unity hangs. My (CPU side) erosion code looks something like this (executed via editor script):

    HydraulicCompute.SetFloat("_ErosionRadius", ErosionRadius);
    HydraulicCompute.SetBuffer(_erosionId, "HeightMap", heightMap);
    HydraulicCompute.SetBuffer(_erosionId, "Droplets", _dropletBuffer);

    int threadGroupsX = Mathf.CeilToInt(mapSize / 8.0f);
    int threadGroupsY = Mathf.CeilToInt(mapSize / 8.0f);
    for (int i = 0; i < 100; i++) {
        HydraulicCompute.Dispatch(_dropletId, Mathf.CeilToInt(_dropletBuffer.count / 1024.0f), 1, 1);
        HydraulicCompute.Dispatch(_erosionId, threadGroupsX, threadGroupsY, 1);
    }

When the size of the _dropletBuffer is bigger than 12,000 (32 bytes per droplet), and the heightMap buffer larger than 1024x1024 (4 bytes per pixel), then I run into the aforementioned problem.

I would guess that the issue occurs either because there is a problem with the buffer sizes, or that the frame takes too long and Unity times out.

When I comment out the Dispatch calls Unity is able to allocate and populate the buffers instantaneously (at least it looks really quick). While that doesn't rule out the potential buffer problem, it certainly makes it seem less likely.

So what exactly is the problem here? Is it a memory problem? Or is the frame timing out? Or something else entirely?

Is there a prescribed way to doing this kind of intensive GPU work in the background in editor mode? I've looked at the Job system, but that seems to be CPU side only...

[EDIT]

I have managed to put together the following snippet which always crashes on my GPU (NVIDIA 980ti):

[numthreads(1,1,1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
    for (int i = 0; i < _NumIterations; i++) {
        HeightMap[1024*512 + 512] = 0;
    }
}

When executed as 1 thread group for 1 iteration (_NumIterations = 1), this crashes my GPU driver. I am running on the latest version. I have no idea as to what might be causing the problem, windows event viewer just lists a nvlddmkm error, which apparently means it could be just about anything. It's frustrating to say the least.

\$\endgroup\$
4
  • \$\begingroup\$ Can you show us the compute shader you're using here? It might be useful to see if you can chop its work into smaller steps, like doing fewer iterations in a frame, and compounding passes over subsequent frames, so you can keep passing control back to the editor periodically and keep it from going unresponsive. \$\endgroup\$
    – DMGregory
    Feb 25 '20 at 1:11
  • \$\begingroup\$ @DMGregory I've updated my answer. \$\endgroup\$
    – otoomey
    Feb 25 '20 at 21:38
  • \$\begingroup\$ Has this question been solved? I had the same problem with compute shader in Unity editor mode. I tried to insert breakpoint and debug in Visual Studio, but it didn't stop at ComputeShader.Dispatch() or any other operation on compute buffer. And Unity does freeze after the function which executes the compute shader, there I can not see what is happening... \$\endgroup\$
    – yuans
    May 27 at 3:22
  • \$\begingroup\$ @yuans I can't remember the exact solution, but in my case it was most likely due to heavy use of non-linear memory access. Try to run your compute shader on the iGPU and see if it works, I found that intel's integrated GPUs specifically tend to be much more forgiving to non linear memory ops than the dedicated cards. That at least might point you in the right direction. \$\endgroup\$
    – otoomey
    May 27 at 21:34
0
\$\begingroup\$

I found a possible reason and it works in my case.

There's a feature names "Timeout Detection and Recovery(TDR)" on Windows since Vista. And what TDR do is assume a crash and reset the graphics card's driver if the graphics card does not respond within a certain time frame. The default TDR time is about 2 seconds, it's easy to exceed that limit when using GPGPUS like CUDA and compute shader.

There are 2 solutions according to the cause of the problem:

  1. Divide the task into several subtasks. Means if there's a ComputeShader.Dispatch() performs 100 cycles, you can do ComputeShader.Dispatch() 10 times and 10 cycles each time. This is the way I finally used.
  2. Increase the TDR delay time by modifying the corresponding registry entry. Run the command "regedit", navigate to "HKEY_LOCAL_MACHINE -> SYSTEM -> CurrentControlSet -> Control -> GraphicsDrivers" where you can create a key of type "DWORD" and name it "TdrDelay" taking the delay time as an argument. Restart your computer.

There is a link to the introduction of TDR. Hope it helps.

\$\endgroup\$
1
  • \$\begingroup\$ I rolled back your other (deleted) answer because from a moderation point of view it made more sense. (There is nothing to be done about it, and no harm done either.) \$\endgroup\$
    – Vaillancourt
    Jun 2 at 2:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.