[][src]Struct nobs_vkmem::Allocator

pub struct Allocator { /* fields omitted */ }

Allocator for buffer and image resources

Manages device memory for a single device. The actual memory is managed for each memory type separately by a page table. Pages are allocated lazyly, as soon as memory is needed. The pagesizes may be specified in the AllocatorSizes.

When the Allocator is dropped, all buffers and allocated device momory is freed.

Example

The Allocator is created from a device handle and it's associated physical device. Buffers and images can be easyly created with the Buffer and Image builder. Host accessible buffers can be conveniently accessed with get_mapped / get_mapped_region and Mapped. Allocated resources may be freed with destroy(_many). Memory of pages that have no bore resource binding can be freed with free_unused again.

extern crate nobs_vk as vk;
extern crate nobs_vkmem as vkmem;

struct Ub {
  a: u32,
  b: u32,
  c: u32,
}


// create an allocator with default page size
// (128MiB for device local / 8MB for host visible memory)
let mut allocator = vkmem::Allocator::new(pdevice.handle, device.handle);

// declare handles
let mut buf_ub = vk::NULL_HANDLE;
let mut buf_out = vk::NULL_HANDLE;
let mut img = vk::NULL_HANDLE;
let mut bb = vk::NULL_HANDLE;

// configure create infos
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)
  .new_buffer(&mut buf_out)
  .size(123 * std::mem::size_of::<u32>() as vk::DeviceSize)
  .usage(vk::BUFFER_USAGE_TRANSFER_DST_BIT | vk::BUFFER_USAGE_STORAGE_BUFFER_BIT)
  .devicelocal(false)
  .new_image(&mut img)
  .image_type(vk::IMAGE_TYPE_2D)
  .size(123, 123, 1)
  .usage(vk::IMAGE_USAGE_SAMPLED_BIT)
  .devicelocal(true)
  .new_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)
  .devicelocal(true)

  // this will create the image/buffers and bind them to memory
  .bind(&mut allocator, vkmem::BindType::Scatter)
  .unwrap();

// Mapped gives a convenient view on the memory
// get_mapped mapps the whole block of memory to which the resources was bound
// get_mapped_region lets us define a byte offset respective to the beginning of the resource and a size in bytes
{
  let mapped = allocator.get_mapped(buf_ub).unwrap();
  let ubb = Ub { a: 123, b: 4, c: 5 };
  mapped.host_to_device(&ubb);
}
{
  let mapped = allocator.get_mapped(buf_ub).unwrap();
  let mut ubb = Ub { a: 0, b: 0, c: 0 };
  mapped.device_to_host(&mut ubb);
}

{
  let mapped = allocator.get_mapped_region(buf_out, 4, 100).unwrap();
  let v = mapped.as_slice::<u32>();
}

// we can print stats in a yaml format for the currently allocated pages
println!("{}", allocator.print_stats());

// buffers and images can be destroyed
allocator.destroy(img);
allocator.destroy_many(&[buf_ub, buf_out]);

// 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();

// dropping the allocator automatically destroys bound resources and frees all memory

Methods

impl Allocator[src]

pub fn get_min_pagesize(pdevice: PhysicalDevice) -> DeviceSize[src]

Gets the smallest pagesize for the specified physical device

The minimum page size is defined through the bufferImageGranularity of the physical device properties

Arguments

  • pdevice - physical device handle

Returns

The minimum pagesize in bytes.

pub fn get_memtype(
    pdevice: PhysicalDevice,
    requirements: &MemoryRequirements,
    properties: MemoryPropertyFlags
) -> Option<u32>
[src]

Get the memtype for a combination of memory requirements and properties

Arguments

  • pdevice - physical device handle
  • requirements - memory reqirements retrieved with vk::GetBufferMemoryRequirements or vk::GetBufferMemoryRequirements
  • properties - combination of vk::MemoryPropertyFlagBits

Returns

  • Some(memtype) - where memtype is the memory type index
  • None - if there no such a combination of memory requirements and properties exists on the physical device

pub fn new(pdevice: PhysicalDevice, device: Device) -> Allocator[src]

Creates an Allocator

The Allocator will use the default AllocatorSizes, with 128MiB / 8MiB pagesizes for device local / host accessible memory.

Arguments

  • pdevice - physical device handle
  • device - device handle

pub fn with_sizes(device: Device, sizes: AllocatorSizes) -> Allocator[src]

Creates an Allocator from AllocatorSizes

The AllocatorSizes will consumed by the consturctor. This allows additional configuration of the pagesizes for every memory type.

Arguments

  • device - device handle
  • sizes - AllocatorSizes with the physical device handle and pagesize definitions

Example

Creates an Allocator with 32MiB large pages for host accassable memory

let mut sizes = vkmem::AllocatorSizes::new(pdevice.handle, device.handle);
if let Some(memtype) = sizes.get_buffer_memtype(vk::MEMORY_PROPERTY_HOST_VISIBLE_BIT | vk::MEMORY_PROPERTY_HOST_COHERENT_BIT) {
  sizes.set_pagesize(memtype, 1 << 25);
}
let mut allocator = vkmem::Allocator::with_sizes(pdevice.handle, sizes);

pub fn bind(
    &mut self,
    bindinfos: &[BindInfo],
    bindtype: BindType
) -> Result<(), Error>
[src]

Bind resources to device memory

This will automatically allocate memory, if necessary.

Resources that are used together shoulb be bound in the same call to this function, since it tries to minimize the number of continuous memory blocks on which the resources are bound. Predominatly this is important after resources have been deleted and free blocks of memory are distributed over multiple pages.

We can specify a rough strategy of how resources are bound with the bindtype parameter. See BindType for the different strategies

The Allocator takes ownorship ower the resource handles.

Note that it is not neccesary that all BindInfos need to specify resources that are allocated on the same memory type. The Allocator will detangle the BindInfos automatically and generate one binding for every group of resources on the same memory type.

Arguments

  • bindinfos - Array of BindInfo that specifies the resources to be bound
  • bindtype - Allocation strategy

Returns

Error if the allocator failed to bind one or more resources:

  • Error::AllocError - if a new page could not be allocated
  • Error::OutOfMemory - if not enough memory is available to bind all resources
  • Error::OversizedBlock - if a single resourcse is larger than it's associated pagesize, or if bindtype is BindType::Block and the combined size of all resources is larger than their associated pagesize
  • Error::InvalidMemoryType - if for one or more resources no memory type is found that satisfies the memory requirements and properties
  • Error::BindMemoryFailed - if one or more resources could not be bound to device memory
  • Error::AlreadyBound - if one or more resources are already bound to device memory

Example

Shows how buffers and images can be bound to the allocator. Prior to bind the resources have to be created with either vk::CreateBuffer or vk::CreateImage.

The BindInfo can be generated manually (as in the example), see Buffer and Image for convenient configuration and binding of buffers and images

let mut allocator = vkmem::Allocator::new(pdevice.handle, device.handle);

let buf = vk::NULL_HANDLE;
let img = vk::NULL_HANDLE;
// ... create buffers/images

let buf = vkmem::Handle::Buffer(buf);
let img = vkmem::Handle::Image(img);
let host_access_flags =
    vk::MEMORY_PROPERTY_HOST_VISIBLE_BIT |
    vk::MEMORY_PROPERTY_HOST_COHERENT_BIT;
let device_local_flags = vk::MEMORY_PROPERTY_DEVICE_LOCAL_BIT;

allocator.bind(
  &[
    vkmem::BindInfo::with_size(buf, 12, host_access_flags),
    vkmem::BindInfo::new(img, device_local_flags),
  ],
  vkmem::BindType::Scatter,
).expect("binding buffers failed");

pub fn destroy(&mut self, handle: u64)[src]

Destroys a resource, that has been bound to this allocator

see destroy_many

pub fn destroy_many(&mut self, handles: &[u64])[src]

Destroys resources, that have been bound to this allocator

Destroys the buffer or image and makes their associated memory available again.

Freeing the memory is relatively expensive compared to allocation, which is why it should be preferred to use destroy_many over just destroy. When multiple resources are destroyed in bulk, merging blocks of free memory and padding together with the freed allocation has to be done only once.

Note that memory bindings of not destroyed resources can not be rearranged, since vulkan does not allow rebinding a buffer/image to a different location.

Example

let mut allocator = vkmem::Allocator::new(pdevice.handle, device.handle);

let mut buf = vk::NULL_HANDLE;
let mut img = vk::NULL_HANDLE;
//... create, bind, use ...
allocator.destroy_many(&[buf, img]);

pub fn free_unused(&mut self)[src]

Frees memory of unused pages

pub fn get_physical_device(&self) -> PhysicalDevice[src]

Gets the physical device handle

pub fn get_device(&self) -> Device[src]

Gets the device handle

pub fn get_mapped(&self, handle: u64) -> Option<Mapped>[src]

Gets a Mapped of the spicified resource handle

Example

Creates a uniform buffer, stores some values in it and reads them back

 let mut allocator = vkmem::Allocator::new(pdevice.handle, device.handle);

 #[derive(Debug)]
 struct Ub { a: u32, b: u32, c: u32 }
 let mut buf_ub = vk::NULL_HANDLE;

 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)
   .bind(&mut allocator, vkmem::BindType::Scatter)
   .unwrap();

 {
   let mapped = allocator.get_mapped(buf_ub).unwrap();
   let ubb = Ub { a: 123, b: 4, c: 5 };
   mapped.host_to_device(&ubb);
 }
 {
   let mapped = allocator.get_mapped(buf_ub).unwrap();
   let mut ubb = Ub { a: 0, b: 0, c: 0 };
   mapped.device_to_host(&mut ubb);
   assert_eq!(ubb.a, 123);
   assert_eq!(ubb.b, 4);
   assert_eq!(ubb.c, 5);
 }

pub fn get_mapped_region(
    &self,
    handle: u64,
    offset: DeviceSize,
    size: DeviceSize
) -> Option<Mapped>
[src]

Gets a Mapped of the spicified resource handle with an offset and size in bytes

Example

Creates a u32 shader storage buffer, mappes it with offset and writes and reads values

 let mut allocator = vkmem::Allocator::new(pdevice.handle, device.handle);

 let mut buf = vk::NULL_HANDLE;
 vkmem::Buffer::new(&mut buf)
   .size(123 * std::mem::size_of::<u32>() as vk::DeviceSize)
   .usage(vk::BUFFER_USAGE_TRANSFER_DST_BIT | vk::BUFFER_USAGE_STORAGE_BUFFER_BIT)
   .devicelocal(false)
   .bind(&mut allocator, vkmem::BindType::Scatter)
   .unwrap();

 {
   let mut mapped = allocator.get_mapped_region(buf, 4, 100).unwrap();
   let v = mapped.as_slice_mut::<u32>();
   v[0] = 123;
   v[1] = 4;
   v[2] = 5;
 }
 {
   let mapped = allocator.get_mapped_region(buf, 4, 100).unwrap();
   let v = mapped.as_slice::<u32>();
   assert_eq!(v[0], 123);
   assert_eq!(v[1], 4);
   assert_eq!(v[2], 5);
 }

pub fn print_stats(&self) -> String[src]

Print staticstics for the Allocator in yaml format

Trait Implementations

impl Drop for Allocator[src]

Auto Trait Implementations

impl Send for Allocator

impl Sync for Allocator

Blanket Implementations

impl<T, U> Into for T where
    U: From<T>, 
[src]

impl<T> From for T[src]

impl<T, U> TryFrom for T where
    U: Into<T>, 
[src]

type Error = !

🔬 This is a nightly-only experimental API. (try_from)

The type returned in the event of a conversion error.

impl<T> Borrow for T where
    T: ?Sized
[src]

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> BorrowMut for T where
    T: ?Sized
[src]

impl<T, U> TryInto for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

🔬 This is a nightly-only experimental API. (try_from)

The type returned in the event of a conversion error.