问题
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 of MTLTexture
:
getBytes(UnsafeMutableRawPointer, bytesPerRow: Int, bytesPerImage: Int, from: MTLRegion, mipmapLevel: Int, slice: Int)
I don't know at all how to use UnsafeMutableRawPointer, how it works, and how to get the data back into a simple Swift array.
My first attempt was to create a pointer and allocate enough space like that, but I don't even know if that's what I should do:
var pointer = UnsafeMutableRawPointer.allocate(bytes: myTextureSizeInBytes, alignedTo: 0)
Then I have no idea at all of how to get this data back into a standard Swift array...
Thank you.
回答1:
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.
回答2:
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.
回答3:
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)
}
回答4:
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))
来源:https://stackoverflow.com/questions/41574498/how-to-use-unsafemutablerawpointer-to-fill-an-array