How do I pass an array from Swift to MSL parameter (C++)

289 Views Asked by At

I want to make this custom CIFilter.

var dummyColors = [
        CIVector(x: 0.9, y: 0.3, z: 0.4),
        CIVector(x: 0.2, y: 0.5, z: 0.9),
        CIVector(x: 0.5, y: 0.9, z: 0.3)
    ]
    
    var normal = dummyColors.withUnsafeMutableBufferPointer { (buffer) -> UnsafeMutablePointer<CIVector> in
        var p = buffer.baseAddress
        print(p)
        return p!
    }

    //this is  parameter and how to pass bvalue to the kernel function
    return self.kernel.apply(extent: inputExtent,
                             roiCallback: roiCallback,
                             arguments: [inputImage, reddish, greenish, blueish, normal])  // (5)

Here is me trying to pass parameter with pointer. However the code seem doesn't like it and it just crashed without no printing error.

And here is the metal function

extern "C" { namespace coreimage {               // (3)

//this is how you define parameter on the top of the function
float4 dyeInThree(sampler src,
                  float3 redVector,
                  float3 greenVector,
                  float3 blueVector,
                  device float3 *a) 

Is there another way how to pass the parameter to my metal code?

2

There are 2 best solutions below

0
On BEST ANSWER

I adopted this answer to your use case: https://stackoverflow.com/a/58706038/16896928

Here's what I used for memory allocation:

var dummyColors = [
            SIMD3<Float>(x: 1.1, y: 0.1, z: 0.1), 
            SIMD3<Float>(x: 0.1, y: 1.1, z: 0.1),
            SIMD3<Float>(x: 0.1, y: 0.1, z: 1.1)
        ]

let pointer = UnsafeMutableRawPointer.allocate(
            byteCount: 3 * MemoryLayout<SIMD3<Float>>.stride,
            alignment: MemoryLayout<SIMD3<Float>>.alignment)
let sPointer = dummyColors.withUnsafeMutableBufferPointer { (buffer) -> UnsafeMutablePointer<SIMD3<Float>> in
            let p = pointer.initializeMemory(as: SIMD3<Float>.self,
            from: buffer.baseAddress!,
            count: buffer.count)
            return p
        }
let data = Data(bytesNoCopy: sPointer, count: 3 * MemoryLayout<SIMD3<Float>>.stride, deallocator: .free)

You need to convert the buffer into NSData before passing it to the kernel. And here is the Metal function declaration:

extern "C" { namespace coreimage {               // (3)
    float4 dyeInThree(sampler src,
                      float3 redVector,
                      float3 greenVector,
                      float3 blueVector,
                      constant float3 a[]) {

Note the 'constant' namespace instead of 'device'. Otherwise the Metal compiler would give error at runtime.

1
On

The pointer you get with withUnsafeMutableBufferPointer is only valid inside the closure you passed to the function. You need to allocate a more "permanent" storage for the parameters.

You can start by using something like UnsafeMutableBufferPointer.allocate to allocate the memory, but you will have to track the memory somewhere, because you will need to deallocate it after you are done using it.