pub mod chunk;
pub mod hybrid;
pub mod passthrough;
pub use self::hybrid::{HybridAllocation, HybridAllocator};
use std::ops::Range;
use gfx_hal::adapter::{MemoryProperties, MemoryTypeId};
use gfx_hal::device::OutOfMemory;
use gfx_hal::memory::{Properties, Requirements};
use gfx_hal::Backend;
use failure::Fail;
#[derive(Debug, Fail)]
pub enum AllocationError {
#[fail(display = "{}", _0)]
OutOfMemory(OutOfMemory),
#[fail(display = "Too many objects allocated")]
TooManyObjects,
#[fail(
display = "No suitable memory type found among {:#b} with flags {:?}",
type_mask, flags
)]
NoSuitableHeap { type_mask: u64, flags: Properties },
}
impl From<gfx_hal::device::AllocationError> for AllocationError {
fn from(v: gfx_hal::device::AllocationError) -> AllocationError {
match v {
gfx_hal::device::AllocationError::OutOfMemory(o) => AllocationError::OutOfMemory(o),
gfx_hal::device::AllocationError::TooManyObjects => AllocationError::TooManyObjects,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Hint {
Permanent,
ShortTerm,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AllocationSpec {
pub hint: Hint,
pub required_flags: Properties,
pub preferred_flags: Properties,
}
impl AllocationSpec {
pub fn new(
hint: Hint,
required_flags: Properties,
preferred_flags: Properties,
) -> AllocationSpec {
AllocationSpec {
hint,
required_flags,
preferred_flags,
}
}
}
pub trait Allocation<B: Backend> {
fn memory(&self) -> &B::Memory;
fn flags(&self) -> Properties;
fn range(&self) -> Range<u64>;
}
pub trait Allocator<B: Backend> {
type Allocation: Allocation<B>;
fn alloc(
&mut self,
device: &B::Device,
req: Requirements,
spec: AllocationSpec,
) -> Result<Self::Allocation, AllocationError>;
fn free(&mut self, device: &B::Device, allocation: Self::Allocation);
}
pub(crate) fn pick_memory_type(
props: &MemoryProperties,
req: Requirements,
spec: AllocationSpec,
) -> Result<MemoryTypeId, AllocationError> {
props
.memory_types
.iter()
.enumerate()
.filter(|&(i, ty)| {
req.size <= props.memory_heaps[ty.heap_index]
&& req.type_mask & (1 << i as u64) != 0
&& spec.required_flags.contains(ty.properties)
})
.max_by_key(|(_, ty)| (ty.properties & spec.preferred_flags).bits().count_ones())
.map(|(i, _)| MemoryTypeId(i))
.ok_or(AllocationError::NoSuitableHeap {
type_mask: req.type_mask,
flags: spec.required_flags,
})
}