c++swiftmetalcifiltermetal-performance-shaders

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


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?


Solution

  • 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.