Skip to main content

grafix_toolbox/kit/opengl/control/
uniform_state.rs

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