glium/uniforms/
image_unit.rs

1//! Image units, views into specific planes of textures
2use crate::ToGlEnum;
3use crate::gl;
4use crate::texture;
5use crate::texture::GetFormatError;
6
7#[derive(Debug)]
8/// Represents an error related to the use of an Image Unit
9pub enum ImageUnitError {
10    /// The texture does not contain a mipmap at the requested level
11    NoMipmapAtLevel(u32),
12    /// This type of texture is not layered
13    LayeringNotSupported(texture::Dimensions),
14    /// The layer requested is out of the bounds of this texture
15    LayerOutOfBounds(u32),
16    /// The format of the texture and the requested format are not compatible
17    BadFormatClass(usize, usize),
18    /// Error while trying to get the format of the passed texture
19    GetFormat(GetFormatError),
20}
21
22impl std::fmt::Display for ImageUnitError {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        use self::ImageUnitError::*;
25
26        let desc = match *self {
27            NoMipmapAtLevel(level) => write!(f, "No mipmap level {} found", level),
28            LayeringNotSupported(kind) => write!(f, "Layering is not supported with textures of dimensions {:?}", kind),
29            LayerOutOfBounds(layer) => write!(f, "Request layer {} is out of bounds", layer),
30            BadFormatClass(tbits, ibits) => write!(f, "Texture format has {} bits but image format has {} bits", tbits, ibits),
31            GetFormat(error) => write!(f, "{}", error),
32        };
33        Ok(())
34    }
35}
36
37impl std::error::Error for ImageUnitError {}
38
39
40/// How we bind a texture to an image unit
41#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
42pub struct ImageUnitBehavior {
43    /// The mip level to bind
44    pub level: u32,
45    pub(crate) layer: Option<u32>,
46    /// How the shader will access the image unit
47    pub access: ImageUnitAccess,
48    /// How the shader should interpret the image
49    pub format: ImageUnitFormat,
50}
51
52impl Default for ImageUnitBehavior {
53    #[inline]
54    fn default() -> ImageUnitBehavior {
55        ImageUnitBehavior {
56            level: 0,
57            layer: None,
58            access: ImageUnitAccess::ReadWrite,
59            format: ImageUnitFormat::R32I,
60        }
61    }
62}
63
64/// An image unit uniform marker
65pub struct ImageUnit<'t, T: 't + core::ops::Deref<Target = crate::texture::TextureAny>>(pub &'t T, pub ImageUnitBehavior);
66
67impl<'t, T: 't + core::ops::Deref<Target = crate::texture::TextureAny>> ImageUnit<'t, T> {
68    /// Create a new marker
69    pub fn new(texture: &'t T, format: ImageUnitFormat) -> Result<ImageUnit<'t, T>, ImageUnitError> {
70        let tbits = texture.get_internal_format().unwrap().get_total_bits();
71        if tbits != format.get_total_bits() {
72            return Err(ImageUnitError::BadFormatClass(tbits, format.get_total_bits()))
73        }
74
75        Ok(ImageUnit(texture, ImageUnitBehavior {
76	    format,
77	    ..Default::default()
78	}))
79    }
80
81    /// Set the mip level that will be bound
82    pub fn set_level(mut self, level: u32) -> Result<Self, ImageUnitError> {
83        self.0.mipmap(level).ok_or(ImageUnitError::NoMipmapAtLevel(level))?;
84        self.1.level = level;
85        Ok(self)
86    }
87
88    /// Sets the layer of the texture to bind, or None to disable layer binding
89    // TODO: only implement this for texture types where layering makes sense
90    pub fn set_layer(mut self, layer: Option<u32>) -> Result<Self, ImageUnitError> {
91        if let Some(layer) = layer {
92            match self.0.dimensions() {
93                texture::Dimensions::Texture1d { width } =>
94                    Err(ImageUnitError::LayeringNotSupported(self.0.dimensions())),
95                texture::Dimensions::Texture2d { width, height } =>
96                    Err(ImageUnitError::LayeringNotSupported(self.0.dimensions())),
97                texture::Dimensions::Texture2dMultisample { width, height, samples } =>
98                    Err(ImageUnitError::LayeringNotSupported(self.0.dimensions())),
99                texture::Dimensions::Texture1dArray { width, array_size } =>
100                    if layer >= array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
101                texture::Dimensions::Texture2dArray { width, height, array_size } =>
102                    if layer >= array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
103                texture::Dimensions::Texture2dMultisampleArray { width, height, array_size, samples } =>
104                    if layer >= array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
105                texture::Dimensions::Texture3d { width, height, depth } =>
106                    if layer >= depth { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
107                texture::Dimensions::Cubemap { dimension } =>
108                    if layer >= 6 { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
109                texture::Dimensions::CubemapArray { dimension, array_size } =>
110                    if layer >= 6*array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
111            }?;
112        }
113        self.1.layer = layer;
114        Ok(self)
115    }
116
117    /// State how the shader will access the image unit
118    pub fn set_access(mut self, access: ImageUnitAccess) -> Self {
119        self.1.access = access;
120        self
121    }
122
123}
124
125/// States how the shader will access the image unit
126#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
127pub enum ImageUnitAccess {
128    /// The shader will only read from the image unit
129    Read,
130    /// The shader will only write to the image unit
131    Write,
132    /// The shader will perform both reads and writes to the image unit
133    ReadWrite,
134}
135
136impl ToGlEnum for ImageUnitAccess {
137    #[inline]
138    fn to_glenum(&self) -> gl::types::GLenum {
139        match *self {
140            ImageUnitAccess::Read => gl::READ_ONLY,
141            ImageUnitAccess::Write => gl::WRITE_ONLY,
142            ImageUnitAccess::ReadWrite => gl::READ_WRITE,
143        }
144    }
145}
146
147
148
149/// How the shader should interpret the data in the image
150#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
151pub enum ImageUnitFormat {
152    /// The image elements are 4-component 32 bit floating point
153    RGBA32F,
154    /// The image elements are 4-component 16 bit floating point
155    RGBA16F,
156    /// The image elements are 2-component 32 bit floating point
157    RG32F,
158    /// The image elements are 4-component 16 bit floating point
159    RG16F,
160    /// The image elements are 2 11-bit floats and 1 10-bit float
161    R11FG11FB10F,
162    /// The image elements are 1-component 32 bit floating point
163    R32F,
164    /// The image elements are 4-component 16 bit floating point
165    R16F,
166
167    /// The image elements are 4-component 32 bit unsigned integer
168    RGBA32UI,
169    /// The image elements are 4-component 16 bit unsigned integer
170    RGBA16UI,
171    /// The image elements have 3 10-bit unsigned integer components and 1 2-bit alpha component
172    RGB10A2UI,
173    /// The image elements are 4-component 8 bit unsigned integer
174    RGBA8UI,
175    /// The image elements are 2-component 32 bit unsigned integer
176    RG32UI,
177    /// The image elements are 2-component 16 bit unsigned integer
178    RG16UI,
179    /// The image elements are 2-component 8 bit unsigned integer
180    RG8UI,
181    /// The image elements are 1-component 32 bit unsigned integer
182    R32UI,
183    /// The image elements are 1-component 16 bit unsigned integer
184    R16UI,
185    /// The image elements are 1-component 8 bit unsigned integer
186    R8UI,
187
188    /// The image elements are 4-component 32 bit signed integer
189    RGBA32I,
190    /// The image elements are 4-component 16 bit signed integer
191    RGBA16I,
192    /// The image elements are 4-component 8 bit signed integer
193    RGBA8I,
194    /// The image elements are 2-component 32 bit signed integer
195    RG32I,
196    /// The image elements are 2-component 16 bit signed integer
197    RG16I,
198    /// The image elements are 2-component 8 bit signed integer
199    RG8I,
200    /// The image elements are 1-component 32 bit signed integer
201    R32I,
202    /// The image elements are 1-component 16 bit signed integer
203    R16I,
204    /// The image elements are 1-component 8 bit signed integer
205    R8I,
206
207    /// The image elements are 4-component 16 bit floating point
208    RGBA16,
209    /// The image elements are 3-component 10 bit floating point with 2 alpha bits
210    RGB10A2,
211    /// The image elements are 4-component 8 bit floating point
212    RGBA8,
213    /// The image elements are 2-component 16 bit floating point
214    RG16,
215    /// The image elements are 2-component 8 bit floating point
216    RG8,
217    /// The image elements are 1-component 16 bit floating point
218    R16,
219    /// The image elements are 1-component 8 bit floating point
220    R8,
221
222    /// The image elements are 4-component 16 bit floating point, normalized to the -1.0 to 1.0 range
223    RGBA16snorm,
224    /// The image elements are 4-component 8 bit floating point, normalized to the -1.0 to 1.0 range
225    RGBA8snorm,
226    /// The image elements are 2-component 16 bit floating point, normalized to the -1.0 to 1.0 range
227    RG16snorm,
228    /// The image elements are 2-component 8 bit floating point, normalized to the -1.0 to 1.0 range
229    RG8snorm,
230    /// The image elements are 1-component 16 bit floating point, normalized to the -1.0 to 1.0 range
231    R16snorm,
232    /// The image elements are 1-component 8 bit floating point, normalized to the -1.0 to 1.0 range
233    R8snorm,
234}
235
236impl ImageUnitFormat {
237    fn get_total_bits(&self) -> usize {
238        match self {
239            ImageUnitFormat::RGBA32F => 4*32,
240            ImageUnitFormat::RGBA16F => 4*16,
241            ImageUnitFormat::RG32F => 2*32,
242            ImageUnitFormat::RG16F => 2*16,
243            ImageUnitFormat::R11FG11FB10F => 11*2 + 10,
244            ImageUnitFormat::R32F => 1*32,
245            ImageUnitFormat::R16F => 1*16,
246
247            ImageUnitFormat::RGBA32UI => 4*32,
248            ImageUnitFormat::RGBA16UI => 4*16,
249            ImageUnitFormat::RGB10A2UI => 3*10 + 2,
250            ImageUnitFormat::RGBA8UI => 8*4,
251            ImageUnitFormat::RG32UI => 2*32,
252            ImageUnitFormat::RG16UI => 2*16,
253            ImageUnitFormat::RG8UI => 2*8,
254            ImageUnitFormat::R32UI => 1*32,
255            ImageUnitFormat::R16UI => 1*16,
256            ImageUnitFormat::R8UI => 1*8,
257
258            ImageUnitFormat::RGBA32I => 4*32,
259            ImageUnitFormat::RGBA16I => 2*32,
260            ImageUnitFormat::RGBA8I => 4*8,
261            ImageUnitFormat::RG32I => 2*32,
262            ImageUnitFormat::RG16I => 2*16,
263            ImageUnitFormat::RG8I => 2*8,
264            ImageUnitFormat::R32I => 1*32,
265            ImageUnitFormat::R16I => 1*16,
266            ImageUnitFormat::R8I => 1*8,
267
268            ImageUnitFormat::RGBA16 => 4*16,
269            ImageUnitFormat::RGB10A2 => 3*10+2,
270            ImageUnitFormat::RGBA8 => 4*8,
271            ImageUnitFormat::RG16 => 2*16,
272            ImageUnitFormat::RG8 => 2*8,
273            ImageUnitFormat::R16 => 1*16,
274            ImageUnitFormat::R8 => 1*8,
275
276            ImageUnitFormat::RGBA16snorm => 4*16,
277            ImageUnitFormat::RGBA8snorm => 4*8,
278            ImageUnitFormat::RG16snorm => 2*16,
279            ImageUnitFormat::RG8snorm => 2*8,
280            ImageUnitFormat::R16snorm => 1*16,
281            ImageUnitFormat::R8snorm => 1*8,
282        }
283    }
284}
285
286impl ToGlEnum for ImageUnitFormat {
287    #[inline]
288    fn to_glenum(&self) -> gl::types::GLenum {
289        match *self {
290            ImageUnitFormat::RGBA32F => gl::RGBA32F,
291            ImageUnitFormat::RGBA16F => gl::RGBA16F,
292            ImageUnitFormat::RG32F => gl::RG32F,
293            ImageUnitFormat::RG16F => gl::RG16F,
294            ImageUnitFormat::R11FG11FB10F => gl::R11F_G11F_B10F,
295            ImageUnitFormat::R32F => gl::R32F,
296            ImageUnitFormat::R16F => gl::R16F,
297
298            ImageUnitFormat::RGBA32UI => gl::RGBA32UI,
299            ImageUnitFormat::RGBA16UI => gl::RGBA16UI,
300            ImageUnitFormat::RGB10A2UI => gl::RGB10_A2UI,
301            ImageUnitFormat::RGBA8UI => gl::RGBA8UI,
302            ImageUnitFormat::RG32UI => gl::RG32UI,
303            ImageUnitFormat::RG16UI => gl::RG16UI,
304            ImageUnitFormat::RG8UI => gl::RG8UI,
305            ImageUnitFormat::R32UI => gl::R32UI,
306            ImageUnitFormat::R16UI => gl::R16UI,
307            ImageUnitFormat::R8UI => gl::R8UI,
308
309            ImageUnitFormat::RGBA32I => gl::RGBA32I,
310            ImageUnitFormat::RGBA16I => gl::RGBA16I,
311            ImageUnitFormat::RGBA8I => gl::RGBA8I,
312            ImageUnitFormat::RG32I => gl::RG32I,
313            ImageUnitFormat::RG16I => gl::RG16I,
314            ImageUnitFormat::RG8I => gl::RG8I,
315            ImageUnitFormat::R32I => gl::R32I,
316            ImageUnitFormat::R16I => gl::R16I,
317            ImageUnitFormat::R8I => gl::R8I,
318
319            ImageUnitFormat::RGBA16 => gl::RGBA16,
320            ImageUnitFormat::RGB10A2 => gl::RGB10_A2,
321            ImageUnitFormat::RGBA8 => gl::RGBA8,
322            ImageUnitFormat::RG16 => gl::RG16,
323            ImageUnitFormat::RG8 => gl::RG8,
324            ImageUnitFormat::R16 => gl::R16,
325            ImageUnitFormat::R8 => gl::R8,
326
327            ImageUnitFormat::RGBA16snorm => gl::RGBA16_SNORM,
328            ImageUnitFormat::RGBA8snorm => gl::RGBA8_SNORM,
329            ImageUnitFormat::RG16snorm => gl::RG16_SNORM,
330            ImageUnitFormat::RG8snorm => gl::RG8_SNORM,
331            ImageUnitFormat::R16snorm => gl::R16_SNORM,
332            ImageUnitFormat::R8snorm => gl::R8_SNORM,
333        }
334    }
335}
336