glium/context/
capabilities.rs

1use crate::context::ExtensionsList;
2use crate::version::Version;
3use crate::version::Api;
4
5use std::cmp;
6use std::collections::HashMap;
7use std::ffi::CStr;
8use std::hash::BuildHasherDefault;
9
10use fnv::FnvHasher;
11
12use crate::gl;
13use crate::ToGlEnum;
14
15use crate::CapabilitiesSource;
16use crate::image_format::TextureFormat;
17
18/// Describes the OpenGL context profile.
19#[derive(Debug, Copy, Clone)]
20pub enum Profile {
21    /// The context uses only future-compatible functions and definitions.
22    Core,
23    /// The context includes all immediate mode functions and definitions.
24    Compatibility
25}
26
27/// Represents the capabilities of the context.
28///
29/// Contrary to the state, these values never change.
30#[derive(Debug)]
31pub struct Capabilities {
32    /// List of versions of GLSL that are supported by the compiler.
33    ///
34    /// An empty list means that the backend doesn't have a compiler.
35    pub supported_glsl_versions: Vec<Version>,
36
37    /// Returns a version or release number. Vendor-specific information may follow the version
38    /// number.
39    pub version: String,
40
41    /// The company responsible for this GL implementation.
42    pub vendor: String,
43
44    /// The name of the renderer. This name is typically specific to a particular
45    /// configuration of a hardware platform.
46    pub renderer: String,
47
48    /// The OpenGL context profile if available.
49    ///
50    /// The context profile is available from OpenGL 3.2 onwards. `None` if not supported.
51    pub profile: Option<Profile>,
52
53    /// The context is in debug mode, which may have additional error and performance issue
54    /// reporting functionality.
55    pub debug: bool,
56
57    /// The context is in "forward-compatible" mode, which means that no deprecated functionality
58    /// will be supported.
59    pub forward_compatible: bool,
60
61    /// True if out-of-bound access on the GPU side can't result in crashes.
62    pub robustness: bool,
63
64    /// True if it is possible for the OpenGL context to be lost.
65    pub can_lose_context: bool,
66
67    /// What happens when you change the current OpenGL context.
68    pub release_behavior: ReleaseBehavior,
69
70    /// Whether the context supports left and right buffers.
71    pub stereo: bool,
72
73    /// True if the default framebuffer is in sRGB.
74    pub srgb: bool,
75
76    /// Number of bits in the default framebuffer's depth buffer
77    pub depth_bits: Option<u16>,
78
79    /// Number of bits in the default framebuffer's stencil buffer
80    pub stencil_bits: Option<u16>,
81
82    /// Informations about formats when used to create textures.
83    pub internal_formats_textures: HashMap<TextureFormat, FormatInfos, BuildHasherDefault<FnvHasher>>,
84
85    /// Informations about formats when used to create renderbuffers.
86    pub internal_formats_renderbuffers: HashMap<TextureFormat, FormatInfos, BuildHasherDefault<FnvHasher>>,
87
88    /// Maximum number of textures that can be bound to a program.
89    ///
90    /// `glActiveTexture` must be between `GL_TEXTURE0` and `GL_TEXTURE0` + this value - 1.
91    pub max_combined_texture_image_units: gl::types::GLint,
92
93    /// Maximum value for `GL_TEXTURE_MAX_ANISOTROPY_EXT​`.
94    ///
95    /// `None` if the extension is not supported by the hardware.
96    pub max_texture_max_anisotropy: Option<gl::types::GLfloat>,
97
98    /// Maximum size of a texture (i.e. GL_MAX_TEXTURE_SIZE)
99    pub max_texture_size: gl::types::GLint,
100
101    /// Maximum size of a buffer texture. `None` if this is not supported.
102    pub max_texture_buffer_size: Option<gl::types::GLint>,
103
104    /// Maximum width and height of `glViewport`.
105    pub max_viewport_dims: (gl::types::GLint, gl::types::GLint),
106
107    /// Maximum number of elements that can be passed with `glDrawBuffers`.
108    pub max_draw_buffers: gl::types::GLint,
109
110    /// Maximum number of vertices per patch. `None` if tessellation is not supported.
111    pub max_patch_vertices: Option<gl::types::GLint>,
112
113    /// Number of available buffer bind points for `GL_ATOMIC_COUNTER_BUFFER`.
114    pub max_indexed_atomic_counter_buffer: gl::types::GLint,
115
116    /// Number of available buffer bind points for `GL_SHADER_STORAGE_BUFFER`.
117    pub max_indexed_shader_storage_buffer: gl::types::GLint,
118
119    /// Number of available buffer bind points for `GL_TRANSFORM_FEEDBACK_BUFFER`.
120    pub max_indexed_transform_feedback_buffer: gl::types::GLint,
121
122    /// Number of available buffer bind points for `GL_UNIFORM_BUFFER`.
123    pub max_indexed_uniform_buffer: gl::types::GLint,
124
125    /// Number of work groups for compute shaders.
126    pub max_compute_work_group_count: (gl::types::GLint, gl::types::GLint, gl::types::GLint),
127
128    /// Maximum number of color attachment bind points.
129    pub max_color_attachments: gl::types::GLint,
130
131    /// Maximum width of an empty framebuffer. `None` if not supported.
132    pub max_framebuffer_width: Option<gl::types::GLint>,
133
134    /// Maximum height of an empty framebuffer. `None` if not supported.
135    pub max_framebuffer_height: Option<gl::types::GLint>,
136
137    /// Maximum layers of an empty framebuffer. `None` if not supported.
138    pub max_framebuffer_layers: Option<gl::types::GLint>,
139
140    /// Maximum samples of an empty framebuffer. `None` if not supported.
141    pub max_framebuffer_samples: Option<gl::types::GLint>,
142}
143
144/// Information about an internal format.
145#[derive(Debug)]
146pub struct FormatInfos {
147    /// Possible values for multisampling. `None` if unknown.
148    pub multisamples: Option<Vec<gl::types::GLint>>,
149}
150
151/// Defines what happens when you change the current context.
152#[derive(Copy, Clone, Debug, PartialEq, Eq)]
153pub enum ReleaseBehavior {
154    /// Nothing is done when using another context.
155    None,
156
157    /// The commands queue of the current context is flushed.
158    Flush,
159}
160
161/// Loads the capabilities.
162///
163/// *Safety*: the OpenGL context corresponding to `gl` must be current in the thread.
164///
165/// ## Panic
166///
167/// Can panic if the version number or extensions list don't match the backend, leading to
168/// unloaded functions being called.
169///
170pub unsafe fn get_capabilities(gl: &gl::Gl, version: &Version, extensions: &ExtensionsList)
171                               -> Capabilities
172{
173    // GL_CONTEXT_FLAGS are only available from GL 3.0 onwards
174    let (debug, forward_compatible) = if version >= &Version(Api::Gl, 3, 0) {
175        let mut val = 0;
176        gl.GetIntegerv(gl::CONTEXT_FLAGS, &mut val);
177        let val = val as gl::types::GLenum;
178        ((val & gl::CONTEXT_FLAG_DEBUG_BIT) != 0,
179         (val & gl::CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) != 0)
180    } else {
181        (false, false)
182    };
183
184    // getting the value of `GL_RENDERER`
185    let renderer = {
186        let s = gl.GetString(gl::RENDERER);
187        assert!(!s.is_null());
188        String::from_utf8(CStr::from_ptr(s as *const _).to_bytes().to_vec()).ok()
189                                    .expect("glGetString(GL_RENDERER) returned a non-UTF8 string")
190    };
191
192    Capabilities {
193        supported_glsl_versions: {
194            get_supported_glsl(gl, version, extensions)
195        },
196
197        version: {
198            let s = gl.GetString(gl::VERSION);
199            assert!(!s.is_null());
200            String::from_utf8(CStr::from_ptr(s as *const _).to_bytes().to_vec()).ok()
201                                        .expect("glGetString(GL_VERSION) returned a non-UTF8 string")
202        },
203
204        vendor: {
205            let s = gl.GetString(gl::VENDOR);
206            assert!(!s.is_null());
207            String::from_utf8(CStr::from_ptr(s as *const _).to_bytes().to_vec()).ok()
208                                        .expect("glGetString(GL_VENDOR) returned a non-UTF8 string")
209        },
210
211        profile: {
212            if version >= &Version(Api::Gl, 3, 2) {
213                let mut val = 0;
214                gl.GetIntegerv(gl::CONTEXT_PROFILE_MASK, &mut val);
215                let val = val as gl::types::GLenum;
216                if (val & gl::CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0 {
217                    Some(Profile::Compatibility)
218                } else if (val & gl::CONTEXT_CORE_PROFILE_BIT) != 0 {
219                    Some(Profile::Core)
220                } else {
221                    None
222                }
223            } else {
224                None
225            }
226        },
227
228        debug,
229
230        forward_compatible,
231
232        robustness: if version >= &Version(Api::Gl, 4, 5) || version >= &Version(Api::GlEs, 3, 2) ||
233                       (version >= &Version(Api::Gl, 3, 0) && extensions.gl_arb_robustness)
234        {
235            // TODO: there seems to be no way to query `GL_CONTEXT_FLAGS` before OpenGL 3.0, even
236            //       if `GL_ARB_robustness` is there
237            let mut val = 0;
238            gl.GetIntegerv(gl::CONTEXT_FLAGS, &mut val);
239            let val = val as gl::types::GLenum;
240            (val & gl::CONTEXT_FLAG_ROBUST_ACCESS_BIT) != 0
241
242        } else if extensions.gl_khr_robustness || extensions.gl_ext_robustness {
243            let mut val = 0;
244            gl.GetBooleanv(gl::CONTEXT_ROBUST_ACCESS, &mut val);
245            val != 0
246
247        } else {
248            false
249        },
250
251        can_lose_context: if version >= &Version(Api::Gl, 4, 5) || extensions.gl_khr_robustness ||
252                             extensions.gl_arb_robustness || extensions.gl_ext_robustness
253        {
254            let mut val = 0;
255            gl.GetIntegerv(gl::RESET_NOTIFICATION_STRATEGY, &mut val);
256
257            match val as gl::types::GLenum {
258                gl::LOSE_CONTEXT_ON_RESET => true,
259                gl::NO_RESET_NOTIFICATION => false,
260
261                // WORK-AROUND: AMD drivers erroneously return this value, which doesn't even
262                //              correspond to any GLenum in the specs. We work around this bug
263                //              by interpreting it as `false`.
264                0x31BE => false,
265
266                // WORK-AROUND: Adreno 430/506 drivers return NO_ERROR.
267                gl::NO_ERROR => false,
268
269                _ => unreachable!()
270            }
271
272        } else {
273            false
274        },
275
276        release_behavior: if extensions.gl_khr_context_flush_control {
277            let mut val = 0;
278            gl.GetIntegerv(gl::CONTEXT_RELEASE_BEHAVIOR, &mut val);
279
280            match val as gl::types::GLenum {
281                gl::NONE => ReleaseBehavior::None,
282                gl::CONTEXT_RELEASE_BEHAVIOR_FLUSH => ReleaseBehavior::Flush,
283                _ => unreachable!()
284            }
285
286        } else {
287            ReleaseBehavior::Flush
288        },
289
290        stereo: {
291            if version >= &Version(Api::Gl, 1, 0) {
292                let mut val: gl::types::GLboolean = 0;
293                gl.GetBooleanv(gl::STEREO, &mut val);
294                val != 0
295            } else {
296                false
297            }
298        },
299
300        srgb: {
301            // `glGetFramebufferAttachmentParameteriv` incorrectly returns GL_INVALID_ENUM on some
302            // drivers, so we prefer using `glGetIntegerv` if possible.
303            if version >= &Version(Api::Gl, 3, 0) && !extensions.gl_ext_framebuffer_srgb {
304                let mut fb = 0;
305                gl.GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut fb);
306                let attachment = if fb == 0 { gl::FRONT_LEFT } else { gl::COLOR_ATTACHMENT0 };
307                let mut value = 0;
308                gl.GetFramebufferAttachmentParameteriv(gl::FRAMEBUFFER, attachment,
309                                                       gl::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING,
310                                                       &mut value);
311                value as gl::types::GLenum == gl::SRGB
312
313            } else if extensions.gl_ext_framebuffer_srgb {
314                let mut value = 0;
315                gl.GetBooleanv(gl::FRAMEBUFFER_SRGB_CAPABLE_EXT, &mut value);
316                value != 0
317
318            } else {
319                false
320            }
321        },
322
323        depth_bits: {
324            let mut value = 0;
325
326            // `glGetFramebufferAttachmentParameteriv` incorrectly returns GL_INVALID_ENUM on some
327            // drivers, so we prefer using `glGetIntegerv` if possible.
328            //
329            // Also note that `gl_arb_es2_compatibility` may provide `GL_DEPTH_BITS` but os/x
330            // doesn't even though it provides this extension. I'm not sure whether this is a bug
331            // with OS/X or just the extension actually not providing it.
332            if version >= &Version(Api::Gl, 3, 0) && !extensions.gl_arb_compatibility {
333                let mut fb = 0;
334                gl.GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut fb);
335                let attachment = if fb == 0 { gl::DEPTH } else { gl::DEPTH_ATTACHMENT };
336                let mut ty = 0;
337                gl.GetFramebufferAttachmentParameteriv(gl::FRAMEBUFFER, attachment,
338                                                       gl::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
339                                                       &mut ty);
340
341                if ty as gl::types::GLenum == gl::NONE {
342                    value = 0;
343                } else {
344                    gl.GetFramebufferAttachmentParameteriv(gl::FRAMEBUFFER, attachment,
345                                                           gl::FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE,
346                                                           &mut value);
347                }
348
349            } else {
350                gl.GetIntegerv(gl::DEPTH_BITS, &mut value);
351            };
352
353            match value {
354                0 => None,
355                v => Some(v as u16),
356            }
357        },
358
359        stencil_bits: {
360            let mut value = 0;
361
362            // `glGetFramebufferAttachmentParameteriv` incorrectly returns GL_INVALID_ENUM on some
363            // drivers, so we prefer using `glGetIntegerv` if possible.
364            //
365            // Also note that `gl_arb_es2_compatibility` may provide `GL_STENCIL_BITS` but os/x
366            // doesn't even though it provides this extension. I'm not sure whether this is a bug
367            // with OS/X or just the extension actually not providing it.
368            if version >= &Version(Api::Gl, 3, 0) && !extensions.gl_arb_compatibility {
369                let mut fb = 0;
370                gl.GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut fb);
371                let attachment = if fb == 0 { gl::STENCIL } else { gl::STENCIL_ATTACHMENT };
372                let mut ty = 0;
373                gl.GetFramebufferAttachmentParameteriv(gl::FRAMEBUFFER, attachment,
374                                                       gl::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
375                                                       &mut ty);
376
377                if ty as gl::types::GLenum == gl::NONE {
378                    value = 0;
379                } else {
380                    gl.GetFramebufferAttachmentParameteriv(gl::FRAMEBUFFER, attachment,
381                                                           gl::FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
382                                                           &mut value);
383                }
384
385            } else {
386                gl.GetIntegerv(gl::STENCIL_BITS, &mut value);
387            };
388
389            match value {
390                0 => None,
391                v => Some(v as u16),
392            }
393        },
394
395        internal_formats_textures: get_internal_formats(gl, version, extensions, false),
396        internal_formats_renderbuffers: get_internal_formats(gl, version, extensions, true),
397
398        max_combined_texture_image_units: {
399            let mut val = 2;
400            gl.GetIntegerv(gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mut val);
401
402            // WORK-AROUND (issue #1181)
403            // Some Radeon drivers crash if you use texture units 32 or more.
404            if renderer.contains("Radeon") {
405                val = cmp::min(val, 32);
406            }
407
408            val
409        },
410
411        max_texture_max_anisotropy: if !extensions.gl_ext_texture_filter_anisotropic {
412            None
413
414        } else {
415            Some({
416                let mut val = 0.0;
417                gl.GetFloatv(gl::MAX_TEXTURE_MAX_ANISOTROPY_EXT, &mut val);
418                val
419            })
420        },
421
422        max_texture_size: {
423            let mut val = 0;
424            gl.GetIntegerv(gl::MAX_TEXTURE_SIZE, &mut val);
425            val
426        },
427
428        max_texture_buffer_size: {
429            if version >= &Version(Api::Gl, 3, 0) || extensions.gl_arb_texture_buffer_object ||
430               extensions.gl_ext_texture_buffer_object || extensions.gl_oes_texture_buffer ||
431               extensions.gl_ext_texture_buffer
432            {
433                Some({
434                    let mut val = 0;
435                    gl.GetIntegerv(gl::MAX_TEXTURE_BUFFER_SIZE, &mut val);
436                    val
437                })
438
439            } else {
440                None
441            }
442        },
443
444        max_viewport_dims: {
445            let mut val: [gl::types::GLint; 2] = [ 0, 0 ];
446            gl.GetIntegerv(gl::MAX_VIEWPORT_DIMS, val.as_mut_ptr());
447            (val[0], val[1])
448        },
449
450        max_draw_buffers: {
451            if version >= &Version(Api::Gl, 2, 0) ||
452                version >= &Version(Api::GlEs, 3, 0) ||
453                extensions.gl_ati_draw_buffers || extensions.gl_arb_draw_buffers
454            {
455                let mut val = 1;
456                gl.GetIntegerv(gl::MAX_DRAW_BUFFERS, &mut val);
457                val
458            } else {
459                1
460            }
461        },
462
463        max_patch_vertices: if version >= &Version(Api::Gl, 4, 0) ||
464            extensions.gl_arb_tessellation_shader
465        {
466            Some({
467                let mut val = 0;
468                gl.GetIntegerv(gl::MAX_PATCH_VERTICES, &mut val);
469                val
470            })
471
472        } else {
473            None
474        },
475
476        max_indexed_atomic_counter_buffer: if version >= &Version(Api::Gl, 4, 2) {      // TODO: ARB_shader_atomic_counters   // TODO: GLES
477            let mut val = 0;
478            gl.GetIntegerv(gl::MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &mut val);
479            val
480        } else {
481            0
482        },
483
484        max_indexed_shader_storage_buffer: {
485            if version >= &Version(Api::Gl, 4, 3) || extensions.gl_arb_shader_storage_buffer_object {      // TODO: GLES
486                let mut val = 0;
487                gl.GetIntegerv(gl::MAX_SHADER_STORAGE_BUFFER_BINDINGS, &mut val);
488                val
489            } else {
490                0
491            }
492        },
493
494        max_indexed_transform_feedback_buffer: {
495            if version >= &Version(Api::Gl, 4, 0) || extensions.gl_arb_transform_feedback3 {      // TODO: GLES
496                let mut val = 0;
497                gl.GetIntegerv(gl::MAX_TRANSFORM_FEEDBACK_BUFFERS, &mut val);
498                val
499            } else if version >= &Version(Api::Gl, 3, 0) || extensions.gl_ext_transform_feedback {
500                let mut val = 0;
501                gl.GetIntegerv(gl::MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT, &mut val);
502                val
503            } else {
504                0
505            }
506        },
507
508        max_indexed_uniform_buffer: {
509            if version >= &Version(Api::Gl, 3, 1) || extensions.gl_arb_uniform_buffer_object {      // TODO: GLES
510                let mut val = 0;
511                gl.GetIntegerv(gl::MAX_UNIFORM_BUFFER_BINDINGS, &mut val);
512                val
513            } else {
514                0
515            }
516        },
517
518        max_compute_work_group_count: if version >= &Version(Api::Gl, 4, 3) ||
519                                         version >= &Version(Api::GlEs, 3, 1) ||
520                                         extensions.gl_arb_compute_shader
521        {
522            let mut val1 = 0;
523            let mut val2 = 0;
524            let mut val3 = 0;
525            gl.GetIntegeri_v(gl::MAX_COMPUTE_WORK_GROUP_COUNT, 0, &mut val1);
526            gl.GetIntegeri_v(gl::MAX_COMPUTE_WORK_GROUP_COUNT, 1, &mut val2);
527            gl.GetIntegeri_v(gl::MAX_COMPUTE_WORK_GROUP_COUNT, 2, &mut val3);
528            (val1, val2, val3)
529
530        } else {
531            (0, 0, 0)
532        },
533
534        max_color_attachments: {
535            if version >= &Version(Api::Gl, 3, 0) || version >= &Version(Api::GlEs, 3, 0) ||
536               extensions.gl_arb_framebuffer_object || extensions.gl_ext_framebuffer_object ||
537               extensions.gl_nv_fbo_color_attachments
538            {
539                let mut val = 4;
540                gl.GetIntegerv(gl::MAX_COLOR_ATTACHMENTS, &mut val);
541                val
542            } else if version >= &Version(Api::GlEs, 2, 0) {
543                1
544            } else {
545                // glium doesn't allow creating contexts that don't support FBOs
546                unreachable!()
547            }
548        },
549
550        max_framebuffer_width: {
551            if version >= &Version(Api::Gl, 4, 3) || version >= &Version(Api::GlEs, 3, 1) ||
552               extensions.gl_arb_framebuffer_no_attachments
553            {
554                let mut val = 0;
555                gl.GetIntegerv(gl::MAX_FRAMEBUFFER_WIDTH, &mut val);
556                Some(val)
557
558            } else {
559                None
560            }
561        },
562
563        max_framebuffer_height: {
564            if version >= &Version(Api::Gl, 4, 3) || version >= &Version(Api::GlEs, 3, 1) ||
565               extensions.gl_arb_framebuffer_no_attachments
566            {
567                let mut val = 0;
568                gl.GetIntegerv(gl::MAX_FRAMEBUFFER_HEIGHT, &mut val);
569                Some(val)
570
571            } else {
572                None
573            }
574        },
575
576        max_framebuffer_layers: {
577            if version >= &Version(Api::Gl, 4, 3) || version >= &Version(Api::GlEs, 3, 2) ||
578               extensions.gl_arb_framebuffer_no_attachments
579            {
580                let mut val = 0;
581                gl.GetIntegerv(gl::MAX_FRAMEBUFFER_LAYERS, &mut val);
582                Some(val)
583
584            } else {
585                None
586            }
587        },
588
589        max_framebuffer_samples: {
590            if version >= &Version(Api::Gl, 4, 3) || version >= &Version(Api::GlEs, 3, 1) ||
591               extensions.gl_arb_framebuffer_no_attachments
592            {
593                let mut val = 0;
594                gl.GetIntegerv(gl::MAX_FRAMEBUFFER_SAMPLES, &mut val);
595                Some(val)
596
597            } else {
598                None
599            }
600        },
601
602        renderer,
603    }
604}
605
606/// Gets the list of GLSL versions supported by the backend.
607///
608/// *Safety*: the OpenGL context corresponding to `gl` must be current in the thread.
609///
610/// ## Panic
611///
612/// Can panic if the version number or extensions list don't match the backend, leading to
613/// unloaded functions being called.
614///
615pub unsafe fn get_supported_glsl(gl: &gl::Gl, version: &Version, extensions: &ExtensionsList)
616                                 -> Vec<Version>
617{
618    // checking if the implementation has a shader compiler
619    // a compiler is optional in OpenGL ES
620    if version.0 == Api::GlEs {
621        let mut val = 0;
622        gl.GetBooleanv(gl::SHADER_COMPILER, &mut val);
623        if val == 0 {
624            return vec![];
625        }
626    }
627
628    // some recent versions have an API to determine the list of supported versions
629    if version >= &Version(Api::Gl, 4, 3) {
630        // FIXME: implement this and return the result directly
631    }
632
633    let mut result = Vec::with_capacity(8);
634
635    if version >= &Version(Api::GlEs, 2, 0) || version >= &Version(Api::Gl, 4, 1) ||
636       extensions.gl_arb_es2_compatibility
637    {
638        result.push(Version(Api::GlEs, 1, 0));
639    }
640
641    if version >= &Version(Api::GlEs, 3, 0) || version >= &Version(Api::Gl, 4, 3) ||
642       extensions.gl_arb_es3_compatibility
643    {
644        result.push(Version(Api::GlEs, 3, 0));
645    }
646
647    if version >= &Version(Api::GlEs, 3, 1) || version >= &Version(Api::Gl, 4, 5) ||
648       extensions.gl_arb_es3_1_compatibility
649    {
650        result.push(Version(Api::GlEs, 3, 1));
651    }
652
653    if version >= &Version(Api::GlEs, 3, 2) || extensions.gl_arb_es3_2_compatibility {
654        result.push(Version(Api::GlEs, 3, 2));
655    }
656
657    if version >= &Version(Api::Gl, 2, 0) && version <= &Version(Api::Gl, 3, 0) ||
658       extensions.gl_arb_compatibility
659    {
660        result.push(Version(Api::Gl, 1, 1));
661    }
662
663    if version >= &Version(Api::Gl, 2, 1) && version <= &Version(Api::Gl, 3, 0) ||
664       extensions.gl_arb_compatibility
665    {
666        result.push(Version(Api::Gl, 1, 2));
667    }
668
669    if version == &Version(Api::Gl, 3, 0) || extensions.gl_arb_compatibility {
670        result.push(Version(Api::Gl, 1, 3));
671    }
672
673    if version >= &Version(Api::Gl, 3, 1) {
674        result.push(Version(Api::Gl, 1, 4));
675    }
676
677    if version >= &Version(Api::Gl, 3, 2) {
678        result.push(Version(Api::Gl, 1, 5));
679    }
680
681    for &(major, minor) in &[(3, 3), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5)] {
682        if version >= &Version(Api::Gl, major, minor) {
683            result.push(Version(Api::Gl, major, minor));
684        }
685    }
686
687    result
688}
689
690/// Returns all informations about all supported internal formats.
691pub fn get_internal_formats(gl: &gl::Gl, version: &Version, extensions: &ExtensionsList,
692                            renderbuffer: bool) -> HashMap<TextureFormat, FormatInfos, BuildHasherDefault<FnvHasher>>
693{
694    // We create a dummy object to implement the `CapabilitiesSource` trait.
695    let dummy = {
696        struct DummyCaps<'a>(&'a Version, &'a ExtensionsList);
697        impl<'a> CapabilitiesSource for DummyCaps<'a> {
698            fn get_version(&self) -> &Version { self.0 }
699            fn get_extensions(&self) -> &ExtensionsList { self.1 }
700            fn get_capabilities(&self) -> &Capabilities { unreachable!() }
701        }
702        DummyCaps(version, extensions)
703    };
704
705    TextureFormat::get_formats_list().into_iter().filter_map(|format| {
706        if renderbuffer {
707            if !format.is_supported_for_renderbuffers(&dummy) {
708                return None;
709            }
710        } else if !format.is_supported_for_textures(&dummy) {
711            return None;
712        }
713
714        let infos = get_internal_format(gl, version, extensions, format, renderbuffer);
715        Some((format, infos))
716    }).collect()
717}
718
719/// Returns informations about a precise internal format.
720pub fn get_internal_format(gl: &gl::Gl, version: &Version, extensions: &ExtensionsList,
721                           format: TextureFormat, renderbuffer: bool) -> FormatInfos
722{
723    // We create a dummy object to implement the `CapabilitiesSource` trait.
724    let dummy = {
725        struct DummyCaps<'a>(&'a Version, &'a ExtensionsList);
726        impl<'a> CapabilitiesSource for DummyCaps<'a> {
727            fn get_version(&self) -> &Version { self.0 }
728            fn get_extensions(&self) -> &ExtensionsList { self.1 }
729            fn get_capabilities(&self) -> &Capabilities { unreachable!() }
730        }
731        DummyCaps(version, extensions)
732    };
733
734    unsafe {
735        let target = if renderbuffer { gl::RENDERBUFFER } else { gl::TEXTURE_2D_MULTISAMPLE };
736
737        let samples = if format.is_renderable(&dummy) &&
738                         ((version >= &Version(Api::GlEs, 3, 0) && renderbuffer) ||
739                          version >= &Version(Api::Gl, 4, 2) ||
740                          extensions.gl_arb_internalformat_query)
741        {
742            let mut num = 0;
743            gl.GetInternalformativ(target, format.to_glenum(), gl::NUM_SAMPLE_COUNTS, 1, &mut num);
744
745            if num >= 1 {
746                let mut formats = Vec::with_capacity(num as usize);
747                gl.GetInternalformativ(target, format.to_glenum(), gl::SAMPLES, num,
748                                       formats.as_mut_ptr());
749                formats.set_len(num as usize);
750                Some(formats)
751
752            } else {
753                Some(Vec::new())
754            }
755
756        } else {
757            None
758        };
759
760        FormatInfos {
761            multisamples: samples,
762        }
763    }
764}