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}