2 unstable releases
0.2.0 | Feb 24, 2019 |
---|---|
0.1.0 | Feb 3, 2019 |
#377 in Graphics APIs
Used in 2 crates
(via nobs-vulkanism-headless)
1MB
16K
SLoC
nobs-vkmem
Vulkan memory management as extension to nobs-vk.
Motivation
Buffer and image creation in vulkan is tricky in comparison to e.g. OpenGL, because
- We have to create the buffer/image and then later bind it to a
vkDeviceMemory
that has to be created separately. - Creating a single
vkDeviceMemory
allocation for every buffer/image is bad practice, in fact it is encouraged to bind resources that are used together on the same allocation. - Another layer of difficulty is introduced with memory types, since not all resources (should) share the same memory properties - which is different for each Driver/Vendor
Features
nobs-vkmem provides convenient and accessible methods for creating buffers and images and binding them to physical memory. This dramatically reduces boiler plate code, while still offers the user considerable control over how resources are bound to memory.
- Easy buffer and image creation with builder patterns.
- Device memory is allocated in larger pages. The library keeps track of free and used regions in a page.
- Offers different allocation strategies for different purposes, including forcing the binding of several resources to a continuous block, or binding resources on private pages.
- Easy mapping of host accessible buffers
Documentation
Find a complete documentation of this library at docs.rs.
Example Usage
// create an allocator with default page size
// (128MiB for device local / 8MB for host visible memory)
let mut allocator = vkmem::Allocator::new(physical_device_handle, device_handle);
// declare handles
let mut buf_ub = vk::NULL_HANDLE;
let mut img = vk::NULL_HANDLE;
let mut bb = vk::NULL_HANDLE;
// configure
vkmem::Buffer::new(&mut buf_ub)
.size(std::mem::size_of::<Ub>() as vk::DeviceSize)
.usage(vk::BUFFER_USAGE_TRANSFER_DST_BIT | vk::BUFFER_USAGE_UNIFORM_BUFFER_BIT)
.devicelocal(false)
.next_image(&mut img)
.image_type(vk::IMAGE_TYPE_2D)
.size(123, 123, 1)
.usage(vk::IMAGE_USAGE_SAMPLED_BIT)
.next_buffer(&mut bb)
.size(123 * std::mem::size_of::<u32>() as vk::DeviceSize)
.usage(vk::BUFFER_USAGE_TRANSFER_DST_BIT | vk::BUFFER_USAGE_STORAGE_BUFFER_BIT)
// binds all configured resources in bulk using as less blocks of memory as possible.
// But allows to split resources of the same memory type to be scattered to multiple blocks
// on the same page, if no large enough free block is found
.bind(&mut allocator, vkmem::BindType::Scatter)
.unwrap();
// Mapped gives a convenient view on the memory
{
let mapped = allocator.get_mapped(buf_ub).unwrap();
let ubb = Ub { a: 123, b: 4, c: 5 };
mapped.host_to_device(&ubb);
// going out of scope automatically unmapps...
}
{
let mapped = allocator.get_mapped(buf_ub).unwrap();
let mut ubb = Ub { a: 0, b: 0, c: 0 };
mapped.device_to_host(&mut ubb);
println!("{:?}", ubb);
}
// we can print stats in a yaml format for the currently allocated pages
println!("{}", allocator.print_stats());
// buffers and images can be destroyed
// destroy_many() should be preferred over destroy(),
// because this will rearrange and merge allocated blocks into the free list again
allocator.destroy_many(&[buf_ub, img]);
// destroying does NOT free memory
// if we want to free memory we can do this only, if a whole page is not used any more
// in this case we can free the memory again
allocator.free_unused();
Contributing
Feel encouraged to contribute, in any way you can think!