我正在用float2向量填充MTLBuffer。缓冲区的创建和填充如下:
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]
在我的Metal文件中,缓冲区的访问方式如下:
struct Particle {
float2 position;
...
};
kernel void compute(device Particle *particles [[buffer(0)]], … )
我需要在我的Metal计算内核中使用半精度浮点数。在Metal方面,只需为数据类型指定half2即可。
在CPU端,用半精度浮点数填充缓冲区的最佳方法是什么?
答案 0 :(得分:0)
Swift中的半精度浮点数非常笨拙,因为还没有Float16
类型(尽管one has been proposed)并且Clang不完全支持Clang支持的非标准__fp16
类型还是斯威夫特。
但是,通过类型绑定和桥接标头的魔力,您也许可以拼凑出一个可行的解决方案。
基本方法是:在Objective-C标头中,声明一个带有两个half2
成员的uint16_t
类型。这些将是我们的存储类型。还声明一个接受浮点数的函数,并将其写为好像指向{{1}的指针的__fp16
:
uint16_t
在Swift中,您可以声明一个类型别名并在您的粒子结构定义中使用它:
typedef struct {
uint16_t x, y;
} half2;
static void storeAsF16(float value, uint16_t *_Nonnull pointer) { *(__fp16 *)pointer = value; }
(在这里,我将小写字母类型别名化为Swiftier名称;如果愿意,可以跳过此名称,而仅将Obj-C类型命名为typealias Half2 = half2
struct Particle {
var position: Half2
}
。)
代替绑定粒子类型,您需要将缓冲区绑定到半矢量类型:
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
请注意,这种方法既不可移植也不安全,特别是因为Swift不能对结构成员的布局做任何保证。也许还有其他不那么麻烦的方法。这就是过去对我有用的。