glium/texture/
get_format.rs

1use crate::context::CommandContext;
2use crate::version::Version;
3use crate::version::Api;
4use crate::gl;
5
6use std::fmt;
7use std::error::Error;
8
9use crate::texture::any::TextureAny;
10use crate::TextureExt;
11use crate::GlObject;
12
13/// Error that can happen when retrieving the internal format of a texture.
14#[derive(Copy, Clone, Debug)]
15pub enum GetFormatError {
16    /// The backend doesn't support retrieving the internal format.
17    NotSupported,
18}
19
20impl fmt::Display for GetFormatError {
21    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
22        use self::GetFormatError::*;
23        let desc = match self {
24            NotSupported => "The backend doesn't support retrieving the internal format",
25        };
26        fmt.write_str(desc)
27    }
28}
29
30impl Error for GetFormatError {}
31
32/// Internal format of a texture.
33///
34/// The actual format of a texture is not necessarily one of the predefined ones, so we have
35/// to use a very generic description.
36// TODO: change bits to be u16 for consistency with the rest of the library
37#[derive(Copy, Clone, Debug, PartialEq, Eq)]
38pub enum InternalFormat {
39    /// The format has one component.
40    OneComponent {
41        /// Type of the first component of the format.
42        ty1: InternalFormatType,
43        /// Number of bits of the first component.
44        bits1: usize,
45    },
46
47    /// The format has two components.
48    TwoComponents {
49        /// Type of the first component of the format.
50        ty1: InternalFormatType,
51        /// Number of bits of the first component.
52        bits1: usize,
53        /// Type of the second component.
54        ty2: InternalFormatType,
55        /// Number of bits of the second component.
56        bits2: usize,
57    },
58
59    /// The format has three components.
60    ThreeComponents {
61        /// Type of the first component of the format.
62        ty1: InternalFormatType,
63        /// Number of bits of the first component.
64        bits1: usize,
65        /// Type of the second component.
66        ty2: InternalFormatType,
67        /// Number of bits of the second component.
68        bits2: usize,
69        /// Type of the third component.
70        ty3: InternalFormatType,
71        /// Number of bits of the third component.
72        bits3: usize,
73    },
74
75    /// The format has four components.
76    FourComponents {
77        /// Type of the first component of the format.
78        ty1: InternalFormatType,
79        /// Number of bits of the first component.
80        bits1: usize,
81        /// Type of the second component.
82        ty2: InternalFormatType,
83        /// Number of bits of the second component.
84        bits2: usize,
85        /// Type of the third component.
86        ty3: InternalFormatType,
87        /// Number of bits of the third component.
88        bits3: usize,
89        /// Type of the fourth component.
90        ty4: InternalFormatType,
91        /// Number of bits of the fourth component.
92        bits4: usize,
93    },
94}
95
96impl InternalFormat {
97    /// Returns the total number of bits of this format.
98    #[inline]
99    pub fn get_total_bits(&self) -> usize {
100        match *self {
101            InternalFormat::OneComponent { bits1, .. } => bits1,
102            InternalFormat::TwoComponents { bits1, bits2, .. } => bits1 + bits2,
103            InternalFormat::ThreeComponents { bits1, bits2, bits3, .. } => bits1 + bits2 + bits3,
104            InternalFormat::FourComponents { bits1, bits2, bits3, bits4, .. } =>
105                                                                    bits1 + bits2 + bits3 + bits4,
106        }
107    }
108}
109
110/// Format of a component of an internal format.
111#[derive(Copy, Clone, Debug, PartialEq, Eq)]
112pub enum InternalFormatType {
113    /// Floating point texture with signed components.
114    SignedNormalized,
115    /// Floating point texture with unsigned components.
116    UnsignedNormalized,
117    /// Floating point texture with floats.
118    Float,
119    /// Integral texture.
120    Int,
121    /// Unsigned texture.
122    UnsignedInt,
123}
124
125impl InternalFormatType {
126    /// Builds the `InternalFormatType` of the GLenum. Panics if the value is not recognized.
127    #[inline]
128    fn from_glenum(val: gl::types::GLenum) -> InternalFormatType {
129        match val {
130            gl::SIGNED_NORMALIZED => InternalFormatType::SignedNormalized,
131            gl::UNSIGNED_NORMALIZED => InternalFormatType::UnsignedNormalized,
132            gl::FLOAT => InternalFormatType::Float,
133            gl::INT => InternalFormatType::Int,
134            gl::UNSIGNED_INT => InternalFormatType::UnsignedInt,
135            gl::NONE => unreachable!(),     // separating this case for easier debugging
136            _ => unreachable!(),
137        }
138    }
139}
140
141/// Determines the format of a texture.
142///
143/// A `TextureAny` is guaranteed to have the same format for each mipmap.
144pub fn get_format(ctxt: &mut CommandContext<'_>, texture: &TextureAny)
145                  -> Result<InternalFormat, GetFormatError>
146{
147    if ctxt.version >= &Version(Api::Gl, 3, 0) || ctxt.version >= &Version(Api::GlEs, 3, 0) {
148        let (red_sz, red_ty, green_sz, green_ty, blue_sz, blue_ty,
149             alpha_sz, alpha_ty, depth_sz, depth_ty) = unsafe
150        {
151            let mut red_sz = 0;
152            let mut red_ty = 0;
153            let mut green_sz = 0;
154            let mut green_ty = 0;
155            let mut blue_sz = 0;
156            let mut blue_ty = 0;
157            let mut alpha_sz = 0;
158            let mut alpha_ty = 0;
159            let mut depth_sz = 0;
160            let mut depth_ty = 0;
161
162            if ctxt.version >= &Version(Api::Gl, 4, 5) ||
163               ctxt.extensions.gl_arb_direct_state_access
164            {
165                let id = texture.get_id();
166                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_RED_SIZE, &mut red_sz);
167                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_RED_TYPE, &mut red_ty);
168                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_GREEN_SIZE, &mut green_sz);
169                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_GREEN_TYPE, &mut green_ty);
170                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_BLUE_SIZE, &mut blue_sz);
171                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_BLUE_TYPE, &mut blue_ty);
172                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_ALPHA_SIZE, &mut alpha_sz);
173                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_ALPHA_TYPE, &mut alpha_ty);
174                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_DEPTH_SIZE, &mut depth_sz);
175                ctxt.gl.GetTextureLevelParameteriv(id, 0, gl::TEXTURE_DEPTH_TYPE, &mut depth_ty);
176
177            } else if ctxt.extensions.gl_ext_direct_state_access {
178                let id = texture.get_id();
179                let bind_point = texture.get_bind_point();
180
181                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_RED_SIZE,
182                                                      &mut red_sz);
183                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_RED_TYPE,
184                                                      &mut red_ty);
185                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_GREEN_SIZE,
186                                                      &mut green_sz);
187                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_GREEN_TYPE,
188                                                      &mut green_ty);
189                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_BLUE_SIZE,
190                                                      &mut blue_sz);
191                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_BLUE_TYPE,
192                                                      &mut blue_ty);
193                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_ALPHA_SIZE,
194                                                      &mut alpha_sz);
195                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_ALPHA_TYPE,
196                                                      &mut alpha_ty);
197                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_DEPTH_SIZE,
198                                                      &mut depth_sz);
199                ctxt.gl.GetTextureLevelParameterivEXT(id, bind_point, 0, gl::TEXTURE_DEPTH_TYPE,
200                                                      &mut depth_ty);
201
202            } else {
203                let bind_point = texture.bind_to_current(ctxt);
204                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_RED_SIZE, &mut red_sz);
205                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_RED_TYPE, &mut red_ty);
206                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_GREEN_SIZE,
207                                               &mut green_sz);
208                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_GREEN_TYPE,
209                                               &mut green_ty);
210                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_BLUE_SIZE, &mut blue_sz);
211                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_BLUE_TYPE, &mut blue_ty);
212                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_ALPHA_SIZE,
213                                               &mut alpha_sz);
214                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_ALPHA_TYPE,
215                                               &mut alpha_ty);
216                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_DEPTH_SIZE,
217                                               &mut depth_sz);
218                ctxt.gl.GetTexLevelParameteriv(bind_point, 0, gl::TEXTURE_DEPTH_TYPE,
219                                               &mut depth_ty);
220            }
221
222            (red_sz as gl::types::GLenum, red_ty as gl::types::GLenum,
223             green_sz as gl::types::GLenum, green_ty as gl::types::GLenum,
224             blue_sz as gl::types::GLenum, blue_ty as gl::types::GLenum,
225             alpha_sz as gl::types::GLenum, alpha_ty as gl::types::GLenum,
226             depth_sz as gl::types::GLenum, depth_ty as gl::types::GLenum)
227        };
228
229        Ok(match (red_sz, red_ty, green_sz, green_ty, blue_sz, blue_ty,
230               alpha_sz, alpha_ty, depth_sz, depth_ty)
231        {
232            (_, gl::NONE, _, _, _, _, _, _, _, gl::NONE) => return Err(GetFormatError::NotSupported),
233            (_, gl::NONE, _, _, _, _, _, _, sz1, ty1) => InternalFormat::OneComponent {
234                ty1: InternalFormatType::from_glenum(ty1),
235                bits1: sz1 as usize,
236            },
237            (sz1, ty1, _, gl::NONE, _, _, _, _, _, _) => InternalFormat::OneComponent {
238                ty1: InternalFormatType::from_glenum(ty1),
239                bits1: sz1 as usize,
240            },
241            (sz1, ty1, sz2, ty2, _, gl::NONE, _, _, _, _) => InternalFormat::TwoComponents {
242                ty1: InternalFormatType::from_glenum(ty1),
243                bits1: sz1 as usize,
244                ty2: InternalFormatType::from_glenum(ty2),
245                bits2: sz2 as usize,
246            },
247            (sz1, ty1, sz2, ty2, sz3, ty3, _, gl::NONE, _, _) => InternalFormat::ThreeComponents {
248                ty1: InternalFormatType::from_glenum(ty1),
249                bits1: sz1 as usize,
250                ty2: InternalFormatType::from_glenum(ty2),
251                bits2: sz2 as usize,
252                ty3: InternalFormatType::from_glenum(ty3),
253                bits3: sz3 as usize,
254            },
255            (sz1, ty1, sz2, ty2, sz3, ty3, sz4, ty4, _, gl::NONE) => InternalFormat::FourComponents {
256                ty1: InternalFormatType::from_glenum(ty1),
257                bits1: sz1 as usize,
258                ty2: InternalFormatType::from_glenum(ty2),
259                bits2: sz2 as usize,
260                ty3: InternalFormatType::from_glenum(ty3),
261                bits3: sz3 as usize,
262                ty4: InternalFormatType::from_glenum(ty4),
263                bits4: sz4 as usize,
264            },
265            _ => unreachable!()
266        })
267
268    } else {
269        // FIXME: GL2
270        Err(GetFormatError::NotSupported)
271    }
272}