gpt4 book ai didi

rust - 如何在 Rust 中实现面向数据的设计?

转载 作者:行者123 更新时间:2023-11-29 07:47:46 25 4
gpt4 key购买 nike

背景

在游戏引擎开发中,我们通常使用面向数据的设计来优化内存和计算性能。

我们以粒子系统为例。

在粒子系统中,我们有很多粒子,每个粒子可能有几个属性,比如位置、速度等。

C++ 中的典型实现是这样的:

struct Particle {
float positionX, positionY, positionZ;
float velocityX, velocityY, velocityZ;
float mass;
// ...
};

struct ParticleSystem {
vector<Particle> particles;
// ...
};

此实现的一个问题是粒子属性相互交错。这种内存布局对缓存不友好,可能不适合 SIMD 计算。

在面向数据的设计中,我们编写以下代码:

struct ParticleAttribute {
size_t size;
size_t alignment;
const char* semantic;
};

struct ParticleSystem {
ParticleSystem(
size_t numParticles,
const ParticleAttribute* attributes,
size_t bufferSize) {
for (size_t i = 0; i < numAttributes; ++i) {
bufferSize += attributes[i].size * numParticles;
// Also add paddings to satisfy the alignment requirements.
}
particleBuffer = malloc(bufferSize);
}

uint8* getAttribute(const char* semantic) {
// Locate the semantic in attributes array.
// Compute the offset to the starting address of that attribute.
}

uint8* particleBuffer;
};

现在我们只有一个分配,每个属性都连续驻留在内存中。为了模拟粒子,我们可以编写如下代码:

symplecticEuler(ps.getAttribute("positionX"), ps.getAttribute("velocityX"), dt);

getAttribute 函数将获取特定属性的起始地址。

问题

我想知道如何在 Rust 中实现它。

我的想法是首先创建一个名为 ParticleSystem 的类,它需要几个 ParticleAttribute 来计算总缓冲区大小,然后为缓冲区分配内存。我认为这可以在 Rust 安全代码中完成。

下一步是实现getAttribute函数,它将返回对特定属性起始地址的引用。我需要你的帮助。我如何获取带有偏移量的原始地址并将其转换为所需的类型(例如 float*)并将该原始指针包装到 Rust 中的可变引用?

此外,我认为我应该将该原始指针包装到对数组的可变引用,因为我需要使用 SIMD 库通过该引用加载四个元素。我如何使用 Rust 实现这一点?


更新:提供更多关于属性的信息。属性的数量和详细信息在运行时确定。属性的类型可能会有所不同,但我认为我们只需要支持原始类型(f32、f64、ints、...)。

最佳答案

这是实现 DOD 的一种非常复杂的方式,使用运行时查找 getter 的想法让我感到畏缩。

简单的版本是简单地为每个属性分配一个内存:

struct Particles {
x: Vec<f32>,
y: Vec<f32>,
}

这需要事先知道属性。

那么获取所有 ys 就没有什么恶作剧了,它们只是坐在那里,已经打好了,等着你。


将其扩展到动态确定的属性并不那么复杂:

  • 我们可以使用HashMap<String, xxx>在运行时查找给定的属性
  • 我们可以使用enum有一个Value存储在可以采用多种形式的 HashMap 中(另一种解决方案是使用特征)

这变成了:

#[derive(Debug, Hash, PartialEq, Eq)]
enum Value {
UniformInt(i64),
UniformFloat32(f32),
UniformFloat64(f64),
DistinctInt(Vec<i64>),
DistinctFloat32(Vec<f32>),
DistinctFloat64(Vec<f64>),
}

struct Particles {
store: HashMap<String, Value>,
}

我们也可以使用 6 个散列映射...但是除非事先知道类型是什么(当唯一拥有的是字符串时),否则必须一次一个地查看所有散列映射:烦人, 浪费时间。

关于rust - 如何在 Rust 中实现面向数据的设计?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39754863/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com