grafix_toolbox/kit/opengl/control/
uniform_state.rs1use 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>);