1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::hash::BuildHasherDefault;
4use RawUniformValue;
5
6use smallvec::SmallVec;
7use fnv::FnvHasher;
8
9use gl;
10use Handle;
11use context::CommandContext;
12use version::Version;
13use version::Api;
14use program::reflection::ShaderStage;
15
16pub struct UniformsStorage {
17 values: RefCell<HashMap<gl::types::GLint, Option<RawUniformValue>,
18 BuildHasherDefault<FnvHasher>>>,
19 uniform_blocks: RefCell<SmallVec<[Option<gl::types::GLuint>; 4]>>,
20 shader_storage_blocks: RefCell<SmallVec<[Option<gl::types::GLuint>; 4]>>,
21 subroutine_uniforms: RefCell<HashMap<ShaderStage, Vec<gl::types::GLuint>,
22 BuildHasherDefault<FnvHasher>>>,
23}
24
25impl UniformsStorage {
26 #[inline]
28 pub fn new() -> UniformsStorage {
29 UniformsStorage {
30 values: RefCell::new(HashMap::with_hasher(Default::default())),
31 uniform_blocks: RefCell::new(SmallVec::new()),
32 shader_storage_blocks: RefCell::new(SmallVec::new()),
33 subroutine_uniforms: RefCell::new(HashMap::with_hasher(Default::default())),
34 }
35 }
36
37 pub fn set_uniform_value(&self, ctxt: &mut CommandContext, program: Handle,
40 location: gl::types::GLint, value: &RawUniformValue)
41 {
42 let mut values = self.values.borrow_mut();
43
44 assert!(ctxt.state.program == program);
46
47 macro_rules! uniform(
48 ($ctxt:expr, $uniform:ident, $uniform_arb:ident, $($params:expr),+) => (
49 unsafe {
50 if $ctxt.version >= &Version(Api::Gl, 1, 5) ||
51 $ctxt.version >= &Version(Api::GlEs, 2, 0)
52 {
53 $ctxt.gl.$uniform($($params),+)
54 } else {
55 assert!($ctxt.extensions.gl_arb_shader_objects);
56 $ctxt.gl.$uniform_arb($($params),+)
57 }
58 }
59 )
60 );
61
62 macro_rules! uniform_f64(
63 ($ctxt:expr, $uniform:ident, $($params:expr),+) => (
64 unsafe {
65 if $ctxt.extensions.gl_arb_gpu_shader_fp64 {
66 $ctxt.gl.$uniform($($params),+)
67 } else {
68 panic!("Double precision floats are not supported on this system.")
69 }
70 }
71 )
72 );
73
74 macro_rules! uniform_i64(
75 ($ctxt:expr, $uniform:ident, $($params:expr),+) => (
76 unsafe {
77 if $ctxt.extensions.gl_arb_gpu_shader_int64 {
78 $ctxt.gl.$uniform($($params),+)
79 } else {
80 panic!("64 bit integers are not supported on this system.")
81 }
82 }
83 )
84 );
85
86 match (value, values.entry(location).or_insert(None)) {
87 (&RawUniformValue::SignedInt(a), &mut Some(RawUniformValue::SignedInt(b))) if a == b => (),
88 (&RawUniformValue::UnsignedInt(a), &mut Some(RawUniformValue::UnsignedInt(b))) if a == b => (),
89 (&RawUniformValue::Float(a), &mut Some(RawUniformValue::Float(b))) if a == b => (),
90 (&RawUniformValue::Mat2(a), &mut Some(RawUniformValue::Mat2(b))) if a == b => (),
91 (&RawUniformValue::Mat3(a), &mut Some(RawUniformValue::Mat3(b))) if a == b => (),
92 (&RawUniformValue::Mat4(a), &mut Some(RawUniformValue::Mat4(b))) if a == b => (),
93 (&RawUniformValue::Vec2(a), &mut Some(RawUniformValue::Vec2(b))) if a == b => (),
94 (&RawUniformValue::Vec3(a), &mut Some(RawUniformValue::Vec3(b))) if a == b => (),
95 (&RawUniformValue::Vec4(a), &mut Some(RawUniformValue::Vec4(b))) if a == b => (),
96 (&RawUniformValue::IntVec2(a), &mut Some(RawUniformValue::IntVec2(b))) if a == b => (),
97 (&RawUniformValue::IntVec3(a), &mut Some(RawUniformValue::IntVec3(b))) if a == b => (),
98 (&RawUniformValue::IntVec4(a), &mut Some(RawUniformValue::IntVec4(b))) if a == b => (),
99 (&RawUniformValue::UnsignedIntVec2(a), &mut Some(RawUniformValue::UnsignedIntVec2(b))) if a == b => (),
100 (&RawUniformValue::UnsignedIntVec3(a), &mut Some(RawUniformValue::UnsignedIntVec3(b))) if a == b => (),
101 (&RawUniformValue::UnsignedIntVec4(a), &mut Some(RawUniformValue::UnsignedIntVec4(b))) if a == b => (),
102 (&RawUniformValue::Double(a), &mut Some(RawUniformValue::Double(b))) if a == b => (),
103 (&RawUniformValue::DoubleMat2(a), &mut Some(RawUniformValue::DoubleMat2(b))) if a == b => (),
104 (&RawUniformValue::DoubleMat3(a), &mut Some(RawUniformValue::DoubleMat3(b))) if a == b => (),
105 (&RawUniformValue::DoubleMat4(a), &mut Some(RawUniformValue::DoubleMat4(b))) if a == b => (),
106 (&RawUniformValue::DoubleVec2(a), &mut Some(RawUniformValue::DoubleVec2(b))) if a == b => (),
107 (&RawUniformValue::DoubleVec3(a), &mut Some(RawUniformValue::DoubleVec3(b))) if a == b => (),
108 (&RawUniformValue::DoubleVec4(a), &mut Some(RawUniformValue::DoubleVec4(b))) if a == b => (),
109 (&RawUniformValue::Int64(a), &mut Some(RawUniformValue::Int64(b))) if a == b => (),
110 (&RawUniformValue::Int64Vec2(a), &mut Some(RawUniformValue::Int64Vec2(b))) if a == b => (),
111 (&RawUniformValue::Int64Vec3(a), &mut Some(RawUniformValue::Int64Vec3(b))) if a == b => (),
112 (&RawUniformValue::Int64Vec4(a), &mut Some(RawUniformValue::Int64Vec4(b))) if a == b => (),
113 (&RawUniformValue::UnsignedInt64(a), &mut Some(RawUniformValue::UnsignedInt64(b))) if a == b => (),
114 (&RawUniformValue::UnsignedInt64Vec2(a), &mut Some(RawUniformValue::UnsignedInt64Vec2(b))) if a == b => (),
115 (&RawUniformValue::UnsignedInt64Vec3(a), &mut Some(RawUniformValue::UnsignedInt64Vec3(b))) if a == b => (),
116 (&RawUniformValue::UnsignedInt64Vec4(a), &mut Some(RawUniformValue::UnsignedInt64Vec4(b))) if a == b => (),
117
118 (&RawUniformValue::SignedInt(v), target) => {
119 *target = Some(RawUniformValue::SignedInt(v));
120 uniform!(ctxt, Uniform1i, Uniform1iARB, location, v);
121 },
122
123 (&RawUniformValue::UnsignedInt(v), target) => {
124 *target = Some(RawUniformValue::UnsignedInt(v));
125
126 unsafe {
128 if ctxt.version >= &Version(Api::Gl, 1, 5) ||
129 ctxt.version >= &Version(Api::GlEs, 2, 0)
130 {
131 ctxt.gl.Uniform1ui(location, v)
132 } else {
133 assert!(ctxt.extensions.gl_arb_shader_objects);
134 ctxt.gl.Uniform1iARB(location, v as gl::types::GLint)
135 }
136 }
137 },
138
139 (&RawUniformValue::Float(v), target) => {
140 *target = Some(RawUniformValue::Float(v));
141 uniform!(ctxt, Uniform1f, Uniform1fARB, location, v);
142 },
143
144 (&RawUniformValue::Mat2(v), target) => {
145 *target = Some(RawUniformValue::Mat2(v));
146 uniform!(ctxt, UniformMatrix2fv, UniformMatrix2fvARB,
147 location, 1, gl::FALSE, v.as_ptr() as *const f32);
148 },
149
150 (&RawUniformValue::Mat3(v), target) => {
151 *target = Some(RawUniformValue::Mat3(v));
152 uniform!(ctxt, UniformMatrix3fv, UniformMatrix3fvARB,
153 location, 1, gl::FALSE, v.as_ptr() as *const f32);
154 },
155
156 (&RawUniformValue::Mat4(v), target) => {
157 *target = Some(RawUniformValue::Mat4(v));
158 uniform!(ctxt, UniformMatrix4fv, UniformMatrix4fvARB,
159 location, 1, gl::FALSE, v.as_ptr() as *const f32);
160 },
161
162 (&RawUniformValue::Vec2(v), target) => {
163 *target = Some(RawUniformValue::Vec2(v));
164 uniform!(ctxt, Uniform2fv, Uniform2fvARB, location, 1, v.as_ptr() as *const f32);
165 },
166
167 (&RawUniformValue::Vec3(v), target) => {
168 *target = Some(RawUniformValue::Vec3(v));
169 uniform!(ctxt, Uniform3fv, Uniform3fvARB, location, 1, v.as_ptr() as *const f32);
170 },
171
172 (&RawUniformValue::Vec4(v), target) => {
173 *target = Some(RawUniformValue::Vec4(v));
174 uniform!(ctxt, Uniform4fv, Uniform4fvARB, location, 1, v.as_ptr() as *const f32);
175 },
176
177 (&RawUniformValue::IntVec2(v), target) => {
178 *target = Some(RawUniformValue::IntVec2(v));
179 uniform!(ctxt, Uniform2iv, Uniform2ivARB, location, 1, v.as_ptr() as *const gl::types::GLint);
180 },
181
182 (&RawUniformValue::IntVec3(v), target) => {
183 *target = Some(RawUniformValue::IntVec3(v));
184 uniform!(ctxt, Uniform3iv, Uniform3ivARB, location, 1, v.as_ptr() as *const gl::types::GLint);
185 },
186
187 (&RawUniformValue::IntVec4(v), target) => {
188 *target = Some(RawUniformValue::IntVec4(v));
189 uniform!(ctxt, Uniform4iv, Uniform4ivARB, location, 1, v.as_ptr() as *const gl::types::GLint);
190 },
191
192 (&RawUniformValue::UnsignedIntVec2(v), target) => {
193 *target = Some(RawUniformValue::UnsignedIntVec2(v));
194
195 unsafe {
197 if ctxt.version >= &Version(Api::Gl, 1, 5) ||
198 ctxt.version >= &Version(Api::GlEs, 2, 0)
199 {
200 ctxt.gl.Uniform2uiv(location, 1, v.as_ptr() as *const gl::types::GLuint)
201 } else {
202 assert!(ctxt.extensions.gl_arb_shader_objects);
203 ctxt.gl.Uniform2ivARB(location, 1, v.as_ptr() as *const gl::types::GLint)
204 }
205 }
206 },
207
208 (&RawUniformValue::UnsignedIntVec3(v), target) => {
209 *target = Some(RawUniformValue::UnsignedIntVec3(v));
210
211 unsafe {
213 if ctxt.version >= &Version(Api::Gl, 1, 5) ||
214 ctxt.version >= &Version(Api::GlEs, 2, 0)
215 {
216 ctxt.gl.Uniform3uiv(location, 1, v.as_ptr() as *const gl::types::GLuint)
217 } else {
218 assert!(ctxt.extensions.gl_arb_shader_objects);
219 ctxt.gl.Uniform3ivARB(location, 1, v.as_ptr() as *const gl::types::GLint)
220 }
221 }
222 },
223
224 (&RawUniformValue::UnsignedIntVec4(v), target) => {
225 *target = Some(RawUniformValue::UnsignedIntVec4(v));
226
227 unsafe {
229 if ctxt.version >= &Version(Api::Gl, 1, 5) ||
230 ctxt.version >= &Version(Api::GlEs, 2, 0)
231 {
232 ctxt.gl.Uniform4uiv(location, 1, v.as_ptr() as *const gl::types::GLuint)
233 } else {
234 assert!(ctxt.extensions.gl_arb_shader_objects);
235 ctxt.gl.Uniform4ivARB(location, 1, v.as_ptr() as *const gl::types::GLint)
236 }
237 }
238 },
239 (&RawUniformValue::Double(v), target) => {
240 *target = Some(RawUniformValue::Double(v));
241 uniform_f64!(ctxt, Uniform1d, location, v);
242 },
243
244 (&RawUniformValue::DoubleMat2(v), target) => {
245 *target = Some(RawUniformValue::DoubleMat2(v));
246 uniform_f64!(ctxt, UniformMatrix2dv,
247 location, 1, gl::FALSE, v.as_ptr() as *const gl::types::GLdouble);
248 },
249
250 (&RawUniformValue::DoubleMat3(v), target) => {
251 *target = Some(RawUniformValue::DoubleMat3(v));
252 uniform_f64!(ctxt, UniformMatrix3dv,
253 location, 1, gl::FALSE, v.as_ptr() as *const gl::types::GLdouble);
254 },
255
256 (&RawUniformValue::DoubleMat4(v), target) => {
257 *target = Some(RawUniformValue::DoubleMat4(v));
258 uniform_f64!(ctxt, UniformMatrix4dv,
259 location, 1, gl::FALSE, v.as_ptr() as *const gl::types::GLdouble);
260 },
261
262 (&RawUniformValue::DoubleVec2(v), target) => {
263 *target = Some(RawUniformValue::DoubleVec2(v));
264 uniform_f64!(ctxt, Uniform2dv, location, 1, v.as_ptr() as *const gl::types::GLdouble);
265 },
266
267 (&RawUniformValue::DoubleVec3(v), target) => {
268 *target = Some(RawUniformValue::DoubleVec3(v));
269 uniform_f64!(ctxt, Uniform3dv, location, 1, v.as_ptr() as *const gl::types::GLdouble);
270 },
271
272 (&RawUniformValue::DoubleVec4(v), target) => {
273 *target = Some(RawUniformValue::DoubleVec4(v));
274 uniform_f64!(ctxt, Uniform4dv, location, 1, v.as_ptr() as *const gl::types::GLdouble);
275 },
276 (&RawUniformValue::Int64(v), target) => {
277 *target = Some(RawUniformValue::Int64(v));
278 uniform_i64!(ctxt, Uniform1i64ARB, location, v);
279 },
280 (&RawUniformValue::Int64Vec2(v), target) => {
281 *target = Some(RawUniformValue::Int64Vec2(v));
282 uniform_i64!(ctxt, Uniform2i64vARB, location, 1, v.as_ptr() as *const gl::types::GLint64);
283 },
284
285 (&RawUniformValue::Int64Vec3(v), target) => {
286 *target = Some(RawUniformValue::Int64Vec3(v));
287 uniform_i64!(ctxt, Uniform3i64vARB, location, 1, v.as_ptr() as *const gl::types::GLint64);
288 },
289
290 (&RawUniformValue::Int64Vec4(v), target) => {
291 *target = Some(RawUniformValue::Int64Vec4(v));
292 uniform_i64!(ctxt, Uniform4i64vARB, location, 1, v.as_ptr() as *const gl::types::GLint64);
293 },
294 (&RawUniformValue::UnsignedInt64(v), target) => {
295 *target = Some(RawUniformValue::UnsignedInt64(v));
296 uniform_i64!(ctxt, Uniform1ui64ARB, location, v);
297 },
298 (&RawUniformValue::UnsignedInt64Vec2(v), target) => {
299 *target = Some(RawUniformValue::UnsignedInt64Vec2(v));
300 uniform_i64!(ctxt, Uniform2ui64vARB, location, 1, v.as_ptr() as *const gl::types::GLuint64);
301 },
302
303 (&RawUniformValue::UnsignedInt64Vec3(v), target) => {
304 *target = Some(RawUniformValue::UnsignedInt64Vec3(v));
305 uniform_i64!(ctxt, Uniform3ui64vARB, location, 1, v.as_ptr() as *const gl::types::GLuint64);
306 },
307
308 (&RawUniformValue::UnsignedInt64Vec4(v), target) => {
309 *target = Some(RawUniformValue::UnsignedInt64Vec4(v));
310 uniform_i64!(ctxt, Uniform4ui64vARB, location, 1, v.as_ptr() as *const gl::types::GLuint64);
311 },
312 }
313 }
314
315 pub fn set_uniform_block_binding(&self, ctxt: &mut CommandContext, program: Handle,
318 location: gl::types::GLuint, value: gl::types::GLuint)
319 {
320 let mut blocks = self.uniform_blocks.borrow_mut();
321
322 if blocks.len() <= location as usize {
323 for _ in blocks.len() .. location as usize + 1 {
324 blocks.push(None);
325 }
326 }
327
328 assert!(ctxt.state.program == program);
330
331 match (value, &mut blocks[location as usize]) {
332 (a, &mut Some(b)) if a == b => (),
333
334 (a, target) => {
335 *target = Some(a);
336 match program {
337 Handle::Id(id) => unsafe {
338 ctxt.gl.UniformBlockBinding(id, location, value);
339 },
340 _ => unreachable!()
341 }
342 },
343 }
344 }
345
346 pub fn set_shader_storage_block_binding(&self, ctxt: &mut CommandContext, program: Handle,
349 location: gl::types::GLuint, value: gl::types::GLuint)
350 {
351 let mut blocks = self.shader_storage_blocks.borrow_mut();
352
353 if blocks.len() <= location as usize {
354 for _ in blocks.len() .. location as usize + 1 {
355 blocks.push(None);
356 }
357 }
358
359 assert!(ctxt.state.program == program);
361
362 match (value, &mut blocks[location as usize]) {
363 (a, &mut Some(b)) if a == b => (),
364
365 (a, target) => {
366 *target = Some(a);
367 match program {
368 Handle::Id(id) => unsafe {
369 ctxt.gl.ShaderStorageBlockBinding(id, location, value);
370 },
371 _ => unreachable!()
372 }
373 },
374 }
375 }
376
377 pub fn set_subroutine_uniforms_for_stage(&self, ctxt: &mut CommandContext,
380 program: Handle,
381 stage: ShaderStage,
382 indices: &[gl::types::GLuint])
383 {
384 let mut subroutine_uniforms = self.subroutine_uniforms.borrow_mut();
385 if let Some(stored_indices) = subroutine_uniforms.get(&stage) {
386 if &stored_indices[..] == indices {
387 return
388 }
389 }
390 assert!(ctxt.state.program == program);
392 subroutine_uniforms.insert(stage, indices.iter().cloned().collect());
393 unsafe {
394 ctxt.gl.UniformSubroutinesuiv(stage.to_gl_enum(), indices.len() as gl::types::GLsizei, indices.as_ptr() as *const _);
395 }
396 }
397}