Чтобы записать в массив функции с плавающей точкой внутри функции ядра, вам необходимо предоставить в буфер аргумент буфера.Параметр должен иметь тип device float *
и иметь атрибут buffer
, указывающий, какой слот таблицы аргументов он будет занимать:
kernel void my_kernel(device float *data [[buffer(0)]],
uint threadIndex [[thread_position_in_grid]])
{
data[threadIndex] = /* calculate value for this element */;
}
Чтобы создать такой буфер в коде приложения, запросите его:быть назначенным вашим устройством Metal:
let buffer = device.makeBuffer(length: MemoryLayout<Float>.stride * dataCount,
options: [])!
На Mac вы можете создать буфер с опцией .storageModeManaged
, которая не будет автоматически синхронизировать значения, записываемые из вашего ядра, обратно в CPU-читаемая память.Вы можете использовать блитовый кодер и метод synchronize(resource:)
для копирования обратно из памяти графического процессора.В iOS управляемые буферы не существуют, и синхронизация не требуется, кроме обычной (гарантируя, что вы никогда не читаете из того же места, которое пишет кто-то другой).
Когда вы будете готовы отправить своювычислите работу, привяжите буфер в качестве аргумента вашего кодировщика команд вычисления:
computeCommandEncoder.setBuffer(buffer, offset: 0, index: 0)
Отправьте любой размер сетки, который имеет смысл, чтобы выполнить работу.Кодируйте любую другую работу, которая вам может потребоваться (включая команды синхронизации), в своем буфере команд, зафиксируйте буфер команд и убедитесь, что он завершен, прежде чем пытаться прочитать содержимое буфера.
Чтобы прочитать содержимоеbuffer, приведите содержимое буфера к UnsafeMutableBufferPointer
соответствующего типа, что позволяет вам обращаться с буфером так же, как с любым другим Sequence
:
let data = UnsafeMutableBufferPointer<Float>(start: buffer.contents().assumingMemoryBound(to: Float.self),
count:dataCount)
// iterate over elements of data or whatever...