How to pass array of MTLBuffers to compute kernel

I'm trying to work with an MTLBuffer that has a size greater than the maximum allowed buffer length for an MTLBuffer. As such I have split it into an array of MTLBuffers like this:

// swift declaration
var _mBuffers : [MTLBuffer]!

// swift allocation
_mBuffers = []
for _ in 0..<64 { // use 64 buffers
   if let buffer = _mDevice.makeBuffer(length: BUFFER_BYTES, options: .storageModeShared) {
       _mBuffers.append(buffer)
   }
}

// we now have an array of 64 MTLBuffers in _mBuffers

Then in my metal compute kernel I have a function like this, where I want to organise data across the 64 buffers:

struct Foo {
     device uint* data_buffers[64];
};

kernel void test_buffers(
                         constant Foo & f [[buffer(0)]],
                         device metal::atomic_uint *out_counters,
                         const uint index [[thread_position_in_grid]])
{
    // figure out which group value belows to
    uint group = index % 64;

    // find the slot in memory for that group
    uint position = atomic_fetch_add_explicit(&out_counters[group], 1, memory_order_relaxed);

    // add the value to the buffer with that group, and it's position in buffer
    f.data_buffers[group][position] = index;
}

Now I can't figure out how to call this kernel function from swift code using the command encoders.

// swift calling code snippets...(not even close to working)

// this should be the same as the C struct in the kernel code?
struct Foo {
    var buffers : [MTLBuffer]
};

// how to pass the _mBuffer with 64 elements to the computeEncoder arguments??
var arguments : Foo = {
        buffers: [MTLBuffer]!
}

// how to pass the arguments to the computeEncoder correctly?
computeEncoder.setBytes(&arguments, length: MemoryLayout<Foo>.stride, index: 0)

Any help would be much appreciated! I feel like this should be simpler than it is.

  • AFAIK, it is not possible... but I'd love to hear if this may be possible. I ended up packing multiple "virtual" arrays in each of the 32 allowed buffers you can pass. Then I used some indexing to differentiate one virtual array from another. This approach has obviously important limitations in that there may be instances a virtual array can't fit along others in the maximum size of the buffer. But at least it allowed us to pass more arrays than the upper limit of 32.

  • It should be possible since the kernel code is valid. Using the encoders with C code should be doable, I just can't figure out how to do it in Swift. I might just have to port parts of the code into C and try it that way.

Add a Comment