use std::collections::VecDeque;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct WgpuAllocationId(u64);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct WgpuArenaAllocation {
pub id: WgpuAllocationId,
pub bytes: u64,
}
#[derive(Clone, Debug)]
struct LiveAllocation {
allocation: WgpuArenaAllocation,
active: bool,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct WgpuArenaSnapshot {
pub live_allocations: usize,
pub resident_bytes: u64,
pub evictions: usize,
}
#[derive(Clone, Debug)]
pub struct WgpuResidentArena {
max_bytes: u64,
next_id: u64,
resident_bytes: u64,
evictions: usize,
allocations: VecDeque<LiveAllocation>,
}
impl WgpuResidentArena {
pub fn new(max_bytes: u64) -> Self {
Self {
max_bytes,
next_id: 0,
resident_bytes: 0,
evictions: 0,
allocations: VecDeque::new(),
}
}
pub fn allocate(&mut self, bytes: u64) -> Result<WgpuArenaAllocation, String> {
if bytes > self.max_bytes {
return Err("wgpu resident allocation exceeds arena".to_owned());
}
while self.resident_bytes.saturating_add(bytes) > self.max_bytes {
let Some(mut allocation) = self.allocations.pop_front() else {
break;
};
if allocation.active {
allocation.active = false;
self.resident_bytes = self
.resident_bytes
.saturating_sub(allocation.allocation.bytes);
self.evictions += 1;
}
self.allocations.push_back(allocation);
}
self.next_id += 1;
let allocation = WgpuArenaAllocation {
id: WgpuAllocationId(self.next_id),
bytes,
};
self.resident_bytes += bytes;
self.allocations.push_back(LiveAllocation {
allocation: allocation.clone(),
active: true,
});
Ok(allocation)
}
pub fn contains(&self, id: WgpuAllocationId) -> bool {
self.allocations
.iter()
.any(|allocation| allocation.active && allocation.allocation.id == id)
}
pub fn snapshot(&self) -> WgpuArenaSnapshot {
WgpuArenaSnapshot {
live_allocations: self
.allocations
.iter()
.filter(|allocation| allocation.active)
.count(),
resident_bytes: self.resident_bytes,
evictions: self.evictions,
}
}
}