15 releases
Uses old Rust 2015
0.4.9 | Apr 20, 2020 |
---|---|
0.4.7 | Jan 27, 2020 |
0.4.6 | Dec 7, 2019 |
0.4.5 | Sep 22, 2019 |
0.2.0 | Sep 25, 2018 |
#145 in Graphics APIs
30 downloads per month
3MB
57K
SLoC
Lava
Wrapper to manipulate the Vulkan API in Rust more conveniently than with bindings:
- removes the need to specify the structure type when sending structures to Vulkan
- takes care of making double Vulkan calls when necessary (when retrieving a list of Vulkan objects)
- returns objects retrieved by Vulkan in a
Result
instead of requiring a user-provided pointer - allows to manipulate references, slices and options instead of pointers (in particular, allows to provide slice instead of pointer + length)
- exposes the API in an object-oriented way (e.g
instance.enumerate_physical_devices()
instead ofenumerate_physical_devices(&instance)
) - removes the extension suffix from function and data-structure names (modules are used instead)
- exposes bit flags as structures instead of integers
- provides a default value for all structures, allowing to "auto-complete" structure with optional fields using
..Default::default()
- manages the calls to
vkGetInstanceProcAddr
andvkGetDeviceProcAddr
to manipulate functions that are not exposed statically - provides a generic
create_surface
method to create surfaces
Lava is entirely generated from the C header files of Vulkan.
Current restrictions
- no way to provide allocator callbacks
- no way to set the
pNext
field of structures
Usage
[dependencies]
lava = "0.4"
Examples
This code creates a Vulkan instance, adds a debug report callback and displays the name of each GPU of the machine:
#[macro_use] extern crate lava;
use lava::*;
fn main() {
let instance = vk_create_instance(VkInstanceCreateInfo {
flags: VkInstanceCreateFlags!(),
application_info: Some(VkApplicationInfo {
application_name: Some("lava-example"),
application_version: 1,
engine_name: None,
engine_version: 1,
api_version: VkVersion(1, 0, 0),
}),
enabled_layer_names: vec![VK_LAYER_KHRONOS_VALIDATION_NAME],
enabled_extension_names: vec![VK_EXT_DEBUG_REPORT_EXTENSION_NAME]
}).expect("Failed to create instance");
let debug_report_callback = instance.create_debug_report_callback(VkDebugReportCallbackCreateInfo {
flags: VkDebugReportFlags!(error, warning),
callback: |data: VkDebugReportCallbackData| {
println!("{}", data.message);
}
}).expect("Failed to create debug callback");
let physical_devices = instance.enumerate_physical_devices()
.expect("Failed to retrieve physical devices");
for physical_device in &physical_devices {
let properties = physical_device.get_properties();
println!("{}", properties.device_name);
}
debug_report_callback.destroy();
instance.destroy();
}
This snippet shows how to create a surface from a GLFW window:
// We assume that `window` is a pointer to a GLFWwindow, as described here:
// http://www.glfw.org/docs/latest/group__vulkan.html#ga1a24536bec3f80b08ead18e28e6ae965
let surface = instance.create_surface(
|handle, allocator, surface| unsafe { glfwCreateWindowSurface(handle, window, allocator, surface) }
).expect("Failed to create surface from glfw window");
Additional usage information
Module partitionning
Data-structures are separated in multiple modules, according to their extension (KHR, EXT, etc). Data-structures that have no extension are in the lava::vk
module.
Some constants (e.g validation layer names) are located in the lava::constants
module.
Lava re-exports all the members of lava::vk
, lava::constants
, lava::ext
and lava::khr
("use lava::*
" makes all data-structures contained in these modules available without needing to prefix them).
Bit flags
Bit flags are represented as structures instead of integers. Moreover all bit flags structures have static none()
and all()
functions. The typical way of creating a bit flags structure is as following:
// Creates a structure with the `vertex` and `fragment` flag enabled, and all the others disabled
VkShaderStageFlags {
vertex: true,
fragment: true,
..VkShaderStageFlags::none()
}
Since it can be tedious to write, all bit flags structures have a macro shortcut:
// Same effect as previous snippet
VkShaderStageFlags!(vertex, fragment)
Additionally, all bit flags structures have the following methods:
let no_shader_stage = VkShaderStageFlags::none();
let all_shader_stages = VkShaderStageFlags::all();
let shader_stages = VkShaderStageFlags::from_u32(17);
let shader_stages_int = shader_stages.to_u32();
Results
When relevant, functions return a Result<T, (VkResult, T)>
. The return value is Ok(T)
if the VkResult
returned by the Vulkan function is 0.
Otherwise it's Err((VkResult, T))
. The first element of the tuple is the error code returned by the Vulkan function. The second element is, in the specific case where the VkResult
is not 0 but is not an error either (e.g when calling swapchain.acquire_next_image()
), the value produced by the function. Otherwise it's a zeroed value that will most likely crash when used.
Objects destruction and drop
Users are required to manually destroy their objects themselves, instead of Rust doing it automatically when the object is dropped. There are two reasons for that:
- In the C API some objects must not be destroyed by the user. For example, the
VkImage
objects of a swapchain are automatically destroyed when the swapchain is destroyed, and attempting to destroy them manually will produce an error. But the user is still expected to destroy theVkImage
objects that they create manually. An automatic destruction mechanism would require some context on where the object comes from, and this is out of scope. - The order in which objects are dropped has a good chance to not match the oder in which they must be destroyed, especially when structures are dropped.
Manual build
The content of the src/vulkan/
folder is generated from the vulkan_core.h
and vk.xml
files of the
Vulkan documentation repository.
If you wish to re-generate it manually, you can do (requires Node.js):
npm install
node generate.js [ --tag <version> ]
Where <version>
is a branch or tag name of the Vulkan-Docs repository (for example v1.1.80
).
If omitted, it defaults to master
.
The script will download the corresponding files in the download/
folder and generate the new source files.