#memory-allocator #memory #memory-block #memory-management #memory-pool #vulkan #allocator

vma

Rust ffi绑定和AMD Vulkan内存分配器(VMA)的惯用包装

2个版本

0.4.0 2023年5月27日
0.3.1 2023年7月4日
0.3.0 2023年5月27日

#26 in 渲染引擎

MIT/Apache

310KB
3K SLoC

vk-mem

vk-mem on travis-ci.com Latest version Documentation Lines of Code MIT APACHE2

这是一个由@gwihlidal创建的vk-mem-rs的分支,它最初发布在crates.io上,名称为vma

此crate为优秀的AMD Vulkan内存分配器(VMA)C/C++库提供FFI层和惯用Rust包装。

问题

由于以下原因,在Vulkan中进行内存分配和资源(缓冲区和图像)创建比旧的图形API(如D3D11或OpenGL)困难:

  • 它需要大量的样板代码,就像Vulkan中的所有其他内容一样,因为它是一个低级和高性能API。
  • 存在额外的间接层次:VkDeviceMemory是独立于创建VkBuffer/VkImage分配的,并且它们必须绑定在一起。绑定之后不能更改 - 资源必须重新创建。
  • 必须查询驱动程序以获取支持的内存堆和内存类型。不同的IHVs提供不同类型的内存。
  • 建议分配更大的内存块,并将它们的部分分配给特定的资源。

功能

此crate通过提供一些高级函数来帮助游戏开发者管理内存分配和资源创建:

  • 帮助选择正确的和最优内存类型的函数,基于内存的预期使用。
    • 与Vulkan标志相比,使用更高层次的描述来表达内存所需或首选的特质。
  • 分配内存块、预留并返回其中的一部分(VkDeviceMemory + 偏移量 + 大小)给用户的函数。
    • 库跟踪分配的内存块、其中使用和未使用的范围,为新分配找到最佳匹配的未使用范围,尊重所有对齐和缓冲区/图像粒度的规则。
  • 一次调用即可创建图像/缓冲区、为其分配内存并将其绑定在一起的功能。

附加功能

  • 跨平台
    • Windows
    • Linux
    • macOS (MoltenVK)
  • 经过良好测试和文档化的API
    • 基础库被包含在多个商业游戏标题中。
    • 详尽的文档(包括VMA仓库中的完整算法描述)
  • 支持自定义内存池
    • 创建具有所需参数的池(例如,固定或限制最大大小)
    • 从其中分配内存。
    • 支持线性或伙伴分配策略
    • 创建具有线性算法的池并用于更快的分配和释放,一次释放、堆栈、双堆栈或环形缓冲区。
  • 详细统计
    • 全局、每个内存堆栈和每种内存类型。
    • 使用的内存量
    • 未使用的内存量
    • 已分配块的数量
    • 分配次数
    • 等等。
  • 调试注释
    • 将字符串与名称或与您自己的数据的不透明指针关联到每次分配。
  • JSON转储
    • 获取一个字符串,以JSON格式详细映射内部状态,包括分配列表以及它们之间的间隙。
    • 将此JSON转储转换为图片以可视化您的内存。请参阅tools/VmaDumpVis
  • 支持内存映射
    • 内部引用计数。
    • 支持持久映射内存;只需使用适当的标志进行分配,即可获得映射指针的访问权限。
  • 支持碎片化分配
    • 调用一个函数,让库移动数据,以释放一些内存块并使您的分配更紧凑。
  • 支持丢失的分配
    • 使用适当的标志分配内存,并让库删除长时间未使用的分配,为新分配腾出空间。
  • 支持非一致性内存和刷新分配
    • nonCoherentAtomSize自动受到尊重。
  • 尝试检测不正确的映射内存使用
    • 启用对所有分配的内存进行位模式初始化,以检测未初始化或已释放内存的使用。
    • 在每次分配前后启用验证魔数,以检测越界内存损坏。

计划中的功能

  • 广泛的单元测试和示例。
    • 一些单元测试,但不是全覆盖
    • 示例尚未编写 - 很可能将VMA示例迁移到ashvk_mem
  • 记录和回放分配,以深入了解内存使用、资源转换等
    • 检查正确性、测量性能并收集统计信息。

示例

此crate的基本用法非常简单;高级功能是可选的。

在创建一个vk_mem::Allocator实例后,创建缓冲区需要的代码很少

// Create the buffer (GPU only, 16KiB in this example)
let create_info = vk_mem::AllocationCreateInfo {
    usage: vk_mem::MemoryUsage::GpuOnly,
    ..Default::default()
};

let (buffer, allocation, allocation_info) = allocator
    .create_buffer(
        &ash::vk::BufferCreateInfo::builder()
            .size(16 * 1024)
            .usage(ash::vk::BufferUsageFlags::VERTEX_BUFFER | ash::vk::BufferUsageFlags::TRANSFER_DST)
            .build(),
        &create_info,
    )
    .unwrap();

// Do stuff with buffer! (type is ash::vk::Buffer)

// Destroy the buffer
allocator.destroy_buffer(buffer, &allocation).unwrap();

通过此单个函数调用(vk_mem::Allocator::create_buffer

  • ash::vk::BufferVkBuffer)被创建。
  • 如果需要,将分配ash::vk::DeviceMemoryVkDeviceMemory)块。
  • 内存块的一个未使用区域绑定到该缓冲区。
  • vk_mem::Allocation被创建,表示分配给该缓冲区的内存。它可以查询参数,如Vulkan内存句柄和偏移量。

MoltenVK

对于macOS上的MoltenVK,您需要设置正确的环境变量。例如

export SDK_PATH=/path/to/vulkansdk-macos-1.1.106.0
export DYLD_LIBRARY_PATH=$SDK_PATH/macOS/lib
export VK_ICD_FILENAMES=$SDK_PATH/macOS/etc/vulkan/icd.d/MoltenVK_icd.json
export VK_LAYER_PATH=$SDK_PATH/macOS/etc/vulkan/explicit_layer.d
cargo test

用法

将此添加到您的Cargo.toml

[dependencies]
vma = "0.4.0"

并将其添加到您的crate根目录下

extern crate vma;

使用MinGW W64进行编译

Vulkan内存分配器需要C++11线程。MinGW W64默认不支持这些,因此您需要切换到posix构建。例如,在debian上,您需要运行以下命令

update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix
update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
update-alternatives --set i686-w64-mingw32-gcc /usr/bin/i686-w64-mingw32-gcc-posix
update-alternatives --set i686-w64-mingw32-g++ /usr/bin/i686-w64-mingw32-g++-posix

许可证

根据以下之一进行许可

任选其一。

致谢及特别感谢

贡献

除非您明确说明,否则您根据Apache-2.0许可证提交的任何有意包含在此crate中的贡献,应如上所述双许可,无需任何附加条款或条件。

欢迎贡献;请查看问题跟踪器了解已记录的已知改进。

行为准则

根据贡献者公约组织对vma crate的贡献,vk-mem的维护者@Neo-Zhixing承诺将介入以维护该行为准则。

依赖项

~5.5MB
~133K SLoC