glium/
image_format.rs

1/*!
2This private module handles the various image formats in OpenGL.
3
4*/
5use std::fmt;
6use std::error::Error;
7
8use crate::gl;
9use crate::context::Context;
10
11use crate::CapabilitiesSource;
12use crate::ToGlEnum;
13use crate::version::{Api, Version};
14
15/// Error that is returned if the format is not supported by OpenGL.
16#[derive(Copy, Clone, Debug)]
17pub struct FormatNotSupportedError;
18
19impl fmt::Display for FormatNotSupportedError {
20    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
21        write!(fmt, "Format is not supported by OpenGL")
22    }
23}
24
25impl Error for FormatNotSupportedError {}
26
27/// Texture format request.
28#[derive(Copy, Clone, Debug)]
29pub enum TextureFormatRequest {
30    /// Request a specific format.
31    Specific(TextureFormat),
32
33    /// Request any floating-point format, normalized or not.
34    AnyFloatingPoint,
35
36    // TODO:
37    // /// Request any floating-point format represented with floats.
38    //AnyFloatingPointFloat,
39
40    /// Request any compressed format.
41    AnyCompressed,
42
43    /// Request any sRGB format.
44    AnySrgb,
45
46    /// Request any compressed sRGB format.
47    AnyCompressedSrgb,
48
49    /// Request any integral format.
50    AnyIntegral,
51
52    /// Request any unsigned format.
53    AnyUnsigned,
54
55    /// Request any depth format.
56    AnyDepth,
57
58    /// Request any stencil format.
59    AnyStencil,
60
61    /// Request any depth-stencil format.
62    AnyDepthStencil,
63}
64
65/// List of client-side pixel formats.
66///
67/// These are all the possible formats of input data when uploading to a texture.
68#[allow(missing_docs)]
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum ClientFormat {
71    U8,
72    U8U8,
73    U8U8U8,
74    U8U8U8U8,
75    I8,
76    I8I8,
77    I8I8I8,
78    I8I8I8I8,
79    U16,
80    U16U16,
81    U16U16U16,
82    U16U16U16U16,
83    I16,
84    I16I16,
85    I16I16I16,
86    I16I16I16I16,
87    U32,
88    U32U32,
89    U32U32U32,
90    U32U32U32U32,
91    I32,
92    I32I32,
93    I32I32I32,
94    I32I32I32I32,
95    U3U3U2,
96    U5U6U5,
97    U4U4U4U4,
98    U5U5U5U1,
99    U1U5U5U5Reversed,
100    U10U10U10U2,
101    F16,
102    F16F16,
103    F16F16F16,
104    F16F16F16F16,
105    F32,
106    F32F32,
107    F32F32F32,
108    F32F32F32F32,
109}
110
111impl ClientFormat {
112    /// Returns the size in bytes of a pixel of this type.
113    pub fn get_size(&self) -> usize {
114        use std::mem;
115
116        match *self {
117            ClientFormat::U8 => 1 * mem::size_of::<u8>(),
118            ClientFormat::U8U8 => 2 * mem::size_of::<u8>(),
119            ClientFormat::U8U8U8 => 3 * mem::size_of::<u8>(),
120            ClientFormat::U8U8U8U8 => 4 * mem::size_of::<u8>(),
121            ClientFormat::I8 => 1 * mem::size_of::<i8>(),
122            ClientFormat::I8I8 => 2 * mem::size_of::<i8>(),
123            ClientFormat::I8I8I8 => 3 * mem::size_of::<i8>(),
124            ClientFormat::I8I8I8I8 => 4 * mem::size_of::<i8>(),
125            ClientFormat::U16 => 1 * mem::size_of::<u16>(),
126            ClientFormat::U16U16 => 2 * mem::size_of::<u16>(),
127            ClientFormat::U16U16U16 => 3 * mem::size_of::<u16>(),
128            ClientFormat::U16U16U16U16 => 4 * mem::size_of::<u16>(),
129            ClientFormat::I16 => 1 * mem::size_of::<i16>(),
130            ClientFormat::I16I16 => 2 * mem::size_of::<i16>(),
131            ClientFormat::I16I16I16 => 3 * mem::size_of::<i16>(),
132            ClientFormat::I16I16I16I16 => 4 * mem::size_of::<i16>(),
133            ClientFormat::U32 => 1 * mem::size_of::<u32>(),
134            ClientFormat::U32U32 => 2 * mem::size_of::<u32>(),
135            ClientFormat::U32U32U32 => 3 * mem::size_of::<u32>(),
136            ClientFormat::U32U32U32U32 => 4 * mem::size_of::<u32>(),
137            ClientFormat::I32 => 1 * mem::size_of::<i32>(),
138            ClientFormat::I32I32 => 2 * mem::size_of::<i32>(),
139            ClientFormat::I32I32I32 => 3 * mem::size_of::<i32>(),
140            ClientFormat::I32I32I32I32 => 4 * mem::size_of::<i32>(),
141            ClientFormat::U3U3U2 => (3 + 3 + 2) / 8,
142            ClientFormat::U5U6U5 => (5 + 6 + 5) / 8,
143            ClientFormat::U4U4U4U4 => (4 + 4 + 4 + 4) / 8,
144            ClientFormat::U5U5U5U1 => (5 + 5 + 5 + 1) / 8,
145            ClientFormat::U1U5U5U5Reversed => (1 + 5 + 5 + 5) / 8,
146            ClientFormat::U10U10U10U2 => (10 + 10 + 10 + 2) / 8,
147            ClientFormat::F16 => 16 / 8,
148            ClientFormat::F16F16 => (16 + 16) / 8,
149            ClientFormat::F16F16F16 => (16 + 16 + 16) / 8,
150            ClientFormat::F16F16F16F16 => (16 + 16 + 16 + 16) / 8,
151            ClientFormat::F32 => 1 * mem::size_of::<f32>(),
152            ClientFormat::F32F32 => 2 * mem::size_of::<f32>(),
153            ClientFormat::F32F32F32 => 3 * mem::size_of::<f32>(),
154            ClientFormat::F32F32F32F32 => 4 * mem::size_of::<f32>(),
155        }
156    }
157
158    /// Returns the number of components of this client format.
159    pub fn get_num_components(&self) -> u8 {
160        match *self {
161            ClientFormat::U8 => 1,
162            ClientFormat::U8U8 => 2,
163            ClientFormat::U8U8U8 => 3,
164            ClientFormat::U8U8U8U8 => 4,
165            ClientFormat::I8 => 1,
166            ClientFormat::I8I8 => 2,
167            ClientFormat::I8I8I8 => 3,
168            ClientFormat::I8I8I8I8 => 4,
169            ClientFormat::U16 => 1,
170            ClientFormat::U16U16 => 2,
171            ClientFormat::U16U16U16 => 3,
172            ClientFormat::U16U16U16U16 => 4,
173            ClientFormat::I16 => 1,
174            ClientFormat::I16I16 => 2,
175            ClientFormat::I16I16I16 => 3,
176            ClientFormat::I16I16I16I16 => 4,
177            ClientFormat::U32 => 1,
178            ClientFormat::U32U32 => 2,
179            ClientFormat::U32U32U32 => 3,
180            ClientFormat::U32U32U32U32 => 4,
181            ClientFormat::I32 => 1,
182            ClientFormat::I32I32 => 2,
183            ClientFormat::I32I32I32 => 3,
184            ClientFormat::I32I32I32I32 => 4,
185            ClientFormat::U3U3U2 => 3,
186            ClientFormat::U5U6U5 => 3,
187            ClientFormat::U4U4U4U4 => 4,
188            ClientFormat::U5U5U5U1 => 4,
189            ClientFormat::U1U5U5U5Reversed => 4,
190            ClientFormat::U10U10U10U2 => 4,
191            ClientFormat::F16 => 1,
192            ClientFormat::F16F16 => 2,
193            ClientFormat::F16F16F16 => 3,
194            ClientFormat::F16F16F16F16 => 4,
195            ClientFormat::F32 => 1,
196            ClientFormat::F32F32 => 2,
197            ClientFormat::F32F32F32 => 3,
198            ClientFormat::F32F32F32F32 => 4,
199        }
200    }
201}
202
203/// List of uncompressed pixel formats that contain floating-point-like data.
204///
205/// Some formats are marked as "guaranteed to be supported". What this means is that you are
206/// certain that the backend will use exactly these formats. If you try to use a format that
207/// is not supported by the backend, it will automatically fall back to a larger format.
208// TODO: missing RGB565
209#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
210pub enum UncompressedFloatFormat {
211    ///
212    ///
213    /// Guaranteed to be supported for both textures and renderbuffers.
214    U8,
215    ///
216    ///
217    /// Guaranteed to be supported for textures.
218    I8,
219    ///
220    ///
221    /// Guaranteed to be supported for both textures and renderbuffers.
222    U16,
223    ///
224    ///
225    /// Guaranteed to be supported for textures.
226    I16,
227    ///
228    ///
229    /// Guaranteed to be supported for both textures and renderbuffers.
230    U8U8,
231    ///
232    ///
233    /// Guaranteed to be supported for textures.
234    I8I8,
235    ///
236    ///
237    /// Guaranteed to be supported for both textures and renderbuffers.
238    U16U16,
239    ///
240    ///
241    /// Guaranteed to be supported for textures.
242    I16I16,
243    ///
244    U3U3U2,
245    ///
246    U4U4U4,
247    ///
248    U5U5U5,
249    ///
250    ///
251    /// Guaranteed to be supported for textures.
252    U8U8U8,
253    ///
254    ///
255    /// Guaranteed to be supported for textures.
256    I8I8I8,
257    ///
258    U10U10U10,
259    ///
260    U12U12U12,
261    ///
262    ///
263    /// Guaranteed to be supported for both textures and renderbuffers.
264    U16U16U16,
265    ///
266    ///
267    /// Guaranteed to be supported for textures.
268    I16I16I16,
269    ///
270    U2U2U2U2,
271    ///
272    U4U4U4U4,
273    ///
274    U5U5U5U1,
275    ///
276    ///
277    /// Guaranteed to be supported for both textures and renderbuffers.
278    U8U8U8U8,
279    ///
280    ///
281    /// Guaranteed to be supported for textures.
282    I8I8I8I8,
283    ///
284    ///
285    /// Guaranteed to be supported for both textures and renderbuffers.
286    U10U10U10U2,
287    ///
288    U12U12U12U12,
289    ///
290    ///
291    /// Guaranteed to be supported for both textures and renderbuffers.
292    U16U16U16U16,
293    ///
294    ///
295    /// Guaranteed to be supported for both textures and renderbuffers.
296    I16I16I16I16,
297    ///
298    ///
299    /// Guaranteed to be supported for both textures and renderbuffers.
300    F16,
301    ///
302    ///
303    /// Guaranteed to be supported for both textures and renderbuffers.
304    F16F16,
305    ///
306    ///
307    /// Guaranteed to be supported for textures.
308    F16F16F16,
309    ///
310    ///
311    /// Guaranteed to be supported for both textures and renderbuffers.
312    F16F16F16F16,
313    ///
314    ///
315    /// Guaranteed to be supported for both textures and renderbuffers.
316    F32,
317    ///
318    ///
319    /// Guaranteed to be supported for both textures and renderbuffers.
320    F32F32,
321    ///
322    ///
323    /// Guaranteed to be supported for textures.
324    F32F32F32,
325    ///
326    ///
327    /// Guaranteed to be supported for both textures and renderbuffers.
328    F32F32F32F32,
329    ///
330    ///
331    /// Guaranteed to be supported for both textures and renderbuffers.
332    F11F11F10,
333    /// Uses three components of 9 bits of precision that all share the same exponent.
334    ///
335    /// Use this format only if all the components are approximately equal.
336    ///
337    /// Guaranteed to be supported for textures.
338    F9F9F9,
339}
340
341impl UncompressedFloatFormat {
342    /// Returns a list of all the possible values of this enumeration.
343    #[inline]
344    pub fn get_formats_list() -> Vec<UncompressedFloatFormat> {
345        vec![
346            UncompressedFloatFormat::U8,
347            UncompressedFloatFormat::I8,
348            UncompressedFloatFormat::U16,
349            UncompressedFloatFormat::I16,
350            UncompressedFloatFormat::U8U8,
351            UncompressedFloatFormat::I8I8,
352            UncompressedFloatFormat::U16U16,
353            UncompressedFloatFormat::I16I16,
354            UncompressedFloatFormat::U3U3U2,
355            UncompressedFloatFormat::U4U4U4,
356            UncompressedFloatFormat::U5U5U5,
357            UncompressedFloatFormat::U8U8U8,
358            UncompressedFloatFormat::I8I8I8,
359            UncompressedFloatFormat::U10U10U10,
360            UncompressedFloatFormat::U12U12U12,
361            UncompressedFloatFormat::U16U16U16,
362            UncompressedFloatFormat::I16I16I16,
363            UncompressedFloatFormat::U2U2U2U2,
364            UncompressedFloatFormat::U4U4U4U4,
365            UncompressedFloatFormat::U5U5U5U1,
366            UncompressedFloatFormat::U8U8U8U8,
367            UncompressedFloatFormat::I8I8I8I8,
368            UncompressedFloatFormat::U10U10U10U2,
369            UncompressedFloatFormat::U12U12U12U12,
370            UncompressedFloatFormat::U16U16U16U16,
371            UncompressedFloatFormat::I16I16I16I16,
372            UncompressedFloatFormat::F16,
373            UncompressedFloatFormat::F16F16,
374            UncompressedFloatFormat::F16F16F16,
375            UncompressedFloatFormat::F16F16F16F16,
376            UncompressedFloatFormat::F32,
377            UncompressedFloatFormat::F32F32,
378            UncompressedFloatFormat::F32F32F32,
379            UncompressedFloatFormat::F32F32F32F32,
380            UncompressedFloatFormat::F11F11F10,
381            UncompressedFloatFormat::F9F9F9,
382        ]
383    }
384
385    /// Turns this format into a more generic `TextureFormat`.
386    #[inline]
387    pub fn to_texture_format(self) -> TextureFormat {
388        TextureFormat::UncompressedFloat(self)
389    }
390
391    /// Returns true if this format is supported by the backend.
392    pub fn is_supported<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
393        let version = context.get_version();
394        let extensions = context.get_extensions();
395
396        match self {
397            UncompressedFloatFormat::U8 => {
398                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
399                    extensions.gl_arb_texture_rg
400            },
401            UncompressedFloatFormat::I8 => {
402                version >= &Version(Api::Gl, 3, 2) || version >= &Version(Api::GlEs, 3, 0) ||
403                    extensions.gl_ext_texture_snorm
404            },
405            UncompressedFloatFormat::U16 => {
406                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
407                    extensions.gl_arb_texture_rg
408            },
409            UncompressedFloatFormat::I16 => {
410                version >= &Version(Api::Gl, 3, 2) || version >= &Version(Api::GlEs, 3, 0) ||
411                    extensions.gl_ext_texture_snorm
412            },
413            UncompressedFloatFormat::U8U8 => {
414                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
415                    extensions.gl_arb_texture_rg
416            },
417            UncompressedFloatFormat::I8I8 => {
418                version >= &Version(Api::Gl, 3, 2) || version >= &Version(Api::GlEs, 3, 0) ||
419                    extensions.gl_ext_texture_snorm
420            },
421            UncompressedFloatFormat::U16U16 => {
422                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
423                    extensions.gl_arb_texture_rg
424            },
425            UncompressedFloatFormat::I16I16 => {
426                version >= &Version(Api::Gl, 3, 2) || version >= &Version(Api::GlEs, 3, 0) ||
427                    extensions.gl_ext_texture_snorm
428            },
429            UncompressedFloatFormat::U3U3U2 => {
430                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
431            },
432            UncompressedFloatFormat::U4U4U4 => {
433                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
434            },
435            UncompressedFloatFormat::U5U5U5 => {
436                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
437            },
438            UncompressedFloatFormat::U8U8U8 => {
439                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
440            },
441            UncompressedFloatFormat::I8I8I8 => {
442                version >= &Version(Api::Gl, 3, 2) || version >= &Version(Api::GlEs, 3, 0) ||
443                    extensions.gl_ext_texture_snorm
444            },
445            UncompressedFloatFormat::U10U10U10 => {
446                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
447            },
448            UncompressedFloatFormat::U12U12U12 => {
449                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
450            },
451            UncompressedFloatFormat::U16U16U16 => {
452                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0)
453            },
454            UncompressedFloatFormat::I16I16I16 => {
455                version >= &Version(Api::Gl, 3, 2) || version >= &Version(Api::GlEs, 3, 0) ||
456                    extensions.gl_ext_texture_snorm
457            },
458            UncompressedFloatFormat::U2U2U2U2 => {
459                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
460            },
461            UncompressedFloatFormat::U4U4U4U4 => {
462                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
463            },
464            UncompressedFloatFormat::U5U5U5U1 => {
465                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
466            },
467            UncompressedFloatFormat::U8U8U8U8 => {
468                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
469            },
470            UncompressedFloatFormat::I8I8I8I8 => {
471                version >= &Version(Api::Gl, 3, 2) || version >= &Version(Api::GlEs, 3, 0) ||
472                    extensions.gl_ext_texture_snorm
473            },
474            UncompressedFloatFormat::U10U10U10U2 => {
475                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
476            },
477            UncompressedFloatFormat::U12U12U12U12 => {
478                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
479            },
480            UncompressedFloatFormat::U16U16U16U16 => {
481                version >= &Version(Api::Gl, 1, 1) || version >= &Version(Api::GlEs, 3, 0)
482            },
483            UncompressedFloatFormat::I16I16I16I16 => {
484                version >= &Version(Api::Gl, 3, 2) || version >= &Version(Api::GlEs, 3, 0) ||
485                    extensions.gl_ext_texture_snorm
486            },
487            UncompressedFloatFormat::F16 => {
488                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
489                    (extensions.gl_arb_texture_float && extensions.gl_arb_texture_rg)
490            },
491            UncompressedFloatFormat::F16F16 => {
492                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
493                    (extensions.gl_arb_texture_float && extensions.gl_arb_texture_rg)
494            },
495            UncompressedFloatFormat::F16F16F16 => {
496                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
497                    extensions.gl_arb_texture_float || extensions.gl_ati_texture_float
498            },
499            UncompressedFloatFormat::F16F16F16F16 => {
500                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
501                    extensions.gl_arb_texture_float || extensions.gl_ati_texture_float
502            },
503            UncompressedFloatFormat::F32 => {
504                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
505                    (extensions.gl_arb_texture_float && extensions.gl_arb_texture_rg)
506            },
507            UncompressedFloatFormat::F32F32 => {
508                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
509                    (extensions.gl_arb_texture_float && extensions.gl_arb_texture_rg)
510            },
511            UncompressedFloatFormat::F32F32F32 => {
512                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
513                    extensions.gl_arb_texture_float || extensions.gl_ati_texture_float
514            },
515            UncompressedFloatFormat::F32F32F32F32 => {
516                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
517                    extensions.gl_arb_texture_float || extensions.gl_ati_texture_float
518            },
519            UncompressedFloatFormat::F11F11F10 => {
520                version >= &Version(Api::Gl, 3, 2) || version >= &Version(Api::GlEs, 3, 0) ||
521                    extensions.gl_ext_packed_float
522            },
523            UncompressedFloatFormat::F9F9F9 => {
524                version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
525                    extensions.gl_ext_texture_shared_exponent
526            },
527        }
528    }
529
530    /// Returns true if a texture or renderbuffer with this format can be used as a framebuffer
531    /// attachment.
532    pub fn is_color_renderable<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
533        // this is the only format that is never renderable
534        if matches!(self, UncompressedFloatFormat::F9F9F9) {
535            return false;
536        }
537
538        // checking whether it's supported, so that we don't return `true` by accident
539        if !self.is_supported(context) {
540            return false;
541        }
542
543        let version = context.get_version();
544        let extensions = context.get_extensions();
545
546        // if we have OpenGL, everything here is color-renderable
547        if version >= &Version(Api::Gl, 1, 0) {
548            return true;
549        }
550
551        // if we have OpenGL ES, it depends
552        // TODO: there are maybe more formats here
553        match self {
554            UncompressedFloatFormat::U8 => {
555                version >= &Version(Api::GlEs, 3, 0) || extensions.gl_arb_texture_rg
556            },
557            UncompressedFloatFormat::U8U8 => {
558                version >= &Version(Api::GlEs, 3, 0) || extensions.gl_arb_texture_rg
559            },
560            //&UncompressedFloatFormat::U5U6U5 => true,
561            UncompressedFloatFormat::U8U8U8 => {
562                version >= &Version(Api::GlEs, 3, 0) || extensions.gl_oes_rgb8_rgba8
563            },
564            UncompressedFloatFormat::U4U4U4U4 => true,
565            UncompressedFloatFormat::U5U5U5U1 => true,
566            UncompressedFloatFormat::U8U8U8U8 => {
567                version >= &Version(Api::GlEs, 3, 0) || extensions.gl_arm_rgba8 ||
568                extensions.gl_oes_rgb8_rgba8
569            },
570            UncompressedFloatFormat::U10U10U10U2 => version >= &Version(Api::GlEs, 3, 0),
571            UncompressedFloatFormat::F16 => version >= &Version(Api::GlEs, 3, 2),
572            UncompressedFloatFormat::F16F16 => version >= &Version(Api::GlEs, 3, 2),
573            UncompressedFloatFormat::F16F16F16F16 => version >= &Version(Api::GlEs, 3, 2),
574            UncompressedFloatFormat::F32 => version >= &Version(Api::GlEs, 3, 2),
575            UncompressedFloatFormat::F32F32 => version >= &Version(Api::GlEs, 3, 2),
576            UncompressedFloatFormat::F32F32F32F32 => version >= &Version(Api::GlEs, 3, 2),
577            UncompressedFloatFormat::F11F11F10 => version >= &Version(Api::GlEs, 3, 2),
578            _ => false
579        }
580    }
581
582    fn to_glenum(&self) -> gl::types::GLenum {
583        match self {
584            UncompressedFloatFormat::U8 => gl::R8,
585            UncompressedFloatFormat::I8 => gl::R8_SNORM,
586            UncompressedFloatFormat::U16 => gl::R16,
587            UncompressedFloatFormat::I16 => gl::R16_SNORM,
588            UncompressedFloatFormat::U8U8 => gl::RG8,
589            UncompressedFloatFormat::I8I8 => gl::RG8_SNORM,
590            UncompressedFloatFormat::U16U16 => gl::RG16,
591            UncompressedFloatFormat::I16I16 => gl::RG16_SNORM,
592            UncompressedFloatFormat::U3U3U2 => gl::R3_G3_B2,
593            UncompressedFloatFormat::U4U4U4 => gl::RGB4,
594            UncompressedFloatFormat::U5U5U5 => gl::RGB5,
595            UncompressedFloatFormat::U8U8U8 => gl::RGB8,
596            UncompressedFloatFormat::I8I8I8 => gl::RGB8_SNORM,
597            UncompressedFloatFormat::U10U10U10 => gl::RGB10,
598            UncompressedFloatFormat::U12U12U12 => gl::RGB12,
599            UncompressedFloatFormat::U16U16U16 => gl::RGB16,
600            UncompressedFloatFormat::I16I16I16 => gl::RGB16_SNORM,
601            UncompressedFloatFormat::U2U2U2U2 => gl::RGBA2,
602            UncompressedFloatFormat::U4U4U4U4 => gl::RGBA4,
603            UncompressedFloatFormat::U5U5U5U1 => gl::RGB5_A1,
604            UncompressedFloatFormat::U8U8U8U8 => gl::RGBA8,
605            UncompressedFloatFormat::I8I8I8I8 => gl::RGBA8_SNORM,
606            UncompressedFloatFormat::U10U10U10U2 => gl::RGB10_A2,
607            UncompressedFloatFormat::U12U12U12U12 => gl::RGBA12,
608            UncompressedFloatFormat::U16U16U16U16 => gl::RGBA16,
609            UncompressedFloatFormat::I16I16I16I16 => gl::RGBA16_SNORM,
610            UncompressedFloatFormat::F16 => gl::R16F,
611            UncompressedFloatFormat::F16F16 => gl::RG16F,
612            UncompressedFloatFormat::F16F16F16 => gl::RGB16F,
613            UncompressedFloatFormat::F16F16F16F16 => gl::RGBA16F,
614            UncompressedFloatFormat::F32 => gl::R32F,
615            UncompressedFloatFormat::F32F32 => gl::RG32F,
616            UncompressedFloatFormat::F32F32F32 => gl::RGB32F,
617            UncompressedFloatFormat::F32F32F32F32 => gl::RGBA32F,
618            UncompressedFloatFormat::F11F11F10 => gl::R11F_G11F_B10F,
619            UncompressedFloatFormat::F9F9F9 => gl::RGB9_E5,
620        }
621    }
622}
623
624/// List of uncompressed pixel formats that contain floating-point data in the sRGB color space.
625#[allow(missing_docs)]
626#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
627pub enum SrgbFormat {
628    U8U8U8,
629    U8U8U8U8,
630}
631
632impl SrgbFormat {
633    /// Returns a list of all the possible values of this enumeration.
634    #[inline]
635    pub fn get_formats_list() -> Vec<SrgbFormat> {
636        vec![
637            SrgbFormat::U8U8U8,
638            SrgbFormat::U8U8U8U8,
639        ]
640    }
641
642    /// Turns this format into a more generic `TextureFormat`.
643    #[inline]
644    pub fn to_texture_format(self) -> TextureFormat {
645        TextureFormat::Srgb(self)
646    }
647
648    /// Returns true if this format is supported by the backend.
649    pub fn is_supported<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
650        let version = context.get_version();
651        let extensions = context.get_extensions();
652
653        match self {
654            SrgbFormat::U8U8U8 => {
655                version >= &Version(Api::Gl, 2, 1) || version >= &Version(Api::GlEs, 3, 0) ||
656                   extensions.gl_ext_texture_srgb
657            },
658
659            SrgbFormat::U8U8U8U8 => {
660                version >= &Version(Api::Gl, 2, 1) || version >= &Version(Api::GlEs, 3, 0) ||
661                   extensions.gl_ext_texture_srgb
662            },
663        }
664    }
665
666    /// Returns true if a texture or renderbuffer with this format can be used as a framebuffer
667    /// attachment.
668    pub fn is_color_renderable<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
669        // checking whether it's supported, so that we don't return `true` by accident
670        if !self.is_supported(context) {
671            return false;
672        }
673
674        let version = context.get_version();
675        let extensions = context.get_extensions();
676
677        match self {
678            SrgbFormat::U8U8U8 => version >= &Version(Api::Gl, 1, 0),
679            SrgbFormat::U8U8U8U8 => version >= &Version(Api::Gl, 1, 0) ||
680                                     version >= &Version(Api::GlEs, 3, 0),
681        }
682    }
683
684    fn to_glenum(&self) -> gl::types::GLenum {
685        match self {
686            SrgbFormat::U8U8U8 => gl::SRGB8,
687            SrgbFormat::U8U8U8U8 => gl::SRGB8_ALPHA8,
688        }
689    }
690}
691
692/// List of uncompressed pixel formats that contain signed integral data.
693#[allow(missing_docs)]
694#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
695pub enum UncompressedIntFormat {
696    I8,
697    I16,
698    I32,
699    I8I8,
700    I16I16,
701    I32I32,
702    I8I8I8,
703    /// May not be supported by renderbuffers.
704    I16I16I16,
705    /// May not be supported by renderbuffers.
706    I32I32I32,
707    /// May not be supported by renderbuffers.
708    I8I8I8I8,
709    I16I16I16I16,
710    I32I32I32I32,
711}
712
713impl UncompressedIntFormat {
714    /// Returns a list of all the possible values of this enumeration.
715    #[inline]
716    pub fn get_formats_list() -> Vec<UncompressedIntFormat> {
717        vec![
718            UncompressedIntFormat::I8,
719            UncompressedIntFormat::I16,
720            UncompressedIntFormat::I32,
721            UncompressedIntFormat::I8I8,
722            UncompressedIntFormat::I16I16,
723            UncompressedIntFormat::I32I32,
724            UncompressedIntFormat::I8I8I8,
725            UncompressedIntFormat::I16I16I16,
726            UncompressedIntFormat::I32I32I32,
727            UncompressedIntFormat::I8I8I8I8,
728            UncompressedIntFormat::I16I16I16I16,
729            UncompressedIntFormat::I32I32I32I32,
730        ]
731    }
732
733    /// Turns this format into a more generic `TextureFormat`.
734    #[inline]
735    pub fn to_texture_format(self) -> TextureFormat {
736        TextureFormat::UncompressedIntegral(self)
737    }
738
739    /// Returns true if this format is supported by the backend.
740    pub fn is_supported<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
741        let version = context.get_version();
742        let extensions = context.get_extensions();
743
744        match self {
745            UncompressedIntFormat::I8 => {
746                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
747                                                       extensions.gl_arb_texture_rg)
748            },
749
750            UncompressedIntFormat::I16 => {
751                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
752                                                       extensions.gl_arb_texture_rg)
753            },
754
755            UncompressedIntFormat::I32 => {
756                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
757                                                       extensions.gl_arb_texture_rg)
758            },
759
760            UncompressedIntFormat::I8I8 => {
761                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
762                                                       extensions.gl_arb_texture_rg)
763            },
764
765            UncompressedIntFormat::I16I16 => {
766                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
767                                                       extensions.gl_arb_texture_rg)
768            },
769
770            UncompressedIntFormat::I32I32 => {
771                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
772                                                       extensions.gl_arb_texture_rg)
773            },
774
775            UncompressedIntFormat::I8I8I8 => {
776                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
777            },
778
779            UncompressedIntFormat::I16I16I16 => {
780                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
781            },
782
783            UncompressedIntFormat::I32I32I32 => {
784                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
785            },
786
787            UncompressedIntFormat::I8I8I8I8 => {
788                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
789            },
790
791            UncompressedIntFormat::I16I16I16I16 => {
792                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
793            },
794
795            UncompressedIntFormat::I32I32I32I32 => {
796                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
797            },
798        }
799    }
800
801    /// Returns true if a texture or renderbuffer with this format can be used as a framebuffer
802    /// attachment.
803    pub fn is_color_renderable<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
804        // checking whether it's supported, so that we don't return `true` by accident
805        if !self.is_supported(context) {
806            return false;
807        }
808
809        let version = context.get_version();
810
811        // if we have OpenGL, everything here is color-renderable
812        if version >= &Version(Api::Gl, 1, 0) {
813            return true;
814        }
815
816        // if we have OpenGL ES, it depends
817        match self {
818            UncompressedIntFormat::I8 => version >= &Version(Api::GlEs, 3, 0),
819            UncompressedIntFormat::I16 => version >= &Version(Api::GlEs, 3, 0),
820            UncompressedIntFormat::I32 => version >= &Version(Api::GlEs, 3, 0),
821            UncompressedIntFormat::I8I8 => version >= &Version(Api::GlEs, 3, 0),
822            UncompressedIntFormat::I16I16 => version >= &Version(Api::GlEs, 3, 0),
823            UncompressedIntFormat::I32I32 => version >= &Version(Api::GlEs, 3, 0),
824            UncompressedIntFormat::I8I8I8 => false,
825            UncompressedIntFormat::I16I16I16 => false,
826            UncompressedIntFormat::I32I32I32 => false,
827            UncompressedIntFormat::I8I8I8I8 => version >= &Version(Api::GlEs, 3, 0),
828            UncompressedIntFormat::I16I16I16I16 => version >= &Version(Api::GlEs, 3, 0),
829            UncompressedIntFormat::I32I32I32I32 => version >= &Version(Api::GlEs, 3, 0),
830        }
831    }
832
833    fn to_glenum(&self) -> gl::types::GLenum {
834        match self {
835            UncompressedIntFormat::I8 => gl::R8I,
836            UncompressedIntFormat::I16 => gl::R16I,
837            UncompressedIntFormat::I32 => gl::R32I,
838            UncompressedIntFormat::I8I8 => gl::RG8I,
839            UncompressedIntFormat::I16I16 => gl::RG16I,
840            UncompressedIntFormat::I32I32 => gl::RG32I,
841            UncompressedIntFormat::I8I8I8 => gl::RGB8I,
842            UncompressedIntFormat::I16I16I16 => gl::RGB16I,
843            UncompressedIntFormat::I32I32I32 => gl::RGB32I,
844            UncompressedIntFormat::I8I8I8I8 => gl::RGBA8I,
845            UncompressedIntFormat::I16I16I16I16 => gl::RGBA16I,
846            UncompressedIntFormat::I32I32I32I32 => gl::RGBA32I,
847        }
848    }
849}
850
851/// List of uncompressed pixel formats that contain unsigned integral data.
852#[allow(missing_docs)]
853#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
854pub enum UncompressedUintFormat {
855    U8,
856    U16,
857    U32,
858    U8U8,
859    U16U16,
860    U32U32,
861    U8U8U8,
862    /// May not be supported by renderbuffers.
863    U16U16U16,
864    /// May not be supported by renderbuffers.
865    U32U32U32,
866    /// May not be supported by renderbuffers.
867    U8U8U8U8,
868    U16U16U16U16,
869    U32U32U32U32,
870    U10U10U10U2,
871}
872
873impl UncompressedUintFormat {
874    /// Returns a list of all the possible values of this enumeration.
875    #[inline]
876    pub fn get_formats_list() -> Vec<UncompressedUintFormat> {
877        vec![
878            UncompressedUintFormat::U8,
879            UncompressedUintFormat::U16,
880            UncompressedUintFormat::U32,
881            UncompressedUintFormat::U8U8,
882            UncompressedUintFormat::U16U16,
883            UncompressedUintFormat::U32U32,
884            UncompressedUintFormat::U8U8U8,
885            UncompressedUintFormat::U16U16U16,
886            UncompressedUintFormat::U32U32U32,
887            UncompressedUintFormat::U8U8U8U8,
888            UncompressedUintFormat::U16U16U16U16,
889            UncompressedUintFormat::U32U32U32U32,
890            UncompressedUintFormat::U10U10U10U2,
891        ]
892    }
893
894    /// Turns this format into a more generic `TextureFormat`.
895    #[inline]
896    pub fn to_texture_format(self) -> TextureFormat {
897        TextureFormat::UncompressedUnsigned(self)
898    }
899
900    /// Returns true if this format is supported by the backend.
901    pub fn is_supported<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
902        let version = context.get_version();
903        let extensions = context.get_extensions();
904
905        match self {
906            UncompressedUintFormat::U8 => {
907                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
908                                                       extensions.gl_arb_texture_rg)
909            },
910
911            UncompressedUintFormat::U16 => {
912                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
913                                                       extensions.gl_arb_texture_rg)
914            },
915
916            UncompressedUintFormat::U32 => {
917                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
918                                                       extensions.gl_arb_texture_rg)
919            },
920
921            UncompressedUintFormat::U8U8 => {
922                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
923                                                       extensions.gl_arb_texture_rg)
924            },
925
926            UncompressedUintFormat::U16U16 => {
927                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
928                                                       extensions.gl_arb_texture_rg)
929            },
930
931            UncompressedUintFormat::U32U32 => {
932                version >= &Version(Api::Gl, 3, 0) || (extensions.gl_ext_texture_integer &&
933                                                       extensions.gl_arb_texture_rg)
934            },
935
936            UncompressedUintFormat::U8U8U8 => {
937                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
938            },
939
940            UncompressedUintFormat::U16U16U16 => {
941                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
942            },
943
944            UncompressedUintFormat::U32U32U32 => {
945                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
946            },
947
948            UncompressedUintFormat::U8U8U8U8 => {
949                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
950            },
951
952            UncompressedUintFormat::U16U16U16U16 => {
953                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
954            },
955
956            UncompressedUintFormat::U32U32U32U32 => {
957                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_texture_integer
958            },
959
960            UncompressedUintFormat::U10U10U10U2 => {
961                version >= &Version(Api::Gl, 3, 3) || extensions.gl_arb_texture_rgb10_a2ui
962            },
963        }
964    }
965
966    /// Returns true if a texture or renderbuffer with this format can be used as a framebuffer
967    /// attachment.
968    pub fn is_color_renderable<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
969        // checking whether it's supported, so that we don't return `true` by accident
970        if !self.is_supported(context) {
971            return false;
972        }
973
974        let version = context.get_version();
975
976        // if we have OpenGL, everything here is color-renderable
977        if version >= &Version(Api::Gl, 1, 0) {
978            return true;
979        }
980
981        // if we have OpenGL ES, it depends
982        match self {
983            UncompressedUintFormat::U8 => version >= &Version(Api::GlEs, 3, 0),
984            UncompressedUintFormat::U16 => version >= &Version(Api::GlEs, 3, 0),
985            UncompressedUintFormat::U32 => version >= &Version(Api::GlEs, 3, 0),
986            UncompressedUintFormat::U8U8 => version >= &Version(Api::GlEs, 3, 0),
987            UncompressedUintFormat::U16U16 => version >= &Version(Api::GlEs, 3, 0),
988            UncompressedUintFormat::U32U32 => version >= &Version(Api::GlEs, 3, 0),
989            UncompressedUintFormat::U8U8U8 => false,
990            UncompressedUintFormat::U16U16U16 => false,
991            UncompressedUintFormat::U32U32U32 => false,
992            UncompressedUintFormat::U8U8U8U8 => version >= &Version(Api::GlEs, 3, 0),
993            UncompressedUintFormat::U16U16U16U16 => version >= &Version(Api::GlEs, 3, 0),
994            UncompressedUintFormat::U32U32U32U32 => version >= &Version(Api::GlEs, 3, 0),
995            UncompressedUintFormat::U10U10U10U2 => version >= &Version(Api::GlEs, 3, 0),
996        }
997    }
998
999    fn to_glenum(&self) -> gl::types::GLenum {
1000        match self {
1001            UncompressedUintFormat::U8 => gl::R8UI,
1002            UncompressedUintFormat::U16 => gl::R16UI,
1003            UncompressedUintFormat::U32 => gl::R32UI,
1004            UncompressedUintFormat::U8U8 => gl::RG8UI,
1005            UncompressedUintFormat::U16U16 => gl::RG16UI,
1006            UncompressedUintFormat::U32U32 => gl::RG32UI,
1007            UncompressedUintFormat::U8U8U8 => gl::RGB8UI,
1008            UncompressedUintFormat::U16U16U16 => gl::RGB16UI,
1009            UncompressedUintFormat::U32U32U32 => gl::RGB32UI,
1010            UncompressedUintFormat::U8U8U8U8 => gl::RGBA8UI,
1011            UncompressedUintFormat::U16U16U16U16 => gl::RGBA16UI,
1012            UncompressedUintFormat::U32U32U32U32 => gl::RGBA32UI,
1013            UncompressedUintFormat::U10U10U10U2 => gl::RGB10_A2UI,
1014        }
1015    }
1016}
1017
1018/// List of compressed texture formats.
1019#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1020pub enum CompressedFormat {
1021    /// Red/green compressed texture with one unsigned component.
1022    RgtcFormatU,
1023    /// Red/green compressed texture with one signed component.
1024    RgtcFormatI,
1025    /// Red/green compressed texture with two unsigned components.
1026    RgtcFormatUU,
1027    /// Red/green compressed texture with two signed components.
1028    RgtcFormatII,
1029
1030    /// BPTC format with four components represented as integers.
1031    BptcUnorm4,
1032    /// BPTC format with three components (no alpha) represented as signed floats.
1033    BptcSignedFloat3,
1034    /// BPTC format with three components (no alpha) represented as unsigned floats.
1035    BptcUnsignedFloat3,
1036
1037    /// S3TC DXT1 without alpha, see <https://www.opengl.org/wiki/S3_Texture_Compression>.
1038    S3tcDxt1NoAlpha,
1039    /// S3TC DXT1 with 1-bit alpha, see <https://www.opengl.org/wiki/S3_Texture_Compression>.
1040    S3tcDxt1Alpha,
1041    /// S3TC DXT3, see <https://www.opengl.org/wiki/S3_Texture_Compression>.
1042    S3tcDxt3Alpha,
1043    /// S3TC DXT5, see <https://www.opengl.org/wiki/S3_Texture_Compression>.
1044    S3tcDxt5Alpha,
1045}
1046
1047impl CompressedFormat {
1048    /// Returns a list of all the possible values of this enumeration.
1049    #[inline]
1050    pub fn get_formats_list() -> Vec<CompressedFormat> {
1051        vec![
1052            CompressedFormat::RgtcFormatU,
1053            CompressedFormat::RgtcFormatI,
1054            CompressedFormat::RgtcFormatUU,
1055            CompressedFormat::RgtcFormatII,
1056            CompressedFormat::BptcUnorm4,
1057            CompressedFormat::BptcSignedFloat3,
1058            CompressedFormat::BptcUnsignedFloat3,
1059            CompressedFormat::S3tcDxt1NoAlpha,
1060            CompressedFormat::S3tcDxt1Alpha,
1061            CompressedFormat::S3tcDxt3Alpha,
1062            CompressedFormat::S3tcDxt5Alpha,
1063        ]
1064    }
1065
1066    /// Turns this format into a more generic `TextureFormat`.
1067    #[inline]
1068    pub fn to_texture_format(self) -> TextureFormat {
1069        TextureFormat::CompressedFormat(self)
1070    }
1071
1072    /// Returns true if this format is supported by the backend.
1073    pub fn is_supported<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
1074        let version = context.get_version();
1075        let extensions = context.get_extensions();
1076
1077        match self {
1078            CompressedFormat::RgtcFormatU => {
1079                version >= &Version(Api::Gl, 3, 0)
1080            },
1081            CompressedFormat::RgtcFormatI => {
1082                version >= &Version(Api::Gl, 3, 0)
1083            },
1084            CompressedFormat::RgtcFormatUU => {
1085                version >= &Version(Api::Gl, 3, 0)
1086            },
1087            CompressedFormat::RgtcFormatII => {
1088                version >= &Version(Api::Gl, 3, 0)
1089            },
1090            CompressedFormat::BptcUnorm4 => {
1091                version >= &Version(Api::Gl, 4, 2) || extensions.gl_arb_texture_compression_bptc
1092            },
1093            CompressedFormat::BptcSignedFloat3 => {
1094                version >= &Version(Api::Gl, 4, 2) || extensions.gl_arb_texture_compression_bptc
1095            },
1096            CompressedFormat::BptcUnsignedFloat3 => {
1097                version >= &Version(Api::Gl, 4, 2) || extensions.gl_arb_texture_compression_bptc
1098            },
1099            CompressedFormat::S3tcDxt1NoAlpha => {
1100                extensions.gl_ext_texture_compression_s3tc
1101            },
1102            CompressedFormat::S3tcDxt1Alpha => {
1103                extensions.gl_ext_texture_compression_s3tc
1104            },
1105            CompressedFormat::S3tcDxt3Alpha => {
1106                extensions.gl_ext_texture_compression_s3tc
1107            },
1108            CompressedFormat::S3tcDxt5Alpha => {
1109                extensions.gl_ext_texture_compression_s3tc
1110            },
1111        }
1112    }
1113
1114    fn to_glenum(&self) -> gl::types::GLenum {
1115        match self {
1116            CompressedFormat::RgtcFormatU => gl::COMPRESSED_RED_RGTC1,
1117            CompressedFormat::RgtcFormatI => gl::COMPRESSED_SIGNED_RED_RGTC1,
1118            CompressedFormat::RgtcFormatUU => gl::COMPRESSED_RG_RGTC2,
1119            CompressedFormat::RgtcFormatII => gl::COMPRESSED_SIGNED_RG_RGTC2,
1120            CompressedFormat::BptcUnorm4 => gl::COMPRESSED_RGBA_BPTC_UNORM,
1121            CompressedFormat::BptcSignedFloat3 => gl::COMPRESSED_RGB_BPTC_SIGNED_FLOAT,
1122            CompressedFormat::BptcUnsignedFloat3 => gl::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,
1123            CompressedFormat::S3tcDxt1NoAlpha => gl::COMPRESSED_RGB_S3TC_DXT1_EXT,
1124            CompressedFormat::S3tcDxt1Alpha => gl::COMPRESSED_RGBA_S3TC_DXT1_EXT,
1125            CompressedFormat::S3tcDxt3Alpha => gl::COMPRESSED_RGBA_S3TC_DXT3_EXT,
1126            CompressedFormat::S3tcDxt5Alpha => gl::COMPRESSED_RGBA_S3TC_DXT5_EXT,
1127        }
1128    }
1129}
1130
1131/// List of compressed pixel formats in the sRGB color space.
1132#[allow(missing_docs)]
1133#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1134pub enum CompressedSrgbFormat {
1135    /// BPTC format. sRGB with alpha. Also called `BC7` by DirectX.
1136    Bptc,
1137    S3tcDxt1NoAlpha,
1138    S3tcDxt1Alpha,
1139    S3tcDxt3Alpha,
1140    S3tcDxt5Alpha,
1141}
1142
1143impl CompressedSrgbFormat {
1144    /// Returns a list of all the possible values of this enumeration.
1145    #[inline]
1146    pub fn get_formats_list() -> Vec<CompressedSrgbFormat> {
1147        vec![
1148            CompressedSrgbFormat::Bptc,
1149            CompressedSrgbFormat::S3tcDxt1NoAlpha,
1150            CompressedSrgbFormat::S3tcDxt1Alpha,
1151            CompressedSrgbFormat::S3tcDxt3Alpha,
1152            CompressedSrgbFormat::S3tcDxt5Alpha,
1153        ]
1154    }
1155
1156    /// Turns this format into a more generic `TextureFormat`.
1157    #[inline]
1158    pub fn to_texture_format(self) -> TextureFormat {
1159        TextureFormat::CompressedSrgbFormat(self)
1160    }
1161
1162    /// Returns true if this format is supported by the backend.
1163    pub fn is_supported<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
1164        let version = context.get_version();
1165        let extensions = context.get_extensions();
1166
1167        match self {
1168            CompressedSrgbFormat::Bptc => {
1169                version >= &Version(Api::Gl, 4, 2) || extensions.gl_arb_texture_compression_bptc
1170            },
1171            CompressedSrgbFormat::S3tcDxt1NoAlpha => {
1172                extensions.gl_ext_texture_compression_s3tc && extensions.gl_ext_texture_srgb
1173            },
1174            CompressedSrgbFormat::S3tcDxt1Alpha => {
1175                extensions.gl_ext_texture_compression_s3tc && extensions.gl_ext_texture_srgb
1176            },
1177            CompressedSrgbFormat::S3tcDxt3Alpha => {
1178                extensions.gl_ext_texture_compression_s3tc && extensions.gl_ext_texture_srgb
1179            },
1180            CompressedSrgbFormat::S3tcDxt5Alpha => {
1181                extensions.gl_ext_texture_compression_s3tc && extensions.gl_ext_texture_srgb
1182            },
1183        }
1184    }
1185
1186    fn to_glenum(&self) -> gl::types::GLenum {
1187        match self {
1188            CompressedSrgbFormat::Bptc => gl::COMPRESSED_SRGB_ALPHA_BPTC_UNORM,
1189            CompressedSrgbFormat::S3tcDxt1NoAlpha => gl::COMPRESSED_SRGB_S3TC_DXT1_EXT,
1190            CompressedSrgbFormat::S3tcDxt1Alpha => gl::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
1191            CompressedSrgbFormat::S3tcDxt3Alpha => gl::COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
1192            CompressedSrgbFormat::S3tcDxt5Alpha => gl::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
1193        }
1194    }
1195}
1196
1197/// List of formats available for depth textures.
1198///
1199/// `I16`, `I24` and `I32` are still treated as if they were floating points.
1200/// Only the internal representation is integral.
1201#[allow(missing_docs)]
1202#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1203pub enum DepthFormat {
1204    I16,
1205    I24,
1206    /// May not be supported by all hardware.
1207    I32,
1208    F32,
1209}
1210
1211impl DepthFormat {
1212    /// Returns a list of all the possible values of this enumeration.
1213    #[inline]
1214    pub fn get_formats_list() -> Vec<DepthFormat> {
1215        vec![
1216            DepthFormat::I16,
1217            DepthFormat::I24,
1218            DepthFormat::I32,
1219            DepthFormat::F32,
1220        ]
1221    }
1222
1223    /// Turns this format into a more generic `TextureFormat`.
1224    #[inline]
1225    pub fn to_texture_format(self) -> TextureFormat {
1226        TextureFormat::DepthFormat(self)
1227    }
1228
1229    /// Returns true if this format is supported by the backend.
1230    pub fn is_supported<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
1231        let version = context.get_version();
1232        let extensions = context.get_extensions();
1233
1234        match self {
1235            DepthFormat::I16 => {
1236                version >= &Version(Api::Gl, 3, 0) || extensions.gl_arb_depth_texture
1237            },
1238
1239            DepthFormat::I24 => {
1240                version >= &Version(Api::Gl, 3, 0) || extensions.gl_arb_depth_texture
1241            },
1242
1243            DepthFormat::I32 => {
1244                version >= &Version(Api::Gl, 3, 0) || extensions.gl_arb_depth_texture
1245            },
1246
1247            DepthFormat::F32 => {
1248                version >= &Version(Api::Gl, 3, 0)
1249            },
1250        }
1251    }
1252
1253    fn to_glenum(&self) -> gl::types::GLenum {
1254        match self {
1255            DepthFormat::I16 => gl::DEPTH_COMPONENT16,
1256            DepthFormat::I24 => gl::DEPTH_COMPONENT24,
1257            DepthFormat::I32 => gl::DEPTH_COMPONENT32,
1258            DepthFormat::F32 => gl::DEPTH_COMPONENT32F,
1259        }
1260    }
1261}
1262
1263/// List of formats available for depth-stencil textures.
1264// TODO: If OpenGL 4.3 or ARB_stencil_texturing is not available, then depth/stencil
1265//       textures are treated by samplers exactly like depth-only textures
1266#[allow(missing_docs)]
1267#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1268pub enum DepthStencilFormat {
1269    I24I8,
1270    F32I8,
1271}
1272
1273impl DepthStencilFormat {
1274    /// Returns a list of all the possible values of this enumeration.
1275    #[inline]
1276    pub fn get_formats_list() -> Vec<DepthStencilFormat> {
1277        vec![
1278            DepthStencilFormat::I24I8,
1279            DepthStencilFormat::F32I8,
1280        ]
1281    }
1282
1283    /// Turns this format into a more generic `TextureFormat`.
1284    #[inline]
1285    pub fn to_texture_format(self) -> TextureFormat {
1286        TextureFormat::DepthStencilFormat(self)
1287    }
1288
1289    /// Returns true if this format is supported by the backend.
1290    pub fn is_supported<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
1291        let version = context.get_version();
1292        let extensions = context.get_extensions();
1293
1294        match self {
1295            DepthStencilFormat::I24I8 => {
1296                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_packed_depth_stencil ||
1297                    extensions.gl_oes_packed_depth_stencil
1298            },
1299
1300            DepthStencilFormat::F32I8 => {
1301                version >= &Version(Api::Gl, 3, 0)
1302            },
1303        }
1304    }
1305
1306    fn to_glenum(&self) -> gl::types::GLenum {
1307        match self {
1308            DepthStencilFormat::I24I8 => gl::DEPTH24_STENCIL8,
1309            DepthStencilFormat::F32I8 => gl::DEPTH32F_STENCIL8,
1310        }
1311    }
1312}
1313
1314/// List of formats available for stencil textures.
1315///
1316/// You are strongly advised to only use `I8`.
1317///
1318/// Stencil textures are a very recent OpenGL feature that may not be supported everywhere.
1319/// Only `I8` is supported for textures. All the other formats can only be used with renderbuffers.
1320#[allow(missing_docs)]
1321#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1322pub enum StencilFormat {
1323    I1,
1324    I4,
1325    I8,
1326    I16,
1327}
1328
1329impl StencilFormat {
1330    /// Returns a list of all the possible values of this enumeration.
1331    #[inline]
1332    pub fn get_formats_list() -> Vec<StencilFormat> {
1333        vec![
1334            StencilFormat::I1,
1335            StencilFormat::I4,
1336            StencilFormat::I8,
1337            StencilFormat::I16,
1338        ]
1339    }
1340
1341    /// Turns this format into a more generic `TextureFormat`.
1342    #[inline]
1343    pub fn to_texture_format(self) -> TextureFormat {
1344        TextureFormat::StencilFormat(self)
1345    }
1346
1347    /// Returns true if this format is supported by the backend for textures.
1348    pub fn is_supported_for_textures<C: ?Sized>(&self, context: &C) -> bool where C: CapabilitiesSource {
1349        let version = context.get_version();
1350        let extensions = context.get_extensions();
1351
1352        match self {
1353            StencilFormat::I8 => {
1354                version >= &Version(Api::Gl, 4, 4) || version >= &Version(Api::GlEs, 3, 2) ||
1355                extensions.gl_arb_texture_stencil8 || extensions.gl_oes_texture_stencil8
1356            },
1357
1358            _ => false
1359        }
1360    }
1361
1362    /// Returns true if this format is supported by the backend for renderbuffers.
1363    pub fn is_supported_for_renderbuffers<C: ?Sized>(&self, context: &C) -> bool
1364                                             where C: CapabilitiesSource
1365    {
1366        let version = context.get_version();
1367        let extensions = context.get_extensions();
1368
1369        match self {
1370            StencilFormat::I1 => {
1371                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_framebuffer_object ||
1372                    extensions.gl_arb_framebuffer_object || extensions.gl_oes_stencil1
1373            },
1374
1375            StencilFormat::I4 => {
1376                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_framebuffer_object ||
1377                    extensions.gl_arb_framebuffer_object || extensions.gl_oes_stencil4
1378            },
1379
1380            StencilFormat::I8 => {
1381                version >= &Version(Api::Gl, 3, 0) || extensions.gl_arb_texture_stencil8 ||
1382                    version >= &Version(Api::GlEs, 2, 0)
1383            },
1384
1385            StencilFormat::I16 => {
1386                version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_framebuffer_object ||
1387                    extensions.gl_arb_framebuffer_object
1388            },
1389        }
1390    }
1391
1392    fn to_glenum(&self) -> gl::types::GLenum {
1393        match self {
1394            StencilFormat::I1 => gl::STENCIL_INDEX1,
1395            StencilFormat::I4 => gl::STENCIL_INDEX4,
1396            StencilFormat::I8 => gl::STENCIL_INDEX8,
1397            StencilFormat::I16 => gl::STENCIL_INDEX16,
1398        }
1399    }
1400}
1401
1402/// Format of the internal representation of a texture.
1403#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1404#[allow(missing_docs)]
1405pub enum TextureFormat {
1406    UncompressedFloat(UncompressedFloatFormat),
1407    UncompressedIntegral(UncompressedIntFormat),
1408    UncompressedUnsigned(UncompressedUintFormat),
1409    Srgb(SrgbFormat),
1410    CompressedFormat(CompressedFormat),
1411    CompressedSrgbFormat(CompressedSrgbFormat),
1412    DepthFormat(DepthFormat),
1413    StencilFormat(StencilFormat),
1414    DepthStencilFormat(DepthStencilFormat),
1415}
1416
1417impl TextureFormat {
1418    /// Returns a list of all the possible values of this enumeration.
1419    #[inline]
1420    pub fn get_formats_list() -> Vec<TextureFormat> {
1421        // Chaining so many iterators can blow up the stack on some platforms
1422        let mut result: Vec<_> = UncompressedFloatFormat::get_formats_list().into_iter().map(|f| f.to_texture_format()).collect();
1423        result.extend(UncompressedIntFormat::get_formats_list().into_iter().map(|f| f.to_texture_format()));
1424        result.extend(UncompressedUintFormat::get_formats_list().into_iter().map(|f| f.to_texture_format()));
1425        result.extend(SrgbFormat::get_formats_list().into_iter().map(|f| f.to_texture_format()));
1426        result.extend(CompressedFormat::get_formats_list().into_iter().map(|f| f.to_texture_format()));
1427        result.extend(CompressedSrgbFormat::get_formats_list().into_iter().map(|f| f.to_texture_format()));
1428        result.extend(DepthFormat::get_formats_list().into_iter().map(|f| f.to_texture_format()));
1429        result.extend(StencilFormat::get_formats_list().into_iter().map(|f| f.to_texture_format()));
1430        result.extend(DepthStencilFormat::get_formats_list().into_iter().map(|f| f.to_texture_format()));
1431        result
1432    }
1433
1434    /// Returns true if this format is supported by the backend for textures.
1435    #[inline]
1436    pub fn is_supported_for_textures<C: ?Sized>(&self, c: &C) -> bool where C: CapabilitiesSource {
1437        match self {
1438            TextureFormat::UncompressedFloat(format) => format.is_supported(c),
1439            TextureFormat::UncompressedIntegral(format) => format.is_supported(c),
1440            TextureFormat::UncompressedUnsigned(format) => format.is_supported(c),
1441            TextureFormat::Srgb(format) => format.is_supported(c),
1442            TextureFormat::CompressedFormat(format) => format.is_supported(c),
1443            TextureFormat::CompressedSrgbFormat(format) => format.is_supported(c),
1444            TextureFormat::DepthFormat(format) => format.is_supported(c),
1445            TextureFormat::StencilFormat(format) => format.is_supported_for_textures(c),
1446            TextureFormat::DepthStencilFormat(format) => format.is_supported(c),
1447        }
1448    }
1449
1450    /// Returns true if this format is supported by the backend for renderbuffers.
1451    #[inline]
1452    pub fn is_supported_for_renderbuffers<C: ?Sized>(&self, c: &C) -> bool where C: CapabilitiesSource {
1453        match self {
1454            TextureFormat::UncompressedFloat(format) => format.is_supported(c),
1455            TextureFormat::UncompressedIntegral(format) => format.is_supported(c),
1456            TextureFormat::UncompressedUnsigned(format) => format.is_supported(c),
1457            TextureFormat::Srgb(format) => format.is_supported(c),
1458            TextureFormat::CompressedFormat(format) => format.is_supported(c),
1459            TextureFormat::CompressedSrgbFormat(format) => format.is_supported(c),
1460            TextureFormat::DepthFormat(format) => format.is_supported(c),
1461            TextureFormat::StencilFormat(format) => format.is_supported_for_renderbuffers(c),
1462            TextureFormat::DepthStencilFormat(format) => format.is_supported(c),
1463        }
1464    }
1465
1466    /// Returns true if the format is color-renderable, depth-renderable, depth-stencil-renderable
1467    /// or stencil-renderable.
1468    #[inline]
1469    pub fn is_renderable<C: ?Sized>(&self, c: &C) -> bool where C: CapabilitiesSource {
1470        match self {
1471            TextureFormat::UncompressedFloat(format) => format.is_color_renderable(c),
1472            TextureFormat::UncompressedIntegral(format) => format.is_color_renderable(c),
1473            TextureFormat::UncompressedUnsigned(format) => format.is_color_renderable(c),
1474            TextureFormat::Srgb(format) => format.is_color_renderable(c),
1475            TextureFormat::CompressedFormat(_) => false,
1476            TextureFormat::CompressedSrgbFormat(_) => false,
1477            TextureFormat::DepthFormat(_) => true,
1478            TextureFormat::StencilFormat(_) => true,
1479            TextureFormat::DepthStencilFormat(_) => true,
1480        }
1481    }
1482}
1483
1484impl ToGlEnum for TextureFormat {
1485    fn to_glenum(&self) -> gl::types::GLenum {
1486        match self {
1487            TextureFormat::UncompressedFloat(f) => f.to_glenum(),
1488            TextureFormat::UncompressedIntegral(f) => f.to_glenum(),
1489            TextureFormat::UncompressedUnsigned(f) => f.to_glenum(),
1490            TextureFormat::Srgb(f) => f.to_glenum(),
1491            TextureFormat::CompressedFormat(f) => f.to_glenum(),
1492            TextureFormat::CompressedSrgbFormat(f) => f.to_glenum(),
1493            TextureFormat::DepthFormat(f) => f.to_glenum(),
1494            TextureFormat::StencilFormat(f) => f.to_glenum(),
1495            TextureFormat::DepthStencilFormat(f) => f.to_glenum(),
1496        }
1497    }
1498}
1499
1500#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1501pub enum ClientFormatAny {
1502    ClientFormat(ClientFormat),
1503    CompressedFormat(CompressedFormat),
1504    CompressedSrgbFormat(CompressedSrgbFormat),
1505}
1506
1507impl ClientFormatAny {
1508    /// Checks if this format is a compressed format.
1509    #[inline]
1510    pub fn is_compressed(&self) -> bool {
1511        match *self {
1512            ClientFormatAny::ClientFormat(_) => false,
1513            ClientFormatAny::CompressedFormat(_) => true,
1514            ClientFormatAny::CompressedSrgbFormat(_) => true,
1515        }
1516    }
1517
1518    /// Gets the size in bytes of the buffer required to store a uncompressed image
1519    /// of the specified dimensions on this format.
1520    ///
1521    /// ## Panic
1522    ///
1523    /// Panics if the dimensions are invalid for this format.
1524    pub fn get_buffer_size(&self, width: u32, height: Option<u32>,
1525                           depth: Option<u32>, array_size: Option<u32>) -> usize {
1526        match *self {
1527            ClientFormatAny::ClientFormat(ref format) => {
1528                format.get_size() * width as usize * height.unwrap_or(1) as usize *
1529                                depth.unwrap_or(1) as usize * array_size.unwrap_or(1) as usize
1530            },
1531
1532            // 8 bytes per 4x4 block
1533            ClientFormatAny::CompressedFormat(CompressedFormat::S3tcDxt1Alpha) |
1534            ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::S3tcDxt1Alpha) |
1535            ClientFormatAny::CompressedFormat(CompressedFormat::S3tcDxt1NoAlpha) |
1536            ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::S3tcDxt1NoAlpha) |
1537            ClientFormatAny::CompressedFormat(CompressedFormat::RgtcFormatU) |
1538            ClientFormatAny::CompressedFormat(CompressedFormat::RgtcFormatI) => {
1539
1540                let width = if width < 4 { 4 } else { width as usize };
1541                let height = height.map(|height| if height < 4 { 4 } else { height as usize })
1542                                   .expect("ST3C, RGTC and BPTC textures must have 2 dimensions");
1543                if (width % 4) != 0 || (height % 4) != 0 {
1544                    panic!("ST3C, RGTC and BPTC textures must have a width and height multiple of 4.");
1545                }
1546                if depth.is_some() { // allow `array_size` (2D textures arrays) but not depth (3D textures)
1547                    panic!("ST3C, RGTC and BPTC textures are 2 dimension only.")
1548                }
1549
1550                let uncompressed_bit_size =  4 * width as usize * height as usize *
1551                                            depth.unwrap_or(1) as usize * array_size.unwrap_or(1) as usize;
1552                uncompressed_bit_size / 8   // Apply 8:1 compression ratio
1553            },
1554
1555            // 16 bytes per 4x4 block
1556            ClientFormatAny::CompressedFormat(CompressedFormat::S3tcDxt3Alpha) |
1557            ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::S3tcDxt3Alpha) |
1558            ClientFormatAny::CompressedFormat(CompressedFormat::S3tcDxt5Alpha) |
1559            ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::S3tcDxt5Alpha) |
1560            ClientFormatAny::CompressedFormat(CompressedFormat::BptcUnorm4) |
1561            ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::Bptc) |
1562            ClientFormatAny::CompressedFormat(CompressedFormat::BptcSignedFloat3) |
1563            ClientFormatAny::CompressedFormat(CompressedFormat::BptcUnsignedFloat3) |
1564            ClientFormatAny::CompressedFormat(CompressedFormat::RgtcFormatUU) |
1565            ClientFormatAny::CompressedFormat(CompressedFormat::RgtcFormatII) => {
1566
1567                let width = if width < 4 { 4 } else { width as usize };
1568                let height = height.map(|height| if height < 4 { 4 } else { height as usize })
1569                                   .expect("ST3C, RGTC and BPTC textures must have 2 dimensions");
1570                if (width % 4) != 0 || (height % 4) != 0 {
1571                    panic!("ST3C, RGTC and BPTC textures must have a width and height multiple of 4.");
1572                }
1573                if depth.is_some() { // allow `array_size` (2D textures arrays) but not depth (3D textures)
1574                    panic!("ST3C, RGTC and BPTC textures are 2 dimension only.")
1575                }
1576
1577                let uncompressed_bit_size =  4 * width as usize * height as usize *
1578                                            depth.unwrap_or(1) as usize * array_size.unwrap_or(1) as usize;
1579                uncompressed_bit_size / 4   // Apply 4:1 compression ratio
1580            },
1581        }
1582    }
1583
1584    #[inline]
1585    pub fn get_num_components(&self) -> u8 {
1586        match *self {
1587            ClientFormatAny::ClientFormat(ref format) => format.get_num_components(),
1588            _ => unimplemented!(),
1589        }
1590    }
1591
1592    #[doc(hidden)]
1593    pub fn from_internal_compressed_format(internal: gl::types::GLenum) -> Option<ClientFormatAny> {
1594        match internal {
1595            gl::COMPRESSED_RGB_S3TC_DXT1_EXT => Some(ClientFormatAny::CompressedFormat(CompressedFormat::S3tcDxt1NoAlpha)),
1596            gl::COMPRESSED_RGBA_S3TC_DXT1_EXT => Some(ClientFormatAny::CompressedFormat(CompressedFormat::S3tcDxt1Alpha)),
1597            gl::COMPRESSED_RGBA_S3TC_DXT3_EXT => Some(ClientFormatAny::CompressedFormat(CompressedFormat::S3tcDxt3Alpha)),
1598            gl::COMPRESSED_RGBA_S3TC_DXT5_EXT => Some(ClientFormatAny::CompressedFormat(CompressedFormat::S3tcDxt5Alpha)),
1599            gl::COMPRESSED_SRGB_S3TC_DXT1_EXT => Some(ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::S3tcDxt1NoAlpha)),
1600            gl::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT => Some(ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::S3tcDxt1Alpha)),
1601            gl::COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT => Some(ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::S3tcDxt3Alpha)),
1602            gl::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT => Some(ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::S3tcDxt5Alpha)),
1603            gl::COMPRESSED_RGBA_BPTC_UNORM => Some(ClientFormatAny::CompressedFormat(CompressedFormat::BptcUnorm4)),
1604            gl::COMPRESSED_SRGB_ALPHA_BPTC_UNORM => Some(ClientFormatAny::CompressedSrgbFormat(CompressedSrgbFormat::Bptc)),
1605            gl::COMPRESSED_RGB_BPTC_SIGNED_FLOAT => Some(ClientFormatAny::CompressedFormat(CompressedFormat::BptcSignedFloat3)),
1606            gl::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT => Some(ClientFormatAny::CompressedFormat(CompressedFormat::BptcUnsignedFloat3)),
1607            gl::COMPRESSED_RED_RGTC1 => Some(ClientFormatAny::CompressedFormat(CompressedFormat::RgtcFormatU)),
1608            gl::COMPRESSED_SIGNED_RED_RGTC1 => Some(ClientFormatAny::CompressedFormat(CompressedFormat::RgtcFormatI)),
1609            gl::COMPRESSED_RG_RGTC2 => Some(ClientFormatAny::CompressedFormat(CompressedFormat::RgtcFormatUU)),
1610            gl::COMPRESSED_SIGNED_RG_RGTC2 => Some(ClientFormatAny::CompressedFormat(CompressedFormat::RgtcFormatII)),
1611            _ => None,
1612        }
1613    }
1614}
1615
1616/// Type of request.
1617#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1618pub enum RequestType {
1619    /// A format suitable for `glTexImage#D`.
1620    TexImage(Option<ClientFormatAny>),
1621    /// A format suitable for `glTexStorage#D`.
1622    TexStorage,
1623    /// A format suitable for `glRenderbufferStorage`.
1624    Renderbuffer,
1625}
1626
1627impl RequestType {
1628    /// Returns the client format of the data that will be put in the texture.
1629    #[inline]
1630    pub fn get_client_format(&self) -> Option<ClientFormatAny> {
1631        match self {
1632            RequestType::TexImage(f) => *f,
1633            RequestType::TexStorage => None,
1634            RequestType::Renderbuffer => None,
1635        }
1636    }
1637}
1638
1639/// Checks that the texture format is supported and compatible with the client format.
1640///
1641/// Returns two `GLenum`s. The first one can be unsized and is suitable for the internal format
1642/// of `glTexImage#D`. The second one is always sized and is suitable for `glTexStorage*D` or
1643/// `glRenderbufferStorage`.
1644pub fn format_request_to_glenum(context: &Context, format: TextureFormatRequest,
1645                                rq_ty: RequestType)
1646                                -> Result<gl::types::GLenum, FormatNotSupportedError>
1647{
1648    let version = context.get_opengl_version();
1649    let extensions = context.get_extensions();
1650
1651    let is_client_compressed = match rq_ty.get_client_format() {
1652        Some(ref client) => client.is_compressed(),
1653        None => false,
1654    };
1655
1656    Ok(match format {
1657        /*******************************************************************/
1658        /*                           REGULAR                               */
1659        /*******************************************************************/
1660        TextureFormatRequest::AnyFloatingPoint => {
1661            let size = rq_ty.get_client_format().map(|c| c.get_num_components());
1662
1663            if version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) {
1664
1665                match (rq_ty, size) {
1666                    (RequestType::TexImage(_), Some(1)) => gl::RED,
1667                    (RequestType::TexImage(_), Some(2)) => gl::RG,
1668                    (RequestType::TexImage(_), Some(3)) => gl::RGB,
1669                    (RequestType::TexImage(_), Some(4)) => gl::RGBA,
1670                    (RequestType::TexImage(_), None) => gl::RGBA,
1671                    (_, Some(1)) => gl::R8,
1672                    (_, Some(2)) => gl::RG8,
1673                    (_, Some(3)) => gl::RGB8,
1674                    (_, Some(4)) => gl::RGBA8,
1675                    (_, None) => gl::RGBA8,
1676                    _ => unreachable!(),
1677                }
1678
1679            } else if version >= &Version(Api::Gl, 1, 1) {
1680                match (rq_ty, size) {
1681                    (RequestType::TexImage(_), Some(1)) => gl::RED,
1682                    (RequestType::TexImage(_), Some(2)) => gl::RG,
1683                    (RequestType::TexImage(_), Some(3)) => gl::RGB,
1684                    (RequestType::TexImage(_), Some(4)) => gl::RGBA,
1685                    (RequestType::TexImage(_), None) => gl::RGBA,
1686                    (_, Some(1)) if extensions.gl_arb_texture_rg => gl::R8,
1687                    (_, Some(2)) if extensions.gl_arb_texture_rg => gl::RG8,
1688                    (_, Some(3)) => gl::RGB8,
1689                    (_, Some(4)) => gl::RGBA8,
1690                    (_, None) => gl::RGBA8,
1691                    _ => return Err(FormatNotSupportedError),
1692                }
1693
1694            } else if version >= &Version(Api::Gl, 1, 0) {
1695                match rq_ty {
1696                    RequestType::TexImage(_) => size.unwrap_or(4) as gl::types::GLenum,
1697                    _ => return Err(FormatNotSupportedError)
1698                }
1699
1700            } else if version >= &Version(Api::GlEs, 2, 0) {
1701                match (rq_ty, size) {
1702                    (RequestType::TexImage(_), Some(3)) => gl::RGB,
1703                    (_, Some(3)) => {
1704                        if extensions.gl_oes_rgb8_rgba8 {
1705                            gl::RGB8_OES
1706                        } else if extensions.gl_arm_rgba8 {
1707                            gl::RGBA8_OES
1708                        } else {
1709                            gl::RGB565
1710                        }
1711                    },
1712                    (RequestType::TexImage(_), Some(4)) => gl::RGBA,
1713                    (RequestType::TexImage(_), None) => gl::RGBA,
1714                    (_, Some(4)) | (_, None) => {
1715                        if extensions.gl_oes_rgb8_rgba8 || extensions.gl_arm_rgba8 {
1716                            gl::RGBA8_OES
1717                        } else {
1718                            gl::RGB5_A1
1719                        }
1720                    },
1721                    _ => return Err(FormatNotSupportedError)
1722                }
1723
1724            } else {
1725                unreachable!();
1726            }
1727        },
1728
1729        TextureFormatRequest::Specific(TextureFormat::UncompressedFloat(format)) => {
1730            if format.is_supported(context) {
1731                format.to_glenum()
1732            } else {
1733                return Err(FormatNotSupportedError);
1734            }
1735        },
1736
1737        /*******************************************************************/
1738        /*                         COMPRESSED                              */
1739        /*******************************************************************/
1740        TextureFormatRequest::AnyCompressed if is_client_compressed => {
1741            // Note: client is always Some here. When refactoring this function it'd be a good idea
1742            // to let the client participate on the matching process.
1743            let newformat = TextureFormat::CompressedFormat(match rq_ty.get_client_format() {
1744                Some(ClientFormatAny::CompressedFormat(format)) => format,
1745                _ => unreachable!(),
1746            });
1747            format_request_to_glenum(context, TextureFormatRequest::Specific(newformat), rq_ty)?
1748        },
1749
1750        TextureFormatRequest::AnyCompressed => {
1751            match rq_ty {
1752                RequestType::TexImage(client) => {
1753                    let size = client.map(|c| c.get_num_components());
1754
1755                    if version >= &Version(Api::Gl, 1, 1) {
1756                        match size {
1757                            Some(1) => if version >= &Version(Api::Gl, 3, 0) ||
1758                                          extensions.gl_arb_texture_rg
1759                            {
1760                                gl::COMPRESSED_RED
1761                            } else {
1762                                1
1763                            },
1764                            Some(2) => if version >= &Version(Api::Gl, 3, 0) ||
1765                                          extensions.gl_arb_texture_rg
1766                            {
1767                                gl::COMPRESSED_RG
1768                            } else {
1769                                2
1770                            },
1771                            Some(3) => gl::COMPRESSED_RGB,
1772                            Some(4) => gl::COMPRESSED_RGBA,
1773                            None => gl::COMPRESSED_RGBA,
1774                            _ => unreachable!(),
1775                        }
1776
1777                    } else {
1778                        // OpenGL 1.0 doesn't support compressed textures, so we use a
1779                        // regular float format instead
1780                        size.unwrap_or(4) as gl::types::GLenum
1781                    }
1782                },
1783                RequestType::TexStorage | RequestType::Renderbuffer => {
1784                    return Err(FormatNotSupportedError)
1785                },
1786            }
1787        },
1788
1789        TextureFormatRequest::Specific(TextureFormat::CompressedFormat(format)) => {
1790            if format.is_supported(context) {
1791                format.to_glenum()
1792            } else {
1793                return Err(FormatNotSupportedError);
1794            }
1795        },
1796
1797        /*******************************************************************/
1798        /*                             SRGB                                */
1799        /*******************************************************************/
1800        TextureFormatRequest::AnySrgb => {
1801            let size = rq_ty.get_client_format().map(|c| c.get_num_components());
1802
1803            if version >= &Version(Api::Gl, 2, 1) || version >= &Version(Api::GlEs, 3, 0) ||
1804               extensions.gl_ext_texture_srgb
1805            {
1806                match size {
1807                    Some(1 ..= 3) => gl::SRGB8,
1808                    Some(4) => gl::SRGB8_ALPHA8,
1809                    None => if let RequestType::TexImage(_) = rq_ty { gl::SRGB8 } else { gl::SRGB8_ALPHA8 },
1810                    _ => unreachable!(),
1811                }
1812
1813            } else {
1814                // no support for sRGB
1815                format_request_to_glenum(context, TextureFormatRequest::AnyFloatingPoint,
1816                                              rq_ty)?
1817            }
1818        },
1819
1820        TextureFormatRequest::Specific(TextureFormat::Srgb(format)) => {
1821            if format.is_supported(context) {
1822                format.to_glenum()
1823            } else {
1824                return Err(FormatNotSupportedError);
1825            }
1826        },
1827
1828        /*******************************************************************/
1829        /*                        COMPRESSED SRGB                          */
1830        /*******************************************************************/
1831        TextureFormatRequest::AnyCompressedSrgb if is_client_compressed => {
1832            let newformat = TextureFormat::CompressedSrgbFormat(match rq_ty.get_client_format() {
1833                Some(ClientFormatAny::CompressedSrgbFormat(format)) => format,
1834                _ => unreachable!(),
1835            });
1836            format_request_to_glenum(context, TextureFormatRequest::Specific(newformat), rq_ty)?
1837        },
1838
1839        TextureFormatRequest::AnyCompressedSrgb => {
1840            if version >= &Version(Api::Gl, 4, 0) || extensions.gl_ext_texture_srgb {
1841                match rq_ty {
1842                    RequestType::TexImage(client) => {
1843                        match client.map(|c| c.get_num_components()) {
1844                            Some(1 ..= 3) => gl::COMPRESSED_SRGB,
1845                            Some(4) => gl::COMPRESSED_SRGB_ALPHA,
1846                            None => gl::COMPRESSED_SRGB_ALPHA,
1847                            _ => unreachable!(),
1848                        }
1849                    },
1850                    RequestType::TexStorage | RequestType::Renderbuffer => {
1851                        return Err(FormatNotSupportedError)
1852                    },
1853                }
1854
1855            } else {
1856                // no support for compressed srgb textures
1857                format_request_to_glenum(context, TextureFormatRequest::AnySrgb, rq_ty)?
1858            }
1859        },
1860
1861        TextureFormatRequest::Specific(TextureFormat::CompressedSrgbFormat(format)) => {
1862            if format.is_supported(context) {
1863                format.to_glenum()
1864            } else {
1865                return Err(FormatNotSupportedError);
1866            }
1867        },
1868
1869        /*******************************************************************/
1870        /*                          INTEGRAL                               */
1871        /*******************************************************************/
1872        TextureFormatRequest::AnyIntegral => {
1873            let size = rq_ty.get_client_format().map(|c| c.get_num_components());
1874
1875            if version >= &Version(Api::Gl, 3, 0) {
1876                match size {  // FIXME: choose between 8, 16 and 32 depending on the client format
1877                    Some(1) => gl::R32I,
1878                    Some(2) => gl::RG32I,
1879                    Some(3) => gl::RGB32I,
1880                    Some(4) => gl::RGBA32I,
1881                    None => gl::RGBA32I,
1882                    _ => unreachable!(),
1883                }
1884
1885            } else {
1886                if !extensions.gl_ext_texture_integer {
1887                    return Err(FormatNotSupportedError);
1888                }
1889
1890                match size {  // FIXME: choose between 8, 16 and 32 depending on the client format
1891                    Some(1) => if extensions.gl_arb_texture_rg {
1892                        gl::R32I
1893                    } else {
1894                        return Err(FormatNotSupportedError);
1895                    },
1896                    Some(2) => if extensions.gl_arb_texture_rg {
1897                        gl::RG32I
1898                    } else {
1899                        return Err(FormatNotSupportedError);
1900                    },
1901                    Some(3) => gl::RGB32I_EXT,
1902                    Some(4) => gl::RGBA32I_EXT,
1903                    None => gl::RGBA32I_EXT,
1904                    _ => unreachable!(),
1905                }
1906            }
1907        },
1908
1909        TextureFormatRequest::Specific(TextureFormat::UncompressedIntegral(format)) => {
1910            if format.is_supported(context) {
1911                format.to_glenum()
1912            } else {
1913                return Err(FormatNotSupportedError);
1914            }
1915        },
1916
1917        /*******************************************************************/
1918        /*                          UNSIGNED                               */
1919        /*******************************************************************/
1920        TextureFormatRequest::AnyUnsigned => {
1921            let size = rq_ty.get_client_format().map(|c| c.get_num_components());
1922
1923            if version >= &Version(Api::Gl, 3, 0) {
1924                match size {  // FIXME: choose between 8, 16 and 32 depending on the client format
1925                    Some(1) => gl::R32UI,
1926                    Some(2) => gl::RG32UI,
1927                    Some(3) => gl::RGB32UI,
1928                    Some(4) => gl::RGBA32UI,
1929                    None => gl::RGBA32UI,
1930                    _ => unreachable!(),
1931                }
1932
1933            } else {
1934                if !extensions.gl_ext_texture_integer {
1935                    return Err(FormatNotSupportedError);
1936                }
1937
1938                match size {  // FIXME: choose between 8, 16 and 32 depending on the client format
1939                    Some(1) => if extensions.gl_arb_texture_rg {
1940                        gl::R32UI
1941                    } else {
1942                        return Err(FormatNotSupportedError);
1943                    },
1944                    Some(2) => if extensions.gl_arb_texture_rg {
1945                        gl::RG32UI
1946                    } else {
1947                        return Err(FormatNotSupportedError);
1948                    },
1949                    Some(3) => gl::RGB32UI_EXT,
1950                    Some(4) => gl::RGBA32UI_EXT,
1951                    None => gl::RGBA32UI_EXT,
1952                    _ => unreachable!(),
1953                }
1954            }
1955        },
1956
1957        TextureFormatRequest::Specific(TextureFormat::UncompressedUnsigned(format)) => {
1958            if format.is_supported(context) {
1959                format.to_glenum()
1960            } else {
1961                return Err(FormatNotSupportedError);
1962            }
1963        },
1964
1965        /*******************************************************************/
1966        /*                            DEPTH                                */
1967        /*******************************************************************/
1968        TextureFormatRequest::AnyDepth => {
1969            if version >= &Version(Api::Gl, 2, 0) {
1970                match rq_ty {
1971                    RequestType::TexImage(_) => gl::DEPTH_COMPONENT,
1972                    RequestType::TexStorage | RequestType::Renderbuffer => gl::DEPTH_COMPONENT24,
1973                }
1974
1975            } else if version >= &Version(Api::Gl, 1, 4) || extensions.gl_arb_depth_texture ||
1976                      extensions.gl_oes_depth_texture
1977            {
1978                match rq_ty {
1979                    RequestType::TexImage(_) => gl::DEPTH_COMPONENT,
1980                    RequestType::TexStorage | RequestType::Renderbuffer => return Err(FormatNotSupportedError),     // TODO: sized format?
1981                }
1982
1983            } else {
1984                return Err(FormatNotSupportedError);
1985            }
1986        },
1987
1988        TextureFormatRequest::Specific(TextureFormat::DepthFormat(format)) => {
1989            if format.is_supported(context) {
1990                format.to_glenum()
1991            } else {
1992                return Err(FormatNotSupportedError);
1993            }
1994        },
1995
1996        /*******************************************************************/
1997        /*                           STENCIL                               */
1998        /*******************************************************************/
1999        TextureFormatRequest::AnyStencil => {
2000            // TODO: we just request I8, but this could be more flexible
2001            return format_request_to_glenum(context,
2002                                     TextureFormatRequest::Specific(
2003                                        TextureFormat::StencilFormat(
2004                                            StencilFormat::I8)), rq_ty);
2005        },
2006
2007        TextureFormatRequest::Specific(TextureFormat::StencilFormat(format)) => {
2008            match rq_ty {
2009                RequestType::TexImage(_) | RequestType::TexStorage => {
2010                    if format.is_supported_for_textures(context) {
2011                        format.to_glenum()
2012                    } else {
2013                        return Err(FormatNotSupportedError);
2014                    }
2015                },
2016                RequestType::Renderbuffer => {
2017                    if format.is_supported_for_renderbuffers(context) {
2018                        format.to_glenum()
2019                    } else {
2020                        return Err(FormatNotSupportedError);
2021                    }
2022                },
2023            }
2024        },
2025
2026        /*******************************************************************/
2027        /*                        DEPTH-STENCIL                            */
2028        /*******************************************************************/
2029        TextureFormatRequest::AnyDepthStencil => {
2030            if version >= &Version(Api::Gl, 3, 0) {
2031                match rq_ty {
2032                    RequestType::TexImage(_) => gl::DEPTH_STENCIL,
2033                    RequestType::TexStorage | RequestType::Renderbuffer => gl::DEPTH24_STENCIL8,
2034                }
2035
2036            } else if extensions.gl_ext_packed_depth_stencil {
2037                match rq_ty {
2038                    RequestType::TexImage(_) => gl::DEPTH_STENCIL_EXT,
2039                    RequestType::TexStorage | RequestType::Renderbuffer => gl::DEPTH24_STENCIL8_EXT,
2040                }
2041
2042            } else if extensions.gl_oes_packed_depth_stencil {
2043                match rq_ty {
2044                    RequestType::TexImage(_) => gl::DEPTH_STENCIL_OES,
2045                    RequestType::TexStorage | RequestType::Renderbuffer => gl::DEPTH24_STENCIL8_OES,
2046                }
2047
2048            } else {
2049                return Err(FormatNotSupportedError);
2050            }
2051        },
2052
2053        TextureFormatRequest::Specific(TextureFormat::DepthStencilFormat(format)) => {
2054            if format.is_supported(context) {
2055                format.to_glenum()
2056            } else {
2057                return Err(FormatNotSupportedError);
2058            }
2059        },
2060    })
2061}
2062
2063/// Checks that the client texture format is supported.
2064///
2065/// If `inverted` is true, returns a format where the R, G and B components are flipped.
2066///
2067/// Returns two GLenums suitable for `glTexImage#D` and `glTexSubImage#D`.
2068pub fn client_format_to_glenum(context: &Context, client: ClientFormatAny,
2069                               format: TextureFormatRequest, inverted: bool)
2070                               -> Result<(gl::types::GLenum, gl::types::GLenum),
2071                                         FormatNotSupportedError>
2072{
2073    let value = match format {
2074        TextureFormatRequest::AnyCompressed if client.is_compressed() => {
2075            match client {
2076                ClientFormatAny::CompressedFormat(client_format) => {
2077                    if client_format.is_supported(context) {
2078                        let e = client_format.to_glenum();
2079                        Ok((e, e))
2080                    } else {
2081                        return Err(FormatNotSupportedError);
2082                    }
2083                },
2084                _ => unreachable!(),
2085            }
2086        },
2087
2088        TextureFormatRequest::AnyCompressedSrgb if client.is_compressed() => {
2089            match client {
2090                ClientFormatAny::CompressedSrgbFormat(client_format) => {
2091                    if client_format.is_supported(context) {
2092                        let e = client_format.to_glenum();
2093                        Ok((e, e))
2094                    } else {
2095                        return Err(FormatNotSupportedError);
2096                    }
2097                },
2098                _ => unreachable!(),
2099            }
2100        },
2101
2102        TextureFormatRequest::Specific(TextureFormat::CompressedFormat(format))
2103                                                        if client.is_compressed() => {
2104            if format.is_supported(context) {
2105                let e = format.to_glenum();
2106                Ok((e, e))
2107            } else {
2108                return Err(FormatNotSupportedError);
2109            }
2110        },
2111
2112        TextureFormatRequest::Specific(TextureFormat::CompressedSrgbFormat(format))
2113                                                        if client.is_compressed() => {
2114            if format.is_supported(context) {
2115                let e = format.to_glenum();
2116                Ok((e, e))
2117            } else {
2118                return Err(FormatNotSupportedError);
2119            }
2120        },
2121
2122        TextureFormatRequest::AnyFloatingPoint | TextureFormatRequest::AnyCompressed |
2123        TextureFormatRequest::AnySrgb | TextureFormatRequest::AnyCompressedSrgb |
2124        TextureFormatRequest::Specific(TextureFormat::UncompressedFloat(_)) |
2125        TextureFormatRequest::Specific(TextureFormat::Srgb(_)) |
2126        TextureFormatRequest::Specific(TextureFormat::CompressedFormat(_)) |
2127        TextureFormatRequest::Specific(TextureFormat::CompressedSrgbFormat(_)) =>
2128        {
2129            match client {
2130                ClientFormatAny::ClientFormat(ClientFormat::U8) => Ok((gl::RED, gl::UNSIGNED_BYTE)),
2131                ClientFormatAny::ClientFormat(ClientFormat::U8U8) => Ok((gl::RG, gl::UNSIGNED_BYTE)),
2132                ClientFormatAny::ClientFormat(ClientFormat::U8U8U8) => Ok((gl::RGB, gl::UNSIGNED_BYTE)),
2133                ClientFormatAny::ClientFormat(ClientFormat::U8U8U8U8) => Ok((gl::RGBA, gl::UNSIGNED_BYTE)),
2134                ClientFormatAny::ClientFormat(ClientFormat::I8) => Ok((gl::RED, gl::BYTE)),
2135                ClientFormatAny::ClientFormat(ClientFormat::I8I8) => Ok((gl::RG, gl::BYTE)),
2136                ClientFormatAny::ClientFormat(ClientFormat::I8I8I8) => Ok((gl::RGB, gl::BYTE)),
2137                ClientFormatAny::ClientFormat(ClientFormat::I8I8I8I8) => Ok((gl::RGBA, gl::BYTE)),
2138                ClientFormatAny::ClientFormat(ClientFormat::U16) => Ok((gl::RED, gl::UNSIGNED_SHORT)),
2139                ClientFormatAny::ClientFormat(ClientFormat::U16U16) => Ok((gl::RG, gl::UNSIGNED_SHORT)),
2140                ClientFormatAny::ClientFormat(ClientFormat::U16U16U16) => Ok((gl::RGB, gl::UNSIGNED_SHORT)),
2141                ClientFormatAny::ClientFormat(ClientFormat::U16U16U16U16) => Ok((gl::RGBA, gl::UNSIGNED_SHORT)),
2142                ClientFormatAny::ClientFormat(ClientFormat::I16) => Ok((gl::RED, gl::SHORT)),
2143                ClientFormatAny::ClientFormat(ClientFormat::I16I16) => Ok((gl::RG, gl::SHORT)),
2144                ClientFormatAny::ClientFormat(ClientFormat::I16I16I16) => Ok((gl::RGB, gl::SHORT)),
2145                ClientFormatAny::ClientFormat(ClientFormat::I16I16I16I16) => Ok((gl::RGBA, gl::SHORT)),
2146                ClientFormatAny::ClientFormat(ClientFormat::U32) => Ok((gl::RED, gl::UNSIGNED_INT)),
2147                ClientFormatAny::ClientFormat(ClientFormat::U32U32) => Ok((gl::RG, gl::UNSIGNED_INT)),
2148                ClientFormatAny::ClientFormat(ClientFormat::U32U32U32) => Ok((gl::RGB, gl::UNSIGNED_INT)),
2149                ClientFormatAny::ClientFormat(ClientFormat::U32U32U32U32) => Ok((gl::RGBA, gl::UNSIGNED_INT)),
2150                ClientFormatAny::ClientFormat(ClientFormat::I32) => Ok((gl::RED, gl::INT)),
2151                ClientFormatAny::ClientFormat(ClientFormat::I32I32) => Ok((gl::RG, gl::INT)),
2152                ClientFormatAny::ClientFormat(ClientFormat::I32I32I32) => Ok((gl::RGB, gl::INT)),
2153                ClientFormatAny::ClientFormat(ClientFormat::I32I32I32I32) => Ok((gl::RGBA, gl::INT)),
2154                ClientFormatAny::ClientFormat(ClientFormat::U3U3U2) => Ok((gl::RGB, gl::UNSIGNED_BYTE_3_3_2)),
2155                ClientFormatAny::ClientFormat(ClientFormat::U5U6U5) => Ok((gl::RGB, gl::UNSIGNED_SHORT_5_6_5)),
2156                ClientFormatAny::ClientFormat(ClientFormat::U4U4U4U4) => Ok((gl::RGBA, gl::UNSIGNED_SHORT_4_4_4_4)),
2157                ClientFormatAny::ClientFormat(ClientFormat::U5U5U5U1) => Ok((gl::RGBA, gl::UNSIGNED_SHORT_5_5_5_1)),
2158                ClientFormatAny::ClientFormat(ClientFormat::U1U5U5U5Reversed) => Ok((gl::RGBA, gl::UNSIGNED_SHORT_1_5_5_5_REV)),
2159                ClientFormatAny::ClientFormat(ClientFormat::U10U10U10U2) => Ok((gl::RGBA, gl::UNSIGNED_INT_10_10_10_2)),
2160                ClientFormatAny::ClientFormat(ClientFormat::F16) => Ok((gl::RED, gl::HALF_FLOAT)),
2161                ClientFormatAny::ClientFormat(ClientFormat::F16F16) => Ok((gl::RG, gl::HALF_FLOAT)),
2162                ClientFormatAny::ClientFormat(ClientFormat::F16F16F16) => Ok((gl::RGB, gl::HALF_FLOAT)),
2163                ClientFormatAny::ClientFormat(ClientFormat::F16F16F16F16) => Ok((gl::RGBA, gl::HALF_FLOAT)),
2164                ClientFormatAny::ClientFormat(ClientFormat::F32) => Ok((gl::RED, gl::FLOAT)),
2165                ClientFormatAny::ClientFormat(ClientFormat::F32F32) => Ok((gl::RG, gl::FLOAT)),
2166                ClientFormatAny::ClientFormat(ClientFormat::F32F32F32) => Ok((gl::RGB, gl::FLOAT)),
2167                ClientFormatAny::ClientFormat(ClientFormat::F32F32F32F32) => Ok((gl::RGBA, gl::FLOAT)),
2168
2169                // this kind of situation shouldn't happen, it should have a special handling when
2170                // client is compressed.
2171                ClientFormatAny::CompressedFormat(_) => unreachable!(),
2172                ClientFormatAny::CompressedSrgbFormat(_) => unreachable!(),
2173            }
2174        },
2175
2176        TextureFormatRequest::AnyIntegral | TextureFormatRequest::AnyUnsigned |
2177        TextureFormatRequest::Specific(TextureFormat::UncompressedIntegral(_)) |
2178        TextureFormatRequest::Specific(TextureFormat::UncompressedUnsigned(_)) =>
2179        {
2180            match client {
2181                ClientFormatAny::ClientFormat(ClientFormat::U8) => Ok((gl::RED_INTEGER, gl::UNSIGNED_BYTE)),
2182                ClientFormatAny::ClientFormat(ClientFormat::U8U8) => Ok((gl::RG_INTEGER, gl::UNSIGNED_BYTE)),
2183                ClientFormatAny::ClientFormat(ClientFormat::U8U8U8) => Ok((gl::RGB_INTEGER, gl::UNSIGNED_BYTE)),
2184                ClientFormatAny::ClientFormat(ClientFormat::U8U8U8U8) => Ok((gl::RGBA_INTEGER, gl::UNSIGNED_BYTE)),
2185                ClientFormatAny::ClientFormat(ClientFormat::I8) => Ok((gl::RED_INTEGER, gl::BYTE)),
2186                ClientFormatAny::ClientFormat(ClientFormat::I8I8) => Ok((gl::RG_INTEGER, gl::BYTE)),
2187                ClientFormatAny::ClientFormat(ClientFormat::I8I8I8) => Ok((gl::RGB_INTEGER, gl::BYTE)),
2188                ClientFormatAny::ClientFormat(ClientFormat::I8I8I8I8) => Ok((gl::RGBA_INTEGER, gl::BYTE)),
2189                ClientFormatAny::ClientFormat(ClientFormat::U16) => Ok((gl::RED_INTEGER, gl::UNSIGNED_SHORT)),
2190                ClientFormatAny::ClientFormat(ClientFormat::U16U16) => Ok((gl::RG_INTEGER, gl::UNSIGNED_SHORT)),
2191                ClientFormatAny::ClientFormat(ClientFormat::U16U16U16) => Ok((gl::RGB_INTEGER, gl::UNSIGNED_SHORT)),
2192                ClientFormatAny::ClientFormat(ClientFormat::U16U16U16U16) => Ok((gl::RGBA_INTEGER, gl::UNSIGNED_SHORT)),
2193                ClientFormatAny::ClientFormat(ClientFormat::I16) => Ok((gl::RED_INTEGER, gl::SHORT)),
2194                ClientFormatAny::ClientFormat(ClientFormat::I16I16) => Ok((gl::RG_INTEGER, gl::SHORT)),
2195                ClientFormatAny::ClientFormat(ClientFormat::I16I16I16) => Ok((gl::RGB_INTEGER, gl::SHORT)),
2196                ClientFormatAny::ClientFormat(ClientFormat::I16I16I16I16) => Ok((gl::RGBA_INTEGER, gl::SHORT)),
2197                ClientFormatAny::ClientFormat(ClientFormat::U32) => Ok((gl::RED_INTEGER, gl::UNSIGNED_INT)),
2198                ClientFormatAny::ClientFormat(ClientFormat::U32U32) => Ok((gl::RG_INTEGER, gl::UNSIGNED_INT)),
2199                ClientFormatAny::ClientFormat(ClientFormat::U32U32U32) => Ok((gl::RGB_INTEGER, gl::UNSIGNED_INT)),
2200                ClientFormatAny::ClientFormat(ClientFormat::U32U32U32U32) => Ok((gl::RGBA_INTEGER, gl::UNSIGNED_INT)),
2201                ClientFormatAny::ClientFormat(ClientFormat::I32) => Ok((gl::RED_INTEGER, gl::INT)),
2202                ClientFormatAny::ClientFormat(ClientFormat::I32I32) => Ok((gl::RG_INTEGER, gl::INT)),
2203                ClientFormatAny::ClientFormat(ClientFormat::I32I32I32) => Ok((gl::RGB_INTEGER, gl::INT)),
2204                ClientFormatAny::ClientFormat(ClientFormat::I32I32I32I32) => Ok((gl::RGBA_INTEGER, gl::INT)),
2205                ClientFormatAny::ClientFormat(ClientFormat::U3U3U2) => Ok((gl::RGB_INTEGER, gl::UNSIGNED_BYTE_3_3_2)),
2206                ClientFormatAny::ClientFormat(ClientFormat::U5U6U5) => Ok((gl::RGB_INTEGER, gl::UNSIGNED_SHORT_5_6_5)),
2207                ClientFormatAny::ClientFormat(ClientFormat::U4U4U4U4) => Ok((gl::RGBA_INTEGER, gl::UNSIGNED_SHORT_4_4_4_4)),
2208                ClientFormatAny::ClientFormat(ClientFormat::U5U5U5U1) => Ok((gl::RGBA_INTEGER, gl::UNSIGNED_SHORT_5_5_5_1)),
2209                ClientFormatAny::ClientFormat(ClientFormat::U1U5U5U5Reversed) => Ok((gl::RGBA_INTEGER, gl::UNSIGNED_SHORT_1_5_5_5_REV)),
2210                ClientFormatAny::ClientFormat(ClientFormat::U10U10U10U2) => Ok((gl::RGBA_INTEGER, gl::UNSIGNED_INT_10_10_10_2)),
2211                ClientFormatAny::ClientFormat(ClientFormat::F16) => Ok((gl::RED_INTEGER, gl::HALF_FLOAT)),
2212                ClientFormatAny::ClientFormat(ClientFormat::F16F16) => Ok((gl::RG_INTEGER, gl::HALF_FLOAT)),
2213                ClientFormatAny::ClientFormat(ClientFormat::F16F16F16) => Ok((gl::RGB_INTEGER, gl::HALF_FLOAT)),
2214                ClientFormatAny::ClientFormat(ClientFormat::F16F16F16F16) => Ok((gl::RGBA_INTEGER, gl::HALF_FLOAT)),
2215                ClientFormatAny::ClientFormat(ClientFormat::F32) => Ok((gl::RED_INTEGER, gl::FLOAT)),
2216                ClientFormatAny::ClientFormat(ClientFormat::F32F32) => Ok((gl::RG_INTEGER, gl::FLOAT)),
2217                ClientFormatAny::ClientFormat(ClientFormat::F32F32F32) => Ok((gl::RGB_INTEGER, gl::FLOAT)),
2218                ClientFormatAny::ClientFormat(ClientFormat::F32F32F32F32) => Ok((gl::RGBA_INTEGER, gl::FLOAT)),
2219
2220                // this kind of situation shouldn't happen, it should have a special handling when
2221                // client is compressed.
2222                ClientFormatAny::CompressedFormat(_) => unreachable!(),
2223                ClientFormatAny::CompressedSrgbFormat(_) => unreachable!(),
2224            }
2225        },
2226
2227        TextureFormatRequest::AnyDepth |
2228        TextureFormatRequest::Specific(TextureFormat::DepthFormat(_)) =>
2229        {
2230            if client != ClientFormatAny::ClientFormat(ClientFormat::F32) {
2231                panic!("Only ClientFormatAny::ClientFormat(ClientFormat::F32) can be used to upload on a depth texture");
2232            }
2233
2234            Ok((gl::DEPTH_COMPONENT, gl::FLOAT))
2235        }
2236
2237        TextureFormatRequest::AnyStencil |
2238        TextureFormatRequest::Specific(TextureFormat::StencilFormat(_)) =>
2239        {
2240            match client {
2241                ClientFormatAny::ClientFormat(ClientFormat::U8) => Ok((gl::RED_INTEGER, gl::UNSIGNED_BYTE)),
2242                ClientFormatAny::ClientFormat(ClientFormat::I8) => Ok((gl::RED_INTEGER, gl::BYTE)),
2243                ClientFormatAny::ClientFormat(ClientFormat::U16) => Ok((gl::RED_INTEGER, gl::UNSIGNED_SHORT)),
2244                ClientFormatAny::ClientFormat(ClientFormat::I16) => Ok((gl::RED_INTEGER, gl::SHORT)),
2245                ClientFormatAny::ClientFormat(ClientFormat::U32) => Ok((gl::RED_INTEGER, gl::UNSIGNED_INT)),
2246                ClientFormatAny::ClientFormat(ClientFormat::I32) => Ok((gl::RED_INTEGER, gl::INT)),
2247                ClientFormatAny::ClientFormat(ClientFormat::F16) => Ok((gl::RED_INTEGER, gl::HALF_FLOAT)),
2248                ClientFormatAny::ClientFormat(ClientFormat::F32) => Ok((gl::RED_INTEGER, gl::FLOAT)),
2249                _ => panic!("Can't upload to a stencil texture with more than one channel")
2250            }
2251        }
2252
2253        TextureFormatRequest::AnyDepthStencil |
2254        TextureFormatRequest::Specific(TextureFormat::DepthStencilFormat(_)) =>
2255        {
2256            unimplemented!();
2257        },
2258    };
2259
2260    if inverted {
2261        value.and_then(|(format, ty)| {
2262            let format = match format {
2263                gl::RGB => gl::BGR,
2264                gl::RGBA => gl::BGRA,
2265                f => return Err(FormatNotSupportedError)
2266            };
2267
2268            Ok((format, ty))
2269        })
2270    } else {
2271        value
2272    }
2273}