Thursday, July 25, 2019

c# - How do I build a 3D array result set from a compute shader in unity?


I took this right down to the absolute most basic scenario but for some reason I can't get anything back from the GPU when this completes, could someone explain what I am doing wrong ...



Here's my CPU code:


using (var debugBuffer = new ComputeBuffer(27, sizeof(int)))
{
var kernel = compute.FindKernel("DoStuff");
compute.SetBuffer(kernel, "debug", debugBuffer);
MeshGenerator.Dispatch(kernel, 1, 1, 1);

var debug = new int[3, 3, 3];
debugBuffer.GetData(debug);
debugBuffer.Release();

}

And here is my GPU code:


#pragma kernel DoStuff

RWTexture3D debug;

[numthreads(3,3,3)]
void DoStuff (uint3 id : SV_DispatchThreadID)
{

debug[id] = 1;
}

The resulting 3D array is full of 0's and all documentation suggests that I should have a buffer full of 1's


EDIT:


Very curious behaviour ... so I am using compute to generate sets of voxel data and then generate meshes for the data, I created a simple voxel gen to fill only the center voxel in a 3,3,3 array like this ...


#pragma kernel GenerateChunk

struct voxel
{

float weight;
uint type;
};

voxel newVoxel(float weight, uint type)
{
voxel voxel;
voxel.weight = weight;
voxel.type = type;
return voxel;

};

// params for voxel generation
int3 from;
int3 to;

// the voxel generation result buffer
RWTexture3D voxels;

[numthreads(3,3,3)]

void GenerateChunk (uint3 threadId : SV_DispatchThreadID)
{
int3 pos = threadId + from;

bool xOk = (pos.x > 0 && pos.x < to.x);
bool yOk = (pos.y > 0 && pos.y < to.y);
bool zOk = (pos.z > 0 && pos.z < to.z);
bool ok = (xOk && yOk && zOk);

if (ok)

{
voxels[threadId] = newVoxel(1, 1);
}

if(!ok)
{
voxels[threadId] = newVoxel(-1, 0);
}
}


Calling this up in the same way as my original question results in me getting what appears to be a not populated buffer of voxels however, before I started this I created all this code as cpu based versions.


If I take my "not populated voxel buffer" and run that through my meshing code on the cpu I get as expected a single cube.


I'm now not sure how it's possible to debug the results of a compute shader since it seems that you cannot view the data using the debugger in visual studio.


I'm going to take a look in unity's built in MonoDevelop IDE and see if that shows anything but it may be that my original question was actually not even broken code in the first place!


EDIT2:


Ok MonoDevelop doesn't work either, nor does logging out the data using UnityEngine.Debug.Log();


As per the code, all values are -1 for the weights of my voxels except for the center voxel in my 3,3,3 grid and yet debugging / logging out any of the values always reports 0.


The cpu code appears to get what Iwould expect though and outputs the right result.


Now I have a problem when my gpu based meshing code doesn't work and I have no way to determine why ... does anyone have any ideas how I might be able to debug this code without apparently logging or using an IDE?


... jeez unity!!!



EDIT3:


I have spoken to unity about this by way of a bug, they initially stated that the problem was in my code but that was before I extracted this simple demo of the problem, I raised the problem in the unity forums too in the hope that someone with internal unity knowledge might be able to see something I can't, that discussion is here: http://forum.unity3d.com/threads/compute-shaders-populating-buffers-reading-computed-results-and-general-debugging-advice.385297/


It looks like my next step is to build the same scenario in raw DX perhaps using SharpDX to talk to DX's API directly that would at least tell me if a "RWTexture3D" buffer can be mapped to an array in this manner.


Personal note:


I can't believe that noone has faced this problem before, surely someone out there has seen this? I mean ... even the 2D scenario isn't doing what I think makes sense and if your problem is 1D then why use the GPU at all right?


Someone therefore must know the answer to this, my gut feeling is that there is some underlying architectural reason why a 3D buffer can't just be created like this, maybe it's worth asking the guys over at nVidia this question!



Answer



So it turns out if you put the data in to a standard structured buffer on the gpu in the right order you can basically just pull that data in to a 3d array on the cpu.


It requires you to flatten your indexes in to the buffer on the gpu in to 1d indexes but it's pretty clean on the cpu at least.


Not quite what I wanted as I wanted to have a 3d container for the data on both the cpu and the gpu but since unity technologies had nothing to offer I assume it must not be possible right now.



No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...