"simd" 前缀在 SceneKit 中是什么意思?

What does the "simd" prefix mean in SceneKit?

有一个名为 SCNNode(SIMD)SCNNode 类别,它声明了一些属性,例如 simdPositionsimdRotation 等。这些似乎是 original/normal 属性 positionrotation.

的重复属性
@property(nonatomic) simd_float3 simdPosition API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
@property(nonatomic) simd_float4 simdRotation API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));

positionsimdPosition有什么区别?前缀 "simd" 到底是什么意思?

SIMD 是一个建立在 vector types 之上的小型库,您可以从 <simd/simd.h> 导入它。它允许更具表现力和更高性能的代码。

例如使用 SIMD 你可以写

simd_float3 result = a + 2.0 * b;

而不是

SCNVector3 result = SCNVector3Make(a.x + 2.0 * b.x, a.y + 2.0 * b.y, a.z + 2.0 * b.z);

在 Objective-C 中,您不能重载方法。那就是你不能同时拥有

@property(nonatomic) SCNVector3 position;
@property(nonatomic) simd_float3 position API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));

基于 SIMD 的新 API 需要一个不同的名称,这就是 SceneKit 公开 simdPosition 的原因。

SIMD:单指令多数据

SIMD 指令允许您同时对多个值执行相同的操作

让我们看一个例子

串行方法(无 SIMD)

我们有这 4 个 Int32 值

let x0: Int32 = 10
let y0: Int32 = 20

let x1: Int32 = 30
let y1: Int32 = 40

现在我们要对 2 个 x 和 2 个 y 值求和,所以我们写

let sumX = x0 + x1 // 40
let sumY = y0 + y1 // 60

为了执行前面的 2 个 sums,CPU 需要

  1. load x0 and x1 in memory and add them
  2. load y0 and y1 in memory and add them

所以经过2次运算得到结果

我创建了一些图形来更好地向您展示这个想法

Step 1

Step 2

SIMD

现在让我们看看 SIMD 是如何工作的。 首先,我们需要以正确的 SIMD 格式存储输入值,因此

let x = simd_int2(10, 20)
let y = simd_int2(30, 40)

可以看到前面的xy都是向量。事实上 xy 都包含 2 个组件。

现在我们可以写了

let sum = x + y

让我们看看CPU为了执行前面的操作做了什么

  1. load x and y in memory and add them

就是这样!

x 的两个组件和 y 的两个组件同时处理

并行编程

我们不是谈论并发编程,而是真正的并行编程

正如您可以想象的那样,在某些操作中,SIMD 方法比串行方法快得多。

场景工具包

现在让我们看一个 SceneKit 中的例子

我们要将10添加到场景节点的所有直接后代的xyz组件中。

使用经典的串行方法我们可以写

for node in scene.rootNode.childNodes {
    node.position.x += 10
    node.position.y += 10
    node.position.z += 10
}

Here a total of childNodes.count * 3 operations is executed.

现在让我们看看如何将之前的代码转换成SIMD指令

let delta = simd_float3(10)
for node in scene.rootNode.childNodes {
    node.simdPosition += delta
}

此代码比上一个代码快得多。我不确定是快了 2 倍还是 3 倍,但相信我,它好多了。

总结

如果您需要对不同的值执行多次相同的操作,只需使用 SIMD 属性:)