Заполнение MTLBuffer 16-битными числами - PullRequest
1 голос
/ 11 июня 2019

Я заполняю MTLBuffer векторами float2. Буфер создается и заполняется так:

struct Particle {
   var position: float2
   ...
}

let particleCount = 100000
let bufferSize = MemoryLayout<Particle>.stride * particleCount
particleBuffer = device.makeBuffer(length: bufferSize)!

var pointer = particleBuffer.contents().bindMemory(to: Particle.self, capacity: particleCount)
pointer = pointer.advanced(by: currentParticles)
pointer.pointee.position = [x, y]

В моем металлическом файле доступ к буферу осуществляется следующим образом:

struct Particle {
   float2 position;
   ...
};

kernel void compute(device Particle *particles [[buffer(0)]], … ) 

Мне нужно использовать поплавки половинной точности в моем вычислительном ядре Metal. Со стороны Metal это так же просто, как указать half2 для типа данных.

Как лучше всего заполнять буфер с плавающей запятой с половиной точности на стороне процессора?

1 Ответ

0 голосов
/ 12 июня 2019

Поплавки с половинной точностью в Swift очень неудобны, так как пока нет типа Float16 (хотя был предложен ), а нестандартный тип __fp16, поддерживаемый Clang, не поддерживается полностьюлибо в Swift.

Однако, используя магию заголовков типа Punching и Bridging, вы можете объединить работоспособное решение.

Основной подход заключается в следующем:Заголовок C, объявите тип half2 с двумя uint16_t членами.Это будет наш тип хранения.Также объявите функцию, которая принимает float и записывает его так, как если бы он был __fp16 для указателя на uint16_t:

typedef struct {
    uint16_t x, y;
} half2;

static void storeAsF16(float value, uint16_t *_Nonnull pointer) { *(__fp16 *)pointer = value; }

Вернувшись в Swift, вы можете объявить typealias и использовать егов определении структуры вашей частицы:

typealias Half2 = half2

struct Particle {
    var position: Half2
}

(Здесь я печатаю от строчного типа к имени Swiftier; вы можете пропустить это и просто назвать тип Obj-C Half2, если хотите).

Вместо привязки к типу частицы, вам нужно вместо этого привязать буфер к вашему типу половинного вектора:

var pointer = particleBuffer.contents().bindMemory(to: Half2.self, capacity: particleCount)

Когда мы используем нашу служебную функцию для хранения числа с плавающей запятойбитовый шаблон для соответствующего половинного значения записывается в UInt16:

var x: UInt16 = 0
var y: UInt16 = 0
storeAsF16(1.0, &x) // 0x3c00
storeAsF16(0.5, &y) // 0x3800

Теперь, когда у нас есть правильно отформатированные половинные значения в этой паре переменных, мы можем записать их в буфер:

pointer.pointee = Half2(x: x, y: y)

Обратите внимание, что этот подход не является ни переносимым, ни безопасным, особенно потому, что Swift не дает никаких гарантий относительно структуры элементов struct.Могут быть и другие, менее громоздкие подходы;это то, что работало для меня в прошлом.

...