gl_helpers/
gl_info.rs

1use std::sync::atomic::{AtomicUsize, Ordering};
2
3use gl;
4use gl::types::*;
5use regex::Regex;
6
7static MAJOR: AtomicUsize = AtomicUsize::new(3);
8static MINOR: AtomicUsize = AtomicUsize::new(0);
9
10static GLSL_MAJOR: AtomicUsize = AtomicUsize::new(3);
11static GLSL_MINOR: AtomicUsize = AtomicUsize::new(0);
12
13static HIGHP: &'static str = "highp";
14static MEDIUMP: &'static str = "mediump";
15static LOWP: &'static str = "lowp";
16
17#[inline]
18pub fn gl_major() -> usize {
19    MAJOR.load(Ordering::Relaxed)
20}
21#[inline]
22pub fn gl_minor() -> usize {
23    MINOR.load(Ordering::Relaxed)
24}
25
26#[inline]
27pub fn glsl_major() -> usize {
28    GLSL_MAJOR.load(Ordering::Relaxed)
29}
30#[inline]
31pub fn glsl_minor() -> usize {
32    GLSL_MINOR.load(Ordering::Relaxed)
33}
34
35#[derive(Debug, Clone, Hash)]
36pub struct GLInfo {
37    version: String,
38
39    major: usize,
40    minor: usize,
41    glsl_major: usize,
42    glsl_minor: usize,
43
44    extenstions: Vec<String>,
45
46    max_anisotropy: usize,
47    max_textures: usize,
48    max_vertex_textures: usize,
49    max_texture_size: usize,
50    max_cube_texture_size: usize,
51    max_render_buffer_size: usize,
52
53    max_uniforms: usize,
54    max_varyings: usize,
55    max_attributes: usize,
56
57    precision: &'static str,
58}
59
60impl GLInfo {
61    #[inline(always)]
62    pub fn new() -> Self {
63        let mut info = GLInfo {
64            version: String::new(),
65
66            major: 0,
67            minor: 0,
68            glsl_major: 0,
69            glsl_minor: 0,
70
71            extenstions: Vec::new(),
72
73            max_anisotropy: 0,
74            max_textures: 0,
75            max_vertex_textures: 0,
76            max_texture_size: 0,
77            max_cube_texture_size: 0,
78            max_render_buffer_size: 0,
79
80            max_uniforms: 0,
81            max_varyings: 0,
82            max_attributes: 0,
83
84            precision: HIGHP,
85        };
86
87        info.gl_info();
88        info
89    }
90
91    #[inline(always)]
92    pub fn version(&self) -> &String {
93        &self.version
94    }
95
96    #[inline(always)]
97    pub fn major(&self) -> usize {
98        self.major
99    }
100    #[inline(always)]
101    pub fn minor(&self) -> usize {
102        self.minor
103    }
104    #[inline(always)]
105    pub fn glsl_major(&self) -> usize {
106        self.glsl_major
107    }
108    #[inline(always)]
109    pub fn glsl_minor(&self) -> usize {
110        self.glsl_minor
111    }
112    #[inline(always)]
113    #[inline(always)]
114    pub fn extenstions(&self) -> &[String] {
115        &*self.extenstions
116    }
117
118    #[inline(always)]
119    pub fn max_anisotropy(&self) -> usize {
120        self.max_anisotropy
121    }
122    #[inline(always)]
123    pub fn max_textures(&self) -> usize {
124        self.max_textures
125    }
126    #[inline(always)]
127    pub fn max_vertex_textures(&self) -> usize {
128        self.max_vertex_textures
129    }
130    #[inline(always)]
131    pub fn max_texture_size(&self) -> usize {
132        self.max_texture_size
133    }
134    #[inline(always)]
135    pub fn max_cube_texture_size(&self) -> usize {
136        self.max_cube_texture_size
137    }
138    #[inline(always)]
139    pub fn max_render_buffer_size(&self) -> usize {
140        self.max_render_buffer_size
141    }
142
143    #[inline(always)]
144    pub fn max_uniforms(&self) -> usize {
145        self.max_uniforms
146    }
147    #[inline(always)]
148    pub fn max_varyings(&self) -> usize {
149        self.max_varyings
150    }
151    #[inline(always)]
152    pub fn max_attributes(&self) -> usize {
153        self.max_attributes
154    }
155
156    #[inline(always)]
157    pub fn precision(&self) -> &'static str {
158        self.precision
159    }
160
161    #[inline(always)]
162    pub fn has_extenstion(&self, string: &str) -> bool {
163        match self.extenstions.iter().position(|e| e == string) {
164            Some(_) => true,
165            None => false,
166        }
167    }
168
169    #[inline]
170    fn gl_info(&mut self) {
171        let mut vs_high_float_precision: GLint = 0;
172        let mut vs_high_float_range: GLint = 0;
173        unsafe {
174            gl::GetShaderPrecisionFormat(
175                gl::VERTEX_SHADER,
176                gl::HIGH_FLOAT,
177                &mut vs_high_float_range,
178                &mut vs_high_float_precision,
179            );
180        }
181
182        let mut vs_mediump_float_precision: GLint = 0;
183        let mut vs_mediump_float_range: GLint = 0;
184        unsafe {
185            gl::GetShaderPrecisionFormat(
186                gl::VERTEX_SHADER,
187                gl::MEDIUM_FLOAT,
188                &mut vs_mediump_float_range,
189                &mut vs_mediump_float_precision,
190            );
191        }
192
193        let mut fs_high_float_precision: GLint = 0;
194        let mut fs_high_float_range: GLint = 0;
195        unsafe {
196            gl::GetShaderPrecisionFormat(
197                gl::FRAGMENT_SHADER,
198                gl::HIGH_FLOAT,
199                &mut fs_high_float_range,
200                &mut fs_high_float_precision,
201            );
202        }
203
204        let mut fs_mediump_float_precision: GLint = 0;
205        let mut fs_mediump_float_range: GLint = 0;
206        unsafe {
207            gl::GetShaderPrecisionFormat(
208                gl::FRAGMENT_SHADER,
209                gl::MEDIUM_FLOAT,
210                &mut fs_mediump_float_range,
211                &mut fs_mediump_float_precision,
212            );
213        }
214
215        let highp_available = vs_high_float_precision > 0 && fs_high_float_precision > 0;
216        let mediump_available = vs_mediump_float_precision > 0 && fs_mediump_float_precision > 0;
217
218        self.precision = if !highp_available {
219            if mediump_available {
220                MEDIUMP
221            } else {
222                LOWP
223            }
224        } else {
225            HIGHP
226        };
227
228        unsafe {
229            let ptr = gl::GetString(gl::VERSION);
230            string_from_ptr(ptr, &mut self.version);
231
232            let (mut major, mut minor) = match Regex::new(r"(\d+).(\d+)")
233                .expect("regex failed to compile")
234                .captures(&self.version)
235            {
236                Some(cap) => (
237                    match cap.get(1) {
238                        Some(major) => major.as_str().parse::<i32>().unwrap(),
239                        None => 3,
240                    },
241                    match cap.get(2) {
242                        Some(minor) => minor.as_str().parse::<i32>().unwrap(),
243                        None => 1,
244                    },
245                ),
246                None => (3, 1),
247            };
248
249            if major > 2 {
250                gl::GetIntegerv(gl::MAJOR_VERSION, &mut major);
251                self.major = major as usize;
252                gl::GetIntegerv(gl::MINOR_VERSION, &mut minor);
253                self.minor = minor as usize;
254            } else {
255                self.major = 2;
256                self.minor = 0;
257            }
258
259            glsl_version(
260                self.major,
261                self.minor,
262                &mut self.glsl_major,
263                &mut self.glsl_minor,
264            );
265            parse_extenstions(&mut self.extenstions, self.major);
266        }
267
268        MAJOR.store(self.major, Ordering::SeqCst);
269        MINOR.store(self.minor, Ordering::SeqCst);
270
271        GLSL_MAJOR.store(self.glsl_major, Ordering::SeqCst);
272        GLSL_MINOR.store(self.glsl_minor, Ordering::SeqCst);
273
274        unsafe {
275            let mut max_textures = 0;
276            gl::GetIntegerv(gl::MAX_TEXTURE_IMAGE_UNITS, &mut max_textures);
277            self.max_textures = max_textures as usize;
278
279            let mut max_vertex_textures = 0;
280            gl::GetIntegerv(gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mut max_vertex_textures);
281            self.max_vertex_textures = max_vertex_textures as usize;
282
283            let mut max_texture_size = 0;
284            gl::GetIntegerv(gl::MAX_TEXTURE_SIZE, &mut max_texture_size);
285            self.max_texture_size = max_texture_size as usize;
286
287            let mut max_cube_texture_size = 0;
288            gl::GetIntegerv(gl::MAX_CUBE_MAP_TEXTURE_SIZE, &mut max_cube_texture_size);
289            self.max_cube_texture_size = max_cube_texture_size as usize;
290
291            let mut max_render_buffer_size = 0;
292            gl::GetIntegerv(gl::MAX_RENDERBUFFER_SIZE, &mut max_render_buffer_size);
293            self.max_render_buffer_size = max_render_buffer_size as usize;
294
295            let mut vs_max_uniforms = 0;
296            let mut fs_max_uniforms = 0;
297            gl::GetIntegerv(gl::MAX_VERTEX_UNIFORM_VECTORS, &mut vs_max_uniforms);
298            gl::GetIntegerv(gl::MAX_FRAGMENT_UNIFORM_VECTORS, &mut fs_max_uniforms);
299            self.max_uniforms = if vs_max_uniforms < fs_max_uniforms {
300                vs_max_uniforms
301            } else {
302                fs_max_uniforms
303            } as usize * 4;
304
305            let mut max_varyings = 0;
306            gl::GetIntegerv(gl::MAX_VARYING_VECTORS, &mut max_varyings);
307            self.max_varyings = max_varyings as usize * 4;
308
309            let mut max_attributes = 0;
310            gl::GetIntegerv(gl::MAX_VERTEX_ATTRIBS, &mut max_attributes);
311            self.max_attributes = max_attributes as usize;
312        }
313    }
314}
315
316#[inline]
317unsafe fn string_from_ptr(ptr: *const u8, string: &mut String) {
318    let mut i = 0isize;
319    loop {
320        let ch = *ptr.offset(i);
321
322        if ch != 0u8 {
323            string.push(ch as char);
324            i = i + 1isize;
325        } else {
326            break;
327        }
328    }
329}
330
331#[inline]
332unsafe fn parse_extenstions(extenstions: &mut Vec<String>, major_version: usize) {
333    if major_version > 2 {
334        let mut count = 0;
335        gl::GetIntegerv(gl::NUM_EXTENSIONS, &mut count);
336
337        for i in 0..(count as u32) {
338            let mut string = String::new();
339            string_from_ptr(gl::GetStringi(gl::EXTENSIONS, i), &mut string);
340            extenstions.push(string);
341        }
342    } else {
343        let mut string = String::new();
344        string_from_ptr(gl::GetString(gl::EXTENSIONS), &mut string);
345
346        for extenstion in string.split_whitespace() {
347            extenstions.push(String::from(extenstion));
348        }
349    }
350}
351
352#[inline]
353fn glsl_version(major: usize, minor: usize, glsl_major: &mut usize, glsl_minor: &mut usize) {
354    if major <= 3 && minor <= 2 {
355        *glsl_major = 1;
356        *glsl_minor = if major == 3 && minor == 2 {
357            5
358        } else if major == 3 && minor == 1 {
359            4
360        } else if major == 3 && minor == 0 {
361            3
362        } else if major == 2 && minor == 1 {
363            2
364        } else {
365            1
366        }
367    } else {
368        *glsl_major = major;
369        *glsl_minor = minor;
370    }
371}