Search code examples
iosswiftmetal

Reading data from MTLBuffer in Swift


I need to read data from a MTLBuffer after processing on the GPU. So far I've tried following code, but it always crashes with an EXC_BAD_ACCESS error code.

struct gauss_model {
  var mean : [Float32] = [0.0, 0.0, 0.0];
  var covMat : [[Float32]] = [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]];
  var invCovMat : [[Float32]] = [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]];
  var samples : Int32 = 0;
}

self.gaussModels = [gauss_model](count: Int(10), repeatedValue: gauss_model())
self.modelsBuffer = self.device.newBufferWithBytes(self.gaussModels, length:      self.gaussModels.count * sizeof(gauss_model), options: MTLResourceOptions.OptionCPUCacheModeDefault)
commandEncoder.setBuffer(self.modelsBuffer, offset: 0, atIndex: 0)

    // execute GPU code

var model = unsafeBitCast(self.modelsBuffer.contents(), UnsafeMutablePointer<gauss_model>.self)
NSLog("%@", model.memory.mean) // crashes on this statement

I've also tried different approaches of obtaining the value like

var model = UnsafeMutablePointer<gauss_model>(self.modelsBuffer.contents())
// iterate over models with model.memory and model.successor()

or

var model = UnsafeMutablePointer<[gauss_model]>(self.modelBuffer.contents())
let models : [gauss_model] = model.memory

but none of them worked. Is there even a way to do this?


Solution

  • I've managed to fix the problem. The problem was in my wrong assumption about memory management in Swift and the fact that the function newBufferWithBytes does only a shallow copy. Calling the function only copied the pointers to mean, covMat and invCovMat arrays and self.modelBuffer.contents() contained pointers to uninitialized memory. Accessing the memory was causing the crash.