13 个稳定版本
2.2.1 | 2021 年 7 月 9 日 |
---|---|
2.2.0 | 2021 年 3 月 9 日 |
2.0.3 | 2020 年 4 月 4 日 |
2.0.2 | 2020 年 2 月 25 日 |
0.1.9 |
|
#96 在 图形 API
79 每月下载量
125KB
3K SLoC
vkgen
从 Vulkan/OpenXR 注册表中生成 Rust 源代码。
一般信息
许可证
本软件遵循 MIT 许可。
依赖和需求
Rust 版本
已测试生成代码的最新 Rust 版本为 1.40 和 1.42-nightly。
Cargo Crates
log
用于日志记录。
libloading
用于加载 Vulkan/OpenXR 共享库,但生成的代码可以轻松修改以使用其他内容。
生成器本身仅使用 serde
解析注册表。
环境(共享库等)
编译和运行生成的代码不需要 C/C++ 头文件/源代码或任何二进制文件,只需 Vulkan/OpenXR 共享库。(Linux 上的 libvulkan.so
和 Win32 上的 vulkan-1.dll
)
其他
使用生成的代码不需要其他依赖项,如果代码无法编译或运行时崩溃,并且可以排除 API 使用错误,请在 Gitlab 上提交问题。
用法
$ vkgen <input file (optional)> [options]
如果没有指定输入文件,则将从 stdin
读取注册表。
选项
--help
,-h
显示帮助页面--out=<输出文件>
,-o=<输出文件>
指定输出文件。如果没有指定输出文件,则生成的代码将写入<input file>.rs
--out-cargo=<输出货物文件>
,-oc=<输出货物文件>
指定输出货物文件。如果没有指定输出文件,生成的代码将写入<输入文件>.toml
示例
$ vkgen ./vk.xml
# specify output files
$ vkgen ./vk.xml -out=vk.rs -out-cargo=vk.toml
# download the Vulkan registry and pipe it to vkgen
$ wget -qO- https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/registry/vk.xml | vkgen
# download the OpenXR regsitry and pipe it to vkgen
$ wget -qO- https://raw.githubusercontent.com/KhronosGroup/OpenXR-SDK-Source/master/specification/registry/xr.xml | vkgen
更改库加载方法
如果您不想使用libloading,请从生成的toml文件中删除依赖项,并编辑vkInit
/xrInit
以使用您首选的方法加载函数指针。
详细信息
函数加载
当静态函数(不需要传递可分发的句柄的函数)首次被调用时,Vulkan/OpenXR共享库在vkInit
/xrInit
中加载。要使用非静态函数,需要将可分发的句柄用VkXxxImpl::new(handle)
或XrXxxImpl::new(handle)
包装。
包装结构体
方法
为所有可分发的句柄生成包装结构体,包含一个函数表或指向其父句柄的函数表。当调用包装方法时,将调用函数表中的等效函数。包装方法的签名仅在切片参数上与表中的不同,其中表中的函数接受指针和长度,而包装方法接受切片,以提供一些安全性。不提供其他安全保护。
方法表
特殊的包装器VkInstanceImpl
、VkDeviceImpl
和XrInstanceImpl
将在创建时填充一个表,其中包含通过vkGetInstanceProcAddr
、vkGetDeviceProcAddr
和xrGetInstanceProcAddr
获得的函数指针。
其他
所有包装结构体都实现了Debug
用于调试目的显然,以及Deref
/DerefMut
,以访问包装的句柄。表条目不是pub
,因此不能访问,只能通过包装方法。
结构体和枚举
所有结构体和枚举都实现了Copy
、Clone
、Default
和Debug
以方便使用。
常见错误
使用指向数组的指针成员初始化结构体可能会导致未定义的行为
// never do this
VkSomeStruct {
arrayLen: 0,
pArray: [
// some elements
].as_ptr() // <-- the slice will be dropped here, as it is no longer required,
// this sometimes only happens when the release target is built
// and is thus very hard to debug
};
// always do this
let array = [
// some elements
];
VkSomeStruct {
arrayLen: array.len() as _,
pArray: array.as_ptr() // the slice is not dropped, because the declaration
// is in the outer scope
};
枚举位字段
由于一些枚举代表可以组合的位字段中的位,因此变体必须转换为u32
才能使用。
VK_SOME_ENUM_VARIANT1_BIT as u32 | VK_SOME_ENUM_VARIANT2_BIT as u32
结构体位字段
Vulkan注册表的较新版本包含具有C位字段的结构的版本。由于Rust不支持此类位字段,这些结构体生成不正确,因此不应使用。截至2021年3月,只有VkAccelerationStructureInstanceKHR
受到影响。
VkResult
枚举VkResult
和XrResult
实现了Error
和ops::Try
,这意味着它们可以使用?
运算符。要利用此功能,需要一个夜间编译器,并且必须启用try_trait
功能。
#![feature("try_trait")]
...
VkInstanceImpl::create(&info, allocator, &mut instance)?; // <-- returns early if the result was an error
版本和扩展
几乎每个命令都有一个 #[cfg(feature = "VK_VERSION_X_X")]
或 #[cfg(feature = "VK_SOME_FEATURE_KHR"")]
属性,这意味着要使用此命令,必须启用某个功能。Vulkan API 的版本 VK_VERSION_1_0
、VK_VERSION_1_1
和 VK_VERSION_1_2
默认启用。
常量
常量的类型将通过查看其值来推断。如果生成器无法推断类型,则将使用 u32
。这可能会导致具有错误类型的常量,从而阻止它们传递给函数或用于结构体。在这种情况下,请在 Gitlab 上提交一个问题。
使用字符串
Vulkan/OpenXR 中的所有字符串都是空终止的 *const u8
。包装器不会在 Rust 和 Vulkan 的字符串表示之间进行转换,所有传递给或从函数或结构体返回的字符串都必须由用户转换。
示例
以下简单示例演示了如何输出实例版本(1.1.0)并创建一个实例。vk.rs 是包含生成的 Rust 源代码的文件。在第一次方法调用时(在这种情况下为 VkInstanceImpl::enumerateVersion
)将加载共享库。
Cargo.toml
[package]
name = "vkgen_test"
version = "0.1.0"
authors = ["tobias"]
edition = "2018"
[features]
default = ["VK_VERSION_1_0", "VK_VERSION_1_1"]
VK_VERSION_1_0 = []
VK_VERSION_1_1 = []
...
[dependencies]
libloading = "0.5.0"
main.rs
mod vk;
use self::vk::*;
use std::ptr::null;
fn main() {
let mut v: u32 = 0;
VkInstanceImpl::enumerateVersion(&mut v);
println!("vulkan instance version is {}.{}.{}", VK_VERSION_MAJOR(v), VK_VERSION_MINOR(v), VK_VERSION_PATCH(v));
let instance_info = VkInstanceCreateInfo {
sType: VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
pNext: null(),
flags: 0,
pApplicationInfo: &VkApplicationInfo {
sType: VK_STRUCTURE_TYPE_APPLICATION_INFO,
pNext: null(),
pApplicationName: "test app\0".as_ptr(),
applicationVersion: VK_MAKE_VERSION(0, 0, 1),
pEngineName: "test engine\0".as_ptr(),
engineVersion: VK_MAKE_VERSION(0, 0, 1),
apiVersion: VK_MAKE_VERSION(1, 1, 0),
},
enabledLayerCount: 0,
ppEnabledLayerNames: null(),
enabledExtensionCount: 0,
ppEnabledExtensionNames: null()
};
let mut instance = VK_NULL_HANDLE;
if VkInstanceImpl::create(&instance_info, null(), &mut instance) != VK_SUCCESS {
panic!("something went wrong :-/");
};
let instance = unsafe { VkInstanceImpl::new(instance) };
}
依赖项
~0.4–1MB
~23K SLoC