15个版本 (8个破坏性)
0.9.0 | 2024年6月22日 |
---|---|
0.7.0 | 2024年1月2日 |
0.6.1 | 2023年5月9日 |
0.5.0 | 2023年3月4日 |
0.1.3 | 2022年3月16日 |
#2 in 渲染
93,131 每月下载量
用于 752 个crate(9个直接使用)
115KB
2.5K SLoC
提供了一种将数据布局到GPU缓冲区的机制,确保满足WGSL的内存布局要求。
功能
动机
手动将数据布局到GPU缓冲区可能非常繁琐且容易出错。如何确保缓冲区中的数据布局正确?如何强制执行以确保未来的更改不会破坏这种微妙的平衡?
encase
允许您在编译时确保您的类型将被正确布局。
设计
核心特质是 ShaderType
,它主要包含有关给定类型的元数据。
WriteInto
、ReadFrom
和 CreateFrom
特质分别代表类型写入缓冲区、从缓冲区读取和从缓冲区创建的能力。
大多数数据类型可以通过各自的宏实现上述特质
impl_vector!
用于向量impl_matrix!
用于矩阵impl_rts_array!
用于运行时大小数组impl_wrapper!
用于包装器ShaderType
用于结构体
结构体 UniformBuffer
、StorageBuffer
、DynamicUniformBuffer
和 DynamicStorageBuffer
是围绕底层原始缓冲区(实现 BufferRef
和/或 BufferMut
的类型)的包装器,这取决于所需的功能。它们简化了读写/创建操作。
示例
将仿射变换写入统一缓冲区
use encase::{ShaderType, UniformBuffer};
#[derive(ShaderType)]
struct AffineTransform2D {
matrix: glam::Mat2,
translate: glam::Vec2
}
let transform = AffineTransform2D {
matrix: glam::Mat2::IDENTITY,
translate: glam::Vec2::ZERO,
};
let mut buffer = UniformBuffer::new(Vec::<u8>::new());
buffer.write(&transform).unwrap();
let byte_buffer = buffer.into_inner();
// write byte_buffer to GPU
assert_eq!(&byte_buffer, &[0, 0, 128, 63, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0]);
通过从特定偏移量读取动态统一缓冲区来创建向量实例
use encase::DynamicUniformBuffer;
// read byte_buffer from GPU
let byte_buffer = [1u8; 256 + 8];
let mut buffer = DynamicUniformBuffer::new(&byte_buffer);
buffer.set_offset(256);
let vector: mint::Vector2<i32> = buffer.create().unwrap();
assert_eq!(vector, mint::Vector2 { x: 16843009, y: 16843009 });
从存储缓冲区写入和读取数据
use encase::{ShaderType, ArrayLength, StorageBuffer};
#[derive(ShaderType)]
struct Positions {
length: ArrayLength,
#[size(runtime)]
positions: Vec<mint::Point2<f32>>
}
let mut positions = Positions {
length: ArrayLength,
positions: Vec::from([
mint::Point2 { x: 4.5, y: 3.4 },
mint::Point2 { x: 1.5, y: 7.4 },
mint::Point2 { x: 4.3, y: 1.9 },
])
};
let mut byte_buffer: Vec<u8> = Vec::new();
let mut buffer = StorageBuffer::new(&mut byte_buffer);
buffer.write(&positions).unwrap();
// write byte_buffer to GPU
// change length on GPU side
byte_buffer[0] = 2;
// read byte_buffer from GPU
let mut buffer = StorageBuffer::new(&mut byte_buffer);
buffer.read(&mut positions).unwrap();
assert_eq!(positions.positions.len(), 2);
将不同数据类型写入动态存储缓冲区
use encase::{ShaderType, DynamicStorageBuffer};
let mut byte_buffer: Vec<u8> = Vec::new();
let mut buffer = DynamicStorageBuffer::new_with_alignment(&mut byte_buffer, 64);
let offsets = [
buffer.write(&[5.; 10]).unwrap(),
buffer.write(&vec![3u32; 20]).unwrap(),
buffer.write(&glam::Vec3::ONE).unwrap(),
];
// write byte_buffer to GPU
assert_eq!(offsets, [0, 64, 192]);
也支持写入未初始化的内存。
use std::mem::MaybeUninit;
use encase::{ShaderType, DynamicStorageBuffer};
let mut uninit_buffer: Vec<MaybeUninit<u8>> = Vec::new();
let mut buffer = DynamicStorageBuffer::new_with_alignment(&mut uninit_buffer, 64);
let offsets = [
buffer.write(&[5.; 10]).unwrap(),
buffer.write(&vec![3u32; 20]).unwrap(),
buffer.write(&glam::Vec3::ONE).unwrap(),
];
// SAFETY: Vec<u8> and Vec<MaybeUninit<u8>> share the same layout.
let byte_buffer: Vec<u8> = unsafe {
Vec::from_raw_parts(
uninit_buffer.as_mut_ptr().cast(),
uninit_buffer.len(),
uninit_buffer.capacity()
)
};
std::mem::forget(uninit_buffer);
// write byte_buffer to GPU
assert_eq!(offsets, [0, 64, 192]);
依赖关系
~0.5–4MB
~90K SLoC