Dynamic allocation of cl::Buffer

Dear all,

I have a situation where I need to dynamically allocate buffers in an OpenCL program (not inside a kernel). I am using the C++ wrapper from the cl.hpp header file. I'd like to do the analog of what is possible on a CPU:

cl_uint *myarray;

if(somecondition)
{
cl_uint arraysize = computed_number;
myarray = (cl_uint*)malloc(arraysize * sizeof(cl_uint));
}

Is it possible to do some analogous with cl::Buffer?

Many thanks!

No, cl::Buffer doesn’t directly support re-sizing. You would have to allocate a new buffer with the new size, copy over the data, and then release the old buffer.

If you’re looking for a higher-level API which does this, check out the boost::compute::vector<T>) class in the Boost.Compute OpenCL wrapper library which supports dynamic resizing and has an API just like std::vector<T>.

As Kyle pointed out the cl.hpp constructs are intended to be thin and overhead-free wrappers around OpenCL constructs, so dynamic memory management is not present. In fact, the header is almost entirely free of dynamic memory management of any sort - the cases where that fails are allocating strings for info return values and one or two other places.

Having said that, you should be able to allocate a cl::Buffer dynamically. Why not try:
cl::Buffer *buf = new cl::Buffer(…);

Or, better, to be in-keeping with C++ memory management in general:
std::shared_ptr<cl::Buffer> buf;
buf = std::make_shared<cl::Buffer>(…);

It won’t resize dynamically, but it will be allocated dynamically.

Unfortunately construction and assignment or re-assignment to a buffer object is unsafe due to the design of the header. Updating a shared_ptr to a buffer should work ok. The following code worked for me, for example:
std::shared_ptr<cl::Buffer> inputABuffer = std::make_shared<cl::Buffer>(begin(inputA), end(inputA), true);
cl::Buffer inputBBuffer(begin(inputB), end(inputB), true);
cl::Buffer outputBuffer(begin(output), end(output), false);

vectorAddKernel(
    cl::EnqueueArgs(
        cl::NDRange(numElements),
        cl::NDRange(numElements)),
    *inputABuffer,
    inputBBuffer,
    outputBuffer);

Actually, I misinterpreted the behaviour of my debugger. This works too:
cl::Buffer inputABuffer(begin(inputA), end(inputA), true);
cl::Buffer inputBBuffer(begin(inputB), end(inputB), true);
cl::Buffer outputBuffer(begin(output), end(output), false);

{
	
	cl::Buffer inputCBuffer(begin(inputA), end(inputA), true);
	inputBBuffer = inputCBuffer;
}

It correctly manages the lifetime of the underlying buffer using reference counting. So all you are then missing is a resize operator, but as Buffers manage real data in the OpenCL runtime I lean towards making sizes explicit at this level so I’m not sure that a resize operator would be the right thing to do.