1

I have been trying to move my Marching Cubes algorithm from the CPU to the GPU with an OpenCL kernel for a while now.

The problem I´m getting is that a function in my kernel returns strange values, so I wrote a test case where I specify the possible return values in an array of 12 float3s with the float3 components being 0, 0.5 and 1 (see code below)

For some reason I get weirdly large numbers though, e.g. an edgeIndex of "11" returns the float3: (-145085952., 6.600e-43#DEN, 0) while it should be (1, 0, 0.5). The y coordinate basically is 0 though as far as I´m aware so that´s not the problem, but the x coordinate is what´s giving me headaches.

At first I thought OpenCL might have a problem with converting the given values to float3s so I specified them with ".f" (e.g. (float3)(0.f, 0.5f, 0.f)). This only resulted in even more strange and different results which makes me think that I have to make a mistake somewhere. I´m fairly new to OpenCL (this is my first real project using it) and I haven´t been programming in general that long either so I hope I´m not making some newbie mistake here but I tried to tackle this and related problems for days now and I can´t find a solution.

I narrowed down the problem as far as I could and tested whether the code is doing what it should for each step that it takes. Up to the function call of "CalculateEdgePos" everything seems to be going fine and I get the expected results. I stripped the function of all the unnecessary code (therefore you can ignore the "values" parameter as it´s not being used right now) but now I´m at my wits end.

the function returning the strange results:

float3 CalculateEdgePos(int edgeIndex, __global int* values) 
{ 
    if(edgeIndex == -1) 
    { 
        return (float3)(-1,-1,-1); 
    } 

        float3 EdgePositions[12] = {(float3)(0, 0.5, 0), (float3)(0.5, 1, 0), (float3)(1, 0.5, 0), (float3)(0.5, 0, 0), (float3)(0, 0.5, 1), (float3)(0.5, 1, 1), (float3)(1, 0.5, 1), (float3)(0.5, 0, 1), (float3)(0, 0, 0.5), (float3)(0, 1, 0.5), (float3)(1, 1, 0.5), (float3)(1, 0, 0.5)};

        return EdgePositions[edgeIndex];
} 


and the part of the kernel with the function call and the result getting send back to the CPU 
(edgeIndex is calculated fine beforehand):

__kernel void MarchCubes(__global float* outVertices, __global int* values, __global int* edges) 
{ 
.
.
.
    float3 vertexPos = CalculateEdgePos(edgeIndex, values); 
    float coords[3] = {vertexPos.x, vertexPos.y, vertexPos.z}; 

    outVertices[get_global_id(0)] = coords[coordIndex]; 
}

If anyone of you has any tips or help to offer, I´d greatly appreciate it. If you need any more code snippets let me know but I think this should be sufficient as it´s only the specified function that acts weirdly.

Kind regards, foodius

foodius
  • 53
  • 1
  • 6
  • So I actually found the solution shortly after posting this. It was too long for a comment though, so I updated the original post. – foodius Oct 09 '19 at 12:14
  • Answers should go into _Your Answer_ field, not into the _Question_. – Ruslan Oct 09 '19 at 12:16
  • Cheers for the heads up, I oversaw the answer field and was already wondering why I couldn´t mark the question as resolved. I didn´t think answers and comments were different so thanks for clarifying. – foodius Oct 09 '19 at 12:19

1 Answers1

1

Of course, right after I post this problem I´ve been sitting on for so long, I find the solution...

So if anyone has a similar problem:

It seems like OpenCL really doesn´t like it if you declare array elements right in the declaration of the array itself. So instead of writing:

 float3 EdgePositions[12] = {(float3)(0, 0.5, 0), (float3)(0.5, 1, 0), (float3)(1, 0.5, 0), (float3)(0.5, 0, 0), (float3)(0, 0.5, 1), (float3)(0.5, 1, 1), (float3)(1, 0.5, 1), (float3)(0.5, 0, 1), (float3)(0, 0, 0.5), (float3)(0, 1, 0.5), (float3)(1, 1, 0.5), (float3)(1, 0, 0.5)};

I now wrote:

float3 pos0 = (float3)(0.f, 0.5f, 0.f);
    float3 pos1 = (float3)(0.5f, 1.f, 0.f);
    float3 pos2 = (float3)(1.f, 0.5f, 0.f);
    float3 pos3 = (float3)(0.5f, 0.f, 0.f);
    float3 pos4 = (float3)(0.f, 0.5f, 1.f);
    float3 pos5 = (float3)(0.5f, 1.f, 1.f);
    float3 pos6 = (float3)(1.f, 0.5f, 1.f);
    float3 pos7 = (float3)(0.5f, 0.f, 1.f);
    float3 pos8 = (float3)(0.f, 0.f, 0.5f);
    float3 pos9 = (float3)(0.f, 1.f, 0.5f);
    float3 pos10 = (float3)(1.f, 1.f, 0.5f);
    float3 pos11 = (float3)(1.f, 0.f, 0.5f);

    float3 EdgePositions[12] = {pos0, pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8, pos9, pos10, pos11};

and it works like a charm now.

I still don´t really get why this isn´t allowed or returns false values, so if anyone knows and likes to elaborate, I would very much apprecitate it.

foodius
  • 53
  • 1
  • 6
  • My wild guess is, that it is allowed and does work; the problem isn't the OpenCL language, the problem is that your OpenCL *implementation* is buggy. Have you tried with multiple implementations ? – mogu Oct 11 '19 at 10:42
  • 1
    BTW you can get rid of the `if(edgeIndex == -1)` in CalculateEdgePos by prepending (-1,-1,-1) to the EdgePositions array, and changing last line to `return EdgePositions[edgeIndex+1]` - it's always a good idea to minimize code divergence in GPU code. – mogu Oct 11 '19 at 10:46
  • @mogu Hey, I tried multiple implementations but it never quite worked. I haven´t really went back into it though after I got it to work just because it was such a simple fix. But thanks the for the heads up, I will see if I get it to work next time I code something in Open CL. Also thanks a lot for the tip regarding the "if" statement. That´s a cool idea and I will change it right now. :) – foodius Oct 15 '19 at 19:27