Как использовать UnsafeMutableRawPointer для заполнения массива?
У меня есть металлическая текстура, я хочу получить доступ к ее данным из Swift, сделав ее массивом float4 (чтобы я мог получить доступ к каждому пикселю 4 цветовых компонента).
Я обнаружил этот метод MTLTexture
:
getBytes(UnsafeMutableRawPointer, bytesPerRow: Int, bytesPerImage: Int, from: MTLRegion, mipmapLevel: Int, slice: Int)
Я совсем не знаю, как использовать UnsafeMutableRawPointer, как он работает и как вернуть данные в простой массив Swift.
Моя первая попытка состояла в том, чтобы создать указатель и выделить достаточно места для этого, но я даже не знаю, должен ли я это делать:
var pointer = UnsafeMutableRawPointer.allocate(bytes: myTextureSizeInBytes, alignedTo: 0)
Тогда я понятия не имею, как вернуть эти данные в стандартный массив Swift...
Спасибо.
3 ответа
Во-первых, давайте предположим, что у вас есть UnsafeRawPointer
и длина:
let ptr: UnsafeRawPointer = ...
let length: Int = ...
Теперь вы хотите преобразовать это в [float4]
, Во-первых, вы можете конвертировать ваши UnsafeRawPointer
к типизированному указателю, привязав его к типу:
let float4Ptr = ptr.bindMemory(to: float4.self, capacity: length)
Теперь вы можете преобразовать это в типизированный указатель буфера:
let float4Buffer = UnsafeBufferPointer(start: float4Ptr, count: length)
А так как буфер является коллекцией, вы можете инициализировать массив с ним:
let output = Array(float4Buffer)
Для гораздо большего по работе с UnsafeRawPointer
см. SE-0138, SE-0107 и Руководство по миграции UnsafeRawPointer.
Другой вариант - создать массив соответствующего размера и передать адрес в основное хранилище функции:
var pixelData = Array(repeating: float4(), count: myTextureSizeInFloat4)
pixelData.withUnsafeMutableBytes {
texture.getBytes($0.baseAddress!, ...)
}
Внутри закрытия, $0
это UnsafeMutableRawBufferPointer
представление хранилища массива в виде коллекции байтов и$0.baseAddress
указатель на первый байт
Детали
- Xcode 11.2.1 (11B500), Swift 5.1
Решение
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))
}
}
Применение
var array = [1,2,3,4,5]
let ponter = UnsafeMutableRawPointer(mutating: array)
print(ponter.toArray(to: Int.self, capacity: array.count))
В дополнение к ответу @VasilyBodnarchuk:
extension UnsafeMutableRawPointer {
func toArray<T>(to type: T.Type, capacity count: Int) -> [T] {
return Array(UnsafeBufferPointer(start: bindMemory(to: type, capacity: count), count: count))
}
}
Это пример Swift 4 для преобразования литерального массива UInt8 в UnsafeMutableRawPointer и обратно в массив UInt32
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)
}