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);