How to use UnsafeMutableRawPointer to fill an array?

前端 未结 5 1991
傲寒
傲寒 2021-02-09 02:25

I have a Metal texture, I want to access its data from Swift by making it a float4 array (so that I can access each pixel 4 color components).

I discovered this method

相关标签:
5条回答
  • 2021-02-09 02:26

    This is a Swift 4 example of converting a literal UInt8 array to an UnsafeMutableRawPointer and back to an UInt32 array

    static func unsafePointerTest() {
        //let a : [UInt8] = [0,0,0,4,0,0,0,8,0,0,0,12]
        let a : [UInt8] = [0x04, 0x00, 0x00, 0x00,
                           0x08, 0x00, 0x00, 0x00,
                           0x0C, 0x00, 0x00, 0x00] //little endian
        //0xFF, 0xF0, 0xF0, 0x12]  //317780223 = 12F0F0FF
        let b:UnsafeMutableRawPointer = UnsafeMutableRawPointer(mutating:a)
        let bTypedPtr = b.bindMemory(to: UInt32.self, capacity: a.count/4)
        let UInt32Buffer = UnsafeBufferPointer(start: bTypedPtr, count: a.count/4)
        let output = Array(UInt32Buffer)
        print(output)
    }
    
    0 讨论(0)
  • 2021-02-09 02:40

    Details

    • Xcode 11.2.1 (11B500), Swift 5.1

    Solution

    extension UnsafeMutableRawPointer {
        func toArray<T>(to type: T.Type, capacity count: Int) -> [T]{
            let pointer = bindMemory(to: type, capacity: count)
            return Array(UnsafeBufferPointer(start: pointer, count: count))
        }
    }
    

    Usage

    var array = [1,2,3,4,5]
    let ponter = UnsafeMutableRawPointer(mutating: array)
    print(ponter.toArray(to: Int.self, capacity: array.count))
    
    0 讨论(0)
  • 2021-02-09 02:44

    First, let's assume you have a UnsafeRawPointer and a length:

    let ptr: UnsafeRawPointer = ...
    let length: Int = ...
    

    Now you want to convert that to an [float4]. First, you can convert your UnsafeRawPointer to a typed pointer by binding it to a type:

    let float4Ptr = ptr.bindMemory(to: float4.self, capacity: length)
    

    Now you can convert that to a typed buffer pointer:

    let float4Buffer = UnsafeBufferPointer(start: float4Ptr, count: length)
    

    And since a buffer is a collection, you can initialize an array with it:

    let output = Array(float4Buffer)
    

    For much more on working with UnsafeRawPointer, see SE-0138, SE-0107, and the UnsafeRawPointer Migration Guide.

    0 讨论(0)
  • 2021-02-09 02:48

    Another option is to create an array of the appropriate size and pass the address to the underlying storage to the function:

    var pixelData = Array(repeating: float4(), count: myTextureSizeInFloat4)
    pixelData.withUnsafeMutableBytes {
        texture.getBytes($0.baseAddress!, ...)
    }
    

    Inside the closure, $0 is a UnsafeMutableRawBufferPointer representing the array storage as a collection of bytes, and $0.baseAddress is a pointer to the first byte.

    0 讨论(0)
  • 2021-02-09 02:49

    To complement @VasilyBodnarchuk's answer:

    extension UnsafeMutableRawPointer {
        func toArray<T>(to type: T.Type, capacity count: Int) -> [T] {
            return Array(UnsafeBufferPointer(start: bindMemory(to: type, capacity: count), count: count))
        }
    }
    
    0 讨论(0)
提交回复
热议问题