use super::policy::*; use crate::lib::*; struct Locations { used: u32, len: u32, locs: Vec, } #[derive(Default, Debug, Clone)] struct Loc { buf: u32, bind_count: u32, } impl ShdBuffType for Uniform { fn max_bindings() -> i32 { GL::MAX_UNIFORM_BUFFER_BINDINGS() } fn max_size() -> usize { usize(GL::MAX_UNIFORM_BLOCK_SIZE()) } } impl ShdBuffType for ShdStorage { fn max_bindings() -> i32 { GL::MAX_SHADER_STORAGE_BUFFER_BINDINGS() } fn max_size() -> usize { usize(GL::MAX_SHADER_STORAGE_BLOCK_SIZE()) } } impl UniformState { fn bound_locs() -> &'static mut Locations { LocalStatic!(Locations, { let len = u32(T::max_bindings()); Locations { used: 0, len, locs: vec![Def(); usize(len)] } }) } fn garbage_collect() -> u32 { let Locations { used, ref len, locs } = Self::bound_locs(); let npos = 1 + *len; let mut empty = npos; for i in 0..*len { let Loc { buf, ref bind_count } = locs.at_mut(i); if *bind_count == 0 { DEBUG!("Unbing GL {} buffer {buf} from binding location {i}", type_name::()); *buf = 0; if empty == npos { empty = i; } } else { *used = i; } } if empty == npos { FAIL!("Ran out of GL {} buffer bindings({len} available), returning rubbish", type_name::()); empty = 0; } empty } pub fn Unbind(l: u32) { let Loc { bind_count, .. } = Self::bound_locs().locs.at_mut(l); *bind_count -= 1; } pub fn Clone(l: u32) { let Loc { bind_count, .. } = Self::bound_locs().locs.at_mut(l); *bind_count += 1; } pub fn Bind(obj: u32, hint: u32) -> u32 { let Locations { used, ref len, locs } = Self::bound_locs(); let Loc { ref buf, bind_count } = locs.at_mut(hint); if *buf == obj { *bind_count += 1; return hint; } let npos = 1 + *len; let mut empty = npos; for i in 0..*used { let Loc { ref buf, bind_count } = locs.at_mut(i); if *buf == obj { *bind_count += 1; return i; } if empty == npos && *buf == 0 { empty = i; } } if empty == npos { empty = *used; *used += 1; } if empty >= *len { empty = Self::garbage_collect(); } let Loc { buf, bind_count } = locs.at_mut(empty); *bind_count += 1; *buf = obj; let l = empty; DEBUG!("Binding GL {} buffer {obj} to binding location {l}", type_name::()); GL!(gl::BindBufferBase(T::TYPE, l, obj)); DEBUG!("GL buffer binding locations: {locs:?}"); l } pub fn BindLocation(obj: u32, l: u32) -> bool { let Locations { locs, ref len, .. } = Self::bound_locs(); let Loc { buf, bind_count } = locs.at_mut(l); if l >= *len { FAIL!( "Cannot bind GL {} buffer {obj} to binding location {l}, not enough locations({len} available)", type_name::() ); return false; } if *buf != 0 && *buf != obj { DEBUG!("Cannot bind GL {} buffer {obj} to binding location {l}, already occupied by {buf}", type_name::()); return false; } *bind_count += 1; if *buf == obj { return true; } *buf = obj; DEBUG!("Binding GL {} buffer {obj} to binding location {l}", type_name::()); GL!(gl::BindBufferBase(T::TYPE, l, obj)); DEBUG!("GL buffer binding locations: {locs:?}"); true } pub fn drop(obj: u32) { let Locations { used, ref len, locs } = Self::bound_locs(); for i in 0..*len { let Loc { buf, bind_count: _c } = locs.at_mut(i); if obj == *buf { ASSERT!(*_c == 0, "Leakage in GL uniform buffer {obj} binding"); *buf = 0; if *used == i + 1 { *used = i; while *used > 0 && locs.at(*used).buf == 0 { *used -= 1; } } } } } } pub struct UniformState(Dummy);