Swift 中 simd_packed 向量的对齐vs Metal Shader 语言

问题描述

我无法理解 Swift 中 simd 模块中的 simd_packed 向量。我用的是float4的例子,希望有人能帮忙。

我的理解是,simd_float4typealiasSIMD4< Float>(字节)的 MemoryLayout<SIMD4< Float>>.alignment = 16,因此是 MemoryLayout<simd_float4>.alignment = 16。有道理。

但以下我不明白:simd_packed_float4 也是 typealiasSIMD4<Float>。所以MemoryLayout<simd_packed_float4>.alignment = 16

那么 simd_packed_float4 中的“打包”有什么意义?文档中提到的“宽松对齐”在哪里?

Metal Shader Language Specification(2.4 版)中( https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf) 在表 2.4 (p.28) 中,它说 packed_float4 的对齐是 4(这也是标量类型,float 的对齐),所以这是一个“宽松对齐”(与 16 相比) .这本身就很有意义,但我如何将其与上述内容相协调(simd_packed_float4SIMD4<Float>MemoryLayout<simd_packed_float4> = 16 的类型别名)?

解决方法

我实际上认为在 Swift 中使用打包类型来实现这样的宽松对齐是不可能的。我认为 Swift 编译器无法将对齐属性带到实际的 Swift 接口中。

我认为这使得 simd_packed_float4 在 Swift 中毫无用处。

我制作了一个操场来检查这一点,但按预期使用它是行不通的。

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)

或者你甚至可以让它通用

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...