Как использовать 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)
}
Другие вопросы по тегам