Add shading table bucket allocator
This commit is contained in:
parent
a4179fa307
commit
e86af05a1f
|
@ -295,3 +295,137 @@ impl BrickmapManager {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ShadingBucket {
|
||||
global_offset: u32,
|
||||
slot_count: u32,
|
||||
slot_size: u32,
|
||||
free: Vec<u32>,
|
||||
used: Vec<u32>,
|
||||
}
|
||||
|
||||
impl ShadingBucket {
|
||||
pub fn new(global_offset: u32, slot_count: u32, slot_size: u32) -> Self {
|
||||
let mut free = Vec::with_capacity(slot_count as usize);
|
||||
for i in (0..slot_count).rev() {
|
||||
free.push(i);
|
||||
}
|
||||
|
||||
let used = Vec::with_capacity(slot_count as usize);
|
||||
Self {
|
||||
global_offset,
|
||||
slot_count,
|
||||
slot_size,
|
||||
free,
|
||||
used,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_address(&self, address: u32) -> bool {
|
||||
let min = self.global_offset;
|
||||
let max = min + self.slot_count * self.slot_size;
|
||||
return min <= address && address < max;
|
||||
}
|
||||
|
||||
pub fn try_alloc(&mut self) -> Option<u32> {
|
||||
// Mark the first free index as used
|
||||
let bucket_index = self.free.pop()?;
|
||||
self.used.push(bucket_index);
|
||||
|
||||
// Convert the bucket index into a global address
|
||||
let address = self.global_offset + bucket_index * self.slot_size;
|
||||
return Some(address);
|
||||
}
|
||||
|
||||
pub fn try_dealloc(&mut self, address: u32) -> Result<(), &str> {
|
||||
if !self.contains_address(address) {
|
||||
return Err("Address is not within bucket range.");
|
||||
}
|
||||
|
||||
let local_address = address - self.global_offset;
|
||||
if local_address % self.slot_size != 0 {
|
||||
return Err("Address is not aligned to bucket element size.");
|
||||
}
|
||||
|
||||
let bucket_index = local_address / self.slot_size;
|
||||
if !self.used.contains(&bucket_index) {
|
||||
return Err("Address is not currently allocated.");
|
||||
}
|
||||
|
||||
// All the potential errors are out of the way, time to actually deallocate
|
||||
let position = self.used.iter().position(|x| *x == bucket_index).unwrap();
|
||||
self.used.swap_remove(position);
|
||||
self.free.push(bucket_index);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ShadingTableAllocator {
|
||||
buckets: Vec<ShadingBucket>,
|
||||
bucket_count: u32,
|
||||
elements_per_bucket: u32,
|
||||
total_elements: u32,
|
||||
used_elements: u32,
|
||||
}
|
||||
|
||||
impl ShadingTableAllocator {
|
||||
pub fn new(bucket_count: u32, elements_per_bucket: u32) -> Self {
|
||||
let total_elements = bucket_count * elements_per_bucket;
|
||||
let used_elements = 0;
|
||||
|
||||
// Build the buckets. Ordered in ascending size
|
||||
let mut buckets = Vec::with_capacity(bucket_count as usize);
|
||||
for i in (0..bucket_count).rev() {
|
||||
let global_offset = i * elements_per_bucket;
|
||||
let slot_size = u32::pow(2, 9 - i);
|
||||
let slot_count = elements_per_bucket / slot_size;
|
||||
log::info!(
|
||||
"Creating bucket: offset({}), slot_size({}), slot_count({})",
|
||||
global_offset,
|
||||
slot_size,
|
||||
slot_count
|
||||
);
|
||||
buckets.push(ShadingBucket::new(global_offset, slot_count, slot_size));
|
||||
}
|
||||
|
||||
Self {
|
||||
buckets,
|
||||
bucket_count,
|
||||
elements_per_bucket,
|
||||
total_elements,
|
||||
used_elements,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_alloc(&mut self, size: u32) -> Option<u32> {
|
||||
for i in 0..self.bucket_count as usize {
|
||||
let bucket = &mut self.buckets[i];
|
||||
if bucket.slot_size < size {
|
||||
continue;
|
||||
}
|
||||
|
||||
let idx = bucket.try_alloc();
|
||||
if idx.is_some() {
|
||||
self.used_elements += bucket.slot_size;
|
||||
log::info!(
|
||||
"Allocated to shader table at {}. {}/{}",
|
||||
idx.unwrap(),
|
||||
self.used_elements,
|
||||
self.total_elements
|
||||
);
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn try_dealloc(&mut self, address: u32) -> Result<(), &str> {
|
||||
let bucket_idx = address / self.elements_per_bucket;
|
||||
let bucket = &mut self.buckets[bucket_idx as usize];
|
||||
self.used_elements -= bucket.slot_size;
|
||||
bucket.try_dealloc(address)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue