6个版本
新增 0.0.6 | 2024年8月23日 |
---|---|
0.0.5 | 2024年8月10日 |
0.0.4 | 2024年7月28日 |
83 在 图形API 中排名
272 每月下载量
4MB
102K SLoC
非官方的Vulkan图形API绑定
目标是提供一种优雅且安全的方式使用Rust进行Vulkan编程,在大多数情况下没有额外的开销。
这些绑定试图在Rust上复现使用官方的Vulkan C++绑定的体验,这使得它与流行的Vulkan crate ash有所不同。
特性
安全性
Vulkan句柄可以被看作是对Vulkan对象的引用。因此,使用这个crate,Vulkan句柄不能为NULL(没有vk::NULL_HANDLE值),分配句柄意味着你可以假设它不为空且有效。所有以前接受null句柄参数的vulkan函数现在接受一个Option<Handle>
参数。
关于命令安全性,我决定采用与cxx
crate类似的方法:在rust和Vulkan API/驱动代码(可能用C编写)的边界处保证安全性。这些绑定还试图确保任何可以被检查符合Vulkan规范而几乎不增加成本(编译时运行)的事情都是这样做的。
当使用Vulkan API时,将调用驱动代码,这可能是专有的,并且你对它没有控制权。即使你完全遵循Vulkan规范并且没有验证错误,你仍然可能在某些GPU/驱动程序上运行程序时遇到一些意外的段错误(我根据经验说的)。因此,第一个解决方案是使每个vulkan命令或函数调用一个不安全的vulkan命令,但在我看来这是适得其反的。我选择保持大多数Vulkan命令的安全性。例外的是销毁命令,你必须确保你要销毁的所有创建的东西都已经销毁。
请注意,这些绑定假定驱动程序实现至少符合Vulkan规范。特别是如果驱动程序返回一个完全未知的 VkStatus
状态码(规范不允许),这将导致Rust代码中的未定义行为。
智能句柄
与C++绑定类似,此绑定按照执行它的句柄将Vulkan命令分组。因此,在ash上的代码
unsafe {
device.begin_command_buffer(
&vk::CommandBufferBeginInfo::default()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT)
)
...
swapchain_khr.queue_present_khr(queue, &present_info)?;
}
变为
cmd_buffer.begin(
&vk::CommandBufferBeginInfo::default()
.flags(vk::CommandBufferUsageFlags::OneTimeSubmit)
)?;
queue.present_khr(&present_info)?;
结果
将Vulkan的 VkResult
枚举重命名为 vk::Status(这是与C绑定名称不同的唯一枚举/结构)。相反,vk::Result<A>
被定义为 [Result<A, vk::Status>],并且所有在规范中返回Result的Vulkan命令现在返回一个 vk::Result。
let device = instance.create_device(&device_info)?;
此外,如果Vulkan命令可以返回多个成功代码,状态将作为结果的一部分
let (status, image_idx) = self.device.acquire_next_image_khr(
&self.swapchain_objects.swapchain,
u64::MAX,
Some(semaphore),
None, // not signaling any fence
)?;
if status == vk::Status::vk::Status::SuboptimalKHR {
...
}
切片
现在,每个接受长度和原始指针作为输入的Vulkan命令或结构都接受切片作为输入。如果长度用于多个原始指针,则必须一起输入匹配的切片,并检查它们具有相同的长度。
impl CommandBuffer {
pub fn set_viewport(&self, first_viewport: u32, viewports: impl AsSlice<vk::Viewport>);
}
cmd_buffer.set_viewport(0, &[vk::Viewport{..}, vk::Viewport{..}])
let color_attachment = vec![...];
let resolve_attachment = vec![...];
let subpass_description = vk::SubpassDescription::default()
// the resolve attachment field is optional for SubpassDescription
// but if it is supplied it must have the same length as color_attachment
.color_attachment(&color_attachment, Some(&resolve_attachment))
....;
数组作为命令输出
对于返回数组(长度指针和数据指针)的Vulkan命令,现在可以使用实现[DynamicArray](对于智能句柄的情况为[AdvancedDynamicArray])的任何结构作为输出。这是[Vec]的情况
let surface_formats : Vec<_> = physical_device.get_surface_formats_khr(Some(surface))?;
需要添加 : Vec<_>
的原因是在使用 smallvec
功能时,可以进行以下操作
// won't make any heap allocation if you have less than 3 GPUs
let physical_devices: SmallVec<[_; 3]> = instance.enumerate_physical_devices()?;
请注意,vk::Status::Incomplete 的情况由实现处理:您可以将 vk::Status::Incomplete 假定为永远不会返回
结构链作为命令输出
如果Vulkan命令返回一个可以扩展的结构,可以使用元组来指定要插入哪个结构
let (vk_props, vk11_props) : (_, vk::PhysicalDeviceVulkan11Properties) = physical_device.get_properties2();
println!("Max supported API is {}, Subgroup size is {}", vk_props.properties.api_version, vk11_props.subgroup_size);
如果您不想使用结构链,您有以下两种选择(在默认情况下无法显式推断类型)
let vk_props: vk::PhysicalDeviceProperties2 = physical_device.get_properties2();
let (vk_props,) = physical_device.get_properties2();
请注意,结构链的完整性在编译时进行检查:以下代码将导致编译错误 ::PhysicalDeviceVulkan11Features] 不能在头部为 vk::PhysicalDeviceFeatures 的结构链中使用)
let (_, _) : (_, vk::PhysicalDeviceVulkan11Features) = physical_device.get_properties2();
此编译时检查也适用于下一部分
结构链作为命令输入
构建结构链的第一种可能的方法是使用 structure.push_next(&mut next_structure)
。还提供了一些宏,以类似于C++绑定的方式执行相同操作
let mut device_info = vk_headers::structure_chain!(
vk::DeviceCreateInfo::default()
.queue_create_infos(&queue_info)
.enabled_features(Some(&features))
.enabled_extension(&required_extensions),
vk::PhysicalDeviceShaderObjectFeaturesEXT::default().shader_object(true)
);
if does_not_support_extension {
device_info.unlink::<vk::PhysicalDeviceShaderObjectFeaturesEXT>()
}
if does_not_support_feature {
device_info.get_mut::<vk::PhysicalDeviceShaderObjectFeaturesEXT>().shader_object(false);
}
let device = physical_device.create_device(device_info.as_ref())?;
特性
以下功能可用:
loaded
:允许crate使用libloading
crate动态加载Vulkan库,请参阅 Dispatcher::new_loadedsmallvec
:添加对smallvec crate的支持以最小化堆分配,启用此功能允许以下操作:let physical_devices: SmallVec<[_; 3]> = instance.enumerate_physical_devices()?;
。raw-window-handle
:添加与raw-window-handle crate的互操作性,用于从原始句柄创建表面,请参阅[窗口]模块
MSRV
该crate当前最低支持的Rust版本是1.77(C-字符串字面量使用频繁)。计划在不久的将来提高此版本,如果发生这种情况,将选择一个合理的(至少6个月前)MSRV。
请注意,这些绑定仍在进行中,如果这提高了安全性或使代码更易于使用,公共API可能会看到破坏性变化。
请务必注意,这个crate尚未准备好投入生产,未来版本可能会出现破坏性变化。
依赖关系
~0–5MB