Swift 中 simd_packed 向量的对齐(与 Metal Shader 语言相比)
Alignment of simd_packed vector in Swift (vs Metal Shader language)
我无法理解 Swift 中 simd 模块中有关 simd_packed 向量的内容。我用的是float4的例子,希望有人能帮忙
我的理解是 simd_float4
是 SIMD4< Float>
和 MemoryLayout<SIMD4< Float>>.alignment = 16
(字节)的 typealias
,因此 MemoryLayout<simd_float4>.alignment = 16
。有道理。
但是下面的我不明白:simd_packed_float4
也是SIMD4<Float>
的typealias
。所以 MemoryLayout<simd_packed_float4>.alignment = 16
.
那么simd_packed_float4
中的“打包”有什么意义呢?文档中提到的“宽松对齐”在哪里?
在金属着色器语言规范(2.4 版)中(
https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf)
在 Table 2.4 (p.28) 中,它说 packed_float4
的对齐方式是 4(这也是标量类型 float 的对齐方式),所以这是一个“宽松的对齐方式”(相比之下到 16)。这本身就有意义,但我如何将其与上面的内容相协调(simd_packed_float4
是 SIMD4<Float>
和 MemoryLayout<simd_packed_float4> = 16
的类型别名)?
我实际上认为在 Swift 中使用打包类型不可能实现像这样的松散对齐。我认为 Swift 编译器无法将对齐属性带入实际的 Swift 接口。
我认为这会使 simd_packed_float4
在 Swift 中变得无用。
我做了一个 playground 来检查这个,但按预期使用它不起作用。
import simd
MemoryLayout<simd_float4>.stride
MemoryLayout<simd_packed_float4>.alignment
let capacity = 8
let buffer = UnsafeMutableBufferPointer<Float>.allocate(capacity: capacity)
for i in 0..<capacity {
buffer[i] = Float(i)
}
let rawBuffer = UnsafeMutableRawBufferPointer.init(buffer)
let readAligned = rawBuffer.load(fromByteOffset: MemoryLayout<Float>.stride * 4, as: simd_packed_float4.self)
print(readAligned)
let readUnaligned = rawBuffer.load(fromByteOffset: MemoryLayout<Float>.stride * 2, as: simd_packed_float4.self)
print(readUnaligned)
哪个会输出
SIMD4<Float>(4.0, 5.0, 6.0, 7.0)
Swift/UnsafeRawPointer.swift:900: Fatal error: load from misaligned raw pointer
如果您确实需要将未对齐的 simd_float4
向量加载或放入缓冲区,我建议只做一个扩展来按组件执行此操作,这样所有对齐都可以解决,有点像这样
extension UnsafeMutableRawBufferPointer {
func loadFloat4(fromByteOffset offset: Int) -> simd_float4 {
let x = rawBuffer.load(fromByteOffset: offset + MemoryLayout<Float>.stride * 0, as: Float.self)
let y = rawBuffer.load(fromByteOffset: offset + MemoryLayout<Float>.stride * 1, as: Float.self)
let z = rawBuffer.load(fromByteOffset: offset + MemoryLayout<Float>.stride * 2, as: Float.self)
let w = rawBuffer.load(fromByteOffset: offset + MemoryLayout<Float>.stride * 3, as: Float.self)
return simd_float4(x, y, z, w)
}
}
let readUnaligned2 = rawBuffer.loadFloat4(fromByteOffset: MemoryLayout<Float>.stride * 2)
print(readUnaligned2)
或者您甚至可以将其设为通用
我无法理解 Swift 中 simd 模块中有关 simd_packed 向量的内容。我用的是float4的例子,希望有人能帮忙
我的理解是 simd_float4
是 SIMD4< Float>
和 MemoryLayout<SIMD4< Float>>.alignment = 16
(字节)的 typealias
,因此 MemoryLayout<simd_float4>.alignment = 16
。有道理。
但是下面的我不明白:simd_packed_float4
也是SIMD4<Float>
的typealias
。所以 MemoryLayout<simd_packed_float4>.alignment = 16
.
那么simd_packed_float4
中的“打包”有什么意义呢?文档中提到的“宽松对齐”在哪里?
在金属着色器语言规范(2.4 版)中(
https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf)
在 Table 2.4 (p.28) 中,它说 packed_float4
的对齐方式是 4(这也是标量类型 float 的对齐方式),所以这是一个“宽松的对齐方式”(相比之下到 16)。这本身就有意义,但我如何将其与上面的内容相协调(simd_packed_float4
是 SIMD4<Float>
和 MemoryLayout<simd_packed_float4> = 16
的类型别名)?
我实际上认为在 Swift 中使用打包类型不可能实现像这样的松散对齐。我认为 Swift 编译器无法将对齐属性带入实际的 Swift 接口。
我认为这会使 simd_packed_float4
在 Swift 中变得无用。
我做了一个 playground 来检查这个,但按预期使用它不起作用。
import simd
MemoryLayout<simd_float4>.stride
MemoryLayout<simd_packed_float4>.alignment
let capacity = 8
let buffer = UnsafeMutableBufferPointer<Float>.allocate(capacity: capacity)
for i in 0..<capacity {
buffer[i] = Float(i)
}
let rawBuffer = UnsafeMutableRawBufferPointer.init(buffer)
let readAligned = rawBuffer.load(fromByteOffset: MemoryLayout<Float>.stride * 4, as: simd_packed_float4.self)
print(readAligned)
let readUnaligned = rawBuffer.load(fromByteOffset: MemoryLayout<Float>.stride * 2, as: simd_packed_float4.self)
print(readUnaligned)
哪个会输出
SIMD4<Float>(4.0, 5.0, 6.0, 7.0)
Swift/UnsafeRawPointer.swift:900: Fatal error: load from misaligned raw pointer
如果您确实需要将未对齐的 simd_float4
向量加载或放入缓冲区,我建议只做一个扩展来按组件执行此操作,这样所有对齐都可以解决,有点像这样
extension UnsafeMutableRawBufferPointer {
func loadFloat4(fromByteOffset offset: Int) -> simd_float4 {
let x = rawBuffer.load(fromByteOffset: offset + MemoryLayout<Float>.stride * 0, as: Float.self)
let y = rawBuffer.load(fromByteOffset: offset + MemoryLayout<Float>.stride * 1, as: Float.self)
let z = rawBuffer.load(fromByteOffset: offset + MemoryLayout<Float>.stride * 2, as: Float.self)
let w = rawBuffer.load(fromByteOffset: offset + MemoryLayout<Float>.stride * 3, as: Float.self)
return simd_float4(x, y, z, w)
}
}
let readUnaligned2 = rawBuffer.loadFloat4(fromByteOffset: MemoryLayout<Float>.stride * 2)
print(readUnaligned2)
或者您甚至可以将其设为通用