MSAOpenCL re-initialise buffers

Hello All

I am working with the msaOpenCl library on a sketch where I need to update/change the sizes of the buffers on the openCL device, during the running of the app.

I’ve tried just re-initialising the buffers on an event, (i.e. on a keypress), as follows:`

octreeGPU.initBuffer(octree.size());
for(int i = 0; i < octree.size(); i++) octreeGPU[i] = octree[i];
octreeGPU.writeToDevice();`

Where the octree array is based on a typedef struct as follows:

typedef struct{
float2 origin;
float2 size;
int count = 0;
int children;
int lines[10];
} node;

vector <node> octree;
msa::OpenCLBufferManagedT<node>	octreeGPU; // vector of GPU octree

But doing so crashes the app. Is there a ‘correct’ approach to resizing and updating the openCl buffers?

I guess maybe that running initBuffer more than once is overloading the memory of the device and causing it to crash. In which case, the question might be better put; how do I clear existing buffers from the device, ready for them to be re-initialised?

I’ve had a look right through the OpenCLBufferManagedT and other classes, but cannot see a function to call to do this.

I’m probably misunderstanding something here
S

Hey, first thing I would try is to not do the reallocation on a keypress. That might be happening in a different thread. A ghetto method that I usually do is just have a variable which you set to true on the keypress (e.g. doInit = True). And then in your update() (i.e. main thread), check the variable, and if it’s true, reinit (and remember to clear the variable!). OpenGL across threads is a pain.

void update() {
    if (doInit) {
        doInit = false;
        octreeGPU.initBuffer(octree.size());
        for(int i = 0; i < octree.size(); i++) octreeGPU[i] = octree[i];
        octreeGPU.writeToDevice();`
    }
    // more code here
}

However, I don’t know if that is only the issue, maybe you are running out of memory because the old buffer isn’t being cleared. Just looking at the code, it looks like I don’t release the old clMemObject when you re-init, whoops :S. But I do release it when the OpenCLBufferManagedT object itself is deleted. Which is good. So for now you can try two different things:

  1. I have made public getters for the internal opencl vars, so you can release manually, using MSAOpenCLBufferManagedT::getCLMem()
auto& clMemObject = octreeGPU.getCLMem(); // get handle to actual opencl memory object
if(clMemObject) clReleaseMemObject(clMemObject); // if it's allocated, release it
octreeGPU.initBuffer(size); // now you can reallocate

OR

  1. instead of instantiating a OpenCLBufferManagedT directly, instantiate a OpenCLBufferManagedT pointer. i.e.
// declare your variable
shared_ptr< OpenCLBufferManagedT <node> >  octreeGPU;

// in your code (in setup or update etc).
octreeGPU = make_shared< <OpenCLBufferManagedT <node> >(); // this will delete the old octreeGPU if there was one. it's destructor will be called, which should delete the old clMemObject.
octreeGPU->initBuffer(size); // now access methods via -> syntax instead of . syntax

The second method is probably safer and more future proof. I only allow the first thing to happen in case you do need to do something which the API doesn’t yet allow. But it may break in the future.

(P.S. I haven’t tested the above code so there may be syntax errors).

This is a workaround, initBuffer should release any allocated buffers. And the classes should have public release method. That is an oversight on my behalf and I’ll try to address when I have time .

P.P.S. instead of

octreeGPU.initBuffer(octree.size());
for(int i = 0; i < octree.size(); i++) octreeGPU[i] = octree[i];

I think you can write

octreeGPU.initBuffer(octree.size(), octree.data()); // this will copy all the data from octree into the buffer on init

oh, and also check what the actual error is, what line is it crashing on, what does it say etc :slight_smile:

Hey there Memo,

Thanks for the really detailed response. I’d already wondered about the keypress issue, and set up a boolean switch as you suggested into update(). So that wasn’t the issue.

I’ve implemented both of the above suggestions (and the alternative .data() init, which is handy, thanks!)
They both run, and work as expected… right up until I hit the keypress. Arg. The fact that I’m still crashing does suggest that initBuffer was working fine and releasing the allocated buffers, as you expected. So my hunch on memory may be wrong.

One frustrating issue is that the problem seems to freeze Xcode/everything on my screen except the mouse movement. So I can’t read any error messages; and I have to force restart the machine to continue. That in itself may be a clue?

So… after a bit of trial and error commenting out lines, and numerous force restarts(!), I think the crash may be happening when I set the newly initiated buffer as the Kernel argument. i.e. when the final line in the following is called:

    planToOctree();
    opencl.finish();
    opencl.kernel("rayCheck")->setArg(2, plan);
    opencl.kernel("rayCheck")->setArg(5, *octreeGPU);

When I comment out that line, the app runs through the keypress until it gets to the kernel run line i.e. run1D(). And then it has an EXC_BAD_ACCESS issue, which I guess is to be expected if there is a buffer not set.

So why would setting the kernel arguments cause a stall? Perhaps I need to end, delete and restart the whole kernel?

Thanks for the help so far, anyhow!
S

p.s… in the above, planToOctree() contains all of the plan resampling and buffer re-initialising as discussed.

p.p.s. one type on the make_shared line, which I think should be:

    octreeGPU = make_shared< msa::OpenCLBufferManagedT <node> >() ;

update:

I’ve tried just commenting out the entire contents of the kernel code, and running it. It works, and re-initialises fine. So the problem is actually with the octree-search that I’m doing in that. doh.

However; it is still weird, in that the same code runs and searches fine the first time round. I’m betting on some kind of an un-initialised variable in the updated buffer that is causing the search to spin forever. I’ll go boil my head and see if I can pin it down

S

waaaaaa, fixed it.

Within the node type, one of the variables (int children) was not set to a default zeroed value as the octree was being constructed. As a result, when the node buffer was re-initialised, some of the values of that variable remained filled with old data noise and caused endless loops in the search that the kernel was running.

In the first initialisation of the kernel buffers this doesn’t seem to happen, which is what was making me think it was a memory issue. I guess in a way it is.

Anyway, thanks to Memo for the pointers, and hopefully this thread will be of use to future people who may come this way.