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