grafix_toolbox/kit/opengl/control/
uniform_state.rs

1use super::policy::*;
2use crate::lib::*;
3
4struct Locations {
5	used: u32,
6	len: u32,
7	locs: Vec<Loc>,
8}
9#[derive(Default, Debug, Clone)]
10struct Loc {
11	buf: u32,
12	bind_count: u32,
13}
14
15impl ShdBuffType for Uniform {
16	fn max_bindings() -> i32 {
17		GL::MAX_UNIFORM_BUFFER_BINDINGS()
18	}
19	fn max_size() -> usize {
20		usize(GL::MAX_UNIFORM_BLOCK_SIZE())
21	}
22}
23impl ShdBuffType for ShdStorage {
24	fn max_bindings() -> i32 {
25		GL::MAX_SHADER_STORAGE_BUFFER_BINDINGS()
26	}
27	fn max_size() -> usize {
28		usize(GL::MAX_SHADER_STORAGE_BLOCK_SIZE())
29	}
30}
31
32impl<T: ShdBuffType> UniformState<T> {
33	fn bound_locs() -> &'static mut Locations {
34		LocalStatic!(Locations, {
35			let len = u32(T::max_bindings());
36			Locations { used: 0, len, locs: vec![Def(); usize(len)] }
37		})
38	}
39	fn garbage_collect() -> u32 {
40		let Locations { used, ref len, locs } = Self::bound_locs();
41
42		let npos = 1 + *len;
43		let mut empty = npos;
44		for i in 0..*len {
45			let Loc { buf, ref bind_count } = locs.at_mut(i);
46			if *bind_count == 0 {
47				DEBUG!("Unbing GL {} buffer {buf} from binding location {i}", type_name::<T>());
48				*buf = 0;
49				if empty == npos {
50					empty = i;
51				}
52			} else {
53				*used = i;
54			}
55		}
56
57		if empty == npos {
58			FAIL!("Ran out of GL {} buffer bindings({len} available), returning rubbish", type_name::<T>());
59			empty = 0;
60		}
61
62		empty
63	}
64	pub fn Unbind(l: u32) {
65		let Loc { bind_count, .. } = Self::bound_locs().locs.at_mut(l);
66		*bind_count -= 1;
67	}
68	pub fn Clone(l: u32) {
69		let Loc { bind_count, .. } = Self::bound_locs().locs.at_mut(l);
70		*bind_count += 1;
71	}
72	pub fn Bind(obj: u32, hint: u32) -> u32 {
73		let Locations { used, ref len, locs } = Self::bound_locs();
74
75		let Loc { ref buf, bind_count } = locs.at_mut(hint);
76		if *buf == obj {
77			*bind_count += 1;
78			return hint;
79		}
80
81		let npos = 1 + *len;
82		let mut empty = npos;
83		for i in 0..*used {
84			let Loc { ref buf, bind_count } = locs.at_mut(i);
85			if *buf == obj {
86				*bind_count += 1;
87				return i;
88			}
89			if empty == npos && *buf == 0 {
90				empty = i;
91			}
92		}
93
94		if empty == npos {
95			empty = *used;
96			*used += 1;
97		}
98
99		if empty >= *len {
100			empty = Self::garbage_collect();
101		}
102
103		let Loc { buf, bind_count } = locs.at_mut(empty);
104		*bind_count += 1;
105		*buf = obj;
106		let l = empty;
107		DEBUG!("Binding GL {} buffer {obj} to binding location {l}", type_name::<T>());
108		GL!(gl::BindBufferBase(T::TYPE, l, obj));
109		DEBUG!("GL buffer binding locations: {locs:?}");
110		l
111	}
112	pub fn BindLocation(obj: u32, l: u32) -> bool {
113		let Locations { locs, ref len, .. } = Self::bound_locs();
114
115		let Loc { buf, bind_count } = locs.at_mut(l);
116		if l >= *len {
117			FAIL!(
118				"Cannot bind GL {} buffer {obj} to binding location {l}, not enough locations({len} available)",
119				type_name::<T>()
120			);
121			return false;
122		}
123
124		if *buf != 0 && *buf != obj {
125			DEBUG!("Cannot bind GL {} buffer {obj} to binding location {l}, already occupied by {buf}", type_name::<T>());
126			return false;
127		}
128
129		*bind_count += 1;
130
131		if *buf == obj {
132			return true;
133		}
134
135		*buf = obj;
136		DEBUG!("Binding GL {} buffer {obj} to binding location {l}", type_name::<T>());
137		GL!(gl::BindBufferBase(T::TYPE, l, obj));
138		DEBUG!("GL buffer binding locations: {locs:?}");
139		true
140	}
141	pub fn drop(obj: u32) {
142		let Locations { used, ref len, locs } = Self::bound_locs();
143		for i in 0..*len {
144			let Loc { buf, bind_count: _c } = locs.at_mut(i);
145			if obj == *buf {
146				ASSERT!(*_c == 0, "Leakage in GL uniform buffer {obj} binding");
147				*buf = 0;
148				if *used == i + 1 {
149					*used = i;
150					while *used > 0 && locs.at(*used).buf == 0 {
151						*used -= 1;
152					}
153				}
154			}
155		}
156	}
157}
158pub struct UniformState<T>(Dummy<T>);