glium/uniforms/mod.rs
1/*!
2A uniform is a global variable in your program. In order to draw something, you will need to
3give `glium` the values of all your uniforms. Objects that implement the `Uniform` trait are
4here to do that.
5
6The currently preferred way to do this is to use the `uniform!` macro provided by glium:
7
8```no_run
9# use glium::uniform;
10# use glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
11# fn example<T>(display: glium::Display<T>) where T: SurfaceTypeTrait + ResizeableSurface {
12# let tex: f32 = 0.0;
13# let matrix: f32 = 0.0;
14let uniforms = uniform! {
15 texture: tex,
16 matrix: matrix
17};
18# }
19```
20
21Each field must implement the `UniformValue` trait for this to work.
22
23## Samplers
24
25In order to customize the way a texture is being sampled, you must use a `Sampler`.
26
27```no_run
28# use glium::uniform;
29# use glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
30# fn example<T>(display: glium::Display<T>, texture: glium::texture::Texture2d)
31# where T: SurfaceTypeTrait + ResizeableSurface {
32let uniforms = uniform! {
33 texture: glium::uniforms::Sampler::new(&texture)
34 .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
35};
36# }
37```
38
39## Blocks
40
41In GLSL, you can choose to use a uniform *block*. When you use a block, you first need to
42upload the content of this block in the video memory thanks to a `UniformBuffer`. Then you
43can link the buffer to the name of the block, just like any other uniform.
44
45```no_run
46# use glium::uniform;
47# use glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
48# fn example<T>(display: glium::Display<T>, texture: glium::texture::Texture2d)
49# where T: SurfaceTypeTrait + ResizeableSurface {
50let program = glium::Program::from_source(&display,
51 "
52 #version 110
53
54 attribute vec2 position;
55
56 void main() {
57 gl_Position = vec4(position, 0.0, 1.0);
58 }
59 ",
60 "
61 #version 330
62 uniform layout(std140);
63
64 uniform MyBlock {
65 vec3 color;
66 };
67
68 void main() {
69 gl_FragColor = vec4(color, 1.0);
70 }
71 ",
72 None);
73
74let buffer = glium::uniforms::UniformBuffer::new(&display, (0.5f32, 0.5f32, 0.5f32)).unwrap();
75
76let uniforms = uniform! {
77 MyBlock: &buffer
78};
79# }
80```
81
82## Subroutines
83OpenGL allows the use of subroutines, which are like function pointers. Subroutines can be used
84to change the functionality of a shader program at runtime. This method is usually a lot faster
85than using multiple programs that are switched during execution.
86
87A subroutine uniform is unique per shader stage, and not per program.
88
89```no_run
90# use glium::uniform;
91# use glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
92# fn example<T>(display: glium::Display<T>, texture: glium::texture::Texture2d)
93# where T: SurfaceTypeTrait + ResizeableSurface {
94let program = glium::Program::from_source(&display,
95 "
96 #version 150
97 in vec2 position;
98 void main() {
99 gl_Position = vec4(position, 0.0, 1.0);
100 }
101 ",
102 "
103 #version 150
104 #extension GL_ARB_shader_subroutine : require
105 out vec4 fragColor;
106 subroutine vec4 modify_t(vec4 color);
107 subroutine uniform modify_t modify_color;
108
109 subroutine(modify_t) vec4 delete_r(vec4 color)
110 {
111 return vec4(0, color.g, color.b, color.a);
112 }
113
114 subroutine(modify_t) vec4 delete_b(vec4 color)
115 {
116 return vec4(color.r, color.g, 0, color.a);
117 }
118
119 void main()
120 {
121 vec4 white= vec4(1, 1, 1, 1);
122 fragColor = modify_color(white);
123 }
124 ", None);
125
126 let uniforms = uniform! {
127 modify_color: ("delete_b", glium::program::ShaderStage::Fragment)
128 };
129# }
130```
131*/
132pub use self::buffer::UniformBuffer;
133pub use self::sampler::{SamplerWrapFunction, MagnifySamplerFilter, MinifySamplerFilter, DepthTextureComparison};
134pub use self::sampler::{Sampler, SamplerBehavior};
135pub use self::uniforms::{EmptyUniforms, UniformsStorage, DynamicUniforms};
136pub use self::image_unit::{ImageUnitAccess, ImageUnitFormat, ImageUnitError};
137pub use self::image_unit::{ImageUnit, ImageUnitBehavior};
138pub use self::value::{UniformValue, UniformType};
139
140use std::error::Error;
141use std::fmt;
142
143use crate::buffer::Content as BufferContent;
144use crate::buffer::Buffer;
145use crate::program;
146use crate::program::BlockLayout;
147
148mod bind;
149mod buffer;
150mod image_unit;
151mod sampler;
152mod uniforms;
153mod value;
154
155/// Object that contains the values of all the uniforms to bind to a program.
156///
157/// Objects of this type can be passed to the `draw()` function.
158pub trait Uniforms {
159 /// Calls the parameter once with the name and value of each uniform.
160 fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, _: F);
161}
162
163/// Error about a block layout mismatch.
164#[derive(Clone, Debug)]
165pub enum LayoutMismatchError {
166 /// There is a mismatch in the type of one element.
167 TypeMismatch {
168 /// Type expected by the shader.
169 expected: UniformType,
170 /// Type that you gave.
171 obtained: UniformType,
172 },
173
174 /// The expected layout is totally different from what we have.
175 LayoutMismatch {
176 /// Layout expected by the shader.
177 expected: BlockLayout,
178 /// Layout of the input.
179 obtained: BlockLayout,
180 },
181
182 /// The type of data is good, but there is a misalignment.
183 OffsetMismatch {
184 /// Expected offset of a member.
185 expected: usize,
186 /// Offset of the same member in the input.
187 obtained: usize,
188 },
189
190 /// There is a mismatch in a submember of this layout.
191 ///
192 /// This is kind of a hierarchy inside the `LayoutMismatchError`s.
193 MemberMismatch {
194 /// Name of the field.
195 member: String,
196 /// The sub-error.
197 err: Box<LayoutMismatchError>,
198 },
199
200 /// A field is missing in either the expected of the input data layout.
201 MissingField {
202 /// Name of the field.
203 name: String,
204 },
205}
206
207impl Error for LayoutMismatchError {
208 fn source(&self) -> Option<&(dyn Error + 'static)> {
209 use self::LayoutMismatchError::*;
210 match *self {
211 MemberMismatch{ ref err, .. } => Some(err.as_ref()),
212 _ => None,
213 }
214 }
215}
216
217impl fmt::Display for LayoutMismatchError {
218 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
219 use self::LayoutMismatchError::*;
220 let desc = match *self {
221 TypeMismatch { .. } =>
222 "There is a mismatch in the type of one element",
223 LayoutMismatch { .. } =>
224 "The expected layout is totally different from what we have",
225 OffsetMismatch { .. } =>
226 "The type of data is good, but there is a misalignment",
227 MemberMismatch { .. } =>
228 "There is a mismatch in a submember of this layout",
229 MissingField { .. } =>
230 "A field is missing in either the expected of the input data layout",
231 };
232 match *self {
233 //duplicate Patternmatching, different Types can't be condensed
234 TypeMismatch { ref expected, ref obtained } =>
235 write!(
236 fmt,
237 "{}, got: {:?}, expected: {:?}",
238 desc,
239 obtained,
240 expected,
241 ),
242 LayoutMismatch { ref expected, ref obtained } =>
243 write!(
244 fmt,
245 "{}, got: {:?}, expected: {:?}",
246 desc,
247 obtained,
248 expected,
249 ),
250 OffsetMismatch { ref expected, ref obtained } =>
251 write!(
252 fmt,
253 "{}, got: {}, expected: {}",
254 desc,
255 obtained,
256 expected,
257 ),
258 MemberMismatch { ref member, ref err } =>
259 write!(
260 fmt,
261 "{}, {}: {}",
262 desc,
263 member,
264 err,
265 ),
266 MissingField { ref name } =>
267 write!(
268 fmt,
269 "{}: {}",
270 desc,
271 name,
272 ),
273 }
274 }
275}
276
277/// Value that can be used as the value of a uniform.
278///
279/// This includes buffers and textures for example.
280pub trait AsUniformValue {
281 /// Builds a `UniformValue`.
282 fn as_uniform_value(&self) -> UniformValue<'_>;
283}
284
285// TODO: no way to bind a slice
286impl<'a, T: ?Sized> AsUniformValue for &'a Buffer<T> where T: UniformBlock + BufferContent {
287 #[inline]
288 fn as_uniform_value(&self) -> UniformValue<'_> {
289 #[inline]
290 fn f<T: ?Sized>(block: &program::UniformBlock)
291 -> Result<(), LayoutMismatchError> where T: UniformBlock + BufferContent
292 {
293 // TODO: more checks?
294 T::matches(&block.layout, 0)
295 }
296
297 UniformValue::Block(self.as_slice_any(), f::<T>)
298 }
299}
300
301/// Objects that are suitable for being inside a uniform block or a SSBO.
302pub trait UniformBlock { // TODO: `: Copy`, but unsized structs don't impl `Copy`
303 /// Checks whether the uniforms' layout matches the given block if `Self` starts at
304 /// the given offset.
305 fn matches(_: &BlockLayout, base_offset: usize) -> Result<(), LayoutMismatchError>;
306
307 /// Builds the `BlockLayout` corresponding to the current object.
308 fn build_layout(base_offset: usize) -> BlockLayout;
309}
310
311impl<T> UniformBlock for [T] where T: UniformBlock {
312 fn matches(layout: &BlockLayout, base_offset: usize)
313 -> Result<(), LayoutMismatchError>
314 {
315 if let BlockLayout::Struct { members } = layout {
316 if members.len() == 1 {
317 return Self::matches(&members[0].1, base_offset);
318 }
319 }
320
321 if let BlockLayout::DynamicSizedArray { content } = layout {
322 <T as UniformBlock>::matches(content, base_offset)
323 .map_err(|err| {
324 LayoutMismatchError::MemberMismatch {
325 member: "<dynamic array content>".to_owned(),
326 err: Box::new(err),
327 }
328 })
329
330 } else if let BlockLayout::Array { content, .. } = layout {
331 <T as UniformBlock>::matches(content, base_offset)
332 .map_err(|err| {
333 LayoutMismatchError::MemberMismatch {
334 member: "<dynamic array content>".to_owned(),
335 err: Box::new(err),
336 }
337 })
338
339 } else {
340 Err(LayoutMismatchError::LayoutMismatch {
341 expected: layout.clone(),
342 obtained: <Self as UniformBlock>::build_layout(base_offset),
343 })
344 }
345 }
346
347 #[inline]
348 fn build_layout(base_offset: usize) -> BlockLayout {
349 BlockLayout::DynamicSizedArray {
350 content: Box::new(<T as UniformBlock>::build_layout(base_offset)),
351 }
352 }
353}
354
355macro_rules! impl_uniform_block_array {
356 ($len:expr) => (
357 impl<T> UniformBlock for [T; $len] where T: UniformBlock {
358 fn matches(layout: &program::BlockLayout, base_offset: usize)
359 -> Result<(), LayoutMismatchError>
360 {
361 if let &BlockLayout::Struct { ref members } = layout {
362 if members.len() == 1 {
363 return Self::matches(&members[0].1, base_offset);
364 }
365 }
366
367 if let &BlockLayout::Array { ref content, length } = layout {
368 if let Err(err) = T::matches(content, base_offset) {
369 return Err(LayoutMismatchError::MemberMismatch {
370 member: "<array content>".to_owned(),
371 err: Box::new(err),
372 });
373 }
374
375 if length != $len {
376 return Err(LayoutMismatchError::LayoutMismatch {
377 expected: layout.clone(),
378 obtained: Self::build_layout(base_offset),
379 });
380 }
381
382 Ok(())
383
384 } else {
385 Err(LayoutMismatchError::LayoutMismatch {
386 expected: layout.clone(),
387 obtained: Self::build_layout(base_offset),
388 })
389 }
390 }
391
392 #[inline]
393 fn build_layout(base_offset: usize) -> program::BlockLayout {
394 BlockLayout::Array {
395 content: Box::new(T::build_layout(base_offset)),
396 length: $len,
397 }
398 }
399 }
400 );
401}
402
403impl_uniform_block_array!(5);
404impl_uniform_block_array!(6);
405impl_uniform_block_array!(7);
406impl_uniform_block_array!(8);
407impl_uniform_block_array!(9);
408impl_uniform_block_array!(10);
409impl_uniform_block_array!(11);
410impl_uniform_block_array!(12);
411impl_uniform_block_array!(13);
412impl_uniform_block_array!(14);
413impl_uniform_block_array!(15);
414impl_uniform_block_array!(16);
415impl_uniform_block_array!(17);
416impl_uniform_block_array!(18);
417impl_uniform_block_array!(19);
418impl_uniform_block_array!(20);
419impl_uniform_block_array!(21);
420impl_uniform_block_array!(22);
421impl_uniform_block_array!(23);
422impl_uniform_block_array!(24);
423impl_uniform_block_array!(25);
424impl_uniform_block_array!(26);
425impl_uniform_block_array!(27);
426impl_uniform_block_array!(28);
427impl_uniform_block_array!(29);
428impl_uniform_block_array!(30);
429impl_uniform_block_array!(31);
430impl_uniform_block_array!(32);
431impl_uniform_block_array!(64);
432impl_uniform_block_array!(128);
433impl_uniform_block_array!(256);
434impl_uniform_block_array!(512);
435impl_uniform_block_array!(1024);
436impl_uniform_block_array!(2048);
437impl_uniform_block_array!(4096);